if_mx.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 2,495 行 · 第 1/4 页
C
2,495 行
pcidi_t device_id;{ struct mx_type *t; u_int32_t rev; t = mx_devs; while(t->mx_name != NULL) { if ((device_id & 0xFFFF) == t->mx_vid && ((device_id >> 16) & 0xFFFF) == t->mx_did) { /* Check the PCI revision */ rev = pci_conf_read(config_id, MX_PCI_REVID) & 0xFF; if (t->mx_did == MX_DEVICEID_98713 && rev >= MX_REVISION_98713A) t++; if (t->mx_did == CP_DEVICEID_98713 && rev >= MX_REVISION_98713A) t++; if (t->mx_did == MX_DEVICEID_987x5 && rev >= MX_REVISION_98725) t++; return(t->mx_name); } t++; } return(NULL);}/* * Attach the interface. Allocate softc structures, do ifmedia * setup and ethernet/BPF attach. */static voidmx_attach(config_id, unit) pcici_t config_id; int unit;{ int s, i;#ifndef MX_USEIOSPACE vm_offset_t pbase, vbase;#endif u_char eaddr[ETHER_ADDR_LEN]; u_int32_t command; struct mx_softc *sc; struct ifnet *ifp; int media = IFM_ETHER|IFM_100_TX|IFM_FDX; unsigned int round; caddr_t roundptr; struct mx_type *p; u_int16_t phy_vid, phy_did, phy_sts, mac_offset = 0; u_int32_t revision, pci_id; s = splimp(); sc = malloc(sizeof(struct mx_softc), M_DEVBUF, M_NOWAIT); if (sc == NULL) { printf("mx%d: no memory for softc struct!\n", unit); goto fail; } bzero(sc, sizeof(struct mx_softc)); /* * Handle power management nonsense. */ command = pci_conf_read(config_id, MX_PCI_CAPID) & 0x000000FF; if (command == 0x01) { command = pci_conf_read(config_id, MX_PCI_PWRMGMTCTRL); if (command & MX_PSTATE_MASK) { u_int32_t iobase, membase, irq; /* Save important PCI config data. */ iobase = pci_conf_read(config_id, MX_PCI_LOIO); membase = pci_conf_read(config_id, MX_PCI_LOMEM); irq = pci_conf_read(config_id, MX_PCI_INTLINE); /* Reset the power state. */ printf("mx%d: chip is in D%d power mode " "-- setting to D0\n", unit, command & MX_PSTATE_MASK); command &= 0xFFFFFFFC; pci_conf_write(config_id, MX_PCI_PWRMGMTCTRL, command); /* Restore PCI config data. */ pci_conf_write(config_id, MX_PCI_LOIO, iobase); pci_conf_write(config_id, MX_PCI_LOMEM, membase); pci_conf_write(config_id, MX_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 MX_USEIOSPACE if (!(command & PCIM_CMD_PORTEN)) { printf("mx%d: failed to enable I/O ports!\n", unit); free(sc, M_DEVBUF); goto fail; } if (!pci_map_port(config_id, MX_PCI_LOIO, (u_short *)&(sc->mx_bhandle))) { printf ("mx%d: couldn't map ports\n", unit); goto fail; }#ifdef __i386__ sc->mx_btag = I386_BUS_SPACE_IO;#endif#ifdef __alpha__ sc->mx_btag = ALPHA_BUS_SPACE_IO;#endif#else if (!(command & PCIM_CMD_MEMEN)) { printf("mx%d: failed to enable memory mapping!\n", unit); goto fail; } if (!pci_map_mem(config_id, MX_PCI_LOMEM, &vbase, &pbase)) { printf ("mx%d: couldn't map memory\n", unit); goto fail; }#ifdef __i386__ sc->mx_btag = I386_BUS_SPACE_MEM;#endif#ifdef __alpha__ sc->mx_btag = ALPHA_BUS_SPACE_MEM;#endif sc->mx_bhandle = vbase;#endif /* Allocate interrupt */ if (!pci_map_int(config_id, mx_intr, sc, &net_imask)) { printf("mx%d: couldn't map interrupt\n", unit); goto fail; } /* Need this info to decide on a chip type. */ revision = pci_conf_read(config_id, MX_PCI_REVID) & 0x000000FF; pci_id = (pci_conf_read(config_id,MX_PCI_VENDOR_ID) >> 16) & 0x0000FFFF; if (pci_id == MX_DEVICEID_98713 && revision < MX_REVISION_98713A) sc->mx_type = MX_TYPE_98713; else if (pci_id == CP_DEVICEID_98713 && revision < MX_REVISION_98713A) sc->mx_type = MX_TYPE_98713; else if (pci_id == MX_DEVICEID_98713 && revision >= MX_REVISION_98713A) sc->mx_type = MX_TYPE_98713A; else sc->mx_type = MX_TYPE_987x5; /* Save the cache line size. */ sc->mx_cachesize = pci_conf_read(config_id, MX_PCI_CACHELEN) & 0xFF; /* Reset the adapter. */ mx_reset(sc); /* * Get station address from the EEPROM. */ mx_read_eeprom(sc, (caddr_t)&mac_offset, (MX_EE_NODEADDR_OFFSET / 2), 1, 0); mx_read_eeprom(sc, (caddr_t)&eaddr, (mac_offset / 2), 3, 0); /* * A PMAC chip was detected. Inform the world. */ printf("mx%d: Ethernet address: %6D\n", unit, eaddr, ":"); sc->mx_unit = unit; bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); sc->mx_ldata_ptr = malloc(sizeof(struct mx_list_data) + 8, M_DEVBUF, M_NOWAIT); if (sc->mx_ldata_ptr == NULL) { free(sc, M_DEVBUF); printf("mx%d: no memory for list buffers!\n", unit); goto fail; } sc->mx_ldata = (struct mx_list_data *)sc->mx_ldata_ptr; round = (unsigned int)sc->mx_ldata_ptr & 0xF; roundptr = sc->mx_ldata_ptr; for (i = 0; i < 8; i++) { if (round % 8) { round++; roundptr++; } break; } sc->mx_ldata = (struct mx_list_data *)roundptr; bzero(sc->mx_ldata, sizeof(struct mx_list_data)); ifp = &sc->arpcom.ac_if; ifp->if_softc = sc; ifp->if_unit = unit; ifp->if_name = "mx"; ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = mx_ioctl; ifp->if_output = ether_output; ifp->if_start = mx_start; ifp->if_watchdog = mx_watchdog; ifp->if_init = mx_init; ifp->if_baudrate = 10000000; ifp->if_snd.ifq_maxlen = MX_TX_LIST_CNT - 1; if (sc->mx_type == MX_TYPE_98713) { if (bootverbose) printf("mx%d: probing for a PHY\n", sc->mx_unit); for (i = MX_PHYADDR_MIN; i < MX_PHYADDR_MAX + 1; i++) { if (bootverbose) printf("mx%d: checking address: %d\n", sc->mx_unit, i); sc->mx_phy_addr = i; mx_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); DELAY(500); while(mx_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_RESET); if ((phy_sts = mx_phy_readreg(sc, PHY_BMSR))) break; } if (phy_sts) { phy_vid = mx_phy_readreg(sc, PHY_VENID); phy_did = mx_phy_readreg(sc, PHY_DEVID); if (bootverbose) printf("mx%d: found PHY at address %d, ", sc->mx_unit, sc->mx_phy_addr); if (bootverbose) printf("vendor id: %x device id: %x\n", phy_vid, phy_did); p = mx_phys; while(p->mx_vid) { if (phy_vid == p->mx_vid && (phy_did | 0x000F) == p->mx_did) { sc->mx_pinfo = p; break; } p++; } if (sc->mx_pinfo == NULL) sc->mx_pinfo = &mx_phys[PHY_UNKNOWN]; if (bootverbose) printf("mx%d: PHY type: %s\n", sc->mx_unit, sc->mx_pinfo->mx_name); } else {#ifdef DIAGNOSTIC printf("mx%d: MII without any phy!\n", sc->mx_unit);#endif } } /* * Do ifmedia setup. */ ifmedia_init(&sc->ifmedia, 0, mx_ifmedia_upd, mx_ifmedia_sts); if (sc->mx_type == MX_TYPE_98713 && sc->mx_pinfo != NULL) { mx_getmode_mii(sc); mx_autoneg_mii(sc, MX_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); mx_autoneg(sc, MX_FLAG_FORCEDELAY, 1); } media = sc->ifmedia.ifm_media; mx_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(mx_shutdown, sc, SHUTDOWN_POST_SYNC);fail: splx(s); return;}/* * Initialize the transmit descriptors. */static int mx_list_tx_init(sc) struct mx_softc *sc;{ struct mx_chain_data *cd; struct mx_list_data *ld; int i; cd = &sc->mx_cdata; ld = sc->mx_ldata; for (i = 0; i < MX_TX_LIST_CNT; i++) { cd->mx_tx_chain[i].mx_ptr = &ld->mx_tx_list[i]; if (i == (MX_TX_LIST_CNT - 1)) cd->mx_tx_chain[i].mx_nextdesc = &cd->mx_tx_chain[0]; else cd->mx_tx_chain[i].mx_nextdesc = &cd->mx_tx_chain[i + 1]; } cd->mx_tx_free = &cd->mx_tx_chain[0]; cd->mx_tx_tail = cd->mx_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 mx_list_rx_init(sc) struct mx_softc *sc;{ struct mx_chain_data *cd; struct mx_list_data *ld; int i; cd = &sc->mx_cdata; ld = sc->mx_ldata; for (i = 0; i < MX_RX_LIST_CNT; i++) { cd->mx_rx_chain[i].mx_ptr = (struct mx_desc *)&ld->mx_rx_list[i]; if (mx_newbuf(sc, &cd->mx_rx_chain[i]) == ENOBUFS) return(ENOBUFS); if (i == (MX_RX_LIST_CNT - 1)) { cd->mx_rx_chain[i].mx_nextdesc = &cd->mx_rx_chain[0]; ld->mx_rx_list[i].mx_next = vtophys(&ld->mx_rx_list[0]); } else { cd->mx_rx_chain[i].mx_nextdesc = &cd->mx_rx_chain[i + 1]; ld->mx_rx_list[i].mx_next = vtophys(&ld->mx_rx_list[i + 1]); } } cd->mx_rx_head = &cd->mx_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 mx_newbuf(sc, c) struct mx_softc *sc; struct mx_chain_onefrag *c;{ struct mbuf *m_new = NULL; MGETHDR(m_new, M_DONTWAIT, MT_DATA); if (m_new == NULL) { printf("mx%d: no memory for rx list -- packet dropped!\n", sc->mx_unit); return(ENOBUFS); } MCLGET(m_new, M_DONTWAIT); if (!(m_new->m_flags & M_EXT)) { printf("mx%d: no memory for rx list -- packet dropped!\n", sc->mx_unit); m_freem(m_new); return(ENOBUFS); } c->mx_mbuf = m_new; c->mx_ptr->mx_status = MX_RXSTAT; c->mx_ptr->mx_data = vtophys(mtod(m_new, caddr_t)); c->mx_ptr->mx_ctl = MX_RXCTL_RLINK | (MCLBYTES - 1); return(0);}/* * A frame has been uploaded: pass the resulting mbuf chain up to * the higher level protocols. */static void mx_rxeof(sc) struct mx_softc *sc;{ struct ether_header *eh; struct mbuf *m; struct ifnet *ifp; struct mx_chain_onefrag *cur_rx; int total_len = 0; u_int32_t rxstat; ifp = &sc->arpcom.ac_if; while(!((rxstat = sc->mx_cdata.mx_rx_head->mx_ptr->mx_status) & MX_RXSTAT_OWN)) {#ifdef __alpha__ struct mbuf *m0 = NULL;#endif cur_rx = sc->mx_cdata.mx_rx_head; sc->mx_cdata.mx_rx_head = cur_rx->mx_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 & MX_RXSTAT_RXERR) { ifp->if_ierrors++; if (rxstat & MX_RXSTAT_COLLSEEN) ifp->if_collisions++; cur_rx->mx_ptr->mx_status = MX_RXSTAT; cur_rx->mx_ptr->mx_ctl = MX_RXCTL_RLINK | (MCLBYTES - 1); continue; } /* No errors; receive the packet. */ m = cur_rx->mx_mbuf; total_len = MX_RXBYTES(cur_rx->mx_ptr->mx_status); /* * XXX The Macronix chips 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 (mx_newbuf(sc, cur_rx) == ENOBUFS) { ifp->if_ierrors++; cur_rx->mx_ptr->mx_status = MX_RXSTAT; cur_rx->mx_ptr->mx_ctl = MX_RXCTL_RLINK | (MCLBYTES - 1); continue; }#ifdef __alpha__ /* * Deal with alignment on alpha. */ MGETHDR(m0, M_DONTWAIT, MT_DATA); if (m0 == NULL) { ifp->if_ierrors++; cur_rx->mx_ptr->mx_status = MX_RXSTAT; cur_rx->mx_ptr->mx_ctl = MX_RXCTL_RLINK | (MCLBYTES - 1); bzero((char *)mtod(cur_rx->mx_mbuf, char *), MCLBYTES); 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; }#else m->m_pkthdr.len = m->m_len = total_len;#endif ifp->if_ipackets++; eh = mtod(m, struct ether_header *); m->m_pkthdr.rcvif = ifp;#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 mx_rxeoc(sc) struct mx_softc *sc;{ mx_rxeof(sc); MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_RX_ON); CSR_WRITE_4(sc, MX_RXADDR, vtophys(sc->mx_cdata.mx_rx_head->mx_ptr)); MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_RX_ON); CSR_WRITE_4(sc, MX_RXSTART, 0xFFFFFFFF); return;}/* * A frame was downloaded to the chip. It's safe for us to clean up * the list buffers. */static void mx_txeof(sc) struct mx_softc *sc;{ struct mx_chain *cur_tx; struct ifnet *ifp; ifp = &sc->arpcom.ac_if; /* Clear the timeout timer. */ ifp->if_timer = 0; if (sc->mx_cdata.mx_tx_head == NULL) return; /* * Go through our tx list and free mbufs for those * frames that have been transmitted. */ while(sc->mx_cdata.mx_tx_head->mx_mbuf != NULL) { u_int32_t txstat; cur_tx = sc->mx_cdata.mx_tx_head; txstat = MX_TXSTATUS(cur_tx); if (txstat & MX_TXSTAT_OWN) break; if (txstat & MX_TXSTAT_ERRSUM) { ifp->if_oerrors++; if (txstat & MX_TXSTAT_EXCESSCOLL) ifp->if_collisions++; if (txstat & MX_TXSTAT_LATECOLL) ifp->if_collisions++; } ifp->if_collisions += (txstat & MX_TXSTAT_COLLCNT) >> 3; ifp->if_opackets++; m_freem(cur_tx->mx_mbuf); cur_tx->mx_mbuf = NULL; if (sc->mx_cdata.mx_tx_head == sc->mx_cdata.mx_tx_tail) { sc->mx_cdata.mx_tx_head = NULL; sc->mx_cdata.mx_tx_tail = NULL; break; } sc->mx_cdata.mx_tx_head = cur_tx->mx_nextdesc; } return;}/* * TX 'end of channel' interrupt handler. */static void mx_txeoc(sc) struct mx_softc *sc;{ struct ifnet *ifp; ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; if (sc->mx_cdata.mx_tx_head == NULL) { ifp->if_flags &= ~IFF_OACTIVE; sc->mx_cdata.mx_tx_tail = NULL; if (sc->mx_want_auto) { if (sc->mx_type == MX_TYPE_98713 && sc->mx_pinfo != NULL) mx_autoneg_mii(sc, MX_FLAG_DELAYTIMEO, 1); else mx_autoneg(sc, MX_FLAG_DELAYTIMEO, 1); } }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?