root/dev/mii/amphy.c

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

DEFINITIONS

This source file includes following definitions.
  1. amphymatch
  2. amphyattach
  3. amphy_service
  4. amphy_status

    1 /*      $OpenBSD: amphy.c,v 1.15 2006/12/31 15:04:33 krw Exp $  */
    2 
    3 /*
    4  * Copyright (c) 1997, 1998, 1999
    5  *      Bill Paul <wpaul@ee.columbia.edu>.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *      This product includes software developed by Bill Paul.
   18  * 4. Neither the name of the author nor the names of any co-contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
   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
   32  * THE POSSIBILITY OF SUCH DAMAGE.
   33  *
   34  * $FreeBSD: src/sys/dev/mii/amphy.c,v 1.3 2000/04/19 14:57:29 phk Exp $
   35  */
   36 
   37 /*
   38  * driver for AMD AM79c873 PHYs
   39  * This driver also works for the Davicom DM9101 PHY, which appears to
   40  * be an AM79c873 workalike.
   41  */
   42 
   43 #include <sys/param.h>
   44 #include <sys/systm.h>
   45 #include <sys/kernel.h>
   46 #include <sys/device.h>
   47 #include <sys/socket.h>
   48 
   49 #include <net/if.h>
   50 #include <net/if_media.h>
   51 
   52 #include <dev/mii/mii.h>
   53 #include <dev/mii/miivar.h>
   54 #include <dev/mii/miidevs.h>
   55 
   56 #include <dev/mii/amphyreg.h>
   57 
   58 int     amphymatch(struct device *, void *, void *);
   59 void    amphyattach(struct device *, struct device *, void *);
   60 
   61 struct cfattach amphy_ca = {
   62         sizeof(struct mii_softc), amphymatch, amphyattach, mii_phy_detach,
   63             mii_phy_activate
   64 };
   65 
   66 struct cfdriver amphy_cd = {
   67         NULL, "amphy", DV_DULL
   68 };
   69 
   70 int     amphy_service(struct mii_softc *, struct mii_data *, int);
   71 void    amphy_status(struct mii_softc *);
   72 
   73 const struct mii_phy_funcs amphy_funcs = {
   74         amphy_service, amphy_status, mii_phy_reset,
   75 };
   76 
   77 static const struct mii_phydesc amphys[] = {
   78         { MII_OUI_xxAMD,                MII_MODEL_xxAMD_79C873,
   79           MII_STR_xxAMD_79C873 },
   80         { MII_OUI_xxDAVICOM,            MII_MODEL_xxDAVICOM_DM9101,
   81           MII_STR_xxDAVICOM_DM9101 },
   82         { MII_OUI_DAVICOM,              MII_MODEL_DAVICOM_DM9102,
   83           MII_STR_DAVICOM_DM9102 },
   84         { MII_OUI_DAVICOM,              MII_MODEL_DAVICOM_DM9601,
   85           MII_STR_DAVICOM_DM9601 },
   86         { MII_OUI_xxALTIMA,             MII_MODEL_AMD_79C875phy,
   87           MII_STR_AMD_79C875phy },
   88 
   89         { 0,                            0,
   90           NULL },
   91 };
   92 
   93 int
   94 amphymatch(struct device *parent, void *match, void *aux)
   95 {
   96         struct mii_attach_args *ma = aux;
   97 
   98         if (mii_phy_match(ma, amphys) != NULL)
   99                 return (10);
  100 
  101         return (0);
  102 }
  103 
  104 void
  105 amphyattach(struct device *parent, struct device *self, void *aux)
  106 {
  107         struct mii_softc *sc = (struct mii_softc *)self;
  108         struct mii_attach_args *ma = aux;
  109         struct mii_data *mii = ma->mii_data;
  110         const struct mii_phydesc *mpd;
  111 
  112         mpd = mii_phy_match(ma, amphys);
  113         printf(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
  114 
  115         sc->mii_inst = mii->mii_instance;
  116         sc->mii_phy = ma->mii_phyno;
  117         sc->mii_funcs = &amphy_funcs;
  118         sc->mii_pdata = mii;
  119         sc->mii_flags = ma->mii_flags;
  120 
  121         sc->mii_flags |= MIIF_NOISOLATE;
  122 
  123         PHY_RESET(sc);
  124 
  125         sc->mii_capabilities =
  126             PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
  127         if (sc->mii_capabilities & BMSR_MEDIAMASK)
  128                 mii_phy_add_media(sc);
  129 }
  130 
  131 int
  132 amphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
  133 {
  134         struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
  135         int reg;
  136 
  137         switch (cmd) {
  138         case MII_POLLSTAT:
  139                 /*
  140                  * If we're not polling our PHY instance, just return.
  141                  */
  142                 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
  143                         return (0);
  144                 break;
  145 
  146         case MII_MEDIACHG:
  147                 /*
  148                  * If the media indicates a different PHY instance,
  149                  * isolate ourselves.
  150                  */
  151                 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
  152                         reg = PHY_READ(sc, MII_BMCR);
  153                         PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
  154                         return (0);
  155                 }
  156 
  157                 /*
  158                  * If the interface is not up, don't do anything.
  159                  */
  160                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
  161                         break;
  162 
  163                 mii_phy_setmedia(sc);
  164                 break;
  165 
  166         case MII_TICK:
  167                 /*
  168                  * If we're not currently selected, just return.
  169                  */
  170                 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
  171                         return (0);
  172 
  173                 if (mii_phy_tick(sc) == EJUSTRETURN)
  174                         return (0);
  175                 break;
  176         case MII_DOWN:
  177                 mii_phy_down(sc);
  178                 return (0);
  179         }
  180 
  181         /* Update the media status. */
  182         mii_phy_status(sc);
  183 
  184         /* Callback if something changed. */
  185         mii_phy_update(sc, cmd);
  186         return (0);
  187 }
  188 
  189 void
  190 amphy_status(struct mii_softc *sc)
  191 {
  192         struct mii_data *mii = sc->mii_pdata;
  193         struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
  194         int bmsr, bmcr, par, anlpar;
  195 
  196         mii->mii_media_status = IFM_AVALID;
  197         mii->mii_media_active = IFM_ETHER;
  198 
  199         bmsr = PHY_READ(sc, MII_BMSR) |
  200             PHY_READ(sc, MII_BMSR);
  201         if (bmsr & BMSR_LINK)
  202                 mii->mii_media_status |= IFM_ACTIVE;
  203 
  204         bmcr = PHY_READ(sc, MII_BMCR);
  205         if (bmcr & BMCR_ISO) {
  206                 mii->mii_media_active |= IFM_NONE;
  207                 mii->mii_media_status = 0;
  208                 return;
  209         }
  210 
  211         if (bmcr & BMCR_LOOP)
  212                 mii->mii_media_active |= IFM_LOOP;
  213 
  214         if (bmcr & BMCR_AUTOEN) {
  215                 /*
  216                  * The PAR status bits are only valid of autonegotiation
  217                  * has completed (or it's disabled).
  218                  */
  219                 if ((bmsr & BMSR_ACOMP) == 0) {
  220                         /* Erg, still trying, I guess... */
  221                         mii->mii_media_active |= IFM_NONE;
  222                         return;
  223                 }
  224 
  225                 if (PHY_READ(sc, MII_ANER) & ANER_LPAN) {
  226                         anlpar = PHY_READ(sc, MII_ANAR) &
  227                             PHY_READ(sc, MII_ANLPAR);
  228                         if (anlpar & ANLPAR_T4)
  229                                 mii->mii_media_active |= IFM_100_T4|IFM_HDX;
  230                         else if (anlpar & ANLPAR_TX_FD)
  231                                 mii->mii_media_active |= IFM_100_TX|IFM_FDX;
  232                         else if (anlpar & ANLPAR_TX)
  233                                 mii->mii_media_active |= IFM_100_TX|IFM_HDX;
  234                         else if (anlpar & ANLPAR_10_FD)
  235                                 mii->mii_media_active |= IFM_10_T|IFM_FDX;
  236                         else if (anlpar & ANLPAR_10)
  237                                 mii->mii_media_active |= IFM_10_T|IFM_HDX;
  238                         else
  239                                 mii->mii_media_active |= IFM_NONE;
  240                         return;
  241                 }
  242 
  243                 /*
  244                  * Link partner is not capable of autonegotiation.
  245                  */
  246                 par = PHY_READ(sc, MII_AMPHY_DSCSR);
  247                 if (par & DSCSR_100FDX)
  248                         mii->mii_media_active |= IFM_100_TX|IFM_FDX;
  249                 else if (par & DSCSR_100HDX)
  250                         mii->mii_media_active |= IFM_100_TX|IFM_HDX;
  251                 else if (par & DSCSR_10FDX)
  252                         mii->mii_media_active |= IFM_10_T|IFM_HDX;
  253                 else if (par & DSCSR_10HDX)
  254                         mii->mii_media_active |= IFM_10_T|IFM_HDX;
  255         } else
  256                 mii->mii_media_active = ife->ifm_media;
  257 }

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