diff options
author | Jason Downs <downsj@cvs.openbsd.org> | 1998-08-21 20:29:14 +0000 |
---|---|---|
committer | Jason Downs <downsj@cvs.openbsd.org> | 1998-08-21 20:29:14 +0000 |
commit | 25791729ee175a0d43c086c9a3906a780c9fe33a (patch) | |
tree | 44425bbfd4247763068b2fda2d65e3f46890d8c2 /sys/dev/pci/if_fxp.c | |
parent | 0837d6e5a8986e9a59fdd0c871b9f9604b132b05 (diff) |
Recent FreeBSD changes and a bug fix.
Diffstat (limited to 'sys/dev/pci/if_fxp.c')
-rw-r--r-- | sys/dev/pci/if_fxp.c | 157 |
1 files changed, 107 insertions, 50 deletions
diff --git a/sys/dev/pci/if_fxp.c b/sys/dev/pci/if_fxp.c index d7a9e4af1fe..7a305eddbab 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.13 1998/07/02 21:15:45 downsj Exp $ */ +/* $OpenBSD: if_fxp.c,v 1.14 1998/08/21 20:29:10 downsj Exp $ */ /* $NetBSD: if_fxp.c,v 1.2 1997/06/05 02:01:55 thorpej Exp $ */ /* @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * Id: if_fxp.c,v 1.34 1997/04/23 01:44:30 davidg Exp + * Id: if_fxp.c,v 1.55 1998/08/04 08:53:12 dg Exp */ /* @@ -216,6 +216,15 @@ static int tx_threshold = 64; #define FXP_NTXCB 128 /* + * Number of completed TX commands at which point an interrupt + * will be generated to garbage collect the attached buffers. + * Must be at least one less than FXP_NTXCB, and should be + * enough less so that the transmitter doesn't becomes idle + * during the buffer rundown (which would reduce performance). + */ +#define FXP_CXINT_THRESH 120 + +/* * TxCB list index mask. This is used to do list wrap-around. */ #define FXP_TXCB_MASK (FXP_NTXCB - 1) @@ -393,9 +402,10 @@ fxp_attach(parent, self, aux) */ if_attach(ifp); /* - * Let the system queue as many packets as we have TX descriptors. + * Let the system queue as many packets as we have available + * TX descriptors. */ - ifp->if_snd.ifq_maxlen = FXP_NTXCB; + ifp->if_snd.ifq_maxlen = FXP_NTXCB - 1; #ifdef __NetBSD__ ether_ifattach(ifp, enaddr); #else @@ -577,9 +587,10 @@ fxp_attach(config_id, unit) */ if_attach(ifp); /* - * Let the system queue as many packets as we have TX descriptors. + * Let the system queue as many packets as we have available + * TX descriptors. */ - ifp->if_snd.ifq_maxlen = FXP_NTXCB; + ifp->if_snd.ifq_maxlen = FXP_NTXCB - 1; ether_ifattach(ifp); #if NBPFILTER > 0 bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); @@ -782,8 +793,10 @@ fxp_start(ifp) /* * We're finished if there is nothing more to add to the list or if * we're all filled up with buffers to transmit. + * NOTE: One TxCB is reserved to guarantee that fxp_mc_setup() can add + * a NOP command when needed. */ - while (ifp->if_snd.ifq_head != NULL && sc->tx_queued < FXP_NTXCB) { + while (ifp->if_snd.ifq_head != NULL && sc->tx_queued < FXP_NTXCB - 1) { struct mbuf *m, *mb_head; int segment; @@ -844,8 +857,18 @@ tbdinit: 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; + if (sc->tx_queued != FXP_CXINT_THRESH - 1) { + txp->cb_command = + FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF | FXP_CB_COMMAND_S; + } else { + txp->cb_command = + 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; /* @@ -880,12 +903,6 @@ tbdinit: if (txp != NULL) { fxp_scb_wait(sc); CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_RESUME); - - /* - * Set a 5 second timer just in case we don't hear from the - * card again. - */ - ifp->if_timer = 5; } } @@ -913,6 +930,33 @@ fxp_intr(arg) CSR_WRITE_1(sc, FXP_CSR_SCB_STATACK, statack); /* + * Free any finished transmit mbuf chains. + */ + if (statack & FXP_SCB_STATACK_CXTNO) { + 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; + ifp->if_timer = 0; + if (sc->tx_queued == 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); + } + /* * Process receiver interrupts. If a no-resource (RNR) * condition exists, get whatever packets we can and * re-start the receiver. @@ -988,33 +1032,6 @@ 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); @@ -1202,7 +1219,6 @@ fxp_init(xsc) fxp_stop(sc); prm = (ifp->if_flags & IFF_PROMISC) ? 1 : 0; - sc->promisc_mode = prm; /* * Initialize base of CBL and RFA memory. Loading with zero @@ -1248,7 +1264,7 @@ fxp_init(xsc) cbp->dma_bce = 0; /* (disable) dma max counters */ cbp->late_scb = 0; /* (don't) defer SCB update */ cbp->tno_int = 0; /* (disable) tx not okay interrupt */ - cbp->ci_int = 0; /* interrupt on CU not active */ + cbp->ci_int = 1; /* interrupt on CU idle */ cbp->save_bf = prm; /* save bad frames */ cbp->disc_short_rx = !prm; /* discard short packets */ cbp->underrun_retry = 1; /* retry mode (1) on DMA underrun */ @@ -1340,16 +1356,16 @@ fxp_init(xsc) switch (sc->phy_primary_device) { case FXP_PHY_DP83840: case FXP_PHY_DP83840A: - case FXP_PHY_82553A: - case FXP_PHY_82553C: - case FXP_PHY_82555B: fxp_mdi_write(sc, sc->phy_primary_addr, FXP_DP83840_PCR, fxp_mdi_read(sc, sc->phy_primary_addr, FXP_DP83840_PCR) | FXP_DP83840_PCR_LED4_MODE | /* LED4 always indicates duplex */ FXP_DP83840_PCR_F_CONNECT | /* force link disconnect bypass */ FXP_DP83840_PCR_BIT10); /* XXX I have no idea */ /* fallthrough */ + case FXP_PHY_82553A: + case FXP_PHY_82553C: case FXP_PHY_82555: + case FXP_PHY_82555B: /* * If link0 is set, disable auto-negotiation and then: * If link1 is unset = 10Mbps @@ -1621,7 +1637,7 @@ fxp_ioctl(ifp, command, data) * * 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 + * this. By requiring this, it allows us to keep up 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 @@ -1644,8 +1660,49 @@ fxp_mc_setup(sc) #endif int nmcasts; + /* + * If there are queued commands, we must wait until they are all + * completed. If we are already waiting, then add a NOP command + * with interrupt option so that we're notified when all commands + * have been completed - fxp_start() ensures that no additional + * TX commands will be added when need_mcsetup is true. + */ if (sc->tx_queued) { + struct fxp_cb_tx *txp; + + /* + * need_mcsetup will be true if we are already waiting for the + * NOP command to be completed (see below). In this case, bail. + */ + if (sc->need_mcsetup) + return; sc->need_mcsetup = 1; + + /* + * Add a NOP command with interrupt so that we are notified when all + * TX commands have been processed. + */ + txp = sc->cbl_last->next; + txp->mb_head = NULL; + txp->cb_status = 0; + txp->cb_command = FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S | FXP_CB_COMMAND_I; + /* + * Advance the end of list forward. + */ + sc->cbl_last->cb_command &= ~FXP_CB_COMMAND_S; + sc->cbl_last = txp; + sc->tx_queued++; + /* + * Issue a resume in case the CU has just suspended. + */ + fxp_scb_wait(sc); + CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_RESUME); + /* + * Set a 5 second timer just in case we don't hear from the + * card again. + */ + ifp->if_timer = 5; + return; } sc->need_mcsetup = 0; @@ -1656,7 +1713,7 @@ fxp_mc_setup(sc) 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->cb_command = FXP_CB_COMMAND_MCAS | FXP_CB_COMMAND_S | FXP_CB_COMMAND_I; mcsp->link_addr = vtophys(&sc->cbl_base->cb_status); nmcasts = 0; @@ -1716,6 +1773,6 @@ fxp_mc_setup(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; + ifp->if_timer = 2; return; } |