summaryrefslogtreecommitdiff
path: root/sys/dev/pci/if_fxp.c
diff options
context:
space:
mode:
authorJason Downs <downsj@cvs.openbsd.org>1998-08-21 20:29:14 +0000
committerJason Downs <downsj@cvs.openbsd.org>1998-08-21 20:29:14 +0000
commit25791729ee175a0d43c086c9a3906a780c9fe33a (patch)
tree44425bbfd4247763068b2fda2d65e3f46890d8c2 /sys/dev/pci/if_fxp.c
parent0837d6e5a8986e9a59fdd0c871b9f9604b132b05 (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.c157
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;
}