if_ax.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 2,242 行 · 第 1/4 页
C
2,242 行
command &= 0xFFFFFFFC; pci_conf_write(config_id, AX_PCI_PWRMGMTCTRL, command); /* Restore PCI config data. */ pci_conf_write(config_id, AX_PCI_LOIO, iobase); pci_conf_write(config_id, AX_PCI_LOMEM, membase); pci_conf_write(config_id, AX_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 AX_USEIOSPACE if (!(command & PCIM_CMD_PORTEN)) { printf("ax%d: failed to enable I/O ports!\n", unit); free(sc, M_DEVBUF); goto fail; } if (!pci_map_port(config_id, AX_PCI_LOIO, (u_short *)&(sc->ax_bhandle))) { printf ("ax%d: couldn't map ports\n", unit); goto fail; }#ifdef __i386__ sc->ax_btag = I386_BUS_SPACE_IO;#endif#ifdef __alpha__ sc->ax_btag = ALPHA_BUS_SPACE_IO;#endif#else if (!(command & PCIM_CMD_MEMEN)) { printf("ax%d: failed to enable memory mapping!\n", unit); goto fail; } if (!pci_map_mem(config_id, AX_PCI_LOMEM, &vbase, &pbase)) { printf ("ax%d: couldn't map memory\n", unit); goto fail; }#ifdef __i386__ sc->ax_btag = I386_BUS_SPACE_MEM;#endif#ifdef __alpha__ sc->ax_btag = ALPHA_BUS_SPACE_MEM;#endif sc->ax_bhandle = vbase;#endif /* Allocate interrupt */ if (!pci_map_int(config_id, ax_intr, sc, &net_imask)) { printf("ax%d: couldn't map interrupt\n", unit); goto fail; } /* Reset the adapter. */ ax_reset(sc); /* * Get station address from the EEPROM. */ ax_read_eeprom(sc, (caddr_t)&eaddr, AX_EE_NODEADDR, 3, 0); /* * An ASIX chip was detected. Inform the world. */ printf("ax%d: Ethernet address: %6D\n", unit, eaddr, ":"); sc->ax_unit = unit; bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); sc->ax_ldata_ptr = malloc(sizeof(struct ax_list_data) + 8, M_DEVBUF, M_NOWAIT); if (sc->ax_ldata_ptr == NULL) { free(sc, M_DEVBUF); printf("ax%d: no memory for list buffers!\n", unit); goto fail; } sc->ax_ldata = (struct ax_list_data *)sc->ax_ldata_ptr; round = (unsigned int)sc->ax_ldata_ptr & 0xF; roundptr = sc->ax_ldata_ptr; for (i = 0; i < 8; i++) { if (round % 8) { round++; roundptr++; } else break; } sc->ax_ldata = (struct ax_list_data *)roundptr; bzero(sc->ax_ldata, sizeof(struct ax_list_data)); ifp = &sc->arpcom.ac_if; ifp->if_softc = sc; ifp->if_unit = unit; ifp->if_name = "ax"; ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = ax_ioctl; ifp->if_output = ether_output; ifp->if_start = ax_start; ifp->if_watchdog = ax_watchdog; ifp->if_init = ax_init; ifp->if_baudrate = 10000000; ifp->if_snd.ifq_maxlen = AX_TX_LIST_CNT - 1; if (bootverbose) printf("ax%d: probing for a PHY\n", sc->ax_unit); for (i = AX_PHYADDR_MIN; i < AX_PHYADDR_MAX + 1; i++) { if (bootverbose) printf("ax%d: checking address: %d\n", sc->ax_unit, i); sc->ax_phy_addr = i; ax_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); DELAY(500); while(ax_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_RESET); if ((phy_sts = ax_phy_readreg(sc, PHY_BMSR))) break; } if (phy_sts) { phy_vid = ax_phy_readreg(sc, PHY_VENID); phy_did = ax_phy_readreg(sc, PHY_DEVID); if (bootverbose) printf("ax%d: found PHY at address %d, ", sc->ax_unit, sc->ax_phy_addr); if (bootverbose) printf("vendor id: %x device id: %x\n", phy_vid, phy_did); p = ax_phys; while(p->ax_vid) { if (phy_vid == p->ax_vid && (phy_did | 0x000F) == p->ax_did) { sc->ax_pinfo = p; break; } p++; } if (sc->ax_pinfo == NULL) sc->ax_pinfo = &ax_phys[PHY_UNKNOWN]; if (bootverbose) printf("ax%d: PHY type: %s\n", sc->ax_unit, sc->ax_pinfo->ax_name); } else {#ifdef DIAGNOSTIC printf("ax%d: MII without any phy!\n", sc->ax_unit);#endif } /* * Do ifmedia setup. */ ifmedia_init(&sc->ifmedia, 0, ax_ifmedia_upd, ax_ifmedia_sts); if (sc->ax_pinfo != NULL) { ax_getmode_mii(sc); ax_autoneg_mii(sc, AX_FLAG_FORCEDELAY, 1); } else { ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); } media = sc->ifmedia.ifm_media; ax_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(ax_shutdown, sc, SHUTDOWN_POST_SYNC);fail: splx(s); return;}/* * Initialize the transmit descriptors. */static int ax_list_tx_init(sc) struct ax_softc *sc;{ struct ax_chain_data *cd; struct ax_list_data *ld; int i; cd = &sc->ax_cdata; ld = sc->ax_ldata; for (i = 0; i < AX_TX_LIST_CNT; i++) { cd->ax_tx_chain[i].ax_ptr = &ld->ax_tx_list[i]; if (i == (AX_TX_LIST_CNT - 1)) cd->ax_tx_chain[i].ax_nextdesc = &cd->ax_tx_chain[0]; else cd->ax_tx_chain[i].ax_nextdesc = &cd->ax_tx_chain[i + 1]; } cd->ax_tx_free = &cd->ax_tx_chain[0]; cd->ax_tx_tail = cd->ax_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 ax_list_rx_init(sc) struct ax_softc *sc;{ struct ax_chain_data *cd; struct ax_list_data *ld; int i; cd = &sc->ax_cdata; ld = sc->ax_ldata; for (i = 0; i < AX_RX_LIST_CNT; i++) { cd->ax_rx_chain[i].ax_ptr = (volatile struct ax_desc *)&ld->ax_rx_list[i]; if (ax_newbuf(sc, &cd->ax_rx_chain[i]) == ENOBUFS) return(ENOBUFS); if (i == (AX_RX_LIST_CNT - 1)) { cd->ax_rx_chain[i].ax_nextdesc = &cd->ax_rx_chain[0]; ld->ax_rx_list[i].ax_next = vtophys(&ld->ax_rx_list[0]); } else { cd->ax_rx_chain[i].ax_nextdesc = &cd->ax_rx_chain[i + 1]; ld->ax_rx_list[i].ax_next = vtophys(&ld->ax_rx_list[i + 1]); } } cd->ax_rx_head = &cd->ax_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 ax_newbuf(sc, c) struct ax_softc *sc; struct ax_chain_onefrag *c;{ struct mbuf *m_new = NULL; MGETHDR(m_new, M_DONTWAIT, MT_DATA); if (m_new == NULL) { printf("ax%d: no memory for rx list -- packet dropped!\n", sc->ax_unit); return(ENOBUFS); } MCLGET(m_new, M_DONTWAIT); if (!(m_new->m_flags & M_EXT)) { printf("ax%d: no memory for rx list -- packet dropped!\n", sc->ax_unit); m_freem(m_new); return(ENOBUFS); } c->ax_mbuf = m_new; c->ax_ptr->ax_status = AX_RXSTAT; c->ax_ptr->ax_data = vtophys(mtod(m_new, caddr_t)); c->ax_ptr->ax_ctl = MCLBYTES - 1; return(0);}/* * A frame has been uploaded: pass the resulting mbuf chain up to * the higher level protocols. */static void ax_rxeof(sc) struct ax_softc *sc;{ struct ether_header *eh; struct mbuf *m; struct ifnet *ifp; struct ax_chain_onefrag *cur_rx; int total_len = 0; u_int32_t rxstat; ifp = &sc->arpcom.ac_if; while(!((rxstat = sc->ax_cdata.ax_rx_head->ax_ptr->ax_status) & AX_RXSTAT_OWN)) {#ifdef __alpha__ struct mbuf *m0 = NULL;#endif cur_rx = sc->ax_cdata.ax_rx_head; sc->ax_cdata.ax_rx_head = cur_rx->ax_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 & AX_RXSTAT_RXERR) { ifp->if_ierrors++; if (rxstat & AX_RXSTAT_COLLSEEN) ifp->if_collisions++; cur_rx->ax_ptr->ax_status = AX_RXSTAT; cur_rx->ax_ptr->ax_ctl = (MCLBYTES - 1); continue; } /* No errors; receive the packet. */ m = cur_rx->ax_mbuf; total_len = AX_RXBYTES(cur_rx->ax_ptr->ax_status); total_len -= ETHER_CRC_LEN;#ifdef __alpha__ /* * 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 (ax_newbuf(sc, cur_rx) == ENOBUFS) { ifp->if_ierrors++; cur_rx->ax_ptr->ax_status = AX_RXSTAT; cur_rx->ax_ptr->ax_ctl = (MCLBYTES - 1); continue; } /* * Sadly, the ASIX chip doesn't decode the last few * bits of the RX DMA buffer address, so we have to * cheat in order to obtain proper payload alignment * on the alpha. */ MGETHDR(m0, M_DONTWAIT, MT_DATA); if (m0 == NULL) { ifp->if_ierrors++; cur_rx->ax_ptr->ax_status = AX_RXSTAT; cur_rx->ax_ptr->ax_ctl = (MCLBYTES - 1); continue; } m0->m_data += 2; if (total_len <= (MHLEN - 2)) { bcopy(mtod(m, caddr_t), mtod(m0, caddr_t), total_len); m_freem(m); m = m0; m->m_pkthdr.len = m->m_len = total_len; } else { bcopy(mtod(m, caddr_t), mtod(m0, caddr_t), (MHLEN - 2)); m->m_len = total_len - (MHLEN - 2); m->m_data += (MHLEN - 2); m0->m_next = m; m0->m_len = (MHLEN - 2); m = m0; m->m_pkthdr.len = total_len; } m->m_pkthdr.rcvif = ifp;#else if (total_len < MINCLSIZE) { m = m_devget(mtod(cur_rx->ax_mbuf, char *), total_len, 0, ifp, NULL); cur_rx->ax_ptr->ax_status = AX_RXSTAT; cur_rx->ax_ptr->ax_ctl = (MCLBYTES - 1); if (m == NULL) { ifp->if_ierrors++; continue; } } else { m = cur_rx->ax_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 (ax_newbuf(sc, cur_rx) == ENOBUFS) { ifp->if_ierrors++; cur_rx->ax_ptr->ax_status = AX_RXSTAT; cur_rx->ax_ptr->ax_ctl = (MCLBYTES - 1); continue; } m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = total_len; }#endif ifp->if_ipackets++; 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 (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 ax_rxeoc(sc) struct ax_softc *sc;{ ax_rxeof(sc); AX_CLRBIT(sc, AX_NETCFG, AX_NETCFG_RX_ON); CSR_WRITE_4(sc, AX_RXADDR, vtophys(sc->ax_cdata.ax_rx_head->ax_ptr)); AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_RX_ON); CSR_WRITE_4(sc, AX_RXSTART, 0xFFFFFFFF); return;}/* * A frame was downloaded to the chip. It's safe for us to clean up * the list buffers. */static void ax_txeof(sc) struct ax_softc *sc;{ struct ax_chain *cur_tx; struct ifnet *ifp; ifp = &sc->arpcom.ac_if; /* Clear the timeout timer. */ ifp->if_timer = 0; if (sc->ax_cdata.ax_tx_head == NULL) return; /* * Go through our tx list and free mbufs for those * frames that have been transmitted. */ while(sc->ax_cdata.ax_tx_head->ax_mbuf != NULL) { u_int32_t txstat; cur_tx = sc->ax_cdata.ax_tx_head; txstat = AX_TXSTATUS(cur_tx); if (txstat & AX_TXSTAT_OWN) break; if (txstat & AX_TXSTAT_ERRSUM) { ifp->if_oerrors++; if (txstat & AX_TXSTAT_EXCESSCOLL) ifp->if_collisions++; if (txstat & AX_TXSTAT_LATECOLL) ifp->if_collisions++; } ifp->if_collisions += (txstat & AX_TXSTAT_COLLCNT) >> 3; ifp->if_opackets++; m_freem(cur_tx->ax_mbuf); cur_tx->ax_mbuf = NULL; if (sc->ax_cdata.ax_tx_head == sc->ax_cdata.ax_tx_tail) { sc->ax_cdata.ax_tx_head = NULL; sc->ax_cdata.ax_tx_tail = NULL; break; } sc->ax_cdata.ax_tx_head = cur_tx->ax_nextdesc; } return;}/* * TX 'end of channel' interrupt handler. */static void ax_txeoc(sc) struct ax_softc *sc;{ struct ifnet *ifp; ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; if (sc->ax_cdata.ax_tx_head == NULL) { ifp->if_flags &= ~IFF_OACTIVE; sc->ax_cdata.ax_tx_tail = NULL; if (sc->ax_want_auto) ax_autoneg_mii(sc, AX_FLAG_DELAYTIMEO, 1); } return;}static void ax_intr(arg) void *arg;{ struct ax_softc *sc; struct ifnet *ifp; u_int32_t status; sc = arg; ifp = &sc->arpcom.ac_if; /* Supress unwanted interrupts */ if (!(ifp->if_flags & IFF_UP)) { ax_stop(sc); return; } /* Disable interrupts. */ CSR_WRITE_4(sc, AX_IMR, 0x00000000); for (;;) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?