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/jmphy.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) 2008, Pyun YongHyeon <yongari@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice unmodified, this list of conditions, and the following
   10  *    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  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD: releng/8.4/sys/dev/mii/jmphy.c 230718 2012-01-29 01:35:14Z marius $");
   30 
   31 /*
   32  * Driver for the JMicron JMP211 10/100/1000, JMP202 10/100 PHY.
   33  */
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/kernel.h>
   38 #include <sys/module.h>
   39 #include <sys/socket.h>
   40 #include <sys/bus.h>
   41 
   42 #include <net/if.h>
   43 #include <net/if_media.h>
   44 
   45 #include <dev/mii/mii.h>
   46 #include <dev/mii/miivar.h>
   47 #include "miidevs.h"
   48 
   49 #include <dev/mii/jmphyreg.h>
   50 
   51 #include "miibus_if.h"
   52 
   53 static int      jmphy_probe(device_t);
   54 static int      jmphy_attach(device_t);
   55 static void     jmphy_reset(struct mii_softc *);
   56 static uint16_t jmphy_anar(struct ifmedia_entry *);
   57 static int      jmphy_setmedia(struct mii_softc *, struct ifmedia_entry *);
   58 
   59 struct jmphy_softc {
   60         struct mii_softc mii_sc;
   61         int mii_oui;
   62         int mii_model;
   63         int mii_rev;
   64 };
   65 
   66 static device_method_t jmphy_methods[] = {
   67         /* Device interface. */
   68         DEVMETHOD(device_probe,         jmphy_probe),
   69         DEVMETHOD(device_attach,        jmphy_attach),
   70         DEVMETHOD(device_detach,        mii_phy_detach),
   71         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
   72         DEVMETHOD_END
   73 };
   74 
   75 static devclass_t jmphy_devclass;
   76 static driver_t jmphy_driver = {
   77         "jmphy",
   78         jmphy_methods,
   79         sizeof(struct jmphy_softc)
   80 };
   81 
   82 DRIVER_MODULE(jmphy, miibus, jmphy_driver, jmphy_devclass, 0, 0);
   83 
   84 static int      jmphy_service(struct mii_softc *, struct mii_data *, int);
   85 static void     jmphy_status(struct mii_softc *);
   86 
   87 static const struct mii_phydesc jmphys[] = {
   88         MII_PHY_DESC(JMICRON, JMP202),
   89         MII_PHY_DESC(JMICRON, JMP211),
   90         MII_PHY_END
   91 };
   92 
   93 static int
   94 jmphy_probe(device_t dev)
   95 {
   96 
   97         return (mii_phy_dev_probe(dev, jmphys, BUS_PROBE_DEFAULT));
   98 }
   99 
  100 static int
  101 jmphy_attach(device_t dev)
  102 {
  103         struct jmphy_softc *jsc;
  104         struct mii_softc *sc;
  105         struct mii_attach_args *ma;
  106         struct mii_data *mii;
  107         struct ifnet *ifp;
  108 
  109         jsc = device_get_softc(dev);
  110         sc = &jsc->mii_sc;
  111         ma = device_get_ivars(dev);
  112         sc->mii_dev = device_get_parent(dev);
  113         mii = ma->mii_data;
  114         LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
  115 
  116         sc->mii_flags = miibus_get_flags(dev);
  117         sc->mii_inst = mii->mii_instance++;
  118         sc->mii_phy = ma->mii_phyno;
  119         sc->mii_service = jmphy_service;
  120         sc->mii_pdata = mii;
  121 
  122         ifp = sc->mii_pdata->mii_ifp;
  123         if (strcmp(ifp->if_dname, "jme") == 0 &&
  124             (sc->mii_flags & MIIF_MACPRIV0) != 0)
  125                 sc->mii_flags |= MIIF_PHYPRIV0;
  126         jsc->mii_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
  127         jsc->mii_model = MII_MODEL(ma->mii_id2);
  128         jsc->mii_rev = MII_REV(ma->mii_id2);
  129         if (bootverbose)
  130                 device_printf(dev, "OUI 0x%06x, model 0x%04x, rev. %d\n",
  131                     jsc->mii_oui, jsc->mii_model, jsc->mii_rev);
  132 
  133         jmphy_reset(sc);
  134 
  135         sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
  136         if (sc->mii_capabilities & BMSR_EXTSTAT)
  137                 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
  138         device_printf(dev, " ");
  139         mii_phy_add_media(sc);
  140         printf("\n");
  141 
  142         MIIBUS_MEDIAINIT(sc->mii_dev);
  143         return (0);
  144 }
  145 
  146 static int
  147 jmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
  148 {
  149         struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
  150 
  151         switch (cmd) {
  152         case MII_POLLSTAT:
  153                 break;
  154 
  155         case MII_MEDIACHG:
  156                 /*
  157                  * If the interface is not up, don't do anything.
  158                  */
  159                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
  160                         break;
  161 
  162                 if (jmphy_setmedia(sc, ife) != EJUSTRETURN)
  163                         return (EINVAL);
  164                 break;
  165 
  166         case MII_TICK:
  167                 /*
  168                  * Is the interface even up?
  169                  */
  170                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
  171                         return (0);
  172 
  173                 /*
  174                  * Only used for autonegotiation.
  175                  */
  176                 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
  177                         sc->mii_ticks = 0;
  178                         break;
  179                 }
  180 
  181                 /* Check for link. */
  182                 if ((PHY_READ(sc, JMPHY_SSR) & JMPHY_SSR_LINK_UP) != 0) {
  183                         sc->mii_ticks = 0;
  184                         break;
  185                 }
  186 
  187                 /* Announce link loss right after it happens. */
  188                 if (sc->mii_ticks++ == 0)
  189                         break;
  190                 if (sc->mii_ticks <= sc->mii_anegticks)
  191                         return (0);
  192 
  193                 sc->mii_ticks = 0;
  194                 (void)jmphy_setmedia(sc, ife);
  195                 break;
  196         }
  197 
  198         /* Update the media status. */
  199         jmphy_status(sc);
  200 
  201         /* Callback if something changed. */
  202         mii_phy_update(sc, cmd);
  203         return (0);
  204 }
  205 
  206 static void
  207 jmphy_status(struct mii_softc *sc)
  208 {
  209         struct mii_data *mii = sc->mii_pdata;
  210         int bmcr, ssr;
  211 
  212         mii->mii_media_status = IFM_AVALID;
  213         mii->mii_media_active = IFM_ETHER;
  214 
  215         ssr = PHY_READ(sc, JMPHY_SSR);
  216         if ((ssr & JMPHY_SSR_LINK_UP) != 0)
  217                 mii->mii_media_status |= IFM_ACTIVE;
  218 
  219         bmcr = PHY_READ(sc, MII_BMCR);
  220         if ((bmcr & BMCR_ISO) != 0) {
  221                 mii->mii_media_active |= IFM_NONE;
  222                 mii->mii_media_status = 0;
  223                 return;
  224         }
  225 
  226         if ((bmcr & BMCR_LOOP) != 0)
  227                 mii->mii_media_active |= IFM_LOOP;
  228 
  229         if ((ssr & JMPHY_SSR_SPD_DPLX_RESOLVED) == 0) {
  230                 /* Erg, still trying, I guess... */
  231                 mii->mii_media_active |= IFM_NONE;
  232                 return;
  233         }
  234 
  235         switch ((ssr & JMPHY_SSR_SPEED_MASK)) {
  236         case JMPHY_SSR_SPEED_1000:
  237                 mii->mii_media_active |= IFM_1000_T;
  238                 /*
  239                  * jmphy(4) got a valid link so reset mii_ticks.
  240                  * Resetting mii_ticks is needed in order to
  241                  * detect link loss after auto-negotiation.
  242                  */
  243                 sc->mii_ticks = 0;
  244                 break;
  245         case JMPHY_SSR_SPEED_100:
  246                 mii->mii_media_active |= IFM_100_TX;
  247                 sc->mii_ticks = 0;
  248                 break;
  249         case JMPHY_SSR_SPEED_10:
  250                 mii->mii_media_active |= IFM_10_T;
  251                 sc->mii_ticks = 0;
  252                 break;
  253         default:
  254                 mii->mii_media_active |= IFM_NONE;
  255                 return;
  256         }
  257 
  258         if ((ssr & JMPHY_SSR_DUPLEX) != 0)
  259                 mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc);
  260         else
  261                 mii->mii_media_active |= IFM_HDX;
  262 
  263         if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) {
  264                 if ((PHY_READ(sc, MII_100T2SR) & GTSR_MS_RES) != 0)
  265                         mii->mii_media_active |= IFM_ETH_MASTER;
  266         }
  267 }
  268 
  269 static void
  270 jmphy_reset(struct mii_softc *sc)
  271 {
  272         uint16_t t2cr, val;
  273         int i;
  274 
  275         /* Disable sleep mode. */
  276         PHY_WRITE(sc, JMPHY_TMCTL,
  277             PHY_READ(sc, JMPHY_TMCTL) & ~JMPHY_TMCTL_SLEEP_ENB);
  278         PHY_WRITE(sc, MII_BMCR, BMCR_RESET | BMCR_AUTOEN);
  279 
  280         for (i = 0; i < 1000; i++) {
  281                 DELAY(1);
  282                 if ((PHY_READ(sc, MII_BMCR) & BMCR_RESET) == 0)
  283                         break;
  284         }
  285         /* Perform vendor recommended PHY calibration. */
  286         if ((sc->mii_flags & MIIF_PHYPRIV0) != 0) {
  287                 /* Select PHY test mode 1. */
  288                 t2cr = PHY_READ(sc, MII_100T2CR);
  289                 t2cr &= ~GTCR_TEST_MASK;
  290                 t2cr |= 0x2000;
  291                 PHY_WRITE(sc, MII_100T2CR, t2cr);
  292                 /* Apply calibration patch. */
  293                 PHY_WRITE(sc, JMPHY_SPEC_ADDR, JMPHY_SPEC_ADDR_READ |
  294                     JMPHY_EXT_COMM_2);
  295                 val = PHY_READ(sc, JMPHY_SPEC_DATA);
  296                 val &= ~0x0002;
  297                 val |= 0x0010 | 0x0001;
  298                 PHY_WRITE(sc, JMPHY_SPEC_DATA, val);
  299                 PHY_WRITE(sc, JMPHY_SPEC_ADDR, JMPHY_SPEC_ADDR_WRITE |
  300                     JMPHY_EXT_COMM_2);
  301 
  302                 /* XXX 20ms to complete recalibration. */
  303                 DELAY(20 * 1000);
  304 
  305                 PHY_READ(sc, MII_100T2CR);
  306                 PHY_WRITE(sc, JMPHY_SPEC_ADDR, JMPHY_SPEC_ADDR_READ |
  307                     JMPHY_EXT_COMM_2);
  308                 val = PHY_READ(sc, JMPHY_SPEC_DATA);
  309                 val &= ~(0x0001 | 0x0002 | 0x0010);
  310                 PHY_WRITE(sc, JMPHY_SPEC_DATA, val);
  311                 PHY_WRITE(sc, JMPHY_SPEC_ADDR, JMPHY_SPEC_ADDR_WRITE |
  312                     JMPHY_EXT_COMM_2);
  313                 /* Disable PHY test mode. */
  314                 PHY_READ(sc, MII_100T2CR);
  315                 t2cr &= ~GTCR_TEST_MASK;
  316                 PHY_WRITE(sc, MII_100T2CR, t2cr);
  317         }
  318 }
  319 
  320 static uint16_t
  321 jmphy_anar(struct ifmedia_entry *ife)
  322 {
  323         uint16_t anar;
  324 
  325         anar = 0;
  326         switch (IFM_SUBTYPE(ife->ifm_media)) {
  327         case IFM_AUTO:
  328                 anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10;
  329                 break;
  330         case IFM_1000_T:
  331                 break;
  332         case IFM_100_TX:
  333                 anar |= ANAR_TX | ANAR_TX_FD;
  334                 break;
  335         case IFM_10_T:
  336                 anar |= ANAR_10 | ANAR_10_FD;
  337                 break;
  338         default:
  339                 break;
  340         }
  341 
  342         return (anar);
  343 }
  344 
  345 static int
  346 jmphy_setmedia(struct mii_softc *sc, struct ifmedia_entry *ife)
  347 {
  348         uint16_t anar, bmcr, gig;
  349 
  350         gig = 0;
  351         bmcr = PHY_READ(sc, MII_BMCR);
  352         switch (IFM_SUBTYPE(ife->ifm_media)) {
  353         case IFM_AUTO:
  354                 gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
  355                 break;
  356         case IFM_1000_T:
  357                 gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
  358                 break;
  359         case IFM_100_TX:
  360         case IFM_10_T:
  361                 break;
  362         case IFM_NONE:
  363                 PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO | BMCR_PDOWN);
  364                 return (EJUSTRETURN);
  365         default:
  366                 return (EINVAL);
  367         }
  368 
  369         if ((ife->ifm_media & IFM_LOOP) != 0)
  370                 bmcr |= BMCR_LOOP;
  371 
  372         anar = jmphy_anar(ife);
  373         if ((IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO ||
  374             (ife->ifm_media & IFM_FDX) != 0) &&
  375             ((ife->ifm_media & IFM_FLOW) != 0 ||
  376             (sc->mii_flags & MIIF_FORCEPAUSE) != 0))
  377                 anar |= ANAR_PAUSE_TOWARDS;
  378 
  379         if ((sc->mii_flags & MIIF_HAVE_GTCR) != 0) {
  380                 if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) {
  381                         gig |= GTCR_MAN_MS;
  382                         if ((ife->ifm_media & IFM_ETH_MASTER) != 0)
  383                                 gig |= GTCR_ADV_MS;
  384                 }
  385                 PHY_WRITE(sc, MII_100T2CR, gig);
  386         }
  387         PHY_WRITE(sc, MII_ANAR, anar | ANAR_CSMA);
  388         PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_AUTOEN | BMCR_STARTNEG);
  389 
  390         return (EJUSTRETURN);
  391 }

Cache object: cdaefe5a02f0ed00bf9e7a6dfe485ac0


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