summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/if_fxp.c157
-rw-r--r--sys/dev/pci/if_fxpvar.h22
2 files changed, 119 insertions, 60 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;
}
diff --git a/sys/dev/pci/if_fxpvar.h b/sys/dev/pci/if_fxpvar.h
index 6cc50921dce..d4b9e656e8f 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.3 1998/07/02 21:15:47 downsj Exp $ */
+/* $OpenBSD: if_fxpvar.h,v 1.4 1998/08/21 20:29:13 downsj Exp $ */
/* $NetBSD: if_fxpvar.h,v 1.1 1997/06/05 02:01:58 thorpej Exp $ */
/*
@@ -30,14 +30,17 @@
* 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_fxpvar.h,v 1.6 1998/08/02 00:29:15 dg Exp
*/
/*
* Misc. defintions for the Intel EtherExpress Pro/100B PCI Fast
* Ethernet driver
*/
-
+/*
+ * NOTE: Elements are ordered for optimal cacheline behavior, and NOT
+ * for functional grouping.
+ */
struct fxp_softc {
#if defined(__NetBSD__) || defined(__OpenBSD__)
struct device sc_dev; /* generic device structures */
@@ -53,18 +56,17 @@ struct fxp_softc {
#if defined(__NetBSD__)
struct ethercom sc_ethercom; /* ethernet common part */
#endif
- 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 */
struct mbuf *rfa_headm; /* first mbuf in receive frame area */
struct mbuf *rfa_tailm; /* last mbuf in receive frame area */
+ struct fxp_cb_tx *cbl_first; /* first active TxCB in list */
+ int tx_queued; /* # of active TxCB's */
+ int need_mcsetup; /* multicast filter needs programming */
+ struct fxp_cb_tx *cbl_last; /* last active TxCB in list */
struct fxp_stats *fxp_stats; /* Pointer to interface stats */
+ int rx_idle_secs; /* # of seconds RX has been idle */
+ struct fxp_cb_tx *cbl_base; /* base of TxCB list */
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 */
int phy_10Mbps_only; /* PHY is 10Mbps-only device */