diff options
Diffstat (limited to 'drivers/usb/core')
-rw-r--r-- | drivers/usb/core/driver.c | 65 | ||||
-rw-r--r-- | drivers/usb/core/hcd.c | 6 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 4 | ||||
-rw-r--r-- | drivers/usb/core/inode.c | 11 | ||||
-rw-r--r-- | drivers/usb/core/usb.c | 46 | ||||
-rw-r--r-- | drivers/usb/core/usb.h | 19 |
6 files changed, 103 insertions, 48 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index b1046324441..113e484c763 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -24,6 +24,7 @@ #include <linux/device.h> #include <linux/usb.h> +#include <linux/workqueue.h> #include "hcd.h" #include "usb.h" @@ -302,11 +303,11 @@ int usb_driver_claim_interface(struct usb_driver *driver, dev->driver = &driver->drvwrap.driver; usb_set_intfdata(iface, priv); - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); iface->condition = USB_INTERFACE_BOUND; mark_active(iface); iface->pm_usage_cnt = !(driver->supports_autosuspend); - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); /* if interface was already added, bind now; else let * the future device_add() bind it, bypassing probe() @@ -355,11 +356,11 @@ void usb_driver_release_interface(struct usb_driver *driver, dev->driver = NULL; usb_set_intfdata(iface, NULL); - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); iface->condition = USB_INTERFACE_UNBOUND; mark_quiesced(iface); iface->needs_remote_wakeup = 0; - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); } EXPORT_SYMBOL(usb_driver_release_interface); @@ -788,7 +789,7 @@ EXPORT_SYMBOL_GPL_FUTURE(usb_deregister); #ifdef CONFIG_PM -/* Caller has locked udev->pm_mutex */ +/* Caller has locked udev's pm_mutex */ static int suspend_device(struct usb_device *udev, pm_message_t msg) { struct usb_device_driver *udriver; @@ -815,7 +816,7 @@ done: return status; } -/* Caller has locked udev->pm_mutex */ +/* Caller has locked udev's pm_mutex */ static int resume_device(struct usb_device *udev) { struct usb_device_driver *udriver; @@ -841,7 +842,7 @@ done: return status; } -/* Caller has locked intf's usb_device's pm_mutex */ +/* Caller has locked intf's usb_device's pm mutex */ static int suspend_interface(struct usb_interface *intf, pm_message_t msg) { struct usb_driver *driver; @@ -1063,7 +1064,7 @@ int usb_resume_both(struct usb_device *udev) /* Propagate the resume up the tree, if necessary */ if (udev->state == USB_STATE_SUSPENDED) { if (parent) { - mutex_lock_nested(&parent->pm_mutex, parent->level); + usb_pm_lock(parent); parent->auto_pm = 1; status = usb_resume_both(parent); } else { @@ -1078,7 +1079,7 @@ int usb_resume_both(struct usb_device *udev) if (status == 0) status = resume_device(udev); if (parent) - mutex_unlock(&parent->pm_mutex); + usb_pm_unlock(parent); } else { /* Needed only for setting udev->dev.power.power_state.event @@ -1103,8 +1104,8 @@ int usb_resume_both(struct usb_device *udev) /** * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces - * @udev - the usb_device to autosuspend - * @dec_usage_cnt - flag to decrement @udev's PM-usage counter + * @udev: the usb_device to autosuspend + * @dec_usage_cnt: flag to decrement @udev's PM-usage counter * * This routine should be called when a core subsystem is finished using * @udev and wants to allow it to autosuspend. Examples would be when @@ -1128,20 +1129,20 @@ int usb_resume_both(struct usb_device *udev) */ void usb_autosuspend_device(struct usb_device *udev, int dec_usage_cnt) { - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); udev->pm_usage_cnt -= dec_usage_cnt; if (udev->pm_usage_cnt <= 0) - schedule_delayed_work(&udev->autosuspend, + queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, USB_AUTOSUSPEND_DELAY); - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); // dev_dbg(&udev->dev, "%s: cnt %d\n", // __FUNCTION__, udev->pm_usage_cnt); } /** * usb_autoresume_device - immediately autoresume a USB device and its interfaces - * @udev - the usb_device to autoresume - * @inc_usage_cnt - flag to increment @udev's PM-usage counter + * @udev: the usb_device to autoresume + * @inc_usage_cnt: flag to increment @udev's PM-usage counter * * This routine should be called when a core subsystem wants to use @udev * and needs to guarantee that it is not suspended. In addition, the @@ -1167,13 +1168,13 @@ int usb_autoresume_device(struct usb_device *udev, int inc_usage_cnt) { int status; - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); udev->pm_usage_cnt += inc_usage_cnt; udev->auto_pm = 1; status = usb_resume_both(udev); if (status != 0) udev->pm_usage_cnt -= inc_usage_cnt; - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); // dev_dbg(&udev->dev, "%s: status %d cnt %d\n", // __FUNCTION__, status, udev->pm_usage_cnt); return status; @@ -1181,7 +1182,7 @@ int usb_autoresume_device(struct usb_device *udev, int inc_usage_cnt) /** * usb_autopm_put_interface - decrement a USB interface's PM-usage counter - * @intf - the usb_interface whose counter should be decremented + * @intf: the usb_interface whose counter should be decremented * * This routine should be called by an interface driver when it is * finished using @intf and wants to allow it to autosuspend. A typical @@ -1214,13 +1215,13 @@ void usb_autopm_put_interface(struct usb_interface *intf) { struct usb_device *udev = interface_to_usbdev(intf); - mutex_lock_nested(&udev->pm_mutex, udev->level); - if (intf->condition != USB_INTERFACE_UNBOUND) { - if (--intf->pm_usage_cnt <= 0) - schedule_delayed_work(&udev->autosuspend, - USB_AUTOSUSPEND_DELAY); + usb_pm_lock(udev); + if (intf->condition != USB_INTERFACE_UNBOUND && + --intf->pm_usage_cnt <= 0) { + queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, + USB_AUTOSUSPEND_DELAY); } - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); // dev_dbg(&intf->dev, "%s: cnt %d\n", // __FUNCTION__, intf->pm_usage_cnt); } @@ -1228,7 +1229,7 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface); /** * usb_autopm_get_interface - increment a USB interface's PM-usage counter - * @intf - the usb_interface whose counter should be incremented + * @intf: the usb_interface whose counter should be incremented * * This routine should be called by an interface driver when it wants to * use @intf and needs to guarantee that it is not suspended. In addition, @@ -1262,7 +1263,7 @@ int usb_autopm_get_interface(struct usb_interface *intf) struct usb_device *udev = interface_to_usbdev(intf); int status; - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); if (intf->condition == USB_INTERFACE_UNBOUND) status = -ENODEV; else { @@ -1272,7 +1273,7 @@ int usb_autopm_get_interface(struct usb_interface *intf) if (status != 0) --intf->pm_usage_cnt; } - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); // dev_dbg(&intf->dev, "%s: status %d cnt %d\n", // __FUNCTION__, status, intf->pm_usage_cnt); return status; @@ -1288,10 +1289,10 @@ static int usb_suspend(struct device *dev, pm_message_t message) if (is_usb_device(dev)) { struct usb_device *udev = to_usb_device(dev); - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); udev->auto_pm = 0; status = usb_suspend_both(udev, message); - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); } else status = 0; return status; @@ -1304,10 +1305,10 @@ static int usb_resume(struct device *dev) if (is_usb_device(dev)) { struct usb_device *udev = to_usb_device(dev); - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); udev->auto_pm = 0; status = usb_resume_both(udev); - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); /* Rebind drivers that had no suspend method? */ } else diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index e86f6295708..37f9f5e7425 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -345,7 +345,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) struct usb_ctrlrequest *cmd; u16 typeReq, wValue, wIndex, wLength; u8 *ubuf = urb->transfer_buffer; - u8 tbuf [sizeof (struct usb_hub_descriptor)]; + u8 tbuf [sizeof (struct usb_hub_descriptor)] + __attribute__((aligned(4))); const u8 *bufp = tbuf; int len = 0; int patch_wakeup = 0; @@ -835,8 +836,7 @@ 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->poll_rh && - hcd->state != HC_STATE_HALT) + if (hcd->driver->hub_irq_enable && hcd->state != HC_STATE_HALT) hcd->driver->hub_irq_enable (hcd); } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 2a8cb3c2b19..7676690a038 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1779,7 +1779,7 @@ static int remote_wakeup(struct usb_device *udev) * to the parent hub! */ usb_lock_device(udev); - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); if (udev->state == USB_STATE_SUSPENDED) { dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-"); /* TRSMRCY = 10 msec */ @@ -1788,7 +1788,7 @@ static int remote_wakeup(struct usb_device *udev) if (status == 0) udev->dev.power.power_state.event = PM_EVENT_ON; } - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); if (status == 0) usb_autoresume_device(udev, 0); diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index df3d152f049..7c77c2d8d30 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -263,7 +263,7 @@ static struct inode *usbfs_get_inode (struct super_block *sb, int mode, dev_t de inode->i_fop = &simple_dir_operations; /* directory inodes start off with i_nlink == 2 (for "." entry) */ - inode->i_nlink++; + inc_nlink(inode); break; } } @@ -295,7 +295,7 @@ static int usbfs_mkdir (struct inode *dir, struct dentry *dentry, int mode) mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR; res = usbfs_mknod (dir, dentry, mode, 0); if (!res) - dir->i_nlink++; + inc_nlink(dir); return res; } @@ -332,7 +332,7 @@ static int usbfs_unlink (struct inode *dir, struct dentry *dentry) { struct inode *inode = dentry->d_inode; mutex_lock(&inode->i_mutex); - dentry->d_inode->i_nlink--; + drop_nlink(dentry->d_inode); dput(dentry); mutex_unlock(&inode->i_mutex); d_delete(dentry); @@ -347,10 +347,11 @@ static int usbfs_rmdir(struct inode *dir, struct dentry *dentry) mutex_lock(&inode->i_mutex); dentry_unhash(dentry); if (usbfs_empty(dentry)) { - dentry->d_inode->i_nlink -= 2; + drop_nlink(dentry->d_inode); + drop_nlink(dentry->d_inode); dput(dentry); inode->i_flags |= S_DEAD; - dir->i_nlink--; + drop_nlink(dir); error = 0; } mutex_unlock(&inode->i_mutex); diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 60ef4ef0101..e4df9edf1bc 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -33,6 +33,7 @@ #include <linux/smp_lock.h> #include <linux/usb.h> #include <linux/mutex.h> +#include <linux/workqueue.h> #include <asm/io.h> #include <asm/scatterlist.h> @@ -47,6 +48,8 @@ const char *usbcore_name = "usbcore"; static int nousb; /* Disable USB when built into kernel image */ +struct workqueue_struct *ksuspend_usb_wq; /* For autosuspend */ + /** * usb_ifnum_to_if - get the interface object with a given interface number @@ -170,9 +173,9 @@ static void usb_release_dev(struct device *dev) udev = to_usb_device(dev); -#ifdef CONFIG_PM +#ifdef CONFIG_USB_SUSPEND cancel_delayed_work(&udev->autosuspend); - flush_scheduled_work(); + flush_workqueue(ksuspend_usb_wq); #endif usb_destroy_configuration(udev); usb_put_hcd(bus_to_hcd(udev->bus)); @@ -184,17 +187,44 @@ static void usb_release_dev(struct device *dev) #ifdef CONFIG_PM +static int ksuspend_usb_init(void) +{ + ksuspend_usb_wq = create_singlethread_workqueue("ksuspend_usbd"); + if (!ksuspend_usb_wq) + return -ENOMEM; + return 0; +} + +static void ksuspend_usb_cleanup(void) +{ + destroy_workqueue(ksuspend_usb_wq); +} + +#else + +#define ksuspend_usb_init() 0 +#define ksuspend_usb_cleanup() do {} while (0) + +#endif + +#ifdef CONFIG_USB_SUSPEND + /* usb_autosuspend_work - callback routine to autosuspend a USB device */ static void usb_autosuspend_work(void *_udev) { struct usb_device *udev = _udev; - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); udev->auto_pm = 1; usb_suspend_both(udev, PMSG_SUSPEND); - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); } +#else + +static void usb_autosuspend_work(void *_udev) +{} + #endif /** @@ -976,9 +1006,12 @@ static int __init usb_init(void) return 0; } + retval = ksuspend_usb_init(); + if (retval) + goto out; retval = bus_register(&usb_bus_type); if (retval) - goto out; + goto bus_register_failed; retval = usb_host_init(); if (retval) goto host_init_failed; @@ -1014,6 +1047,8 @@ major_init_failed: usb_host_cleanup(); host_init_failed: bus_unregister(&usb_bus_type); +bus_register_failed: + ksuspend_usb_cleanup(); out: return retval; } @@ -1035,6 +1070,7 @@ static void __exit usb_exit(void) usb_hub_cleanup(); usb_host_cleanup(); bus_unregister(&usb_bus_type); + ksuspend_usb_cleanup(); } subsys_initcall(usb_init); diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 0c09ecced6e..f69df137ec0 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -36,6 +36,16 @@ extern int usb_resume_both(struct usb_device *udev); extern int usb_port_suspend(struct usb_device *dev); extern int usb_port_resume(struct usb_device *dev); +static inline void usb_pm_lock(struct usb_device *udev) +{ + mutex_lock_nested(&udev->pm_mutex, udev->level); +} + +static inline void usb_pm_unlock(struct usb_device *udev) +{ + mutex_unlock(&udev->pm_mutex); +} + #else #define usb_suspend_both(udev, msg) 0 @@ -45,6 +55,8 @@ static inline int usb_resume_both(struct usb_device *udev) } #define usb_port_suspend(dev) 0 #define usb_port_resume(dev) 0 +static inline void usb_pm_lock(struct usb_device *udev) {} +static inline void usb_pm_unlock(struct usb_device *udev) {} #endif @@ -58,10 +70,15 @@ extern int usb_autoresume_device(struct usb_device *udev, int inc_busy_cnt); #else #define usb_autosuspend_device(udev, dec_busy_cnt) do {} while (0) -#define usb_autoresume_device(udev, inc_busy_cnt) 0 +static inline int usb_autoresume_device(struct usb_device *udev, + int inc_busy_cnt) +{ + return 0; +} #endif +extern struct workqueue_struct *ksuspend_usb_wq; extern struct bus_type usb_bus_type; extern struct usb_device_driver usb_generic_driver; |