]> err.no Git - linux-2.6/commitdiff
USB: automatically enable RHSC interrupts
authorAlan Stern <stern@rowland.harvard.edu>
Wed, 20 Aug 2008 21:22:05 +0000 (17:22 -0400)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 21 Aug 2008 17:26:38 +0000 (10:26 -0700)
This patch (as1069c) changes the way OHCI root-hub status-change
interrupts are enabled.  Currently a special HCD method,
hub_irq_enable(), is called when the hub driver is finished using a
root hub.  This approach turns out to be subject to races, resulting
in unnecessary polling.

The patch does away with the method entirely.  Instead, the driver
automatically enables the RHSC interrupt when no more status changes
are present.  This scheme is safe with controllers using
level-triggered semantics for their interrupt flags.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
22 files changed:
drivers/usb/core/hcd.c
drivers/usb/core/hcd.h
drivers/usb/core/hub.c
drivers/usb/host/ohci-at91.c
drivers/usb/host/ohci-au1xxx.c
drivers/usb/host/ohci-ep93xx.c
drivers/usb/host/ohci-hub.c
drivers/usb/host/ohci-lh7a404.c
drivers/usb/host/ohci-omap.c
drivers/usb/host/ohci-pci.c
drivers/usb/host/ohci-pnx4008.c
drivers/usb/host/ohci-pnx8550.c
drivers/usb/host/ohci-ppc-of.c
drivers/usb/host/ohci-ppc-soc.c
drivers/usb/host/ohci-ps3.c
drivers/usb/host/ohci-pxa27x.c
drivers/usb/host/ohci-s3c2410.c
drivers/usb/host/ohci-sa1111.c
drivers/usb/host/ohci-sh.c
drivers/usb/host/ohci-sm501.c
drivers/usb/host/ohci-ssb.c
drivers/usb/host/u132-hcd.c

index f7bfd72ef115bae2855e05c9b622ff41588477b1..8abd4e59bf4abac0bb2edcee5385894f42310e98 100644 (file)
@@ -924,15 +924,6 @@ static int register_root_hub(struct usb_hcd *hcd)
        return retval;
 }
 
-void usb_enable_root_hub_irq (struct usb_bus *bus)
-{
-       struct usb_hcd *hcd;
-
-       hcd = container_of (bus, struct usb_hcd, self);
-       if (hcd->driver->hub_irq_enable && hcd->state != HC_STATE_HALT)
-               hcd->driver->hub_irq_enable (hcd);
-}
-
 
 /*-------------------------------------------------------------------------*/
 
index 5b0b59b0d89b37709da23af08cf0271c193d9ebf..e710ce04e228f94647908d789500a4e2b8a646f9 100644 (file)
@@ -212,8 +212,6 @@ struct hc_driver {
        int     (*bus_suspend)(struct usb_hcd *);
        int     (*bus_resume)(struct usb_hcd *);
        int     (*start_port_reset)(struct usb_hcd *, unsigned port_num);
-       void    (*hub_irq_enable)(struct usb_hcd *);
-               /* Needed only if port-change IRQs are level-triggered */
 
                /* force handover of high-speed port to full-speed companion */
        void    (*relinquish_port)(struct usb_hcd *, int);
@@ -379,8 +377,6 @@ extern struct list_head usb_bus_list;
 extern struct mutex usb_bus_list_lock;
 extern wait_queue_head_t usb_kill_urb_queue;
 
-extern void usb_enable_root_hub_irq(struct usb_bus *bus);
-
 extern int usb_find_interface_driver(struct usb_device *dev,
        struct usb_interface *interface);
 
index 107e1d25ddec3fbe0a485191131dad985342c8ff..6a5cb018383d538a2b504429183be99e112c6a5b 100644 (file)
@@ -2102,8 +2102,6 @@ int usb_port_resume(struct usb_device *udev)
        }
 
        clear_bit(port1, hub->busy_bits);
-       if (!hub->hdev->parent && !hub->busy_bits[0])
-               usb_enable_root_hub_irq(hub->hdev->bus);
 
        status = check_port_resume_type(udev,
                        hub, port1, status, portchange, portstatus);
@@ -3081,11 +3079,6 @@ static void hub_events(void)
                        }
                }
 
-               /* If this is a root hub, tell the HCD it's okay to
-                * re-enable port-change interrupts now. */
-               if (!hdev->parent && !hub->busy_bits[0])
-                       usb_enable_root_hub_irq(hdev->bus);
-
 loop_autopm:
                /* Allow autosuspend if we're not going to run again */
                if (list_empty(&hub->event_list))
@@ -3311,8 +3304,6 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
                        break;
        }
        clear_bit(port1, parent_hub->busy_bits);
-       if (!parent_hdev->parent && !parent_hub->busy_bits[0])
-               usb_enable_root_hub_irq(parent_hdev->bus);
 
        if (ret < 0)
                goto re_enumerate;
index 6db7a2889e6648f50344d4d42e3a2c04d332a91b..4ed228a899435a91bc1428daa37a9eb54f283b14 100644 (file)
@@ -260,7 +260,6 @@ static const struct hc_driver ohci_at91_hc_driver = {
         */
        .hub_status_data =      ohci_hub_status_data,
        .hub_control =          ohci_hub_control,
-       .hub_irq_enable =       ohci_rhsc_enable,
 #ifdef CONFIG_PM
        .bus_suspend =          ohci_bus_suspend,
        .bus_resume =           ohci_bus_resume,
index c0948008fe3d17c068c47d83b768b2e7fc365bff..2ac4e022a13f6fc68c6ea32702f1bab05713b88a 100644 (file)
@@ -163,7 +163,6 @@ static const struct hc_driver ohci_au1xxx_hc_driver = {
         */
        .hub_status_data =      ohci_hub_status_data,
        .hub_control =          ohci_hub_control,
-       .hub_irq_enable =       ohci_rhsc_enable,
 #ifdef CONFIG_PM
        .bus_suspend =          ohci_bus_suspend,
        .bus_resume =           ohci_bus_resume,
index cb0b506f8259b20237854bfaae4f9b290223b82a..fb3055f084b5f1a89aaf30efe19cd643b9ddef85 100644 (file)
@@ -134,7 +134,6 @@ static struct hc_driver ohci_ep93xx_hc_driver = {
        .get_frame_number       = ohci_get_frame,
        .hub_status_data        = ohci_hub_status_data,
        .hub_control            = ohci_hub_control,
-       .hub_irq_enable         = ohci_rhsc_enable,
 #ifdef CONFIG_PM
        .bus_suspend            = ohci_bus_suspend,
        .bus_resume             = ohci_bus_resume,
index 439beb784f3e1eb42495d4a323288a56d5eea02d..7ea9a7b311554199f4e5f97ba060cc853786f2f0 100644 (file)
 
 /*-------------------------------------------------------------------------*/
 
-/* hcd->hub_irq_enable() */
-static void ohci_rhsc_enable (struct usb_hcd *hcd)
-{
-       struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
-
-       spin_lock_irq(&ohci->lock);
-       if (!ohci->autostop)
-               del_timer(&hcd->rh_timer);      /* Prevent next poll */
-       ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
-       spin_unlock_irq(&ohci->lock);
-}
-
 #define OHCI_SCHED_ENABLES \
        (OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE)
 
@@ -374,18 +362,28 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
                int any_connected)
 {
        int     poll_rh = 1;
+       int     rhsc;
 
+       rhsc = ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC;
        switch (ohci->hc_control & OHCI_CTRL_HCFS) {
 
        case OHCI_USB_OPER:
-               /* keep on polling until we know a device is connected
-                * and RHSC is enabled */
+               /* If no status changes are pending, enable status-change
+                * interrupts.
+                */
+               if (!rhsc && !changed) {
+                       rhsc = OHCI_INTR_RHSC;
+                       ohci_writel(ohci, rhsc, &ohci->regs->intrenable);
+               }
+
+               /* Keep on polling until we know a device is connected
+                * and RHSC is enabled, or until we autostop.
+                */
                if (!ohci->autostop) {
                        if (any_connected ||
                                        !device_may_wakeup(&ohci_to_hcd(ohci)
                                                ->self.root_hub->dev)) {
-                               if (ohci_readl(ohci, &ohci->regs->intrenable) &
-                                               OHCI_INTR_RHSC)
+                               if (rhsc)
                                        poll_rh = 0;
                        } else {
                                ohci->autostop = 1;
@@ -398,12 +396,13 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
                                ohci->autostop = 0;
                                ohci->next_statechange = jiffies +
                                                STATECHANGE_DELAY;
-                       } else if (time_after_eq(jiffies,
+                       } else if (rhsc && time_after_eq(jiffies,
                                                ohci->next_statechange)
                                        && !ohci->ed_rm_list
                                        && !(ohci->hc_control &
                                                OHCI_SCHED_ENABLES)) {
                                ohci_rh_suspend(ohci, 1);
+                               poll_rh = 0;
                        }
                }
                break;
@@ -417,6 +416,12 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
                        else
                                usb_hcd_resume_root_hub(ohci_to_hcd(ohci));
                } else {
+                       if (!rhsc && (ohci->autostop ||
+                                       ohci_to_hcd(ohci)->self.root_hub->
+                                               do_remote_wakeup))
+                               ohci_writel(ohci, OHCI_INTR_RHSC,
+                                               &ohci->regs->intrenable);
+
                        /* everything is idle, no need for polling */
                        poll_rh = 0;
                }
@@ -438,12 +443,16 @@ static inline int ohci_rh_resume(struct ohci_hcd *ohci)
 static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
                int any_connected)
 {
-       int     poll_rh = 1;
-
-       /* keep on polling until RHSC is enabled */
+       /* If RHSC is enabled, don't poll */
        if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC)
-               poll_rh = 0;
-       return poll_rh;
+               return 0;
+
+       /* If no status changes are pending, enable status-change interrupts */
+       if (!changed) {
+               ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
+               return 0;
+       }
+       return 1;
 }
 
 #endif /* CONFIG_PM */
index 9e31d440d115e7e8260476bcd81e39fd80b026e1..de42283149c7154608c30c9b1ceeec29e14b07ba 100644 (file)
@@ -193,7 +193,6 @@ static const struct hc_driver ohci_lh7a404_hc_driver = {
         */
        .hub_status_data =      ohci_hub_status_data,
        .hub_control =          ohci_hub_control,
-       .hub_irq_enable =       ohci_rhsc_enable,
 #ifdef CONFIG_PM
        .bus_suspend =          ohci_bus_suspend,
        .bus_resume =           ohci_bus_resume,
index 3d532b709670c9386959f1a8c84a327875790d10..1eb64d08b60a9591bd994f757c0372602b7c7ef4 100644 (file)
@@ -470,7 +470,6 @@ static const struct hc_driver ohci_omap_hc_driver = {
         */
        .hub_status_data =      ohci_hub_status_data,
        .hub_control =          ohci_hub_control,
-       .hub_irq_enable =       ohci_rhsc_enable,
 #ifdef CONFIG_PM
        .bus_suspend =          ohci_bus_suspend,
        .bus_resume =           ohci_bus_resume,
index 083e8df0a817f83b925ac397f5e90cb43b8af1d2..a9c2ae36c7ad5ce6bf9585fc9b8e418ad10751ba 100644 (file)
@@ -459,7 +459,6 @@ static const struct hc_driver ohci_pci_hc_driver = {
         */
        .hub_status_data =      ohci_hub_status_data,
        .hub_control =          ohci_hub_control,
-       .hub_irq_enable =       ohci_rhsc_enable,
 #ifdef CONFIG_PM
        .bus_suspend =          ohci_bus_suspend,
        .bus_resume =           ohci_bus_resume,
index b02cd0761977aed3bf6c85eda07227a6bfe8d4c1..658a2a978c32139bcf98181e9cd5fa4466f214b0 100644 (file)
@@ -277,7 +277,6 @@ static const struct hc_driver ohci_pnx4008_hc_driver = {
         */
        .hub_status_data = ohci_hub_status_data,
        .hub_control = ohci_hub_control,
-       .hub_irq_enable = ohci_rhsc_enable,
 #ifdef CONFIG_PM
        .bus_suspend = ohci_bus_suspend,
        .bus_resume = ohci_bus_resume,
index 605d59cba28e79d46bbbb3215cfc9ccd1b6f6a5b..28467e288a93d54607c7cb244e1e904dc6136395 100644 (file)
@@ -201,7 +201,6 @@ static const struct hc_driver ohci_pnx8550_hc_driver = {
         */
        .hub_status_data =      ohci_hub_status_data,
        .hub_control =          ohci_hub_control,
-       .hub_irq_enable =       ohci_rhsc_enable,
 #ifdef CONFIG_PM
        .bus_suspend =          ohci_bus_suspend,
        .bus_resume =           ohci_bus_resume,
index 91e6e101a4cc987feae9591a4926f6a35aef95a0..7ac53264ead369b1beb9c140cd50e131a019ea40 100644 (file)
@@ -72,7 +72,6 @@ static const struct hc_driver ohci_ppc_of_hc_driver = {
         */
        .hub_status_data =      ohci_hub_status_data,
        .hub_control =          ohci_hub_control,
-       .hub_irq_enable =       ohci_rhsc_enable,
 #ifdef CONFIG_PM
        .bus_suspend =          ohci_bus_suspend,
        .bus_resume =           ohci_bus_resume,
index 523c30125577d39a8c24287ce30ae2b2532929e2..cd3398b675b2dea8c2402fd2178cee58c23a52e4 100644 (file)
@@ -172,7 +172,6 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = {
         */
        .hub_status_data =      ohci_hub_status_data,
        .hub_control =          ohci_hub_control,
-       .hub_irq_enable =       ohci_rhsc_enable,
 #ifdef CONFIG_PM
        .bus_suspend =          ohci_bus_suspend,
        .bus_resume =           ohci_bus_resume,
index 55c95647f008d7eec7eb6991a6a5f19212f4fd59..2089d8a46c4bbedb0cd140dc5db4d0cee4cab908 100644 (file)
@@ -68,7 +68,6 @@ static const struct hc_driver ps3_ohci_hc_driver = {
        .get_frame_number       = ohci_get_frame,
        .hub_status_data        = ohci_hub_status_data,
        .hub_control            = ohci_hub_control,
-       .hub_irq_enable         = ohci_rhsc_enable,
        .start_port_reset       = ohci_start_port_reset,
 #if defined(CONFIG_PM)
        .bus_suspend            = ohci_bus_suspend,
index 8c9c4849db6efc5fedfec17201622f60a6df9174..7f0f35c781858628a995dc85df361c6cae56b264 100644 (file)
@@ -298,7 +298,6 @@ static const struct hc_driver ohci_pxa27x_hc_driver = {
         */
        .hub_status_data =      ohci_hub_status_data,
        .hub_control =          ohci_hub_control,
-       .hub_irq_enable =       ohci_rhsc_enable,
 #ifdef  CONFIG_PM
        .bus_suspend =          ohci_bus_suspend,
        .bus_resume =           ohci_bus_resume,
index 9e3dc4069e8bc9cb4dac244f1b8dfa5f276ff9ac..f46af7a718d416a548b565c142ccf8d229c1505f 100644 (file)
@@ -466,7 +466,6 @@ static const struct hc_driver ohci_s3c2410_hc_driver = {
         */
        .hub_status_data =      ohci_s3c2410_hub_status_data,
        .hub_control =          ohci_s3c2410_hub_control,
-       .hub_irq_enable =       ohci_rhsc_enable,
 #ifdef CONFIG_PM
        .bus_suspend =          ohci_bus_suspend,
        .bus_resume =           ohci_bus_resume,
index 4626b002e670f15a5a93a1f8cf1c80edf12480b9..e4bbe8e188e4653355426294e511e92588085b9a 100644 (file)
@@ -231,7 +231,6 @@ static const struct hc_driver ohci_sa1111_hc_driver = {
         */
        .hub_status_data =      ohci_hub_status_data,
        .hub_control =          ohci_hub_control,
-       .hub_irq_enable =       ohci_rhsc_enable,
 #ifdef CONFIG_PM
        .bus_suspend =          ohci_bus_suspend,
        .bus_resume =           ohci_bus_resume,
index e7ee607278fece8b92570beb5b839e74ca8aa2db..60f03cc7ec4f20a4f80d228b59faebe715ae1148 100644 (file)
@@ -68,7 +68,6 @@ static const struct hc_driver ohci_sh_hc_driver = {
         */
        .hub_status_data =      ohci_hub_status_data,
        .hub_control =          ohci_hub_control,
-       .hub_irq_enable =       ohci_rhsc_enable,
 #ifdef CONFIG_PM
        .bus_suspend =          ohci_bus_suspend,
        .bus_resume =           ohci_bus_resume,
index 21b164e4abebf8bc71d12611b4356bb97e038718..cff23637cfcc5e6cd5322d8faddd866f885b9e27 100644 (file)
@@ -75,7 +75,6 @@ static const struct hc_driver ohci_sm501_hc_driver = {
         */
        .hub_status_data =      ohci_hub_status_data,
        .hub_control =          ohci_hub_control,
-       .hub_irq_enable =       ohci_rhsc_enable,
 #ifdef CONFIG_PM
        .bus_suspend =          ohci_bus_suspend,
        .bus_resume =           ohci_bus_resume,
index 3660c83d80af44b269bfa9c32311846db1878105..23fd6a886bddb0f25d2279d3da8d11c66e5e61ad 100644 (file)
@@ -81,7 +81,6 @@ static const struct hc_driver ssb_ohci_hc_driver = {
 
        .hub_status_data        = ohci_hub_status_data,
        .hub_control            = ohci_hub_control,
-       .hub_irq_enable         = ohci_rhsc_enable,
 #ifdef CONFIG_PM
        .bus_suspend            = ohci_bus_suspend,
        .bus_resume             = ohci_bus_resume,
index 20ad3c48fcb2966fb20e2bc36fc49971b239110b..228f2b070f2b7d558e33271827cccb3588794ebd 100644 (file)
@@ -2934,16 +2934,6 @@ static int u132_start_port_reset(struct usb_hcd *hcd, unsigned port_num)
                return 0;
 }
 
-static void u132_hub_irq_enable(struct usb_hcd *hcd)
-{
-       struct u132 *u132 = hcd_to_u132(hcd);
-       if (u132->going > 1) {
-               dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
-                       , u132->going);
-       } else if (u132->going > 0)
-               dev_err(&u132->platform_dev->dev, "device is being removed\n");
-}
-
 
 #ifdef CONFIG_PM
 static int u132_bus_suspend(struct usb_hcd *hcd)
@@ -2995,7 +2985,6 @@ static struct hc_driver u132_hc_driver = {
        .bus_suspend = u132_bus_suspend,
        .bus_resume = u132_bus_resume,
        .start_port_reset = u132_start_port_reset,
-       .hub_irq_enable = u132_hub_irq_enable,
 };
 
 /*