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/tlphy.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: tlphy.c,v 1.18 1999/05/14 11:40:28 drochner Exp $      */
    2 
    3 /*-
    4  * SPDX-License-Identifier: BSD-2-Clause-NetBSD AND BSD-2-Clause
    5  *
    6  * Copyright (c) 1998, 1999 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 /*-
   36  * Copyright (c) 1997 Manuel Bouyer.  All rights reserved.
   37  *
   38  * Redistribution and use in source and binary forms, with or without
   39  * modification, are permitted provided that the following conditions
   40  * are met:
   41  * 1. Redistributions of source code must retain the above copyright
   42  *    notice, this list of conditions and the following disclaimer.
   43  * 2. Redistributions in binary form must reproduce the above copyright
   44  *    notice, this list of conditions and the following disclaimer in the
   45  *    documentation and/or other materials provided with the distribution.
   46  *
   47  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   48  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   49  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   50  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   51  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   52  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   53  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   54  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   55  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   56  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   57  */
   58 
   59 #include <sys/cdefs.h>
   60 __FBSDID("$FreeBSD$");
   61 
   62 /*
   63  * Driver for Texas Instruments's ThunderLAN PHYs
   64  */
   65 
   66 #include <sys/param.h>
   67 #include <sys/systm.h>
   68 #include <sys/kernel.h>
   69 #include <sys/socket.h>
   70 #include <sys/errno.h>
   71 #include <sys/module.h>
   72 #include <sys/bus.h>
   73 #include <sys/malloc.h>
   74 
   75 #include <machine/bus.h>
   76 
   77 #include <net/if.h>
   78 #include <net/if_media.h>
   79 
   80 #include <dev/mii/mii.h>
   81 #include <dev/mii/miivar.h>
   82 #include "miidevs.h"
   83 
   84 #include <dev/mii/tlphyreg.h>
   85 
   86 #include "miibus_if.h"
   87 
   88 struct tlphy_softc {
   89         struct mii_softc sc_mii;                /* generic PHY */
   90         int sc_need_acomp;
   91 };
   92 
   93 static int tlphy_probe(device_t);
   94 static int tlphy_attach(device_t);
   95 
   96 static device_method_t tlphy_methods[] = {
   97         /* device interface */
   98         DEVMETHOD(device_probe,         tlphy_probe),
   99         DEVMETHOD(device_attach,        tlphy_attach),
  100         DEVMETHOD(device_detach,        mii_phy_detach),
  101         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  102         DEVMETHOD_END
  103 };
  104 
  105 static devclass_t tlphy_devclass;
  106 
  107 static driver_t tlphy_driver = {
  108         "tlphy",
  109         tlphy_methods,
  110         sizeof(struct tlphy_softc)
  111 };
  112 
  113 DRIVER_MODULE(tlphy, miibus, tlphy_driver, tlphy_devclass, 0, 0);
  114 
  115 static int      tlphy_service(struct mii_softc *, struct mii_data *, int);
  116 static int      tlphy_auto(struct tlphy_softc *);
  117 static void     tlphy_acomp(struct tlphy_softc *);
  118 static void     tlphy_status(struct mii_softc *);
  119 
  120 static const struct mii_phydesc tlphys[] = {
  121         MII_PHY_DESC(TI, TLAN10T),
  122         MII_PHY_END
  123 };
  124 
  125 static const struct mii_phy_funcs tlphy_funcs = {
  126         tlphy_service,
  127         tlphy_status,
  128         mii_phy_reset
  129 };
  130 
  131 static int
  132 tlphy_probe(device_t dev)
  133 {
  134 
  135         if (!mii_dev_mac_match(dev, "tl"))
  136                 return (ENXIO);
  137         return (mii_phy_dev_probe(dev, tlphys, BUS_PROBE_DEFAULT));
  138 }
  139 
  140 static int
  141 tlphy_attach(device_t dev)
  142 {
  143         device_t *devlist;
  144         struct mii_softc *other, *sc_mii;
  145         const char *sep = "";
  146         int capmask, devs, i;
  147 
  148         sc_mii = device_get_softc(dev);
  149 
  150         mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &tlphy_funcs, 0);
  151 
  152         /*
  153          * Note that if we're on a device that also supports 100baseTX,
  154          * we are not going to want to use the built-in 10baseT port,
  155          * since there will be another PHY on the MII wired up to the
  156          * UTP connector.
  157          */
  158         capmask = BMSR_DEFCAPMASK;
  159         if (sc_mii->mii_inst &&
  160             device_get_children(sc_mii->mii_dev, &devlist, &devs) == 0) {
  161                 for (i = 0; i < devs; i++) {
  162                         if (devlist[i] != dev) {
  163                                 other = device_get_softc(devlist[i]);
  164                                 capmask &= ~other->mii_capabilities;
  165                                 break;
  166                         }
  167                 }
  168                 free(devlist, M_TEMP);
  169         }
  170 
  171         PHY_RESET(sc_mii);
  172 
  173         sc_mii->mii_capabilities = PHY_READ(sc_mii, MII_BMSR) & capmask;
  174 
  175 #define ADD(m, c)                                                       \
  176     ifmedia_add(&sc_mii->mii_pdata->mii_media, (m), (c), NULL)
  177 #define PRINT(s)        printf("%s%s", sep, s); sep = ", "
  178 
  179         if ((sc_mii->mii_flags & (MIIF_MACPRIV0 | MIIF_MACPRIV1)) != 0 &&
  180             (sc_mii->mii_capabilities & BMSR_MEDIAMASK) != 0)
  181                 device_printf(dev, " ");
  182         if ((sc_mii->mii_flags & MIIF_MACPRIV0) != 0) {
  183                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_2, 0, sc_mii->mii_inst),
  184                     0);
  185                 PRINT("10base2/BNC");
  186         }
  187         if ((sc_mii->mii_flags & MIIF_MACPRIV1) != 0) {
  188                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_5, 0, sc_mii->mii_inst),
  189                     0);
  190                 PRINT("10base5/AUI");
  191         }
  192         if ((sc_mii->mii_capabilities & BMSR_MEDIAMASK) != 0) {
  193                 printf("%s", sep);
  194                 mii_phy_add_media(sc_mii);
  195         }
  196         if ((sc_mii->mii_flags & (MIIF_MACPRIV0 | MIIF_MACPRIV1)) != 0 &&
  197             (sc_mii->mii_capabilities & BMSR_MEDIAMASK) != 0)
  198                 printf("\n");
  199 #undef ADD
  200 #undef PRINT
  201 
  202         MIIBUS_MEDIAINIT(sc_mii->mii_dev);
  203         return (0);
  204 }
  205 
  206 static int
  207 tlphy_service(struct mii_softc *self, struct mii_data *mii, int cmd)
  208 {
  209         struct tlphy_softc *sc = (struct tlphy_softc *)self;
  210         struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
  211         int reg;
  212 
  213         if (sc->sc_need_acomp)
  214                 tlphy_acomp(sc);
  215 
  216         switch (cmd) {
  217         case MII_POLLSTAT:
  218                 break;
  219 
  220         case MII_MEDIACHG:
  221                 switch (IFM_SUBTYPE(ife->ifm_media)) {
  222                 case IFM_AUTO:
  223                         /*
  224                          * The ThunderLAN PHY doesn't self-configure after
  225                          * an autonegotiation cycle, so there's no such
  226                          * thing as "already in auto mode".
  227                          */
  228                         (void)tlphy_auto(sc);
  229                         break;
  230                 case IFM_10_2:
  231                 case IFM_10_5:
  232                         PHY_WRITE(&sc->sc_mii, MII_BMCR, 0);
  233                         PHY_WRITE(&sc->sc_mii, MII_TLPHY_CTRL, CTRL_AUISEL);
  234                         DELAY(100000);
  235                         break;
  236                 default:
  237                         PHY_WRITE(&sc->sc_mii, MII_TLPHY_CTRL, 0);
  238                         DELAY(100000);
  239                         mii_phy_setmedia(&sc->sc_mii);
  240                 }
  241                 break;
  242 
  243         case MII_TICK:
  244                 /*
  245                  * Only used for autonegotiation.
  246                  */
  247                 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
  248                         break;
  249 
  250                 /*
  251                  * Check to see if we have link.  If we do, we don't
  252                  * need to restart the autonegotiation process.  Read
  253                  * the BMSR twice in case it's latched.
  254                  *
  255                  * XXX WHAT ABOUT CHECKING LINK ON THE BNC/AUI?!
  256                  */
  257                 reg = PHY_READ(&sc->sc_mii, MII_BMSR) |
  258                     PHY_READ(&sc->sc_mii, MII_BMSR);
  259                 if (reg & BMSR_LINK)
  260                         break;
  261 
  262                 /*
  263                  * Only retry autonegotiation every 5 seconds.
  264                  */
  265                 if (++sc->sc_mii.mii_ticks <= MII_ANEGTICKS)
  266                         break;
  267 
  268                 sc->sc_mii.mii_ticks = 0;
  269                 PHY_RESET(&sc->sc_mii);
  270                 (void)tlphy_auto(sc);
  271                 return (0);
  272         }
  273 
  274         /* Update the media status. */
  275         PHY_STATUS(self);
  276 
  277         /* Callback if something changed. */
  278         mii_phy_update(&sc->sc_mii, cmd);
  279         return (0);
  280 }
  281 
  282 static void
  283 tlphy_status(struct mii_softc *self)
  284 {
  285         struct tlphy_softc *sc = (struct tlphy_softc *)self;
  286         struct mii_data *mii = sc->sc_mii.mii_pdata;
  287         int bmsr, bmcr, tlctrl;
  288 
  289         mii->mii_media_status = IFM_AVALID;
  290         mii->mii_media_active = IFM_ETHER;
  291 
  292         bmcr = PHY_READ(&sc->sc_mii, MII_BMCR);
  293         if (bmcr & BMCR_ISO) {
  294                 mii->mii_media_active |= IFM_NONE;
  295                 mii->mii_media_status = 0;
  296                 return;
  297         }
  298 
  299         tlctrl = PHY_READ(&sc->sc_mii, MII_TLPHY_CTRL);
  300         if (tlctrl & CTRL_AUISEL) {
  301                 mii->mii_media_status = 0;
  302                 mii->mii_media_active = mii->mii_media.ifm_cur->ifm_media;
  303                 return;
  304         }
  305 
  306         bmsr = PHY_READ(&sc->sc_mii, MII_BMSR) |
  307             PHY_READ(&sc->sc_mii, MII_BMSR);
  308         if (bmsr & BMSR_LINK)
  309                 mii->mii_media_status |= IFM_ACTIVE;
  310 
  311         if (bmcr & BMCR_LOOP)
  312                 mii->mii_media_active |= IFM_LOOP;
  313 
  314         /*
  315          * Grr, braindead ThunderLAN PHY doesn't have any way to
  316          * tell which media is actually active.  (Note it also
  317          * doesn't self-configure after autonegotiation.)  We
  318          * just have to report what's in the BMCR.
  319          */
  320         if (bmcr & BMCR_FDX)
  321                 mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(self);
  322         else
  323                 mii->mii_media_active |= IFM_HDX;
  324         mii->mii_media_active |= IFM_10_T;
  325 }
  326 
  327 static int
  328 tlphy_auto(struct tlphy_softc *sc)
  329 {
  330         int error;
  331 
  332         switch ((error = mii_phy_auto(&sc->sc_mii))) {
  333         case EIO:
  334                 /*
  335                  * Just assume we're not in full-duplex mode.
  336                  * XXX Check link and try AUI/BNC?
  337                  */
  338                 PHY_WRITE(&sc->sc_mii, MII_BMCR, 0);
  339                 break;
  340 
  341         case EJUSTRETURN:
  342                 /* Flag that we need to program when it completes. */
  343                 sc->sc_need_acomp = 1;
  344                 break;
  345 
  346         default:
  347                 tlphy_acomp(sc);
  348         }
  349 
  350         return (error);
  351 }
  352 
  353 static void
  354 tlphy_acomp(struct tlphy_softc *sc)
  355 {
  356         int aner, anlpar;
  357 
  358         sc->sc_need_acomp = 0;
  359 
  360         /*
  361          * Grr, braindead ThunderLAN PHY doesn't self-configure
  362          * after autonegotiation.  We have to do it ourselves
  363          * based on the link partner status.
  364          */
  365 
  366         aner = PHY_READ(&sc->sc_mii, MII_ANER);
  367         if (aner & ANER_LPAN) {
  368                 anlpar = PHY_READ(&sc->sc_mii, MII_ANLPAR) &
  369                     PHY_READ(&sc->sc_mii, MII_ANAR);
  370                 if (anlpar & ANAR_10_FD) {
  371                         PHY_WRITE(&sc->sc_mii, MII_BMCR, BMCR_FDX);
  372                         return;
  373                 }
  374         }
  375         PHY_WRITE(&sc->sc_mii, MII_BMCR, 0);
  376 }

Cache object: 33a5b80cac62dfd8bbd602dbf2ba168c


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