Subject: kern/33454: The USB OHCI code is incorrectly using hccaDoneHead when WD is clear
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: None <ric.yeates@gmail.com>
List: netbsd-bugs
Date: 05/10/2006 10:20:54
>Number:         33454
>Category:       kern
>Synopsis:       The USB OHCI code is incorrectly using hccaDoneHead when WD is clear
>Confidential:   no
>Severity:       critical
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed May 10 10:20:53 +0000 2006
>Originator:     Ric Yeates
>Release:        HEAD
>Organization:
RadiSys Corp.
>Environment:
Not using a BSD machine, porting source code to an RTOS
>Description:
The function ohci_abort_xfer() calls usb_schedsoftintr(). usb_schedsoftintr() handles any done TDs from the hccaDoneHead. The rule is, though, that you cannot write to hccaDoneHead when the interrupt status WD bit is not set. Since WD is not set in this context, it's possible for the controller to update hccaDoneHead at the same time that ohci_softintr() is updating it. Worse than that, ohci_softintr() will acknowledge any outstanding WD interrupt. This makes it possible to miss interrupts.
>How-To-Repeat:
My problems occurred due to aborted transactions due to timeouts.
>Fix:
I don't think the call the usb_schedsoftintr() in ohci_abort_xfer() is required (unless maybe polling, don't know about that case). It has already set the SKIP bit on the ED and slept for a while, which would allow for any interrupts that add to the done queue to happen (and call usb_schedsoftintr()). My attempt at fixing the problem will be removing the usb_schedsoftintr() call from ohci_abort_xfer().