📄 if_wx.c
字号:
if (sc->wx_mii) { mii_pollstat(WX_MII_FROM_SOFTC(sc)); return; } rxcw = READ_CSR(sc, WXREG_RECV_CFGW); dcr = READ_CSR(sc, WXREG_DCR); dsr = READ_CSR(sc, WXREG_DSR); if ((dsr & WXDSR_LU) == 0 && (dcr & WXDCR_SWDPIN1) == 0 && (rxcw & WXRXCW_C) == 0) { if (sc->ane_failed == 0) { sc->ane_failed = 1; return; } DPRINTF(sc, (inane, sc->wx_name)); WRITE_CSR(sc, WXREG_XMIT_CFGW, WXTXCW_DEFAULT & ~WXTXCW_ANE); if (sc->wx_idnrev < WX_WISEMAN_2_1) sc->wx_dcr &= ~WXDCR_TFCE; sc->wx_dcr |= WXDCR_SLU; WRITE_CSR(sc, WXREG_DCR, sc->wx_dcr); } else if ((rxcw & WXRXCW_C) != 0 && (dcr & WXDCR_SLU) != 0) { DPRINTF(sc, (ane, sc->wx_name)); WRITE_CSR(sc, WXREG_XMIT_CFGW, WXTXCW_DEFAULT); sc->wx_dcr &= ~WXDCR_SLU; WRITE_CSR(sc, WXREG_DCR, sc->wx_dcr); }}static voidwx_handle_rxint(wx_softc_t *sc){ struct ether_header *eh; struct mbuf *m0, *mb, *pending[WX_MAX_RDESC]; struct ifnet *ifp = &sc->wx_if; int npkts, ndesc, lidx, idx, tlen; DPRINTF(sc, ("%s: wx_handle_rxint\n", sc->wx_name)); for (m0 = sc->rpending, tlen = ndesc = npkts = 0, idx = sc->rnxt, lidx = R_PREV_IDX(idx); ndesc < WX_MAX_RDESC; ndesc++, lidx = idx, idx = R_NXT_IDX(idx)) { wxrd_t *rd; rxpkt_t *rxpkt; int length, offset, lastframe; rd = &sc->rdescriptors[idx];#if defined(__mips__) rd = (wxrd_t *)PHYS_TO_UNCACHED(vtophys(rd));#endif /* * XXX: DMA Flush descriptor */ if ((rd->status & RDSTAT_DD) == 0) { if (m0) { if (sc->rpending == NULL) { m0->m_pkthdr.len = tlen; sc->rpending = m0; } else { m_freem(m0); } m0 = NULL; } DPRINTF(sc, ("%s: WXRX: ndesc %d idx %d lidx %d\n", sc->wx_name, ndesc, idx, lidx)); break; } if (rd->errors != 0) {#if 0 printf("%s: packet with errors (%x)\n", sc->wx_name, rd->errors);#endif rd->status = 0; ifp->if_ierrors++; if (m0) { m_freem(m0); m0 = NULL; if (sc->rpending) { m_freem(sc->rpending); sc->rpending = NULL; } } continue; } rxpkt = &sc->rbase[idx]; mb = rxpkt->dptr; if (mb == NULL) { printf("%s: receive descriptor with no mbuf\n", sc->wx_name); (void) wx_get_rbuf(sc, rxpkt); rd->status = 0; ifp->if_ierrors++; if (m0) { m_freem(m0); m0 = NULL; if (sc->rpending) { m_freem(sc->rpending); sc->rpending = NULL; } } continue; } /* XXX: Flush DMA for rxpkt */ if (wx_get_rbuf(sc, rxpkt)) { sc->wx_rxnobuf++; wx_rxdma_map(sc, rxpkt, mb); ifp->if_ierrors++; rd->status = 0; if (m0) { m_freem(m0); m0 = NULL; if (sc->rpending) { m_freem(sc->rpending); sc->rpending = NULL; } } continue; } /* * Save the completing packet's offset value and length * and install the new one into the descriptor. */ lastframe = (rd->status & RDSTAT_EOP) != 0; length = letoh16(rd->length); offset = letoh32(rd->address.lowpart) & 0xff; bzero (rd, sizeof (*rd)); rd->address.lowpart = htole32(rxpkt->dma_addr + WX_RX_OFFSET_VALUE); mb->m_len = length; mb->m_data += offset; mb->m_next = NULL; if (m0 == NULL) { m0 = mb; tlen = length; } else if (m0 == sc->rpending) { /* * Pick up where we left off before. If * we have an offset (we're assuming the * first frame has an offset), then we've * lost sync somewhere along the line. */ if (offset) { printf("%s: lost sync with partial packet\n", sc->wx_name); m_freem(sc->rpending); sc->rpending = NULL; m0 = mb; tlen = length; } else { sc->rpending = NULL; tlen = m0->m_pkthdr.len; } } else { tlen += length; } DPRINTF(sc, ("%s: RDESC[%d] len %d off %d lastframe %d\n", sc->wx_name, idx, mb->m_len, offset, lastframe)); if (m0 != mb) m_cat(m0, mb); if (lastframe == 0) { continue; } m0->m_pkthdr.rcvif = ifp; m0->m_pkthdr.len = tlen - WX_CRC_LENGTH; mb->m_len -= WX_CRC_LENGTH; eh = mtod(m0, struct ether_header *); /* * No need to check for promiscous mode since * the decision to keep or drop the packet is * handled by ether_input() */ pending[npkts++] = m0; m0 = NULL; tlen = 0; } if (ndesc) { if (IS_WISEMAN(sc)) { WRITE_CSR(sc, WXREG_RDT0, lidx); } else { WRITE_CSR(sc, WXREG_RDT0_LIVENGOOD, lidx); } sc->rnxt = idx; } if (npkts) { sc->wx_rxintr++; } for (idx = 0; idx < npkts; idx++) { mb = pending[idx];#if NBPFILTER > 0 if (ifp->if_bpf) { bpf_mtap(WX_BPFTAP_ARG(ifp), mb); }#endif ifp->if_ipackets++; DPRINTF(sc, ("%s: RECV packet length %d\n", sc->wx_name, mb->m_pkthdr.len));#ifndef PMON ether_input_mbuf(ifp, mb);#else { struct ether_header *eh; eh = mtod(mb, struct ether_header *); mb->m_data += sizeof(struct ether_header); ether_input(ifp, eh, mb); }#endif }}static voidwx_gc(wx_softc_t *sc){ struct ifnet *ifp = &sc->wx_if; txpkt_t *txpkt; u_int32_t tdh; WX_LOCK(sc); txpkt = sc->tbsyf; if (IS_WISEMAN(sc)) { tdh = READ_CSR(sc, WXREG_TDH); } else { tdh = READ_CSR(sc, WXREG_TDH_LIVENGOOD); } while (txpkt != NULL) { u_int32_t end = txpkt->eidx, cidx = tdh; /* * Normalize start..end indices to 2 * * WX_MAX_TDESC range to eliminate wrap. */ if (txpkt->eidx < txpkt->sidx) { end += WX_MAX_TDESC; } /* * Normalize current chip index to 2 * * WX_MAX_TDESC range to eliminate wrap. */ if (cidx < txpkt->sidx) { cidx += WX_MAX_TDESC; } /* * If the current chip index is between low and * high indices for this packet, it's not finished * transmitting yet. Because transmits are done FIFO, * this means we're done garbage collecting too. */ if (txpkt->sidx <= cidx && cidx < txpkt->eidx) {#if 0 DPRINTF(sc, ("%s: TXGC %d..%d TDH %d\n", sc->wx_name, txpkt->sidx, txpkt->eidx, tdh));#endif break; } ifp->if_opackets++; if (txpkt->dptr) { (void) m_freem(txpkt->dptr); } else { printf("%s: null mbuf in gc\n", sc->wx_name); } for (cidx = txpkt->sidx; cidx != txpkt->eidx; cidx = T_NXT_IDX(cidx)) { txpkt_t *tmp; wxtd_t *td; td = &sc->tdescriptors[cidx];#if defined(__mips__) td = (wxtd_t *)PHYS_TO_UNCACHED(vtophys(td));#else CACHESYNC(td, sizeof(*td), SYNC_R);#endif if (td->status & TXSTS_EC) { IPRINTF(sc, ("%s: excess collisions\n", sc->wx_name)); ifp->if_collisions++; ifp->if_oerrors++; } if (td->status & TXSTS_LC) { IPRINTF(sc, ("%s: lost carrier\n", sc->wx_name)); ifp->if_oerrors++; } tmp = &sc->tbase[cidx]; DPRINTF(sc, ("%s: TXGC[%d] %p %d..%d done nact %d " "TDH %d\n", sc->wx_name, cidx, tmp->dptr, txpkt->sidx, txpkt->eidx, sc->tactive, tdh)); tmp->dptr = NULL; if (sc->tactive == 0) { printf("%s: nactive < 0?\n", sc->wx_name); } else { sc->tactive -= 1; } bzero(td, sizeof (*td)); } sc->tbsyf = txpkt->next; txpkt = sc->tbsyf; } if (sc->tactive < WX_MAX_TDESC - 1) { ifp->if_timer = 0; ifp->if_flags &= ~IFF_OACTIVE; } /* used SW LED to indicate transmission not active */ if (sc->tactive == 0 && sc->wx_mii) { WRITE_CSR(sc, WXREG_DCR, READ_CSR(sc, WXREG_DCR) & ~(WXDCR_SWDPIO0|WXDCR_SWDPIN0)); } WX_UNLOCK(sc);}static voidwx_watchdog(void *arg){ wx_softc_t *sc = arg; WX_LOCK(sc); if (sc->wx_needreinit) { WX_UNLOCK(sc); if (wx_init(sc) == 0) { WX_LOCK(sc); sc->wx_needreinit = 0; } else { WX_LOCK(sc); } } else { wx_gc(sc); wx_check_link(sc); } WX_UNLOCK(sc); /* * Schedule another timeout one second from now. */ TIMEOUT(sc, wx_watchdog, sc, hz);}/* * Stop and reinitialize the hardware */static voidwx_hw_stop(wx_softc_t *sc){ u_int32_t icr; DPRINTF(sc, ("%s: wx_hw_stop\n", sc->wx_name)); WX_DISABLE_INT(sc); if (sc->wx_idnrev < WX_WISEMAN_2_1) { wx_mwi_whackon(sc); } WRITE_CSR(sc, WXREG_DCR, WXDCR_RST); DELAY(20 * 1000); icr = READ_CSR(sc, WXREG_ICR); if (sc->wx_idnrev < WX_WISEMAN_2_1) { wx_mwi_unwhack(sc); }}static voidwx_set_addr(wx_softc_t *sc, int idx, u_int8_t *mac){ u_int32_t t0, t1; DPRINTF(sc, ("%s: wx_set_addr\n", sc->wx_name)); t0 = (mac[0]) | (mac[1] << 8) | (mac[2] << 16) | (mac[3] << 24); t1 = (mac[4] << 0) | (mac[5] << 8); t1 |= WX_RAL_AV; WRITE_CSR(sc, WXREG_RAL_LO(idx), t0); WRITE_CSR(sc, WXREG_RAL_HI(idx), t1);}static intwx_hw_initialize(wx_softc_t *sc){ int i; DPRINTF(sc, ("%s: wx_hw_initialize\n", sc->wx_name)); WRITE_CSR(sc, WXREG_VET, 0); for (i = 0; i < (WX_VLAN_TAB_SIZE << 2); i += 4) { WRITE_CSR(sc, (WXREG_VFTA + i), 0); } if (sc->wx_idnrev < WX_WISEMAN_2_1) { wx_mwi_whackon(sc); WRITE_CSR(sc, WXREG_RCTL, WXRCTL_RST); DELAY(5 * 1000); } /* * Load the first receiver address with our MAC address, * and load as many multicast addresses as can fit into * the receive address array. */ wx_set_addr(sc, 0, sc->wx_enaddr); for (i = 1; i <= sc->wx_nmca; i++) { if (i >= WX_RAL_TAB_SIZE) { break; } else { wx_set_addr(sc, i, sc->wx_mcaddr[i-1]); } } while (i < WX_RAL_TAB_SIZE) { WRITE_CSR(sc, WXREG_RAL_LO(i), 0); WRITE_CSR(sc, WXREG_RAL_HI(i), 0); i++; } if (sc->wx_idnrev < WX_WISEMAN_2_1) { WRITE_CSR(sc, WXREG_RCTL, 0); DELAY(1 * 1000); wx_mwi_unwhack(sc); } /* * Clear out the hashed multicast table array. */ for (i = 0; i < WX_MC_TAB_SIZE; i++) { WRITE_CSR(sc, WXREG_MTA + (sizeof (u_int32_t) * 4), 0); } if (IS_LIVENGOOD_CU(sc)) { /* * has a PHY - raise its reset line to make it operational */ u_int32_t tmp = READ_CSR(sc, WXREG_EXCT); tmp |= WXPHY_RESET_DIR4; WRITE_CSR(sc, WXREG_EXCT, tmp); DELAY(20*1000); tmp = READ_CSR(sc, WXREG_EXCT); tmp &= ~WXPHY_RESET4; WRITE_CSR(sc, WXREG_EXCT, tmp); DELAY(20*1000); tmp = READ_CSR(sc, WXREG_EXCT); tmp |= WXPHY_RESET4; WRITE_CSR(sc, WXREG_EXCT, tmp); DELAY(20*1000); } else if (IS_LIVENGOOD(sc)) { u_int16_t tew; /* * Handle link control */ WRITE_CSR(sc, WXREG_DCR, sc->wx_dcr | WXDCR_LRST); DELAY(50 * 1000); wx_read_eeprom(sc, &tew, WX_EEPROM_CTLR2_OFF, 1); tew = (tew & WX_EEPROM_CTLR2_SWDPIO) << WX_EEPROM_EXT_SHIFT; WRITE_CSR(sc, WXREG_EXCT, (u_int32_t)tew); } if (sc->wx_dcr & (WXDCR_RFCE|WXDCR_TFCE)) { WRITE_CSR(sc, WXREG_FCAL, FC_FRM_CONST_LO); WRITE_CSR(sc, WXREG_FCAH, FC_FRM_CONST_HI); WRITE_CSR(sc, WXREG_FCT, FC_TYP_CONST); } else { WRITE_CSR(sc, WXREG_FCAL, 0); WRITE_CSR(sc, WXREG_FCAH, 0); WRITE_CSR(sc, WXREG_FCT, 0); } WRITE_CSR(sc, WXREG_FLOW_XTIMER, WX_XTIMER_DFLT); if (IS_WISEMAN(sc)) { if (sc->wx_idnrev < WX_WISEMAN_2_1) { WRITE_CSR(sc, WXREG_FLOW_RCV_HI, 0); WRITE_CSR(sc, WXREG_FLOW_RCV_LO, 0); sc->wx_dcr &= ~(WXDCR_RFCE|WXDCR_TFCE); } else { WRITE_CSR(sc, WXREG_FLOW_RCV_HI, WX_RCV_FLOW_HI_DFLT); WRITE_CSR(sc, WXREG_FLOW_RCV_LO, WX_RCV_FLOW_LO_DFLT); } } else { WRITE_CSR(sc, WXREG_FLOW_RCV_HI_LIVENGOOD, WX_RCV_FLOW_HI_DFLT); WRITE_CSR(sc, WXREG_FLOW_RCV_LO_LIVENGOOD, WX_RCV_FLOW_LO_DFLT); } if (!IS_LIVENGOOD_CU(sc)) WRITE_CSR(sc, WXREG_XMIT_CFGW, WXTXCW_DEFAULT); WRITE_CSR(sc, WXREG_DCR, sc->wx_dcr); DELAY(50 * 1000); if (!IS_LIVENGOOD_CU(sc)) { /* * The pin stuff is all FM from the Linux driver. */ if ((READ_CSR(sc, WXREG_DCR) & WXDCR_SWDPIN1) == 0) { for (i = 0; i < (WX_LINK_UP_TIMEOUT/10); i++) { DELAY(10 * 1000); if (READ_CSR(sc, WXREG_DSR) & WXDSR_LU) { sc->linkup = 1; break; } } if (sc->linkup == 0) { sc->ane_failed = 1; wx_check_link(sc); } sc->ane_failed = 0; } else { printf("%s: SWDPIO1 did not clear- check for reversed " "or disconnected cable\n", sc->wx_name); /* but return okay anyway */ } } sc->wx_ienable = WXIENABLE_DEFAULT; return (0);}/* * Stop the interface. Cancels the statistics updater and resets the interface. */static voidwx_stop(wx_softc_t *sc){ txpkt_t *txp; rxpkt_t *rxp; struct ifnet *ifp = &sc->wx_if; DPRINTF(sc, ("%s: wx_stop\n", sc->wx_name)); /* * Cancel stats updater. */ UNTIMEOUT(wx_watchdog, sc, sc); /* * Reset the chip */ wx_hw_stop(sc); /* * Release any xmit buffers. */ for (txp = sc->tbase; txp && txp < &sc->tbase[WX_MAX_TDESC]; txp++) { if (txp->dptr) { m_free(txp->dptr); txp->dptr = NULL; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -