From dfe61cf102778c55f2f85cddfba57c2e1b13ff83 Mon Sep 17 00:00:00 2001 From: David Greenman Date: Fri, 1 Dec 1995 22:41:56 +0000 Subject: [PATCH] Fix minor bug that would cause the packet statistics updates to stop working under extremely rare circumstances. Also added some additional comments.. --- sys/dev/fxp/if_fxp.c | 99 +++++++++++++++++++++++++++++++++----------- sys/pci/if_fxp.c | 99 +++++++++++++++++++++++++++++++++----------- 2 files changed, 150 insertions(+), 48 deletions(-) diff --git a/sys/dev/fxp/if_fxp.c b/sys/dev/fxp/if_fxp.c index ff895e77e7e3..f8f7ac4e3ffa 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$ + * $Id: if_fxp.c,v 1.1 1995/11/28 23:55:20 davidg Exp $ */ /* @@ -74,18 +74,18 @@ #include #endif -#include -#include -#include -#include +#include /* for vtophys */ +#include /* for vtophys */ +#include /* for vtophys */ +#include /* for DELAY */ #include #include struct fxp_softc { - struct arpcom arpcom; - caddr_t bpf; - struct fxp_csr *csr; + struct arpcom arpcom; /* per-interface network data */ + caddr_t bpf; /* BPF token */ + struct fxp_csr *csr; /* control/status registers */ struct fxp_cb_tx *cbl_base; /* base of TxCB list */ struct fxp_cb_tx *cbl_first; /* first active TxCB in list */ struct fxp_cb_tx *cbl_last; /* last active TxCB in list */ @@ -181,6 +181,10 @@ DATA_SET(pcidevice_set, fxp_device); */ #define FXP_NRFABUFS 32 +/* + * Wait for the previous command to be accepted (but not necessarily + * completed). + */ static inline void fxp_scb_wait(csr) struct fxp_csr *csr; @@ -190,6 +194,9 @@ fxp_scb_wait(csr) while ((csr->scb_command & FXP_SCB_COMMAND_MASK) && --i); } +/* + * Return identification string if this is device is ours. + */ static char * fxp_probe(config_id, device_id) pcici_t config_id; @@ -222,6 +229,9 @@ fxp_attach(config_id, unit) s = splimp(); + /* + * Map control/status registers. + */ if (!pci_map_mem(config_id, FXP_PCI_MMBA, (vm_offset_t *)&sc->csr, &pbase)) { printf("fxp%d: couldn't map memory\n", unit); @@ -229,11 +239,14 @@ fxp_attach(config_id, unit) } /* - * Now that the CSR is mapped, issue a software reset. + * Issue a software reset. */ sc->csr->port = 0; DELAY(10); + /* + * Allocate our interrupt. + */ if (!pci_map_int(config_id, fxp_intr, sc, &net_imask)) { printf("fxp%d: couldn't map interrupt\n", unit); goto fail; @@ -249,6 +262,9 @@ fxp_attach(config_id, unit) goto malloc_fail; bzero(sc->fxp_stats, sizeof(struct fxp_stats)); + /* + * Pre-allocate our receive buffers. + */ for (i = 0; i < FXP_NRFABUFS; i++) { if (fxp_add_rfabuf(sc, NULL) != 0) { goto malloc_fail; @@ -270,6 +286,9 @@ fxp_attach(config_id, unit) printf("fxp%d: Ethernet address %s\n", unit, ether_sprintf(sc->arpcom.ac_enaddr)); + /* + * Attach the interface. + */ if_attach(ifp); #if NBPFILTER > 0 bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); @@ -409,6 +428,9 @@ fxp_start(ifp) ifp->if_flags |= IFF_OACTIVE; return; } + /* + * Grab a packet to transmit. + */ IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, mb_head); if (mb_head == NULL) { /* @@ -417,6 +439,9 @@ fxp_start(ifp) return; } + /* + * Get pointer to next available (unused) descriptor. + */ txp = sc->cbl_last->next; /* @@ -550,12 +575,19 @@ fxp_intr(arg) struct fxp_rfa *rfa; rcvloop: m = sc->rfa_headm; - rfa = (struct fxp_rfa *)(mtod(m, u_long) & ~(MCLBYTES - 1)); + rfa = (struct fxp_rfa *)m->m_ext.ext_buf; if (rfa->rfa_status & FXP_RFA_STATUS_C) { + /* + * 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_short total_len; @@ -589,8 +621,7 @@ fxp_intr(arg) ifp->if_ierrors++; fxp_scb_wait(csr); - csr->scb_general = vtophys(mtod(sc->rfa_headm, u_long) & - ~(MCLBYTES - 1)); + csr->scb_general = vtophys(sc->rfa_headm->m_ext.ext_buf); csr->scb_command = FXP_SCB_COMMAND_RU_START; } } @@ -599,6 +630,17 @@ fxp_intr(arg) return found; } +/* + * 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. + */ void fxp_stats_update(arg) void *arg; @@ -616,19 +658,24 @@ fxp_stats_update(arg) * around. Make sure we don't count the stats twice * however. */ - if (sc->csr->scb_command & FXP_SCB_COMMAND_MASK) { + if ((sc->csr->scb_command & FXP_SCB_COMMAND_MASK) == 0) { + /* + * Start another stats dump. By waiting for it to be + * accepted, we avoid having to do splhigh locking when + * writing scb_command in other parts of the driver. + */ + sc->csr->scb_command = FXP_SCB_COMMAND_CU_DUMPRESET; + fxp_scb_wait(sc); + } 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. + */ sp->tx_good = 0; sp->tx_total_collisions = 0; sp->rx_good = 0; - return; } - /* - * Start another stats dump. By waiting for it to be accepted, - * we avoid having to do splhigh locking when writing scb_command - * in other parts of the driver. - */ - sc->csr->scb_command = FXP_SCB_COMMAND_CU_DUMPRESET; - fxp_scb_wait(sc); /* * Schedule another timeout one second from now. */ @@ -830,7 +877,7 @@ fxp_init(unit) * Initialize receiver buffer area - RFA. */ fxp_scb_wait(csr); - csr->scb_general = vtophys(mtod(sc->rfa_headm, u_long) & ~(MCLBYTES - 1)); + csr->scb_general = vtophys(sc->rfa_headm->m_ext.ext_buf); csr->scb_command = FXP_SCB_COMMAND_RU_START; ifp->if_flags |= IFF_RUNNING; @@ -879,8 +926,12 @@ fxp_add_rfabuf(sc, oldm) rfa->actual_size = 0; rfa->size = MCLBYTES - sizeof(struct fxp_rfa); m->m_data += sizeof(struct fxp_rfa); + /* + * If there are other buffers already on the list, attach this + * one to the end by fixing up the tail to point to this one. + */ if (sc->rfa_headm != NULL) { - p_rfa = (struct fxp_rfa *) (mtod(sc->rfa_tailm, u_long) & ~(MCLBYTES - 1)); + p_rfa = (struct fxp_rfa *) sc->rfa_tailm->m_ext.ext_buf; sc->rfa_tailm->m_next = m; p_rfa->link_addr = vtophys(rfa); p_rfa->rfa_control &= ~FXP_RFA_CONTROL_EL; @@ -889,7 +940,7 @@ fxp_add_rfabuf(sc, oldm) } sc->rfa_tailm = m; - return m == oldm ? 1 : 0; + return (m == oldm); } static int diff --git a/sys/pci/if_fxp.c b/sys/pci/if_fxp.c index ff895e77e7e3..f8f7ac4e3ffa 100644 --- a/sys/pci/if_fxp.c +++ b/sys/pci/if_fxp.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: if_fxp.c,v 1.1 1995/11/28 23:55:20 davidg Exp $ */ /* @@ -74,18 +74,18 @@ #include #endif -#include -#include -#include -#include +#include /* for vtophys */ +#include /* for vtophys */ +#include /* for vtophys */ +#include /* for DELAY */ #include #include struct fxp_softc { - struct arpcom arpcom; - caddr_t bpf; - struct fxp_csr *csr; + struct arpcom arpcom; /* per-interface network data */ + caddr_t bpf; /* BPF token */ + struct fxp_csr *csr; /* control/status registers */ struct fxp_cb_tx *cbl_base; /* base of TxCB list */ struct fxp_cb_tx *cbl_first; /* first active TxCB in list */ struct fxp_cb_tx *cbl_last; /* last active TxCB in list */ @@ -181,6 +181,10 @@ DATA_SET(pcidevice_set, fxp_device); */ #define FXP_NRFABUFS 32 +/* + * Wait for the previous command to be accepted (but not necessarily + * completed). + */ static inline void fxp_scb_wait(csr) struct fxp_csr *csr; @@ -190,6 +194,9 @@ fxp_scb_wait(csr) while ((csr->scb_command & FXP_SCB_COMMAND_MASK) && --i); } +/* + * Return identification string if this is device is ours. + */ static char * fxp_probe(config_id, device_id) pcici_t config_id; @@ -222,6 +229,9 @@ fxp_attach(config_id, unit) s = splimp(); + /* + * Map control/status registers. + */ if (!pci_map_mem(config_id, FXP_PCI_MMBA, (vm_offset_t *)&sc->csr, &pbase)) { printf("fxp%d: couldn't map memory\n", unit); @@ -229,11 +239,14 @@ fxp_attach(config_id, unit) } /* - * Now that the CSR is mapped, issue a software reset. + * Issue a software reset. */ sc->csr->port = 0; DELAY(10); + /* + * Allocate our interrupt. + */ if (!pci_map_int(config_id, fxp_intr, sc, &net_imask)) { printf("fxp%d: couldn't map interrupt\n", unit); goto fail; @@ -249,6 +262,9 @@ fxp_attach(config_id, unit) goto malloc_fail; bzero(sc->fxp_stats, sizeof(struct fxp_stats)); + /* + * Pre-allocate our receive buffers. + */ for (i = 0; i < FXP_NRFABUFS; i++) { if (fxp_add_rfabuf(sc, NULL) != 0) { goto malloc_fail; @@ -270,6 +286,9 @@ fxp_attach(config_id, unit) printf("fxp%d: Ethernet address %s\n", unit, ether_sprintf(sc->arpcom.ac_enaddr)); + /* + * Attach the interface. + */ if_attach(ifp); #if NBPFILTER > 0 bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); @@ -409,6 +428,9 @@ fxp_start(ifp) ifp->if_flags |= IFF_OACTIVE; return; } + /* + * Grab a packet to transmit. + */ IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, mb_head); if (mb_head == NULL) { /* @@ -417,6 +439,9 @@ fxp_start(ifp) return; } + /* + * Get pointer to next available (unused) descriptor. + */ txp = sc->cbl_last->next; /* @@ -550,12 +575,19 @@ fxp_intr(arg) struct fxp_rfa *rfa; rcvloop: m = sc->rfa_headm; - rfa = (struct fxp_rfa *)(mtod(m, u_long) & ~(MCLBYTES - 1)); + rfa = (struct fxp_rfa *)m->m_ext.ext_buf; if (rfa->rfa_status & FXP_RFA_STATUS_C) { + /* + * 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_short total_len; @@ -589,8 +621,7 @@ fxp_intr(arg) ifp->if_ierrors++; fxp_scb_wait(csr); - csr->scb_general = vtophys(mtod(sc->rfa_headm, u_long) & - ~(MCLBYTES - 1)); + csr->scb_general = vtophys(sc->rfa_headm->m_ext.ext_buf); csr->scb_command = FXP_SCB_COMMAND_RU_START; } } @@ -599,6 +630,17 @@ fxp_intr(arg) return found; } +/* + * 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. + */ void fxp_stats_update(arg) void *arg; @@ -616,19 +658,24 @@ fxp_stats_update(arg) * around. Make sure we don't count the stats twice * however. */ - if (sc->csr->scb_command & FXP_SCB_COMMAND_MASK) { + if ((sc->csr->scb_command & FXP_SCB_COMMAND_MASK) == 0) { + /* + * Start another stats dump. By waiting for it to be + * accepted, we avoid having to do splhigh locking when + * writing scb_command in other parts of the driver. + */ + sc->csr->scb_command = FXP_SCB_COMMAND_CU_DUMPRESET; + fxp_scb_wait(sc); + } 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. + */ sp->tx_good = 0; sp->tx_total_collisions = 0; sp->rx_good = 0; - return; } - /* - * Start another stats dump. By waiting for it to be accepted, - * we avoid having to do splhigh locking when writing scb_command - * in other parts of the driver. - */ - sc->csr->scb_command = FXP_SCB_COMMAND_CU_DUMPRESET; - fxp_scb_wait(sc); /* * Schedule another timeout one second from now. */ @@ -830,7 +877,7 @@ fxp_init(unit) * Initialize receiver buffer area - RFA. */ fxp_scb_wait(csr); - csr->scb_general = vtophys(mtod(sc->rfa_headm, u_long) & ~(MCLBYTES - 1)); + csr->scb_general = vtophys(sc->rfa_headm->m_ext.ext_buf); csr->scb_command = FXP_SCB_COMMAND_RU_START; ifp->if_flags |= IFF_RUNNING; @@ -879,8 +926,12 @@ fxp_add_rfabuf(sc, oldm) rfa->actual_size = 0; rfa->size = MCLBYTES - sizeof(struct fxp_rfa); m->m_data += sizeof(struct fxp_rfa); + /* + * If there are other buffers already on the list, attach this + * one to the end by fixing up the tail to point to this one. + */ if (sc->rfa_headm != NULL) { - p_rfa = (struct fxp_rfa *) (mtod(sc->rfa_tailm, u_long) & ~(MCLBYTES - 1)); + p_rfa = (struct fxp_rfa *) sc->rfa_tailm->m_ext.ext_buf; sc->rfa_tailm->m_next = m; p_rfa->link_addr = vtophys(rfa); p_rfa->rfa_control &= ~FXP_RFA_CONTROL_EL; @@ -889,7 +940,7 @@ fxp_add_rfabuf(sc, oldm) } sc->rfa_tailm = m; - return m == oldm ? 1 : 0; + return (m == oldm); } static int