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/mii.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: mii.c,v 1.33 2003/01/01 00:10:21 thorpej Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
    9  * NASA Ames Research Center.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *      This product includes software developed by the NetBSD
   22  *      Foundation, Inc. and its contributors.
   23  * 4. Neither the name of The NetBSD Foundation nor the names of its
   24  *    contributors may be used to endorse or promote products derived
   25  *    from this software without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   31  * BE 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  * MII bus layer, glues MII-capable network interface drivers to sharable
   42  * PHY drivers.
   43  */
   44 
   45 #include <sys/cdefs.h>
   46 __KERNEL_RCSID(0, "$NetBSD: mii.c,v 1.33 2003/01/01 00:10:21 thorpej Exp $");
   47 
   48 #include <sys/param.h>
   49 #include <sys/device.h>
   50 #include <sys/systm.h>
   51 #include <sys/socket.h>
   52 
   53 #include <net/if.h>
   54 #include <net/if_media.h>
   55 
   56 #include <dev/mii/mii.h>
   57 #include <dev/mii/miivar.h>
   58 
   59 int     mii_print(void *, const char *);
   60 int     mii_submatch(struct device *, struct cfdata *, void *);
   61 
   62 /*
   63  * Helper function used by network interface drivers, attaches PHYs
   64  * to the network interface driver parent.
   65  */
   66 void
   67 mii_attach(struct device *parent, struct mii_data *mii, int capmask,
   68     int phyloc, int offloc, int flags)
   69 {
   70         struct mii_attach_args ma;
   71         struct mii_softc *child;
   72         int bmsr, offset = 0;
   73         int phymin, phymax;
   74 
   75         if (phyloc != MII_PHY_ANY && offloc != MII_PHY_ANY)
   76                 panic("mii_attach: phyloc and offloc specified");
   77 
   78         if (phyloc == MII_PHY_ANY) {
   79                 phymin = 0;
   80                 phymax = MII_NPHY - 1;
   81         } else
   82                 phymin = phymax = phyloc;
   83 
   84         if ((mii->mii_flags & MIIF_INITDONE) == 0) {
   85                 LIST_INIT(&mii->mii_phys);
   86                 mii->mii_flags |= MIIF_INITDONE;
   87         }
   88 
   89         for (ma.mii_phyno = phymin; ma.mii_phyno <= phymax; ma.mii_phyno++) {
   90                 /*
   91                  * Make sure we haven't already configured a PHY at this
   92                  * address.  This allows mii_attach() to be called
   93                  * multiple times.
   94                  */
   95                 for (child = LIST_FIRST(&mii->mii_phys); child != NULL;
   96                      child = LIST_NEXT(child, mii_list)) {
   97                         if (child->mii_phy == ma.mii_phyno) {
   98                                 /*
   99                                  * Yes, there is already something
  100                                  * configured at this address.
  101                                  */
  102                                 offset++;
  103                                 continue;
  104                         }
  105                 }
  106 
  107                 /*
  108                  * Check to see if there is a PHY at this address.  Note,
  109                  * many braindead PHYs report 0/0 in their ID registers,
  110                  * so we test for media in the BMSR.
  111                  */
  112                 bmsr = (*mii->mii_readreg)(parent, ma.mii_phyno, MII_BMSR);
  113                 if (bmsr == 0 || bmsr == 0xffff ||
  114                     (bmsr & (BMSR_EXTSTAT|BMSR_MEDIAMASK)) == 0) {
  115                         /* Assume no PHY at this address. */
  116                         continue;
  117                 }
  118 
  119                 /*
  120                  * There is a PHY at this address.  If we were given an
  121                  * `offset' locator, skip this PHY if it doesn't match.
  122                  */
  123                 if (offloc != MII_OFFSET_ANY && offloc != offset) {
  124                         offset++;
  125                         continue;
  126                 }
  127 
  128                 /*
  129                  * Extract the IDs.  Braindead PHYs will be handled by
  130                  * the `ukphy' driver, as we have no ID information to
  131                  * match on.
  132                  */
  133                 ma.mii_id1 = (*mii->mii_readreg)(parent, ma.mii_phyno,
  134                     MII_PHYIDR1);
  135                 ma.mii_id2 = (*mii->mii_readreg)(parent, ma.mii_phyno,
  136                     MII_PHYIDR2);
  137 
  138                 ma.mii_data = mii;
  139                 ma.mii_capmask = capmask;
  140                 ma.mii_flags = flags | (mii->mii_flags & MIIF_INHERIT_MASK);
  141 
  142                 if ((child = (struct mii_softc *)config_found_sm(parent, &ma,
  143                     mii_print, mii_submatch)) != NULL) {
  144                         /*
  145                          * Link it up in the parent's MII data.
  146                          */
  147                         callout_init(&child->mii_nway_ch);
  148                         LIST_INSERT_HEAD(&mii->mii_phys, child, mii_list);
  149                         child->mii_offset = offset;
  150                         mii->mii_instance++;
  151                 }
  152                 offset++;
  153         }
  154 }
  155 
  156 void
  157 mii_activate(struct mii_data *mii, enum devact act, int phyloc, int offloc)
  158 {
  159         struct mii_softc *child;
  160 
  161         if (phyloc != MII_PHY_ANY && offloc != MII_PHY_ANY)
  162                 panic("mii_activate: phyloc and offloc specified");
  163 
  164         if ((mii->mii_flags & MIIF_INITDONE) == 0)
  165                 return;
  166 
  167         for (child = LIST_FIRST(&mii->mii_phys);
  168              child != NULL; child = LIST_NEXT(child, mii_list)) {
  169                 if (phyloc != MII_PHY_ANY || offloc != MII_OFFSET_ANY) {
  170                         if (phyloc != MII_PHY_ANY &&
  171                             phyloc != child->mii_phy)
  172                                 continue;
  173                         if (offloc != MII_OFFSET_ANY &&
  174                             offloc != child->mii_offset)
  175                                 continue;
  176                 }
  177                 switch (act) {
  178                 case DVACT_ACTIVATE:
  179                         panic("mii_activate: DVACT_ACTIVATE");
  180                         break;
  181 
  182                 case DVACT_DEACTIVATE:
  183                         if (config_deactivate(&child->mii_dev) != 0)
  184                                 panic("%s: config_activate(%d) failed",
  185                                     child->mii_dev.dv_xname, act);
  186                 }
  187         }
  188 }
  189 
  190 void
  191 mii_detach(struct mii_data *mii, int phyloc, int offloc)
  192 {
  193         struct mii_softc *child, *nchild;
  194 
  195         if (phyloc != MII_PHY_ANY && offloc != MII_PHY_ANY)
  196                 panic("mii_detach: phyloc and offloc specified");
  197 
  198         if ((mii->mii_flags & MIIF_INITDONE) == 0)
  199                 return;
  200 
  201         for (child = LIST_FIRST(&mii->mii_phys);
  202              child != NULL; child = nchild) {
  203                 nchild = LIST_NEXT(child, mii_list);
  204                 if (phyloc != MII_PHY_ANY || offloc != MII_OFFSET_ANY) {
  205                         if (phyloc != MII_PHY_ANY &&
  206                             phyloc != child->mii_phy)
  207                                 continue;
  208                         if (offloc != MII_OFFSET_ANY &&
  209                             offloc != child->mii_offset)
  210                                 continue;
  211                 }
  212                 LIST_REMOVE(child, mii_list);
  213                 (void) config_detach(&child->mii_dev, DETACH_FORCE);
  214         }
  215 }
  216 
  217 int
  218 mii_print(void *aux, const char *pnp)
  219 {
  220         struct mii_attach_args *ma = aux;
  221 
  222         if (pnp != NULL)
  223                 aprint_normal("OUI 0x%06x model 0x%04x rev %d at %s",
  224                     MII_OUI(ma->mii_id1, ma->mii_id2), MII_MODEL(ma->mii_id2),
  225                     MII_REV(ma->mii_id2), pnp);
  226 
  227         aprint_normal(" phy %d", ma->mii_phyno);
  228         return (UNCONF);
  229 }
  230 
  231 int
  232 mii_submatch(struct device *parent, struct cfdata *cf, void *aux)
  233 {
  234         struct mii_attach_args *ma = aux;
  235 
  236         if (ma->mii_phyno != cf->cf_loc[MIICF_PHY] &&
  237             cf->cf_loc[MIICF_PHY] != MIICF_PHY_DEFAULT)
  238                 return (0);
  239 
  240         return (config_match(parent, cf, aux));
  241 }
  242 
  243 /*
  244  * Media changed; notify all PHYs.
  245  */
  246 int
  247 mii_mediachg(struct mii_data *mii)
  248 {
  249         struct mii_softc *child;
  250         int rv;
  251 
  252         mii->mii_media_status = 0;
  253         mii->mii_media_active = IFM_NONE;
  254 
  255         for (child = LIST_FIRST(&mii->mii_phys); child != NULL;
  256              child = LIST_NEXT(child, mii_list)) {
  257                 rv = PHY_SERVICE(child, mii, MII_MEDIACHG);
  258                 if (rv)
  259                         return (rv);
  260         }
  261         return (0);
  262 }
  263 
  264 /*
  265  * Call the PHY tick routines, used during autonegotiation.
  266  */
  267 void
  268 mii_tick(struct mii_data *mii)
  269 {
  270         struct mii_softc *child;
  271 
  272         for (child = LIST_FIRST(&mii->mii_phys); child != NULL;
  273              child = LIST_NEXT(child, mii_list))
  274                 (void) PHY_SERVICE(child, mii, MII_TICK);
  275 }
  276 
  277 /*
  278  * Get media status from PHYs.
  279  */
  280 void
  281 mii_pollstat(struct mii_data *mii)
  282 {
  283         struct mii_softc *child;
  284 
  285         mii->mii_media_status = 0;
  286         mii->mii_media_active = IFM_NONE;
  287 
  288         for (child = LIST_FIRST(&mii->mii_phys); child != NULL;
  289              child = LIST_NEXT(child, mii_list))
  290                 (void) PHY_SERVICE(child, mii, MII_POLLSTAT);
  291 }
  292 
  293 /*
  294  * Inform the PHYs that the interface is down.
  295  */
  296 void
  297 mii_down(struct mii_data *mii)
  298 {
  299         struct mii_softc *child;
  300 
  301         for (child = LIST_FIRST(&mii->mii_phys); child != NULL;
  302              child = LIST_NEXT(child, mii_list))
  303                 (void) PHY_SERVICE(child, mii, MII_DOWN);
  304 }
  305 
  306 static unsigned char
  307 bitreverse(unsigned char x)
  308 {
  309         static unsigned char nibbletab[16] = {
  310                 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15
  311         };
  312 
  313         return ((nibbletab[x & 15] << 4) | nibbletab[x >> 4]);
  314 }
  315 
  316 u_int
  317 mii_oui(u_int id1, u_int id2)
  318 {
  319         u_int h;
  320 
  321         h = (id1 << 6) | (id2 >> 10);
  322 
  323         return ((bitreverse(h >> 16) << 16) |
  324                 (bitreverse((h >> 8) & 255) << 8) |
  325                 bitreverse(h & 255));
  326 }

Cache object: b5c6653f277e786e1d199525b7194838


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