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/netif/mii_layer/nsgphy.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 /*
    2  * Copyright (c) 2001 Wind River Systems
    3  * Copyright (c) 2001
    4  *      Bill Paul <wpaul@bsdi.com>.  All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. All advertising materials mentioning features or use of this software
   15  *    must display the following acknowledgement:
   16  *      This product includes software developed by Bill Paul.
   17  * 4. Neither the name of the author nor the names of any co-contributors
   18  *    may be used to endorse or promote products derived from this software
   19  *    without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
   25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   31  * THE POSSIBILITY OF SUCH DAMAGE.
   32  *
   33  * $FreeBSD: src/sys/dev/mii/nsgphy.c,v 1.1.2.3 2002/11/08 21:53:49 semenu Exp $
   34  */
   35 
   36 /*
   37  * Driver for the National Semiconductor DP83891 and DP83861
   38  * 10/100/1000 PHYs.
   39  * Datasheet available at: http://www.national.com/ds/DP/DP83861.pdf
   40  *
   41  * The DP83891 is the older NatSemi gigE PHY which isn't being sold
   42  * anymore. The DP83861 is its replacement, which is an 'enhanced'
   43  * firmware driven component. The major difference between the
   44  * two is that the 83891 can't generate interrupts, while the
   45  * 83861 can. (I think it wasn't originally designed to do this, but
   46  * it can now thanks to firmware updates.) The 83861 also allows
   47  * access to its internal RAM via indirect register access.
   48  */
   49 
   50 #include <sys/param.h>
   51 #include <sys/systm.h>
   52 #include <sys/kernel.h>
   53 #include <sys/socket.h>
   54 #include <sys/bus.h>
   55 
   56 #include <machine/clock.h>
   57 
   58 #include <net/if.h>
   59 #include <net/if_media.h>
   60 
   61 #include "mii.h"
   62 #include "miivar.h"
   63 #include "miidevs.h"
   64 
   65 #include "nsgphyreg.h"
   66 
   67 #include "miibus_if.h"
   68 
   69 static int nsgphy_probe         (device_t);
   70 static int nsgphy_attach        (device_t);
   71 
   72 static device_method_t nsgphy_methods[] = {
   73         /* device interface */
   74         DEVMETHOD(device_probe,         nsgphy_probe),
   75         DEVMETHOD(device_attach,        nsgphy_attach),
   76         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
   77         DEVMETHOD_END
   78 };
   79 
   80 static const struct mii_phydesc nsgphys[] = {
   81         MII_PHYDESC(NATSEMI,    DP83891),
   82         MII_PHYDESC(NATSEMI,    DP83861),
   83         MII_PHYDESC_NULL
   84 };
   85 
   86 static devclass_t nsgphy_devclass;
   87 
   88 static driver_t nsgphy_driver = {
   89         "nsgphy",
   90         nsgphy_methods,
   91         sizeof(struct mii_softc)
   92 };
   93 
   94 DRIVER_MODULE(nsgphy, miibus, nsgphy_driver, nsgphy_devclass, NULL, NULL);
   95 
   96 static int      nsgphy_service(struct mii_softc *, struct mii_data *, int);
   97 static void     nsgphy_status(struct mii_softc *);
   98 
   99 static int
  100 nsgphy_probe(device_t dev)
  101 {
  102         struct mii_attach_args *ma = device_get_ivars(dev);
  103         const struct mii_phydesc *mpd;
  104 
  105         mpd = mii_phy_match(ma, nsgphys);
  106         if (mpd != NULL) {
  107                 device_set_desc(dev, mpd->mpd_name);
  108                 return (0);
  109         }
  110         return(ENXIO);
  111 }
  112 
  113 static int
  114 nsgphy_attach(device_t dev)
  115 {
  116         struct mii_softc *sc;
  117         struct mii_attach_args *ma;
  118         struct mii_data *mii;
  119 
  120         sc = device_get_softc(dev);
  121         ma = device_get_ivars(dev);
  122         mii_softc_init(sc, ma);
  123         sc->mii_dev = device_get_parent(dev);
  124         mii = device_get_softc(sc->mii_dev);
  125         LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
  126 
  127         sc->mii_inst = mii->mii_instance;
  128         sc->mii_service = nsgphy_service;
  129         /*
  130          * Only retry autonegotiation every 17 seconds.
  131          * Actually, for gigE PHYs, we should wait longer, since
  132          * 5 seconds is the mimimum time the documentation
  133          * says to wait for a 1000mbps link to be established.
  134          */
  135         sc->mii_anegticks = 17;
  136         sc->mii_pdata = mii;
  137 
  138         sc->mii_flags |= MIIF_NOISOLATE;
  139         mii->mii_instance++;
  140 
  141 #define ADD(m, c)       ifmedia_add(&mii->mii_media, (m), (c), NULL)
  142 
  143         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
  144             MII_MEDIA_NONE);
  145 #if 0
  146         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
  147             MII_MEDIA_100_TX);
  148 #endif
  149 
  150         mii_phy_reset(sc);
  151 
  152         sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
  153         if (sc->mii_capabilities & BMSR_EXTSTAT)
  154                 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
  155 
  156         device_printf(dev, " ");
  157         if ((sc->mii_capabilities & BMSR_MEDIAMASK) ||
  158             (sc->mii_extcapabilities & EXTSR_MEDIAMASK))
  159                 mii_phy_add_media(sc);
  160         else
  161                 kprintf("no media present");
  162 
  163         kprintf("\n");
  164 #undef ADD
  165 
  166         MIIBUS_MEDIAINIT(sc->mii_dev);
  167         return(0);
  168 }
  169 
  170 int
  171 nsgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
  172 {
  173         struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
  174         int reg;
  175 
  176         switch (cmd) {
  177         case MII_POLLSTAT:
  178                 /*
  179                  * If we're not polling our PHY instance, just return.
  180                  */
  181                 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
  182                         return (0);
  183                 break;
  184 
  185         case MII_MEDIACHG:
  186                 /*
  187                  * If the media indicates a different PHY instance,
  188                  * isolate ourselves.
  189                  */
  190                 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
  191                         reg = PHY_READ(sc, MII_BMCR);
  192                         PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
  193                         return (0);
  194                 }
  195 
  196                 /*
  197                  * If the interface is not up, don't do anything.
  198                  */
  199                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
  200                         break;
  201 
  202                 mii_phy_set_media(sc);
  203                 break;
  204 
  205         case MII_TICK:
  206                 /*
  207                  * If we're not currently selected, just return.
  208                  */
  209                 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
  210                         return (0);
  211 
  212                 if (mii_phy_tick(sc) == EJUSTRETURN)
  213                         return (0);
  214                 break;
  215         }
  216 
  217         /* Update the media status. */
  218         nsgphy_status(sc);
  219 
  220         /* Callback if something changed. */
  221         mii_phy_update(sc, cmd);
  222         return (0);
  223 }
  224 
  225 static void
  226 nsgphy_status(struct mii_softc *sc)
  227 {
  228         struct mii_data *mii = sc->mii_pdata;
  229         int bmsr, bmcr, physup, anlpar, gstat;
  230 
  231         mii->mii_media_status = IFM_AVALID;
  232         mii->mii_media_active = IFM_ETHER;
  233 
  234         bmsr = PHY_READ(sc, NSGPHY_MII_BMSR);
  235         physup = PHY_READ(sc, NSGPHY_MII_PHYSUP);
  236         if (physup & NSGPHY_PHYSUP_LNKSTS)
  237                 mii->mii_media_status |= IFM_ACTIVE;
  238 
  239         bmcr = PHY_READ(sc, NSGPHY_MII_BMCR);
  240 
  241         if (bmcr & NSGPHY_BMCR_LOOP)
  242                 mii->mii_media_active |= IFM_LOOP;
  243 
  244         if (bmcr & NSGPHY_BMCR_AUTOEN) {
  245                 if ((bmsr & NSGPHY_BMSR_ACOMP) == 0) {
  246                         /* Erg, still trying, I guess... */
  247                         mii->mii_media_active |= IFM_NONE;
  248                         return;
  249                 }
  250                 anlpar = PHY_READ(sc, NSGPHY_MII_ANLPAR);
  251                 gstat = PHY_READ(sc, NSGPHY_MII_1000STS);
  252                 if (gstat & NSGPHY_1000STS_LPFD)
  253                         mii->mii_media_active |= IFM_1000_T | IFM_FDX;
  254                 else if (gstat & NSGPHY_1000STS_LPHD)
  255                         mii->mii_media_active |= IFM_1000_T | IFM_HDX;
  256                 else if (anlpar & NSGPHY_ANLPAR_100T4)
  257                         mii->mii_media_active |= IFM_100_T4;
  258                 else if (anlpar & NSGPHY_ANLPAR_100FDX)
  259                         mii->mii_media_active |= IFM_100_TX|IFM_FDX;
  260                 else if (anlpar & NSGPHY_ANLPAR_100HDX)
  261                         mii->mii_media_active |= IFM_100_TX;
  262                 else if (anlpar & NSGPHY_ANLPAR_10FDX)
  263                         mii->mii_media_active |= IFM_10_T|IFM_FDX;
  264                 else if (anlpar & NSGPHY_ANLPAR_10HDX)
  265                         mii->mii_media_active |= IFM_10_T|IFM_HDX;
  266                 else
  267                         mii->mii_media_active |= IFM_NONE;
  268                 return;
  269         }
  270 
  271         switch(bmcr & (NSGPHY_BMCR_SPD1|NSGPHY_BMCR_SPD0)) {
  272         case NSGPHY_S1000:
  273                 mii->mii_media_active |= IFM_1000_T;
  274                 break;
  275         case NSGPHY_S100:
  276                 mii->mii_media_active |= IFM_100_TX;
  277                 break;
  278         case NSGPHY_S10:
  279                 mii->mii_media_active |= IFM_10_T;
  280                 break;
  281         default:
  282                 break;
  283         }
  284 
  285         if (bmcr & NSGPHY_BMCR_FDX)
  286                 mii->mii_media_active |= IFM_FDX;
  287         else
  288                 mii->mii_media_active |= IFM_HDX;
  289 }

Cache object: e1cc2bb4eb4350979ee48b2341c8174d


[ 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.