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$");
   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_auto(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         { NULL, NULL }
   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 
  108         jsc = device_get_softc(dev);
  109         sc = &jsc->mii_sc;
  110         ma = device_get_ivars(dev);
  111         sc->mii_dev = device_get_parent(dev);
  112         mii = device_get_softc(sc->mii_dev);
  113         LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
  114 
  115         sc->mii_inst = mii->mii_instance;
  116         sc->mii_phy = ma->mii_phyno;
  117         sc->mii_service = jmphy_service;
  118         sc->mii_pdata = mii;
  119 
  120         mii->mii_instance++;
  121 
  122         jsc->mii_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
  123         jsc->mii_model = MII_MODEL(ma->mii_id2);
  124         jsc->mii_rev = MII_REV(ma->mii_id2);
  125         if (bootverbose)
  126                 device_printf(dev, "OUI 0x%06x, model 0x%04x, rev. %d\n",
  127                     jsc->mii_oui, jsc->mii_model, jsc->mii_rev);
  128 
  129         jmphy_reset(sc);
  130 
  131         sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
  132         if (sc->mii_capabilities & BMSR_EXTSTAT)
  133                 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
  134         device_printf(dev, " ");
  135         mii_phy_add_media(sc);
  136         printf("\n");
  137 
  138         MIIBUS_MEDIAINIT(sc->mii_dev);
  139         return(0);
  140 }
  141 
  142 static int
  143 jmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
  144 {
  145         struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
  146         uint16_t bmcr;
  147 
  148         switch (cmd) {
  149         case MII_POLLSTAT:
  150                 /*
  151                  * If we're not polling our PHY instance, just return.
  152                  */
  153                 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
  154                         return (0);
  155                 break;
  156 
  157         case MII_MEDIACHG:
  158                 /*
  159                  * If the media indicates a different PHY instance,
  160                  * isolate ourselves.
  161                  */
  162                 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
  163                         bmcr = PHY_READ(sc, MII_BMCR);
  164                         PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO);
  165                         return (0);
  166                 }
  167 
  168                 /*
  169                  * If the interface is not up, don't do anything.
  170                  */
  171                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
  172                         break;
  173 
  174                 if (jmphy_auto(sc, ife) != EJUSTRETURN)
  175                         return (EINVAL);
  176                 break;
  177 
  178         case MII_TICK:
  179                 /*
  180                  * If we're not currently selected, just return.
  181                  */
  182                 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
  183                         return (0);
  184 
  185                 /*
  186                  * Is the interface even up?
  187                  */
  188                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
  189                         return (0);
  190 
  191                 /*
  192                  * Only used for autonegotiation.
  193                  */
  194                 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
  195                         sc->mii_ticks = 0;
  196                         break;
  197                 }
  198 
  199                 /* Check for link. */
  200                 if ((PHY_READ(sc, JMPHY_SSR) & JMPHY_SSR_LINK_UP) != 0) {
  201                         sc->mii_ticks = 0;
  202                         break;
  203                 }
  204 
  205                 /* Announce link loss right after it happens. */
  206                 if (sc->mii_ticks++ == 0)
  207                         break;
  208                 if (sc->mii_ticks <= sc->mii_anegticks)
  209                         return (0);
  210 
  211                 sc->mii_ticks = 0;
  212                 jmphy_auto(sc, ife);
  213                 break;
  214         }
  215 
  216         /* Update the media status. */
  217         jmphy_status(sc);
  218 
  219         /* Callback if something changed. */
  220         mii_phy_update(sc, cmd);
  221         return (0);
  222 }
  223 
  224 static void
  225 jmphy_status(struct mii_softc *sc)
  226 {
  227         struct mii_data *mii = sc->mii_pdata;
  228         int bmcr, ssr;
  229 
  230         mii->mii_media_status = IFM_AVALID;
  231         mii->mii_media_active = IFM_ETHER;
  232 
  233         ssr = PHY_READ(sc, JMPHY_SSR);
  234         if ((ssr & JMPHY_SSR_LINK_UP) != 0)
  235                 mii->mii_media_status |= IFM_ACTIVE;
  236 
  237         bmcr = PHY_READ(sc, MII_BMCR);
  238         if ((bmcr & BMCR_ISO) != 0) {
  239                 mii->mii_media_active |= IFM_NONE;
  240                 mii->mii_media_status = 0;
  241                 return;
  242         }
  243 
  244         if ((bmcr & BMCR_LOOP) != 0)
  245                 mii->mii_media_active |= IFM_LOOP;
  246 
  247         if ((ssr & JMPHY_SSR_SPD_DPLX_RESOLVED) == 0) {
  248                 /* Erg, still trying, I guess... */
  249                 mii->mii_media_active |= IFM_NONE;
  250                 return;
  251         }
  252 
  253         switch ((ssr & JMPHY_SSR_SPEED_MASK)) {
  254         case JMPHY_SSR_SPEED_1000:
  255                 mii->mii_media_active |= IFM_1000_T;
  256                 /*
  257                  * jmphy(4) got a valid link so reset mii_ticks.
  258                  * Resetting mii_ticks is needed in order to
  259                  * detect link loss after auto-negotiation.
  260                  */
  261                 sc->mii_ticks = 0;
  262                 break;
  263         case JMPHY_SSR_SPEED_100:
  264                 mii->mii_media_active |= IFM_100_TX;
  265                 sc->mii_ticks = 0;
  266                 break;
  267         case JMPHY_SSR_SPEED_10:
  268                 mii->mii_media_active |= IFM_10_T;
  269                 sc->mii_ticks = 0;
  270                 break;
  271         default:
  272                 mii->mii_media_active |= IFM_NONE;
  273                 return;
  274         }
  275 
  276         if ((ssr & JMPHY_SSR_DUPLEX) != 0)
  277                 mii->mii_media_active |= IFM_FDX;
  278         else
  279                 mii->mii_media_active |= IFM_HDX;
  280         /* XXX Flow-control. */
  281 #ifdef notyet
  282         if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) {
  283                 if ((PHY_READ(sc, MII_100T2SR) & GTSR_MS_RES) != 0)
  284                         mii->mii_media_active |= IFM_ETH_MASTER;
  285         }
  286 #endif
  287 }
  288 
  289 static void
  290 jmphy_reset(struct mii_softc *sc)
  291 {
  292         struct jmphy_softc *jsc;
  293         int i;
  294 
  295         jsc = (struct jmphy_softc *)sc;
  296 
  297         /* Disable sleep mode. */
  298         PHY_WRITE(sc, JMPHY_TMCTL,
  299             PHY_READ(sc, JMPHY_TMCTL) & ~JMPHY_TMCTL_SLEEP_ENB);
  300         PHY_WRITE(sc, MII_BMCR, BMCR_RESET | BMCR_AUTOEN);
  301 
  302         for (i = 0; i < 1000; i++) {
  303                 DELAY(1);
  304                 if ((PHY_READ(sc, MII_BMCR) & BMCR_RESET) == 0)
  305                         break;
  306         }
  307 }
  308 
  309 static uint16_t
  310 jmphy_anar(struct ifmedia_entry *ife)
  311 {
  312         uint16_t anar;
  313 
  314         anar = 0;
  315         switch (IFM_SUBTYPE(ife->ifm_media)) {
  316         case IFM_AUTO:
  317                 anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10;
  318                 break;
  319         case IFM_1000_T:
  320                 break;
  321         case IFM_100_TX:
  322                 anar |= ANAR_TX | ANAR_TX_FD;
  323                 break;
  324         case IFM_10_T:
  325                 anar |= ANAR_10 | ANAR_10_FD;
  326                 break;
  327         default:
  328                 break;
  329         }
  330 
  331         return (anar);
  332 }
  333 
  334 static int
  335 jmphy_auto(struct mii_softc *sc, struct ifmedia_entry *ife)
  336 {
  337         uint16_t anar, bmcr, gig;
  338 
  339         gig = 0;
  340         bmcr = PHY_READ(sc, MII_BMCR);
  341         switch (IFM_SUBTYPE(ife->ifm_media)) {
  342         case IFM_AUTO:
  343                 gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
  344                 break;
  345         case IFM_1000_T:
  346                 gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
  347                 break;
  348         case IFM_100_TX:
  349         case IFM_10_T:
  350                 break;
  351         case IFM_NONE:
  352                 PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO | BMCR_PDOWN);
  353                 return (EJUSTRETURN);
  354         default:
  355                 return (EINVAL);
  356         }
  357 
  358         if ((ife->ifm_media & IFM_LOOP) != 0)
  359                 bmcr |= BMCR_LOOP;
  360 
  361         anar = jmphy_anar(ife);
  362         /* XXX Always advertise pause capability. */
  363         anar |= (3 << 10);
  364 
  365         if ((sc->mii_flags & MIIF_HAVE_GTCR) != 0) {
  366 #ifdef notyet
  367                 struct mii_data *mii;
  368 
  369                 mii = sc->mii_pdata;
  370                 if ((mii->mii_media.ifm_media & IFM_ETH_MASTER) != 0)
  371                         gig |= GTCR_MAN_MS | GTCR_MAN_ADV;
  372 #endif
  373                 PHY_WRITE(sc, MII_100T2CR, gig);
  374         }
  375         PHY_WRITE(sc, MII_ANAR, anar | ANAR_CSMA);
  376         PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_AUTOEN | BMCR_STARTNEG);
  377 
  378         return (EJUSTRETURN);
  379 }

Cache object: 2a42ca26f97969432c6f3ebd806d739d


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