The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/mii/mii_physubr.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: mii_physubr.c,v 1.5 1999/08/03 19:41:49 drochner Exp $ */
    2 
    3 /*-
    4  * SPDX-License-Identifier: BSD-2-Clause-NetBSD
    5  *
    6  * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
    7  * All rights reserved.
    8  *
    9  * This code is derived from software contributed to The NetBSD Foundation
   10  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
   11  * NASA Ames Research Center.
   12  *
   13  * Redistribution and use in source and binary forms, with or without
   14  * modification, are permitted provided that the following conditions
   15  * are met:
   16  * 1. Redistributions of source code must retain the above copyright
   17  *    notice, this list of conditions and the following disclaimer.
   18  * 2. Redistributions in binary form must reproduce the above copyright
   19  *    notice, this list of conditions and the following disclaimer in the
   20  *    documentation and/or other materials provided with the distribution.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   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 THE
   32  * POSSIBILITY OF SUCH DAMAGE.
   33  */
   34 
   35 #include <sys/cdefs.h>
   36 __FBSDID("$FreeBSD$");
   37 
   38 /*
   39  * Subroutines common to all PHYs.
   40  */
   41 
   42 #include <sys/param.h>
   43 #include <sys/systm.h>
   44 #include <sys/kernel.h>
   45 #include <sys/socket.h>
   46 #include <sys/errno.h>
   47 #include <sys/module.h>
   48 #include <sys/bus.h>
   49 
   50 #include <net/if.h>
   51 #include <net/if_media.h>
   52 
   53 #include <dev/mii/mii.h>
   54 #include <dev/mii/miivar.h>
   55 
   56 #include "miibus_if.h"
   57 
   58 /*
   59  *
   60  * An array of structures to map MII media types to BMCR/ANAR settings.
   61  */
   62 enum { 
   63         MII_MEDIA_NONE = 0,
   64         MII_MEDIA_10_T,
   65         MII_MEDIA_10_T_FDX,
   66         MII_MEDIA_100_T4,
   67         MII_MEDIA_100_TX,
   68         MII_MEDIA_100_TX_FDX,
   69         MII_MEDIA_1000_X,
   70         MII_MEDIA_1000_X_FDX,
   71         MII_MEDIA_1000_T,
   72         MII_MEDIA_1000_T_FDX,
   73         MII_NMEDIA,
   74 };
   75 
   76 static const struct mii_media {
   77         u_int   mm_bmcr;                /* BMCR settings for this media */
   78         u_int   mm_anar;                /* ANAR settings for this media */
   79         u_int   mm_gtcr;                /* 100base-T2 or 1000base-T CR */
   80 } mii_media_table[MII_NMEDIA] = {
   81         /* None */
   82         { BMCR_ISO,             ANAR_CSMA,
   83           0, },
   84 
   85         /* 10baseT */
   86         { BMCR_S10,             ANAR_CSMA|ANAR_10,
   87           0, },
   88 
   89         /* 10baseT-FDX */
   90         { BMCR_S10|BMCR_FDX,    ANAR_CSMA|ANAR_10_FD,
   91           0, },
   92 
   93         /* 100baseT4 */
   94         { BMCR_S100,            ANAR_CSMA|ANAR_T4,
   95           0, },
   96 
   97         /* 100baseTX */
   98         { BMCR_S100,            ANAR_CSMA|ANAR_TX,
   99           0, },
  100 
  101         /* 100baseTX-FDX */
  102         { BMCR_S100|BMCR_FDX,   ANAR_CSMA|ANAR_TX_FD,
  103           0, },
  104 
  105         /* 1000baseX */
  106         { BMCR_S1000,           ANAR_CSMA,
  107           0, },
  108 
  109         /* 1000baseX-FDX */
  110         { BMCR_S1000|BMCR_FDX,  ANAR_CSMA,
  111           0, },
  112 
  113         /* 1000baseT */
  114         { BMCR_S1000,           ANAR_CSMA,
  115           GTCR_ADV_1000THDX },
  116 
  117         /* 1000baseT-FDX */
  118         { BMCR_S1000,           ANAR_CSMA,
  119           GTCR_ADV_1000TFDX },
  120 };
  121 
  122 void
  123 mii_phy_setmedia(struct mii_softc *sc)
  124 {
  125         struct mii_data *mii = sc->mii_pdata;
  126         struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
  127         int bmcr, anar, gtcr;
  128         int index = -1;
  129 
  130         switch (IFM_SUBTYPE(ife->ifm_media)) {
  131         case IFM_AUTO:
  132                 /*
  133                  * Force renegotiation if MIIF_DOPAUSE or MIIF_FORCEANEG.
  134                  * The former is necessary as we might switch from flow-
  135                  * control advertisement being off to on or vice versa.
  136                  */
  137                 if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0 ||
  138                     (sc->mii_flags & (MIIF_DOPAUSE | MIIF_FORCEANEG)) != 0)
  139                         (void)mii_phy_auto(sc);
  140                 return;
  141 
  142         case IFM_NONE:
  143                 index = MII_MEDIA_NONE;
  144                 break;
  145 
  146         case IFM_HPNA_1:
  147                 index = MII_MEDIA_10_T;
  148                 break;
  149 
  150         case IFM_10_T:
  151                 switch (IFM_OPTIONS(ife->ifm_media)) {
  152                 case 0:
  153                         index = MII_MEDIA_10_T;
  154                         break;
  155                 case IFM_FDX:
  156                 case (IFM_FDX | IFM_FLOW):
  157                         index = MII_MEDIA_10_T_FDX;
  158                         break;
  159                 }
  160                 break;
  161 
  162         case IFM_100_TX:
  163         case IFM_100_FX:
  164                 switch (IFM_OPTIONS(ife->ifm_media)) {
  165                 case 0:
  166                         index = MII_MEDIA_100_TX;
  167                         break;
  168                 case IFM_FDX:
  169                 case (IFM_FDX | IFM_FLOW):
  170                         index = MII_MEDIA_100_TX_FDX;
  171                         break;
  172                 }
  173                 break;
  174 
  175         case IFM_100_T4:
  176                 index = MII_MEDIA_100_T4;
  177                 break;
  178 
  179         case IFM_1000_SX:
  180                 switch (IFM_OPTIONS(ife->ifm_media)) {
  181                 case 0:
  182                         index = MII_MEDIA_1000_X;
  183                         break;
  184                 case IFM_FDX:
  185                 case (IFM_FDX | IFM_FLOW):
  186                         index = MII_MEDIA_1000_X_FDX;
  187                         break;
  188                 }
  189                 break;
  190 
  191         case IFM_1000_T:
  192                 switch (IFM_OPTIONS(ife->ifm_media)) {
  193                 case 0:
  194                 case IFM_ETH_MASTER:
  195                         index = MII_MEDIA_1000_T;
  196                         break;
  197                 case IFM_FDX:
  198                 case (IFM_FDX | IFM_ETH_MASTER):
  199                 case (IFM_FDX | IFM_FLOW):
  200                 case (IFM_FDX | IFM_FLOW | IFM_ETH_MASTER):
  201                         index = MII_MEDIA_1000_T_FDX;
  202                         break;
  203                 }
  204                 break;
  205         }
  206 
  207         KASSERT(index != -1, ("%s: failed to map media word %d",
  208             __func__, ife->ifm_media));
  209 
  210         anar = mii_media_table[index].mm_anar;
  211         bmcr = mii_media_table[index].mm_bmcr;
  212         gtcr = mii_media_table[index].mm_gtcr;
  213 
  214         if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) {
  215                 gtcr |= GTCR_MAN_MS;
  216                 if ((ife->ifm_media & IFM_ETH_MASTER) != 0)
  217                         gtcr |= GTCR_ADV_MS;
  218         }
  219 
  220         if ((ife->ifm_media & IFM_FDX) != 0 &&
  221             ((ife->ifm_media & IFM_FLOW) != 0 ||
  222             (sc->mii_flags & MIIF_FORCEPAUSE) != 0)) {
  223                 if ((sc->mii_flags & MIIF_IS_1000X) != 0)
  224                         anar |= ANAR_X_PAUSE_TOWARDS;
  225                 else {
  226                         anar |= ANAR_FC;
  227                         /* XXX Only 1000BASE-T has PAUSE_ASYM? */
  228                         if ((sc->mii_flags & MIIF_HAVE_GTCR) != 0 &&
  229                             (sc->mii_extcapabilities &
  230                             (EXTSR_1000THDX | EXTSR_1000TFDX)) != 0)
  231                                 anar |= ANAR_X_PAUSE_ASYM;
  232                 }
  233         }
  234 
  235         PHY_WRITE(sc, MII_ANAR, anar);
  236         PHY_WRITE(sc, MII_BMCR, bmcr);
  237         if ((sc->mii_flags & MIIF_HAVE_GTCR) != 0)
  238                 PHY_WRITE(sc, MII_100T2CR, gtcr);
  239 }
  240 
  241 int
  242 mii_phy_auto(struct mii_softc *sc)
  243 {
  244         struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur;
  245         int anar, gtcr;
  246 
  247         /*
  248          * Check for 1000BASE-X.  Autonegotiation is a bit
  249          * different on such devices.
  250          */
  251         if ((sc->mii_flags & MIIF_IS_1000X) != 0) {
  252                 anar = 0;
  253                 if ((sc->mii_extcapabilities & EXTSR_1000XFDX) != 0)
  254                         anar |= ANAR_X_FD;
  255                 if ((sc->mii_extcapabilities & EXTSR_1000XHDX) != 0)
  256                         anar |= ANAR_X_HD;
  257 
  258                 if ((ife->ifm_media & IFM_FLOW) != 0 ||
  259                     (sc->mii_flags & MIIF_FORCEPAUSE) != 0)
  260                         anar |= ANAR_X_PAUSE_TOWARDS;
  261                 PHY_WRITE(sc, MII_ANAR, anar);
  262         } else {
  263                 anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) |
  264                     ANAR_CSMA;
  265                 if ((ife->ifm_media & IFM_FLOW) != 0 ||
  266                     (sc->mii_flags & MIIF_FORCEPAUSE) != 0) {
  267                         if ((sc->mii_capabilities &
  268                             (BMSR_10TFDX | BMSR_100TXFDX)) != 0)
  269                                 anar |= ANAR_FC;
  270                         /* XXX Only 1000BASE-T has PAUSE_ASYM? */
  271                         if (((sc->mii_flags & MIIF_HAVE_GTCR) != 0) &&
  272                             (sc->mii_extcapabilities &
  273                             (EXTSR_1000THDX | EXTSR_1000TFDX)) != 0)
  274                                 anar |= ANAR_X_PAUSE_ASYM;
  275                 }
  276                 PHY_WRITE(sc, MII_ANAR, anar);
  277                 if ((sc->mii_flags & MIIF_HAVE_GTCR) != 0) {
  278                         gtcr = 0;
  279                         if ((sc->mii_extcapabilities & EXTSR_1000TFDX) != 0)
  280                                 gtcr |= GTCR_ADV_1000TFDX;
  281                         if ((sc->mii_extcapabilities & EXTSR_1000THDX) != 0)
  282                                 gtcr |= GTCR_ADV_1000THDX;
  283                         PHY_WRITE(sc, MII_100T2CR, gtcr);
  284                 }
  285         }
  286         PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
  287         return (EJUSTRETURN);
  288 }
  289 
  290 int
  291 mii_phy_tick(struct mii_softc *sc)
  292 {
  293         struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur;
  294         int reg;
  295 
  296         /*
  297          * If we're not doing autonegotiation, we don't need to do
  298          * any extra work here.  However, we need to check the link
  299          * status so we can generate an announcement if the status
  300          * changes.
  301          */
  302         if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
  303                 sc->mii_ticks = 0;      /* reset autonegotiation timer. */
  304                 return (0);
  305         }
  306 
  307         /* Read the status register twice; BMSR_LINK is latch-low. */
  308         reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
  309         if ((reg & BMSR_LINK) != 0) {
  310                 sc->mii_ticks = 0;      /* reset autonegotiation timer. */
  311                 /* See above. */
  312                 return (0);
  313         }
  314 
  315         /* Announce link loss right after it happens */
  316         if (sc->mii_ticks++ == 0)
  317                 return (0);
  318 
  319         /* XXX: use default value if phy driver did not set mii_anegticks */
  320         if (sc->mii_anegticks == 0)
  321                 sc->mii_anegticks = MII_ANEGTICKS_GIGE;
  322 
  323         /* Only retry autonegotiation every mii_anegticks ticks. */
  324         if (sc->mii_ticks <= sc->mii_anegticks)
  325                 return (EJUSTRETURN);
  326 
  327         sc->mii_ticks = 0;
  328         PHY_RESET(sc);
  329         mii_phy_auto(sc);
  330         return (0);
  331 }
  332 
  333 void
  334 mii_phy_reset(struct mii_softc *sc)
  335 {
  336         struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur;
  337         int i, reg;
  338 
  339         if ((sc->mii_flags & MIIF_NOISOLATE) != 0)
  340                 reg = BMCR_RESET;
  341         else
  342                 reg = BMCR_RESET | BMCR_ISO;
  343         PHY_WRITE(sc, MII_BMCR, reg);
  344 
  345         /* Wait 100ms for it to complete. */
  346         for (i = 0; i < 100; i++) {
  347                 reg = PHY_READ(sc, MII_BMCR);
  348                 if ((reg & BMCR_RESET) == 0)
  349                         break;
  350                 DELAY(1000);
  351         }
  352 
  353         /* NB: a PHY may default to being powered down and/or isolated. */
  354         reg &= ~(BMCR_PDOWN | BMCR_ISO);
  355         if ((sc->mii_flags & MIIF_NOISOLATE) == 0 &&
  356             ((ife == NULL && sc->mii_inst != 0) ||
  357             (ife != NULL && IFM_INST(ife->ifm_media) != sc->mii_inst)))
  358                 reg |= BMCR_ISO;
  359         if (PHY_READ(sc, MII_BMCR) != reg)
  360                 PHY_WRITE(sc, MII_BMCR, reg);
  361 }
  362 
  363 void
  364 mii_phy_update(struct mii_softc *sc, int cmd)
  365 {
  366         struct mii_data *mii = sc->mii_pdata;
  367 
  368         if (sc->mii_media_active != mii->mii_media_active ||
  369             cmd == MII_MEDIACHG) {
  370                 MIIBUS_STATCHG(sc->mii_dev);
  371                 sc->mii_media_active = mii->mii_media_active;
  372         }
  373         if (sc->mii_media_status != mii->mii_media_status) {
  374                 MIIBUS_LINKCHG(sc->mii_dev);
  375                 sc->mii_media_status = mii->mii_media_status;
  376         }
  377 }
  378 
  379 /*
  380  * Initialize generic PHY media based on BMSR, called when a PHY is
  381  * attached.  We expect to be set up to print a comma-separated list
  382  * of media names.  Does not print a newline.
  383  */
  384 void
  385 mii_phy_add_media(struct mii_softc *sc)
  386 {
  387         struct mii_data *mii = sc->mii_pdata;
  388         const char *sep = "";
  389         int fdx = 0;
  390 
  391         if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
  392             (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0) {
  393                 printf("no media present");
  394                 return;
  395         }
  396 
  397         /*
  398          * Set the autonegotiation timer for 10/100 media.  Gigabit media is
  399          * handled below.
  400          */
  401         sc->mii_anegticks = MII_ANEGTICKS;
  402 
  403 #define ADD(m)          ifmedia_add(&mii->mii_media, (m), 0, NULL)
  404 #define PRINT(s)        printf("%s%s", sep, s); sep = ", "
  405 
  406         if ((sc->mii_flags & MIIF_NOISOLATE) == 0) {
  407                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst));
  408                 PRINT("none");
  409         }
  410 
  411         /*
  412          * There are different interpretations for the bits in
  413          * HomePNA PHYs.  And there is really only one media type
  414          * that is supported.
  415          */
  416         if ((sc->mii_flags & MIIF_IS_HPNA) != 0) {
  417                 if ((sc->mii_capabilities & BMSR_10THDX) != 0) {
  418                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0,
  419                             sc->mii_inst));
  420                         PRINT("HomePNA1");
  421                 }
  422                 return;
  423         }
  424 
  425         if ((sc->mii_capabilities & BMSR_10THDX) != 0) {
  426                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst));
  427                 PRINT("10baseT");
  428         }
  429         if ((sc->mii_capabilities & BMSR_10TFDX) != 0) {
  430                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst));
  431                 PRINT("10baseT-FDX");
  432                 if ((sc->mii_flags & MIIF_DOPAUSE) != 0 &&
  433                     (sc->mii_flags & MIIF_NOMANPAUSE) == 0) {
  434                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T,
  435                             IFM_FDX | IFM_FLOW, sc->mii_inst));
  436                         PRINT("10baseT-FDX-flow");
  437                 }
  438                 fdx = 1;
  439         }
  440         if ((sc->mii_capabilities & BMSR_100TXHDX) != 0) {
  441                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst));
  442                 PRINT("100baseTX");
  443         }
  444         if ((sc->mii_capabilities & BMSR_100TXFDX) != 0) {
  445                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst));
  446                 PRINT("100baseTX-FDX");
  447                 if ((sc->mii_flags & MIIF_DOPAUSE) != 0 &&
  448                     (sc->mii_flags & MIIF_NOMANPAUSE) == 0) {
  449                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX,
  450                             IFM_FDX | IFM_FLOW, sc->mii_inst));
  451                         PRINT("100baseTX-FDX-flow");
  452                 }
  453                 fdx = 1;
  454         }
  455         if ((sc->mii_capabilities & BMSR_100T4) != 0) {
  456                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst));
  457                 PRINT("100baseT4");
  458         }
  459 
  460         if ((sc->mii_extcapabilities & EXTSR_MEDIAMASK) != 0) {
  461                 /*
  462                  * XXX Right now only handle 1000SX and 1000TX.  Need
  463                  * XXX to handle 1000LX and 1000CX somehow.
  464                  */
  465                 if ((sc->mii_extcapabilities & EXTSR_1000XHDX) != 0) {
  466                         sc->mii_anegticks = MII_ANEGTICKS_GIGE;
  467                         sc->mii_flags |= MIIF_IS_1000X;
  468                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0,
  469                             sc->mii_inst));
  470                         PRINT("1000baseSX");
  471                 }
  472                 if ((sc->mii_extcapabilities & EXTSR_1000XFDX) != 0) {
  473                         sc->mii_anegticks = MII_ANEGTICKS_GIGE;
  474                         sc->mii_flags |= MIIF_IS_1000X;
  475                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX,
  476                             sc->mii_inst));
  477                         PRINT("1000baseSX-FDX");
  478                         if ((sc->mii_flags & MIIF_DOPAUSE) != 0 &&
  479                             (sc->mii_flags & MIIF_NOMANPAUSE) == 0) {
  480                                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX,
  481                                     IFM_FDX | IFM_FLOW, sc->mii_inst));
  482                                 PRINT("1000baseSX-FDX-flow");
  483                         }
  484                         fdx = 1;
  485                 }
  486 
  487                 /*
  488                  * 1000baseT media needs to be able to manipulate
  489                  * master/slave mode.
  490                  *
  491                  * All 1000baseT PHYs have a 1000baseT control register.
  492                  */
  493                 if ((sc->mii_extcapabilities & EXTSR_1000THDX) != 0) {
  494                         sc->mii_anegticks = MII_ANEGTICKS_GIGE;
  495                         sc->mii_flags |= MIIF_HAVE_GTCR;
  496                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0,
  497                             sc->mii_inst));
  498                         PRINT("1000baseT");
  499                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T,
  500                             IFM_ETH_MASTER, sc->mii_inst));
  501                         PRINT("1000baseT-master");
  502                 }
  503                 if ((sc->mii_extcapabilities & EXTSR_1000TFDX) != 0) {
  504                         sc->mii_anegticks = MII_ANEGTICKS_GIGE;
  505                         sc->mii_flags |= MIIF_HAVE_GTCR;
  506                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX,
  507                             sc->mii_inst));
  508                         PRINT("1000baseT-FDX");
  509                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T,
  510                             IFM_FDX | IFM_ETH_MASTER, sc->mii_inst));
  511                         PRINT("1000baseT-FDX-master");
  512                         if ((sc->mii_flags & MIIF_DOPAUSE) != 0 &&
  513                             (sc->mii_flags & MIIF_NOMANPAUSE) == 0) {
  514                                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T,
  515                                     IFM_FDX | IFM_FLOW, sc->mii_inst));
  516                                 PRINT("1000baseT-FDX-flow");
  517                                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T,
  518                                     IFM_FDX | IFM_FLOW | IFM_ETH_MASTER,
  519                                     sc->mii_inst));
  520                                 PRINT("1000baseT-FDX-flow-master");
  521                         }
  522                         fdx = 1;
  523                 }
  524         }
  525 
  526         if ((sc->mii_capabilities & BMSR_ANEG) != 0) {
  527                 /* intentionally invalid index */
  528                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst));
  529                 PRINT("auto");
  530                 if (fdx != 0 && (sc->mii_flags & MIIF_DOPAUSE) != 0) {
  531                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, IFM_FLOW,
  532                             sc->mii_inst));
  533                         PRINT("auto-flow");
  534                 }
  535         }
  536 #undef ADD
  537 #undef PRINT
  538 }
  539 
  540 int
  541 mii_phy_detach(device_t dev)
  542 {
  543         struct mii_softc *sc;
  544 
  545         sc = device_get_softc(dev);
  546         sc->mii_dev = NULL;
  547         LIST_REMOVE(sc, mii_list);
  548         return (0);
  549 }
  550 
  551 const struct mii_phydesc *
  552 mii_phy_match_gen(const struct mii_attach_args *ma,
  553   const struct mii_phydesc *mpd, size_t len)
  554 {
  555 
  556         for (; mpd->mpd_name != NULL;
  557             mpd = (const struct mii_phydesc *)((const char *)mpd + len)) {
  558                 if (MII_OUI(ma->mii_id1, ma->mii_id2) == mpd->mpd_oui &&
  559                     MII_MODEL(ma->mii_id2) == mpd->mpd_model)
  560                         return (mpd);
  561         }
  562         return (NULL);
  563 }
  564 
  565 const struct mii_phydesc *
  566 mii_phy_match(const struct mii_attach_args *ma, const struct mii_phydesc *mpd)
  567 {
  568 
  569         return (mii_phy_match_gen(ma, mpd, sizeof(struct mii_phydesc)));
  570 }
  571 
  572 int
  573 mii_phy_dev_probe(device_t dev, const struct mii_phydesc *mpd, int mrv)
  574 {
  575 
  576         mpd = mii_phy_match(device_get_ivars(dev), mpd);
  577         if (mpd != NULL) {
  578                 device_set_desc(dev, mpd->mpd_name);
  579                 return (mrv);
  580         }
  581         return (ENXIO);
  582 }
  583 
  584 void
  585 mii_phy_dev_attach(device_t dev, u_int flags, const struct mii_phy_funcs *mpf,
  586     int add_media)
  587 {
  588         struct mii_softc *sc;
  589         struct mii_attach_args *ma;
  590         struct mii_data *mii;
  591 
  592         sc = device_get_softc(dev);
  593         ma = device_get_ivars(dev);
  594         sc->mii_dev = device_get_parent(dev);
  595         mii = ma->mii_data;
  596         LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
  597 
  598         sc->mii_flags = flags | miibus_get_flags(dev);
  599         sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
  600         sc->mii_mpd_model = MII_MODEL(ma->mii_id2);
  601         sc->mii_mpd_rev = MII_REV(ma->mii_id2);
  602         sc->mii_capmask = ma->mii_capmask;
  603         sc->mii_inst = mii->mii_instance++;
  604         sc->mii_phy = ma->mii_phyno;
  605         sc->mii_offset = ma->mii_offset;
  606         sc->mii_funcs = mpf;
  607         sc->mii_pdata = mii;
  608 
  609         if (bootverbose)
  610                 device_printf(dev, "OUI 0x%06x, model 0x%04x, rev. %d\n",
  611                     sc->mii_mpd_oui, sc->mii_mpd_model, sc->mii_mpd_rev);
  612 
  613         if (add_media == 0)
  614                 return;
  615 
  616         PHY_RESET(sc);
  617 
  618         sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & sc->mii_capmask;
  619         if (sc->mii_capabilities & BMSR_EXTSTAT)
  620                 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
  621         device_printf(dev, " ");
  622         mii_phy_add_media(sc);
  623         printf("\n");
  624 
  625         MIIBUS_MEDIAINIT(sc->mii_dev);
  626 }
  627 
  628 /*
  629  * Return the flow control status flag from MII_ANAR & MII_ANLPAR.
  630  */
  631 u_int
  632 mii_phy_flowstatus(struct mii_softc *sc)
  633 {
  634         int anar, anlpar;
  635 
  636         if ((sc->mii_flags & MIIF_DOPAUSE) == 0)
  637                 return (0);
  638 
  639         anar = PHY_READ(sc, MII_ANAR);
  640         anlpar = PHY_READ(sc, MII_ANLPAR);
  641 
  642         /*
  643          * Check for 1000BASE-X.  Autonegotiation is a bit
  644          * different on such devices.
  645          */
  646         if ((sc->mii_flags & MIIF_IS_1000X) != 0) {
  647                 anar <<= 3;
  648                 anlpar <<= 3;
  649         }
  650 
  651         if ((anar & ANAR_PAUSE_SYM) != 0 && (anlpar & ANLPAR_PAUSE_SYM) != 0)
  652                 return (IFM_FLOW | IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE);
  653 
  654         if ((anar & ANAR_PAUSE_SYM) == 0) {
  655                 if ((anar & ANAR_PAUSE_ASYM) != 0 &&
  656                     (anlpar & ANLPAR_PAUSE_TOWARDS) != 0)
  657                         return (IFM_FLOW | IFM_ETH_TXPAUSE);
  658                 else
  659                         return (0);
  660         }
  661 
  662         if ((anar & ANAR_PAUSE_ASYM) == 0) {
  663                 if ((anlpar & ANLPAR_PAUSE_SYM) != 0)
  664                         return (IFM_FLOW | IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE);
  665                 else
  666                         return (0);
  667         }
  668 
  669         switch ((anlpar & ANLPAR_PAUSE_TOWARDS)) {
  670         case ANLPAR_PAUSE_NONE:
  671                 return (0);
  672         case ANLPAR_PAUSE_ASYM:
  673                 return (IFM_FLOW | IFM_ETH_RXPAUSE);
  674         default:
  675                 return (IFM_FLOW | IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE);
  676         }
  677         /* NOTREACHED */
  678 }

Cache object: cd6e999e47f65604f5b9f8350c7c3c7c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.