diff options
author | Jussi Kivilinna <jussi.kivilinna@mbnet.fi> | 2011-02-12 13:43:32 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-02-14 15:51:21 -0500 |
commit | eefdbec1ea8b7093d2c09d1825f68438701723cf (patch) | |
tree | 6dc40b6d25f8dede0522927f48c4a716ff9c88c9 /drivers/net/wireless/zd1211rw/zd_usb.c | |
parent | 37939810b937aba830dd751291fcdc51cae1a6cb (diff) |
zd1211rw: use async urb for write command
Writing beacon to device happen through multiple write command calls.
zd_usb_iowrite16v uses synchronous urb call and with multiple write
commands in row causes high CPU usage.
This patch makes zd_usb_iowrite16v use asynchronous urb submit within
zd_usb.c. zd_usb_iowrite16v_async_start is used to initiate writing
multiple commands to device using zd_usb_iowrite16v_async. Each URB
is delayed and submitted to device by next zd_usb_iowrite16v_async
call or by call to zd_usb_iowrite16v_async_end. URBs submitted by
zd_usb_iowrite16v_async have URB_NO_INTERRUPT set and last URB
send by zd_usb_iowrite16v_async_end does not. This lower CPU
usage when doing writes that require multiple URBs.
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/zd1211rw/zd_usb.c')
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_usb.c | 162 |
1 files changed, 138 insertions, 24 deletions
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 7346512158e8..c98f6e7eed3d 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c | |||
@@ -1156,6 +1156,7 @@ void zd_usb_init(struct zd_usb *usb, struct ieee80211_hw *hw, | |||
1156 | memset(usb, 0, sizeof(*usb)); | 1156 | memset(usb, 0, sizeof(*usb)); |
1157 | usb->intf = usb_get_intf(intf); | 1157 | usb->intf = usb_get_intf(intf); |
1158 | usb_set_intfdata(usb->intf, hw); | 1158 | usb_set_intfdata(usb->intf, hw); |
1159 | init_usb_anchor(&usb->submitted_cmds); | ||
1159 | init_usb_interrupt(usb); | 1160 | init_usb_interrupt(usb); |
1160 | init_usb_tx(usb); | 1161 | init_usb_tx(usb); |
1161 | init_usb_rx(usb); | 1162 | init_usb_rx(usb); |
@@ -1663,13 +1664,104 @@ error: | |||
1663 | return r; | 1664 | return r; |
1664 | } | 1665 | } |
1665 | 1666 | ||
1666 | int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, | 1667 | static void iowrite16v_urb_complete(struct urb *urb) |
1667 | unsigned int count) | 1668 | { |
1669 | struct zd_usb *usb = urb->context; | ||
1670 | |||
1671 | if (urb->status && !usb->cmd_error) | ||
1672 | usb->cmd_error = urb->status; | ||
1673 | } | ||
1674 | |||
1675 | static int zd_submit_waiting_urb(struct zd_usb *usb, bool last) | ||
1676 | { | ||
1677 | int r; | ||
1678 | struct urb *urb = usb->urb_async_waiting; | ||
1679 | |||
1680 | if (!urb) | ||
1681 | return 0; | ||
1682 | |||
1683 | usb->urb_async_waiting = NULL; | ||
1684 | |||
1685 | if (!last) | ||
1686 | urb->transfer_flags |= URB_NO_INTERRUPT; | ||
1687 | |||
1688 | usb_anchor_urb(urb, &usb->submitted_cmds); | ||
1689 | r = usb_submit_urb(urb, GFP_KERNEL); | ||
1690 | if (r) { | ||
1691 | usb_unanchor_urb(urb); | ||
1692 | dev_dbg_f(zd_usb_dev(usb), | ||
1693 | "error in usb_submit_urb(). Error number %d\n", r); | ||
1694 | goto error; | ||
1695 | } | ||
1696 | |||
1697 | /* fall-through with r == 0 */ | ||
1698 | error: | ||
1699 | usb_free_urb(urb); | ||
1700 | return r; | ||
1701 | } | ||
1702 | |||
1703 | static void zd_usb_iowrite16v_async_start(struct zd_usb *usb) | ||
1704 | { | ||
1705 | ZD_ASSERT(usb_anchor_empty(&usb->submitted_cmds)); | ||
1706 | ZD_ASSERT(usb->urb_async_waiting == NULL); | ||
1707 | ZD_ASSERT(!usb->in_async); | ||
1708 | |||
1709 | ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex)); | ||
1710 | |||
1711 | usb->in_async = 1; | ||
1712 | usb->cmd_error = 0; | ||
1713 | usb->urb_async_waiting = NULL; | ||
1714 | } | ||
1715 | |||
1716 | static int zd_usb_iowrite16v_async_end(struct zd_usb *usb, unsigned int timeout) | ||
1717 | { | ||
1718 | int r; | ||
1719 | |||
1720 | ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex)); | ||
1721 | ZD_ASSERT(usb->in_async); | ||
1722 | |||
1723 | /* Submit last iowrite16v URB */ | ||
1724 | r = zd_submit_waiting_urb(usb, true); | ||
1725 | if (r) { | ||
1726 | dev_dbg_f(zd_usb_dev(usb), | ||
1727 | "error in zd_submit_waiting_usb(). " | ||
1728 | "Error number %d\n", r); | ||
1729 | |||
1730 | usb_kill_anchored_urbs(&usb->submitted_cmds); | ||
1731 | goto error; | ||
1732 | } | ||
1733 | |||
1734 | if (timeout) | ||
1735 | timeout = usb_wait_anchor_empty_timeout(&usb->submitted_cmds, | ||
1736 | timeout); | ||
1737 | if (!timeout) { | ||
1738 | usb_kill_anchored_urbs(&usb->submitted_cmds); | ||
1739 | if (usb->cmd_error == -ENOENT) { | ||
1740 | dev_dbg_f(zd_usb_dev(usb), "timed out"); | ||
1741 | r = -ETIMEDOUT; | ||
1742 | goto error; | ||
1743 | } | ||
1744 | } | ||
1745 | |||
1746 | r = usb->cmd_error; | ||
1747 | error: | ||
1748 | usb->in_async = 0; | ||
1749 | return r; | ||
1750 | } | ||
1751 | |||
1752 | static int zd_usb_iowrite16v_async(struct zd_usb *usb, | ||
1753 | const struct zd_ioreq16 *ioreqs, | ||
1754 | unsigned int count) | ||
1668 | { | 1755 | { |
1669 | int r; | 1756 | int r; |
1670 | struct usb_device *udev; | 1757 | struct usb_device *udev; |
1671 | struct usb_req_write_regs *req = NULL; | 1758 | struct usb_req_write_regs *req = NULL; |
1672 | int i, req_len, actual_req_len; | 1759 | int i, req_len; |
1760 | struct urb *urb; | ||
1761 | struct usb_host_endpoint *ep; | ||
1762 | |||
1763 | ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex)); | ||
1764 | ZD_ASSERT(usb->in_async); | ||
1673 | 1765 | ||
1674 | if (count == 0) | 1766 | if (count == 0) |
1675 | return 0; | 1767 | return 0; |
@@ -1685,17 +1777,23 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, | |||
1685 | return -EWOULDBLOCK; | 1777 | return -EWOULDBLOCK; |
1686 | } | 1778 | } |
1687 | 1779 | ||
1688 | ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex)); | 1780 | udev = zd_usb_to_usbdev(usb); |
1689 | BUILD_BUG_ON(sizeof(struct usb_req_write_regs) + | 1781 | |
1690 | USB_MAX_IOWRITE16_COUNT * sizeof(struct reg_data) > | 1782 | ep = usb_pipe_endpoint(udev, usb_sndintpipe(udev, EP_REGS_OUT)); |
1691 | sizeof(usb->req_buf)); | 1783 | if (!ep) |
1692 | BUG_ON(sizeof(struct usb_req_write_regs) + | 1784 | return -ENOENT; |
1693 | count * sizeof(struct reg_data) > | 1785 | |
1694 | sizeof(usb->req_buf)); | 1786 | urb = usb_alloc_urb(0, GFP_KERNEL); |
1787 | if (!urb) | ||
1788 | return -ENOMEM; | ||
1695 | 1789 | ||
1696 | req_len = sizeof(struct usb_req_write_regs) + | 1790 | req_len = sizeof(struct usb_req_write_regs) + |
1697 | count * sizeof(struct reg_data); | 1791 | count * sizeof(struct reg_data); |
1698 | req = (void *)usb->req_buf; | 1792 | req = kmalloc(req_len, GFP_KERNEL); |
1793 | if (!req) { | ||
1794 | r = -ENOMEM; | ||
1795 | goto error; | ||
1796 | } | ||
1699 | 1797 | ||
1700 | req->id = cpu_to_le16(USB_REQ_WRITE_REGS); | 1798 | req->id = cpu_to_le16(USB_REQ_WRITE_REGS); |
1701 | for (i = 0; i < count; i++) { | 1799 | for (i = 0; i < count; i++) { |
@@ -1704,28 +1802,44 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, | |||
1704 | rw->value = cpu_to_le16(ioreqs[i].value); | 1802 | rw->value = cpu_to_le16(ioreqs[i].value); |
1705 | } | 1803 | } |
1706 | 1804 | ||
1707 | udev = zd_usb_to_usbdev(usb); | 1805 | usb_fill_int_urb(urb, udev, usb_sndintpipe(udev, EP_REGS_OUT), |
1708 | r = usb_interrupt_msg(udev, usb_sndintpipe(udev, EP_REGS_OUT), | 1806 | req, req_len, iowrite16v_urb_complete, usb, |
1709 | req, req_len, &actual_req_len, 50 /* ms */); | 1807 | ep->desc.bInterval); |
1808 | urb->transfer_flags |= URB_FREE_BUFFER | URB_SHORT_NOT_OK; | ||
1809 | |||
1810 | /* Submit previous URB */ | ||
1811 | r = zd_submit_waiting_urb(usb, false); | ||
1710 | if (r) { | 1812 | if (r) { |
1711 | dev_dbg_f(zd_usb_dev(usb), | 1813 | dev_dbg_f(zd_usb_dev(usb), |
1712 | "error in usb_interrupt_msg(). Error number %d\n", r); | 1814 | "error in zd_submit_waiting_usb(). " |
1713 | goto error; | 1815 | "Error number %d\n", r); |
1714 | } | ||
1715 | if (req_len != actual_req_len) { | ||
1716 | dev_dbg_f(zd_usb_dev(usb), | ||
1717 | "error in usb_interrupt_msg()" | ||
1718 | " req_len %d != actual_req_len %d\n", | ||
1719 | req_len, actual_req_len); | ||
1720 | r = -EIO; | ||
1721 | goto error; | 1816 | goto error; |
1722 | } | 1817 | } |
1723 | 1818 | ||
1724 | /* FALL-THROUGH with r == 0 */ | 1819 | /* Delay submit so that URB_NO_INTERRUPT flag can be set for all URBs |
1820 | * of currect batch except for very last. | ||
1821 | */ | ||
1822 | usb->urb_async_waiting = urb; | ||
1823 | return 0; | ||
1725 | error: | 1824 | error: |
1825 | usb_free_urb(urb); | ||
1726 | return r; | 1826 | return r; |
1727 | } | 1827 | } |
1728 | 1828 | ||
1829 | int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, | ||
1830 | unsigned int count) | ||
1831 | { | ||
1832 | int r; | ||
1833 | |||
1834 | zd_usb_iowrite16v_async_start(usb); | ||
1835 | r = zd_usb_iowrite16v_async(usb, ioreqs, count); | ||
1836 | if (r) { | ||
1837 | zd_usb_iowrite16v_async_end(usb, 0); | ||
1838 | return r; | ||
1839 | } | ||
1840 | return zd_usb_iowrite16v_async_end(usb, 50 /* ms */); | ||
1841 | } | ||
1842 | |||
1729 | int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits) | 1843 | int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits) |
1730 | { | 1844 | { |
1731 | int r; | 1845 | int r; |