[PATCH] USB: EHCI: remove usages of hcd->state

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

 



This patch (as1483) improves the ehci-hcd driver family by getting rid
of the reliance on the hcd->state variable.  It has no clear owner and
it isn't protected by the usual HCD locks.  In its place, the patch
adds a new, private ehci->rh_state field to record the state of the
root hub.

Along the way, the patch removes a couple of lines containing
redundant assignments to the state variable.  Also, the QUIESCING
state simply gets changed to the RUNNING state, because the driver
doesn't make any distinction between them.

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

---

 drivers/usb/host/ehci-au1xxx.c |    2 +-
 drivers/usb/host/ehci-dbg.c    |   17 +++++++++++++++--
 drivers/usb/host/ehci-fsl.c    |    4 ++--
 drivers/usb/host/ehci-hcd.c    |   20 ++++++++++----------
 drivers/usb/host/ehci-hub.c    |   10 ++++------
 drivers/usb/host/ehci-pci.c    |    2 +-
 drivers/usb/host/ehci-q.c      |   22 ++++++++++------------
 drivers/usb/host/ehci-s5p.c    |    2 +-
 drivers/usb/host/ehci-sched.c  |   11 +++++------
 drivers/usb/host/ehci.h        |    7 +++++++
 10 files changed, 56 insertions(+), 41 deletions(-)

Index: usb-3.0/drivers/usb/host/ehci.h
===================================================================
--- usb-3.0.orig/drivers/usb/host/ehci.h
+++ usb-3.0/drivers/usb/host/ehci.h
@@ -62,6 +62,12 @@ struct ehci_stats {
 
 #define	EHCI_MAX_ROOT_PORTS	15		/* see HCS_N_PORTS */
 
+enum ehci_rh_state {
+	EHCI_RH_HALTED,
+	EHCI_RH_SUSPENDED,
+	EHCI_RH_RUNNING
+};
+
 struct ehci_hcd {			/* one per controller */
 	/* glue to PCI and HCD framework */
 	struct ehci_caps __iomem *caps;
@@ -70,6 +76,7 @@ struct ehci_hcd {			/* one per controlle
 
 	__u32			hcs_params;	/* cached register copy */
 	spinlock_t		lock;
+	enum ehci_rh_state	rh_state;
 
 	/* async schedule support */
 	struct ehci_qh		*async;
Index: usb-3.0/drivers/usb/host/ehci-dbg.c
===================================================================
--- usb-3.0.orig/drivers/usb/host/ehci-dbg.c
+++ usb-3.0/drivers/usb/host/ehci-dbg.c
@@ -697,6 +697,19 @@ static ssize_t fill_periodic_buffer(stru
 }
 #undef DBG_SCHED_LIMIT
 
+static const char *rh_state_string(struct ehci_hcd *ehci)
+{
+	switch (ehci->rh_state) {
+	case EHCI_RH_HALTED:
+		return "halted";
+	case EHCI_RH_SUSPENDED:
+		return "suspended";
+	case EHCI_RH_RUNNING:
+		return "running";
+	}
+	return "?";
+}
+
 static ssize_t fill_registers_buffer(struct debug_buffer *buf)
 {
 	struct usb_hcd		*hcd;
@@ -730,11 +743,11 @@ static ssize_t fill_registers_buffer(str
 	temp = scnprintf (next, size,
 		"bus %s, device %s\n"
 		"%s\n"
-		"EHCI %x.%02x, hcd state %d\n",
+		"EHCI %x.%02x, rh state %s\n",
 		hcd->self.controller->bus->name,
 		dev_name(hcd->self.controller),
 		hcd->product_desc,
-		i >> 8, i & 0x0ff, hcd->state);
+		i >> 8, i & 0x0ff, rh_state_string(ehci));
 	size -= temp;
 	next += temp;
 
Index: usb-3.0/drivers/usb/host/ehci-hcd.c
===================================================================
--- usb-3.0.orig/drivers/usb/host/ehci-hcd.c
+++ usb-3.0/drivers/usb/host/ehci-hcd.c
@@ -238,7 +238,7 @@ static int handshake_on_error_set_halt(s
 	error = handshake(ehci, ptr, mask, done, usec);
 	if (error) {
 		ehci_halt(ehci);
-		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
+		ehci->rh_state = EHCI_RH_HALTED;
 		ehci_err(ehci, "force halt; handshake %p %08x %08x -> %d\n",
 			ptr, mask, done, error);
 	}
@@ -278,7 +278,7 @@ static int ehci_reset (struct ehci_hcd *
 	command |= CMD_RESET;
 	dbg_cmd (ehci, "reset", command);
 	ehci_writel(ehci, command, &ehci->regs->command);
-	ehci_to_hcd(ehci)->state = HC_STATE_HALT;
+	ehci->rh_state = EHCI_RH_HALTED;
 	ehci->next_statechange = jiffies;
 	retval = handshake (ehci, &ehci->regs->command,
 			    CMD_RESET, 0, 250 * 1000);
@@ -307,7 +307,7 @@ static void ehci_quiesce (struct ehci_hc
 	u32	temp;
 
 #ifdef DEBUG
-	if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
+	if (ehci->rh_state != EHCI_RH_RUNNING)
 		BUG ();
 #endif
 
@@ -356,7 +356,7 @@ static void ehci_iaa_watchdog(unsigned l
 	 */
 	if (ehci->reclaim
 			&& !timer_pending(&ehci->iaa_watchdog)
-			&& HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
+			&& ehci->rh_state == EHCI_RH_RUNNING) {
 		u32 cmd, status;
 
 		/* If we get here, IAA is *REALLY* late.  It's barely
@@ -496,7 +496,7 @@ static void ehci_work (struct ehci_hcd *
 	 * misplace IRQs, and should let us run completely without IRQs.
 	 * such lossage has been observed on both VT6202 and VT8235.
 	 */
-	if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state) &&
+	if (ehci->rh_state == EHCI_RH_RUNNING &&
 			(ehci->async->qh_next.ptr != NULL ||
 			 ehci->periodic_sched != 0))
 		timer_action (ehci, TIMER_IO_WATCHDOG);
@@ -516,7 +516,7 @@ static void ehci_stop (struct usb_hcd *h
 	del_timer_sync(&ehci->iaa_watchdog);
 
 	spin_lock_irq(&ehci->lock);
-	if (HC_IS_RUNNING (hcd->state))
+	if (ehci->rh_state == EHCI_RH_RUNNING)
 		ehci_quiesce (ehci);
 
 	ehci_silence_controller(ehci);
@@ -741,7 +741,7 @@ static int ehci_run (struct usb_hcd *hcd
 	 * be started before the port switching actions could complete.
 	 */
 	down_write(&ehci_cf_port_reset_rwsem);
-	hcd->state = HC_STATE_RUNNING;
+	ehci->rh_state = EHCI_RH_RUNNING;
 	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
 	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
 	msleep(5);
@@ -788,7 +788,7 @@ static irqreturn_t ehci_irq (struct usb_
 
 	/* Shared IRQ? */
 	masked_status = status & INTR_MASK;
-	if (!masked_status || unlikely(hcd->state == HC_STATE_HALT)) {
+	if (!masked_status || unlikely(ehci->rh_state == EHCI_RH_HALTED)) {
 		spin_unlock(&ehci->lock);
 		return IRQ_NONE;
 	}
@@ -952,7 +952,7 @@ static int ehci_urb_enqueue (
 static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
 	/* failfast */
-	if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state) && ehci->reclaim)
+	if (ehci->rh_state != EHCI_RH_RUNNING && ehci->reclaim)
 		end_unlink_async(ehci);
 
 	/* If the QH isn't linked then there's nothing we can do
@@ -1079,7 +1079,7 @@ rescan:
 		goto idle_timeout;
 	}
 
-	if (!HC_IS_RUNNING (hcd->state))
+	if (ehci->rh_state != EHCI_RH_RUNNING)
 		qh->qh_state = QH_STATE_IDLE;
 	switch (qh->qh_state) {
 	case QH_STATE_LINKED:
Index: usb-3.0/drivers/usb/host/ehci-hub.c
===================================================================
--- usb-3.0.orig/drivers/usb/host/ehci-hub.c
+++ usb-3.0/drivers/usb/host/ehci-hub.c
@@ -236,10 +236,8 @@ static int ehci_bus_suspend (struct usb_
 	}
 
 	/* stop schedules, clean any completed work */
-	if (HC_IS_RUNNING(hcd->state)) {
+	if (ehci->rh_state == EHCI_RH_RUNNING)
 		ehci_quiesce (ehci);
-		hcd->state = HC_STATE_QUIESCING;
-	}
 	ehci->command = ehci_readl(ehci, &ehci->regs->command);
 	ehci_work(ehci);
 
@@ -313,7 +311,7 @@ static int ehci_bus_suspend (struct usb_
 
 	/* turn off now-idle HC */
 	ehci_halt (ehci);
-	hcd->state = HC_STATE_SUSPENDED;
+	ehci->rh_state = EHCI_RH_SUSPENDED;
 
 	if (ehci->reclaim)
 		end_unlink_async(ehci);
@@ -382,6 +380,7 @@ static int ehci_bus_resume (struct usb_h
 
 	/* restore CMD_RUN, framelist size, and irq threshold */
 	ehci_writel(ehci, ehci->command, &ehci->regs->command);
+	ehci->rh_state = EHCI_RH_RUNNING;
 
 	/* Some controller/firmware combinations need a delay during which
 	 * they set up the port statuses.  See Bugzilla #8190. */
@@ -452,7 +451,6 @@ static int ehci_bus_resume (struct usb_h
 	}
 
 	ehci->next_statechange = jiffies + msecs_to_jiffies(5);
-	hcd->state = HC_STATE_RUNNING;
 
 	/* Now we can safely re-enable irqs */
 	ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
@@ -564,7 +562,7 @@ ehci_hub_status_data (struct usb_hcd *hc
 	u32		ppcd = 0;
 
 	/* if !USB_SUSPEND, root hub timers won't get shut down ... */
-	if (!HC_IS_RUNNING(hcd->state))
+	if (ehci->rh_state != EHCI_RH_RUNNING)
 		return 0;
 
 	/* init status to no-changes */
Index: usb-3.0/drivers/usb/host/ehci-q.c
===================================================================
--- usb-3.0.orig/drivers/usb/host/ehci-q.c
+++ usb-3.0/drivers/usb/host/ehci-q.c
@@ -153,7 +153,7 @@ static void ehci_clear_tt_buffer_complet
 	spin_lock_irqsave(&ehci->lock, flags);
 	qh->clearing_tt = 0;
 	if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list)
-			&& HC_IS_RUNNING(hcd->state))
+			&& ehci->rh_state == EHCI_RH_RUNNING)
 		qh_link_async(ehci, qh);
 	spin_unlock_irqrestore(&ehci->lock, flags);
 }
@@ -425,7 +425,7 @@ qh_completions (struct ehci_hcd *ehci, s
 
 		/* stop scanning when we reach qtds the hc is using */
 		} else if (likely (!stopped
-				&& HC_IS_RUNNING (ehci_to_hcd(ehci)->state))) {
+				&& ehci->rh_state == EHCI_RH_RUNNING)) {
 			break;
 
 		/* scan the whole queue for unlinks whenever it stops */
@@ -433,7 +433,7 @@ qh_completions (struct ehci_hcd *ehci, s
 			stopped = 1;
 
 			/* cancel everything if we halt, suspend, etc */
-			if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state))
+			if (ehci->rh_state != EHCI_RH_RUNNING)
 				last_status = -ESHUTDOWN;
 
 			/* this qtd is active; skip it unless a previous qtd
@@ -977,9 +977,8 @@ static void qh_link_async (struct ehci_h
 			/* in case a clear of CMD_ASE didn't take yet */
 			(void)handshake(ehci, &ehci->regs->status,
 					STS_ASS, 0, 150);
-			cmd |= CMD_ASE | CMD_RUN;
+			cmd |= CMD_ASE;
 			ehci_writel(ehci, cmd, &ehci->regs->command);
-			ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
 			/* posted write need not be known to HC yet ... */
 		}
 	}
@@ -1168,14 +1167,13 @@ static void end_unlink_async (struct ehc
 
 	qh_completions (ehci, qh);
 
-	if (!list_empty (&qh->qtd_list)
-			&& HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
+	if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) {
 		qh_link_async (ehci, qh);
-	else {
+	} else {
 		/* it's not free to turn the async schedule on/off; leave it
 		 * active but idle for a while once it empties.
 		 */
-		if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state)
+		if (ehci->rh_state == EHCI_RH_RUNNING
 				&& ehci->async->qh_next.qh == NULL)
 			timer_action (ehci, TIMER_ASYNC_OFF);
 	}
@@ -1211,7 +1209,7 @@ static void start_unlink_async (struct e
 	/* stop async schedule right now? */
 	if (unlikely (qh == ehci->async)) {
 		/* can't get here without STS_ASS set */
-		if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
+		if (ehci->rh_state != EHCI_RH_HALTED
 				&& !ehci->reclaim) {
 			/* ... and CMD_IAAD clear */
 			ehci_writel(ehci, cmd & ~CMD_ASE,
@@ -1237,7 +1235,7 @@ static void start_unlink_async (struct e
 	wmb ();
 
 	/* If the controller isn't running, we don't have to wait for it */
-	if (unlikely(!HC_IS_RUNNING(ehci_to_hcd(ehci)->state))) {
+	if (unlikely(ehci->rh_state != EHCI_RH_RUNNING)) {
 		/* if (unlikely (qh->reclaim != 0))
 		 *	this will recurse, probably not much
 		 */
@@ -1260,7 +1258,7 @@ static void scan_async (struct ehci_hcd 
 	enum ehci_timer_action	action = TIMER_IO_WATCHDOG;
 
 	timer_action_done (ehci, TIMER_ASYNC_SHRINK);
-	stopped = !HC_IS_RUNNING(ehci_to_hcd(ehci)->state);
+	stopped = (ehci->rh_state != EHCI_RH_RUNNING);
 
 	ehci->qh_scan_next = ehci->async->qh_next.qh;
 	while (ehci->qh_scan_next) {
Index: usb-3.0/drivers/usb/host/ehci-sched.c
===================================================================
--- usb-3.0.orig/drivers/usb/host/ehci-sched.c
+++ usb-3.0/drivers/usb/host/ehci-sched.c
@@ -479,7 +479,6 @@ static int enable_periodic (struct ehci_
 	cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
 	ehci_writel(ehci, cmd, &ehci->regs->command);
 	/* posted write ... PSS happens later */
-	ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
 
 	/* make sure ehci_work scans these */
 	ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index)
@@ -677,7 +676,7 @@ static void intr_deschedule (struct ehci
 
 	/* reschedule QH iff another request is queued */
 	if (!list_empty(&qh->qtd_list) &&
-			HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
+			ehci->rh_state == EHCI_RH_RUNNING) {
 		rc = qh_schedule(ehci, qh);
 
 		/* An error here likely indicates handshake failure
@@ -2275,7 +2274,7 @@ scan_periodic (struct ehci_hcd *ehci)
 	 * Touches as few pages as possible:  cache-friendly.
 	 */
 	now_uframe = ehci->next_uframe;
-	if (HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
+	if (ehci->rh_state == EHCI_RH_RUNNING) {
 		clock = ehci_readl(ehci, &ehci->regs->frame_index);
 		clock_frame = (clock >> 3) & (ehci->periodic_size - 1);
 	} else  {
@@ -2310,7 +2309,7 @@ restart:
 			union ehci_shadow	temp;
 			int			live;
 
-			live = HC_IS_RUNNING (ehci_to_hcd(ehci)->state);
+			live = (ehci->rh_state == EHCI_RH_RUNNING);
 			switch (hc32_to_cpu(ehci, type)) {
 			case Q_TYPE_QH:
 				/* handle any completions */
@@ -2435,7 +2434,7 @@ restart:
 		 * We can't advance our scan without collecting the ISO
 		 * transfers that are still pending in this frame.
 		 */
-		if (incomplete && HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
+		if (incomplete && ehci->rh_state == EHCI_RH_RUNNING) {
 			ehci->next_uframe = now_uframe;
 			break;
 		}
@@ -2451,7 +2450,7 @@ restart:
 		if (now_uframe == clock) {
 			unsigned	now;
 
-			if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)
+			if (ehci->rh_state != EHCI_RH_RUNNING
 					|| ehci->periodic_sched == 0)
 				break;
 			ehci->next_uframe = now_uframe;
Index: usb-3.0/drivers/usb/host/ehci-pci.c
===================================================================
--- usb-3.0.orig/drivers/usb/host/ehci-pci.c
+++ usb-3.0/drivers/usb/host/ehci-pci.c
@@ -439,7 +439,7 @@ static int ehci_pci_resume(struct usb_hc
 	/* here we "know" root ports should always stay powered */
 	ehci_port_power(ehci, 1);
 
-	hcd->state = HC_STATE_SUSPENDED;
+	ehci->rh_state = EHCI_RH_SUSPENDED;
 	return 0;
 }
 #endif
Index: usb-3.0/drivers/usb/host/ehci-au1xxx.c
===================================================================
--- usb-3.0.orig/drivers/usb/host/ehci-au1xxx.c
+++ usb-3.0/drivers/usb/host/ehci-au1xxx.c
@@ -293,7 +293,7 @@ static int ehci_hcd_au1xxx_drv_resume(st
 	/* here we "know" root ports should always stay powered */
 	ehci_port_power(ehci, 1);
 
-	hcd->state = HC_STATE_SUSPENDED;
+	ehci->rh_state = EHCI_RH_SUSPENDED;
 
 	return 0;
 }
Index: usb-3.0/drivers/usb/host/ehci-fsl.c
===================================================================
--- usb-3.0.orig/drivers/usb/host/ehci-fsl.c
+++ usb-3.0/drivers/usb/host/ehci-fsl.c
@@ -392,7 +392,7 @@ static int ehci_fsl_mpc512x_drv_suspend(
 
 	dev_dbg(dev, "suspending...\n");
 
-	hcd->state = HC_STATE_SUSPENDED;
+	ehci->rh_state = EHCI_RH_SUSPENDED;
 	dev->power.power_state = PMSG_SUSPEND;
 
 	/* ignore non-host interrupts */
@@ -481,7 +481,7 @@ static int ehci_fsl_mpc512x_drv_resume(s
 	ehci_writel(ehci, pdata->pm_portsc, &ehci->regs->port_status[0]);
 
 	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-	hcd->state = HC_STATE_RUNNING;
+	ehci->rh_state = EHCI_RH_RUNNING;
 	dev->power.power_state = PMSG_ON;
 
 	tmp = ehci_readl(ehci, &ehci->regs->command);
Index: usb-3.0/drivers/usb/host/ehci-s5p.c
===================================================================
--- usb-3.0.orig/drivers/usb/host/ehci-s5p.c
+++ usb-3.0/drivers/usb/host/ehci-s5p.c
@@ -269,7 +269,7 @@ static int s5p_ehci_resume(struct device
 	/* here we "know" root ports should always stay powered */
 	ehci_port_power(ehci, 1);
 
-	hcd->state = HC_STATE_SUSPENDED;
+	ehci->rh_state = EHCI_RH_SUSPENDED;
 
 	return 0;
 }

--
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