]> git.hungrycats.org Git - linux/commitdiff
[PATCH] USB: usb hcd states
authorDavid Brownell <david-b@pacbell.net>
Tue, 2 Sep 2003 04:09:09 +0000 (21:09 -0700)
committerGreg Kroah-Hartman <greg@kroah.com>
Tue, 2 Sep 2003 04:09:09 +0000 (21:09 -0700)
AFAICT this is ready for your next merge with Linus.

Ben's ohci stuff was not cooked yet, seemed like the
pm stuff wasn't yet supporting the hook(s) he needed.
RMK had similar issues w.r.t. PM on ARM too.

This patch includes:

   - updates from Benjamin Herrenschmidt to make usbcore
     behave a bit better during PM suspend (setting and
     checking hcd state).

   - related updates from me, making more paths into hcds
     fail when the driver is suspended.

   - updates based on some feedback from Alan Stern,
     notably including getting rid of a state we don't
     really need (most of the patch, by volume).

   - an experiment that tries to give a warning in the
     sadly common case of ACPI or APIC (etc) settings
     that need to change before USB works.

Net effect is that some of the PM issues start to get
resolved, maybe IRQ problems will be diagnosed quicker,
and some overdue cleanup gets started.

drivers/usb/core/hcd-pci.c
drivers/usb/core/hcd.c
drivers/usb/core/hcd.h
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-pci.c
drivers/usb/host/uhci-hcd.c

index d21a8a3b56334d8d592cd36c01805cd4d5863d10..dc3a0734aa3b49b1cbfd402b8ad08653f814eae1 100644 (file)
@@ -139,6 +139,7 @@ clean_2:
                        return retval;
                }
        }
+       // hcd zeroed everything
        hcd->regs = base;
        hcd->region = region;
 
@@ -165,6 +166,7 @@ clean_3:
                dev_err (hcd->controller, "can't reset\n");
                goto clean_3;
        }
+       hcd->state = USB_STATE_HALT;
 
        pci_set_master (dev);
 #ifndef __sparc__
@@ -230,7 +232,8 @@ void usb_hcd_pci_remove (struct pci_dev *dev)
                BUG ();
 
        hub = hcd->self.root_hub;
-       hcd->state = USB_STATE_QUIESCING;
+       if (HCD_IS_RUNNING (hcd->state))
+               hcd->state = USB_STATE_QUIESCING;
 
        dev_dbg (hcd->controller, "roothub graceful disconnect\n");
        usb_disconnect (&hub);
@@ -287,8 +290,8 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
                pci_save_state (dev, hcd->pci_state);
 
                /* driver may want to disable DMA etc */
+               hcd->state = USB_STATE_QUIESCING;
                retval = hcd->driver->suspend (hcd, state);
-               hcd->state = USB_STATE_SUSPENDED;
        }
 
        pci_set_power_state (dev, state);
index 18363c38a8faae250d8b446cb8cf01980440b966..2666066e785ba2b7586f4e486c6c54c4c5f998b7 100644 (file)
@@ -1099,6 +1099,8 @@ done:
 static int hcd_get_frame_number (struct usb_device *udev)
 {
        struct usb_hcd  *hcd = (struct usb_hcd *)udev->bus->hcpriv;
+       if (!HCD_IS_RUNNING (hcd->state))
+               return -ESHUTDOWN;
        return hcd->driver->get_frame_number (hcd);
 }
 
@@ -1195,6 +1197,12 @@ static int hcd_unlink_urb (struct urb *urb)
                goto done;
        }
 
+       /* running ~= hc unlink handshake works (irq, timer, etc)
+        * halted ~= no unlink handshake is needed
+        * suspended, resuming == should never happen
+        */
+       WARN_ON (!HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_HALT);
+
        if (!urb->hcpriv) {
                retval = -EINVAL;
                goto done;
@@ -1210,6 +1218,17 @@ static int hcd_unlink_urb (struct urb *urb)
                goto done;
        }
 
+       /* PCI IRQ setup can easily be broken so that USB controllers
+        * never get completion IRQs ... maybe even the ones we need to
+        * finish unlinking the initial failed usb_set_address().
+        */
+       if (!hcd->saw_irq) {
+               dev_warn (hcd->controller, "Unlink after no-IRQ?  "
+                       "Different ACPI or APIC settings may help."
+                       "\n");
+               hcd->saw_irq = 1;
+       }
+
        /* maybe set up to block until the urb's completion fires.  the
         * lower level hcd code is always async, locking on urb->status
         * updates; an intercepted completion unblocks us.
@@ -1289,6 +1308,8 @@ static void hcd_endpoint_disable (struct usb_device *udev, int endpoint)
        dev = udev->hcpriv;
        hcd = udev->bus->hcpriv;
 
+       WARN_ON (!HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_HALT);
+
        local_irq_disable ();
 
 rescan:
@@ -1485,6 +1506,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)
        if (unlikely (hcd->state == USB_STATE_HALT))    /* irq sharing? */
                return IRQ_NONE;
 
+       hcd->saw_irq = 1;
        hcd->driver->irq (hcd, r);
        if (hcd->state != start && hcd->state == USB_STATE_HALT)
                usb_hc_died (hcd);
index a292015405b595b6a165dcaf50ef076e9b9c8ec9..15cda7f94f24af901a421594c829eef40fe7a367 100644 (file)
@@ -73,6 +73,7 @@ struct usb_hcd {      /* usb_bus.hcpriv points to this */
         * hardware info/state
         */
        struct hc_driver        *driver;        /* hw-specific hooks */
+       unsigned                saw_irq : 1;
        int                     irq;            /* irq allocated */
        void                    *regs;          /* device memory/io */
        struct device           *controller;    /* handle to hardware */
@@ -89,13 +90,11 @@ struct usb_hcd {    /* usb_bus.hcpriv points to this */
 
        int                     state;
 #      define  __ACTIVE                0x01
-#      define  __SLEEPY                0x02
 #      define  __SUSPEND               0x04
 #      define  __TRANSIENT             0x80
 
 #      define  USB_STATE_HALT          0
 #      define  USB_STATE_RUNNING       (__ACTIVE)
-#      define  USB_STATE_READY         (__ACTIVE|__SLEEPY)
 #      define  USB_STATE_QUIESCING     (__SUSPEND|__TRANSIENT|__ACTIVE)
 #      define  USB_STATE_RESUMING      (__SUSPEND|__TRANSIENT)
 #      define  USB_STATE_SUSPENDED     (__SUSPEND)
index 76a02428bea0829d8f2bf35602c20a4c8f303c06..84cbc4ef2c3f5f7d9b40af0f9c038266db02e8c0 100644 (file)
@@ -231,7 +231,6 @@ static void ehci_ready (struct ehci_hcd *ehci)
                ehci->hcd.state = USB_STATE_HALT;
                return;
        }
-       ehci->hcd.state = USB_STATE_READY;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -481,7 +480,7 @@ done2:
        ehci->reboot_notifier.notifier_call = ehci_reboot;
        register_reboot_notifier (&ehci->reboot_notifier);
 
-       ehci->hcd.state = USB_STATE_READY;
+       ehci->hcd.state = USB_STATE_RUNNING;
        writel (FLAG_CF, &ehci->regs->configured_flag);
        readl (&ehci->regs->command);   /* unblock posted write */
 
@@ -625,7 +624,7 @@ static int ehci_resume (struct usb_hcd *hcd)
        /* resume HC and each port */
 // restore pci FLADJ value
        // khubd and drivers will set HC running, if needed;
-       hcd->state = USB_STATE_READY;
+       hcd->state = USB_STATE_RUNNING;
        // FIXME Philips/Intel/... etc don't really have a "READY"
        // state ... turn on CMD_RUN too
        for (i = 0; i < ports; i++) {
index 2c80903b68e06935fffc92ec7b60db0c6dbbb908..3bc940ce138e2ddcc27b5ca202ff65a4c82a6c21 100644 (file)
@@ -529,7 +529,7 @@ static int hc_start (struct ohci_hcd *ohci)
        /* connect the virtual root hub */
        bus = hcd_to_bus (&ohci->hcd);
        bus->root_hub = udev = usb_alloc_dev (NULL, bus);
-       ohci->hcd.state = USB_STATE_READY;
+       ohci->hcd.state = USB_STATE_RUNNING;
        if (!udev) {
                disable (ohci);
                ohci->hc_control &= ~OHCI_CTRL_HCFS;
index 8b7c2adae399f91e20d749d628eb6aeaefa695ed..a0820ee9f178a7582732fc104f8773778836e29e 100644 (file)
@@ -267,7 +267,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
                        if (ohci->ed_bulktail)
                                ohci->hc_control |= OHCI_CTRL_BLE;
                }
-               hcd->state = USB_STATE_READY;
+               hcd->state = USB_STATE_RUNNING;
                writel (ohci->hc_control, &ohci->regs->control);
 
                /* trigger a start-frame interrupt (why?) */
index 931edda7fabbe9ca0fe84b0c54cb675198529f07..5811fd1ae415d234e96993cace87f66b63ddf2a5 100644 (file)
@@ -2099,7 +2099,7 @@ static void start_hc(struct uhci_hcd *uhci)
        uhci->state_end = jiffies + HZ;
        outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
 
-        uhci->hcd.state = USB_STATE_READY;
+        uhci->hcd.state = USB_STATE_RUNNING;
 }
 
 /*
@@ -2452,7 +2452,7 @@ static int uhci_resume(struct usb_hcd *hcd)
                reset_hc(uhci);
                start_hc(uhci);
        }
-       uhci->hcd.state = USB_STATE_READY;
+       uhci->hcd.state = USB_STATE_RUNNING;
        return 0;
 }
 #endif