summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authoryongari <yongari@FreeBSD.org>2008-12-17 08:18:11 +0000
committeryongari <yongari@FreeBSD.org>2008-12-17 08:18:11 +0000
commit62ee68bb086f87555449fb796d5153418839b5cf (patch)
tree7ef670de7c8c50c85fce80da7af46f2cc1558dd0 /sys
parent7efe2ccd487653a48a680daec35810cb43bdb1f2 (diff)
downloadFreeBSD-src-62ee68bb086f87555449fb796d5153418839b5cf.zip
FreeBSD-src-62ee68bb086f87555449fb796d5153418839b5cf.tar.gz
It seems that RealTek PCIe controllers require an explicit Tx poll
command whenever Tx completion interrupt is raised. The Tx poll bit is cleared when all packets waiting to be transferred have been processed. This means the second Tx poll command can be silently ignored as the Tx poll bit could be still active while processing of previous Tx poll command is in progress. To address the issue re(4) used to invoke the Tx poll command in Tx completion handler whenever it detects there are pending packets in TxQ. However that still does not seem to completely eliminate watchdog timeouts seen on RealTek PCIe controllers. To fix the issue kick Tx poll command only after Tx completion interrupt is raised as this would indicate Tx is now idle state such that it can accept new Tx poll command again. While here apply this workaround for PCIe based controllers as other controllers does not seem to have this limitation. Tested by: Victor Balada Diaz < victor <> bsdes DOT net >
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/re/if_re.c25
-rw-r--r--sys/pci/if_rlreg.h1
2 files changed, 16 insertions, 10 deletions
diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c
index efd5930..2ad55fd 100644
--- a/sys/dev/re/if_re.c
+++ b/sys/dev/re/if_re.c
@@ -1157,6 +1157,7 @@ re_attach(device_t dev)
msic = 0;
if (pci_find_extcap(dev, PCIY_EXPRESS, &reg) == 0) {
+ sc->rl_flags |= RL_FLAG_PCIE;
msic = pci_msi_count(dev);
if (bootverbose)
device_printf(dev, "MSI count : %d\n", msic);
@@ -2042,16 +2043,6 @@ re_txeof(struct rl_softc *sc)
/* No changes made to the TX ring, so no flush needed */
if (sc->rl_ldata.rl_tx_free != sc->rl_ldata.rl_tx_desc_cnt) {
- /*
- * Some chips will ignore a second TX request issued
- * while an existing transmission is in progress. If
- * the transmitter goes idle but there are still
- * packets waiting to be sent, we need to restart the
- * channel here to flush them out. This only seems to
- * be required with the PCIe devices.
- */
- CSR_WRITE_1(sc, sc->rl_txstart, RL_TXSTART_START);
-
#ifdef RE_TX_MODERATION
/*
* If not all descriptors have been reaped yet, reload
@@ -2115,6 +2106,9 @@ re_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
return;
if (status)
CSR_WRITE_2(sc, RL_ISR, status);
+ if ((status & (RL_ISR_TX_OK | RL_ISR_TX_DESC_UNAVAIL)) &&
+ (sc->rl_flags & RL_FLAG_PCIE))
+ CSR_WRITE_1(sc, sc->rl_txstart, RL_TXSTART_START);
/*
* XXX check behaviour on receiver stalls.
@@ -2176,6 +2170,17 @@ re_int_task(void *arg, int npending)
if (status & (RL_ISR_RX_OK|RL_ISR_RX_ERR|RL_ISR_FIFO_OFLOW))
rval = re_rxeof(sc);
+ /*
+ * Some chips will ignore a second TX request issued
+ * while an existing transmission is in progress. If
+ * the transmitter goes idle but there are still
+ * packets waiting to be sent, we need to restart the
+ * channel here to flush them out. This only seems to
+ * be required with the PCIe devices.
+ */
+ if ((status & (RL_ISR_TX_OK | RL_ISR_TX_DESC_UNAVAIL)) &&
+ (sc->rl_flags & RL_FLAG_PCIE))
+ CSR_WRITE_1(sc, sc->rl_txstart, RL_TXSTART_START);
if (status & (
#ifdef RE_TX_MODERATION
RL_ISR_TIMEOUT_EXPIRED|
diff --git a/sys/pci/if_rlreg.h b/sys/pci/if_rlreg.h
index ccea051..b3569e8 100644
--- a/sys/pci/if_rlreg.h
+++ b/sys/pci/if_rlreg.h
@@ -891,6 +891,7 @@ struct rl_softc {
#define RL_FLAG_PHY8110S 0x0800
#define RL_FLAG_WOLRXENB 0x1000
#define RL_FLAG_MACSLEEP 0x2000
+#define RL_FLAG_PCIE 0x4000
#define RL_FLAG_LINK 0x8000
};
OpenPOWER on IntegriCloud