root/dev/mii/mii.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mii_attach
  2. mii_activate
  3. mii_detach
  4. mii_print
  5. mii_submatch
  6. mii_mediachg
  7. mii_tick
  8. mii_pollstat
  9. mii_down

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

/* [<][>][^][v][top][bottom][index][help] */