USB: EHCI: remove usages of hcd->state
authorAlan Stern <stern@rowland.harvard.edu>
Thu, 18 Aug 2011 20:31:30 +0000 (16:31 -0400)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 22 Aug 2011 22:57:01 +0000 (15:57 -0700)
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@rowland.harvard.edu>
Acked-by: Jingoo Han <jg1.han@samsung.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/host/ehci-au1xxx.c
drivers/usb/host/ehci-dbg.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci-s5p.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/ehci.h

index 42ae57409908750b329385e27ebb3ec36d5c9c24..4363fea85151ace424b583100aac7a3393b9fd27 100644 (file)
@@ -293,7 +293,7 @@ static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
        /* 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 40a844c1dbb4945044a9afe2d94d2097bad29af3..9952505d2357ebd7b96b806c09d8b26e9fee00cf 100644 (file)
@@ -697,6 +697,19 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
 }
 #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(struct debug_buffer *buf)
        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 34a3140d1e5f169e182d2c2ce37762fd8413e8d6..3bf9f16b4fd890ecf945934458b9e9c10b8c5759 100644 (file)
@@ -392,7 +392,7 @@ static int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
 
        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(struct device *dev)
        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 2af3e2a89efc2bde4a392d7e51191f87722d187d..8696489cde566e94c35c46bfc3ce0e512578630b 100644 (file)
@@ -238,7 +238,7 @@ static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr,
        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 *ehci)
        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_hcd *ehci)
        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 long param)
         */
        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 *ehci)
         * 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 *hcd)
        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_hcd *hcd)
 
        /* 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 e051b30c1847804f6b94e188521a865e036108ea..c6104c4f1f38b0a1b6e297b134b4784429703e3b 100644 (file)
@@ -236,10 +236,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
        }
 
        /* 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_hcd *hcd)
 
        /* 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_hcd *hcd)
 
        /* 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_hcd *hcd)
        }
 
        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 *hcd, char *buf)
        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 1102ce65a3a9eff69fee9c612f65f4a6ead9c3a9..8311de7c0a75036002f903a4f5949a3962b81a17 100644 (file)
@@ -439,7 +439,7 @@ static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
        /* 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 0917e3a32465064903dd884cc2c258baadadc0f2..6ce0b3a9a0f9af53366a7c8092046e36e89ae29c 100644 (file)
@@ -153,7 +153,7 @@ static void ehci_clear_tt_buffer_complete(struct usb_hcd *hcd,
        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, struct ehci_qh *qh)
 
                /* 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, struct ehci_qh *qh)
                        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_hcd *ehci, struct ehci_qh *qh)
                        /* 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 ehci_hcd *ehci)
 
        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 ehci_hcd *ehci, struct ehci_qh *qh)
        /* 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 ehci_hcd *ehci, struct ehci_qh *qh)
        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 *ehci)
        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 b3958b3d31634f59c9c067712c7f4cf7c2959c0a..318e0c6d0ab1e3594fcdc7d32063c3e51d33a7b0 100644 (file)
@@ -269,7 +269,7 @@ static int s5p_ehci_resume(struct device *dev)
        /* 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 2abf8543f083fe69b26e6224f8dd8edeffb050ac..488151bb45cb1e0b2eb6bbc23b34eea76b52185f 100644 (file)
@@ -479,7 +479,6 @@ static int enable_periodic (struct ehci_hcd *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_hcd *ehci, struct ehci_qh *qh)
 
        /* 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 cc7d337ec35535bb24e2097775dc653381560b6b..c161d97de7ddb208b55fb2fbf9dcbd8b8c0333d4 100644 (file)
@@ -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 controller */
 
        __u32                   hcs_params;     /* cached register copy */
        spinlock_t              lock;
+       enum ehci_rh_state      rh_state;
 
        /* async schedule support */
        struct ehci_qh          *async;