summaryrefslogtreecommitdiffstats
path: root/sys/dev/fxp
diff options
context:
space:
mode:
authoriedowse <iedowse@FreeBSD.org>2002-11-07 16:04:07 +0000
committeriedowse <iedowse@FreeBSD.org>2002-11-07 16:04:07 +0000
commit92eb830a35122db8e11af254e93833c48efdd107 (patch)
tree28a2b5699d9effc331188af35ac235d9d5108d07 /sys/dev/fxp
parentee7affb74a311710c9e312ff814bd4c56acf3469 (diff)
downloadFreeBSD-src-92eb830a35122db8e11af254e93833c48efdd107.zip
FreeBSD-src-92eb830a35122db8e11af254e93833c48efdd107.tar.gz
Properly fix the occassional random crash issue that revision 1.142
just limited to the DEVICE_POLLING case. This removes the FXP_RFA_RNRMARK hack, and replaces it with a softc flag that is used to record when the handling of a no-resource condition was deferred due to running out of DEVICE_POLLING cycles. This was tested on -stable, but the code is essentially the same as in -current. It should only affect the case where DEVICE_POLLING is defined. The details of the mechanism behind the crashes are still uncertain but the most likely cause seems to be some kind of hardware confusion when the no-resource recovery code is accidentally invoked while the receiver is still active. This could have happened if the hardware left the 0x4000 bit of the RFA status word set. The comments in the commit log for revision 1.142 stating that the driver could clash with the hardware writing to this status word were not correct. Tested by: Guy Helmer <ghelmer@palisadesys.com>
Diffstat (limited to 'sys/dev/fxp')
-rw-r--r--sys/dev/fxp/if_fxp.c54
-rw-r--r--sys/dev/fxp/if_fxpvar.h1
2 files changed, 24 insertions, 31 deletions
diff --git a/sys/dev/fxp/if_fxp.c b/sys/dev/fxp/if_fxp.c
index 63b2b9e..9befadb 100644
--- a/sys/dev/fxp/if_fxp.c
+++ b/sys/dev/fxp/if_fxp.c
@@ -1239,6 +1239,13 @@ fxp_intr_body(struct fxp_softc *sc, u_int8_t statack, int count)
if (rnr)
fxp_rnr++;
+#ifdef DEVICE_POLLING
+ /* Pick up a deferred RNR condition if `count' ran out last time. */
+ if (sc->flags & FXP_FLAG_DEFERRED_RNR) {
+ sc->flags &= ~FXP_FLAG_DEFERRED_RNR;
+ rnr = 1;
+ }
+#endif
/*
* Free any finished transmit mbuf chains.
@@ -1281,47 +1288,40 @@ fxp_intr_body(struct fxp_softc *sc, u_int8_t statack, int count)
/*
* Just return if nothing happened on the receive side.
*/
- if ( (statack & (FXP_SCB_STATACK_FR | FXP_SCB_STATACK_RNR)) == 0)
+ if (!rnr && (statack & FXP_SCB_STATACK_FR) == 0)
return;
/*
* Process receiver interrupts. If a no-resource (RNR)
* condition exists, get whatever packets we can and
* re-start the receiver.
- */
-
-#ifdef DEVICE_POLLING
- /*
+ *
* When using polling, we do not process the list to completion,
* so when we get an RNR interrupt we must defer the restart
* until we hit the last buffer with the C bit set.
* If we run out of cycles and rfa_headm has the C bit set,
- * record the pending RNR in an unused status bit, so that the
- * info will be used in the subsequent polling cycle.
- *
- * XXX there is absolutely no guarantee that this reserved bit
- * will be ignored by the hardware!
+ * record the pending RNR in the FXP_FLAG_DEFERRED_RNR flag so
+ * that the info will be used in the subsequent polling cycle.
*/
-#define FXP_RFA_RNRMARK 0x4000 /* used to mark a pending RNR intr */
-#endif
-
for (;;) {
m = sc->rfa_headm;
rfa = (struct fxp_rfa *)(m->m_ext.ext_buf +
RFA_ALIGNMENT_FUDGE);
#ifdef DEVICE_POLLING /* loop at most count times if count >=0 */
- if (count >= 0 && count-- == 0)
+ if (count >= 0 && count-- == 0) {
+ if (rnr) {
+ /* Defer RNR processing until the next time. */
+ sc->flags |= FXP_FLAG_DEFERRED_RNR;
+ rnr = 0;
+ }
break;
+ }
#endif /* DEVICE_POLLING */
if ( (rfa->rfa_status & FXP_RFA_STATUS_C) == 0)
break;
-#ifdef DEVICE_POLLING
- if (rfa->rfa_status & FXP_RFA_RNRMARK)
- rnr = 1;
-#endif
/*
* Remove first packet from the chain.
*/
@@ -1356,19 +1356,11 @@ fxp_intr_body(struct fxp_softc *sc, u_int8_t statack, int count)
}
}
if (rnr) {
-#ifdef DEVICE_POLLING
- if (rfa->rfa_status & FXP_RFA_STATUS_C)
- rfa->rfa_status |= FXP_RFA_RNRMARK;
- else {
-#endif
- fxp_scb_wait(sc);
- CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL,
- vtophys(sc->rfa_headm->m_ext.ext_buf) +
- RFA_ALIGNMENT_FUDGE);
- fxp_scb_cmd(sc, FXP_SCB_COMMAND_RU_START);
-#ifdef DEVICE_POLLING
- }
-#endif
+ fxp_scb_wait(sc);
+ CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL,
+ vtophys(sc->rfa_headm->m_ext.ext_buf) +
+ RFA_ALIGNMENT_FUDGE);
+ fxp_scb_cmd(sc, FXP_SCB_COMMAND_RU_START);
}
}
diff --git a/sys/dev/fxp/if_fxpvar.h b/sys/dev/fxp/if_fxpvar.h
index d18ca39..1042f1f 100644
--- a/sys/dev/fxp/if_fxpvar.h
+++ b/sys/dev/fxp/if_fxpvar.h
@@ -157,6 +157,7 @@ struct fxp_softc {
#define FXP_FLAG_ALL_MCAST 0x0040 /* accept all multicast frames */
#define FXP_FLAG_CU_RESUME_BUG 0x0080 /* requires workaround for CU_RESUME */
#define FXP_FLAG_UCODE 0x0100 /* ucode is loaded */
+#define FXP_FLAG_DEFERRED_RNR 0x0200 /* DEVICE_POLLING deferred RNR */
/* Macros to ease CSR access. */
#define CSR_READ_1(sc, reg) \
OpenPOWER on IntegriCloud