if_vr.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,963 行 · 第 1/4 页
C
1,963 行
} sc->vr_bhandle = vbase; sc->vr_btag = I386_BUS_SPACE_MEM;#endif /* Allocate interrupt */ if (!pci_map_int(config_id, vr_intr, sc, &net_imask)) { printf("vr%d: couldn't map interrupt\n", unit); goto fail; } /* Reset the adapter. */ vr_reset(sc); /* * Get station address. The way the Rhine chips work, * you're not allowed to directly access the EEPROM once * they've been programmed a special way. Consequently, * we need to read the node address from the PAR0 and PAR1 * registers. */ VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD); DELAY(200); for (i = 0; i < ETHER_ADDR_LEN; i++) eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i); /* * A Rhine chip was detected. Inform the world. */ printf("vr%d: Ethernet address: %6D\n", unit, eaddr, ":"); sc->vr_unit = unit; bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); sc->vr_ldata_ptr = malloc(sizeof(struct vr_list_data) + 8, M_DEVBUF, M_NOWAIT); if (sc->vr_ldata_ptr == NULL) { free(sc, M_DEVBUF); printf("vr%d: no memory for list buffers!\n", unit); return; } sc->vr_ldata = (struct vr_list_data *)sc->vr_ldata_ptr; round = (unsigned int)sc->vr_ldata_ptr & 0xF; roundptr = sc->vr_ldata_ptr; for (i = 0; i < 8; i++) { if (round % 8) { round++; roundptr++; } else break; } sc->vr_ldata = (struct vr_list_data *)roundptr; bzero(sc->vr_ldata, sizeof(struct vr_list_data)); ifp = &sc->arpcom.ac_if; ifp->if_softc = sc; ifp->if_unit = unit; ifp->if_name = "vr"; ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = vr_ioctl; ifp->if_output = ether_output; ifp->if_start = vr_start; ifp->if_watchdog = vr_watchdog; ifp->if_init = vr_init; ifp->if_baudrate = 10000000; ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1; if (bootverbose) printf("vr%d: probing for a PHY\n", sc->vr_unit); for (i = VR_PHYADDR_MIN; i < VR_PHYADDR_MAX + 1; i++) { if (bootverbose) printf("vr%d: checking address: %d\n", sc->vr_unit, i); sc->vr_phy_addr = i; vr_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); DELAY(500); while(vr_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_RESET); if ((phy_sts = vr_phy_readreg(sc, PHY_BMSR))) break; } if (phy_sts) { phy_vid = vr_phy_readreg(sc, PHY_VENID); phy_did = vr_phy_readreg(sc, PHY_DEVID); if (bootverbose) printf("vr%d: found PHY at address %d, ", sc->vr_unit, sc->vr_phy_addr); if (bootverbose) printf("vendor id: %x device id: %x\n", phy_vid, phy_did); p = vr_phys; while(p->vr_vid) { if (phy_vid == p->vr_vid && (phy_did | 0x000F) == p->vr_did) { sc->vr_pinfo = p; break; } p++; } if (sc->vr_pinfo == NULL) sc->vr_pinfo = &vr_phys[PHY_UNKNOWN]; if (bootverbose) printf("vr%d: PHY type: %s\n", sc->vr_unit, sc->vr_pinfo->vr_name); } else { printf("vr%d: MII without any phy!\n", sc->vr_unit); goto fail; } /* * Do ifmedia setup. */ ifmedia_init(&sc->ifmedia, 0, vr_ifmedia_upd, vr_ifmedia_sts); vr_getmode_mii(sc); vr_autoneg_mii(sc, VR_FLAG_FORCEDELAY, 1); media = sc->ifmedia.ifm_media; vr_stop(sc); ifmedia_set(&sc->ifmedia, media); /* * Call MI attach routines. */ if_attach(ifp); ether_ifattach(ifp);#if NBPFILTER > 0 bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));#endif at_shutdown(vr_shutdown, sc, SHUTDOWN_POST_SYNC);fail: splx(s); return;}/* * Initialize the transmit descriptors. */static int vr_list_tx_init(sc) struct vr_softc *sc;{ struct vr_chain_data *cd; struct vr_list_data *ld; int i; cd = &sc->vr_cdata; ld = sc->vr_ldata; for (i = 0; i < VR_TX_LIST_CNT; i++) { cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i]; if (i == (VR_TX_LIST_CNT - 1)) cd->vr_tx_chain[i].vr_nextdesc = &cd->vr_tx_chain[0]; else cd->vr_tx_chain[i].vr_nextdesc = &cd->vr_tx_chain[i + 1]; } cd->vr_tx_free = &cd->vr_tx_chain[0]; cd->vr_tx_tail = cd->vr_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 vr_list_rx_init(sc) struct vr_softc *sc;{ struct vr_chain_data *cd; struct vr_list_data *ld; int i; cd = &sc->vr_cdata; ld = sc->vr_ldata; for (i = 0; i < VR_RX_LIST_CNT; i++) { cd->vr_rx_chain[i].vr_ptr = (struct vr_desc *)&ld->vr_rx_list[i]; if (vr_newbuf(sc, &cd->vr_rx_chain[i]) == ENOBUFS) return(ENOBUFS); if (i == (VR_RX_LIST_CNT - 1)) { cd->vr_rx_chain[i].vr_nextdesc = &cd->vr_rx_chain[0]; ld->vr_rx_list[i].vr_next = vtophys(&ld->vr_rx_list[0]); } else { cd->vr_rx_chain[i].vr_nextdesc = &cd->vr_rx_chain[i + 1]; ld->vr_rx_list[i].vr_next = vtophys(&ld->vr_rx_list[i + 1]); } } cd->vr_rx_head = &cd->vr_rx_chain[0]; return(0);}/* * Initialize an RX descriptor and attach an MBUF cluster. * Note: the length fields are only 11 bits wide, which means the * largest size we can specify is 2047. This is important because * MCLBYTES is 2048, so we have to subtract one otherwise we'll * overflow the field and make a mess. */static int vr_newbuf(sc, c) struct vr_softc *sc; struct vr_chain_onefrag *c;{ struct mbuf *m_new = NULL; MGETHDR(m_new, M_DONTWAIT, MT_DATA); if (m_new == NULL) { printf("vr%d: no memory for rx list -- packet dropped!\n", sc->vr_unit); return(ENOBUFS); } MCLGET(m_new, M_DONTWAIT); if (!(m_new->m_flags & M_EXT)) { printf("vr%d: no memory for rx list -- packet dropped!\n", sc->vr_unit); m_freem(m_new); return(ENOBUFS); } c->vr_mbuf = m_new; c->vr_ptr->vr_status = VR_RXSTAT; c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t)); c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN; return(0);}/* * A frame has been uploaded: pass the resulting mbuf chain up to * the higher level protocols. */static void vr_rxeof(sc) struct vr_softc *sc;{ struct ether_header *eh; struct mbuf *m; struct ifnet *ifp; struct vr_chain_onefrag *cur_rx; int total_len = 0; u_int32_t rxstat; ifp = &sc->arpcom.ac_if; while(!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) & VR_RXSTAT_OWN)) { cur_rx = sc->vr_cdata.vr_rx_head; sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc; /* * If an error occurs, update stats, clear the * status word and leave the mbuf cluster in place: * it should simply get re-used next time this descriptor * comes up in the ring. */ if (rxstat & VR_RXSTAT_RXERR) { ifp->if_ierrors++; printf("vr%d: rx error: ", sc->vr_unit); switch(rxstat & 0x000000FF) { case VR_RXSTAT_CRCERR: printf("crc error\n"); break; case VR_RXSTAT_FRAMEALIGNERR: printf("frame alignment error\n"); break; case VR_RXSTAT_FIFOOFLOW: printf("FIFO overflow\n"); break; case VR_RXSTAT_GIANT: printf("received giant packet\n"); break; case VR_RXSTAT_RUNT: printf("received runt packet\n"); break; case VR_RXSTAT_BUSERR: printf("system bus error\n"); break; case VR_RXSTAT_BUFFERR: printf("rx buffer error\n"); break; default: printf("unknown rx error\n"); break; } cur_rx->vr_ptr->vr_status = VR_RXSTAT; cur_rx->vr_ptr->vr_ctl = VR_RXCTL|VR_RXLEN; continue; } /* No errors; receive the packet. */ m = cur_rx->vr_mbuf; total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status); /* * XXX The VIA Rhine chip includes the CRC with every * received frame, and there's no way to turn this * behavior off (at least, I can't find anything in * the manual that explains how to do it) so we have * to trim off the CRC manually. */ total_len -= ETHER_CRC_LEN; /* * 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 (vr_newbuf(sc, cur_rx) == ENOBUFS) { ifp->if_ierrors++; cur_rx->vr_ptr->vr_status = VR_RXSTAT; cur_rx->vr_ptr->vr_ctl = VR_RXCTL|VR_RXLEN; continue; } ifp->if_ipackets++; eh = mtod(m, struct ether_header *); m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = total_len;#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 (ifp->if_bpf) { bpf_mtap(ifp, m); if (ifp->if_flags & IFF_PROMISC && (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN) && (eh->ether_dhost[0] & 1) == 0)) { m_freem(m); continue; } }#endif /* Remove header from mbuf and pass it on. */ m_adj(m, sizeof(struct ether_header)); ether_input(ifp, eh, m); } return;}void vr_rxeoc(sc) struct vr_softc *sc;{ vr_rxeof(sc); VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO); return;}/* * A frame was downloaded to the chip. It's safe for us to clean up * the list buffers. */static void vr_txeof(sc) struct vr_softc *sc;{ struct vr_chain *cur_tx; struct ifnet *ifp; register struct mbuf *n; ifp = &sc->arpcom.ac_if; /* Clear the timeout timer. */ ifp->if_timer = 0; /* Sanity check. */ if (sc->vr_cdata.vr_tx_head == NULL) return; /* * Go through our tx list and free mbufs for those * frames that have been transmitted. */ while(sc->vr_cdata.vr_tx_head->vr_mbuf != NULL) { u_int32_t txstat; cur_tx = sc->vr_cdata.vr_tx_head; txstat = cur_tx->vr_ptr->vr_status; if (txstat & VR_TXSTAT_OWN) break; if (txstat & VR_TXSTAT_ERRSUM) { ifp->if_oerrors++; if (txstat & VR_TXSTAT_DEFER) ifp->if_collisions++; if (txstat & VR_TXSTAT_LATECOLL) ifp->if_collisions++; } ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3; ifp->if_opackets++; MFREE(cur_tx->vr_mbuf, n); cur_tx->vr_mbuf = NULL; if (sc->vr_cdata.vr_tx_head == sc->vr_cdata.vr_tx_tail) { sc->vr_cdata.vr_tx_head = NULL; sc->vr_cdata.vr_tx_tail = NULL; break; } sc->vr_cdata.vr_tx_head = cur_tx->vr_nextdesc; } return;}/* * TX 'end of channel' interrupt handler. */static void vr_txeoc(sc) struct vr_softc *sc;{ struct ifnet *ifp; ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; if (sc->vr_cdata.vr_tx_head == NULL) { ifp->if_flags &= ~IFF_OACTIVE; sc->vr_cdata.vr_tx_tail = NULL; if (sc->vr_want_auto) vr_autoneg_mii(sc, VR_FLAG_SCHEDDELAY, 1); } return;}static void vr_intr(arg) void *arg;{ struct vr_softc *sc; struct ifnet *ifp; u_int16_t status; sc = arg; ifp = &sc->arpcom.ac_if; /* Supress unwanted interrupts. */ if (!(ifp->if_flags & IFF_UP)) { vr_stop(sc); return; } /* Disable interrupts. */ CSR_WRITE_2(sc, VR_IMR, 0x0000); for (;;) { status = CSR_READ_2(sc, VR_ISR); if (status) CSR_WRITE_2(sc, VR_ISR, status); if ((status & VR_INTRS) == 0) break; if (status & VR_ISR_RX_OK) vr_rxeof(sc); if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW) || (status & VR_ISR_RX_DROPPED)) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?