[BACK]Return to rlphy.c CVS log [TXT][DIR] Up to [local] / sys / dev / mii

Annotation of sys/dev/mii/rlphy.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: rlphy.c,v 1.27 2007/01/27 20:55:14 miod Exp $ */
                      2:
                      3: /*
                      4:  * Copyright (c) 1998, 1999 Jason L. Wright (jason@thought.net)
                      5:  * 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:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     17:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     18:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     19:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
                     20:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
                     21:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     22:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     23:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     24:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
                     25:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     26:  * POSSIBILITY OF SUCH DAMAGE.
                     27:  */
                     28:
                     29: /*
                     30:  * Driver for the internal PHY found on RTL8139 based nics, based
                     31:  * on drivers for the 'exphy' (Internal 3Com phys) and 'nsphy'
                     32:  * (National Semiconductor DP83840).
                     33:  */
                     34:
                     35: #include <sys/param.h>
                     36: #include <sys/systm.h>
                     37: #include <sys/kernel.h>
                     38: #include <sys/device.h>
                     39: #include <sys/socket.h>
                     40: #include <sys/timeout.h>
                     41: #include <sys/errno.h>
                     42:
                     43: #include <net/if.h>
                     44: #include <net/if_media.h>
                     45: #include <netinet/in.h>
                     46: #include <netinet/if_ether.h>
                     47:
                     48: #include <dev/mii/mii.h>
                     49: #include <dev/mii/miivar.h>
                     50: #include <dev/mii/miidevs.h>
                     51: #include <machine/bus.h>
                     52: #include <dev/ic/rtl81x9reg.h>
                     53:
                     54: int    rlphymatch(struct device *, void *, void *);
                     55: void   rlphyattach(struct device *, struct device *, void *);
                     56:
                     57: struct cfattach rlphy_ca = {
                     58:        sizeof(struct mii_softc), rlphymatch, rlphyattach, mii_phy_detach,
                     59:            mii_phy_activate
                     60: };
                     61:
                     62: struct cfdriver rlphy_cd = {
                     63:        NULL, "rlphy", DV_DULL
                     64: };
                     65:
                     66: int    rlphy_service(struct mii_softc *, struct mii_data *, int);
                     67: void   rlphy_status(struct mii_softc *);
                     68:
                     69: const struct mii_phy_funcs rlphy_funcs = {
                     70:        rlphy_service, rlphy_status, mii_phy_reset,
                     71: };
                     72:
                     73: static const struct mii_phydesc rlphys[] = {
                     74:        { MII_OUI_REALTEK,              MII_MODEL_REALTEK_RTL8201L,
                     75:           MII_STR_REALTEK_RTL8201L },
                     76:        { MII_OUI_ICPLUS,               MII_MODEL_ICPLUS_IP101,
                     77:          MII_STR_ICPLUS_IP101 },
                     78:
                     79:        { 0,                            0,
                     80:          NULL },
                     81: };
                     82: int
                     83: rlphymatch(struct device *parent, void *match, void *aux)
                     84: {
                     85:        struct mii_attach_args *ma = aux;
                     86:        char *devname;
                     87:
                     88:        devname = parent->dv_cfdata->cf_driver->cd_name;
                     89:
                     90:        if (mii_phy_match(ma, rlphys) != NULL)
                     91:                return (10);
                     92:
                     93:        if (MII_OUI(ma->mii_id1, ma->mii_id2) != 0 ||
                     94:            MII_MODEL(ma->mii_id2) != 0)
                     95:                return (0);
                     96:
                     97:        if ((strcmp(devname, "re") != 0) &&
                     98:            (strcmp(devname, "rl") != 0))
                     99:                return (0);
                    100:
                    101:        /*
                    102:         * A "real" phy should get preference, but on the 8139 there
                    103:         * is no phyid register.
                    104:         */
                    105:        return (5);
                    106: }
                    107:
                    108: void
                    109: rlphyattach(struct device *parent, struct device *self, void *aux)
                    110: {
                    111:        struct mii_softc *sc = (struct mii_softc *)self;
                    112:        struct mii_attach_args *ma = aux;
                    113:        struct mii_data *mii = ma->mii_data;
                    114:        const struct mii_phydesc *mpd;
                    115:
                    116:        mpd = mii_phy_match(ma, rlphys);
                    117:        if (mpd != NULL) {
                    118:                printf(": %s, rev. %d\n", mpd->mpd_name,
                    119:                    MII_REV(ma->mii_id2));
                    120:        } else
                    121:                printf(": RTL internal PHY\n");
                    122:
                    123:        sc->mii_inst = mii->mii_instance;
                    124:        sc->mii_phy = ma->mii_phyno;
                    125:        sc->mii_funcs = &rlphy_funcs;
                    126:        sc->mii_pdata = mii;
                    127:        sc->mii_flags = ma->mii_flags;
                    128:
                    129:        sc->mii_flags |= MIIF_NOISOLATE;
                    130:
                    131:        PHY_RESET(sc);
                    132:
                    133:        sc->mii_capabilities =
                    134:            PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
                    135:        if (sc->mii_capabilities & BMSR_MEDIAMASK)
                    136:                mii_phy_add_media(sc);
                    137: }
                    138:
                    139: int
                    140: rlphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
                    141: {
                    142:        struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
                    143:
                    144:        if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0)
                    145:                return (ENXIO);
                    146:
                    147:        /*
                    148:         * Can't isolate the RTL8139 phy, so it has to be the only one.
                    149:         */
                    150:        if (IFM_INST(ife->ifm_media) != sc->mii_inst)
                    151:                panic("rlphy_service: attempt to isolate phy");
                    152:
                    153:        switch (cmd) {
                    154:        case MII_POLLSTAT:
                    155:                break;
                    156:
                    157:        case MII_MEDIACHG:
                    158:                /*
                    159:                 * If the interface is not up, don't do anything.
                    160:                 */
                    161:                if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
                    162:                        break;
                    163:
                    164:                switch (IFM_SUBTYPE(ife->ifm_media)) {
                    165:                case IFM_AUTO:
                    166:                        /*
                    167:                         * If we're already in auto mode, just return.
                    168:                         */
                    169:                        if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN)
                    170:                                return (0);
                    171:                        (void) mii_phy_auto(sc, 0);
                    172:                        break;
                    173:                case IFM_100_T4:
                    174:                        /*
                    175:                         * XXX Not supported as a manual setting right now.
                    176:                         */
                    177:                        return (EINVAL);
                    178:                default:
                    179:                        /*
                    180:                         * BMCR data is stored in the ifmedia entry.
                    181:                         */
                    182:                        PHY_WRITE(sc, MII_ANAR,
                    183:                            mii_anar(ife->ifm_media));
                    184:                        PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
                    185:                }
                    186:                break;
                    187:
                    188:        case MII_TICK:
                    189:                /*
                    190:                 * Is the interface even up?
                    191:                 */
                    192:                if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
                    193:                        return (0);
                    194:
                    195:                /*
                    196:                 * Only used for autonegotiation.
                    197:                 */
                    198:                if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
                    199:                        break;
                    200:
                    201:                /*
                    202:                 * The RealTek PHY's autonegotiation doesn't need to be
                    203:                 * kicked; it continues in the background.
                    204:                 */
                    205:                break;
                    206:
                    207:        case MII_DOWN:
                    208:                mii_phy_down(sc);
                    209:                return (0);
                    210:        }
                    211:
                    212:        /* Update the media status. */
                    213:        mii_phy_status(sc);
                    214:
                    215:        /* Callback if something changed. */
                    216:        mii_phy_update(sc, cmd);
                    217:        return (0);
                    218: }
                    219:
                    220: void
                    221: rlphy_status(struct mii_softc *sc)
                    222: {
                    223:        struct mii_data *mii = sc->mii_pdata;
                    224:        struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
                    225:        int bmsr, bmcr, anlpar;
                    226:        char *devname;
                    227:
                    228:        devname = sc->mii_dev.dv_parent->dv_cfdata->cf_driver->cd_name;
                    229:
                    230:        mii->mii_media_status = IFM_AVALID;
                    231:        mii->mii_media_active = IFM_ETHER;
                    232:
                    233:        bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
                    234:        if (bmsr & BMSR_LINK)
                    235:                mii->mii_media_status |= IFM_ACTIVE;
                    236:
                    237:        bmcr = PHY_READ(sc, MII_BMCR);
                    238:        if (bmcr & BMCR_ISO) {
                    239:                mii->mii_media_active |= IFM_NONE;
                    240:                mii->mii_media_status = 0;
                    241:                return;
                    242:        }
                    243:
                    244:        if (bmcr & BMCR_LOOP)
                    245:                mii->mii_media_active |= IFM_LOOP;
                    246:
                    247:        if (bmcr & BMCR_AUTOEN) {
                    248:                /*
                    249:                 * NWay autonegotiation takes the highest-order common
                    250:                 * bit of the ANAR and ANLPAR (i.e. best media advertised
                    251:                 * both by us and our link partner).
                    252:                 */
                    253:                if ((bmsr & BMSR_ACOMP) == 0) {
                    254:                        /* Erg, still trying, I guess... */
                    255:                        mii->mii_media_active |= IFM_NONE;
                    256:                        return;
                    257:                }
                    258:
                    259:                if ((anlpar = PHY_READ(sc, MII_ANAR) &
                    260:                    PHY_READ(sc, MII_ANLPAR))) {
                    261:                        if (anlpar & ANLPAR_T4)
                    262:                                mii->mii_media_active |= IFM_100_T4|IFM_HDX;
                    263:                        else if (anlpar & ANLPAR_TX_FD)
                    264:                                mii->mii_media_active |= IFM_100_TX|IFM_FDX;
                    265:                        else if (anlpar & ANLPAR_TX)
                    266:                                mii->mii_media_active |= IFM_100_TX|IFM_HDX;
                    267:                        else if (anlpar & ANLPAR_10_FD)
                    268:                                mii->mii_media_active |= IFM_10_T|IFM_FDX;
                    269:                        else if (anlpar & ANLPAR_10)
                    270:                                mii->mii_media_active |= IFM_10_T|IFM_HDX;
                    271:                        else
                    272:                                mii->mii_media_active |= IFM_NONE;
                    273:                        return;
                    274:                }
                    275:
                    276:                /*
                    277:                 * If the other side doesn't support NWAY, then the
                    278:                 * best we can do is determine if we have a 10Mbps or
                    279:                 * 100Mbps link. There's no way to know if the link
                    280:                 * is full or half duplex, so we default to half duplex
                    281:                 * and hope that the user is clever enough to manually
                    282:                 * change the media settings if we're wrong.
                    283:                 */
                    284:
                    285:                /*
                    286:                 * The RealTek PHY supports non-NWAY link speed
                    287:                 * detection, however it does not report the link
                    288:                 * detection results via the ANLPAR or BMSR registers.
                    289:                 * (What? RealTek doesn't do things the way everyone
                    290:                 * else does? I'm just shocked, shocked I tell you.)
                    291:                 * To determine the link speed, we have to do one
                    292:                 * of two things:
                    293:                 *
                    294:                 * - If this is a standalone RealTek RTL8201(L) PHY,
                    295:                 *   we can determine the link speed by testing bit 0
                    296:                 *   in the magic, vendor-specific register at offset
                    297:                 *   0x19.
                    298:                 *
                    299:                 * - If this is a RealTek MAC with integrated PHY, we
                    300:                 *   can test the 'SPEED10' bit of the MAC's media status
                    301:                 *   register.
                    302:                 */
                    303:                if (strcmp("rl", devname) == 0 ||
                    304:                    strcmp("re", devname) == 0) {
                    305:                        if (PHY_READ(sc, RL_MEDIASTAT) & RL_MEDIASTAT_SPEED10)
                    306:                                mii->mii_media_active |= IFM_10_T;
                    307:                        else
                    308:                                mii->mii_media_active |= IFM_100_TX;
                    309:                } else {
                    310:                        if (PHY_READ(sc, 0x0019) & 0x01)
                    311:                                mii->mii_media_active |= IFM_100_TX;
                    312:                        else
                    313:                                mii->mii_media_active |= IFM_10_T;
                    314:                }
                    315:                mii->mii_media_active |= IFM_HDX;
                    316:        } else
                    317:                mii->mii_media_active = ife->ifm_media;
                    318: }

CVSweb