if_ax.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 2,242 行 · 第 1/4 页
C
2,242 行
} /* return the filter bit position */ return((crc >> 26) & 0x0000003F);}static void ax_setmulti(sc) struct ax_softc *sc;{ struct ifnet *ifp; int h = 0; u_int32_t hashes[2] = { 0, 0 }; struct ifmultiaddr *ifma; u_int32_t rxfilt; ifp = &sc->arpcom.ac_if; rxfilt = CSR_READ_4(sc, AX_NETCFG); if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { rxfilt |= AX_NETCFG_RX_ALLMULTI; CSR_WRITE_4(sc, AX_NETCFG, rxfilt); return; } else rxfilt &= ~AX_NETCFG_RX_ALLMULTI; /* first, zot all the existing hash bits */ CSR_WRITE_4(sc, AX_FILTIDX, AX_FILTIDX_MAR0); CSR_WRITE_4(sc, AX_FILTDATA, 0); CSR_WRITE_4(sc, AX_FILTIDX, AX_FILTIDX_MAR1); CSR_WRITE_4(sc, AX_FILTDATA, 0); /* now program new ones */ for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; ifma = ifma->ifma_link.le_next) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; h = ax_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); if (h < 32) hashes[0] |= (1 << h); else hashes[1] |= (1 << (h - 32)); } CSR_WRITE_4(sc, AX_FILTIDX, AX_FILTIDX_MAR0); CSR_WRITE_4(sc, AX_FILTDATA, hashes[0]); CSR_WRITE_4(sc, AX_FILTIDX, AX_FILTIDX_MAR1); CSR_WRITE_4(sc, AX_FILTDATA, hashes[1]); CSR_WRITE_4(sc, AX_NETCFG, rxfilt); return;}/* * Initiate an autonegotiation session. */static void ax_autoneg_xmit(sc) struct ax_softc *sc;{ u_int16_t phy_sts; ax_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); DELAY(500); while(ax_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_RESET); phy_sts = ax_phy_readreg(sc, PHY_BMCR); phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR; ax_phy_writereg(sc, PHY_BMCR, phy_sts); return;}/* * Invoke autonegotiation on a PHY. */static void ax_autoneg_mii(sc, flag, verbose) struct ax_softc *sc; int flag; int verbose;{ u_int16_t phy_sts = 0, media, advert, ability; struct ifnet *ifp; struct ifmedia *ifm; ifm = &sc->ifmedia; ifp = &sc->arpcom.ac_if; ifm->ifm_media = IFM_ETHER | IFM_AUTO; /* * The 100baseT4 PHY on the 3c905-T4 has the 'autoneg supported' * bit cleared in the status register, but has the 'autoneg enabled' * bit set in the control register. This is a contradiction, and * I'm not sure how to handle it. If you want to force an attempt * to autoneg for 100baseT4 PHYs, #define FORCE_AUTONEG_TFOUR * and see what happens. */#ifndef FORCE_AUTONEG_TFOUR /* * First, see if autoneg is supported. If not, there's * no point in continuing. */ phy_sts = ax_phy_readreg(sc, PHY_BMSR); if (!(phy_sts & PHY_BMSR_CANAUTONEG)) { if (verbose) printf("ax%d: autonegotiation not supported\n", sc->ax_unit); ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; return; }#endif switch (flag) { case AX_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. */ ax_autoneg_xmit(sc); DELAY(5000000); break; case AX_FLAG_SCHEDDELAY: /* * Wait for the transmitter to go idle before starting * an autoneg session, otherwise ax_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->ax_cdata.ax_tx_head != NULL) { sc->ax_want_auto = 1; return; } ax_autoneg_xmit(sc); ifp->if_timer = 5; sc->ax_autoneg = 1; sc->ax_want_auto = 0; return; break; case AX_FLAG_DELAYTIMEO: ifp->if_timer = 0; sc->ax_autoneg = 0; break; default: printf("ax%d: invalid autoneg flag: %d\n", sc->ax_unit, flag); return; } if (ax_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_AUTONEGCOMP) { if (verbose) printf("ax%d: autoneg complete, ", sc->ax_unit); phy_sts = ax_phy_readreg(sc, PHY_BMSR); } else { if (verbose) printf("ax%d: autoneg not complete, ", sc->ax_unit); } media = ax_phy_readreg(sc, PHY_BMCR); /* Link is good. Report modes and set duplex mode. */ if (ax_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT) { if (verbose) printf("link status good "); advert = ax_phy_readreg(sc, PHY_ANAR); ability = ax_phy_readreg(sc, PHY_LPAR); 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 & PHY_ANAR_10BTHALF && ability & PHY_ANAR_10BTHALF) { 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. */ ax_setcfg(sc, media); ax_phy_writereg(sc, PHY_BMCR, media); } else { if (verbose) printf("no carrier\n"); } ax_init(sc); if (sc->ax_tx_pend) { sc->ax_autoneg = 0; sc->ax_tx_pend = 0; ax_start(ifp); } return;}static void ax_getmode_mii(sc) struct ax_softc *sc;{ u_int16_t bmsr; struct ifnet *ifp; ifp = &sc->arpcom.ac_if; bmsr = ax_phy_readreg(sc, PHY_BMSR); if (bootverbose) printf("ax%d: PHY status word: %x\n", sc->ax_unit, bmsr); /* fallback */ sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; if (bmsr & PHY_BMSR_10BTHALF) { if (bootverbose) printf("ax%d: 10Mbps half-duplex mode supported\n", sc->ax_unit); 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) printf("ax%d: 10Mbps full-duplex mode supported\n", sc->ax_unit); 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) printf("ax%d: 100Mbps half-duplex mode supported\n", sc->ax_unit); ifp->if_baudrate = 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) printf("ax%d: 100Mbps full-duplex mode supported\n", sc->ax_unit); ifp->if_baudrate = 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) printf("ax%d: 100baseT4 mode supported\n", sc->ax_unit); ifp->if_baudrate = 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) printf("ax%d: forcing on autoneg support for BT4\n", sc->ax_unit); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0 NULL): sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO;#endif } if (bmsr & PHY_BMSR_CANAUTONEG) { if (bootverbose) printf("ax%d: autoneg supported\n", sc->ax_unit); 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 ax_setmode_mii(sc, media) struct ax_softc *sc; int media;{ u_int16_t bmcr; struct ifnet *ifp; ifp = &sc->arpcom.ac_if; /* * If an autoneg session is in progress, stop it. */ if (sc->ax_autoneg) { printf("ax%d: canceling autoneg session\n", sc->ax_unit); ifp->if_timer = sc->ax_autoneg = sc->ax_want_auto = 0; bmcr = ax_phy_readreg(sc, PHY_BMCR); bmcr &= ~PHY_BMCR_AUTONEGENBL; ax_phy_writereg(sc, PHY_BMCR, bmcr); } printf("ax%d: selecting MII, ", sc->ax_unit); bmcr = ax_phy_readreg(sc, PHY_BMCR); bmcr &= ~(PHY_BMCR_AUTONEGENBL|PHY_BMCR_SPEEDSEL| PHY_BMCR_DUPLEX|PHY_BMCR_LOOPBK); 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; } ax_setcfg(sc, bmcr); ax_phy_writereg(sc, PHY_BMCR, bmcr); return;}/* * Set speed and duplex mode on internal transceiver. */static void ax_setmode(sc, media, verbose) struct ax_softc *sc; int media; int verbose;{ struct ifnet *ifp; u_int32_t mode; ifp = &sc->arpcom.ac_if; if (verbose) printf("ax%d: selecting internal xcvr, ", sc->ax_unit); mode = CSR_READ_4(sc, AX_NETCFG); mode &= ~(AX_NETCFG_FULLDUPLEX|AX_NETCFG_PORTSEL| AX_NETCFG_PCS|AX_NETCFG_SCRAMBLER|AX_NETCFG_SPEEDSEL); if (IFM_SUBTYPE(media) == IFM_100_T4) { if (verbose) printf("100Mbps/T4, half-duplex\n"); mode |= AX_NETCFG_PORTSEL|AX_NETCFG_PCS|AX_NETCFG_SCRAMBLER; } if (IFM_SUBTYPE(media) == IFM_100_TX) { if (verbose) printf("100Mbps, "); mode |= AX_NETCFG_PORTSEL|AX_NETCFG_PCS|AX_NETCFG_SCRAMBLER; } if (IFM_SUBTYPE(media) == IFM_10_T) { if (verbose) printf("10Mbps, "); mode &= ~AX_NETCFG_PORTSEL; mode |= AX_NETCFG_SPEEDSEL; } if ((media & IFM_GMASK) == IFM_FDX) { if (verbose) printf("full duplex\n"); mode |= AX_NETCFG_FULLDUPLEX; } else { if (verbose) printf("half duplex\n"); mode &= ~AX_NETCFG_FULLDUPLEX; } CSR_WRITE_4(sc, AX_NETCFG, mode); return;}/* * 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 ax_setcfg(sc, bmcr) struct ax_softc *sc; int bmcr;{ int i, restart = 0; if (CSR_READ_4(sc, AX_NETCFG) & (AX_NETCFG_TX_ON|AX_NETCFG_RX_ON)) { restart = 1; AX_CLRBIT(sc, AX_NETCFG, (AX_NETCFG_TX_ON|AX_NETCFG_RX_ON)); for (i = 0; i < AX_TIMEOUT; i++) { DELAY(10); if (CSR_READ_4(sc, AX_ISR) & AX_ISR_TX_IDLE) break; } if (i == AX_TIMEOUT) printf("ax%d: failed to force tx and " "rx to idle state\n", sc->ax_unit); } if (bmcr & PHY_BMCR_SPEEDSEL) AX_CLRBIT(sc, AX_NETCFG, AX_NETCFG_SPEEDSEL); else AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_SPEEDSEL); if (bmcr & PHY_BMCR_DUPLEX) AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_FULLDUPLEX); else AX_CLRBIT(sc, AX_NETCFG, AX_NETCFG_FULLDUPLEX); if (restart) AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_TX_ON|AX_NETCFG_RX_ON); return;}static void ax_reset(sc) struct ax_softc *sc;{ register int i; AX_SETBIT(sc, AX_BUSCTL, AX_BUSCTL_RESET); for (i = 0; i < AX_TIMEOUT; i++) { DELAY(10); if (!(CSR_READ_4(sc, AX_BUSCTL) & AX_BUSCTL_RESET)) break; }#ifdef notdef if (i == AX_TIMEOUT) printf("ax%d: reset never completed!\n", sc->ax_unit);#endif CSR_WRITE_4(sc, AX_BUSCTL, AX_BUSCTL_CONFIG); /* Wait a little while for the chip to get its brains in order. */ DELAY(1000); return;}/* * Probe for an ASIX chip. Check the PCI vendor and device * IDs against our list and return a device name if we find a match. */static const char *ax_probe(config_id, device_id) pcici_t config_id; pcidi_t device_id;{ struct ax_type *t; u_int32_t rev; t = ax_devs; while(t->ax_name != NULL) { if ((device_id & 0xFFFF) == t->ax_vid && ((device_id >> 16) & 0xFFFF) == t->ax_did) { /* Check the PCI revision */ rev = pci_conf_read(config_id, AX_PCI_REVID) & 0xFF; if (rev >= AX_REVISION_88141) t++; return(t->ax_name); } t++; } return(NULL);}/* * Attach the interface. Allocate softc structures, do ifmedia * setup and ethernet/BPF attach. */static voidax_attach(config_id, unit) pcici_t config_id; int unit;{ int s, i;#ifndef AX_USEIOSPACE vm_offset_t pbase, vbase;#endif u_char eaddr[ETHER_ADDR_LEN]; u_int32_t command; struct ax_softc *sc; struct ifnet *ifp; int media = IFM_ETHER|IFM_100_TX|IFM_FDX; unsigned int round; caddr_t roundptr; struct ax_type *p; u_int16_t phy_vid, phy_did, phy_sts; s = splimp(); sc = malloc(sizeof(struct ax_softc), M_DEVBUF, M_NOWAIT); if (sc == NULL) { printf("ax%d: no memory for softc struct!\n", unit); goto fail; } bzero(sc, sizeof(struct ax_softc)); /* * Handle power management nonsense. */ command = pci_conf_read(config_id, AX_PCI_CAPID) & 0x000000FF; if (command == 0x01) { command = pci_conf_read(config_id, AX_PCI_PWRMGMTCTRL); if (command & AX_PSTATE_MASK) { u_int32_t iobase, membase, irq; /* Save important PCI config data. */ iobase = pci_conf_read(config_id, AX_PCI_LOIO); membase = pci_conf_read(config_id, AX_PCI_LOMEM); irq = pci_conf_read(config_id, AX_PCI_INTLINE); /* Reset the power state. */ printf("ax%d: chip is in D%d power mode " "-- setting to D0\n", unit, command & AX_PSTATE_MASK);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?