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