?? if_fxp.c
字號:
txp = sc->cbl_last->next; /* * Go through each of the mbufs in the chain and initialize * the transmit buffer descriptors with the physical address * and size of the mbuf. */tbdinit: for (m = mb_head, segment = 0; m != NULL; m = m->m_next) { if (m->m_len != 0) { if (segment == FXP_NTXSEG) break; txp->tbd[segment].tb_addr = htole32(vtophys(mtod(m, vm_offset_t))); txp->tbd[segment].tb_size = htole32(m->m_len);#if defined(__mips__) pci_sync_cache(sc->sc_pc, mtod(m, vm_offset_t), m->m_len, SYNC_W);#endif segment++; } } if (m != NULL) { struct mbuf *mn; /* * We ran out of segments. We have to recopy this mbuf * chain first. Bail out if we can't get the new buffers. */ MGETHDR(mn, M_DONTWAIT, MT_DATA); if (mn == NULL) { m_freem(mb_head); break; } if (mb_head->m_pkthdr.len > MHLEN) { MCLGET(mn, M_DONTWAIT); if ((mn->m_flags & M_EXT) == 0) { m_freem(mn); m_freem(mb_head); break; } } m_copydata(mb_head, 0, mb_head->m_pkthdr.len, mtod(mn, caddr_t)); mn->m_pkthdr.len = mn->m_len = mb_head->m_pkthdr.len; m_freem(mb_head); mb_head = mn; goto tbdinit; } txp->tbd_number = segment; txp->mb_head = mb_head; txp->cb_status = htole16(0); if (sc->tx_queued != FXP_CXINT_THRESH - 1) { txp->cb_command = htole16(FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF | FXP_CB_COMMAND_S); } else { txp->cb_command = htole16(FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF | FXP_CB_COMMAND_S | FXP_CB_COMMAND_I); /* * Set a 5 second timer just in case we don't hear * from the card again. */ ifp->if_timer = 5; } txp->tx_threshold = tx_threshold; /* * Advance the end of list forward. */ sc->cbl_last->cb_command &= htole16(~FXP_CB_COMMAND_S); sc->cbl_last = txp; /* * Advance the beginning of the list forward if there are * no other packets queued (when nothing is queued, cbl_first * sits on the last TxCB that was sent out). */ if (sc->tx_queued == 0) sc->cbl_first = txp; sc->tx_queued++;#if NBPFILTER > 0 /* * Pass packet to bpf if there is a listener. */ if (ifp->if_bpf) bpf_mtap(FXP_BPFTAP_ARG(ifp), mb_head);#endif } /* * We're finished. If we added to the list, issue a RESUME to get DMA * going again if suspended. */ if (txp != NULL) { fxp_scb_wait(sc); CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_RESUME); }}/* * Process interface interrupts. */FXP_INTR_TYPEfxp_intr(arg) void *arg;{ struct fxp_softc *sc = arg; struct ifnet *ifp = &sc->sc_if; u_int8_t statack;#if defined(__NetBSD__) || defined(__OpenBSD__) int claimed = 0; /* * If the interface isn't running, don't try to * service the interrupt.. just ack it and bail. */ if ((ifp->if_flags & IFF_RUNNING) == 0) { statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK); if (statack) { claimed = 1; CSR_WRITE_1(sc, FXP_CSR_SCB_STATACK, statack); } return claimed; }#endif while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) {#if defined(__NetBSD__) || defined(__OpenBSD__) claimed = 1;#endif /* * First ACK all the interrupts in this pass. */ CSR_WRITE_1(sc, FXP_CSR_SCB_STATACK, statack); /* * Free any finished transmit mbuf chains. */ if (statack & FXP_SCB_STATACK_CXTNO||FXP_SCB_STATACK_CNA) { struct fxp_cb_tx *txp; for (txp = sc->cbl_first; sc->tx_queued && (txp->cb_status & htole16(FXP_CB_STATUS_C)) != 0; txp = txp->next) { if (txp->mb_head != NULL) { m_freem(txp->mb_head); txp->mb_head = NULL; } sc->tx_queued--; } sc->cbl_first = txp; ifp->if_timer = 0;#ifdef USE_FXP_MCAST if (sc->tx_queued == 0) { if (sc->need_mcsetup) fxp_mc_setup(sc); }#endif /* * Try to start more packets transmitting. */ if (ifp->if_snd.ifq_head != NULL) fxp_start(ifp); } //printf("transmit buf freed\n"); /* * Process receiver interrupts. If a no-resource (RNR) * condition exists, get whatever packets we can and * re-start the receiver. */ if (statack & (FXP_SCB_STATACK_FR | FXP_SCB_STATACK_RNR)) { struct mbuf *m; u_int8_t *rfap;rcvloop: //printf("recving a packet\n"); m = sc->rfa_headm; rfap = m->m_ext.ext_buf + RFA_ALIGNMENT_FUDGE;#if defined(__mips__) /* * Read uncached so we don't create any funny * cache coherency side effects. */ //printf("rfap=%x\n",rfap); if (*(u_int16_t *)(PHYS_TO_UNCACHED(vtophys(rfap)) + offsetof(struct fxp_rfa, rfa_status)) & htole16(FXP_RFA_STATUS_C)) {#else if (*(u_int16_t *)(rfap + offsetof(struct fxp_rfa, rfa_status)) & htole16(FXP_RFA_STATUS_C)) {#endif /* __mips__ */ //printf("packet ready for %x\n",rfap); /* * Remove first packet from the chain. */ sc->rfa_headm = m->m_next; m->m_next = NULL; /* * Add a new buffer to the receive chain. * If this fails, the old buffer is recycled * instead. */ if (fxp_add_rfabuf(sc, m) == 0) { struct ether_header *eh; u_int16_t total_len; total_len = (htole16(*(u_int16_t *)(rfap + offsetof(struct fxp_rfa, actual_size)))) & (MCLBYTES - 1); if (total_len < sizeof(struct ether_header)) { m_freem(m); goto rcvloop; } m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = total_len - sizeof(struct ether_header);#ifdef BADPCIBRIDGE m->m_data -= 2; bcopy(m->m_data + 2, m->m_data, total_len);#endif#ifdef GODSONEV1 { int i; if ((*(unsigned char* volatile)PHYS_TO_UNCACHED(vtophys(m->m_data+0)))!=0xff) { for(i=0;i<total_len;i+=32){ m->m_data[i]=*(unsigned char*)PHYS_TO_UNCACHED(vtophys(m->m_data+i));#ifdef BEBUG_DMA_FLUSH_CACHE printf("%x: %2x\n", (unsigned char*)PHYS_TO_UNCACHED(vtophys(m->m_data+i)),*(unsigned char*)PHYS_TO_UNCACHED(vtophys(m->m_data+i))); printf("%x: %2x\t%x,(%2x)\n", (unsigned int)&m->m_data[i],(unsigned int)(unsigned char)m->m_data[80], (unsigned char*)PHYS_TO_UNCACHED(vtophys(m->m_data+i)),*(unsigned char*)PHYS_TO_UNCACHED(vtophys(m->m_data+i)));#endif } } m->m_data[total_len-1]=*(unsigned char*)PHYS_TO_UNCACHED(vtophys(m->m_data+total_len-1)); }#endif eh = mtod(m, struct ether_header *);#if NBPFILTER > 0 if (ifp->if_bpf) bpf_tap(FXP_BPFTAP_ARG(ifp), mtod(m, caddr_t), total_len); #endif /* NBPFILTER > 0 */ m->m_data += sizeof(struct ether_header); //printf("ether input,size=%d\n",total_len); ether_input(ifp, eh, m); } else {#ifndef Pocono int i; for (i=0;i<100;i++) printf("HELP! fxp recycling rxbuf!\n");#endif } goto rcvloop; } if (statack & FXP_SCB_STATACK_RNR) { fxp_scb_wait(sc);/* XXXX MIPS: Flush not req. Already done when put on rfa_headm */ CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(sc->rfa_headm->m_ext.ext_buf) + RFA_ALIGNMENT_FUDGE); CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_START); } } }#if defined(__NetBSD__) || defined(__OpenBSD__) return (claimed);#endif}/* * Update packet in/out/collision statistics. The i82557 doesn't * allow you to access these counters without doing a fairly * expensive DMA to get _all_ of the statistics it maintains, so * we do this operation here only once per second. The statistics * counters in the kernel are updated from the previous dump-stats * DMA and then a new dump-stats DMA is started. The on-chip * counters are zeroed when the DMA completes. If we can't start * the DMA immediately, we don't wait - we just prepare to read * them again next time. */voidfxp_stats_update(arg) void *arg;{#ifdef USE_FXP_STATS struct fxp_softc *sc = arg; struct ifnet *ifp = &sc->sc_if; struct fxp_stats *sp = sc->fxp_stats; int s; ifp->if_opackets += sp->tx_good; ifp->if_collisions += sp->tx_total_collisions; if (sp->rx_good) { ifp->if_ipackets += sp->rx_good; sc->rx_idle_secs = 0; } else { sc->rx_idle_secs++; } ifp->if_ierrors += sp->rx_crc_errors + sp->rx_alignment_errors + sp->rx_rnr_errors + sp->rx_overrun_errors; /* * If any transmit underruns occured, bump up the transmit * threshold by another 512 bytes (64 * 8). */ if (sp->tx_underruns) { ifp->if_oerrors += sp->tx_underruns; if (tx_threshold < 192) tx_threshold += 64; } s = splimp(); /* * If we haven't received any packets in FXP_MAC_RX_IDLE seconds, * then assume the receiver has locked up and attempt to clear * the condition by reprogramming the multicast filter. This is * a work-around for a bug in the 82557 where the receiver locks * up if it gets certain types of garbage in the syncronization * bits prior to the packet header. This bug is supposed to only * occur in 10Mbps mode, but has been seen to occur in 100Mbps * mode as well (perhaps due to a 10/100 speed transition). */ if (sc->rx_idle_secs > FXP_MAX_RX_IDLE) { sc->rx_idle_secs = 0; fxp_mc_setup(sc); } /* * If there is no pending command, start another stats * dump. Otherwise punt for now. */ if (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) == 0) { /* * Start another stats dump. */ CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_DUMPRESET); } else { /* * A previous command is still waiting to be accepted. * Just zero our copy of the stats and wait for the * next timer event to update them. */ sp->tx_good = 0; sp->tx_underruns = 0; sp->tx_total_collisions = 0; sp->rx_good = 0; sp->rx_crc_errors = 0; sp->rx_alignment_errors = 0; sp->rx_rnr_errors = 0; sp->rx_overrun_errors = 0; } /* Tick the MII clock. */ mii_tick(&sc->sc_mii); splx(s); /* * Schedule another timeout one second from now. */ timeout(fxp_stats_update, sc, hz);#endif}/* * Stop the interface. Cancels the statistics updater and resets * the interface. */voidfxp_stop(sc, drain) struct fxp_softc *sc; int drain;{ struct ifnet *ifp = &sc->sc_if; struct fxp_cb_tx *txp; int i; /* * Turn down interface (done early to avoid bad interactions * between panics, shutdown hooks, and the watchdog timer) */ ifp->if_timer = 0; ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);#ifdef USE_FXP_STATS /* * Cancel stats updater. */ untimeout(fxp_stats_update, sc);#endif /* * Issue software reset */ CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET); DELAY(10); /* * Release any xmit buffers. */ for (txp = sc->cbl_first; txp != NULL && txp->mb_head != NULL; txp = txp->next) { m_freem(txp->mb_head); txp->mb_head = NULL; } sc->tx_queued = 0; if (drain) { /* * Free all the receive buffers then reallocate/reinitialize */ if (sc->rfa_headm != NULL) m_freem(sc->rfa_headm); sc->rfa_headm = NULL; sc->rfa_tailm = NULL; for (i = 0; i < FXP_NRFABUFS; i++) { if (fxp_add_rfabuf(sc, NULL) != 0) { /* * This "can't happen" - we're at splimp() * and we just freed all the buffers we need * above. */ panic("fxp_stop: no buffers!"); } } }}/* * Watchdog/transmission transmit timeout handler. Called when a * transmission is started on the interface, but no interrupt is * received before the timeout. This usually indicates that the * card has wedged for some reason. */voidfxp_watchdog(ifp) struct ifnet *ifp;{ struct fxp_softc *sc = ifp->if_softc; int s; log(LOG_ERR, FXP_FORMAT ": device timeout\n", FXP_ARGS(sc)); ifp->if_oerrors++; if (fxp_init(sc) != 0) { ifp->if_timer = FXP_DELAY_BEFORE_REINIT; return; } /* Empty transmit queue */ s = splimp(); /* Protect Q-handling in fxp_start */ if (ifp->if_snd.ifq_head != NULL) { fxp_start(ifp); } splx(s);}intfxp_init(xsc) void *xsc;{ struct fxp_softc *sc = xsc; struct ifnet *ifp = &sc->sc_if; struct fxp_cb_config *cbp; struct fxp_cb_ias *cb_ias; struct fxp_cb_tx *txp; int i, s, prm; s = splimp(); /* * Cancel any pending I/O */ fxp_stop(sc, 0); prm = (ifp->if_flags & IFF_PROMISC) ? 1 : 0; /* * Initialize base of CBL and RFA memory. Loading with zero * sets it up for regular linear addressing. */ printf("IO write loop test..\n"); for(i=0;i<10000;i++) { CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, 0); CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_BASE); fxp_scb_wait(sc); CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_BASE); } printf("IO write loop test done\n"); /* * Initialize base of dump-stats buffer. */ fxp_scb_wait(sc); CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(sc->fxp_stats)); CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_DUMP_ADR); /* * We temporarily use memory that contains the TxCB list to * construct the config CB. The TxCB list memory is rebuilt * later. */ cbp = (struct fxp_cb_config *) sc->cbl_base; /* * This bcopy is kind of disgusting, but there are a bunch of must be
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -