diff options
author | Ming Lei <ming.lei@canonical.com> | 2012-11-05 23:53:04 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-11-07 03:53:38 -0500 |
commit | 0547fad2dd7ccaaf3c914ba49073fa37e4e241eb (patch) | |
tree | 5434c18a01f9c4591c74e0bda596f1d4b29ddd6b | |
parent | ef468d234753aff7afa96075d3be135b0df1ded0 (diff) |
usbnet: introduce usbnet_{read|write}_cmd_nopm
This patch introduces the below two helpers to prepare for solving
the usbnet runtime PM problem, which may cause some network utilities
(ifconfig, ethtool,...) touch a suspended device.
usbnet_read_cmd_nopm()
usbnet_write_cmd_nopm()
The above two helpers should be called by usbnet resume/suspend
callback to avoid deadlock.
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/usb/usbnet.c | 62 | ||||
-rw-r--r-- | include/linux/usb/usbnet.h | 4 |
2 files changed, 61 insertions, 5 deletions
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 447d20d22b7..0ac1ff3571c 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c | |||
@@ -1611,8 +1611,8 @@ void usbnet_device_suggests_idle(struct usbnet *dev) | |||
1611 | EXPORT_SYMBOL(usbnet_device_suggests_idle); | 1611 | EXPORT_SYMBOL(usbnet_device_suggests_idle); |
1612 | 1612 | ||
1613 | /*-------------------------------------------------------------------------*/ | 1613 | /*-------------------------------------------------------------------------*/ |
1614 | int usbnet_read_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, | 1614 | static int __usbnet_read_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, |
1615 | u16 value, u16 index, void *data, u16 size) | 1615 | u16 value, u16 index, void *data, u16 size) |
1616 | { | 1616 | { |
1617 | void *buf = NULL; | 1617 | void *buf = NULL; |
1618 | int err = -ENOMEM; | 1618 | int err = -ENOMEM; |
@@ -1636,10 +1636,10 @@ int usbnet_read_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, | |||
1636 | out: | 1636 | out: |
1637 | return err; | 1637 | return err; |
1638 | } | 1638 | } |
1639 | EXPORT_SYMBOL_GPL(usbnet_read_cmd); | ||
1640 | 1639 | ||
1641 | int usbnet_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, | 1640 | static int __usbnet_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, |
1642 | u16 value, u16 index, const void *data, u16 size) | 1641 | u16 value, u16 index, const void *data, |
1642 | u16 size) | ||
1643 | { | 1643 | { |
1644 | void *buf = NULL; | 1644 | void *buf = NULL; |
1645 | int err = -ENOMEM; | 1645 | int err = -ENOMEM; |
@@ -1662,8 +1662,56 @@ int usbnet_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, | |||
1662 | out: | 1662 | out: |
1663 | return err; | 1663 | return err; |
1664 | } | 1664 | } |
1665 | |||
1666 | /* | ||
1667 | * The function can't be called inside suspend/resume callback, | ||
1668 | * otherwise deadlock will be caused. | ||
1669 | */ | ||
1670 | int usbnet_read_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, | ||
1671 | u16 value, u16 index, void *data, u16 size) | ||
1672 | { | ||
1673 | return __usbnet_read_cmd(dev, cmd, reqtype, value, index, | ||
1674 | data, size); | ||
1675 | } | ||
1676 | EXPORT_SYMBOL_GPL(usbnet_read_cmd); | ||
1677 | |||
1678 | /* | ||
1679 | * The function can't be called inside suspend/resume callback, | ||
1680 | * otherwise deadlock will be caused. | ||
1681 | */ | ||
1682 | int usbnet_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, | ||
1683 | u16 value, u16 index, const void *data, u16 size) | ||
1684 | { | ||
1685 | return __usbnet_write_cmd(dev, cmd, reqtype, value, index, | ||
1686 | data, size); | ||
1687 | } | ||
1665 | EXPORT_SYMBOL_GPL(usbnet_write_cmd); | 1688 | EXPORT_SYMBOL_GPL(usbnet_write_cmd); |
1666 | 1689 | ||
1690 | /* | ||
1691 | * The function can be called inside suspend/resume callback safely | ||
1692 | * and should only be called by suspend/resume callback generally. | ||
1693 | */ | ||
1694 | int usbnet_read_cmd_nopm(struct usbnet *dev, u8 cmd, u8 reqtype, | ||
1695 | u16 value, u16 index, void *data, u16 size) | ||
1696 | { | ||
1697 | return __usbnet_read_cmd(dev, cmd, reqtype, value, index, | ||
1698 | data, size); | ||
1699 | } | ||
1700 | EXPORT_SYMBOL_GPL(usbnet_read_cmd_nopm); | ||
1701 | |||
1702 | /* | ||
1703 | * The function can be called inside suspend/resume callback safely | ||
1704 | * and should only be called by suspend/resume callback generally. | ||
1705 | */ | ||
1706 | int usbnet_write_cmd_nopm(struct usbnet *dev, u8 cmd, u8 reqtype, | ||
1707 | u16 value, u16 index, const void *data, | ||
1708 | u16 size) | ||
1709 | { | ||
1710 | return __usbnet_write_cmd(dev, cmd, reqtype, value, index, | ||
1711 | data, size); | ||
1712 | } | ||
1713 | EXPORT_SYMBOL_GPL(usbnet_write_cmd_nopm); | ||
1714 | |||
1667 | static void usbnet_async_cmd_cb(struct urb *urb) | 1715 | static void usbnet_async_cmd_cb(struct urb *urb) |
1668 | { | 1716 | { |
1669 | struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; | 1717 | struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; |
@@ -1677,6 +1725,10 @@ static void usbnet_async_cmd_cb(struct urb *urb) | |||
1677 | usb_free_urb(urb); | 1725 | usb_free_urb(urb); |
1678 | } | 1726 | } |
1679 | 1727 | ||
1728 | /* | ||
1729 | * The caller must make sure that device can't be put into suspend | ||
1730 | * state until the control URB completes. | ||
1731 | */ | ||
1680 | int usbnet_write_cmd_async(struct usbnet *dev, u8 cmd, u8 reqtype, | 1732 | int usbnet_write_cmd_async(struct usbnet *dev, u8 cmd, u8 reqtype, |
1681 | u16 value, u16 index, const void *data, u16 size) | 1733 | u16 value, u16 index, const void *data, u16 size) |
1682 | { | 1734 | { |
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index 4410e4166c6..9bbeabf66c5 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h | |||
@@ -167,6 +167,10 @@ extern int usbnet_read_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, | |||
167 | u16 value, u16 index, void *data, u16 size); | 167 | u16 value, u16 index, void *data, u16 size); |
168 | extern int usbnet_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, | 168 | extern int usbnet_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, |
169 | u16 value, u16 index, const void *data, u16 size); | 169 | u16 value, u16 index, const void *data, u16 size); |
170 | extern int usbnet_read_cmd_nopm(struct usbnet *dev, u8 cmd, u8 reqtype, | ||
171 | u16 value, u16 index, void *data, u16 size); | ||
172 | extern int usbnet_write_cmd_nopm(struct usbnet *dev, u8 cmd, u8 reqtype, | ||
173 | u16 value, u16 index, const void *data, u16 size); | ||
170 | extern int usbnet_write_cmd_async(struct usbnet *dev, u8 cmd, u8 reqtype, | 174 | extern int usbnet_write_cmd_async(struct usbnet *dev, u8 cmd, u8 reqtype, |
171 | u16 value, u16 index, const void *data, u16 size); | 175 | u16 value, u16 index, const void *data, u16 size); |
172 | 176 | ||