diff options
author | 2020-02-28 14:17:21 +0000 | |
---|---|---|
committer | 2020-02-28 14:17:21 +0000 | |
commit | 11846e193834f04647a1d90c6926f9e5a485b394 (patch) | |
tree | a02b638b583fe6cd45a2c3138173fb15862c1baa | |
parent | In iwm(4), do not drop short control frames in monitor mode and do not (diff) | |
download | wireguard-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.c | 42 |
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; |