root/dev/mii/dcphy.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dcphy_match
  2. dcphy_attach
  3. dcphy_service
  4. dcphy_status
  5. dcphy_mii_phy_auto
  6. dcphy_reset

    1 /*      $OpenBSD: dcphy.c,v 1.18 2006/12/27 19:11:08 kettenis Exp $     */
    2 
    3 /*
    4  * Copyright (c) 1997, 1998, 1999
    5  *      Bill Paul <wpaul@ee.columbia.edu>.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *      This product includes software developed by Bill Paul.
   18  * 4. Neither the name of the author nor the names of any co-contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
   26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   32  * THE POSSIBILITY OF SUCH DAMAGE.
   33  *
   34  * $FreeBSD: src/sys/dev/mii/dcphy.c,v 1.6 2000/10/05 17:36:14 wpaul Exp $
   35  */
   36 
   37 /*
   38  * Pseudo-driver for internal NWAY support on DEC 21143 and workalike
   39  * controllers. Technically we're abusing the miibus code to handle
   40  * media selection and NWAY support here since there is no MII
   41  * interface. However the logical operations are roughly the same,
   42  * and the alternative is to create a fake MII interface in the driver,
   43  * which is harder to do.
   44  */
   45 
   46 #include <sys/param.h>
   47 #include <sys/device.h>
   48 #include <sys/systm.h>
   49 #include <sys/kernel.h>
   50 #include <sys/socket.h>
   51 #include <sys/timeout.h>
   52 #include <sys/errno.h>
   53 
   54 #include <net/if.h>
   55 #include <net/if_dl.h>
   56 #include <net/if_types.h>
   57 #include <net/if_media.h>
   58 #include <netinet/in.h>
   59 #include <netinet/if_ether.h>
   60 
   61 #include <dev/mii/mii.h>
   62 #include <dev/mii/miivar.h>
   63 #include <dev/mii/miidevs.h>
   64 
   65 #include <machine/bus.h>
   66 
   67 #include <dev/pci/pcivar.h>
   68 
   69 #include <dev/ic/dcreg.h>
   70 
   71 #define DC_SETBIT(sc, reg, x)                           \
   72         CSR_WRITE_4(sc, reg,                            \
   73                 CSR_READ_4(sc, reg) | x)
   74 
   75 #define DC_CLRBIT(sc, reg, x)                           \
   76         CSR_WRITE_4(sc, reg,                            \
   77                 CSR_READ_4(sc, reg) & ~x)
   78 
   79 #define MIIF_AUTOTIMEOUT        0x0004
   80 
   81 /*
   82  * This is the subsystem ID for the built-in 21143 ethernet
   83  * in several Compaq Presario systems. Apparently these are
   84  * 10Mbps only, so we need to treat them specially.
   85  */
   86 #define COMPAQ_PRESARIO_ID      0xb0bb0e11
   87 
   88 int     dcphy_match(struct device *, void *, void *);
   89 void    dcphy_attach(struct device *, struct device *, void *);
   90 
   91 struct cfattach dcphy_ca = {
   92         sizeof(struct mii_softc), dcphy_match, dcphy_attach, mii_phy_detach,
   93             mii_phy_activate
   94 };
   95 
   96 struct cfdriver dcphy_cd = {
   97         NULL, "dcphy", DV_DULL
   98 };
   99 
  100 int     dcphy_service(struct mii_softc *, struct mii_data *, int);
  101 void    dcphy_status(struct mii_softc *);
  102 int     dcphy_mii_phy_auto(struct mii_softc *, int);
  103 void    dcphy_reset(struct mii_softc *);
  104 
  105 const struct mii_phy_funcs dcphy_funcs = {
  106         dcphy_service, dcphy_status, dcphy_reset,
  107 };
  108 
  109 int
  110 dcphy_match(struct device *parent, void *match, void *aux)
  111 {
  112         struct mii_attach_args *ma = aux;
  113 
  114         /*
  115          * The dc driver will report the 21143 vendor and device
  116          * ID to let us know that it wants us to attach.
  117          */
  118         if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxDEC &&
  119             MII_MODEL(ma->mii_id2) == MII_MODEL_xxDEC_xxDC)
  120                 return (10);
  121 
  122         return (0);
  123 }
  124 
  125 void
  126 dcphy_attach(struct device *parent, struct device *self, void *aux)
  127 {
  128         struct mii_softc *sc = (struct mii_softc *)self;
  129         struct mii_attach_args *ma = aux;
  130         struct mii_data *mii = ma->mii_data;
  131         struct dc_softc *dc_sc;
  132 
  133         printf(": internal PHY\n");
  134         sc->mii_inst = mii->mii_instance;
  135         sc->mii_phy = ma->mii_phyno;
  136         sc->mii_funcs = &dcphy_funcs;
  137         sc->mii_pdata = mii;
  138         sc->mii_flags = ma->mii_flags;
  139         sc->mii_anegticks = 50;
  140 
  141         sc->mii_flags |= MIIF_NOISOLATE;
  142 
  143         dc_sc = mii->mii_ifp->if_softc;
  144         CSR_WRITE_4(dc_sc, DC_10BTSTAT, 0);
  145         CSR_WRITE_4(dc_sc, DC_10BTCTRL, 0);
  146 
  147 #define ADD(m, c)       ifmedia_add(&mii->mii_media, (m), (c), NULL)
  148 
  149         switch(dc_sc->dc_csid) {
  150         case COMPAQ_PRESARIO_ID:
  151                 /* Example of how to only allow 10Mbps modes. */
  152                 sc->mii_capabilities = BMSR_ANEG|BMSR_10TFDX|BMSR_10THDX;
  153                 break;
  154         default:
  155                 if (dc_sc->dc_pmode == DC_PMODE_SIA) {
  156                         sc->mii_capabilities =
  157                             BMSR_ANEG|BMSR_10TFDX|BMSR_10THDX;
  158                 } else {
  159                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP,
  160                             sc->mii_inst), BMCR_LOOP|BMCR_S100);
  161 
  162                         sc->mii_capabilities =
  163                             BMSR_ANEG|BMSR_100TXFDX|BMSR_100TXHDX|
  164                             BMSR_10TFDX|BMSR_10THDX;
  165                 }
  166                 break;
  167         }
  168 
  169         if (dc_sc->dc_type == DC_TYPE_21145)
  170                 sc->mii_capabilities = BMSR_10THDX;
  171 
  172         sc->mii_capabilities &= ma->mii_capmask;
  173         if (sc->mii_capabilities & BMSR_MEDIAMASK)
  174                 mii_phy_add_media(sc);
  175 #undef ADD
  176 }
  177 
  178 int
  179 dcphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
  180 {
  181         struct dc_softc *dc_sc;
  182         struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
  183         int reg;
  184         u_int32_t mode;
  185 
  186         if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0)
  187                 return (ENXIO);
  188 
  189         dc_sc = mii->mii_ifp->if_softc;
  190 
  191         switch (cmd) {
  192         case MII_POLLSTAT:
  193                 /*
  194                  * If we're not polling our PHY instance, just return.
  195                  */
  196                 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
  197                         return (0);
  198                 break;
  199 
  200         case MII_MEDIACHG:
  201                 /*
  202                  * If the media indicates a different PHY instance,
  203                  * isolate ourselves.
  204                  */
  205                 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
  206                         return (0);
  207 
  208                 /*
  209                  * If the interface is not up, don't do anything.
  210                  */
  211                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
  212                         break;
  213 
  214                 sc->mii_flags = 0;
  215                 mii->mii_media_active = IFM_NONE;
  216                 mode = CSR_READ_4(dc_sc, DC_NETCFG);
  217                 mode &= ~(DC_NETCFG_FULLDUPLEX|DC_NETCFG_PORTSEL|
  218                     DC_NETCFG_PCS|DC_NETCFG_SCRAMBLER|DC_NETCFG_SPEEDSEL);
  219 
  220                 switch (IFM_SUBTYPE(ife->ifm_media)) {
  221                 case IFM_AUTO:
  222                         /*PHY_RESET(sc);*/
  223                         sc->mii_flags &= ~MIIF_DOINGAUTO;
  224                         (void) dcphy_mii_phy_auto(sc, 0);
  225                         break;
  226                 case IFM_100_TX:
  227                         PHY_RESET(sc);
  228                         DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
  229                         mode |= DC_NETCFG_PORTSEL|DC_NETCFG_PCS|
  230                             DC_NETCFG_SCRAMBLER;
  231                         if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
  232                                 mode |= DC_NETCFG_FULLDUPLEX;
  233                         else
  234                                 mode &= ~DC_NETCFG_FULLDUPLEX;
  235                         CSR_WRITE_4(dc_sc, DC_NETCFG, mode);
  236                         break;
  237                 case IFM_10_T:
  238                         DC_CLRBIT(dc_sc, DC_SIARESET, DC_SIA_RESET);
  239                         DC_CLRBIT(dc_sc, DC_10BTCTRL, 0xFFFF);
  240                         if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
  241                                 DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3D);
  242                         else
  243                                 DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3F);
  244                         DC_SETBIT(dc_sc, DC_SIARESET, DC_SIA_RESET);
  245                         DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
  246                         mode &= ~DC_NETCFG_PORTSEL;
  247                         mode |= DC_NETCFG_SPEEDSEL;
  248                         if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
  249                                 mode |= DC_NETCFG_FULLDUPLEX;
  250                         else
  251                                 mode &= ~DC_NETCFG_FULLDUPLEX;
  252                         CSR_WRITE_4(dc_sc, DC_NETCFG, mode);
  253                         break;
  254                 default:
  255                         return (EINVAL);
  256                 }
  257                 break;
  258 
  259         case MII_TICK:
  260                 /*
  261                  * If we're not currently selected, just return.
  262                  */
  263                 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
  264                         return (0);
  265 
  266                 /*
  267                  * Is the interface even up?
  268                  */
  269                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
  270                         return (0);
  271 
  272                 /*
  273                  * Only used for autonegotiation.
  274                  */
  275                 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
  276                         break;
  277 
  278                 reg = CSR_READ_4(dc_sc, DC_10BTSTAT);
  279                 if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100))
  280                         break;
  281 
  282                 /*
  283                  * Only retry autonegotiation every mii_anegticks seconds.
  284                  *
  285                  * Otherwise, fall through to calling dcphy_status()
  286                  * since real Intel 21143 chips don't show valid link
  287                  * status until autonegotiation is switched off, and
  288                  * that only happens in dcphy_status().  Without this,
  289                  * successful autonegotation is never recognised on
  290                  * these chips.
  291                  */
  292                 if (++sc->mii_ticks <= sc->mii_anegticks)
  293                         break;
  294 
  295                 sc->mii_ticks = 0;
  296                 sc->mii_flags &= ~MIIF_DOINGAUTO;
  297                 dcphy_mii_phy_auto(sc, 0);
  298 
  299                 break;
  300         }
  301 
  302         /* Update the media status. */
  303         mii_phy_status(sc);
  304 
  305         /* Callback if something changed. */
  306         mii_phy_update(sc, cmd);
  307         return (0);
  308 }
  309 
  310 void
  311 dcphy_status(struct mii_softc *sc)
  312 {
  313         struct mii_data *mii = sc->mii_pdata;
  314         int reg, anlpar, tstat = 0;
  315         struct dc_softc *dc_sc;
  316 
  317         dc_sc = mii->mii_ifp->if_softc;
  318 
  319         mii->mii_media_status = IFM_AVALID;
  320         mii->mii_media_active = IFM_ETHER;
  321 
  322         reg = CSR_READ_4(dc_sc, DC_10BTSTAT);
  323         if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100))
  324                 mii->mii_media_status |= IFM_ACTIVE;
  325 
  326         if (CSR_READ_4(dc_sc, DC_10BTCTRL) & DC_TCTL_AUTONEGENBL) {
  327                 /* Erg, still trying, I guess... */
  328                 tstat = CSR_READ_4(dc_sc, DC_10BTSTAT);
  329                 if ((tstat & DC_TSTAT_ANEGSTAT) != DC_ASTAT_AUTONEGCMP) {
  330                         if ((DC_IS_MACRONIX(dc_sc) || DC_IS_PNICII(dc_sc)) &&
  331                             (tstat & DC_TSTAT_ANEGSTAT) == DC_ASTAT_DISABLE)
  332                                 goto skip;
  333                         mii->mii_media_active |= IFM_NONE;
  334                         return;
  335                 }
  336 
  337                 if (tstat & DC_TSTAT_LP_CAN_NWAY) {
  338                         anlpar = tstat >> 16;
  339                         if (anlpar & ANLPAR_T4 &&
  340                             sc->mii_capabilities & BMSR_100TXHDX)
  341                                 mii->mii_media_active |= IFM_100_T4|IFM_HDX;
  342                         else if (anlpar & ANLPAR_TX_FD &&
  343                             sc->mii_capabilities & BMSR_100TXFDX)
  344                                 mii->mii_media_active |= IFM_100_TX|IFM_FDX;
  345                         else if (anlpar & ANLPAR_TX &&
  346                             sc->mii_capabilities & BMSR_100TXHDX)
  347                                 mii->mii_media_active |= IFM_100_TX|IFM_HDX;
  348                         else if (anlpar & ANLPAR_10_FD)
  349                                 mii->mii_media_active |= IFM_10_T|IFM_FDX;
  350                         else if (anlpar & ANLPAR_10)
  351                                 mii->mii_media_active |= IFM_10_T|IFM_HDX;
  352                         else
  353                                 mii->mii_media_active |= IFM_NONE;
  354                         if (DC_IS_INTEL(dc_sc))
  355                                 DC_CLRBIT(dc_sc, DC_10BTCTRL,
  356                                     DC_TCTL_AUTONEGENBL);
  357                         return;
  358                 }
  359 
  360                 /*
  361                  * If the other side doesn't support NWAY, then the
  362                  * best we can do is determine if we have a 10Mbps or
  363                  * 100Mbps link. There's no way to know if the link
  364                  * is full or half duplex, so we default to half duplex
  365                  * and hope that the user is clever enough to manually
  366                  * change the media settings if we're wrong.
  367                  */
  368                 if (!(reg & DC_TSTAT_LS100))
  369                         mii->mii_media_active |= IFM_100_TX|IFM_HDX;
  370                 else if (!(reg & DC_TSTAT_LS10))
  371                         mii->mii_media_active |= IFM_10_T|IFM_HDX;
  372                 else
  373                         mii->mii_media_active |= IFM_NONE;
  374                 if (DC_IS_INTEL(dc_sc))
  375                         DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
  376                 return;
  377         }
  378 
  379 skip:
  380         if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_SPEEDSEL)
  381                 mii->mii_media_active |= IFM_10_T;
  382         else
  383                 mii->mii_media_active |= IFM_100_TX;
  384 
  385         if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX)
  386                 mii->mii_media_active |= IFM_FDX;
  387         else
  388                 mii->mii_media_active |= IFM_HDX;
  389 }
  390 
  391 int
  392 dcphy_mii_phy_auto(struct mii_softc *mii, int waitfor)
  393 {
  394         int                     i;
  395         struct dc_softc         *sc;
  396 
  397         sc = mii->mii_pdata->mii_ifp->if_softc;
  398 
  399         if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) {
  400                 DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
  401                 DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX);
  402                 DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET);
  403                 if (mii->mii_capabilities & BMSR_100TXHDX)
  404                         CSR_WRITE_4(sc, DC_10BTCTRL, 0x3FFFF);
  405                 else
  406                         CSR_WRITE_4(sc, DC_10BTCTRL, 0xFFFF);
  407                 DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET);
  408                 DC_SETBIT(sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
  409                 DC_SETBIT(sc, DC_10BTSTAT, DC_ASTAT_TXDISABLE);
  410         }
  411 
  412         if (waitfor) {
  413                 /* Wait 500ms for it to complete. */
  414                 for (i = 0; i < 500; i++) {
  415                         if ((CSR_READ_4(sc, DC_10BTSTAT) & DC_TSTAT_ANEGSTAT)
  416                             == DC_ASTAT_AUTONEGCMP)
  417                                 return (0);
  418                         DELAY(1000);
  419                 }
  420                 /*
  421                  * Don't need to worry about clearing MIIF_DOINGAUTO.
  422                  * If that's set, a timeout is pending, and it will
  423                  * clear the flag.
  424                  */
  425                 return (EIO);
  426         }
  427 
  428         /*
  429          * Just let it finish asynchronously.  This is for the benefit of
  430          * the tick handler driving autonegotiation.  Don't want 500ms
  431          * delays all the time while the system is running!
  432          */
  433         if ((mii->mii_flags & MIIF_DOINGAUTO) == 0)
  434                 mii->mii_flags |= MIIF_DOINGAUTO;
  435 
  436         return (EJUSTRETURN);
  437 }
  438 
  439 void
  440 dcphy_reset(struct mii_softc *mii)
  441 {
  442         struct dc_softc         *sc;
  443 
  444         sc = mii->mii_pdata->mii_ifp->if_softc;
  445 
  446         DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET);
  447         DELAY(1000);
  448         DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET);
  449 
  450         return;
  451 }

/* [<][>][^][v][top][bottom][index][help] */