diff options
author | dg <dg@FreeBSD.org> | 1996-01-03 05:22:32 +0000 |
---|---|---|
committer | dg <dg@FreeBSD.org> | 1996-01-03 05:22:32 +0000 |
commit | b2c9e8d577ab3f9b22eca0db9b1caee4b82acd8d (patch) | |
tree | ef088c34f797a382d133a209cf6f42b2af87e669 /sys/dev/fxp | |
parent | 8fb6f5f3ee03fa4de50aec34bc05ff481c24e440 (diff) | |
download | FreeBSD-src-b2c9e8d577ab3f9b22eca0db9b1caee4b82acd8d.zip FreeBSD-src-b2c9e8d577ab3f9b22eca0db9b1caee4b82acd8d.tar.gz |
Reworked the stop/reset code to properly run-down allocated buffers and
made the code detect and handle wedged cards.
Diffstat (limited to 'sys/dev/fxp')
-rw-r--r-- | sys/dev/fxp/if_fxp.c | 111 |
1 files changed, 75 insertions, 36 deletions
diff --git a/sys/dev/fxp/if_fxp.c b/sys/dev/fxp/if_fxp.c index 8173363..6efb83b 100644 --- a/sys/dev/fxp/if_fxp.c +++ b/sys/dev/fxp/if_fxp.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: if_fxp.c,v 1.5 1995/12/07 12:47:35 davidg Exp $ + * $Id: if_fxp.c,v 1.6 1995/12/18 02:47:43 davidg Exp $ */ /* @@ -134,7 +134,7 @@ static u_char fxp_cb_config_template[] = { 0x0, 0x0 }; -static inline void fxp_scb_wait __P((struct fxp_csr *)); +static inline int fxp_scb_wait __P((struct fxp_csr *)); static char *fxp_probe __P((pcici_t, pcidi_t)); static void fxp_attach __P((pcici_t, int)); static int fxp_shutdown __P((struct kern_devconf *, int)); @@ -191,13 +191,14 @@ DATA_SET(pcidevice_set, fxp_device); * Wait for the previous command to be accepted (but not necessarily * completed). */ -static inline void +static inline int fxp_scb_wait(csr) struct fxp_csr *csr; { int i = 10000; while ((csr->scb_command & FXP_SCB_COMMAND_MASK) && --i); + return (i); } /* @@ -399,14 +400,7 @@ fxp_shutdown(kdc, force) { struct fxp_softc *sc = fxp_sc[kdc->kdc_unit]; - /* - * Cancel stats updater. - */ - untimeout(fxp_stats_update, sc); - /* - * Issue software reset. - */ - sc->csr->port = 0; + fxp_stop(sc); (void) dev_detach(kdc); return 0; @@ -518,10 +512,17 @@ tbdinit: sc->cbl_first = txp; } + if (!fxp_scb_wait(csr)) { + /* + * Hmmm, card has gone out to lunch + */ + fxp_init(ifp); + goto txloop; + } + /* * Resume transmission if suspended. */ - fxp_scb_wait(csr); csr->scb_command = FXP_SCB_COMMAND_CU_RESUME; #if NBPFILTER > 0 @@ -646,8 +647,7 @@ rcvloop: if (statack & FXP_SCB_STATACK_RNR) { struct fxp_csr *csr = sc->csr; - ifp->if_ierrors++; - fxp_scb_wait(csr); + (void) fxp_scb_wait(csr); csr->scb_general = vtophys(sc->rfa_headm->m_ext.ext_buf); csr->scb_command = FXP_SCB_COMMAND_RU_START; } @@ -679,11 +679,15 @@ fxp_stats_update(arg) ifp->if_opackets += sp->tx_good; ifp->if_collisions += sp->tx_total_collisions; ifp->if_ipackets += sp->rx_good; + ifp->if_ierrors += + sp->rx_crc_errors + + sp->rx_alignment_errors + + sp->rx_rnr_errors + + sp->rx_overrun_errors + + sp->rx_shortframes; /* - * If there is a pending command, don't wait for it to - * be accepted - we'll pick up the stats the next time - * around. Make sure we don't count the stats twice - * however. + * If there is no pending command, start another stats + * dump. Otherwise punt for now. */ if ((sc->csr->scb_command & FXP_SCB_COMMAND_MASK) == 0) { /* @@ -692,16 +696,22 @@ fxp_stats_update(arg) * writing scb_command in other parts of the driver. */ sc->csr->scb_command = FXP_SCB_COMMAND_CU_DUMPRESET; - fxp_scb_wait(sc->csr); + (void) fxp_scb_wait(sc->csr); } 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 pdate them. + * next timer event to update them. */ sp->tx_good = 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; + sp->rx_shortframes = 0;; } /* * Schedule another timeout one second from now. @@ -718,15 +728,50 @@ fxp_stop(sc) struct fxp_softc *sc; { struct ifnet *ifp = &sc->arpcom.ac_if; + struct fxp_cb_tx *txp; + int i; /* * Cancel stats updater. */ untimeout(fxp_stats_update, sc); + + /* + * Issue software reset + */ sc->csr->port = 0; DELAY(10); - ifp->if_flags &= ~IFF_RUNNING; + /* + * 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; + + /* + * 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!"); + } + } + + ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); + ifp->if_timer = 0; } /* @@ -756,17 +801,11 @@ fxp_init(ifp) struct fxp_csr *csr = sc->csr; int i, s, mcast, prm; - /* - * Cancel stats updater. - */ - untimeout(fxp_stats_update, sc); - s = splimp(); /* - * Issue software reset and wait 10us for the card to recover. + * Cancel any pending I/O */ - csr->port = 0; - DELAY(10); + fxp_stop(sc); prm = (ifp->if_flags & IFF_PROMISC) ? 1 : 0; sc->promisc_mode = prm; @@ -784,13 +823,13 @@ fxp_init(ifp) csr->scb_general = 0; csr->scb_command = FXP_SCB_COMMAND_CU_BASE; - fxp_scb_wait(csr); + (void) fxp_scb_wait(csr); csr->scb_command = FXP_SCB_COMMAND_RU_BASE; /* * Initialize base of dump-stats buffer. */ - fxp_scb_wait(csr); + (void) fxp_scb_wait(csr); csr->scb_general = vtophys(sc->fxp_stats); csr->scb_command = FXP_SCB_COMMAND_CU_DUMP_ADR; @@ -838,14 +877,14 @@ fxp_init(ifp) cbp->padding = 1; /* (do) pad short tx packets */ cbp->rcv_crc_xfer = 0; /* (don't) xfer CRC to host */ cbp->force_fdx = 0; /* (don't) force full duplex */ - cbp->fdx_pin_en = 0; /* (ignore) FDX# pin */ + cbp->fdx_pin_en = 1; /* (enable) FDX# pin */ cbp->multi_ia = 0; /* (don't) accept multiple IAs */ cbp->mc_all = mcast; /* accept all multicasts */ /* * Start the config command/DMA. */ - fxp_scb_wait(csr); + (void) fxp_scb_wait(csr); csr->scb_general = vtophys(cbp); csr->scb_command = FXP_SCB_COMMAND_CU_START; /* ...and wait for it to complete. */ @@ -865,7 +904,7 @@ fxp_init(ifp) /* * Start the IAS (Individual Address Setup) command/DMA. */ - fxp_scb_wait(csr); + (void) fxp_scb_wait(csr); csr->scb_command = FXP_SCB_COMMAND_CU_START; /* ...and wait for it to complete. */ while (!(cb_ias->cb_status & FXP_CB_STATUS_C)); @@ -891,13 +930,13 @@ fxp_init(ifp) sc->cbl_first = sc->cbl_last = txp; sc->tx_queued = 0; - fxp_scb_wait(csr); + (void) fxp_scb_wait(csr); csr->scb_command = FXP_SCB_COMMAND_CU_START; /* * Initialize receiver buffer area - RFA. */ - fxp_scb_wait(csr); + (void) fxp_scb_wait(csr); csr->scb_general = vtophys(sc->rfa_headm->m_ext.ext_buf); csr->scb_command = FXP_SCB_COMMAND_RU_START; |