[PATCH 2/2] usb: ehci: unlink itd/sitds from hardware list if the controller has stopped periodic schedule

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



In current design, the ehci driver will not unlink itd/sitds from the
hardware list when dequeue isochronous urbs. Rather just wait until they
complete normally or their time slot expires. However, this will cause
issues if the controller has stopped periodic schedule before finished
all periodic schedule. The urb will not be done forever in this case and
then usb_kill/poison_urb() will always wait there.

The ChipIdea IP exactly has a bug: if frame babble occurs during periodic
transfer, PE (PORTSC.bit2) will be cleared and the controller will stop
periodic schedule immediately. So if the user tries to kill or poison
related urb, it will wait there since the urb can't be done forever.

This patch will check if this issue occurs, then it will unlink itd/sitds
from the hardware list depends on the result.

Signed-off-by: Xu Yang <xu.yang_2@xxxxxxx>
---
 drivers/usb/host/ehci-hcd.c | 33 ++++++++++++++++++++++++++++++++-
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index a1930db0da1c..26dc1d1ae5e8 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -930,10 +930,41 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 
 	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
 		/*
-		 * We don't expedite dequeue for isochronous URBs.
+		 * 1. We don't expedite dequeue for isochronous URBs.
 		 * Just wait until they complete normally or their
 		 * time slot expires.
+		 *
+		 * 2. The ChipIdea IP has a bug: if frame babble occurs,
+		 * PE will be cleared and the controller will stop periodic
+		 * schedule. So if we don't force dequeue this urb, it
+		 * won't be done forever. Here, a force dequeue is needed
+		 * for this case.
 		 */
+		unsigned 		i = HCS_N_PORTS (ehci->hcs_params);
+		bool 			need_force_dequeue = false;
+
+		while (i--) {
+			int pstatus;
+
+			pstatus = ehci_readl(ehci,
+					&ehci->regs->port_status[i]);
+
+			/* Any cleared PE means controller has stopped
+			 * periodic schedule.
+			 */
+			if (!(pstatus & PORT_PE)) {
+				need_force_dequeue = true;
+				break;
+			}
+		}
+
+		if (!need_force_dequeue)
+			goto done;
+
+		if (urb->dev->speed == USB_SPEED_HIGH)
+			itd_unlink_urb(ehci, urb);
+		else
+			sitd_unlink_urb(ehci, urb);
 	} else {
 		qh = (struct ehci_qh *) urb->hcpriv;
 		qh->unlink_reason |= QH_UNLINK_REQUESTED;
-- 
2.34.1




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux