aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2009-06-29 11:00:01 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-09-23 09:46:23 -0400
commitccf5b801cef4f9e2d708d3b87e91e2bc6abd5206 (patch)
tree1b7de13df336f44f6f74657934e79dc8c0bfd142
parent7cbe5dca399a50ce8aa74314b1d276e2fb904e1b (diff)
USB: make intf.pm_usage an atomic_t
This patch (as1260) changes the pm_usage_cnt field in struct usb_interface from an int to an atomic_t. This is so that drivers can invoke the usb_autopm_get_interface_async() and usb_autopm_put_interface_async() routines without locking and without fear of corrupting the pm_usage_cnt value. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/core/driver.c38
-rw-r--r--drivers/usb/core/hub.c5
-rw-r--r--include/linux/usb.h6
3 files changed, 28 insertions, 21 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 1bad4e5a6abb..1c976c141f33 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -235,7 +235,7 @@ static int usb_probe_interface(struct device *dev)
235 /* The interface should always appear to be in use 235 /* The interface should always appear to be in use
236 * unless the driver suports autosuspend. 236 * unless the driver suports autosuspend.
237 */ 237 */
238 intf->pm_usage_cnt = !(driver->supports_autosuspend); 238 atomic_set(&intf->pm_usage_cnt, !driver->supports_autosuspend);
239 239
240 /* Carry out a deferred switch to altsetting 0 */ 240 /* Carry out a deferred switch to altsetting 0 */
241 if (intf->needs_altsetting0) { 241 if (intf->needs_altsetting0) {
@@ -347,7 +347,7 @@ int usb_driver_claim_interface(struct usb_driver *driver,
347 usb_pm_lock(udev); 347 usb_pm_lock(udev);
348 iface->condition = USB_INTERFACE_BOUND; 348 iface->condition = USB_INTERFACE_BOUND;
349 mark_active(iface); 349 mark_active(iface);
350 iface->pm_usage_cnt = !(driver->supports_autosuspend); 350 atomic_set(&iface->pm_usage_cnt, !driver->supports_autosuspend);
351 usb_pm_unlock(udev); 351 usb_pm_unlock(udev);
352 352
353 /* if interface was already added, bind now; else let 353 /* if interface was already added, bind now; else let
@@ -1068,7 +1068,7 @@ static int autosuspend_check(struct usb_device *udev, int reschedule)
1068 intf = udev->actconfig->interface[i]; 1068 intf = udev->actconfig->interface[i];
1069 if (!is_active(intf)) 1069 if (!is_active(intf))
1070 continue; 1070 continue;
1071 if (intf->pm_usage_cnt > 0) 1071 if (atomic_read(&intf->pm_usage_cnt) > 0)
1072 return -EBUSY; 1072 return -EBUSY;
1073 if (intf->needs_remote_wakeup && 1073 if (intf->needs_remote_wakeup &&
1074 !udev->do_remote_wakeup) { 1074 !udev->do_remote_wakeup) {
@@ -1464,17 +1464,19 @@ static int usb_autopm_do_interface(struct usb_interface *intf,
1464 status = -ENODEV; 1464 status = -ENODEV;
1465 else { 1465 else {
1466 udev->auto_pm = 1; 1466 udev->auto_pm = 1;
1467 intf->pm_usage_cnt += inc_usage_cnt; 1467 atomic_add(inc_usage_cnt, &intf->pm_usage_cnt);
1468 udev->last_busy = jiffies; 1468 udev->last_busy = jiffies;
1469 if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) { 1469 if (inc_usage_cnt >= 0 &&
1470 atomic_read(&intf->pm_usage_cnt) > 0) {
1470 if (udev->state == USB_STATE_SUSPENDED) 1471 if (udev->state == USB_STATE_SUSPENDED)
1471 status = usb_resume_both(udev, 1472 status = usb_resume_both(udev,
1472 PMSG_AUTO_RESUME); 1473 PMSG_AUTO_RESUME);
1473 if (status != 0) 1474 if (status != 0)
1474 intf->pm_usage_cnt -= inc_usage_cnt; 1475 atomic_sub(inc_usage_cnt, &intf->pm_usage_cnt);
1475 else 1476 else
1476 udev->last_busy = jiffies; 1477 udev->last_busy = jiffies;
1477 } else if (inc_usage_cnt <= 0 && intf->pm_usage_cnt <= 0) { 1478 } else if (inc_usage_cnt <= 0 &&
1479 atomic_read(&intf->pm_usage_cnt) <= 0) {
1478 status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND); 1480 status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
1479 } 1481 }
1480 } 1482 }
@@ -1519,7 +1521,7 @@ void usb_autopm_put_interface(struct usb_interface *intf)
1519 1521
1520 status = usb_autopm_do_interface(intf, -1); 1522 status = usb_autopm_do_interface(intf, -1);
1521 dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", 1523 dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
1522 __func__, status, intf->pm_usage_cnt); 1524 __func__, status, atomic_read(&intf->pm_usage_cnt));
1523} 1525}
1524EXPORT_SYMBOL_GPL(usb_autopm_put_interface); 1526EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
1525 1527
@@ -1547,10 +1549,10 @@ void usb_autopm_put_interface_async(struct usb_interface *intf)
1547 status = -ENODEV; 1549 status = -ENODEV;
1548 } else { 1550 } else {
1549 udev->last_busy = jiffies; 1551 udev->last_busy = jiffies;
1550 --intf->pm_usage_cnt; 1552 atomic_dec(&intf->pm_usage_cnt);
1551 if (udev->autosuspend_disabled || udev->autosuspend_delay < 0) 1553 if (udev->autosuspend_disabled || udev->autosuspend_delay < 0)
1552 status = -EPERM; 1554 status = -EPERM;
1553 else if (intf->pm_usage_cnt <= 0 && 1555 else if (atomic_read(&intf->pm_usage_cnt) <= 0 &&
1554 !timer_pending(&udev->autosuspend.timer)) { 1556 !timer_pending(&udev->autosuspend.timer)) {
1555 queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, 1557 queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
1556 round_jiffies_up_relative( 1558 round_jiffies_up_relative(
@@ -1558,7 +1560,7 @@ void usb_autopm_put_interface_async(struct usb_interface *intf)
1558 } 1560 }
1559 } 1561 }
1560 dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", 1562 dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
1561 __func__, status, intf->pm_usage_cnt); 1563 __func__, status, atomic_read(&intf->pm_usage_cnt));
1562} 1564}
1563EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async); 1565EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async);
1564 1566
@@ -1602,7 +1604,7 @@ int usb_autopm_get_interface(struct usb_interface *intf)
1602 1604
1603 status = usb_autopm_do_interface(intf, 1); 1605 status = usb_autopm_do_interface(intf, 1);
1604 dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", 1606 dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
1605 __func__, status, intf->pm_usage_cnt); 1607 __func__, status, atomic_read(&intf->pm_usage_cnt));
1606 return status; 1608 return status;
1607} 1609}
1608EXPORT_SYMBOL_GPL(usb_autopm_get_interface); 1610EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
@@ -1630,10 +1632,14 @@ int usb_autopm_get_interface_async(struct usb_interface *intf)
1630 status = -ENODEV; 1632 status = -ENODEV;
1631 else if (udev->autoresume_disabled) 1633 else if (udev->autoresume_disabled)
1632 status = -EPERM; 1634 status = -EPERM;
1633 else if (++intf->pm_usage_cnt > 0 && udev->state == USB_STATE_SUSPENDED) 1635 else {
1634 queue_work(ksuspend_usb_wq, &udev->autoresume); 1636 atomic_inc(&intf->pm_usage_cnt);
1637 if (atomic_read(&intf->pm_usage_cnt) > 0 &&
1638 udev->state == USB_STATE_SUSPENDED)
1639 queue_work(ksuspend_usb_wq, &udev->autoresume);
1640 }
1635 dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", 1641 dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
1636 __func__, status, intf->pm_usage_cnt); 1642 __func__, status, atomic_read(&intf->pm_usage_cnt));
1637 return status; 1643 return status;
1638} 1644}
1639EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async); 1645EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async);
@@ -1655,7 +1661,7 @@ int usb_autopm_set_interface(struct usb_interface *intf)
1655 1661
1656 status = usb_autopm_do_interface(intf, 0); 1662 status = usb_autopm_do_interface(intf, 0);
1657 dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", 1663 dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
1658 __func__, status, intf->pm_usage_cnt); 1664 __func__, status, atomic_read(&intf->pm_usage_cnt));
1659 return status; 1665 return status;
1660} 1666}
1661EXPORT_SYMBOL_GPL(usb_autopm_set_interface); 1667EXPORT_SYMBOL_GPL(usb_autopm_set_interface);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index cb54420ed583..69e3a966a4b7 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -373,7 +373,7 @@ static void kick_khubd(struct usb_hub *hub)
373 unsigned long flags; 373 unsigned long flags;
374 374
375 /* Suppress autosuspend until khubd runs */ 375 /* Suppress autosuspend until khubd runs */
376 to_usb_interface(hub->intfdev)->pm_usage_cnt = 1; 376 atomic_set(&to_usb_interface(hub->intfdev)->pm_usage_cnt, 1);
377 377
378 spin_lock_irqsave(&hub_event_lock, flags); 378 spin_lock_irqsave(&hub_event_lock, flags);
379 if (!hub->disconnected && list_empty(&hub->event_list)) { 379 if (!hub->disconnected && list_empty(&hub->event_list)) {
@@ -678,7 +678,8 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
678 msecs_to_jiffies(delay)); 678 msecs_to_jiffies(delay));
679 679
680 /* Suppress autosuspend until init is done */ 680 /* Suppress autosuspend until init is done */
681 to_usb_interface(hub->intfdev)->pm_usage_cnt = 1; 681 atomic_set(&to_usb_interface(hub->intfdev)->
682 pm_usage_cnt, 1);
682 return; /* Continues at init2: below */ 683 return; /* Continues at init2: below */
683 } else { 684 } else {
684 hub_power_on(hub, true); 685 hub_power_on(hub, true);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 3b45a0d27b80..a34fa89f1474 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -195,7 +195,7 @@ struct usb_interface {
195 195
196 struct device dev; /* interface specific device info */ 196 struct device dev; /* interface specific device info */
197 struct device *usb_dev; 197 struct device *usb_dev;
198 int pm_usage_cnt; /* usage counter for autosuspend */ 198 atomic_t pm_usage_cnt; /* usage counter for autosuspend */
199 struct work_struct reset_ws; /* for resets in atomic context */ 199 struct work_struct reset_ws; /* for resets in atomic context */
200}; 200};
201#define to_usb_interface(d) container_of(d, struct usb_interface, dev) 201#define to_usb_interface(d) container_of(d, struct usb_interface, dev)
@@ -551,13 +551,13 @@ extern void usb_autopm_put_interface_async(struct usb_interface *intf);
551 551
552static inline void usb_autopm_enable(struct usb_interface *intf) 552static inline void usb_autopm_enable(struct usb_interface *intf)
553{ 553{
554 intf->pm_usage_cnt = 0; 554 atomic_set(&intf->pm_usage_cnt, 0);
555 usb_autopm_set_interface(intf); 555 usb_autopm_set_interface(intf);
556} 556}
557 557
558static inline void usb_autopm_disable(struct usb_interface *intf) 558static inline void usb_autopm_disable(struct usb_interface *intf)
559{ 559{
560 intf->pm_usage_cnt = 1; 560 atomic_set(&intf->pm_usage_cnt, 1);
561 usb_autopm_set_interface(intf); 561 usb_autopm_set_interface(intf);
562} 562}
563 563