diff --git a/sys/dev/my/if_my.c b/sys/dev/my/if_my.c index 42a85bf502f3..9c90234bdf15 100644 --- a/sys/dev/my/if_my.c +++ b/sys/dev/my/if_my.c @@ -1,1764 +1,1763 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Written by: yen_cw@myson.com.tw * Copyright (c) 2002 Myson Technology Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Myson fast ethernet PCI NIC driver, available at: http://www.myson.com.tw/ */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #define NBPFILTER 1 #include #include #include #include #include #include #include #include #include /* for vtophys */ #include /* for vtophys */ #include #include #include #include #include #include /* * #define MY_USEIOSPACE */ static int MY_USEIOSPACE = 1; #ifdef MY_USEIOSPACE #define MY_RES SYS_RES_IOPORT #define MY_RID MY_PCI_LOIO #else #define MY_RES SYS_RES_MEMORY #define MY_RID MY_PCI_LOMEM #endif #include /* * Various supported device vendors/types and their names. */ struct my_type *my_info_tmp; static struct my_type my_devs[] = { {MYSONVENDORID, MTD800ID, "Myson MTD80X Based Fast Ethernet Card"}, {MYSONVENDORID, MTD803ID, "Myson MTD80X Based Fast Ethernet Card"}, {MYSONVENDORID, MTD891ID, "Myson MTD89X Based Giga Ethernet Card"}, {0, 0, NULL} }; /* * Various supported PHY vendors/types and their names. Note that this driver * will work with pretty much any MII-compliant PHY, so failure to positively * identify the chip is not a fatal error. */ static struct my_type my_phys[] = { {MysonPHYID0, MysonPHYID0, ""}, {SeeqPHYID0, SeeqPHYID0, ""}, {AhdocPHYID0, AhdocPHYID0, ""}, {MarvellPHYID0, MarvellPHYID0, ""}, {LevelOnePHYID0, LevelOnePHYID0, ""}, {0, 0, ""} }; static int my_probe(device_t); static int my_attach(device_t); static int my_detach(device_t); static int my_newbuf(struct my_softc *, struct my_chain_onefrag *); static int my_encap(struct my_softc *, struct my_chain *, struct mbuf *); static void my_rxeof(struct my_softc *); static void my_txeof(struct my_softc *); static void my_txeoc(struct my_softc *); static void my_intr(void *); -static void my_start(struct ifnet *); -static void my_start_locked(struct ifnet *); -static int my_ioctl(struct ifnet *, u_long, caddr_t); +static void my_start(if_t); +static void my_start_locked(if_t); +static int my_ioctl(if_t, u_long, caddr_t); static void my_init(void *); static void my_init_locked(struct my_softc *); static void my_stop(struct my_softc *); static void my_autoneg_timeout(void *); static void my_watchdog(void *); static int my_shutdown(device_t); -static int my_ifmedia_upd(struct ifnet *); -static void my_ifmedia_sts(struct ifnet *, struct ifmediareq *); +static int my_ifmedia_upd(if_t); +static void my_ifmedia_sts(if_t, struct ifmediareq *); static u_int16_t my_phy_readreg(struct my_softc *, int); static void my_phy_writereg(struct my_softc *, int, int); static void my_autoneg_xmit(struct my_softc *); static void my_autoneg_mii(struct my_softc *, int, int); static void my_setmode_mii(struct my_softc *, int); static void my_getmode_mii(struct my_softc *); static void my_setcfg(struct my_softc *, int); static void my_setmulti(struct my_softc *); static void my_reset(struct my_softc *); static int my_list_rx_init(struct my_softc *); static int my_list_tx_init(struct my_softc *); static long my_send_cmd_to_phy(struct my_softc *, int, int); #define MY_SETBIT(sc, reg, x) CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) | (x)) #define MY_CLRBIT(sc, reg, x) CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) & ~(x)) static device_method_t my_methods[] = { /* Device interface */ DEVMETHOD(device_probe, my_probe), DEVMETHOD(device_attach, my_attach), DEVMETHOD(device_detach, my_detach), DEVMETHOD(device_shutdown, my_shutdown), DEVMETHOD_END }; static driver_t my_driver = { "my", my_methods, sizeof(struct my_softc) }; DRIVER_MODULE(my, pci, my_driver, 0, 0); MODULE_PNP_INFO("U16:vendor;U16:device;D:#", pci, my, my_devs, nitems(my_devs) - 1); MODULE_DEPEND(my, pci, 1, 1, 1); MODULE_DEPEND(my, ether, 1, 1, 1); static long my_send_cmd_to_phy(struct my_softc * sc, int opcode, int regad) { long miir; int i; int mask, data; MY_LOCK_ASSERT(sc); /* enable MII output */ miir = CSR_READ_4(sc, MY_MANAGEMENT); miir &= 0xfffffff0; miir |= MY_MASK_MIIR_MII_WRITE + MY_MASK_MIIR_MII_MDO; /* send 32 1's preamble */ for (i = 0; i < 32; i++) { /* low MDC; MDO is already high (miir) */ miir &= ~MY_MASK_MIIR_MII_MDC; CSR_WRITE_4(sc, MY_MANAGEMENT, miir); /* high MDC */ miir |= MY_MASK_MIIR_MII_MDC; CSR_WRITE_4(sc, MY_MANAGEMENT, miir); } /* calculate ST+OP+PHYAD+REGAD+TA */ data = opcode | (sc->my_phy_addr << 7) | (regad << 2); /* sent out */ mask = 0x8000; while (mask) { /* low MDC, prepare MDO */ miir &= ~(MY_MASK_MIIR_MII_MDC + MY_MASK_MIIR_MII_MDO); if (mask & data) miir |= MY_MASK_MIIR_MII_MDO; CSR_WRITE_4(sc, MY_MANAGEMENT, miir); /* high MDC */ miir |= MY_MASK_MIIR_MII_MDC; CSR_WRITE_4(sc, MY_MANAGEMENT, miir); DELAY(30); /* next */ mask >>= 1; if (mask == 0x2 && opcode == MY_OP_READ) miir &= ~MY_MASK_MIIR_MII_WRITE; } return miir; } static u_int16_t my_phy_readreg(struct my_softc * sc, int reg) { long miir; int mask, data; MY_LOCK_ASSERT(sc); if (sc->my_info->my_did == MTD803ID) data = CSR_READ_2(sc, MY_PHYBASE + reg * 2); else { miir = my_send_cmd_to_phy(sc, MY_OP_READ, reg); /* read data */ mask = 0x8000; data = 0; while (mask) { /* low MDC */ miir &= ~MY_MASK_MIIR_MII_MDC; CSR_WRITE_4(sc, MY_MANAGEMENT, miir); /* read MDI */ miir = CSR_READ_4(sc, MY_MANAGEMENT); if (miir & MY_MASK_MIIR_MII_MDI) data |= mask; /* high MDC, and wait */ miir |= MY_MASK_MIIR_MII_MDC; CSR_WRITE_4(sc, MY_MANAGEMENT, miir); DELAY(30); /* next */ mask >>= 1; } /* low MDC */ miir &= ~MY_MASK_MIIR_MII_MDC; CSR_WRITE_4(sc, MY_MANAGEMENT, miir); } return (u_int16_t) data; } static void my_phy_writereg(struct my_softc * sc, int reg, int data) { long miir; int mask; MY_LOCK_ASSERT(sc); if (sc->my_info->my_did == MTD803ID) CSR_WRITE_2(sc, MY_PHYBASE + reg * 2, data); else { miir = my_send_cmd_to_phy(sc, MY_OP_WRITE, reg); /* write data */ mask = 0x8000; while (mask) { /* low MDC, prepare MDO */ miir &= ~(MY_MASK_MIIR_MII_MDC + MY_MASK_MIIR_MII_MDO); if (mask & data) miir |= MY_MASK_MIIR_MII_MDO; CSR_WRITE_4(sc, MY_MANAGEMENT, miir); DELAY(1); /* high MDC */ miir |= MY_MASK_MIIR_MII_MDC; CSR_WRITE_4(sc, MY_MANAGEMENT, miir); DELAY(1); /* next */ mask >>= 1; } /* low MDC */ miir &= ~MY_MASK_MIIR_MII_MDC; CSR_WRITE_4(sc, MY_MANAGEMENT, miir); } return; } static u_int my_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) { uint32_t *hashes = arg; int h; h = ~ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 26; if (h < 32) hashes[0] |= (1 << h); else hashes[1] |= (1 << (h - 32)); return (1); } /* * Program the 64-bit multicast hash filter. */ static void my_setmulti(struct my_softc * sc) { - struct ifnet *ifp; + if_t ifp; u_int32_t hashes[2] = {0, 0}; u_int32_t rxfilt; MY_LOCK_ASSERT(sc); ifp = sc->my_ifp; rxfilt = CSR_READ_4(sc, MY_TCRRCR); - if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { + if (if_getflags(ifp) & IFF_ALLMULTI || if_getflags(ifp) & IFF_PROMISC) { rxfilt |= MY_AM; CSR_WRITE_4(sc, MY_TCRRCR, rxfilt); CSR_WRITE_4(sc, MY_MAR0, 0xFFFFFFFF); CSR_WRITE_4(sc, MY_MAR1, 0xFFFFFFFF); return; } /* first, zot all the existing hash bits */ CSR_WRITE_4(sc, MY_MAR0, 0); CSR_WRITE_4(sc, MY_MAR1, 0); /* now program new ones */ if (if_foreach_llmaddr(ifp, my_hash_maddr, hashes) > 0) rxfilt |= MY_AM; else rxfilt &= ~MY_AM; CSR_WRITE_4(sc, MY_MAR0, hashes[0]); CSR_WRITE_4(sc, MY_MAR1, hashes[1]); CSR_WRITE_4(sc, MY_TCRRCR, rxfilt); } /* * Initiate an autonegotiation session. */ static void my_autoneg_xmit(struct my_softc * sc) { u_int16_t phy_sts = 0; MY_LOCK_ASSERT(sc); my_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); DELAY(500); while (my_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_RESET); phy_sts = my_phy_readreg(sc, PHY_BMCR); phy_sts |= PHY_BMCR_AUTONEGENBL | PHY_BMCR_AUTONEGRSTR; my_phy_writereg(sc, PHY_BMCR, phy_sts); return; } static void my_autoneg_timeout(void *arg) { struct my_softc *sc; sc = arg; MY_LOCK_ASSERT(sc); my_autoneg_mii(sc, MY_FLAG_DELAYTIMEO, 1); } /* * Invoke autonegotiation on a PHY. */ static void my_autoneg_mii(struct my_softc * sc, int flag, int verbose) { u_int16_t phy_sts = 0, media, advert, ability; u_int16_t ability2 = 0; - struct ifnet *ifp; + if_t ifp; struct ifmedia *ifm; MY_LOCK_ASSERT(sc); ifm = &sc->ifmedia; ifp = sc->my_ifp; ifm->ifm_media = IFM_ETHER | IFM_AUTO; #ifndef FORCE_AUTONEG_TFOUR /* * First, see if autoneg is supported. If not, there's no point in * continuing. */ phy_sts = my_phy_readreg(sc, PHY_BMSR); if (!(phy_sts & PHY_BMSR_CANAUTONEG)) { if (verbose) device_printf(sc->my_dev, "autonegotiation not supported\n"); ifm->ifm_media = IFM_ETHER | IFM_10_T | IFM_HDX; return; } #endif switch (flag) { case MY_FLAG_FORCEDELAY: /* * XXX Never use this option anywhere but in the probe * routine: making the kernel stop dead in its tracks for * three whole seconds after we've gone multi-user is really * bad manners. */ my_autoneg_xmit(sc); DELAY(5000000); break; case MY_FLAG_SCHEDDELAY: /* * Wait for the transmitter to go idle before starting an * autoneg session, otherwise my_start() may clobber our * timeout, and we don't want to allow transmission during an * autoneg session since that can screw it up. */ if (sc->my_cdata.my_tx_head != NULL) { sc->my_want_auto = 1; MY_UNLOCK(sc); return; } my_autoneg_xmit(sc); callout_reset(&sc->my_autoneg_timer, hz * 5, my_autoneg_timeout, sc); sc->my_autoneg = 1; sc->my_want_auto = 0; return; case MY_FLAG_DELAYTIMEO: callout_stop(&sc->my_autoneg_timer); sc->my_autoneg = 0; break; default: device_printf(sc->my_dev, "invalid autoneg flag: %d\n", flag); return; } if (my_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_AUTONEGCOMP) { if (verbose) device_printf(sc->my_dev, "autoneg complete, "); phy_sts = my_phy_readreg(sc, PHY_BMSR); } else { if (verbose) device_printf(sc->my_dev, "autoneg not complete, "); } media = my_phy_readreg(sc, PHY_BMCR); /* Link is good. Report modes and set duplex mode. */ if (my_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT) { if (verbose) device_printf(sc->my_dev, "link status good. "); advert = my_phy_readreg(sc, PHY_ANAR); ability = my_phy_readreg(sc, PHY_LPAR); if ((sc->my_pinfo->my_vid == MarvellPHYID0) || (sc->my_pinfo->my_vid == LevelOnePHYID0)) { ability2 = my_phy_readreg(sc, PHY_1000SR); if (ability2 & PHY_1000SR_1000BTXFULL) { advert = 0; ability = 0; /* * this version did not support 1000M, * ifm->ifm_media = * IFM_ETHER|IFM_1000_T|IFM_FDX; */ ifm->ifm_media = IFM_ETHER | IFM_100_TX | IFM_FDX; media &= ~PHY_BMCR_SPEEDSEL; media |= PHY_BMCR_1000; media |= PHY_BMCR_DUPLEX; printf("(full-duplex, 1000Mbps)\n"); } else if (ability2 & PHY_1000SR_1000BTXHALF) { advert = 0; ability = 0; /* * this version did not support 1000M, * ifm->ifm_media = IFM_ETHER|IFM_1000_T; */ ifm->ifm_media = IFM_ETHER | IFM_100_TX; media &= ~PHY_BMCR_SPEEDSEL; media &= ~PHY_BMCR_DUPLEX; media |= PHY_BMCR_1000; printf("(half-duplex, 1000Mbps)\n"); } } if (advert & PHY_ANAR_100BT4 && ability & PHY_ANAR_100BT4) { ifm->ifm_media = IFM_ETHER | IFM_100_T4; media |= PHY_BMCR_SPEEDSEL; media &= ~PHY_BMCR_DUPLEX; printf("(100baseT4)\n"); } else if (advert & PHY_ANAR_100BTXFULL && ability & PHY_ANAR_100BTXFULL) { ifm->ifm_media = IFM_ETHER | IFM_100_TX | IFM_FDX; media |= PHY_BMCR_SPEEDSEL; media |= PHY_BMCR_DUPLEX; printf("(full-duplex, 100Mbps)\n"); } else if (advert & PHY_ANAR_100BTXHALF && ability & PHY_ANAR_100BTXHALF) { ifm->ifm_media = IFM_ETHER | IFM_100_TX | IFM_HDX; media |= PHY_BMCR_SPEEDSEL; media &= ~PHY_BMCR_DUPLEX; printf("(half-duplex, 100Mbps)\n"); } else if (advert & PHY_ANAR_10BTFULL && ability & PHY_ANAR_10BTFULL) { ifm->ifm_media = IFM_ETHER | IFM_10_T | IFM_FDX; media &= ~PHY_BMCR_SPEEDSEL; media |= PHY_BMCR_DUPLEX; printf("(full-duplex, 10Mbps)\n"); } else if (advert) { ifm->ifm_media = IFM_ETHER | IFM_10_T | IFM_HDX; media &= ~PHY_BMCR_SPEEDSEL; media &= ~PHY_BMCR_DUPLEX; printf("(half-duplex, 10Mbps)\n"); } media &= ~PHY_BMCR_AUTONEGENBL; /* Set ASIC's duplex mode to match the PHY. */ my_phy_writereg(sc, PHY_BMCR, media); my_setcfg(sc, media); } else { if (verbose) device_printf(sc->my_dev, "no carrier\n"); } my_init_locked(sc); if (sc->my_tx_pend) { sc->my_autoneg = 0; sc->my_tx_pend = 0; my_start_locked(ifp); } return; } /* * To get PHY ability. */ static void my_getmode_mii(struct my_softc * sc) { u_int16_t bmsr; - struct ifnet *ifp; + if_t ifp; MY_LOCK_ASSERT(sc); ifp = sc->my_ifp; bmsr = my_phy_readreg(sc, PHY_BMSR); if (bootverbose) device_printf(sc->my_dev, "PHY status word: %x\n", bmsr); /* fallback */ sc->ifmedia.ifm_media = IFM_ETHER | IFM_10_T | IFM_HDX; if (bmsr & PHY_BMSR_10BTHALF) { if (bootverbose) device_printf(sc->my_dev, "10Mbps half-duplex mode supported\n"); ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_10_T | IFM_HDX, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_10_T, 0, NULL); } if (bmsr & PHY_BMSR_10BTFULL) { if (bootverbose) device_printf(sc->my_dev, "10Mbps full-duplex mode supported\n"); ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL); sc->ifmedia.ifm_media = IFM_ETHER | IFM_10_T | IFM_FDX; } if (bmsr & PHY_BMSR_100BTXHALF) { if (bootverbose) device_printf(sc->my_dev, "100Mbps half-duplex mode supported\n"); - ifp->if_baudrate = 100000000; + if_setbaudrate(ifp, 100000000); ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_100_TX, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_100_TX | IFM_HDX, 0, NULL); sc->ifmedia.ifm_media = IFM_ETHER | IFM_100_TX | IFM_HDX; } if (bmsr & PHY_BMSR_100BTXFULL) { if (bootverbose) device_printf(sc->my_dev, "100Mbps full-duplex mode supported\n"); - ifp->if_baudrate = 100000000; + if_setbaudrate(ifp, 100000000); ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL); sc->ifmedia.ifm_media = IFM_ETHER | IFM_100_TX | IFM_FDX; } /* Some also support 100BaseT4. */ if (bmsr & PHY_BMSR_100BT4) { if (bootverbose) device_printf(sc->my_dev, "100baseT4 mode supported\n"); - ifp->if_baudrate = 100000000; + if_setbaudrate(ifp, 100000000); ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_100_T4, 0, NULL); sc->ifmedia.ifm_media = IFM_ETHER | IFM_100_T4; #ifdef FORCE_AUTONEG_TFOUR if (bootverbose) device_printf(sc->my_dev, "forcing on autoneg support for BT4\n"); ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_AUTO, 0 NULL): sc->ifmedia.ifm_media = IFM_ETHER | IFM_AUTO; #endif } #if 0 /* this version did not support 1000M, */ if (sc->my_pinfo->my_vid == MarvellPHYID0) { if (bootverbose) device_printf(sc->my_dev, "1000Mbps half-duplex mode supported\n"); - ifp->if_baudrate = 1000000000; + if_setbaudrate(ifp, 1000000000); ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_1000_T, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_1000_T | IFM_HDX, 0, NULL); if (bootverbose) device_printf(sc->my_dev, "1000Mbps full-duplex mode supported\n"); - ifp->if_baudrate = 1000000000; + if_setbaudrate(ifp, 1000000000); ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL); sc->ifmedia.ifm_media = IFM_ETHER | IFM_1000_T | IFM_FDX; } #endif if (bmsr & PHY_BMSR_CANAUTONEG) { if (bootverbose) device_printf(sc->my_dev, "autoneg supported\n"); ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL); sc->ifmedia.ifm_media = IFM_ETHER | IFM_AUTO; } return; } /* * Set speed and duplex mode. */ static void my_setmode_mii(struct my_softc * sc, int media) { u_int16_t bmcr; MY_LOCK_ASSERT(sc); /* * If an autoneg session is in progress, stop it. */ if (sc->my_autoneg) { device_printf(sc->my_dev, "canceling autoneg session\n"); callout_stop(&sc->my_autoneg_timer); sc->my_autoneg = sc->my_want_auto = 0; bmcr = my_phy_readreg(sc, PHY_BMCR); bmcr &= ~PHY_BMCR_AUTONEGENBL; my_phy_writereg(sc, PHY_BMCR, bmcr); } device_printf(sc->my_dev, "selecting MII, "); bmcr = my_phy_readreg(sc, PHY_BMCR); bmcr &= ~(PHY_BMCR_AUTONEGENBL | PHY_BMCR_SPEEDSEL | PHY_BMCR_1000 | PHY_BMCR_DUPLEX | PHY_BMCR_LOOPBK); #if 0 /* this version did not support 1000M, */ if (IFM_SUBTYPE(media) == IFM_1000_T) { printf("1000Mbps/T4, half-duplex\n"); bmcr &= ~PHY_BMCR_SPEEDSEL; bmcr &= ~PHY_BMCR_DUPLEX; bmcr |= PHY_BMCR_1000; } #endif if (IFM_SUBTYPE(media) == IFM_100_T4) { printf("100Mbps/T4, half-duplex\n"); bmcr |= PHY_BMCR_SPEEDSEL; bmcr &= ~PHY_BMCR_DUPLEX; } if (IFM_SUBTYPE(media) == IFM_100_TX) { printf("100Mbps, "); bmcr |= PHY_BMCR_SPEEDSEL; } if (IFM_SUBTYPE(media) == IFM_10_T) { printf("10Mbps, "); bmcr &= ~PHY_BMCR_SPEEDSEL; } if ((media & IFM_GMASK) == IFM_FDX) { printf("full duplex\n"); bmcr |= PHY_BMCR_DUPLEX; } else { printf("half duplex\n"); bmcr &= ~PHY_BMCR_DUPLEX; } my_phy_writereg(sc, PHY_BMCR, bmcr); my_setcfg(sc, bmcr); return; } /* * The Myson manual states that in order to fiddle with the 'full-duplex' and * '100Mbps' bits in the netconfig register, we first have to put the * transmit and/or receive logic in the idle state. */ static void my_setcfg(struct my_softc * sc, int bmcr) { int i, restart = 0; MY_LOCK_ASSERT(sc); if (CSR_READ_4(sc, MY_TCRRCR) & (MY_TE | MY_RE)) { restart = 1; MY_CLRBIT(sc, MY_TCRRCR, (MY_TE | MY_RE)); for (i = 0; i < MY_TIMEOUT; i++) { DELAY(10); if (!(CSR_READ_4(sc, MY_TCRRCR) & (MY_TXRUN | MY_RXRUN))) break; } if (i == MY_TIMEOUT) device_printf(sc->my_dev, "failed to force tx and rx to idle \n"); } MY_CLRBIT(sc, MY_TCRRCR, MY_PS1000); MY_CLRBIT(sc, MY_TCRRCR, MY_PS10); if (bmcr & PHY_BMCR_1000) MY_SETBIT(sc, MY_TCRRCR, MY_PS1000); else if (!(bmcr & PHY_BMCR_SPEEDSEL)) MY_SETBIT(sc, MY_TCRRCR, MY_PS10); if (bmcr & PHY_BMCR_DUPLEX) MY_SETBIT(sc, MY_TCRRCR, MY_FD); else MY_CLRBIT(sc, MY_TCRRCR, MY_FD); if (restart) MY_SETBIT(sc, MY_TCRRCR, MY_TE | MY_RE); return; } static void my_reset(struct my_softc * sc) { int i; MY_LOCK_ASSERT(sc); MY_SETBIT(sc, MY_BCR, MY_SWR); for (i = 0; i < MY_TIMEOUT; i++) { DELAY(10); if (!(CSR_READ_4(sc, MY_BCR) & MY_SWR)) break; } if (i == MY_TIMEOUT) device_printf(sc->my_dev, "reset never completed!\n"); /* Wait a little while for the chip to get its brains in order. */ DELAY(1000); return; } /* * Probe for a Myson chip. Check the PCI vendor and device IDs against our * list and return a device name if we find a match. */ static int my_probe(device_t dev) { struct my_type *t; t = my_devs; while (t->my_name != NULL) { if ((pci_get_vendor(dev) == t->my_vid) && (pci_get_device(dev) == t->my_did)) { device_set_desc(dev, t->my_name); my_info_tmp = t; return (BUS_PROBE_DEFAULT); } t++; } return (ENXIO); } /* * Attach the interface. Allocate softc structures, do ifmedia setup and * ethernet/BPF attach. */ static int my_attach(device_t dev) { int i; u_char eaddr[ETHER_ADDR_LEN]; u_int32_t iobase; struct my_softc *sc; - struct ifnet *ifp; + if_t ifp; int media = IFM_ETHER | IFM_100_TX | IFM_FDX; unsigned int round; caddr_t roundptr; struct my_type *p; u_int16_t phy_vid, phy_did, phy_sts = 0; int rid, error = 0; sc = device_get_softc(dev); sc->my_dev = dev; mtx_init(&sc->my_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF); callout_init_mtx(&sc->my_autoneg_timer, &sc->my_mtx, 0); callout_init_mtx(&sc->my_watchdog, &sc->my_mtx, 0); /* * Map control/status registers. */ pci_enable_busmaster(dev); if (my_info_tmp->my_did == MTD800ID) { iobase = pci_read_config(dev, MY_PCI_LOIO, 4); if (iobase & 0x300) MY_USEIOSPACE = 0; } rid = MY_RID; sc->my_res = bus_alloc_resource_any(dev, MY_RES, &rid, RF_ACTIVE); if (sc->my_res == NULL) { device_printf(dev, "couldn't map ports/memory\n"); error = ENXIO; goto destroy_mutex; } sc->my_btag = rman_get_bustag(sc->my_res); sc->my_bhandle = rman_get_bushandle(sc->my_res); rid = 0; sc->my_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); if (sc->my_irq == NULL) { device_printf(dev, "couldn't map interrupt\n"); error = ENXIO; goto release_io; } sc->my_info = my_info_tmp; /* Reset the adapter. */ MY_LOCK(sc); my_reset(sc); MY_UNLOCK(sc); /* * Get station address */ for (i = 0; i < ETHER_ADDR_LEN; ++i) eaddr[i] = CSR_READ_1(sc, MY_PAR0 + i); sc->my_ldata_ptr = malloc(sizeof(struct my_list_data) + 8, M_DEVBUF, M_NOWAIT); if (sc->my_ldata_ptr == NULL) { device_printf(dev, "no memory for list buffers!\n"); error = ENXIO; goto release_irq; } sc->my_ldata = (struct my_list_data *) sc->my_ldata_ptr; round = (uintptr_t)sc->my_ldata_ptr & 0xF; roundptr = sc->my_ldata_ptr; for (i = 0; i < 8; i++) { if (round % 8) { round++; roundptr++; } else break; } sc->my_ldata = (struct my_list_data *) roundptr; bzero(sc->my_ldata, sizeof(struct my_list_data)); ifp = sc->my_ifp = if_alloc(IFT_ETHER); if (ifp == NULL) { device_printf(dev, "can not if_alloc()\n"); error = ENOSPC; goto free_ldata; } - ifp->if_softc = sc; + if_setsoftc(ifp, sc); if_initname(ifp, device_get_name(dev), device_get_unit(dev)); - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_ioctl = my_ioctl; - ifp->if_start = my_start; - ifp->if_init = my_init; - ifp->if_baudrate = 10000000; - IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); - ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; - IFQ_SET_READY(&ifp->if_snd); + if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); + if_setioctlfn(ifp, my_ioctl); + if_setstartfn(ifp, my_start); + if_setinitfn(ifp, my_init); + if_setbaudrate(ifp, 10000000); + if_setsendqlen(ifp, ifqmaxlen); + if_setsendqready(ifp); if (sc->my_info->my_did == MTD803ID) sc->my_pinfo = my_phys; else { if (bootverbose) device_printf(dev, "probing for a PHY\n"); MY_LOCK(sc); for (i = MY_PHYADDR_MIN; i < MY_PHYADDR_MAX + 1; i++) { if (bootverbose) device_printf(dev, "checking address: %d\n", i); sc->my_phy_addr = i; phy_sts = my_phy_readreg(sc, PHY_BMSR); if ((phy_sts != 0) && (phy_sts != 0xffff)) break; else phy_sts = 0; } if (phy_sts) { phy_vid = my_phy_readreg(sc, PHY_VENID); phy_did = my_phy_readreg(sc, PHY_DEVID); if (bootverbose) { device_printf(dev, "found PHY at address %d, ", sc->my_phy_addr); printf("vendor id: %x device id: %x\n", phy_vid, phy_did); } p = my_phys; while (p->my_vid) { if (phy_vid == p->my_vid) { sc->my_pinfo = p; break; } p++; } if (sc->my_pinfo == NULL) sc->my_pinfo = &my_phys[PHY_UNKNOWN]; if (bootverbose) device_printf(dev, "PHY type: %s\n", sc->my_pinfo->my_name); } else { MY_UNLOCK(sc); device_printf(dev, "MII without any phy!\n"); error = ENXIO; goto free_if; } MY_UNLOCK(sc); } /* Do ifmedia setup. */ ifmedia_init(&sc->ifmedia, 0, my_ifmedia_upd, my_ifmedia_sts); MY_LOCK(sc); my_getmode_mii(sc); my_autoneg_mii(sc, MY_FLAG_FORCEDELAY, 1); media = sc->ifmedia.ifm_media; my_stop(sc); MY_UNLOCK(sc); ifmedia_set(&sc->ifmedia, media); ether_ifattach(ifp, eaddr); error = bus_setup_intr(dev, sc->my_irq, INTR_TYPE_NET | INTR_MPSAFE, NULL, my_intr, sc, &sc->my_intrhand); if (error) { device_printf(dev, "couldn't set up irq\n"); goto detach_if; } return (0); detach_if: ether_ifdetach(ifp); free_if: if_free(ifp); free_ldata: free(sc->my_ldata_ptr, M_DEVBUF); release_irq: bus_release_resource(dev, SYS_RES_IRQ, 0, sc->my_irq); release_io: bus_release_resource(dev, MY_RES, MY_RID, sc->my_res); destroy_mutex: mtx_destroy(&sc->my_mtx); return (error); } static int my_detach(device_t dev) { struct my_softc *sc; - struct ifnet *ifp; + if_t ifp; sc = device_get_softc(dev); ifp = sc->my_ifp; ether_ifdetach(ifp); MY_LOCK(sc); my_stop(sc); MY_UNLOCK(sc); bus_teardown_intr(dev, sc->my_irq, sc->my_intrhand); callout_drain(&sc->my_watchdog); callout_drain(&sc->my_autoneg_timer); if_free(ifp); free(sc->my_ldata_ptr, M_DEVBUF); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->my_irq); bus_release_resource(dev, MY_RES, MY_RID, sc->my_res); mtx_destroy(&sc->my_mtx); return (0); } /* * Initialize the transmit descriptors. */ static int my_list_tx_init(struct my_softc * sc) { struct my_chain_data *cd; struct my_list_data *ld; int i; MY_LOCK_ASSERT(sc); cd = &sc->my_cdata; ld = sc->my_ldata; for (i = 0; i < MY_TX_LIST_CNT; i++) { cd->my_tx_chain[i].my_ptr = &ld->my_tx_list[i]; if (i == (MY_TX_LIST_CNT - 1)) cd->my_tx_chain[i].my_nextdesc = &cd->my_tx_chain[0]; else cd->my_tx_chain[i].my_nextdesc = &cd->my_tx_chain[i + 1]; } cd->my_tx_free = &cd->my_tx_chain[0]; cd->my_tx_tail = cd->my_tx_head = NULL; return (0); } /* * Initialize the RX descriptors and allocate mbufs for them. Note that we * arrange the descriptors in a closed ring, so that the last descriptor * points back to the first. */ static int my_list_rx_init(struct my_softc * sc) { struct my_chain_data *cd; struct my_list_data *ld; int i; MY_LOCK_ASSERT(sc); cd = &sc->my_cdata; ld = sc->my_ldata; for (i = 0; i < MY_RX_LIST_CNT; i++) { cd->my_rx_chain[i].my_ptr = (struct my_desc *) & ld->my_rx_list[i]; if (my_newbuf(sc, &cd->my_rx_chain[i]) == ENOBUFS) { MY_UNLOCK(sc); return (ENOBUFS); } if (i == (MY_RX_LIST_CNT - 1)) { cd->my_rx_chain[i].my_nextdesc = &cd->my_rx_chain[0]; ld->my_rx_list[i].my_next = vtophys(&ld->my_rx_list[0]); } else { cd->my_rx_chain[i].my_nextdesc = &cd->my_rx_chain[i + 1]; ld->my_rx_list[i].my_next = vtophys(&ld->my_rx_list[i + 1]); } } cd->my_rx_head = &cd->my_rx_chain[0]; return (0); } /* * Initialize an RX descriptor and attach an MBUF cluster. */ static int my_newbuf(struct my_softc * sc, struct my_chain_onefrag * c) { struct mbuf *m_new = NULL; MY_LOCK_ASSERT(sc); MGETHDR(m_new, M_NOWAIT, MT_DATA); if (m_new == NULL) { device_printf(sc->my_dev, "no memory for rx list -- packet dropped!\n"); return (ENOBUFS); } if (!(MCLGET(m_new, M_NOWAIT))) { device_printf(sc->my_dev, "no memory for rx list -- packet dropped!\n"); m_freem(m_new); return (ENOBUFS); } c->my_mbuf = m_new; c->my_ptr->my_data = vtophys(mtod(m_new, caddr_t)); c->my_ptr->my_ctl = (MCLBYTES - 1) << MY_RBSShift; c->my_ptr->my_status = MY_OWNByNIC; return (0); } /* * A frame has been uploaded: pass the resulting mbuf chain up to the higher * level protocols. */ static void my_rxeof(struct my_softc * sc) { struct ether_header *eh; struct mbuf *m; - struct ifnet *ifp; + if_t ifp; struct my_chain_onefrag *cur_rx; int total_len = 0; u_int32_t rxstat; MY_LOCK_ASSERT(sc); ifp = sc->my_ifp; while (!((rxstat = sc->my_cdata.my_rx_head->my_ptr->my_status) & MY_OWNByNIC)) { cur_rx = sc->my_cdata.my_rx_head; sc->my_cdata.my_rx_head = cur_rx->my_nextdesc; if (rxstat & MY_ES) { /* error summary: give up this rx pkt */ if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); cur_rx->my_ptr->my_status = MY_OWNByNIC; continue; } /* No errors; receive the packet. */ total_len = (rxstat & MY_FLNGMASK) >> MY_FLNGShift; total_len -= ETHER_CRC_LEN; if (total_len < MINCLSIZE) { m = m_devget(mtod(cur_rx->my_mbuf, char *), total_len, 0, ifp, NULL); cur_rx->my_ptr->my_status = MY_OWNByNIC; if (m == NULL) { if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); continue; } } else { m = cur_rx->my_mbuf; /* * Try to conjure up a new mbuf cluster. If that * fails, it means we have an out of memory condition * and should leave the buffer in place and continue. * This will result in a lost packet, but there's * little else we can do in this situation. */ if (my_newbuf(sc, cur_rx) == ENOBUFS) { if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); cur_rx->my_ptr->my_status = MY_OWNByNIC; continue; } m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = total_len; } if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); eh = mtod(m, struct ether_header *); #if NBPFILTER > 0 /* * Handle BPF listeners. Let the BPF user see the packet, but * don't pass it up to the ether_input() layer unless it's a * broadcast packet, multicast packet, matches our ethernet * address or the interface is in promiscuous mode. */ - if (bpf_peers_present(ifp->if_bpf)) { - bpf_mtap(ifp->if_bpf, m); - if (ifp->if_flags & IFF_PROMISC && - (bcmp(eh->ether_dhost, IF_LLADDR(sc->my_ifp), + if (bpf_peers_present(if_getbpf(ifp))) { + bpf_mtap_if(ifp, m); + if (if_getflags(ifp) & IFF_PROMISC && + (bcmp(eh->ether_dhost, if_getlladdr(sc->my_ifp), ETHER_ADDR_LEN) && (eh->ether_dhost[0] & 1) == 0)) { m_freem(m); continue; } } #endif MY_UNLOCK(sc); - (*ifp->if_input)(ifp, m); + if_input(ifp, m); MY_LOCK(sc); } return; } /* * A frame was downloaded to the chip. It's safe for us to clean up the list * buffers. */ static void my_txeof(struct my_softc * sc) { struct my_chain *cur_tx; - struct ifnet *ifp; + if_t ifp; MY_LOCK_ASSERT(sc); ifp = sc->my_ifp; /* Clear the timeout timer. */ sc->my_timer = 0; if (sc->my_cdata.my_tx_head == NULL) { return; } /* * Go through our tx list and free mbufs for those frames that have * been transmitted. */ while (sc->my_cdata.my_tx_head->my_mbuf != NULL) { u_int32_t txstat; cur_tx = sc->my_cdata.my_tx_head; txstat = MY_TXSTATUS(cur_tx); if ((txstat & MY_OWNByNIC) || txstat == MY_UNSENT) break; if (!(CSR_READ_4(sc, MY_TCRRCR) & MY_Enhanced)) { if (txstat & MY_TXERR) { if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); if (txstat & MY_EC) /* excessive collision */ if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 1); if (txstat & MY_LC) /* late collision */ if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 1); } if_inc_counter(ifp, IFCOUNTER_COLLISIONS, (txstat & MY_NCRMASK) >> MY_NCRShift); } if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); m_freem(cur_tx->my_mbuf); cur_tx->my_mbuf = NULL; if (sc->my_cdata.my_tx_head == sc->my_cdata.my_tx_tail) { sc->my_cdata.my_tx_head = NULL; sc->my_cdata.my_tx_tail = NULL; break; } sc->my_cdata.my_tx_head = cur_tx->my_nextdesc; } if (CSR_READ_4(sc, MY_TCRRCR) & MY_Enhanced) { if_inc_counter(ifp, IFCOUNTER_COLLISIONS, (CSR_READ_4(sc, MY_TSR) & MY_NCRMask)); } return; } /* * TX 'end of channel' interrupt handler. */ static void my_txeoc(struct my_softc * sc) { - struct ifnet *ifp; + if_t ifp; MY_LOCK_ASSERT(sc); ifp = sc->my_ifp; sc->my_timer = 0; if (sc->my_cdata.my_tx_head == NULL) { - ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); sc->my_cdata.my_tx_tail = NULL; if (sc->my_want_auto) my_autoneg_mii(sc, MY_FLAG_SCHEDDELAY, 1); } else { if (MY_TXOWN(sc->my_cdata.my_tx_head) == MY_UNSENT) { MY_TXOWN(sc->my_cdata.my_tx_head) = MY_OWNByNIC; sc->my_timer = 5; CSR_WRITE_4(sc, MY_TXPDR, 0xFFFFFFFF); } } return; } static void my_intr(void *arg) { struct my_softc *sc; - struct ifnet *ifp; + if_t ifp; u_int32_t status; sc = arg; MY_LOCK(sc); ifp = sc->my_ifp; - if (!(ifp->if_flags & IFF_UP)) { + if (!(if_getflags(ifp) & IFF_UP)) { MY_UNLOCK(sc); return; } /* Disable interrupts. */ CSR_WRITE_4(sc, MY_IMR, 0x00000000); for (;;) { status = CSR_READ_4(sc, MY_ISR); status &= MY_INTRS; if (status) CSR_WRITE_4(sc, MY_ISR, status); else break; if (status & MY_RI) /* receive interrupt */ my_rxeof(sc); if ((status & MY_RBU) || (status & MY_RxErr)) { /* rx buffer unavailable or rx error */ if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); #ifdef foo my_stop(sc); my_reset(sc); my_init_locked(sc); #endif } if (status & MY_TI) /* tx interrupt */ my_txeof(sc); if (status & MY_ETI) /* tx early interrupt */ my_txeof(sc); if (status & MY_TBU) /* tx buffer unavailable */ my_txeoc(sc); #if 0 /* 90/1/18 delete */ if (status & MY_FBE) { my_reset(sc); my_init_locked(sc); } #endif } /* Re-enable interrupts. */ CSR_WRITE_4(sc, MY_IMR, MY_INTRS); - if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + if (!if_sendq_empty(ifp)) my_start_locked(ifp); MY_UNLOCK(sc); return; } /* * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data * pointers to the fragment pointers. */ static int my_encap(struct my_softc * sc, struct my_chain * c, struct mbuf * m_head) { struct my_desc *f = NULL; int total_len; struct mbuf *m, *m_new = NULL; MY_LOCK_ASSERT(sc); /* calculate the total tx pkt length */ total_len = 0; for (m = m_head; m != NULL; m = m->m_next) total_len += m->m_len; /* * Start packing the mbufs in this chain into the fragment pointers. * Stop when we run out of fragments or hit the end of the mbuf * chain. */ m = m_head; MGETHDR(m_new, M_NOWAIT, MT_DATA); if (m_new == NULL) { device_printf(sc->my_dev, "no memory for tx list"); return (1); } if (m_head->m_pkthdr.len > MHLEN) { if (!(MCLGET(m_new, M_NOWAIT))) { m_freem(m_new); device_printf(sc->my_dev, "no memory for tx list"); return (1); } } m_copydata(m_head, 0, m_head->m_pkthdr.len, mtod(m_new, caddr_t)); m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; m_freem(m_head); m_head = m_new; f = &c->my_ptr->my_frag[0]; f->my_status = 0; f->my_data = vtophys(mtod(m_new, caddr_t)); total_len = m_new->m_len; f->my_ctl = MY_TXFD | MY_TXLD | MY_CRCEnable | MY_PADEnable; f->my_ctl |= total_len << MY_PKTShift; /* pkt size */ f->my_ctl |= total_len; /* buffer size */ /* 89/12/29 add, for mtd891 *//* [ 89? ] */ if (sc->my_info->my_did == MTD891ID) f->my_ctl |= MY_ETIControl | MY_RetryTxLC; c->my_mbuf = m_head; c->my_lastdesc = 0; MY_TXNEXT(c) = vtophys(&c->my_nextdesc->my_ptr->my_frag[0]); return (0); } /* * Main transmit routine. To avoid having to do mbuf copies, we put pointers * to the mbuf data regions directly in the transmit lists. We also save a * copy of the pointers since the transmit list fragment pointers are * physical addresses. */ static void -my_start(struct ifnet * ifp) +my_start(if_t ifp) { struct my_softc *sc; - sc = ifp->if_softc; + sc = if_getsoftc(ifp); MY_LOCK(sc); my_start_locked(ifp); MY_UNLOCK(sc); } static void -my_start_locked(struct ifnet * ifp) +my_start_locked(if_t ifp) { struct my_softc *sc; struct mbuf *m_head = NULL; struct my_chain *cur_tx = NULL, *start_tx; - sc = ifp->if_softc; + sc = if_getsoftc(ifp); MY_LOCK_ASSERT(sc); if (sc->my_autoneg) { sc->my_tx_pend = 1; return; } /* * Check for an available queue slot. If there are none, punt. */ if (sc->my_cdata.my_tx_free->my_mbuf != NULL) { - ifp->if_drv_flags |= IFF_DRV_OACTIVE; + if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); return; } start_tx = sc->my_cdata.my_tx_free; while (sc->my_cdata.my_tx_free->my_mbuf == NULL) { - IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); + m_head = if_dequeue(ifp); if (m_head == NULL) break; /* Pick a descriptor off the free list. */ cur_tx = sc->my_cdata.my_tx_free; sc->my_cdata.my_tx_free = cur_tx->my_nextdesc; /* Pack the data into the descriptor. */ my_encap(sc, cur_tx, m_head); if (cur_tx != start_tx) MY_TXOWN(cur_tx) = MY_OWNByNIC; #if NBPFILTER > 0 /* * If there's a BPF listener, bounce a copy of this frame to * him. */ BPF_MTAP(ifp, cur_tx->my_mbuf); #endif } /* * If there are no packets queued, bail. */ if (cur_tx == NULL) { return; } /* * Place the request for the upload interrupt in the last descriptor * in the chain. This way, if we're chaining several packets at once, * we'll only get an interrupt once for the whole chain rather than * once for each packet. */ MY_TXCTL(cur_tx) |= MY_TXIC; cur_tx->my_ptr->my_frag[0].my_ctl |= MY_TXIC; sc->my_cdata.my_tx_tail = cur_tx; if (sc->my_cdata.my_tx_head == NULL) sc->my_cdata.my_tx_head = start_tx; MY_TXOWN(start_tx) = MY_OWNByNIC; CSR_WRITE_4(sc, MY_TXPDR, 0xFFFFFFFF); /* tx polling demand */ /* * Set a timeout in case the chip goes out to lunch. */ sc->my_timer = 5; return; } static void my_init(void *xsc) { struct my_softc *sc = xsc; MY_LOCK(sc); my_init_locked(sc); MY_UNLOCK(sc); } static void my_init_locked(struct my_softc *sc) { - struct ifnet *ifp = sc->my_ifp; + if_t ifp = sc->my_ifp; u_int16_t phy_bmcr = 0; MY_LOCK_ASSERT(sc); if (sc->my_autoneg) { return; } if (sc->my_pinfo != NULL) phy_bmcr = my_phy_readreg(sc, PHY_BMCR); /* * Cancel pending I/O and free all RX/TX buffers. */ my_stop(sc); my_reset(sc); /* * Set cache alignment and burst length. */ #if 0 /* 89/9/1 modify, */ CSR_WRITE_4(sc, MY_BCR, MY_RPBLE512); CSR_WRITE_4(sc, MY_TCRRCR, MY_TFTSF); #endif CSR_WRITE_4(sc, MY_BCR, MY_PBL8); CSR_WRITE_4(sc, MY_TCRRCR, MY_TFTSF | MY_RBLEN | MY_RPBLE512); /* * 89/12/29 add, for mtd891, */ if (sc->my_info->my_did == MTD891ID) { MY_SETBIT(sc, MY_BCR, MY_PROG); MY_SETBIT(sc, MY_TCRRCR, MY_Enhanced); } my_setcfg(sc, phy_bmcr); /* Init circular RX list. */ if (my_list_rx_init(sc) == ENOBUFS) { device_printf(sc->my_dev, "init failed: no memory for rx buffers\n"); my_stop(sc); return; } /* Init TX descriptors. */ my_list_tx_init(sc); /* If we want promiscuous mode, set the allframes bit. */ - if (ifp->if_flags & IFF_PROMISC) + if (if_getflags(ifp) & IFF_PROMISC) MY_SETBIT(sc, MY_TCRRCR, MY_PROM); else MY_CLRBIT(sc, MY_TCRRCR, MY_PROM); /* * Set capture broadcast bit to capture broadcast frames. */ - if (ifp->if_flags & IFF_BROADCAST) + if (if_getflags(ifp) & IFF_BROADCAST) MY_SETBIT(sc, MY_TCRRCR, MY_AB); else MY_CLRBIT(sc, MY_TCRRCR, MY_AB); /* * Program the multicast filter, if necessary. */ my_setmulti(sc); /* * Load the address of the RX list. */ MY_CLRBIT(sc, MY_TCRRCR, MY_RE); CSR_WRITE_4(sc, MY_RXLBA, vtophys(&sc->my_ldata->my_rx_list[0])); /* * Enable interrupts. */ CSR_WRITE_4(sc, MY_IMR, MY_INTRS); CSR_WRITE_4(sc, MY_ISR, 0xFFFFFFFF); /* Enable receiver and transmitter. */ MY_SETBIT(sc, MY_TCRRCR, MY_RE); MY_CLRBIT(sc, MY_TCRRCR, MY_TE); CSR_WRITE_4(sc, MY_TXLBA, vtophys(&sc->my_ldata->my_tx_list[0])); MY_SETBIT(sc, MY_TCRRCR, MY_TE); /* Restore state of BMCR */ if (sc->my_pinfo != NULL) my_phy_writereg(sc, PHY_BMCR, phy_bmcr); - ifp->if_drv_flags |= IFF_DRV_RUNNING; - ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0); + if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); callout_reset(&sc->my_watchdog, hz, my_watchdog, sc); return; } /* * Set media options. */ static int -my_ifmedia_upd(struct ifnet * ifp) +my_ifmedia_upd(if_t ifp) { struct my_softc *sc; struct ifmedia *ifm; - sc = ifp->if_softc; + sc = if_getsoftc(ifp); MY_LOCK(sc); ifm = &sc->ifmedia; if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) { MY_UNLOCK(sc); return (EINVAL); } if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) my_autoneg_mii(sc, MY_FLAG_SCHEDDELAY, 1); else my_setmode_mii(sc, ifm->ifm_media); MY_UNLOCK(sc); return (0); } /* * Report current media status. */ static void -my_ifmedia_sts(struct ifnet * ifp, struct ifmediareq * ifmr) +my_ifmedia_sts(if_t ifp, struct ifmediareq * ifmr) { struct my_softc *sc; u_int16_t advert = 0, ability = 0; - sc = ifp->if_softc; + sc = if_getsoftc(ifp); MY_LOCK(sc); ifmr->ifm_active = IFM_ETHER; if (!(my_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_AUTONEGENBL)) { #if 0 /* this version did not support 1000M, */ if (my_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_1000) ifmr->ifm_active = IFM_ETHER | IFM_1000TX; #endif if (my_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_SPEEDSEL) ifmr->ifm_active = IFM_ETHER | IFM_100_TX; else ifmr->ifm_active = IFM_ETHER | IFM_10_T; if (my_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_DUPLEX) ifmr->ifm_active |= IFM_FDX; else ifmr->ifm_active |= IFM_HDX; MY_UNLOCK(sc); return; } ability = my_phy_readreg(sc, PHY_LPAR); advert = my_phy_readreg(sc, PHY_ANAR); #if 0 /* this version did not support 1000M, */ if (sc->my_pinfo->my_vid = MarvellPHYID0) { ability2 = my_phy_readreg(sc, PHY_1000SR); if (ability2 & PHY_1000SR_1000BTXFULL) { advert = 0; ability = 0; ifmr->ifm_active = IFM_ETHER|IFM_1000_T|IFM_FDX; } else if (ability & PHY_1000SR_1000BTXHALF) { advert = 0; ability = 0; ifmr->ifm_active = IFM_ETHER|IFM_1000_T|IFM_HDX; } } #endif if (advert & PHY_ANAR_100BT4 && ability & PHY_ANAR_100BT4) ifmr->ifm_active = IFM_ETHER | IFM_100_T4; else if (advert & PHY_ANAR_100BTXFULL && ability & PHY_ANAR_100BTXFULL) ifmr->ifm_active = IFM_ETHER | IFM_100_TX | IFM_FDX; else if (advert & PHY_ANAR_100BTXHALF && ability & PHY_ANAR_100BTXHALF) ifmr->ifm_active = IFM_ETHER | IFM_100_TX | IFM_HDX; else if (advert & PHY_ANAR_10BTFULL && ability & PHY_ANAR_10BTFULL) ifmr->ifm_active = IFM_ETHER | IFM_10_T | IFM_FDX; else if (advert & PHY_ANAR_10BTHALF && ability & PHY_ANAR_10BTHALF) ifmr->ifm_active = IFM_ETHER | IFM_10_T | IFM_HDX; MY_UNLOCK(sc); return; } static int -my_ioctl(struct ifnet * ifp, u_long command, caddr_t data) +my_ioctl(if_t ifp, u_long command, caddr_t data) { - struct my_softc *sc = ifp->if_softc; + struct my_softc *sc = if_getsoftc(ifp); struct ifreq *ifr = (struct ifreq *) data; int error; switch (command) { case SIOCSIFFLAGS: MY_LOCK(sc); - if (ifp->if_flags & IFF_UP) + if (if_getflags(ifp) & IFF_UP) my_init_locked(sc); - else if (ifp->if_drv_flags & IFF_DRV_RUNNING) + else if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) my_stop(sc); MY_UNLOCK(sc); error = 0; break; case SIOCADDMULTI: case SIOCDELMULTI: MY_LOCK(sc); my_setmulti(sc); MY_UNLOCK(sc); error = 0; break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); break; default: error = ether_ioctl(ifp, command, data); break; } return (error); } static void my_watchdog(void *arg) { struct my_softc *sc; - struct ifnet *ifp; + if_t ifp; sc = arg; MY_LOCK_ASSERT(sc); callout_reset(&sc->my_watchdog, hz, my_watchdog, sc); if (sc->my_timer == 0 || --sc->my_timer > 0) return; ifp = sc->my_ifp; if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); if_printf(ifp, "watchdog timeout\n"); if (!(my_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT)) if_printf(ifp, "no carrier - transceiver cable problem?\n"); my_stop(sc); my_reset(sc); my_init_locked(sc); - if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + if (!if_sendq_empty(ifp)) my_start_locked(ifp); } /* * Stop the adapter and free any mbufs allocated to the RX and TX lists. */ static void my_stop(struct my_softc * sc) { int i; - struct ifnet *ifp; + if_t ifp; MY_LOCK_ASSERT(sc); ifp = sc->my_ifp; callout_stop(&sc->my_autoneg_timer); callout_stop(&sc->my_watchdog); MY_CLRBIT(sc, MY_TCRRCR, (MY_RE | MY_TE)); CSR_WRITE_4(sc, MY_IMR, 0x00000000); CSR_WRITE_4(sc, MY_TXLBA, 0x00000000); CSR_WRITE_4(sc, MY_RXLBA, 0x00000000); /* * Free data in the RX lists. */ for (i = 0; i < MY_RX_LIST_CNT; i++) { if (sc->my_cdata.my_rx_chain[i].my_mbuf != NULL) { m_freem(sc->my_cdata.my_rx_chain[i].my_mbuf); sc->my_cdata.my_rx_chain[i].my_mbuf = NULL; } } bzero((char *)&sc->my_ldata->my_rx_list, sizeof(sc->my_ldata->my_rx_list)); /* * Free the TX list buffers. */ for (i = 0; i < MY_TX_LIST_CNT; i++) { if (sc->my_cdata.my_tx_chain[i].my_mbuf != NULL) { m_freem(sc->my_cdata.my_tx_chain[i].my_mbuf); sc->my_cdata.my_tx_chain[i].my_mbuf = NULL; } } bzero((char *)&sc->my_ldata->my_tx_list, sizeof(sc->my_ldata->my_tx_list)); - ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + if_setdrvflagbits(ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)); return; } /* * Stop all chip I/O so that the kernel's probe routines don't get confused * by errant DMAs when rebooting. */ static int my_shutdown(device_t dev) { struct my_softc *sc; sc = device_get_softc(dev); MY_LOCK(sc); my_stop(sc); MY_UNLOCK(sc); return 0; } diff --git a/sys/dev/my/if_myreg.h b/sys/dev/my/if_myreg.h index a3a723d05322..00a060d2f794 100644 --- a/sys/dev/my/if_myreg.h +++ b/sys/dev/my/if_myreg.h @@ -1,587 +1,587 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2002 Myson Technology Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Written by: yen_cw@myson.com.tw available at: http://www.myson.com.tw/ * * $FreeBSD$ * * Myson MTD80x register definitions. * */ #define MY_PAR0 0x0 /* physical address 0-3 */ #define MY_PAR1 0x04 /* physical address 4-5 */ #define MY_MAR0 0x08 /* multicast address 0-3 */ #define MY_MAR1 0x0C /* multicast address 4-7 */ #define MY_FAR0 0x10 /* flow-control address 0-3 */ #define MY_FAR1 0x14 /* flow-control address 4-5 */ #define MY_TCRRCR 0x18 /* receive & transmit configuration */ #define MY_BCR 0x1C /* bus command */ #define MY_TXPDR 0x20 /* transmit polling demand */ #define MY_RXPDR 0x24 /* receive polling demand */ #define MY_RXCWP 0x28 /* receive current word pointer */ #define MY_TXLBA 0x2C /* transmit list base address */ #define MY_RXLBA 0x30 /* receive list base address */ #define MY_ISR 0x34 /* interrupt status */ #define MY_IMR 0x38 /* interrupt mask */ #define MY_FTH 0x3C /* flow control high/low threshold */ #define MY_MANAGEMENT 0x40 /* bootrom/eeprom and mii management */ #define MY_TALLY 0x44 /* tally counters for crc and mpa */ #define MY_TSR 0x48 /* tally counter for transmit status */ #define MY_PHYBASE 0x4c /* * Receive Configuration Register */ #define MY_RXRUN 0x00008000 /* receive running status */ #define MY_EIEN 0x00004000 /* early interrupt enable */ #define MY_RFCEN 0x00002000 /* receive flow control packet enable */ #define MY_NDFA 0x00001000 /* not defined flow control address */ #define MY_RBLEN 0x00000800 /* receive burst length enable */ #define MY_RPBLE1 0x00000000 /* 1 word */ #define MY_RPBLE4 0x00000100 /* 4 words */ #define MY_RPBLE8 0x00000200 /* 8 words */ #define MY_RPBLE16 0x00000300 /* 16 words */ #define MY_RPBLE32 0x00000400 /* 32 words */ #define MY_RPBLE64 0x00000500 /* 64 words */ #define MY_RPBLE128 0x00000600 /* 128 words */ #define MY_RPBLE512 0x00000700 /* 512 words */ #define MY_PROM 0x000000080 /* promiscuous mode */ #define MY_AB 0x000000040 /* accept broadcast */ #define MY_AM 0x000000020 /* accept mutlicast */ #define MY_ARP 0x000000008 /* receive runt pkt */ #define MY_ALP 0x000000004 /* receive long pkt */ #define MY_SEP 0x000000002 /* receive error pkt */ #define MY_RE 0x000000001 /* receive enable */ /* * Transmit Configuration Register */ #define MY_TXRUN 0x04000000 /* transmit running status */ #define MY_Enhanced 0x02000000 /* transmit enhanced mode */ #define MY_TFCEN 0x01000000 /* tx flow control packet enable */ #define MY_TFT64 0x00000000 /* 64 bytes */ #define MY_TFT32 0x00200000 /* 32 bytes */ #define MY_TFT128 0x00400000 /* 128 bytes */ #define MY_TFT256 0x00600000 /* 256 bytes */ #define MY_TFT512 0x00800000 /* 512 bytes */ #define MY_TFT768 0x00A00000 /* 768 bytes */ #define MY_TFT1024 0x00C00000 /* 1024 bytes */ #define MY_TFTSF 0x00E00000 /* store and forward */ #define MY_FD 0x00100000 /* full duplex mode */ #define MY_PS10 0x00080000 /* port speed is 10M */ #define MY_TE 0x00040000 /* transmit enable */ #define MY_PS1000 0x00010000 /* port speed is 1000M */ /* * Bus Command Register */ #define MY_PROG 0x00000200 /* programming */ #define MY_RLE 0x00000100 /* read line command enable */ #define MY_RME 0x00000080 /* read multiple command enable */ #define MY_WIE 0x00000040 /* write and invalidate cmd enable */ #define MY_PBL1 0x00000000 /* 1 dword */ #define MY_PBL4 0x00000008 /* 4 dwords */ #define MY_PBL8 0x00000010 /* 8 dwords */ #define MY_PBL16 0x00000018 /* 16 dwords */ #define MY_PBL32 0x00000020 /* 32 dwords */ #define MY_PBL64 0x00000028 /* 64 dwords */ #define MY_PBL128 0x00000030 /* 128 dwords */ #define MY_PBL512 0x00000038 /* 512 dwords */ #define MY_ABR 0x00000004 /* arbitration rule */ #define MY_BLS 0x00000002 /* big/little endian select */ #define MY_SWR 0x00000001 /* software reset */ /* * Transmit Poll Demand Register */ #define MY_TxPollDemand 0x1 /* * Receive Poll Demand Register */ #define MY_RxPollDemand 0x01 /* * Interrupt Status Register */ #define MY_RFCON 0x00020000 /* receive flow control xon packet */ #define MY_RFCOFF 0x00010000 /* receive flow control xoff packet */ #define MY_LSCStatus 0x00008000 /* link status change */ #define MY_ANCStatus 0x00004000 /* autonegotiation completed */ #define MY_FBE 0x00002000 /* fatal bus error */ #define MY_FBEMask 0x00001800 #define MY_ParityErr 0x00000000 /* parity error */ #define MY_MasterErr 0x00000800 /* master error */ #define MY_TargetErr 0x00001000 /* target abort */ #define MY_TUNF 0x00000400 /* transmit underflow */ #define MY_ROVF 0x00000200 /* receive overflow */ #define MY_ETI 0x00000100 /* transmit early int */ #define MY_ERI 0x00000080 /* receive early int */ #define MY_CNTOVF 0x00000040 /* counter overflow */ #define MY_RBU 0x00000020 /* receive buffer unavailable */ #define MY_TBU 0x00000010 /* transmit buffer unavilable */ #define MY_TI 0x00000008 /* transmit interrupt */ #define MY_RI 0x00000004 /* receive interrupt */ #define MY_RxErr 0x00000002 /* receive error */ /* * Interrupt Mask Register */ #define MY_MRFCON 0x00020000 /* receive flow control xon packet */ #define MY_MRFCOFF 0x00010000 /* receive flow control xoff packet */ #define MY_MLSCStatus 0x00008000 /* link status change */ #define MY_MANCStatus 0x00004000 /* autonegotiation completed */ #define MY_MFBE 0x00002000 /* fatal bus error */ #define MY_MFBEMask 0x00001800 #define MY_MTUNF 0x00000400 /* transmit underflow */ #define MY_MROVF 0x00000200 /* receive overflow */ #define MY_METI 0x00000100 /* transmit early int */ #define MY_MERI 0x00000080 /* receive early int */ #define MY_MCNTOVF 0x00000040 /* counter overflow */ #define MY_MRBU 0x00000020 /* receive buffer unavailable */ #define MY_MTBU 0x00000010 /* transmit buffer unavilable */ #define MY_MTI 0x00000008 /* transmit interrupt */ #define MY_MRI 0x00000004 /* receive interrupt */ #define MY_MRxErr 0x00000002 /* receive error */ /* 90/1/18 delete */ /* #define MY_INTRS MY_FBE|MY_MRBU|MY_TBU|MY_MTI|MY_MRI|MY_METI */ #define MY_INTRS MY_MRBU|MY_TBU|MY_MTI|MY_MRI|MY_METI /* * Flow Control High/Low Threshold Register */ #define MY_FCHTShift 16 /* flow control high threshold */ #define MY_FCLTShift 0 /* flow control low threshold */ /* * BootROM/EEPROM/MII Management Register */ #define MY_MASK_MIIR_MII_READ 0x00000000 #define MY_MASK_MIIR_MII_WRITE 0x00000008 #define MY_MASK_MIIR_MII_MDO 0x00000004 #define MY_MASK_MIIR_MII_MDI 0x00000002 #define MY_MASK_MIIR_MII_MDC 0x00000001 /* * Tally Counter for CRC and MPA */ #define MY_TCOVF 0x80000000 /* crc tally counter overflow */ #define MY_CRCMask 0x7fff0000 /* crc number: bit 16-30 */ #define MY_CRCShift 16 #define MY_TMOVF 0x00008000 /* mpa tally counter overflow */ #define MY_MPAMask 0x00007fff /* mpa number: bit 0-14 */ #define MY_MPAShift 0 /* * Tally Counters for transmit status */ #define MY_AbortMask 0xff000000 /* transmit abort number */ #define MY_AbortShift 24 #define MY_LColMask 0x00ff0000 /* transmit late collisions */ #define MY_LColShift 16 #define MY_NCRMask 0x0000ffff /* transmit retry number */ #define MY_NCRShift 0 /* * Myson TX/RX descriptor structure. */ struct my_desc { u_int32_t my_status; u_int32_t my_ctl; u_int32_t my_data; u_int32_t my_next; }; /* * for tx/rx descriptors */ #define MY_OWNByNIC 0x80000000 #define MY_OWNByDriver 0x0 /* * receive descriptor 0 */ #define MY_RXOWN 0x80000000 /* own bit */ #define MY_FLNGMASK 0x0fff0000 /* frame length */ #define MY_FLNGShift 16 #define MY_MARSTATUS 0x00004000 /* multicast address received */ #define MY_BARSTATUS 0x00002000 /* broadcast address received */ #define MY_PHYSTATUS 0x00001000 /* physical address received */ #define MY_RXFSD 0x00000800 /* first descriptor */ #define MY_RXLSD 0x00000400 /* last descriptor */ #define MY_ES 0x00000080 /* error summary */ #define MY_RUNT 0x00000040 /* runt packet received */ #define MY_LONG 0x00000020 /* long packet received */ #define MY_FAE 0x00000010 /* frame align error */ #define MY_CRC 0x00000008 /* crc error */ #define MY_RXER 0x00000004 /* receive error */ #define MY_RDES0CHECK 0x000078fc /* only check MAR, BAR, PHY, ES, RUNT, LONG, FAE, CRC and RXER bits */ /* * receive descriptor 1 */ #define MY_RXIC 0x00800000 /* interrupt control */ #define MY_RBSMASK 0x000007ff /* receive buffer size */ #define MY_RBSShift 0 /* * transmit descriptor 0 */ #define MY_TXERR 0x00008000 /* transmit error */ #define MY_JABTO 0x00004000 /* jabber timeout */ #define MY_CSL 0x00002000 /* carrier sense lost */ #define MY_LC 0x00001000 /* late collision */ #define MY_EC 0x00000800 /* excessive collision */ #define MY_UDF 0x00000400 /* fifo underflow */ #define MY_DFR 0x00000200 /* deferred */ #define MY_HF 0x00000100 /* heartbeat fail */ #define MY_NCRMASK 0x000000ff /* collision retry count */ #define MY_NCRShift 0 /* * tx descriptor 1 */ #define MY_TXIC 0x80000000 /* interrupt control */ #define MY_ETIControl 0x40000000 /* early transmit interrupt */ #define MY_TXLD 0x20000000 /* last descriptor */ #define MY_TXFD 0x10000000 /* first descriptor */ #define MY_CRCDisable 0x00000000 /* crc control */ #define MY_CRCEnable 0x08000000 #define MY_PADDisable 0x00000000 /* padding control */ #define MY_PADEnable 0x04000000 #define MY_RetryTxLC 0x02000000 /* retry late collision */ #define MY_PKTShift 11 /* transmit pkt size */ #define MY_TBSMASK 0x000007ff #define MY_TBSShift 0 /* transmit buffer size */ #define MY_MAXFRAGS 1 #define MY_RX_LIST_CNT 64 #define MY_TX_LIST_CNT 64 #define MY_MIN_FRAMELEN 60 /* * A transmit 'super descriptor' is actually MY_MAXFRAGS regular * descriptors clumped together. The idea here is to emulate the * multi-fragment descriptor layout found in devices such as the * Texas Instruments ThunderLAN and 3Com boomerang and cylone chips. * The advantage to using this scheme is that it avoids buffer copies. * The disadvantage is that there's a certain amount of overhead due * to the fact that each 'fragment' is 16 bytes long. In my tests, * this limits top speed to about 10.5MB/sec. It should be more like * 11.5MB/sec. However, the upshot is that you can achieve better * results on slower machines: a Pentium 200 can pump out packets at * same speed as a PII 400. */ struct my_txdesc { struct my_desc my_frag[MY_MAXFRAGS]; }; #define MY_TXSTATUS(x) x->my_ptr->my_frag[x->my_lastdesc].my_status #define MY_TXCTL(x) x->my_ptr->my_frag[x->my_lastdesc].my_ctl #define MY_TXDATA(x) x->my_ptr->my_frag[x->my_lastdesc].my_data #define MY_TXNEXT(x) x->my_ptr->my_frag[x->my_lastdesc].my_next #define MY_TXOWN(x) x->my_ptr->my_frag[0].my_status #define MY_UNSENT 0x1234 struct my_list_data { struct my_desc my_rx_list[MY_RX_LIST_CNT]; struct my_txdesc my_tx_list[MY_TX_LIST_CNT]; }; struct my_chain { struct my_txdesc *my_ptr; struct mbuf *my_mbuf; struct my_chain *my_nextdesc; u_int8_t my_lastdesc; }; struct my_chain_onefrag { struct my_desc *my_ptr; struct mbuf *my_mbuf; struct my_chain_onefrag *my_nextdesc; u_int8_t my_rlast; }; struct my_chain_data { struct my_chain_onefrag my_rx_chain[MY_RX_LIST_CNT]; struct my_chain my_tx_chain[MY_TX_LIST_CNT]; struct my_chain_onefrag *my_rx_head; struct my_chain *my_tx_head; struct my_chain *my_tx_tail; struct my_chain *my_tx_free; }; struct my_type { u_int16_t my_vid; u_int16_t my_did; char *my_name; }; #define MY_FLAG_FORCEDELAY 1 #define MY_FLAG_SCHEDDELAY 2 #define MY_FLAG_DELAYTIMEO 3 struct my_softc { - struct ifnet *my_ifp; + if_t my_ifp; device_t my_dev; struct ifmedia ifmedia; /* media info */ bus_space_handle_t my_bhandle; bus_space_tag_t my_btag; struct my_type *my_info; /* adapter info */ struct my_type *my_pinfo; /* phy info */ struct resource *my_res; struct resource *my_irq; void *my_intrhand; u_int8_t my_phy_addr; /* PHY address */ u_int8_t my_tx_pend; /* TX pending */ u_int8_t my_want_auto; u_int8_t my_autoneg; u_int16_t my_txthresh; u_int8_t my_stats_no_timeout; caddr_t my_ldata_ptr; struct my_list_data *my_ldata; struct my_chain_data my_cdata; device_t my_miibus; /* Add by Surfer 2001/12/2 */ struct mtx my_mtx; struct callout my_autoneg_timer; struct callout my_watchdog; int my_timer; }; /* Add by Surfer 2001/12/2 */ #define MY_LOCK(_sc) mtx_lock(&(_sc)->my_mtx) #define MY_UNLOCK(_sc) mtx_unlock(&(_sc)->my_mtx) #define MY_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->my_mtx, MA_OWNED) /* * register space access macros */ #define CSR_WRITE_4(sc, reg, val) \ bus_space_write_4(sc->my_btag, sc->my_bhandle, reg, val) #define CSR_WRITE_2(sc, reg, val) \ bus_space_write_2(sc->my_btag, sc->my_bhandle, reg, val) #define CSR_WRITE_1(sc, reg, val) \ bus_space_write_1(sc->my_btag, sc->my_bhandle, reg, val) #define CSR_READ_4(sc, reg) \ bus_space_read_4(sc->my_btag, sc->my_bhandle, reg) #define CSR_READ_2(sc, reg) \ bus_space_read_2(sc->my_btag, sc->my_bhandle, reg) #define CSR_READ_1(sc, reg) \ bus_space_read_1(sc->my_btag, sc->my_bhandle, reg) #define MY_TIMEOUT 1000 /* * General constants that are fun to know. * * MYSON PCI vendor ID */ #define MYSONVENDORID 0x1516 /* * MYSON device IDs. */ #define MTD800ID 0x0800 #define MTD803ID 0x0803 #define MTD891ID 0x0891 /* * ST+OP+PHYAD+REGAD+TA */ #define MY_OP_READ 0x6000 /* ST:01+OP:10+PHYAD+REGAD+TA:Z0 */ #define MY_OP_WRITE 0x5002 /* ST:01+OP:01+PHYAD+REGAD+TA:10 */ /* * Constansts for Myson PHY */ #define MysonPHYID0 0x0300 /* * Constansts for Seeq 80225 PHY */ #define SeeqPHYID0 0x0016 #define SEEQ_MIIRegister18 18 #define SEEQ_SPD_DET_100 0x80 #define SEEQ_DPLX_DET_FULL 0x40 /* * Constansts for Ahdoc 101 PHY */ #define AhdocPHYID0 0x0022 #define AHDOC_DiagnosticReg 18 #define AHDOC_DPLX_FULL 0x0800 #define AHDOC_Speed_100 0x0400 /* * Constansts for Marvell 88E1000/88E1000S PHY and LevelOne PHY */ #define MarvellPHYID0 0x0141 #define LevelOnePHYID0 0x0013 #define Marvell_SpecificStatus 17 #define Marvell_Speed1000 0x8000 #define Marvell_Speed100 0x4000 #define Marvell_FullDuplex 0x2000 /* * PCI low memory base and low I/O base register, and * other PCI registers. Note: some are only available on * the 3c905B, in particular those that related to power management. */ #define MY_PCI_VENDOR_ID 0x00 #define MY_PCI_DEVICE_ID 0x02 #define MY_PCI_COMMAND 0x04 #define MY_PCI_STATUS 0x06 #define MY_PCI_CLASSCODE 0x09 #define MY_PCI_LATENCY_TIMER 0x0D #define MY_PCI_HEADER_TYPE 0x0E #define MY_PCI_LOIO 0x10 #define MY_PCI_LOMEM 0x14 #define MY_PCI_BIOSROM 0x30 #define MY_PCI_INTLINE 0x3C #define MY_PCI_INTPIN 0x3D #define MY_PCI_MINGNT 0x3E #define MY_PCI_MINLAT 0x0F #define MY_PCI_RESETOPT 0x48 #define MY_PCI_EEPROM_DATA 0x4C #define PHY_UNKNOWN 3 #define MY_PHYADDR_MIN 0x00 #define MY_PHYADDR_MAX 0x1F #define PHY_BMCR 0x00 #define PHY_BMSR 0x01 #define PHY_VENID 0x02 #define PHY_DEVID 0x03 #define PHY_ANAR 0x04 #define PHY_LPAR 0x05 #define PHY_ANEXP 0x06 #define PHY_NPTR 0x07 #define PHY_LPNPR 0x08 #define PHY_1000CR 0x09 #define PHY_1000SR 0x0a #define PHY_ANAR_NEXTPAGE 0x8000 #define PHY_ANAR_RSVD0 0x4000 #define PHY_ANAR_TLRFLT 0x2000 #define PHY_ANAR_RSVD1 0x1000 #define PHY_ANAR_RSVD2 0x0800 #define PHY_ANAR_RSVD3 0x0400 #define PHY_ANAR_100BT4 0x0200L #define PHY_ANAR_100BTXFULL 0x0100 #define PHY_ANAR_100BTXHALF 0x0080 #define PHY_ANAR_10BTFULL 0x0040 #define PHY_ANAR_10BTHALF 0x0020 #define PHY_ANAR_PROTO4 0x0010 #define PHY_ANAR_PROTO3 0x0008 #define PHY_ANAR_PROTO2 0x0004 #define PHY_ANAR_PROTO1 0x0002 #define PHY_ANAR_PROTO0 0x0001 #define PHY_1000SR_1000BTXFULL 0x0800 #define PHY_1000SR_1000BTXHALF 0x0400 /* * These are the register definitions for the PHY (physical layer * interface chip). */ /* * PHY BMCR Basic Mode Control Register */ #define PHY_BMCR_RESET 0x8000 #define PHY_BMCR_LOOPBK 0x4000 #define PHY_BMCR_SPEEDSEL 0x2000 #define PHY_BMCR_AUTONEGENBL 0x1000 #define PHY_BMCR_RSVD0 0x0800 /* write as zero */ #define PHY_BMCR_ISOLATE 0x0400 #define PHY_BMCR_AUTONEGRSTR 0x0200 #define PHY_BMCR_DUPLEX 0x0100 #define PHY_BMCR_COLLTEST 0x0080 #define PHY_BMCR_1000 0x0040 /* only used for Marvell PHY */ #define PHY_BMCR_RSVD2 0x0020 /* write as zero, don't care */ #define PHY_BMCR_RSVD3 0x0010 /* write as zero, don't care */ #define PHY_BMCR_RSVD4 0x0008 /* write as zero, don't care */ #define PHY_BMCR_RSVD5 0x0004 /* write as zero, don't care */ #define PHY_BMCR_RSVD6 0x0002 /* write as zero, don't care */ #define PHY_BMCR_RSVD7 0x0001 /* write as zero, don't care */ /* * RESET: 1 == software reset, 0 == normal operation * Resets status and control registers to default values. * Relatches all hardware config values. * * LOOPBK: 1 == loopback operation enabled, 0 == normal operation * * SPEEDSEL: 1 == 100Mb/s, 0 == 10Mb/s * Link speed is selected byt his bit or if auto-negotiation if bit * 12 (AUTONEGENBL) is set (in which case the value of this register * is ignored). * * AUTONEGENBL: 1 == Autonegotiation enabled, 0 == Autonegotiation disabled * Bits 8 and 13 are ignored when autoneg is set, otherwise bits 8 and 13 * determine speed and mode. Should be cleared and then set if PHY configured * for no autoneg on startup. * * ISOLATE: 1 == isolate PHY from MII, 0 == normal operation * * AUTONEGRSTR: 1 == restart autonegotiation, 0 = normal operation * * DUPLEX: 1 == full duplex mode, 0 == half duplex mode * * COLLTEST: 1 == collision test enabled, 0 == normal operation */ /* * PHY, BMSR Basic Mode Status Register */ #define PHY_BMSR_100BT4 0x8000 #define PHY_BMSR_100BTXFULL 0x4000 #define PHY_BMSR_100BTXHALF 0x2000 #define PHY_BMSR_10BTFULL 0x1000 #define PHY_BMSR_10BTHALF 0x0800 #define PHY_BMSR_RSVD1 0x0400 /* write as zero, don't care */ #define PHY_BMSR_RSVD2 0x0200 /* write as zero, don't care */ #define PHY_BMSR_RSVD3 0x0100 /* write as zero, don't care */ #define PHY_BMSR_RSVD4 0x0080 /* write as zero, don't care */ #define PHY_BMSR_MFPRESUP 0x0040 #define PHY_BMSR_AUTONEGCOMP 0x0020 #define PHY_BMSR_REMFAULT 0x0010 #define PHY_BMSR_CANAUTONEG 0x0008 #define PHY_BMSR_LINKSTAT 0x0004 #define PHY_BMSR_JABBER 0x0002 #define PHY_BMSR_EXTENDED 0x0001