Re: USB Disconnects / resets after commit b963801164618e25fbdc0cd452ce49c3628b46c8

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

 



On 17 June 2011 18:27, Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> wrote:
> On Wed, 15 Jun 2011, Matej Kenda wrote:
>
>> Patched Linux kernel is now being used on four systems (COMe type) for
>> almost two weeks. USB disk where the complete OS is installed did not
>> unexpectedly disconnect on any of these embedded devices.
>>
>> It seems that the your patch solves the problem.
>
> I've got a new version of this patch for you to test.  In some respects
> it simplifies things compared to the old patch.  (It looks worse than
> it really is because as part of the simplification, a whole chunk of
> code got moved out one indentation level.)
>
> Let me know what happens with it.  I think this will apply to 3.0-rc3,
> and it should apply to earlier kernels with only minor adjustments.
> (Fair warning: I haven't tried this on my own system yet.)

The patch was adapted for 3.6.38 (Ubuntu Natty).

I will install patched kernel and run it for some time.

Please find attached modified patch that applies to 2.6.38.

Regards,

Matej
diff --git a/debian.master/changelog b/debian.master/changelog
index 6a9f46e..65549e0 100644
--- a/debian.master/changelog
+++ b/debian.master/changelog
@@ -1,3 +1,12 @@
+linux (2.6.38-10.299) natty; urgency=low
+
+  [ Alan Stern ]
+
+  * Patch for unwanted USB disconnect
+    - LP: #701011
+
+ -- Matej Kenda <matejken@xxxxxxxxx>  Mon, 20 Jun 2011 09:50:22 +0200
+
 linux (2.6.38-10.44) natty-proposed; urgency=low
 
   [ Steve Conklin ]
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 74dcf49..65a40e9 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -90,7 +90,8 @@ static const char	hcd_name [] = "ehci_hcd";
 #define EHCI_IAA_MSECS		10		/* arbitrary */
 #define EHCI_IO_JIFFIES		(HZ/10)		/* io watchdog > irq_thresh */
 #define EHCI_ASYNC_JIFFIES	(HZ/20)		/* async idle timeout */
-#define EHCI_SHRINK_FRAMES	5		/* async qh unlink delay */
+#define EHCI_SHRINK_JIFFIES	(DIV_ROUND_UP(HZ, 200) + 1)
+						/* async qh unlink delay */
 
 /* Initial IRQ latency:  faster than hw default */
 static int log2_irq_thresh = 0;		// 0 to 6
@@ -150,10 +151,7 @@ timer_action(struct ehci_hcd *ehci, enum ehci_timer_action action)
 			break;
 		/* case TIMER_ASYNC_SHRINK: */
 		default:
-			/* add a jiffie since we synch against the
-			 * 8 KHz uframe counter.
-			 */
-			t = DIV_ROUND_UP(EHCI_SHRINK_FRAMES * HZ, 1000) + 1;
+			t = EHCI_SHRINK_JIFFIES;
 			break;
 		}
 		mod_timer(&ehci->watchdog, t + jiffies);
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index baf7362..8be6351 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -988,6 +988,8 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 	/* splice right after start */
 	qh->qh_next = head->qh_next;
 	qh->hw->hw_next = head->hw->hw_next;
+	if (ehci->qh_scan_next == qh)
+		ehci->qh_scan_next = qh->qh_next.qh;
 	wmb ();
 
 	head->qh_next.qh = qh;
@@ -1249,53 +1251,48 @@ static void scan_async (struct ehci_hcd *ehci)
 	struct ehci_qh		*qh;
 	enum ehci_timer_action	action = TIMER_IO_WATCHDOG;
 
-	ehci->stamp = ehci_readl(ehci, &ehci->regs->frame_index);
 	timer_action_done (ehci, TIMER_ASYNC_SHRINK);
-rescan:
 	stopped = !HC_IS_RUNNING(ehci_to_hcd(ehci)->state);
-	qh = ehci->async->qh_next.qh;
-	if (likely (qh != NULL)) {
-		do {
-			/* clean any finished work for this qh */
-			if (!list_empty(&qh->qtd_list) && (stopped ||
-					qh->stamp != ehci->stamp)) {
-				int temp;
-
-				/* unlinks could happen here; completion
-				 * reporting drops the lock.  rescan using
-				 * the latest schedule, but don't rescan
-				 * qhs we already finished (no looping)
-				 * unless the controller is stopped.
-				 */
-				qh = qh_get (qh);
-				qh->stamp = ehci->stamp;
-				temp = qh_completions (ehci, qh);
-				if (qh->needs_rescan)
-					unlink_async(ehci, qh);
-				qh_put (qh);
-				if (temp != 0) {
-					goto rescan;
-				}
-			}
-
-			/* unlink idle entries, reducing DMA usage as well
-			 * as HCD schedule-scanning costs.  delay for any qh
-			 * we just scanned, there's a not-unusual case that it
-			 * doesn't stay idle for long.
-			 * (plus, avoids some kind of re-activation race.)
-			 */
-			if (list_empty(&qh->qtd_list)
-					&& qh->qh_state == QH_STATE_LINKED) {
-				if (!ehci->reclaim && (stopped ||
-					((ehci->stamp - qh->stamp) & 0x1fff)
-						>= EHCI_SHRINK_FRAMES * 8))
-					start_unlink_async(ehci, qh);
-				else
-					action = TIMER_ASYNC_SHRINK;
-			}
+	ehci->qh_scan_next = ehci->async->qh_next.qh;
+	while (ehci->qh_scan_next) {
+		qh = ehci->qh_scan_next;
+		ehci->qh_scan_next = qh->qh_next.qh;
+rescan:
+		/* clean any finished work for this qh */
+		if (!list_empty(&qh->qtd_list)) {
+			int temp;
+
+			/*
+			* Unlinks could happen here; completion reporting
+			* drops the lock.  That's why ehci->qh_scan_next
+			* always holds the next qh to scan; if the next qh
+			* gets unlinked then ehci->qh_scan_next is adjusted
+			* in start_unlink_async().
+			*/
+			qh = qh_get(qh);
+			temp = qh_completions(ehci, qh);
+			if (qh->needs_rescan)
+				unlink_async(ehci, qh);
+			qh->unlink_time = jiffies + EHCI_SHRINK_JIFFIES;
+			qh_put(qh);
+			if (temp != 0)
+				goto rescan;
+		}
 
-			qh = qh->qh_next.qh;
-		} while (qh);
+		/* unlink idle entries, reducing DMA usage as well
+		* as HCD schedule-scanning costs.  delay for any qh
+		* we just scanned, there's a not-unusual case that it
+		* doesn't stay idle for long.
+		* (plus, avoids some kind of re-activation race.)
+		*/
+		if (list_empty(&qh->qtd_list)
+				&& qh->qh_state == QH_STATE_LINKED) {
+			if (!ehci->reclaim && (stopped ||
+					time_after_eq(jiffies, qh->unlink_time)))
+				start_unlink_async(ehci, qh);
+			else
+				action = TIMER_ASYNC_SHRINK;
+		}
 	}
 	if (action == TIMER_ASYNC_SHRINK)
 		timer_action (ehci, TIMER_ASYNC_SHRINK);
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 799ac16..e0e5472 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -75,6 +75,7 @@ struct ehci_hcd {			/* one per controller */
 	struct ehci_qh		*async;
 	struct ehci_qh		*dummy;		/* For AMD quirk use */
 	struct ehci_qh		*reclaim;
+	struct ehci_qh		*qh_scan_next;
 	unsigned		scanning : 1;
 
 	/* periodic schedule support */
@@ -336,6 +337,7 @@ struct ehci_qh {
 	struct ehci_qh		*reclaim;	/* next to reclaim */
 
 	struct ehci_hcd		*ehci;
+	unsigned long		unlink_time;
 
 	/*
 	 * Do NOT use atomic operations for QH refcounting. On some CPUs

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

  Powered by Linux