Module Name: src
Committed By: riastradh
Date: Wed Feb 28 20:18:13 UTC 2024
Modified Files:
src/sys/dev/usb: if_urtwn.c
Log Message:
urtwn(4): Ditch old queued commands on overflow.
Don't increment ring->queued past what the task will decrement.
This is a stop-gap measure; really, we should just have one task for
each operation that is deferred to the task thread.
PR kern/57965
To generate a diff of this commit:
cvs rdiff -u -r1.108 -r1.109 src/sys/dev/usb/if_urtwn.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/usb/if_urtwn.c
diff -u src/sys/dev/usb/if_urtwn.c:1.108 src/sys/dev/usb/if_urtwn.c:1.109
--- src/sys/dev/usb/if_urtwn.c:1.108 Sat Jan 6 00:26:26 2024
+++ src/sys/dev/usb/if_urtwn.c Wed Feb 28 20:18:13 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: if_urtwn.c,v 1.108 2024/01/06 00:26:26 maya Exp $ */
+/* $NetBSD: if_urtwn.c,v 1.109 2024/02/28 20:18:13 riastradh Exp $ */
/* $OpenBSD: if_urtwn.c,v 1.42 2015/02/10 23:25:46 mpi Exp $ */
/*-
@@ -25,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_urtwn.c,v 1.108 2024/01/06 00:26:26 maya Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_urtwn.c,v 1.109 2024/02/28 20:18:13 riastradh Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@@ -872,6 +872,24 @@ urtwn_tx_beacon(struct urtwn_softc *sc,
}
static void
+urtwn_cmdq_invariants(struct urtwn_softc *sc)
+{
+ struct urtwn_host_cmd_ring *const ring = &sc->cmdq;
+
+ KASSERT(mutex_owned(&sc->sc_task_mtx));
+ KASSERTMSG((ring->cur >= 0 && ring->cur < URTWN_HOST_CMD_RING_COUNT),
+ "%s: cur=%d next=%d queued=%d",
+ device_xname(sc->sc_dev), ring->cur, ring->next, ring->queued);
+ KASSERTMSG((ring->next >= 0 && ring->next < URTWN_HOST_CMD_RING_COUNT),
+ "%s: cur=%d next=%d queued=%d",
+ device_xname(sc->sc_dev), ring->cur, ring->next, ring->queued);
+ KASSERTMSG((ring->queued >= 0 &&
+ ring->queued <= URTWN_HOST_CMD_RING_COUNT),
+ "%s: %d commands queued",
+ device_xname(sc->sc_dev), ring->queued);
+}
+
+static void
urtwn_task(void *arg)
{
struct urtwn_softc *sc = arg;
@@ -903,7 +921,11 @@ urtwn_task(void *arg)
/* Process host commands. */
s = splusb();
mutex_spin_enter(&sc->sc_task_mtx);
+ urtwn_cmdq_invariants(sc);
while (ring->next != ring->cur) {
+ KASSERTMSG(ring->queued > 0, "%s: cur=%d next=%d queued=%d",
+ device_xname(sc->sc_dev),
+ ring->cur, ring->next, ring->queued);
cmd = &ring->cmd[ring->next];
mutex_spin_exit(&sc->sc_task_mtx);
splx(s);
@@ -911,6 +933,10 @@ urtwn_task(void *arg)
cmd->cb(sc, cmd->data);
s = splusb();
mutex_spin_enter(&sc->sc_task_mtx);
+ urtwn_cmdq_invariants(sc);
+ KASSERTMSG(ring->queued > 0, "%s: cur=%d next=%d queued=%d",
+ device_xname(sc->sc_dev),
+ ring->cur, ring->next, ring->queued);
ring->queued--;
ring->next = (ring->next + 1) % URTWN_HOST_CMD_RING_COUNT;
}
@@ -925,6 +951,7 @@ urtwn_do_async(struct urtwn_softc *sc, v
{
struct urtwn_host_cmd_ring *ring = &sc->cmdq;
struct urtwn_host_cmd *cmd;
+ bool schedtask = false;
int s;
URTWNHIST_FUNC();
@@ -933,19 +960,27 @@ urtwn_do_async(struct urtwn_softc *sc, v
s = splusb();
mutex_spin_enter(&sc->sc_task_mtx);
+ urtwn_cmdq_invariants(sc);
cmd = &ring->cmd[ring->cur];
cmd->cb = cb;
KASSERT(len <= sizeof(cmd->data));
memcpy(cmd->data, arg, len);
ring->cur = (ring->cur + 1) % URTWN_HOST_CMD_RING_COUNT;
- /* If there is no pending command already, schedule a task. */
- if (!sc->sc_dying && ++ring->queued == 1) {
- mutex_spin_exit(&sc->sc_task_mtx);
- usb_add_task(sc->sc_udev, &sc->sc_task, USB_TASKQ_DRIVER);
- } else
- mutex_spin_exit(&sc->sc_task_mtx);
+ /*
+ * Schedule a task to process the command if need be.
+ */
+ if (!sc->sc_dying) {
+ if (ring->queued == URTWN_HOST_CMD_RING_COUNT)
+ device_printf(sc->sc_dev, "command queue overflow\n");
+ else if (ring->queued++ == 0)
+ schedtask = true;
+ }
+ mutex_spin_exit(&sc->sc_task_mtx);
splx(s);
+
+ if (schedtask)
+ usb_add_task(sc->sc_udev, &sc->sc_task, USB_TASKQ_DRIVER);
}
static void