[PATCH 2/4 v2] USB: EHCI: improve handling of the ehci->iaa_in_progress flag

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

 



This patch improves the way ehci-hcd handles the iaa_in_progress flag.
The current code is somewhat careless in this regard:

	The flag is meaningless when the root hub isn't running, most
	particularly after the root hub has been suspended.  But in
	start_iaa_cycle(), the driver checks the flag before checking
	the root hub's state.  They should be checked in the opposite
	order.

	That routine also sets the flag too early, before it has
	definitely committed to starting an IAA cycle.

	The flag is turned off in end_unlink_async().  Upcoming
	changes will call that routine at other times, not just at the
	end of an IAA cycle.  The two actions are logically separate
	(although related), so we separate out a new routine to be
	called in place of end_unlink_async() whenever an IAA cycle
	ends: end_iaa_cycle().

	iaa_in_progress should be turned off when the root hub is
	suspended -- we certainly don't want it still to be set when
	the root hub resumes.  Therefore the call to
	end_unlink_async() in ehci_bus_suspend() should also be
	replaced with a call to end_iaa_cycle().

Signed-off-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>

---

v2:	Move this patch before the unlink-delay patch.
	Move end_iaa_cycle() definition and usage into this patch.
	Call end_iaa_cycle() from ehci_bus_suspend(), instead of
	clearing iaa_in_progress in ehci_bus_resume().


[as1794b]


 drivers/usb/host/ehci-hcd.c   |    3 ++-
 drivers/usb/host/ehci-hub.c   |    3 ++-
 drivers/usb/host/ehci-q.c     |   28 +++++++++++++++-------------
 drivers/usb/host/ehci-timer.c |    2 +-
 4 files changed, 20 insertions(+), 16 deletions(-)

Index: usb-4.4/drivers/usb/host/ehci-hcd.c
===================================================================
--- usb-4.4.orig/drivers/usb/host/ehci-hcd.c
+++ usb-4.4/drivers/usb/host/ehci-hcd.c
@@ -306,6 +306,7 @@ static void ehci_quiesce (struct ehci_hc
 
 /*-------------------------------------------------------------------------*/
 
+static void end_iaa_cycle(struct ehci_hcd *ehci);
 static void end_unlink_async(struct ehci_hcd *ehci);
 static void unlink_empty_async(struct ehci_hcd *ehci);
 static void unlink_empty_async_suspended(struct ehci_hcd *ehci);
@@ -758,7 +759,7 @@ static irqreturn_t ehci_irq (struct usb_
 			ehci_dbg(ehci, "IAA with IAAD still set?\n");
 		if (ehci->iaa_in_progress)
 			COUNT(ehci->stats.iaa);
-		end_unlink_async(ehci);
+		end_iaa_cycle(ehci);
 	}
 
 	/* remote wakeup [4.3.1] */
Index: usb-4.4/drivers/usb/host/ehci-hub.c
===================================================================
--- usb-4.4.orig/drivers/usb/host/ehci-hub.c
+++ usb-4.4/drivers/usb/host/ehci-hub.c
@@ -347,7 +347,8 @@ static int ehci_bus_suspend (struct usb_
 		goto done;
 	ehci->rh_state = EHCI_RH_SUSPENDED;
 
-	end_unlink_async(ehci);
+	/* Any IAA cycle that started before the suspend is now invalid */
+	end_iaa_cycle(ehci);
 	unlink_empty_async_suspended(ehci);
 	ehci_handle_start_intr_unlinks(ehci);
 	ehci_handle_intr_unlinks(ehci);
Index: usb-4.4/drivers/usb/host/ehci-timer.c
===================================================================
--- usb-4.4.orig/drivers/usb/host/ehci-timer.c
+++ usb-4.4/drivers/usb/host/ehci-timer.c
@@ -361,7 +361,7 @@ static void ehci_iaa_watchdog(struct ehc
 	}
 
 	ehci_dbg(ehci, "IAA watchdog: status %x cmd %x\n", status, cmd);
-	end_unlink_async(ehci);
+	end_iaa_cycle(ehci);
 }
 
 
Index: usb-4.4/drivers/usb/host/ehci-q.c
===================================================================
--- usb-4.4.orig/drivers/usb/host/ehci-q.c
+++ usb-4.4/drivers/usb/host/ehci-q.c
@@ -1283,17 +1283,13 @@ static void single_unlink_async(struct e
 
 static void start_iaa_cycle(struct ehci_hcd *ehci)
 {
-	/* Do nothing if an IAA cycle is already running */
-	if (ehci->iaa_in_progress)
-		return;
-	ehci->iaa_in_progress = true;
-
 	/* If the controller isn't running, we don't have to wait for it */
 	if (unlikely(ehci->rh_state < EHCI_RH_RUNNING)) {
 		end_unlink_async(ehci);
 
-	/* Otherwise start a new IAA cycle */
-	} else if (likely(ehci->rh_state == EHCI_RH_RUNNING)) {
+	/* Otherwise start a new IAA cycle if one isn't already running */
+	} else if (ehci->rh_state == EHCI_RH_RUNNING &&
+			!ehci->iaa_in_progress) {
 
 		/* Make sure the unlinks are all visible to the hardware */
 		wmb();
@@ -1301,17 +1297,13 @@ static void start_iaa_cycle(struct ehci_
 		ehci_writel(ehci, ehci->command | CMD_IAAD,
 				&ehci->regs->command);
 		ehci_readl(ehci, &ehci->regs->command);
+		ehci->iaa_in_progress = true;
 		ehci_enable_event(ehci, EHCI_HRTIMER_IAA_WATCHDOG, true);
 	}
 }
 
-/* the async qh for the qtds being unlinked are now gone from the HC */
-
-static void end_unlink_async(struct ehci_hcd *ehci)
+static void end_iaa_cycle(struct ehci_hcd *ehci)
 {
-	struct ehci_qh		*qh;
-	bool			early_exit;
-
 	if (ehci->has_synopsys_hc_bug)
 		ehci_writel(ehci, (u32) ehci->async->qh_dma,
 			    &ehci->regs->async_next);
@@ -1319,6 +1311,16 @@ static void end_unlink_async(struct ehci
 	/* The current IAA cycle has ended */
 	ehci->iaa_in_progress = false;
 
+	end_unlink_async(ehci);
+}
+
+/* See if the async qh for the qtds being unlinked are now gone from the HC */
+
+static void end_unlink_async(struct ehci_hcd *ehci)
+{
+	struct ehci_qh		*qh;
+	bool			early_exit;
+
 	if (list_empty(&ehci->async_unlink))
 		return;
 	qh = list_first_entry(&ehci->async_unlink, struct ehci_qh,


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



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

  Powered by Linux