NetBSD Problem Report #55835

From ef@math.uni-bonn.de  Tue Dec  1 18:15:43 2020
Return-Path: <ef@math.uni-bonn.de>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
	(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
	(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
	by mollari.NetBSD.org (Postfix) with ESMTPS id 82D971A9217
	for <gnats-bugs@gnats.NetBSD.org>; Tue,  1 Dec 2020 18:15:43 +0000 (UTC)
Message-Id: <20201201181538.8DC441C038@trave.math.uni-bonn.de>
Date: Tue,  1 Dec 2020 19:15:38 +0100 (CET)
From: ef@math.uni-bonn.de
Reply-To: ef@math.uni-bonn.de
To: gnats-bugs@NetBSD.org
Subject: circular done list in ohci_softint()
X-Send-Pr-Version: 3.95

>Number:         55835
>Category:       kern
>Synopsis:       circular done list in ohci_softint()
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    skrll
>State:          closed
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Dec 01 18:20:00 +0000 2020
>Closed-Date:    Fri Dec 18 22:29:22 +0000 2020
>Last-Modified:  Fri Dec 18 22:29:22 +0000 2020
>Originator:     Edgar Fuß
>Release:        NetBSD 8.2_STABLE
>Organization:
Mathematisches Institut der Universität Bonn
>Environment:


System: NetBSD trave.math.uni-bonn.de 8.2_STABLE NetBSD 8.2_STABLE (MI-Server) #13: Tue Dec 1 12:39:36 CET 2020 support@trave.math.uni-bonn.de:/var/work/obj-8/sys/arch/amd64/compile/miserv-DEBUG amd64
Architecture: x86_64
Machine: amd64
>Description:
	Running a libusb test program with Masterguard A700-19 UPSs connected via USB stalls the system the second time run. The kernel loops endlessly in the "Reverse the done list" part in ohci_softint() because the td_nexttd linking (not the nexttd linking) is circular. Most probably, a previously aborted TD has been recycled by the driver, but the controller is still in command of it and puts it onto the done list. Then, so to speak, two incarnations of the same TD are on the done list, leading to the circular list.
>How-To-Repeat:
	Run this:

	#include <err.h>
	#include <stdio.h>
	#include <usb.h>

	struct usb_bus *bus;
	struct usb_device *dev;
	usb_dev_handle *udev;

	int main(int argc, char *argv[]) {
		puts("init"); fflush(stdout);
		usb_init();
		puts("find_busses"); fflush(stdout);
		usb_find_busses();
		puts("find_devices"); fflush(stdout);
		usb_find_devices();

		puts("scan"); fflush(stdout);
		for (bus = usb_busses; bus; bus = bus->next) {
			puts(bus->dirname); fflush(stdout);
			for (dev = bus->devices; dev; dev = dev->next) {
				printf("%d: %s\n", dev->devnum, dev->filename); fflush(stdout);
				udev = usb_open(dev);
				if (!udev) {
					warnx("usb_open: %s", usb_strerror());
					continue;
				}
				printf("%0x %0x %0x\n", dev->descriptor.idVendor, dev->descriptor.idProduct, dev->descriptor.bcdDevice);
	#if 0
				if (usb_claim_interface(udev, 0) < 0) {
					errx(1, "usb_claim: %s", usb_strerror());
				}
	#endif
				usb_close(udev);
			}
		}
		return 0;
	}

	twice with a Masterguard A700-19 connected via USB. Unfortunately, these devices are out of production for a century.

	Use this:

	Index: ohcivar.h
	===================================================================
	RCS file: /cvsroot/src/sys/dev/usb/ohcivar.h,v
	retrieving revision 1.58.10.1
	diff -u -p -r1.58.10.1 ohcivar.h
	--- ohcivar.h	25 Aug 2018 11:29:52 -0000	1.58.10.1
	+++ ohcivar.h	30 Nov 2020 14:35:44 -0000
	@@ -59,6 +59,9 @@ typedef struct ohci_soft_td {
		uint16_t flags;
	 #define OHCI_CALL_DONE	0x0001
	 #define OHCI_ADD_LEN	0x0002
	+#ifdef	OHCI_DEBUG
	+	int beenthere;			/* loop detection */
	+#endif
	 } ohci_soft_td_t;
	 #define OHCI_STD_SIZE ((sizeof(struct ohci_soft_td) + OHCI_TD_ALIGN - 1) / OHCI_TD_ALIGN * OHCI_TD_ALIGN)
	 #define OHCI_STD_CHUNK 128
	@@ -75,6 +78,9 @@ typedef struct ohci_soft_itd {
		struct usbd_xfer *xfer;
		uint16_t flags;
		bool isdone;	/* used only when DIAGNOSTIC is defined */
	+#ifdef	OHCI_DEBUG
	+	int beenthere;			/* loop detection */
	+#endif
	 } ohci_soft_itd_t;
	 #define OHCI_SITD_SIZE ((sizeof(struct ohci_soft_itd) + OHCI_ITD_ALIGN - 1) / OHCI_ITD_ALIGN * OHCI_ITD_ALIGN)
	 #define OHCI_SITD_CHUNK 64
	Index: ohci.c
	===================================================================
	RCS file: /cvsroot/src/sys/dev/usb/ohci.c,v
	retrieving revision 1.273.6.6
	diff -u -p -r1.273.6.6 ohci.c
	--- ohci.c	25 Feb 2020 18:52:44 -0000	1.273.6.6
	+++ ohci.c	30 Nov 2020 14:35:44 -0000
	@@ -230,6 +230,8 @@ Static void		ohci_dump_td(ohci_softc_t *
	 Static void		ohci_dump_ed(ohci_softc_t *, ohci_soft_ed_t *);
	 Static void		ohci_dump_itd(ohci_softc_t *, ohci_soft_itd_t *);
	 Static void		ohci_dump_itds(ohci_softc_t *, ohci_soft_itd_t *);
	+
	+static int ohci_beenthere = 0;	/* td list loop detection */
	 #endif

	 #define OBARR(sc) bus_space_barrier((sc)->iot, (sc)->ioh, 0, (sc)->sc_size, \
	@@ -693,6 +695,13 @@ ohci_reset_std_chain(ohci_softc_t *sc, s
			DPRINTFN(2, "add 0 xfer", 0, 0, 0, 0);
		}

	+#ifdef OHCI_DEBUG
	+	DPRINTFN(10, "--- dump start ---", 0, 0, 0, 0);
	+	if (ohcidebug >= 10)
	+		ohci_dump_td(sc, sp);
	+	DPRINTFN(10, "--- dump end ---", 0, 0, 0, 0);
	+#endif
	+
		/* Last TD gets usb_syncmem'ed by caller */
		*ep = cur;
	 }
	@@ -1410,9 +1419,26 @@ ohci_softintr(void *v)
		OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_WDH);

		/* Reverse the done list. */
	+#ifdef OHCI_DEBUG
	+	ohci_beenthere++;
	+#endif
		for (sdone = NULL, sidone = NULL; done != 0; ) {
	+		DPRINTFN(10, "done=%#jx", (uintptr_t)done, 0, 0, 0);
			std = ohci_hash_find_td(sc, done);
			if (std != NULL) {
	+#ifdef OHCI_DEBUG
	+			if (ohcidebug >= 10) 
	+				ohci_dump_td(sc, std);
	+			if (std->beenthere == ohci_beenthere) {
	+				DPRINTFN(1, "circular sdone: %#jx->%#jx", (uintptr_t)done, (uintptr_t)std->physaddr, 0, 0);
	+				device_printf(sc->sc_dev, "circular sdone: %#jx->%#jx\n", (uintptr_t)done, (uintptr_t)std->physaddr);
	+#if 0
	+				panic("circular sdone");
	+#endif
	+				break;
	+			}
	+			std->beenthere = ohci_beenthere;
	+#endif
				usb_syncmem(&std->dma, std->offs, sizeof(std->td),
				    BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
				std->dnext = sdone;
	@@ -1423,6 +1449,21 @@ ohci_softintr(void *v)
			}
			sitd = ohci_hash_find_itd(sc, done);
			if (sitd != NULL) {
	+#ifdef OHCI_DEBUG
	+/* XXX no ohci_dump_itd() yet
	+			if (ohcidebug >= 10) 
	+				ohci_dump_itd(sc, sitd);
	+*/
	+			if (sitd->beenthere == ohci_beenthere) {
	+				DPRINTFN(1, "circular sidone: %#jx->%#jx", (uintptr_t)done, (uintptr_t)sitd->physaddr, 0, 0);
	+				device_printf(sc->sc_dev, "circular sidone: %#jx->%#jx\n", (uintptr_t)done, (uintptr_t)sitd->physaddr);
	+#if 0
	+				panic("circular sidone");
	+#endif
	+				break;
	+			}
	+			sitd->beenthere = ohci_beenthere;
	+#endif
				usb_syncmem(&sitd->dma, sitd->offs, sizeof(sitd->itd),
				    BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
				sitd->dnext = sidone;
	@@ -1445,6 +1486,7 @@ ohci_softintr(void *v)
			for (std = sdone; std; std = std->dnext)
				ohci_dump_td(sc, std);
		}
	+/* XXX dump sidone list */
	 #endif
		DPRINTFN(10, "--- TD dump end ---", 0, 0, 0, 0);

	@@ -1838,6 +1880,15 @@ ohci_hash_add_td(ohci_softc_t *sc, ohci_

		KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));

	+#ifdef OHCI_DEBUG
	+	for (ohci_soft_td_t *std2 = LIST_FIRST(&sc->sc_hash_tds[h]);
	+	     std2 != NULL;
	+	     std2 = LIST_NEXT(std2, hnext)) {
	+		if (std2->physaddr == std->physaddr)
	+			panic("OHCI: duplicate physaddr");
	+	}
	+#endif
	+
		LIST_INSERT_HEAD(&sc->sc_hash_tds[h], std, hnext);
	 }

	@@ -1945,7 +1996,11 @@ ohci_timeout_task(void *addr)
	 void
	 ohci_dump_tds(ohci_softc_t *sc, ohci_soft_td_t *std)
	 {
	+	ohci_beenthere++;
		for (; std; std = std->nexttd) {
	+		if (std->beenthere == ohci_beenthere)
	+			panic("circular tds");
	+		std->beenthere = ohci_beenthere;
			ohci_dump_td(sc, std);
			KASSERTMSG(std->nexttd == NULL || std != std->nexttd,
			    "std %p next %p", std, std->nexttd);
	@@ -1973,6 +2028,7 @@ ohci_dump_td(ohci_softc_t *sc, ohci_soft
		       (u_long)O32TOH(std->td.td_cbp),
		       (u_long)O32TOH(std->td.td_nexttd),
		       (u_long)O32TOH(std->td.td_be), 0);
	+	DPRINTF("    nexttd=%#jx", (uintptr_t)std->nexttd, 0, 0, 0);
	 }

	 void

	diff to verify the list has gone circular and rule out that a physaddr has been allocated twice plus break out of the endless loop (or panic).
>Fix:
	Backported (to -8) from the nusb branch, ohci.c 1.254.2.76 (thanks, nick@!):

	--- ohcivar.h.orig	2020-11-30 15:31:45.755906264 +0100
	+++ ohcivar.h	2020-12-01 12:12:58.463657450 +0100
	@@ -1,4 +1,4 @@
	-/*	$NetBSD: ohcivar.h,v 1.58.10.1 2018/08/25 11:29:52 martin Exp $	*/
	+/*	$NetBSD: ohcivar.h,v 1.55.6.15 2016/05/30 06:46:50 skrll Exp $	*/

	 /*
	  * Copyright (c) 1998 The NetBSD Foundation, Inc.
	@@ -50,6 +50,7 @@
		ohci_td_t td;
		struct ohci_soft_td *nexttd;	/* mirrors nexttd in TD */
		struct ohci_soft_td *dnext;	/* next in done list */
	+	struct ohci_soft_td **held;	/* where the ref to this std is held */
		ohci_physaddr_t physaddr;
		usb_dma_t dma;
		int offs;
	@@ -71,6 +72,7 @@
		ohci_itd_t itd;
		struct ohci_soft_itd *nextitd;	/* mirrors nexttd in ITD */
		struct ohci_soft_itd *dnext;	/* next in done list */
	+	struct ohci_soft_itd **held;	/* where the ref to this sitd is held */
		ohci_physaddr_t physaddr;
		usb_dma_t dma;
		int offs;
	@@ -114,6 +116,8 @@
		LIST_HEAD(, ohci_soft_td)  sc_hash_tds[OHCI_HASH_SIZE];
		LIST_HEAD(, ohci_soft_itd) sc_hash_itds[OHCI_HASH_SIZE];

	+	TAILQ_HEAD(, ohci_xfer)	sc_abortingxfers;
	+
		int sc_noport;

		int sc_endian;
	@@ -128,6 +128,8 @@
		int sc_flags;
	 #define OHCIF_SUPERIO          0x0001

	+       kcondvar_t sc_softwake_cv;
	+
		ohci_soft_ed_t *sc_freeeds;
		ohci_soft_td_t *sc_freetds;
		ohci_soft_itd_t *sc_freeitds;
	@@ -148,6 +152,8 @@

	 struct ohci_xfer {
		struct usbd_xfer xfer;
	+	uint32_t ox_abintrs;
	+	TAILQ_ENTRY(ohci_xfer) ox_abnext;
		/* ctrl */
		ohci_soft_td_t *ox_setup;
		ohci_soft_td_t *ox_stat;
	--- ohci.c	2020-11-23 18:30:07.000000000 +0100
	+++ /tmp/ohci.c	2020-11-30 18:02:27.000000000 +0100
	@@ -1,4 +1,4 @@
	-/*	$NetBSD: ohci.c,v 1.273.6.6 2020/02/25 18:52:44 martin Exp $	*/
	+/*	$NetBSD: ohci.c,v 1.254.2.76 2016/05/30 06:46:50 skrll Exp $	*/

	 /*
	  * Copyright (c) 1998, 2004, 2005, 2012 The NetBSD Foundation, Inc.
	@@ -41,7 +41,7 @@
	  */

	 #include <sys/cdefs.h>
	-__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.273.6.6 2020/02/25 18:52:44 martin Exp $");
	+__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.254.2.76 2016/05/30 06:46:50 skrll Exp $");

	 #ifdef _KERNEL_OPT
	 #include "opt_usb.h"
	@@ -384,6 +384,8 @@ ohci_detach(struct ohci_softc *sc, int f

		softint_disestablish(sc->sc_rhsc_si);

	+	cv_destroy(&sc->sc_softwake_cv);
	+
		mutex_destroy(&sc->sc_lock);
		mutex_destroy(&sc->sc_intr_lock);

	@@ -492,6 +494,7 @@ ohci_alloc_std(ohci_softc_t *sc)
		memset(&std->td, 0, sizeof(ohci_td_t));
		std->nexttd = NULL;
		std->xfer = NULL;
	+	std->held = NULL;

		return std;
	 }
	@@ -539,14 +542,17 @@ ohci_alloc_std_chain(ohci_softc_t *sc, s

		DPRINTFN(8, "xfer %#jx nstd %jd", (uintptr_t)xfer, nstd, 0, 0);

	-	for (size_t j = 0; j < ox->ox_nstd;) {
	+	for (size_t j = 0; j < ox->ox_nstd; j++) {
			ohci_soft_td_t *cur = ohci_alloc_std(sc);
			if (cur == NULL)
				goto nomem;

	-		ox->ox_stds[j++] = cur;
	+		ox->ox_stds[j] = cur;
	+		cur->held = &ox->ox_stds[j];
			cur->xfer = xfer;
			cur->flags = 0;
	+		DPRINTFN(10, "xfer=%#jx new std=%#jx held at %#jx", ox, cur,
	+		    cur->held, 0);
		}

		return 0;
	@@ -788,6 +794,7 @@ ohci_init(ohci_softc_t *sc)

		mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
		mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB);
	+	cv_init(&sc->sc_softwake_cv, "ohciab");

		sc->sc_rhsc_si = softint_establish(SOFTINT_USB | SOFTINT_MPSAFE,
		    ohci_rhsc_softint, sc);
	@@ -797,6 +804,8 @@ ohci_init(ohci_softc_t *sc)
		for (i = 0; i < OHCI_HASH_SIZE; i++)
			LIST_INIT(&sc->sc_hash_itds[i]);

	+	TAILQ_INIT(&sc->sc_abortingxfers);
	+
		sc->sc_xferpool = pool_cache_init(sizeof(struct ohci_xfer), 0, 0, 0,
		    "ohcixfer", NULL, IPL_USB, NULL, NULL, NULL);

	@@ -1334,12 +1343,26 @@ ohci_intr1(ohci_softc_t *sc)
			 */
			softint_schedule(sc->sc_rhsc_si);
		}
	+	if (eintrs & OHCI_SF) {
	+		struct ohci_xfer *ox, *tmp;
	+		TAILQ_FOREACH_SAFE(ox, &sc->sc_abortingxfers, ox_abnext, tmp) {
	+			DPRINTFN(10, "SF %#jx xfer %#jx", (uintptr_t)sc, (uintptr_t)ox, 0, 0);
	+			ox->ox_abintrs &= ~OHCI_SF;
	+			KASSERT(ox->ox_abintrs == 0);
	+			TAILQ_REMOVE(&sc->sc_abortingxfers, ox, ox_abnext);
	+		}
	+		cv_broadcast(&sc->sc_softwake_cv);
	+
	+		KASSERT(TAILQ_EMPTY(&sc->sc_abortingxfers));
	+		DPRINTFN(10, "end SOF %#jx", (uintptr_t)sc, 0, 0, 0);
	+		/* Don't remove OHIC_SF from eintrs so it is blocked below */
	+	}

		if (eintrs != 0) {
			/* Block unprocessed interrupts. */
			OWRITE4(sc, OHCI_INTERRUPT_DISABLE, eintrs);
			sc->sc_eintrs &= ~eintrs;
	-		DPRINTF("sc %#jx blocking intrs 0x%jx", (uintptr_t)sc,
	+		DPRINTF("sc %#jx blocking/removing intrs 0x%jx", (uintptr_t)sc,
			    eintrs, 0, 0);
		}

	@@ -1391,12 +1414,22 @@ ohci_softintr(void *v)
		struct ohci_pipe *opipe;
		int len, cc;
		int i, j, actlen, iframes, uedir;
	-	ohci_physaddr_t done;
	+	ohci_physaddr_t done = 0;

		KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));

		OHCIHIST_FUNC(); OHCIHIST_CALLED();

	+	/*
	+	 * Only read hccadone if WDH is set - we might get here from places
	+	 * other than an interrupt
	+	 */
	+	if (!(OREAD4(sc, OHCI_INTERRUPT_STATUS) & OHCI_WDH)) {
	+		DPRINTFN(10, "no WDH %#jx", (uintptr_t)sc, 0, 0, 0);
	+		return;
	+	}
	+
	+	DPRINTFN(10, "WDH %#jx", (uintptr_t)sc, 0, 0, 0);
		usb_syncmem(&sc->sc_hccadma, offsetof(struct ohci_hcca, hcca_done_head),
		    sizeof(sc->sc_hcca->hcca_done_head),
		    BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
	@@ -1451,9 +1484,8 @@ ohci_softintr(void *v)
		for (std = sdone; std; std = stdnext) {
			xfer = std->xfer;
			stdnext = std->dnext;
	-		DPRINTFN(10, "std=%#jx xfer=%#jx hcpriv=%#jx", (uintptr_t)std,
	-		    (uintptr_t)xfer, (uintptr_t)(xfer ? xfer->ux_hcpriv : 0),
	-		    0);
	+		DPRINTFN(10, "std=%#jx xfer=%#jx hcpriv=%#jx dnext=%#jx", (uintptr_t)std,
	+		    (uintptr_t)xfer, (uintptr_t)(xfer ? xfer->ux_hcpriv : 0), (uintptr_t)stdnext);
			if (xfer == NULL) {
				/*
				 * xfer == NULL: There seems to be no xfer associated
	@@ -1463,25 +1495,25 @@ ohci_softintr(void *v)
				 */
				continue;
			}
	-
	-		/*
	-		 * If software has completed it, either by cancellation
	-		 * or timeout, drop it on the floor.
	-		 */
	-		if (xfer->ux_status != USBD_IN_PROGRESS) {
	-			KASSERT(xfer->ux_status == USBD_CANCELLED ||
	-			    xfer->ux_status == USBD_TIMEOUT);
	+		if (std->held == NULL) {
	+			DPRINTFN(10, "std=%#jx held is null", (uintptr_t)std, 0, 0, 0);
	+			ohci_hash_rem_td(sc, std);
	+			ohci_free_std_locked(sc, std);
				continue;
			}
	-
			/*
	-		 * Cancel the timeout and the task, which have not yet
	-		 * run.  If they have already fired, at worst they are
	-		 * waiting for the lock.  They will see that the xfer
	-		 * is no longer in progress and give up.
	+		 * Make sure the timeout handler didn't run or ran to the end
	+		 * and set the transfer status.
			 */
	-		callout_stop(&xfer->ux_callout);
	-		usb_rem_task(xfer->ux_pipe->up_dev, &xfer->ux_aborttask);
	+		callout_halt(&xfer->ux_callout, &sc->sc_lock);
	+
	+		if (xfer->ux_status == USBD_CANCELLED ||
	+		    xfer->ux_status == USBD_TIMEOUT) {
	+			DPRINTF("cancel/timeout %#jx", (uintptr_t)xfer, 0, 0, 0);
	+
	+			/* Handled by abort routine. */
	+			continue;
	+		}

			len = std->len;
			if (std->td.td_cbp != 0)
	@@ -1552,26 +1584,12 @@ ohci_softintr(void *v)
			    0);
			if (xfer == NULL)
				continue;
	-
	-		/*
	-		 * If software has completed it, either by cancellation
	-		 * or timeout, drop it on the floor.
	-		 */
	-		if (xfer->ux_status != USBD_IN_PROGRESS) {
	-			KASSERT(xfer->ux_status == USBD_CANCELLED ||
	-			    xfer->ux_status == USBD_TIMEOUT);
	+		if (xfer->ux_status == USBD_CANCELLED ||
	+		    xfer->ux_status == USBD_TIMEOUT) {
	+			DPRINTF("cancel/timeout %#jx", (uintptr_t)xfer, 0, 0, 0);
	+			/* Handled by abort routine. */
				continue;
			}
	-
	-		/*
	-		 * Cancel the timeout and the task, which have not yet
	-		 * run.  If they have already fired, at worst they are
	-		 * waiting for the lock.  They will see that the xfer
	-		 * is no longer in progress and give up.
	-		 */
	-		callout_stop(&xfer->ux_callout);
	-		usb_rem_task(xfer->ux_pipe->up_dev, &xfer->ux_aborttask);
	-
			KASSERT(!sitd->isdone);
	 #ifdef DIAGNOSTIC
			sitd->isdone = true;
	@@ -1913,17 +1931,33 @@ ohci_hash_find_itd(ohci_softc_t *sc, ohc
	 void
	 ohci_timeout(void *addr)
	 {
	-	OHCIHIST_FUNC(); OHCIHIST_CALLED();
		struct usbd_xfer *xfer = addr;
		ohci_softc_t *sc = OHCI_XFER2SC(xfer);
	-	struct usbd_device *dev = xfer->ux_pipe->up_dev;
	+	bool timeout = false;

	+	OHCIHIST_FUNC(); OHCIHIST_CALLED();
		DPRINTF("xfer=%#jx", (uintptr_t)xfer, 0, 0, 0);

		mutex_enter(&sc->sc_lock);
	-	if (!sc->sc_dying && xfer->ux_status == USBD_IN_PROGRESS)
	-		usb_add_task(dev, &xfer->ux_aborttask, USB_TASKQ_HC);
	+	if (sc->sc_dying) {
	+		ohci_abort_xfer(xfer, USBD_TIMEOUT);
	+		mutex_exit(&sc->sc_lock);
	+		return;
	+	}
	+
	+	if (xfer->ux_status != USBD_CANCELLED) {
	+		xfer->ux_status = USBD_TIMEOUT;
	+		timeout = true;
	+	}
		mutex_exit(&sc->sc_lock);
	+ 
	+	if (timeout) {
	+		/* Execute the abort in a process context. */
	+		usb_init_task(&xfer->ux_aborttask, ohci_timeout_task, addr,
	+		    USB_TASKQ_MPSAFE);
	+		usb_add_task(xfer->ux_pipe->up_dev, &xfer->ux_aborttask,
	+		    USB_TASKQ_HC);
	+	}
	 }

	 void
	@@ -2095,6 +2129,7 @@ ohci_open(struct usbd_pipe *pipe)
					goto bad;

				opipe->tail.itd = sitd;
	+			sitd->held = &opipe->tail.itd;
				tdphys = sitd->physaddr;
				fmt = OHCI_ED_FORMAT_ISO;
				if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN)
	@@ -2107,6 +2142,7 @@ ohci_open(struct usbd_pipe *pipe)
					goto bad;

				opipe->tail.td = std;
	+			std->held = &opipe->tail.td;
				tdphys = std->physaddr;
				fmt = OHCI_ED_FORMAT_GEN | OHCI_ED_DIR_TD;
			}
	@@ -2236,67 +2272,65 @@ ohci_close_pipe(struct usbd_pipe *pipe, 
	 void
	 ohci_abort_xfer(struct usbd_xfer *xfer, usbd_status status)
	 {
	-	OHCIHIST_FUNC(); OHCIHIST_CALLED();
		struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe);
		ohci_softc_t *sc = OHCI_XFER2SC(xfer);
		ohci_soft_ed_t *sed = opipe->sed;
		ohci_soft_td_t *p, *n;
		ohci_physaddr_t headp;
		int hit;
	+	int wake;

	-	KASSERTMSG((status == USBD_CANCELLED || status == USBD_TIMEOUT),
	-	    "invalid status for abort: %d", (int)status);
	-
	+	OHCIHIST_FUNC(); OHCIHIST_CALLED();
		DPRINTF("xfer=%#jx pipe=%#jx sed=%#jx", (uintptr_t)xfer,
		    (uintptr_t)opipe, (uintptr_t)sed, 0);

		KASSERT(mutex_owned(&sc->sc_lock));
		ASSERT_SLEEPABLE();

	-	if (status == USBD_CANCELLED) {
	-		/*
	-		 * We are synchronously aborting.  Try to stop the
	-		 * callout and task, but if we can't, wait for them to
	-		 * complete.
	-		 */
	+	if (sc->sc_dying) {
	+		/* If we're dying, just do the software part. */
	+		KASSERT(xfer->ux_status == status);
			callout_halt(&xfer->ux_callout, &sc->sc_lock);
	-		usb_rem_task_wait(xfer->ux_pipe->up_dev, &xfer->ux_aborttask,
	-		    USB_TASKQ_HC, &sc->sc_lock);
	-	} else {
	-		/* Otherwise, we are timing out.  */
	-		KASSERT(status == USBD_TIMEOUT);
	+		usb_transfer_complete(xfer);
	+		return;
		}

		/*
	-	 * The xfer cannot have been cancelled already.  It is the
	-	 * responsibility of the caller of usbd_abort_pipe not to try
	-	 * to abort a pipe multiple times, whether concurrently or
	-	 * sequentially.
	+	 * If an abort is already in progress then just wait for it to
	+	 * complete and return.
		 */
	-	KASSERT(xfer->ux_status != USBD_CANCELLED);
	-
	-	/* Only the timeout, which runs only once, can time it out.  */
	-	KASSERT(xfer->ux_status != USBD_TIMEOUT);
	-
	-	/* If anyone else beat us, we're done.  */
	-	if (xfer->ux_status != USBD_IN_PROGRESS)
	-		return;
	-
	-	/* We beat everyone else.  Claim the status.  */
	-	xfer->ux_status = status;
	+	if (xfer->ux_hcflags & UXFER_ABORTING) {
	+		DPRINTFN(2, "already aborting", 0, 0, 0, 0);
	+#ifdef DIAGNOSTIC
	+		if (status == USBD_TIMEOUT)
	+			printf("%s: TIMEOUT while aborting\n", __func__);
	+#endif
	+		/* Override the status which might be USBD_TIMEOUT. */
	+		xfer->ux_status = status;
	+		DPRINTFN(2, "waiting for abort to finish", 0, 0, 0, 0);
	+		xfer->ux_hcflags |= UXFER_ABORTWAIT;
	+		while (xfer->ux_hcflags & UXFER_ABORTING)
	+			cv_wait(&xfer->ux_hccv, &sc->sc_lock);
	+		goto done;
	+	}
	+	xfer->ux_hcflags |= UXFER_ABORTING;

		/*
	-	 * If we're dying, skip the hardware action and just notify the
	-	 * software that we're done.
	+	 * Step 1: When cancelling a transfer make sure the timeout handler
	+	 * didn't run or ran to the end and saw the USBD_CANCELLED status.
	+	 * Otherwise we must have got here via a timeout.
	+	 *
	+	 * If we timed out then
		 */
	-	if (sc->sc_dying) {
	-		DPRINTFN(4, "xfer %#jx dying %ju", (uintptr_t)xfer,
	-		    xfer->ux_status, 0, 0);
	-		goto dying;
	+	if (status == USBD_CANCELLED) {
	+		xfer->ux_status = status;
	+		callout_halt(&xfer->ux_callout, &sc->sc_lock);
	+	} else {
	+		KASSERT(xfer->ux_status == USBD_TIMEOUT);
		}

		/*
	-	 * HC Step 1: Unless the endpoint is already halted, we set the endpoint
	+	 * Step 2: Unless the endpoint is already halted, we set the endpoint
		 * descriptor sKip bit and wait for hardware to complete processing.
		 *
		 * This includes ensuring that any TDs of the transfer that got onto
	@@ -2307,20 +2341,39 @@ ohci_abort_xfer(struct usbd_xfer *xfer, 
		usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags),
		    sizeof(sed->ed.ed_flags),
		    BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
	-	sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); /* force hardware skip */
	-	usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags),
	-	    sizeof(sed->ed.ed_flags),
	-	    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
	+	if (!(sed->ed.ed_flags & OHCI_HALTED)) {
	+		/* force hardware skip */
	+		DPRINTFN(1, "pausing ed=%#jx", (uintptr_t)sed, 0, 0, 0);
	+		sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP);
	+		usb_syncmem(&sed->dma,
	+		    sed->offs + offsetof(ohci_ed_t, ed_flags),
	+		    sizeof(sed->ed.ed_flags),
	+		    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);

	-	/*
	-	 * HC Step 2: Wait until we know hardware has finished any possible
	-	 * use of the xfer.
	-	 */
	-	/* Hardware finishes in 1ms */
	-	usb_delay_ms_locked(opipe->pipe.up_dev->ud_bus, 20, &sc->sc_lock);
	+		DPRINTFN(10, "WDH %#jx xfer %#jx", (uintptr_t)sc, (uintptr_t)xfer,
	+		    0, 0);
	+		struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer);
	+		ox->ox_abintrs = OHCI_SF;
	+		TAILQ_INSERT_TAIL(&sc->sc_abortingxfers, ox, ox_abnext);
	+
	+		OWRITE4(sc, OHCI_INTERRUPT_STATUS, OHCI_SF);
	+		sc->sc_eintrs |= OHCI_SF;
	+		OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_SF);
	+		/*
	+		 * Step 2: Wait until we know hardware has finished any possible
	+		 * use of the xfer.
	+		 */
	+		while (ox->ox_abintrs != 0) {
	+			DPRINTFN(10, "WDH %#jx xfer %#jx intrs %#x", (uintptr_t)sc,
	+			    (uintptr_t)xfer, ox->ox_abintrs, 0);
	+			cv_wait(&sc->sc_softwake_cv, &sc->sc_lock);
	+		}
	+	} else {
	+  		DPRINTFN(1, "halted ed=%#jx", (uintptr_t)sed, 0, 0, 0);
	+	}

		/*
	-	 * HC Step 3: Remove any vestiges of the xfer from the hardware.
	+	 * Step 3: Remove any vestiges of the xfer from the hardware.
		 * The complication here is that the hardware may have executed
		 * beyond the xfer we're trying to abort.  So as we're scanning
		 * the TDs of this xfer we check if the hardware points to
	@@ -2339,12 +2392,36 @@ ohci_abort_xfer(struct usbd_xfer *xfer, 
		}
		DPRINTF("--- dump end ---", 0, 0, 0, 0);
	 #endif
	+
	+#define OHCI_CC_ACCESSED_P(x)		(((x) & OHCI_CC_NOT_ACCESSED_MASK) != OHCI_CC_NOT_ACCESSED)
		headp = O32TOH(sed->ed.ed_headp) & OHCI_HEADMASK;
		hit = 0;
		for (; p->xfer == xfer; p = n) {
			hit |= headp == p->physaddr;
			n = p->nexttd;
	-		ohci_hash_rem_td(sc, p);
	+
	+		int cc = OHCI_TD_GET_CC(O32TOH(p->td.td_flags));
	+		if (!OHCI_CC_ACCESSED_P(cc)) {
	+			ohci_hash_rem_td(sc, p);
	+			continue;
	+		}
	+		DPRINTFN(10, "std=%#jx has been touched by HC", (uintptr_t)p,
	+		    0, 0, 0);
	+
	+		mutex_exit(&sc->sc_lock);
	+		ohci_soft_td_t *std = ohci_alloc_std(sc);
	+		if (std == NULL) {
	+			/* XXX What to do??? */
	+			panic("hmm");
	+		}
	+		mutex_enter(&sc->sc_lock);
	+
	+		DPRINTFN(10, "new std=%#jx now held at %#jx", (uintptr_t)std,
	+		    (uintptr_t)p->held, 0, 0);
	+		*(p->held) = std;
	+		std->held = p->held;
	+		std->xfer = xfer;
	+		p->held = NULL;
		}
		/* Zap headp register if hardware pointed inside the xfer. */
		if (hit) {
	@@ -2360,7 +2437,7 @@ ohci_abort_xfer(struct usbd_xfer *xfer, 
		}

		/*
	-	 * HC Step 4: Turn on hardware again.
	+	 * Step 4: Turn on hardware again.
		 */
		usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags),
		    sizeof(sed->ed.ed_flags),
	@@ -2371,12 +2448,15 @@ ohci_abort_xfer(struct usbd_xfer *xfer, 
		    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);

		/*
	-	 * Final step: Notify completion to waiting xfers.
	+	 * Step 5: Execute callback.
		 */
	-dying:
	+	wake = xfer->ux_hcflags & UXFER_ABORTWAIT;
	+	xfer->ux_hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT);
		usb_transfer_complete(xfer);
	-	DPRINTFN(14, "end", 0, 0, 0, 0);
	+	if (wake)
	+		cv_broadcast(&xfer->ux_hccv);

	+done:
		KASSERT(mutex_owned(&sc->sc_lock));
	 }

	@@ -2607,17 +2687,14 @@ Static usbd_status
	 ohci_root_intr_start(struct usbd_xfer *xfer)
	 {
		ohci_softc_t *sc = OHCI_XFER2SC(xfer);
	-	const bool polling = sc->sc_bus.ub_usepolling;

		if (sc->sc_dying)
			return USBD_IOERROR;

	-	if (!polling)
	-		mutex_enter(&sc->sc_lock);
	+	mutex_enter(&sc->sc_lock);
		KASSERT(sc->sc_intrxfer == NULL);
		sc->sc_intrxfer = xfer;
	-	if (!polling)
	-		mutex_exit(&sc->sc_lock);
	+	mutex_exit(&sc->sc_lock);

		return USBD_IN_PROGRESS;
	 }
	@@ -2677,6 +2754,13 @@ ohci_device_ctrl_init(struct usbd_xfer *
		ox->ox_setup = setup;
		ox->ox_stat = stat;
		ox->ox_nstd = 0;
	+	setup->held = &ox->ox_setup;
	+	stat->held = &ox->ox_stat;
	+
	+	DPRINTFN(10, "xfer=%#jx setup=%#jx held at %#jx", (uintptr_t)ox,
	+	    (uintptr_t)setup, (uintptr_t)setup->held, 0);
	+	DPRINTFN(10, "xfer=%#jx stat= %#jx held at %#jx", (uintptr_t)ox,
	+	    (uintptr_t)stat, (uintptr_t)stat->held, 0);

		/* Set up data transaction */
		if (len != 0) {
	@@ -2753,7 +2837,6 @@ ohci_device_ctrl_start(struct usbd_xfer 
		ohci_soft_ed_t *sed;
		int isread;
		int len;
	-	const bool polling = sc->sc_bus.ub_usepolling;

		OHCIHIST_FUNC(); OHCIHIST_CALLED();

	@@ -2772,8 +2855,7 @@ ohci_device_ctrl_start(struct usbd_xfer 
		    UGETW(req->wIndex));

		/* Need to take lock here for pipe->tail.td */
	-	if (!polling)
	-		mutex_enter(&sc->sc_lock);
	+	mutex_enter(&sc->sc_lock);

		/*
		 * Use the pipe "tail" TD as our first and loan our first TD to the
	@@ -2782,13 +2864,21 @@ ohci_device_ctrl_start(struct usbd_xfer 
		setup = opipe->tail.td;
		opipe->tail.td = ox->ox_setup;
		ox->ox_setup = setup;
	+	setup->held = &ox->ox_setup;
	+
	+	DPRINTFN(10, "xfer=%#jx new setup=%#jx held at %#jx", (uintptr_t)ox,
	+	    (uintptr_t)setup, (uintptr_t)setup->held, 0);

		stat = ox->ox_stat;

		/* point at sentinel */
		tail = opipe->tail.td;
	+	tail->held = &opipe->tail.td;
		sed = opipe->sed;

	+	DPRINTFN(10, "xfer=%#jx new tail=%#jx held at %#jx", (uintptr_t)ox,
	+	    (uintptr_t)tail, (uintptr_t)tail->held, 0);
	+
		KASSERTMSG(OHCI_ED_GET_FA(O32TOH(sed->ed.ed_flags)) == dev->ud_addr,
		    "address ED %d pipe %d\n",
		    OHCI_ED_GET_FA(O32TOH(sed->ed.ed_flags)), dev->ud_addr);
	@@ -2889,7 +2979,7 @@ ohci_device_ctrl_start(struct usbd_xfer 
		    sizeof(sed->ed.ed_tailp),
		    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
		OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF);
	-	if (xfer->ux_timeout && !polling) {
	+	if (xfer->ux_timeout && !sc->sc_bus.ub_usepolling) {
			callout_reset(&xfer->ux_callout, mstohz(xfer->ux_timeout),
				    ohci_timeout, xfer);
		}
	@@ -2897,8 +2987,7 @@ ohci_device_ctrl_start(struct usbd_xfer 
		DPRINTF("done", 0, 0, 0, 0);

		xfer->ux_status = USBD_IN_PROGRESS;
	-	if (!polling)
	-		mutex_exit(&sc->sc_lock);
	+	mutex_exit(&sc->sc_lock);

		return USBD_IN_PROGRESS;
	 }
	@@ -3027,7 +3116,6 @@ ohci_device_bulk_start(struct usbd_xfer 
		ohci_soft_td_t *data, *tail, *tdp;
		ohci_soft_ed_t *sed;
		int len, isread, endpt;
	-	const bool polling = sc->sc_bus.ub_usepolling;

		OHCIHIST_FUNC(); OHCIHIST_CALLED();

	@@ -3045,8 +3133,7 @@ ohci_device_bulk_start(struct usbd_xfer 
		    len, isread, xfer->ux_flags);
		DPRINTFN(4, "endpt=%jd", endpt, 0, 0, 0);

	-	if (!polling)
	-		mutex_enter(&sc->sc_lock);
	+	mutex_enter(&sc->sc_lock);

		/*
		 * Use the pipe "tail" TD as our first and loan our first TD to the
	@@ -3055,13 +3142,19 @@ ohci_device_bulk_start(struct usbd_xfer 
		data = opipe->tail.td;
		opipe->tail.td = ox->ox_stds[0];
		ox->ox_stds[0] = data;
	+	data->held = &ox->ox_stds[0];
		ohci_reset_std_chain(sc, xfer, len, isread, data, &last);
	+	DPRINTFN(10, "xfer=%#jx new data=%#jx held at %#jx", (uintptr_t)ox,
	+	    (uintptr_t)data, (uintptr_t)data->held, 0);

		/* point at sentinel */
		tail = opipe->tail.td;
		memset(&tail->td, 0, sizeof(tail->td));
	+	tail->held = &opipe->tail.td;
		tail->nexttd = NULL;
		tail->xfer = NULL;
	+	DPRINTFN(10, "xfer=%#jx new tail=%#jx held at %#jx", (uintptr_t)ox,
	+	    (uintptr_t)tail, (uintptr_t)tail->held, 0);
		usb_syncmem(&tail->dma, tail->offs, sizeof(tail->td),
		    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
		xfer->ux_hcpriv = data;
	@@ -3112,8 +3205,7 @@ ohci_device_bulk_start(struct usbd_xfer 
		}

		xfer->ux_status = USBD_IN_PROGRESS;
	-	if (!polling)
	-		mutex_exit(&sc->sc_lock);
	+	mutex_exit(&sc->sc_lock);

		return USBD_IN_PROGRESS;
	 }
	@@ -3232,7 +3324,6 @@ ohci_device_intr_start(struct usbd_xfer 
		ohci_soft_ed_t *sed = opipe->sed;
		ohci_soft_td_t *data, *last, *tail;
		int len, isread, endpt;
	-	const bool polling = sc->sc_bus.ub_usepolling;

		OHCIHIST_FUNC(); OHCIHIST_CALLED();

	@@ -3248,8 +3339,7 @@ ohci_device_intr_start(struct usbd_xfer 
		endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress;
		isread = UE_GET_DIR(endpt) == UE_DIR_IN;

	-	if (!polling)
	-		mutex_enter(&sc->sc_lock);
	+	mutex_enter(&sc->sc_lock);

		/*
		 * Use the pipe "tail" TD as our first and loan our first TD to the
	@@ -3258,13 +3348,19 @@ ohci_device_intr_start(struct usbd_xfer 
		data = opipe->tail.td;
		opipe->tail.td = ox->ox_stds[0];
		ox->ox_stds[0] = data;
	+	data->held = &ox->ox_stds[0];
		ohci_reset_std_chain(sc, xfer, len, isread, data, &last);
	+	DPRINTFN(10, "xfer=%#jx new data=%#jx held at %#jx", (uintptr_t)ox,
	+	    (uintptr_t)data, (uintptr_t)data->held, 0);

		/* point at sentinel */
		tail = opipe->tail.td;
		memset(&tail->td, 0, sizeof(tail->td));
	+	tail->held = &opipe->tail.td;
		tail->nexttd = NULL;
		tail->xfer = NULL;
	+	DPRINTFN(10, "xfer=%#jx new tail=%#jx held at %#jx", (uintptr_t)ox,
	+	    (uintptr_t)tail, (uintptr_t)tail->held, 0);
		usb_syncmem(&tail->dma, tail->offs, sizeof(tail->td),
		    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
		xfer->ux_hcpriv = data;
	@@ -3301,8 +3397,7 @@ ohci_device_intr_start(struct usbd_xfer 
		    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);

		xfer->ux_status = USBD_IN_PROGRESS;
	-	if (!polling)
	-		mutex_exit(&sc->sc_lock);
	+	mutex_exit(&sc->sc_lock);

		return USBD_IN_PROGRESS;
	 }
	@@ -3467,8 +3562,10 @@ ohci_device_isoc_init(struct usbd_xfer *
				goto fail;
			}
			ox->ox_sitds[i] = sitd;
	+		sitd->held = &ox->ox_sitds[i];
			sitd->xfer = xfer;
			sitd->flags = 0;
	+//		DPRINTFN(10, "xfer=%#jx new tail=%#jx held at %#jx", (uintptr_t)ox, (uintptr_t)tail, (uintptr_t)tail->held, 0);
		}

		return 0;
	@@ -3562,6 +3659,7 @@ ohci_device_isoc_enter(struct usbd_xfer 
		sitd = opipe->tail.itd;
		opipe->tail.itd = ox->ox_sitds[0];
		ox->ox_sitds[0] = sitd;
	+	sitd->held = &ox->ox_sitds[0];

		buf = DMAADDR(&xfer->ux_dmabuf, 0);
		bp0 = OHCI_PAGE(buf);
	@@ -3612,6 +3710,7 @@ ohci_device_isoc_enter(struct usbd_xfer 
		/* point at sentinel */
		tail = opipe->tail.itd;
		memset(&tail->itd, 0, sizeof(tail->itd));
	+	tail->held = &opipe->tail.itd;
		tail->nextitd = NULL;
		tail->xfer = NULL;
		usb_syncmem(&tail->dma, tail->offs, sizeof(tail->itd),

>Release-Note:

>Audit-Trail:

Responsible-Changed-From-To: kern-bug-people->skrll
Responsible-Changed-By: skrll@NetBSD.org
Responsible-Changed-When: Sat, 05 Dec 2020 08:20:46 +0000
Responsible-Changed-Why:
Take


From: "Nick Hudson" <skrll@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/55835 CVS commit: src/sys/dev/usb
Date: Wed, 9 Dec 2020 07:10:02 +0000

 Module Name:	src
 Committed By:	skrll
 Date:		Wed Dec  9 07:10:01 UTC 2020

 Modified Files:
 	src/sys/dev/usb: ohci.c ohcivar.h

 Log Message:
 Restructure the abort code for TD based transfers (ctrl, bulk, intr).

 In PR kern/22646 some TDs can be on the done queue when the abort start
 and, if this is the case, they need to processed after the WDH interrupt.
 Instead of waiting for WDH we release TDs that have been touched by the
 HC and replace them with new ones.  Once WDH happens the floating TDs
 will be returned to the free list.

 Also addresses the issue seen in PR kern/55835

 Thanks to both Andreas Gustafsson and Edgar Fuß for testing.  Apologies to
 Andreas Gustafsson for not committing this to HEAD for 4y6m.w


 To generate a diff of this commit:
 cvs rdiff -u -r1.310 -r1.311 src/sys/dev/usb/ohci.c
 cvs rdiff -u -r1.61 -r1.62 src/sys/dev/usb/ohcivar.h

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

State-Changed-From-To: open->pending-pullups
State-Changed-By: skrll@NetBSD.org
State-Changed-When: Sat, 12 Dec 2020 17:01:00 +0000
State-Changed-Why:
[pullup-8 #1637]
[pullup-9 #1150]


From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/55835 CVS commit: [netbsd-9] src/sys/dev/usb
Date: Sat, 12 Dec 2020 20:29:11 +0000

 Module Name:	src
 Committed By:	martin
 Date:		Sat Dec 12 20:29:11 UTC 2020

 Modified Files:
 	src/sys/dev/usb [netbsd-9]: ohci.c ohcivar.h

 Log Message:
 Pull up following revision(s) (requested by skrll in ticket #1150):

 	sys/dev/usb/ohci.c: revision 1.311
 	sys/dev/usb/ohci.c: revision 1.312
 	sys/dev/usb/ohcivar.h: revision 1.62

 Restructure the abort code for TD based transfers (ctrl, bulk, intr).

 In PR kern/22646 some TDs can be on the done queue when the abort start
 and, if this is the case, they need to processed after the WDH interrupt.
 Instead of waiting for WDH we release TDs that have been touched by the
 HC and replace them with new ones.  Once WDH happens the floating TDs
 will be returned to the free list.

 Also addresses the issue seen in PR kern/55835

 Thanks to both Andreas Gustafsson and Edgar Fu=C3=9F for testing.  Apologi=
 es to
 Andreas Gustafsson for not committing this to HEAD for 4y6m.w

 Remove leading space that crept in in the last change


 To generate a diff of this commit:
 cvs rdiff -u -r1.289.4.5 -r1.289.4.6 src/sys/dev/usb/ohci.c
 cvs rdiff -u -r1.60 -r1.60.6.1 src/sys/dev/usb/ohcivar.h

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/55835 CVS commit: [netbsd-8] src/sys/dev/usb
Date: Sat, 12 Dec 2020 20:30:57 +0000

 Module Name:	src
 Committed By:	martin
 Date:		Sat Dec 12 20:30:57 UTC 2020

 Modified Files:
 	src/sys/dev/usb [netbsd-8]: ohci.c ohcivar.h

 Log Message:
 Pull up following revision(s) (requested by skrll in ticket #1637):

 	sys/dev/usb/ohci.c: revision 1.311
 	sys/dev/usb/ohci.c: revision 1.312
 	sys/dev/usb/ohcivar.h: revision 1.62

 Restructure the abort code for TD based transfers (ctrl, bulk, intr).

 In PR kern/22646 some TDs can be on the done queue when the abort start
 and, if this is the case, they need to processed after the WDH interrupt.
 Instead of waiting for WDH we release TDs that have been touched by the
 HC and replace them with new ones.  Once WDH happens the floating TDs
 will be returned to the free list.

 Also addresses the issue seen in PR kern/55835

 Thanks to both Andreas Gustafsson and Edgar Fu=C3=9F for testing.  Apologi=
 es to
 Andreas Gustafsson for not committing this to HEAD for 4y6m.w

 Remove leading space that crept in in the last change


 To generate a diff of this commit:
 cvs rdiff -u -r1.273.6.6 -r1.273.6.7 src/sys/dev/usb/ohci.c
 cvs rdiff -u -r1.58.10.1 -r1.58.10.2 src/sys/dev/usb/ohcivar.h

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

State-Changed-From-To: pending-pullups->feedback
State-Changed-By: skrll@NetBSD.org
State-Changed-When: Fri, 18 Dec 2020 14:15:27 +0000
State-Changed-Why:
ok to close?


From: Edgar =?iso-8859-1?B?RnXf?= <ef@math.uni-bonn.de>
To: gnats-bugs@netbsd.org
Cc: 
Subject: Re: kern/55835 (circular done list in ohci_softint())
Date: Fri, 18 Dec 2020 16:31:18 +0100

 > ok to close?
 I guess yes.

State-Changed-From-To: feedback->closed
State-Changed-By: skrll@NetBSD.org
State-Changed-When: Fri, 18 Dec 2020 22:29:22 +0000
State-Changed-Why:
submitter confirmed


>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.46 2020/01/03 16:35:01 leot Exp $
$NetBSD: gnats_config.sh,v 1.9 2014/08/02 14:16:04 spz Exp $
Copyright © 1994-2020 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.