diff options
-rw-r--r-- | sys/dev/pci/if_fxp.c | 454 | ||||
-rw-r--r-- | sys/dev/pci/if_fxpreg.h | 85 | ||||
-rw-r--r-- | sys/dev/pci/if_fxpvar.h | 6 |
3 files changed, 353 insertions, 192 deletions
diff --git a/sys/dev/pci/if_fxp.c b/sys/dev/pci/if_fxp.c index 302ba4164a4..d7a9e4af1fe 100644 --- a/sys/dev/pci/if_fxp.c +++ b/sys/dev/pci/if_fxp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_fxp.c,v 1.12 1998/05/26 07:22:13 deraadt Exp $ */ +/* $OpenBSD: if_fxp.c,v 1.13 1998/07/02 21:15:45 downsj Exp $ */ /* $NetBSD: if_fxp.c,v 1.2 1997/06/05 02:01:55 thorpej Exp $ */ /* @@ -180,8 +180,7 @@ static u_char fxp_cb_config_template[] = { 0xf3, /* 18 */ 0x0, /* 19 */ 0x3f, /* 20 */ - 0x5, /* 21 */ - 0x0, 0x0 + 0x5 /* 21 */ }; static inline void fxp_scb_wait __P((struct fxp_softc *)); @@ -200,6 +199,7 @@ static void fxp_read_eeprom __P((struct fxp_softc *, u_int16_t *, static int fxp_attach_common __P((struct fxp_softc *, u_int8_t *)); void fxp_stats_update __P((void *)); +void fxp_mc_setup __P((struct fxp_softc *)); /* * Set initial transmit threshold at 64 (512 bytes). This is @@ -221,21 +221,18 @@ static int tx_threshold = 64; #define FXP_TXCB_MASK (FXP_NTXCB - 1) /* - * Number of DMA segments in a TxCB. Note that this is carefully - * chosen to make the total struct size an even power of two. It's - * critical that no TxCB be split across a page boundry since - * no attempt is made to allocate physically contiguous memory. - * - * XXX - don't forget to change the hard-coded constant in the - * fxp_cb_tx struct (defined in if_fxpreg.h), too! + * Number of receive frame area buffers. These are large so chose + * wisely. */ -#define FXP_NTXSEG 29 +#define FXP_NRFABUFS 64 /* - * Number of receive frame area buffers. These are large so chose - * wisely. + * Maximum number of seconds that the receiver can be idle before we + * assume it's dead and attempt to reset it by reprogramming the + * multicast filter. This is part of a work-around for a bug in the + * NIC. See fxp_stats_update(). */ -#define FXP_NRFABUFS 32 +#define FXP_MAX_RX_IDLE 15 /* * Wait for the previous command to be accepted (but not necessarily @@ -247,8 +244,7 @@ fxp_scb_wait(sc) { int i = 10000; - while ((CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) & FXP_SCB_COMMAND_MASK) - && --i); + while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i); } /************************************************************* @@ -396,6 +392,10 @@ fxp_attach(parent, self, aux) * Attach the interface. */ if_attach(ifp); + /* + * Let the system queue as many packets as we have TX descriptors. + */ + ifp->if_snd.ifq_maxlen = FXP_NTXCB; #ifdef __NetBSD__ ether_ifattach(ifp, enaddr); #else @@ -576,6 +576,10 @@ fxp_attach(config_id, unit) * Attach the interface. */ if_attach(ifp); + /* + * Let the system queue as many packets as we have TX descriptors. + */ + ifp->if_snd.ifq_maxlen = FXP_NTXCB; ether_ifattach(ifp); #if NBPFILTER > 0 bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); @@ -642,6 +646,10 @@ fxp_attach_common(sc, enaddr) goto fail; bzero(sc->fxp_stats, sizeof(struct fxp_stats)); + sc->mcsp = malloc(sizeof(struct fxp_cb_mcs), M_DEVBUF, M_NOWAIT); + if (sc->mcsp == NULL) + goto fail; + /* * Pre-allocate our receive buffers. */ @@ -671,6 +679,8 @@ fxp_attach_common(sc, enaddr) free(sc->cbl_base, M_DEVBUF); if (sc->fxp_stats) free(sc->fxp_stats, M_DEVBUF); + if (sc->mcsp) + free(sc->mcsp, M_DEVBUF); /* frees entire chain */ if (sc->rfa_headm) m_freem(sc->rfa_headm); @@ -758,130 +768,125 @@ fxp_start(ifp) { struct fxp_softc *sc = ifp->if_softc; struct fxp_cb_tx *txp; - struct mbuf *m, *mb_head; - int segment, first = 1; -txloop: /* - * See if we're all filled up with buffers to transmit. + * See if we need to suspend xmit until the multicast filter + * has been reprogrammed (which can only be done at the head + * of the command chain). */ - if (sc->tx_queued >= FXP_NTXCB) + if (sc->need_mcsetup) return; + txp = NULL; + /* - * Grab a packet to transmit. + * We're finished if there is nothing more to add to the list or if + * we're all filled up with buffers to transmit. */ - IF_DEQUEUE(&ifp->if_snd, mb_head); - if (mb_head == NULL) { + while (ifp->if_snd.ifq_head != NULL && sc->tx_queued < FXP_NTXCB) { + struct mbuf *m, *mb_head; + int segment; + /* - * No more packets to send. + * Grab a packet to transmit. */ - return; - } - - /* - * Get pointer to next available (unused) descriptor. - */ - txp = sc->cbl_last->next; + IF_DEQUEUE(&ifp->if_snd, mb_head); - /* - * Go through each of the mbufs in the chain and initialize - * the transmit buffers 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 = - vtophys(mtod(m, vm_offset_t)); - txp->tbd[segment].tb_size = m->m_len; - segment++; - } - } - if (m != NULL) { - struct mbuf *mn; + /* + * Get pointer to next available tx desc. + */ + txp = sc->cbl_last->next; /* - * We ran out of segments. We have to recopy this mbuf - * chain first. + * Go through each of the mbufs in the chain and initialize + * the transmit buffer descriptors with the physical address + * and size of the mbuf. */ - MGETHDR(mn, M_DONTWAIT, MT_DATA); - if (mn == NULL) { - m_freem(mb_head); - return; +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 = + vtophys(mtod(m, vm_offset_t)); + txp->tbd[segment].tb_size = m->m_len; + segment++; + } } - if (mb_head->m_pkthdr.len > MHLEN) { - MCLGET(mn, M_DONTWAIT); - if ((mn->m_flags & M_EXT) == 0) { - m_freem(mn); + 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); - return; + 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; } - 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; - /* - * Finish the initialization of this TxCB. - */ - txp->cb_status = 0; - txp->cb_command = - FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF | FXP_CB_COMMAND_S; - txp->tx_threshold = tx_threshold; + txp->tbd_number = segment; + txp->mb_head = mb_head; + txp->cb_status = 0; + txp->cb_command = + FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF | FXP_CB_COMMAND_S; + txp->tx_threshold = tx_threshold; - /* - * Advance the end-of-list forward. - */ - sc->cbl_last->cb_command &= ~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++; + /* + * Advance the end of list forward. + */ + sc->cbl_last->cb_command &= ~FXP_CB_COMMAND_S; + sc->cbl_last = txp; - /* - * Only need to wait prior to the first resume command. - */ - if (first) { - first--; - fxp_scb_wait(sc); - } + /* + * 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; - /* - * Resume transmission if suspended. - */ - CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_RESUME); + 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); + /* + * Pass packet to bpf if there is a listener. + */ + if (ifp->if_bpf) + bpf_mtap(FXP_BPFTAP_ARG(ifp), mb_head); #endif + } + /* - * Set a 5 second timer just in case we don't hear from the - * card again. + * We're finished. If we added to the list, issue a RESUME to get DMA + * going again if suspended. */ - ifp->if_timer = 5; + if (txp != NULL) { + fxp_scb_wait(sc); + CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_RESUME); - goto txloop; + /* + * Set a 5 second timer just in case we don't hear from the + * card again. + */ + ifp->if_timer = 5; + } } /* @@ -908,32 +913,6 @@ fxp_intr(arg) CSR_WRITE_1(sc, FXP_CSR_SCB_STATACK, statack); /* - * Free any finished transmit mbuf chains. - */ - if (statack & FXP_SCB_STATACK_CNA) { - struct fxp_cb_tx *txp; - - for (txp = sc->cbl_first; - (txp->cb_status & 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--; - } - if (txp->cb_command & FXP_CB_COMMAND_S) - break; - } - sc->cbl_first = txp; - /* - * Clear watchdog timer. It may or may not be set - * again in fxp_start(). - */ - ifp->if_timer = 0; - if (ifp->if_snd.ifq_head != NULL) - fxp_start(ifp); - } - /* * Process receiver interrupts. If a no-resource (RNR) * condition exists, get whatever packets we can and * re-start the receiver. @@ -1009,6 +988,33 @@ rcvloop: FXP_SCB_COMMAND_RU_START); } } + /* + * Free any finished transmit mbuf chains. + */ + if (statack & FXP_SCB_STATACK_CNA) { + struct fxp_cb_tx *txp; + + for (txp = sc->cbl_first; sc->tx_queued && + (txp->cb_status & 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; + if (sc->tx_queued == 0) { + ifp->if_timer = 0; + if (sc->need_mcsetup) + fxp_mc_setup(sc); + } + /* + * Try to start more packets transmitting. + */ + if (ifp->if_snd.ifq_head != NULL) + fxp_start(ifp); + } } #if defined(__NetBSD__) || defined(__OpenBSD__) return (claimed); @@ -1033,10 +1039,16 @@ fxp_stats_update(arg) 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; - ifp->if_ipackets += sp->rx_good; + 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 + @@ -1051,20 +1063,31 @@ fxp_stats_update(arg) 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) & - FXP_SCB_COMMAND_MASK) == 0) { + if (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) == 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. + * Start another stats dump. */ CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_DUMPRESET); - fxp_scb_wait(sc); } else { /* * A previous command is still waiting to be accepted. @@ -1081,6 +1104,7 @@ fxp_stats_update(arg) sp->rx_rnr_errors = 0; sp->rx_overrun_errors = 0; } + splx(s); /* * Schedule another timeout one second from now. */ @@ -1169,7 +1193,7 @@ fxp_init(xsc) struct fxp_cb_config *cbp; struct fxp_cb_ias *cb_ias; struct fxp_cb_tx *txp; - int i, s, mcast, prm; + int i, s, prm; s = splimp(); /* @@ -1179,12 +1203,6 @@ fxp_init(xsc) prm = (ifp->if_flags & IFF_PROMISC) ? 1 : 0; sc->promisc_mode = prm; - /* - * Sleeze out here and enable reception of all multicasts if - * multicasts are enabled. Ideally, we'd program the multicast - * address filter to only accept specific multicasts. - */ - mcast = (ifp->if_flags & (IFF_MULTICAST|IFF_ALLMULTI)) ? 1 : 0; /* * Initialize base of CBL and RFA memory. Loading with zero @@ -1215,7 +1233,8 @@ fxp_init(xsc) * zero and must be one bits in this structure and this is the easiest * way to initialize them all to proper values. */ - bcopy(fxp_cb_config_template, cbp, sizeof(struct fxp_cb_config)); + bcopy(fxp_cb_config_template, (void *)&cbp->cb_status, + sizeof(fxp_cb_config_template)); cbp->cb_status = 0; cbp->cb_command = FXP_CB_COMMAND_CONFIG | FXP_CB_COMMAND_EL; @@ -1249,13 +1268,13 @@ fxp_init(xsc) cbp->force_fdx = 0; /* (don't) force full duplex */ cbp->fdx_pin_en = 1; /* (enable) FDX# pin */ cbp->multi_ia = 0; /* (don't) accept multiple IAs */ - cbp->mc_all = mcast; /* accept all multicasts */ + cbp->mc_all = sc->all_mcasts;/* accept all multicasts */ /* * Start the config command/DMA. */ fxp_scb_wait(sc); - CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(cbp)); + CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&cbp->cb_status)); CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START); /* ...and wait for it to complete. */ while (!(cbp->cb_status & FXP_CB_STATUS_C)); @@ -1292,17 +1311,17 @@ fxp_init(xsc) for (i = 0; i < FXP_NTXCB; i++) { txp[i].cb_status = FXP_CB_STATUS_C | FXP_CB_STATUS_OK; txp[i].cb_command = FXP_CB_COMMAND_NOP; - txp[i].link_addr = vtophys(&txp[(i + 1) & FXP_TXCB_MASK]); + txp[i].link_addr = vtophys(&txp[(i + 1) & FXP_TXCB_MASK].cb_status); txp[i].tbd_array_addr = vtophys(&txp[i].tbd[0]); txp[i].next = &txp[(i + 1) & FXP_TXCB_MASK]; } /* - * Set the stop flag on the first TxCB and start the control + * Set the suspend flag on the first TxCB and start the control * unit. It will execute the NOP and then suspend. */ txp->cb_command = FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S; sc->cbl_first = sc->cbl_last = txp; - sc->tx_queued = 0; + sc->tx_queued = 1; fxp_scb_wait(sc); CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START); @@ -1388,7 +1407,7 @@ fxp_init(xsc) * Add a buffer to the end of the RFA buffer list. * Return 0 if successful, 1 for failure. A failure results in * adding the 'oldm' (if non-NULL) on to the end of the list - - * tossing out it's old contents and recycling it. + * tossing out its old contents and recycling it. * The RFA struct is stuck at the beginning of mbuf cluster and the * data pointer is fixed up to point just past it. */ @@ -1531,6 +1550,7 @@ fxp_ioctl(ifp, command, data) break; case SIOCSIFFLAGS: + sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0; /* * If interface is marked up and not running, then start it. @@ -1548,6 +1568,7 @@ fxp_ioctl(ifp, command, data) case SIOCADDMULTI: case SIOCDELMULTI: + sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0; #if defined(__NetBSD__) || defined(__OpenBSD__) { struct ifreq *ifr = (struct ifreq *) data; @@ -1567,7 +1588,14 @@ fxp_ioctl(ifp, command, data) * Multicast list has changed; set the hardware * filter accordingly. */ - fxp_init(sc); + if (!sc->all_mcasts) + fxp_mc_setup(sc); + /* + * fxp_mc_setup() can turn on all_mcasts if we run + * out of space, so check it again rather than else {}. + */ + if (sc->all_mcasts) + fxp_init(sc); error = 0; } } @@ -1587,3 +1615,107 @@ fxp_ioctl(ifp, command, data) (void) splx(s); return (error); } + +/* + * Program the multicast filter. + * + * We have an artificial restriction that the multicast setup command + * must be the first command in the chain, so we take steps to ensure + * that. By requiring this, it allows us to keep the performance of + * the pre-initialized command ring (esp. link pointers) by not actually + * inserting the mcsetup command in the ring - i.e. its link pointer + * points to the TxCB ring, but the mcsetup descriptor itself is not part + * of it. We then can do 'CU_START' on the mcsetup descriptor and have it + * lead into the regular TxCB ring when it completes. + * + * This function must be called at splimp. + */ +void +fxp_mc_setup(sc) + struct fxp_softc *sc; +{ + struct fxp_cb_mcs *mcsp = sc->mcsp; + struct ifnet *ifp = &sc->sc_if; +#if defined(__OpenBSD__) + struct ether_multistep step; + struct ether_multi *enm; +#else + struct ifmultiaddr *ifma; +#endif + int nmcasts; + + if (sc->tx_queued) { + sc->need_mcsetup = 1; + return; + } + sc->need_mcsetup = 0; + + /* + * Initialize multicast setup descriptor. + */ + mcsp->next = sc->cbl_base; + mcsp->mb_head = NULL; + mcsp->cb_status = 0; + mcsp->cb_command = FXP_CB_COMMAND_MCAS | FXP_CB_COMMAND_S; + mcsp->link_addr = vtophys(&sc->cbl_base->cb_status); + + nmcasts = 0; + if (!sc->all_mcasts) { +#if defined(__OpenBSD__) + ETHER_FIRST_MULTI(step, &sc->arpcom, enm); + while (enm != NULL) { + if (nmcasts >= MAXMCADDR) { + sc->all_mcasts = 1; + nmcasts = 0; + break; + } + + /* Punt on ranges. */ + if (bcmp(enm->enm_addrlo, enm->enm_addrhi, + sizeof(enm->enm_addrlo)) != 0) { + sc->all_mcasts = 1; + nmcasts = 0; + break; + } + bcopy(enm->enm_addrlo, + (void *) &sc->mcsp->mc_addr[nmcasts][0], 6); + nmcasts++; + ETHER_NEXT_MULTI(step, enm); + } +#else + for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; + ifma = ifma->ifma_link.le_next) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + if (nmcasts >= MAXMCADDR) { + sc->all_mcasts = 1; + nmcasts = 0; + break; + } + bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), + (void *) &sc->mcsp->mc_addr[nmcasts][0], 6); + nmcasts++; + } +#endif + } + mcsp->mc_cnt = nmcasts * 6; + sc->cbl_first = sc->cbl_last = (struct fxp_cb_tx *) mcsp; + sc->tx_queued = 1; + + /* + * Wait until command unit is not active. This should never + * be the case when nothing is queued, but make sure anyway. + */ + while ((CSR_READ_1(sc, FXP_CSR_SCB_RUSCUS) >> 6) == + FXP_SCB_CUS_ACTIVE) ; + + /* + * Start the multicast setup command. + */ + fxp_scb_wait(sc); + CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&mcsp->cb_status)); + CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START); + + ifp->if_timer = 5; + return; +} diff --git a/sys/dev/pci/if_fxpreg.h b/sys/dev/pci/if_fxpreg.h index 8eb90e8a8f9..38a2ac5fe2e 100644 --- a/sys/dev/pci/if_fxpreg.h +++ b/sys/dev/pci/if_fxpreg.h @@ -1,5 +1,4 @@ -/* $OpenBSD: if_fxpreg.h,v 1.4 1998/03/10 21:37:45 deraadt Exp $ */ -/* $NetBSD: if_fxpreg.h,v 1.2 1997/06/05 02:01:57 thorpej Exp $ */ +/* $OpenBSD: if_fxpreg.h,v 1.5 1998/07/02 21:15:46 downsj Exp $ */ /* * Copyright (c) 1995, David Greenman @@ -27,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * Id: if_fxpreg.h,v 1.8 1997/03/21 08:00:13 davidg Exp + * $FreeBSD: if_fxpreg.h,v 1.13 1998/06/08 09:47:46 bde Exp $ */ #define FXP_VENDORID_INTEL 0x8086 @@ -81,7 +80,6 @@ #define FXP_SCB_STATACK_FR 0x40 #define FXP_SCB_STATACK_CXTNO 0x80 -#define FXP_SCB_COMMAND_MASK 0xff #define FXP_SCB_COMMAND_CU_NOP 0x00 #define FXP_SCB_COMMAND_CU_START 0x10 #define FXP_SCB_COMMAND_CU_RESUME 0x20 @@ -102,11 +100,13 @@ * Command block definitions */ struct fxp_cb_nop { + void *fill[2]; volatile u_int16_t cb_status; volatile u_int16_t cb_command; volatile u_int32_t link_addr; }; struct fxp_cb_ias { + void *fill[2]; volatile u_int16_t cb_status; volatile u_int16_t cb_command; volatile u_int32_t link_addr; @@ -114,69 +114,96 @@ struct fxp_cb_ias { }; /* I hate bit-fields :-( */ struct fxp_cb_config { + void *fill[2]; volatile u_int16_t cb_status; volatile u_int16_t cb_command; volatile u_int32_t link_addr; - volatile u_int8_t byte_count:6, + volatile u_int byte_count:6, :2; - volatile u_int8_t rx_fifo_limit:4, + volatile u_int rx_fifo_limit:4, tx_fifo_limit:3, :1; volatile u_int8_t adaptive_ifs; - volatile u_int8_t :8; - volatile u_int8_t rx_dma_bytecount:7, + volatile u_int :8; + volatile u_int rx_dma_bytecount:7, :1; - volatile u_int8_t tx_dma_bytecount:7, + volatile u_int tx_dma_bytecount:7, dma_bce:1; - volatile u_int8_t late_scb:1, + volatile u_int late_scb:1, :1, tno_int:1, ci_int:1, :3, save_bf:1; - volatile u_int8_t disc_short_rx:1, + volatile u_int disc_short_rx:1, underrun_retry:2, :5; - volatile u_int8_t mediatype:1, + volatile u_int mediatype:1, :7; - volatile u_int8_t :8; - volatile u_int8_t :3, + volatile u_int :8; + volatile u_int :3, nsai:1, preamble_length:2, loopback:2; - volatile u_int8_t linear_priority:3, + volatile u_int linear_priority:3, :5; - volatile u_int8_t linear_pri_mode:1, + volatile u_int linear_pri_mode:1, :3, interfrm_spacing:4; - volatile u_int8_t :8; - volatile u_int8_t :8; - volatile u_int8_t promiscuous:1, + volatile u_int :8; + volatile u_int :8; + volatile u_int promiscuous:1, bcast_disable:1, :5, crscdt:1; - volatile u_int8_t :8; - volatile u_int8_t :8; - volatile u_int8_t stripping:1, + volatile u_int :8; + volatile u_int :8; + volatile u_int stripping:1, padding:1, rcv_crc_xfer:1, :5; - volatile u_int8_t :6, + volatile u_int :6, force_fdx:1, fdx_pin_en:1; - volatile u_int8_t :6, + volatile u_int :6, multi_ia:1, :1; - volatile u_int8_t :3, + volatile u_int :3, mc_all:1, :4; }; + +#define MAXMCADDR 80 +struct fxp_cb_mcs { + struct fxp_cb_tx *next; + struct mbuf *mb_head; + volatile u_int16_t cb_status; + volatile u_int16_t cb_command; + volatile u_int32_t link_addr; + volatile u_int16_t mc_cnt; + volatile u_int8_t mc_addr[MAXMCADDR][6]; +}; + +/* + * Number of DMA segments in a TxCB. Note that this is carefully + * chosen to make the total struct size an even power of two. It's + * critical that no TxCB be split across a page boundry since + * no attempt is made to allocate physically contiguous memory. + * + */ +#ifdef __alpha__ /* XXX - should be conditional on pointer size */ +#define FXP_NTXSEG 28 +#else +#define FXP_NTXSEG 29 +#endif + struct fxp_tbd { volatile u_int32_t tb_addr; volatile u_int32_t tb_size; }; - struct fxp_cb_tx { + struct fxp_cb_tx *next; + struct mbuf *mb_head; volatile u_int16_t cb_status; volatile u_int16_t cb_command; volatile u_int32_t link_addr; @@ -187,9 +214,7 @@ struct fxp_cb_tx { /* * The following isn't actually part of the TxCB. */ - volatile struct fxp_tbd tbd[29]; - struct mbuf *mb_head; - struct fxp_cb_tx *next; + volatile struct fxp_tbd tbd[FXP_NTXSEG]; }; /* @@ -203,7 +228,7 @@ struct fxp_cb_tx { #define FXP_CB_COMMAND_NOP 0x0 #define FXP_CB_COMMAND_IAS 0x1 #define FXP_CB_COMMAND_CONFIG 0x2 -#define FXP_CB_COMMAND_MAS 0x3 +#define FXP_CB_COMMAND_MCAS 0x3 #define FXP_CB_COMMAND_XMIT 0x4 #define FXP_CB_COMMAND_RESRV 0x5 #define FXP_CB_COMMAND_DUMP 0x6 diff --git a/sys/dev/pci/if_fxpvar.h b/sys/dev/pci/if_fxpvar.h index 990fd58fcdb..6cc50921dce 100644 --- a/sys/dev/pci/if_fxpvar.h +++ b/sys/dev/pci/if_fxpvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_fxpvar.h,v 1.2 1997/07/06 16:05:03 niklas Exp $ */ +/* $OpenBSD: if_fxpvar.h,v 1.3 1998/07/02 21:15:47 downsj Exp $ */ /* $NetBSD: if_fxpvar.h,v 1.1 1997/06/05 02:01:58 thorpej Exp $ */ /* @@ -59,7 +59,11 @@ struct fxp_softc { struct mbuf *rfa_headm; /* first mbuf in receive frame area */ struct mbuf *rfa_tailm; /* last mbuf in receive frame area */ struct fxp_stats *fxp_stats; /* Pointer to interface stats */ + struct fxp_cb_mcs *mcsp; /* Pointer to mcast setup descriptor */ + int all_mcasts; /* receive all multicasts */ + int need_mcsetup; /* multicast filter needs programming */ int tx_queued; /* # of active TxCB's */ + int rx_idle_secs; /* # of seconds RX has been idle */ int promisc_mode; /* promiscuous mode enabled */ int phy_primary_addr; /* address of primary PHY */ int phy_primary_device; /* device type of primary PHY */ |