if_vr.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,963 行 · 第 1/4 页
C
1,963 行
if (ifma->ifma_addr->sa_family != AF_LINK) continue; h = vr_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); if (h < 32) hashes[0] |= (1 << h); else hashes[1] |= (1 << (h - 32)); mcnt++; } if (mcnt) rxfilt |= VR_RXCFG_RX_MULTI; else rxfilt &= ~VR_RXCFG_RX_MULTI; CSR_WRITE_4(sc, VR_MAR0, hashes[0]); CSR_WRITE_4(sc, VR_MAR1, hashes[1]); CSR_WRITE_1(sc, VR_RXCFG, rxfilt); return;}/* * Initiate an autonegotiation session. */static void vr_autoneg_xmit(sc) struct vr_softc *sc;{ u_int16_t phy_sts; vr_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); DELAY(500); while(vr_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_RESET); phy_sts = vr_phy_readreg(sc, PHY_BMCR); phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR; vr_phy_writereg(sc, PHY_BMCR, phy_sts); return;}/* * Invoke autonegotiation on a PHY. */static void vr_autoneg_mii(sc, flag, verbose) struct vr_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 = vr_phy_readreg(sc, PHY_BMSR); if (!(phy_sts & PHY_BMSR_CANAUTONEG)) { if (verbose) printf("vr%d: autonegotiation not supported\n", sc->vr_unit); ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; return; }#endif switch (flag) { case VR_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. */ vr_autoneg_xmit(sc); DELAY(5000000); break; case VR_FLAG_SCHEDDELAY: /* * Wait for the transmitter to go idle before starting * an autoneg session, otherwise vr_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->vr_cdata.vr_tx_head != NULL) { sc->vr_want_auto = 1; return; } vr_autoneg_xmit(sc); ifp->if_timer = 5; sc->vr_autoneg = 1; sc->vr_want_auto = 0; return; break; case VR_FLAG_DELAYTIMEO: ifp->if_timer = 0; sc->vr_autoneg = 0; break; default: printf("vr%d: invalid autoneg flag: %d\n", sc->vr_unit, flag); return; } if (vr_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_AUTONEGCOMP) { if (verbose) printf("vr%d: autoneg complete, ", sc->vr_unit); phy_sts = vr_phy_readreg(sc, PHY_BMSR); } else { if (verbose) printf("vr%d: autoneg not complete, ", sc->vr_unit); } media = vr_phy_readreg(sc, PHY_BMCR); /* Link is good. Report modes and set duplex mode. */ if (vr_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT) { if (verbose) printf("link status good "); advert = vr_phy_readreg(sc, PHY_ANAR); ability = vr_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 { 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. */ vr_setcfg(sc, media); vr_phy_writereg(sc, PHY_BMCR, media); } else { if (verbose) printf("no carrier\n"); } vr_init(sc); if (sc->vr_tx_pend) { sc->vr_autoneg = 0; sc->vr_tx_pend = 0; vr_start(ifp); } return;}static void vr_getmode_mii(sc) struct vr_softc *sc;{ u_int16_t bmsr; struct ifnet *ifp; ifp = &sc->arpcom.ac_if; bmsr = vr_phy_readreg(sc, PHY_BMSR); if (bootverbose) printf("vr%d: PHY status word: %x\n", sc->vr_unit, bmsr); /* fallback */ sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; if (bmsr & PHY_BMSR_10BTHALF) { if (bootverbose) printf("vr%d: 10Mbps half-duplex mode supported\n", sc->vr_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("vr%d: 10Mbps full-duplex mode supported\n", sc->vr_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("vr%d: 100Mbps half-duplex mode supported\n", sc->vr_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("vr%d: 100Mbps full-duplex mode supported\n", sc->vr_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("vr%d: 100baseT4 mode supported\n", sc->vr_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("vr%d: forcing on autoneg support for BT4\n", sc->vr_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("vr%d: autoneg supported\n", sc->vr_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 vr_setmode_mii(sc, media) struct vr_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->vr_autoneg) { printf("vr%d: canceling autoneg session\n", sc->vr_unit); ifp->if_timer = sc->vr_autoneg = sc->vr_want_auto = 0; bmcr = vr_phy_readreg(sc, PHY_BMCR); bmcr &= ~PHY_BMCR_AUTONEGENBL; vr_phy_writereg(sc, PHY_BMCR, bmcr); } printf("vr%d: selecting MII, ", sc->vr_unit); bmcr = vr_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; } vr_setcfg(sc, bmcr); vr_phy_writereg(sc, PHY_BMCR, bmcr); 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 vr_setcfg(sc, bmcr) struct vr_softc *sc; u_int16_t bmcr;{ int restart = 0; if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) { restart = 1; VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON)); } if (bmcr & PHY_BMCR_DUPLEX) VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); else VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); if (restart) VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON); return;}static void vr_reset(sc) struct vr_softc *sc;{ register int i; VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET); for (i = 0; i < VR_TIMEOUT; i++) { DELAY(10); if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET)) break; } if (i == VR_TIMEOUT) printf("vr%d: reset never completed!\n", sc->vr_unit); /* Wait a little while for the chip to get its brains in order. */ DELAY(1000); return;}/* * Probe for a VIA Rhine chip. Check the PCI vendor and device * IDs against our list and return a device name if we find a match. */static const char *vr_probe(config_id, device_id) pcici_t config_id; pcidi_t device_id;{ struct vr_type *t; t = vr_devs; while(t->vr_name != NULL) { if ((device_id & 0xFFFF) == t->vr_vid && ((device_id >> 16) & 0xFFFF) == t->vr_did) { return(t->vr_name); } t++; } return(NULL);}/* * Attach the interface. Allocate softc structures, do ifmedia * setup and ethernet/BPF attach. */static voidvr_attach(config_id, unit) pcici_t config_id; int unit;{ int s, i;#ifndef VR_USEIOSPACE vm_offset_t pbase, vbase;#endif u_char eaddr[ETHER_ADDR_LEN]; u_int32_t command; struct vr_softc *sc; struct ifnet *ifp; int media = IFM_ETHER|IFM_100_TX|IFM_FDX; unsigned int round; caddr_t roundptr; struct vr_type *p; u_int16_t phy_vid, phy_did, phy_sts; s = splimp(); sc = malloc(sizeof(struct vr_softc), M_DEVBUF, M_NOWAIT); if (sc == NULL) { printf("vr%d: no memory for softc struct!\n", unit); return; } bzero(sc, sizeof(struct vr_softc)); /* * Handle power management nonsense. */ command = pci_conf_read(config_id, VR_PCI_CAPID) & 0x000000FF; if (command == 0x01) { command = pci_conf_read(config_id, VR_PCI_PWRMGMTCTRL); if (command & VR_PSTATE_MASK) { u_int32_t iobase, membase, irq; /* Save important PCI config data. */ iobase = pci_conf_read(config_id, VR_PCI_LOIO); membase = pci_conf_read(config_id, VR_PCI_LOMEM); irq = pci_conf_read(config_id, VR_PCI_INTLINE); /* Reset the power state. */ printf("vr%d: chip is in D%d power mode " "-- setting to D0\n", unit, command & VR_PSTATE_MASK); command &= 0xFFFFFFFC; pci_conf_write(config_id, VR_PCI_PWRMGMTCTRL, command); /* Restore PCI config data. */ pci_conf_write(config_id, VR_PCI_LOIO, iobase); pci_conf_write(config_id, VR_PCI_LOMEM, membase); pci_conf_write(config_id, VR_PCI_INTLINE, irq); } } /* * Map control/status registers. */ command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, command); command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG);#ifdef VR_USEIOSPACE if (!(command & PCIM_CMD_PORTEN)) { printf("vr%d: failed to enable I/O ports!\n", unit); free(sc, M_DEVBUF); goto fail; } if (!pci_map_port(config_id, VR_PCI_LOIO, (u_int16_t *)(&sc->vr_bhandle))) { printf ("vr%d: couldn't map ports\n", unit); goto fail; } sc->vr_btag = I386_BUS_SPACE_IO;#else if (!(command & PCIM_CMD_MEMEN)) { printf("vr%d: failed to enable memory mapping!\n", unit); goto fail; } if (!pci_map_mem(config_id, VR_PCI_LOMEM, &vbase, &pbase)) { printf ("vr%d: couldn't map memory\n", unit); goto fail;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?