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

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

1.1       nbrk        1: /*     $OpenBSD: mii_physubr.c,v 1.32 2007/02/10 22:36:18 kettenis Exp $       */
                      2: /*     $NetBSD: mii_physubr.c,v 1.20 2001/04/13 23:30:09 thorpej Exp $ */
                      3:
                      4: /*-
                      5:  * Copyright (c) 1998, 1999, 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:  * Subroutines common to all PHYs.
                     43:  */
                     44:
                     45: #include <sys/param.h>
                     46: #include <sys/device.h>
                     47: #include <sys/systm.h>
                     48: #include <sys/kernel.h>
                     49: #include <sys/socket.h>
                     50: #include <sys/errno.h>
                     51: #include <sys/proc.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: /*
                     60:  * Media to register setting conversion table.  Order matters.
                     61:  * XXX 802.3 doesn't specify ANAR or ANLPAR bits for 1000base.
                     62:  */
                     63: const struct mii_media mii_media_table[] = {
                     64:        /* None */
                     65:        { BMCR_ISO,             ANAR_CSMA,              0 },
                     66:        /* 10baseT */
                     67:        { BMCR_S10,             ANAR_CSMA|ANAR_10,      0 },
                     68:        /* 10baseT-FDX */
                     69:        { BMCR_S10|BMCR_FDX,    ANAR_CSMA|ANAR_10_FD,   0 },
                     70:        /* 100baseT4 */
                     71:        { BMCR_S100,            ANAR_CSMA|ANAR_T4,      0 },
                     72:        /* 100baseTX */
                     73:        { BMCR_S100,            ANAR_CSMA|ANAR_TX,      0 },
                     74:        /* 100baseTX-FDX */
                     75:        { BMCR_S100|BMCR_FDX,   ANAR_CSMA|ANAR_TX_FD,   0 },
                     76:        /* 1000baseX */
                     77:        { BMCR_S1000,           ANAR_CSMA,              0 },
                     78:        /* 1000baseX-FDX */
                     79:        { BMCR_S1000|BMCR_FDX,  ANAR_CSMA,              0 },
                     80:        /* 1000baseT */
                     81:        { BMCR_S1000,           ANAR_CSMA,              GTCR_ADV_1000THDX },
                     82:        /* 1000baseT-FDX */
                     83:        { BMCR_S1000|BMCR_FDX,  ANAR_CSMA,              GTCR_ADV_1000TFDX },
                     84: };
                     85:
                     86: void
                     87: mii_phy_setmedia(struct mii_softc *sc)
                     88: {
                     89:        struct mii_data *mii = sc->mii_pdata;
                     90:        struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
                     91:        int bmcr, anar, gtcr;
                     92:
                     93:        if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
                     94:                if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0 ||
                     95:                    (sc->mii_flags & MIIF_FORCEANEG))
                     96:                        (void) mii_phy_auto(sc, 1);
                     97:                return;
                     98:        }
                     99:
                    100:        /*
                    101:         * Table index is stored in the media entry.
                    102:         */
                    103: #ifdef DIAGNOSTIC
                    104:        if (ife->ifm_data < 0 || ife->ifm_data >= MII_NMEDIA)
                    105:                panic("mii_phy_setmedia");
                    106: #endif
                    107:
                    108:        anar = mii_media_table[ife->ifm_data].mm_anar;
                    109:        bmcr = mii_media_table[ife->ifm_data].mm_bmcr;
                    110:        gtcr = mii_media_table[ife->ifm_data].mm_gtcr;
                    111:
                    112:        if (mii->mii_media.ifm_media & IFM_ETH_MASTER) {
                    113:                switch (IFM_SUBTYPE(ife->ifm_media)) {
                    114:                case IFM_1000_T:
                    115:                        gtcr |= GTCR_MAN_MS|GTCR_ADV_MS;
                    116:                        break;
                    117:
                    118:                default:
                    119:                        panic("mii_phy_setmedia: MASTER on wrong media");
                    120:                }
                    121:        }
                    122:
                    123:        if (ife->ifm_media & IFM_LOOP)
                    124:                bmcr |= BMCR_LOOP;
                    125:
                    126:        PHY_WRITE(sc, MII_ANAR, anar);
                    127:        PHY_WRITE(sc, MII_BMCR, bmcr);
                    128:        if (sc->mii_flags & MIIF_HAVE_GTCR)
                    129:                PHY_WRITE(sc, MII_100T2CR, gtcr);
                    130: }
                    131:
                    132: int
                    133: mii_phy_auto(struct mii_softc *sc, int waitfor)
                    134: {
                    135:        int bmsr, i;
                    136:
                    137:        if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) {
                    138:                /*
                    139:                 * Check for 1000BASE-X.  Autonegotiation is a bit
                    140:                 * different on such devices.
                    141:                 */
                    142:                if (sc->mii_flags & MIIF_IS_1000X) {
                    143:                        uint16_t anar = 0;
                    144:
                    145:                        if (sc->mii_extcapabilities & EXTSR_1000XFDX)
                    146:                                anar |= ANAR_X_FD;
                    147:                        if (sc->mii_extcapabilities & EXTSR_1000XHDX)
                    148:                                anar |= ANAR_X_HD;
                    149:
                    150:                        if (sc->mii_flags & MIIF_DOPAUSE &&
                    151:                            sc->mii_extcapabilities & EXTSR_1000XFDX)
                    152:                                anar |= ANAR_X_PAUSE_TOWARDS;
                    153:
                    154:                        PHY_WRITE(sc, MII_ANAR, anar);
                    155:                } else {
                    156:                        uint16_t anar;
                    157:
                    158:                        anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) |
                    159:                            ANAR_CSMA;
                    160:                        /*
                    161:                         * Most 100baseTX PHY's only support symmetric
                    162:                         * PAUSE, so we don't advertise asymmetric
                    163:                         * PAUSE unless we also have 1000baseT capability.
                    164:                         */
                    165:                        if (sc->mii_flags & MIIF_DOPAUSE) {
                    166:                                if (sc->mii_capabilities & BMSR_100TXFDX)
                    167:                                        anar |= ANAR_FC;
                    168:                                if (sc->mii_extcapabilities & EXTSR_1000TFDX)
                    169:                                        anar |= ANAR_PAUSE_TOWARDS;
                    170:                        }
                    171:                        PHY_WRITE(sc, MII_ANAR, anar);
                    172:                        if (sc->mii_flags & MIIF_HAVE_GTCR) {
                    173:                                uint16_t gtcr = 0;
                    174:
                    175:                                if (sc->mii_extcapabilities & EXTSR_1000TFDX)
                    176:                                        gtcr |= GTCR_ADV_1000TFDX;
                    177:                                if (sc->mii_extcapabilities & EXTSR_1000THDX)
                    178:                                        gtcr |= GTCR_ADV_1000THDX;
                    179:
                    180:                                PHY_WRITE(sc, MII_100T2CR, gtcr);
                    181:                        }
                    182:                }
                    183:                PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
                    184:        }
                    185:
                    186:        if (waitfor) {
                    187:                /* Wait 500ms for it to complete. */
                    188:                for (i = 0; i < 500; i++) {
                    189:                        if ((bmsr = PHY_READ(sc, MII_BMSR)) & BMSR_ACOMP)
                    190:                                return (0);
                    191:                        delay(1000);
                    192:                }
                    193:
                    194:                /*
                    195:                 * Don't need to worry about clearing MIIF_DOINGAUTO.
                    196:                 * If that's set, a timeout is pending, and it will
                    197:                 * clear the flag.
                    198:                 */
                    199:                return (EIO);
                    200:        }
                    201:
                    202:        /*
                    203:         * Just let it finish asynchronously.  This is for the benefit of
                    204:         * the tick handler driving autonegotiation.  Don't want 500ms
                    205:         * delays all the time while the system is running!
                    206:         */
                    207:        if (sc->mii_flags & MIIF_AUTOTSLEEP) {
                    208:                sc->mii_flags |= MIIF_DOINGAUTO;
                    209:                tsleep(&sc->mii_flags, PZERO, "miiaut", hz >> 1);
                    210:                mii_phy_auto_timeout(sc);
                    211:        } else if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) {
                    212:                sc->mii_flags |= MIIF_DOINGAUTO;
                    213:                timeout_set(&sc->mii_phy_timo, mii_phy_auto_timeout, sc);
                    214:                timeout_add(&sc->mii_phy_timo, hz / 2);
                    215:        }
                    216:        return (EJUSTRETURN);
                    217: }
                    218:
                    219: void
                    220: mii_phy_auto_timeout(void *arg)
                    221: {
                    222:        struct mii_softc *sc = arg;
                    223:        int s, bmsr;
                    224:
                    225:        if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0)
                    226:                return;
                    227:
                    228:        s = splnet();
                    229:        sc->mii_flags &= ~MIIF_DOINGAUTO;
                    230:        bmsr = PHY_READ(sc, MII_BMSR);
                    231:
                    232:        /* Update the media status. */
                    233:        (void) PHY_SERVICE(sc, sc->mii_pdata, MII_POLLSTAT);
                    234:        splx(s);
                    235: }
                    236:
                    237: int
                    238: mii_phy_tick(struct mii_softc *sc)
                    239: {
                    240:        struct mii_data *mii = sc->mii_pdata;
                    241:        struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
                    242:        int reg;
                    243:
                    244:        /* Just bail now if the interface is down. */
                    245:        if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
                    246:                return (EJUSTRETURN);
                    247:
                    248:        /*
                    249:         * If we're not doing autonegotiation, we don't need to do
                    250:         * any extra work here.  However, we need to check the link
                    251:         * status so we can generate an announcement if the status
                    252:         * changes.
                    253:         */
                    254:        if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
                    255:                return (0);
                    256:
                    257:        /* Read the status register twice; BMSR_LINK is latch-low. */
                    258:        reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
                    259:        if (reg & BMSR_LINK) {
                    260:                /*
                    261:                 * See above.
                    262:                 */
                    263:                return (0);
                    264:        }
                    265:
                    266:        /*
                    267:         * Only retry autonegotiation every mii_anegticks seconds.
                    268:         */
                    269:        if (!sc->mii_anegticks)
                    270:                sc->mii_anegticks = MII_ANEGTICKS;
                    271:
                    272:        if (++sc->mii_ticks <= sc->mii_anegticks)
                    273:                return (EJUSTRETURN);
                    274:
                    275:        sc->mii_ticks = 0;
                    276:        PHY_RESET(sc);
                    277:
                    278:        if (mii_phy_auto(sc, 0) == EJUSTRETURN)
                    279:                return (EJUSTRETURN);
                    280:
                    281:        /*
                    282:         * Might need to generate a status message if autonegotiation
                    283:         * failed.
                    284:         */
                    285:        return (0);
                    286: }
                    287:
                    288: void
                    289: mii_phy_reset(struct mii_softc *sc)
                    290: {
                    291:        int reg, i;
                    292:
                    293:        if (sc->mii_flags & MIIF_NOISOLATE)
                    294:                reg = BMCR_RESET;
                    295:        else
                    296:                reg = BMCR_RESET | BMCR_ISO;
                    297:        PHY_WRITE(sc, MII_BMCR, reg);
                    298:
                    299:        /*
                    300:         * It is best to allow a little time for the reset to settle
                    301:         * in before we start polling the BMCR again.  Notably, the
                    302:         * DP83840A manual states that there should be a 500us delay
                    303:         * between asserting software reset and attempting MII serial
                    304:         * operations.  Also, a DP83815 can get into a bad state on
                    305:         * cable removal and reinsertion if we do not delay here.
                    306:         */
                    307:        delay(500);
                    308:
                    309:        /* Wait another 100ms for it to complete. */
                    310:        for (i = 0; i < 100; i++) {
                    311:                reg = PHY_READ(sc, MII_BMCR);
                    312:                if ((reg & BMCR_RESET) == 0)
                    313:                        break;
                    314:                delay(1000);
                    315:        }
                    316:
                    317:        if (sc->mii_inst != 0 && ((sc->mii_flags & MIIF_NOISOLATE) == 0))
                    318:                PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
                    319: }
                    320:
                    321: void
                    322: mii_phy_down(struct mii_softc *sc)
                    323: {
                    324:        if (sc->mii_flags & MIIF_DOINGAUTO) {
                    325:                sc->mii_flags &= ~MIIF_DOINGAUTO;
                    326:                timeout_del(&sc->mii_phy_timo);
                    327:        }
                    328: }
                    329:
                    330:
                    331: void
                    332: mii_phy_status(struct mii_softc *sc)
                    333: {
                    334:        PHY_STATUS(sc);
                    335: }
                    336:
                    337: void
                    338: mii_phy_update(struct mii_softc *sc, int cmd)
                    339: {
                    340:        struct mii_data *mii = sc->mii_pdata;
                    341:        struct ifnet *ifp = mii->mii_ifp;
                    342:        int announce, s;
                    343:
                    344:        if (sc->mii_media_active != mii->mii_media_active ||
                    345:            sc->mii_media_status != mii->mii_media_status ||
                    346:            cmd == MII_MEDIACHG) {
                    347:                announce = mii_phy_statusmsg(sc);
                    348:                (*mii->mii_statchg)(sc->mii_dev.dv_parent);
                    349:                sc->mii_media_active = mii->mii_media_active;
                    350:                sc->mii_media_status = mii->mii_media_status;
                    351:
                    352:                if (announce) {
                    353:                        s = splnet();
                    354:                        if_link_state_change(ifp);
                    355:                        splx(s);
                    356:                }
                    357:        }
                    358: }
                    359:
                    360: int
                    361: mii_phy_statusmsg(struct mii_softc *sc)
                    362: {
                    363:        struct mii_data *mii = sc->mii_pdata;
                    364:        struct ifnet *ifp = mii->mii_ifp;
                    365:        int baudrate, link_state, announce = 0;
                    366:
                    367:        if (mii->mii_media_status & IFM_AVALID) {
                    368:                if (mii->mii_media_status & IFM_ACTIVE) {
                    369:                        if (mii->mii_media_active & IFM_FDX)
                    370:                                link_state = LINK_STATE_FULL_DUPLEX;
                    371:                        else if (mii->mii_media_active & IFM_HDX)
                    372:                                link_state = LINK_STATE_HALF_DUPLEX;
                    373:                        else
                    374:                                link_state = LINK_STATE_UP;
                    375:                } else
                    376:                        link_state = LINK_STATE_DOWN;
                    377:        } else
                    378:                link_state = LINK_STATE_UNKNOWN;
                    379:
                    380:        baudrate = ifmedia_baudrate(mii->mii_media_active);
                    381:
                    382:        if (link_state != ifp->if_link_state) {
                    383:                ifp->if_link_state = link_state;
                    384:                /*
                    385:                 * XXX Right here we'd like to notify protocols
                    386:                 * XXX that the link status has changed, so that
                    387:                 * XXX e.g. Duplicate Address Detection can restart.
                    388:                 */
                    389:                announce = 1;
                    390:        }
                    391:
                    392:        if (baudrate != ifp->if_baudrate) {
                    393:                ifp->if_baudrate = baudrate;
                    394:                announce = 1;
                    395:        }
                    396:
                    397:        return (announce);
                    398: }
                    399:
                    400: /*
                    401:  * Initialize generic PHY media based on BMSR, called when a PHY is
                    402:  * attached.  We expect to be set up to print a comma-separated list
                    403:  * of media names.  Does not print a newline.
                    404:  */
                    405: void
                    406: mii_phy_add_media(struct mii_softc *sc)
                    407: {
                    408:        struct mii_data *mii = sc->mii_pdata;
                    409:
                    410: #define        ADD(m, c)       ifmedia_add(&mii->mii_media, (m), (c), NULL)
                    411:
                    412:        if ((sc->mii_flags & MIIF_NOISOLATE) == 0)
                    413:                ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
                    414:                    MII_MEDIA_NONE);
                    415:
                    416:        if (sc->mii_capabilities & BMSR_10THDX) {
                    417:                ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst),
                    418:                    MII_MEDIA_10_T);
                    419:        }
                    420:        if (sc->mii_capabilities & BMSR_10TFDX) {
                    421:                ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
                    422:                    MII_MEDIA_10_T_FDX);
                    423:        }
                    424:        if (sc->mii_capabilities & BMSR_100TXHDX) {
                    425:                ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
                    426:                    MII_MEDIA_100_TX);
                    427:        }
                    428:        if (sc->mii_capabilities & BMSR_100TXFDX) {
                    429:                ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
                    430:                    MII_MEDIA_100_TX_FDX);
                    431:        }
                    432:        if (sc->mii_capabilities & BMSR_100T4) {
                    433:                ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst),
                    434:                    MII_MEDIA_100_T4);
                    435:        }
                    436:        if (sc->mii_extcapabilities & EXTSR_MEDIAMASK) {
                    437:                /*
                    438:                 * XXX Right now only handle 1000SX and 1000TX.  Need
                    439:                 * XXX to handle 1000LX and 1000CX some how.
                    440:                 */
                    441:                if (sc->mii_extcapabilities & EXTSR_1000XHDX) {
                    442:                        sc->mii_anegticks = MII_ANEGTICKS_GIGE;
                    443:                        sc->mii_flags |= MIIF_IS_1000X;
                    444:                        ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0,
                    445:                            sc->mii_inst), MII_MEDIA_1000_X);
                    446:                }
                    447:                if (sc->mii_extcapabilities & EXTSR_1000XFDX) {
                    448:                        sc->mii_anegticks = MII_ANEGTICKS_GIGE;
                    449:                        sc->mii_flags |= MIIF_IS_1000X;
                    450:                        ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX,
                    451:                            sc->mii_inst), MII_MEDIA_1000_X_FDX);
                    452:                }
                    453:
                    454:                /*
                    455:                 * 1000baseT media needs to be able to manipulate
                    456:                 * master/slave mode.  We set IFM_ETH_MASTER in
                    457:                 * the "don't care mask" and filter it out when
                    458:                 * the media is set.
                    459:                 *
                    460:                 * All 1000baseT PHYs have a 1000baseT control register.
                    461:                 */
                    462:                if (sc->mii_extcapabilities & EXTSR_1000THDX) {
                    463:                        sc->mii_anegticks = MII_ANEGTICKS_GIGE;
                    464:                        sc->mii_flags |= MIIF_HAVE_GTCR;
                    465:                        mii->mii_media.ifm_mask |= IFM_ETH_MASTER;
                    466:                        ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0,
                    467:                            sc->mii_inst), MII_MEDIA_1000_T);
                    468:                }
                    469:                if (sc->mii_extcapabilities & EXTSR_1000TFDX) {
                    470:                        sc->mii_anegticks = MII_ANEGTICKS_GIGE;
                    471:                        sc->mii_flags |= MIIF_HAVE_GTCR;
                    472:                        mii->mii_media.ifm_mask |= IFM_ETH_MASTER;
                    473:                        ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX,
                    474:                            sc->mii_inst), MII_MEDIA_1000_T_FDX);
                    475:                }
                    476:        }
                    477:
                    478:        if (sc->mii_capabilities & BMSR_ANEG) {
                    479:                ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst),
                    480:                    MII_NMEDIA);        /* intentionally invalid index */
                    481:        }
                    482: #undef ADD
                    483: }
                    484:
                    485: void
                    486: mii_phy_delete_media(struct mii_softc *sc)
                    487: {
                    488:        struct mii_data *mii = sc->mii_pdata;
                    489:
                    490:        ifmedia_delete_instance(&mii->mii_media, sc->mii_inst);
                    491: }
                    492:
                    493: int
                    494: mii_phy_activate(struct device *self, enum devact act)
                    495: {
                    496:        int rv = 0;
                    497:
                    498:        switch (act) {
                    499:        case DVACT_ACTIVATE:
                    500:                rv = EOPNOTSUPP;
                    501:                break;
                    502:
                    503:        case DVACT_DEACTIVATE:
                    504:                /* Nothing special to do. */
                    505:                break;
                    506:        }
                    507:
                    508:        return (rv);
                    509: }
                    510:
                    511: int
                    512: mii_phy_detach(struct device *self, int flags)
                    513: {
                    514:        struct mii_softc *sc = (void *) self;
                    515:
                    516:        if (sc->mii_flags & MIIF_DOINGAUTO)
                    517:                timeout_del(&sc->mii_phy_timo);
                    518:
                    519:        mii_phy_delete_media(sc);
                    520:
                    521:        return (0);
                    522: }
                    523:
                    524: const struct mii_phydesc *
                    525: mii_phy_match(const struct mii_attach_args *ma, const struct mii_phydesc *mpd)
                    526: {
                    527:
                    528:        for (; mpd->mpd_name != NULL; mpd++) {
                    529:                if (MII_OUI(ma->mii_id1, ma->mii_id2) == mpd->mpd_oui &&
                    530:                    MII_MODEL(ma->mii_id2) == mpd->mpd_model)
                    531:                        return (mpd);
                    532:        }
                    533:        return (NULL);
                    534: }
                    535:
                    536: /*
                    537:  * Return the flow control status flag from MII_ANAR & MII_ANLPAR.
                    538:  */
                    539: int
                    540: mii_phy_flowstatus(struct mii_softc *sc)
                    541: {
                    542:        int anar, anlpar;
                    543:
                    544:        if ((sc->mii_flags & MIIF_DOPAUSE) == 0)
                    545:                return (0);
                    546:
                    547:        anar = PHY_READ(sc, MII_ANAR);
                    548:        anlpar = PHY_READ(sc, MII_ANLPAR);
                    549:
                    550:        /* For 1000baseX, the bits are in a different location. */
                    551:        if (sc->mii_flags & MIIF_IS_1000X) {
                    552:                anar <<= 3;
                    553:                anlpar <<= 3;
                    554:        }
                    555:
                    556:        if ((anar & ANAR_PAUSE_SYM) & (anlpar & ANLPAR_PAUSE_SYM))
                    557:                return (IFM_FLOW|IFM_ETH_TXPAUSE|IFM_ETH_RXPAUSE);
                    558:
                    559:        if ((anar & ANAR_PAUSE_SYM) == 0) {
                    560:                if ((anar & ANAR_PAUSE_ASYM) &&
                    561:                    ((anlpar & ANLPAR_PAUSE_TOWARDS) == ANLPAR_PAUSE_TOWARDS))
                    562:                        return (IFM_FLOW|IFM_ETH_TXPAUSE);
                    563:                else
                    564:                        return (0);
                    565:        }
                    566:
                    567:        if ((anar & ANAR_PAUSE_ASYM) == 0) {
                    568:                if (anlpar & ANLPAR_PAUSE_SYM)
                    569:                        return (IFM_FLOW|IFM_ETH_TXPAUSE|IFM_ETH_RXPAUSE);
                    570:                else
                    571:                        return (0);
                    572:        }
                    573:
                    574:        switch ((anlpar & ANLPAR_PAUSE_TOWARDS)) {
                    575:        case ANLPAR_PAUSE_NONE:
                    576:                return (0);
                    577:
                    578:        case ANLPAR_PAUSE_ASYM:
                    579:                return (IFM_FLOW|IFM_ETH_RXPAUSE);
                    580:
                    581:        default:
                    582:                return (IFM_FLOW|IFM_ETH_RXPAUSE|IFM_ETH_TXPAUSE);
                    583:        }
                    584:        /* NOTREACHED */
                    585: }
                    586:
                    587: /*
                    588:  * Given an ifmedia word, return the corresponding ANAR value.
                    589:  */
                    590: int
                    591: mii_anar(int media)
                    592: {
                    593:        int rv;
                    594:
                    595:        switch (media & (IFM_TMASK|IFM_NMASK|IFM_FDX)) {
                    596:        case IFM_ETHER|IFM_10_T:
                    597:                rv = ANAR_10|ANAR_CSMA;
                    598:                break;
                    599:        case IFM_ETHER|IFM_10_T|IFM_FDX:
                    600:                rv = ANAR_10_FD|ANAR_CSMA;
                    601:                break;
                    602:        case IFM_ETHER|IFM_100_TX:
                    603:                rv = ANAR_TX|ANAR_CSMA;
                    604:                break;
                    605:        case IFM_ETHER|IFM_100_TX|IFM_FDX:
                    606:                rv = ANAR_TX_FD|ANAR_CSMA;
                    607:                break;
                    608:        case IFM_ETHER|IFM_100_T4:
                    609:                rv = ANAR_T4|ANAR_CSMA;
                    610:                break;
                    611:        default:
                    612:                rv = 0;
                    613:                break;
                    614:        }
                    615:
                    616:        return (rv);
                    617: }

CVSweb