summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorstsp <stsp@openbsd.org>2020-02-28 14:17:21 +0000
committerstsp <stsp@openbsd.org>2020-02-28 14:17:21 +0000
commit11846e193834f04647a1d90c6926f9e5a485b394 (patch)
treea02b638b583fe6cd45a2c3138173fb15862c1baa
parentIn iwm(4), do not drop short control frames in monitor mode and do not (diff)
downloadwireguard-openbsd-11846e193834f04647a1d90c6926f9e5a485b394.tar.xz
wireguard-openbsd-11846e193834f04647a1d90c6926f9e5a485b394.zip
Sync tobhe's periodic interrupt fix from iwm(4) to iwx(4).
Rx interrupt handling can lead to a race where the interrupt is handled before the shared data was updated. As a workaround each "real" interrupt enables the "periodic" Rx interrupt which triggers after 8 ms and detects any dangling Rx activity. If dangling Rx activity was detected the periodic interrupt is restarted, if not it stays disabled until the next "real" Rx interrupt is handled. The periodic interrupt is not supposed to write IWX_CSR_FH_INT_STATUS unless it has detected dangling Rx activity.
-rw-r--r--sys/dev/pci/if_iwx.c42
1 files changed, 23 insertions, 19 deletions
diff --git a/sys/dev/pci/if_iwx.c b/sys/dev/pci/if_iwx.c
index b7fb06f887f..2800851d5eb 100644
--- a/sys/dev/pci/if_iwx.c
+++ b/sys/dev/pci/if_iwx.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwx.c,v 1.1 2020/02/15 08:47:14 stsp Exp $ */
+/* $OpenBSD: if_iwx.c,v 1.2 2020/02/28 14:17:21 stsp Exp $ */
/*
* Copyright (c) 2014, 2016 genua gmbh <info@genua.de>
@@ -7204,7 +7204,6 @@ iwx_intr(void *arg)
struct iwx_softc *sc = arg;
int handled = 0;
int r1, r2, rv = 0;
- int isperiodic = 0;
IWX_WRITE(sc, IWX_CSR_INT_MASK, 0);
@@ -7313,27 +7312,32 @@ iwx_intr(void *arg)
wakeup(&sc->sc_fw);
}
- if (r1 & IWX_CSR_INT_BIT_RX_PERIODIC) {
- handled |= IWX_CSR_INT_BIT_RX_PERIODIC;
- IWX_WRITE(sc, IWX_CSR_INT, IWX_CSR_INT_BIT_RX_PERIODIC);
- if ((r1 & (IWX_CSR_INT_BIT_FH_RX | IWX_CSR_INT_BIT_SW_RX)) == 0)
- IWX_WRITE_1(sc,
- IWX_CSR_INT_PERIODIC_REG, IWX_CSR_INT_PERIODIC_DIS);
- isperiodic = 1;
- }
-
- if ((r1 & (IWX_CSR_INT_BIT_FH_RX | IWX_CSR_INT_BIT_SW_RX)) ||
- isperiodic) {
- handled |= (IWX_CSR_INT_BIT_FH_RX | IWX_CSR_INT_BIT_SW_RX);
- IWX_WRITE(sc, IWX_CSR_FH_INT_STATUS, IWX_CSR_FH_INT_RX_MASK);
+ if (r1 & (IWX_CSR_INT_BIT_FH_RX | IWX_CSR_INT_BIT_SW_RX |
+ IWX_CSR_INT_BIT_RX_PERIODIC)) {
+ if (r1 & (IWX_CSR_INT_BIT_FH_RX | IWX_CSR_INT_BIT_SW_RX)) {
+ handled |= (IWX_CSR_INT_BIT_FH_RX | IWX_CSR_INT_BIT_SW_RX);
+ IWX_WRITE(sc, IWX_CSR_FH_INT_STATUS, IWX_CSR_FH_INT_RX_MASK);
+ }
+ if (r1 & IWX_CSR_INT_BIT_RX_PERIODIC) {
+ handled |= IWX_CSR_INT_BIT_RX_PERIODIC;
+ IWX_WRITE(sc, IWX_CSR_INT, IWX_CSR_INT_BIT_RX_PERIODIC);
+ }
- iwx_notif_intr(sc);
+ /* Disable periodic interrupt; we use it as just a one-shot. */
+ IWX_WRITE_1(sc, IWX_CSR_INT_PERIODIC_REG, IWX_CSR_INT_PERIODIC_DIS);
- /* enable periodic interrupt, see above */
- if (r1 & (IWX_CSR_INT_BIT_FH_RX | IWX_CSR_INT_BIT_SW_RX) &&
- !isperiodic)
+ /*
+ * Enable periodic interrupt in 8 msec only if we received
+ * real RX interrupt (instead of just periodic int), to catch
+ * any dangling Rx interrupt. If it was just the periodic
+ * interrupt, there was no dangling Rx activity, and no need
+ * to extend the periodic interrupt; one-shot is enough.
+ */
+ if (r1 & (IWX_CSR_INT_BIT_FH_RX | IWX_CSR_INT_BIT_SW_RX))
IWX_WRITE_1(sc, IWX_CSR_INT_PERIODIC_REG,
IWX_CSR_INT_PERIODIC_ENA);
+
+ iwx_notif_intr(sc);
}
rv = 1;