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/igphy.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: igphy.c,v 1.1.2.1 2005/01/07 11:42:14 jdc Exp $        */
    2 
    3 /*
    4  * The Intel copyright applies to the analog register setup, and the
    5  * (currently disabled) SmartSpeed workaround code.
    6  */
    7 
    8 /*******************************************************************************
    9 
   10   Copyright (c) 2001-2003, Intel Corporation
   11   All rights reserved.
   12 
   13   Redistribution and use in source and binary forms, with or without
   14   modification, are permitted provided that the following conditions are met:
   15 
   16    1. Redistributions of source code must retain the above copyright notice,
   17       this list of conditions and the following disclaimer.
   18 
   19    2. Redistributions in binary form must reproduce the above copyright
   20       notice, this list of conditions and the following disclaimer in the
   21       documentation and/or other materials provided with the distribution.
   22 
   23    3. Neither the name of the Intel Corporation nor the names of its
   24       contributors may be used to endorse or promote products derived from
   25       this software without specific prior written permission.
   26 
   27   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   28   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   29   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   30   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   31   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37   POSSIBILITY OF SUCH DAMAGE.
   38 
   39 *******************************************************************************/
   40 
   41 
   42 /*-
   43  * Copyright (c) 1998, 1999, 2000, 2003 The NetBSD Foundation, Inc.
   44  * All rights reserved.
   45  *
   46  * This code is derived from software contributed to The NetBSD Foundation
   47  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
   48  * NASA Ames Research Center, and by Frank van der Linden.
   49  *
   50  * Redistribution and use in source and binary forms, with or without
   51  * modification, are permitted provided that the following conditions
   52  * are met:
   53  * 1. Redistributions of source code must retain the above copyright
   54  *    notice, this list of conditions and the following disclaimer.
   55  * 2. Redistributions in binary form must reproduce the above copyright
   56  *    notice, this list of conditions and the following disclaimer in the
   57  *    documentation and/or other materials provided with the distribution.
   58  * 3. All advertising materials mentioning features or use of this software
   59  *    must display the following acknowledgement:
   60  *      This product includes software developed by the NetBSD
   61  *      Foundation, Inc. and its contributors.
   62  * 4. Neither the name of The NetBSD Foundation nor the names of its
   63  *    contributors may be used to endorse or promote products derived
   64  *    from this software without specific prior written permission.
   65  *
   66  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   67  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   68  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   69  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   70  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   71  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   72  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   73  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   74  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   75  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   76  * POSSIBILITY OF SUCH DAMAGE.
   77  */
   78 
   79 #include <sys/cdefs.h>
   80 __KERNEL_RCSID(0, "$NetBSD: igphy.c,v 1.1.2.1 2005/01/07 11:42:14 jdc Exp $");
   81 
   82 #include "opt_mii.h"
   83 
   84 #include <sys/param.h>
   85 #include <sys/systm.h>
   86 #include <sys/kernel.h>
   87 #include <sys/device.h>
   88 #include <sys/socket.h>
   89 #include <sys/errno.h>
   90 
   91 #include <net/if.h>
   92 #include <net/if_media.h>
   93 
   94 #include <dev/mii/mii.h>
   95 #include <dev/mii/miivar.h>
   96 #include <dev/mii/miidevs.h>
   97 
   98 #include <dev/mii/igphyreg.h>
   99 
  100 struct igphy_softc {
  101         struct mii_softc sc_mii;
  102         int sc_smartspeed;
  103 };
  104 
  105 static void igphy_reset(struct mii_softc *);
  106 static void igphy_load_dspcode(struct mii_softc *);
  107 static void igphy_smartspeed_workaround(struct mii_softc *sc);
  108 
  109 int     igphymatch(struct device *, struct cfdata *, void *);
  110 void    igphyattach(struct device *, struct device *, void *);
  111 
  112 CFATTACH_DECL(igphy, sizeof(struct igphy_softc),
  113     igphymatch, igphyattach, mii_phy_detach, mii_phy_activate);
  114 
  115 int     igphy_service(struct mii_softc *, struct mii_data *, int);
  116 void    igphy_status(struct mii_softc *);
  117 
  118 const struct mii_phy_funcs igphy_funcs = {
  119         igphy_service, igphy_status, igphy_reset,
  120 };
  121 
  122 const struct mii_phydesc igphys[] = {
  123         { MII_OUI_yyINTEL,              MII_MODEL_yyINTEL_IGP01E1000,
  124           MII_STR_yyINTEL_IGP01E1000 },
  125 
  126         {0,                             0,
  127          NULL },
  128 };
  129 
  130 int
  131 igphymatch(struct device *parent, struct cfdata *match, void *aux)
  132 {
  133         struct mii_attach_args *ma = aux;
  134 
  135         if (mii_phy_match(ma, igphys) != NULL)
  136                 return 10;
  137 
  138         return 0;
  139 }
  140 
  141 void
  142 igphyattach(struct device *parent, struct device *self, void *aux)
  143 {
  144         struct mii_softc *sc = (struct mii_softc *)self;
  145         struct mii_attach_args *ma = aux;
  146         struct mii_data *mii = ma->mii_data;
  147         const struct mii_phydesc *mpd;
  148 
  149         mpd = mii_phy_match(ma, igphys);
  150         aprint_naive(": Media interface\n");
  151         aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
  152 
  153         sc->mii_inst = mii->mii_instance;
  154         sc->mii_phy = ma->mii_phyno;
  155         sc->mii_funcs = &igphy_funcs;
  156         sc->mii_pdata = mii;
  157         sc->mii_flags = ma->mii_flags;
  158         sc->mii_anegticks = 10;
  159 
  160         PHY_RESET(sc);
  161 
  162         sc->mii_capabilities =
  163             PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
  164         if (sc->mii_capabilities & BMSR_EXTSTAT)
  165                 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
  166         aprint_normal("%s: ", sc->mii_dev.dv_xname);
  167         if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
  168             (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
  169                 aprint_error("no media present");
  170         else
  171                 mii_phy_add_media(sc);
  172         aprint_normal("\n");
  173 }
  174 
  175 static void
  176 igphy_load_dspcode(struct mii_softc *sc)
  177 {
  178         static const struct {
  179                 int reg;
  180                 uint16_t val;
  181         } dspcode[] = {
  182                 { 0x1f95, 0x0001 },
  183                 { 0x1f71, 0xbd21 },
  184                 { 0x1f79, 0x0018 },
  185                 { 0x1f30, 0x1600 },
  186                 { 0x1f31, 0x0014 },
  187                 { 0x1f32, 0x161c },
  188                 { 0x1f94, 0x0003 },
  189                 { 0x1f96, 0x003f },
  190                 { 0x2010, 0x0008 },
  191                 { 0, 0 },
  192         };
  193         int i;
  194 
  195         delay(10);
  196 
  197         PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000);
  198         PHY_WRITE(sc, 0x0000, 0x0140);
  199 
  200         delay(5);
  201 
  202         for (i = 0; dspcode[i].reg != 0; i++)
  203                 IGPHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
  204 
  205         PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT,0x0000);
  206         PHY_WRITE(sc, 0x0000, 0x3300);
  207 }
  208 
  209 static void
  210 igphy_reset(struct mii_softc *sc)
  211 {
  212         uint16_t fused, fine, coarse;
  213 
  214         mii_phy_reset(sc);
  215         igphy_load_dspcode(sc);
  216 
  217         fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_SPARE_FUSE_STATUS);
  218         if ((fused & ANALOG_SPARE_FUSE_ENABLED) == 0) {
  219                 fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_FUSE_STATUS);
  220 
  221                 fine = fused & ANALOG_FUSE_FINE_MASK;
  222                 coarse = fused & ANALOG_FUSE_COARSE_MASK;
  223 
  224                 if (coarse > ANALOG_FUSE_COARSE_THRESH) {
  225                         coarse -= ANALOG_FUSE_COARSE_10;
  226                         fine -= ANALOG_FUSE_FINE_1;
  227                 } else if (coarse == ANALOG_FUSE_COARSE_THRESH)
  228                         fine -= ANALOG_FUSE_FINE_10;
  229 
  230                 fused = (fused & ANALOG_FUSE_POLY_MASK) |
  231                         (fine & ANALOG_FUSE_FINE_MASK) |
  232                         (coarse & ANALOG_FUSE_COARSE_MASK);
  233 
  234                 IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_CONTROL, fused);
  235                 IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_BYPASS,
  236                     ANALOG_FUSE_ENABLE_SW_CONTROL);
  237         }
  238         PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT,0x0000);
  239 }
  240 
  241 
  242 int
  243 igphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
  244 {
  245         struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
  246         uint16_t reg;
  247 
  248         switch (cmd) {
  249         case MII_POLLSTAT:
  250                 /*
  251                  * If we're not polling our PHY instance, just return.
  252                  */
  253                 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
  254                         return (0);
  255                 break;
  256 
  257         case MII_MEDIACHG:
  258                 /*
  259                  * If the media indicates a different PHY instance,
  260                  * isolate ourselves.
  261                  */
  262                 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
  263                         reg = PHY_READ(sc, MII_BMCR);
  264                         PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
  265                         return (0);
  266                 }
  267 
  268                 /*
  269                  * If the interface is not up, don't do anything.
  270                  */
  271                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
  272                         break;
  273 
  274                 mii_phy_setmedia(sc);
  275                 break;
  276 
  277         case MII_TICK:
  278                 /*
  279                  * If we're not currently selected, just return.
  280                  */
  281                 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
  282                         return (0);
  283 
  284                 igphy_smartspeed_workaround(sc);
  285 
  286                 if (mii_phy_tick(sc) == EJUSTRETURN)
  287                         return (0);
  288                 break;
  289 
  290         case MII_DOWN:
  291                 mii_phy_down(sc);
  292                 return (0);
  293         }
  294 
  295         /* Update the media status. */
  296         mii_phy_status(sc);
  297 
  298         /* Callback if something changed. */
  299         mii_phy_update(sc, cmd);
  300         return (0);
  301 }
  302 
  303 
  304 void
  305 igphy_status(struct mii_softc *sc)
  306 {
  307         struct mii_data *mii = sc->mii_pdata;
  308         struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
  309         uint16_t bmcr, pssr, gtsr, bmsr;
  310 
  311         mii->mii_media_status = IFM_AVALID;
  312         mii->mii_media_active = IFM_ETHER;
  313 
  314         pssr = PHY_READ(sc, MII_IGPHY_PORT_STATUS);
  315 
  316         if (pssr & PSSR_LINK_UP)
  317                 mii->mii_media_status |= IFM_ACTIVE;
  318 
  319         bmcr = PHY_READ(sc, MII_BMCR);
  320         if (bmcr & BMCR_ISO) {
  321                 mii->mii_media_active |= IFM_NONE;
  322                 mii->mii_media_status = 0;
  323                 return;
  324         }
  325 
  326         if (bmcr & BMCR_LOOP)
  327                 mii->mii_media_active |= IFM_LOOP;
  328 
  329         bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
  330 
  331         /*
  332          * XXX can't check if the info is valid, no
  333          * 'negotiation done' bit?
  334          */
  335         if (bmcr & BMCR_AUTOEN) {
  336                 if ((bmsr & BMSR_ACOMP) == 0) {
  337                         mii->mii_media_active |= IFM_NONE;
  338                         return;
  339                 }
  340                 switch (pssr & PSSR_SPEED_MASK) {
  341                 case PSSR_SPEED_1000MBPS:
  342                         mii->mii_media_active |= IFM_1000_T;
  343                         gtsr = PHY_READ(sc, MII_100T2SR);
  344                         if (gtsr & GTSR_MS_RES)
  345                                 mii->mii_media_active |= IFM_ETH_MASTER;
  346                         break;
  347 
  348                 case PSSR_SPEED_100MBPS:
  349                         mii->mii_media_active |= IFM_100_TX;
  350                         break;
  351 
  352                 case PSSR_SPEED_10MBPS:
  353                         mii->mii_media_active |= IFM_10_T;
  354                         break;
  355 
  356                 default:
  357                         mii->mii_media_active |= IFM_NONE;
  358                         mii->mii_media_status = 0;
  359                         return;
  360                 }
  361 
  362                 if (pssr & PSSR_FULL_DUPLEX)
  363                         mii->mii_media_active |= IFM_FDX;
  364         } else
  365                 mii->mii_media_active = ife->ifm_media;
  366 }
  367 
  368 static void
  369 igphy_smartspeed_workaround(struct mii_softc *sc)
  370 {
  371         struct igphy_softc *igsc = (struct igphy_softc *) sc;
  372         uint16_t reg, gtsr, gtcr;
  373 
  374         if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0)
  375                 return;
  376 
  377         /* XXX Assume 1000TX-FDX is advertized if doing autonegotiation. */
  378 
  379         reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
  380         if ((reg & BMSR_LINK) == 0) {
  381                 switch (igsc->sc_smartspeed) {
  382                 case 0:
  383                         gtsr = PHY_READ(sc, MII_100T2SR);
  384                         if (!(gtsr & GTSR_MAN_MS_FLT))
  385                                 break;
  386                         gtsr = PHY_READ(sc, MII_100T2SR);
  387                         if (gtsr & GTSR_MAN_MS_FLT) {
  388                                 gtcr = PHY_READ(sc, MII_100T2CR);
  389                                 if (gtcr & GTCR_MAN_MS) {
  390                                         gtcr &= ~GTCR_MAN_MS;
  391                                         PHY_WRITE(sc, MII_100T2CR,
  392                                             gtcr);
  393                                 }
  394                                 mii_phy_auto(sc, 0);
  395                         }
  396                         break;
  397                 case IGPHY_TICK_DOWNSHIFT:
  398                         gtcr = PHY_READ(sc, MII_100T2CR);
  399                         gtcr |= GTCR_MAN_MS;
  400                         PHY_WRITE(sc, MII_100T2CR, gtcr);
  401                         mii_phy_auto(sc, 0);
  402                         break;
  403                 default:
  404                         break;
  405                 }
  406                 if (igsc->sc_smartspeed++ == IGPHY_TICK_MAX)
  407                         igsc->sc_smartspeed = 0;
  408         } else
  409                 igsc->sc_smartspeed = 0;
  410 }

Cache object: 2d55f5a034f0dcb81061a5ba97358cfb


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