diff options
author | hayeswang <hayeswang@realtek.com> | 2013-08-14 08:54:40 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-08-15 04:34:26 -0400 |
commit | 40a82917b1d3a8aecedee6b64949795b75359731 (patch) | |
tree | d7da8f1f86114e0fdb1bc39aa8bfda44d539a9e9 | |
parent | 5bd23881744b72dc22dfd37738d0e82d35306b76 (diff) |
net/usb/r8152: enable interrupt transfer
Use the interrupt transfer to replace polling link status.
Signed-off-by: Hayes Wang <hayeswang@realtek.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/usb/r8152.c | 140 |
1 files changed, 113 insertions, 27 deletions
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 4d938a7fd5f2..ef2498c6d46b 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c | |||
@@ -272,6 +272,9 @@ enum rtl_register_content { | |||
272 | 272 | ||
273 | #define RTL8152_MAX_TX 10 | 273 | #define RTL8152_MAX_TX 10 |
274 | #define RTL8152_MAX_RX 10 | 274 | #define RTL8152_MAX_RX 10 |
275 | #define INTBUFSIZE 2 | ||
276 | |||
277 | #define INTR_LINK 0x0004 | ||
275 | 278 | ||
276 | #define RTL8152_REQT_READ 0xc0 | 279 | #define RTL8152_REQT_READ 0xc0 |
277 | #define RTL8152_REQT_WRITE 0x40 | 280 | #define RTL8152_REQT_WRITE 0x40 |
@@ -292,7 +295,8 @@ enum rtl_register_content { | |||
292 | enum rtl8152_flags { | 295 | enum rtl8152_flags { |
293 | RTL8152_UNPLUG = 0, | 296 | RTL8152_UNPLUG = 0, |
294 | RTL8152_SET_RX_MODE, | 297 | RTL8152_SET_RX_MODE, |
295 | WORK_ENABLE | 298 | WORK_ENABLE, |
299 | RTL8152_LINK_CHG, | ||
296 | }; | 300 | }; |
297 | 301 | ||
298 | /* Define these values to match your device */ | 302 | /* Define these values to match your device */ |
@@ -347,7 +351,9 @@ struct r8152 { | |||
347 | unsigned long flags; | 351 | unsigned long flags; |
348 | struct usb_device *udev; | 352 | struct usb_device *udev; |
349 | struct tasklet_struct tl; | 353 | struct tasklet_struct tl; |
354 | struct usb_interface *intf; | ||
350 | struct net_device *netdev; | 355 | struct net_device *netdev; |
356 | struct urb *intr_urb; | ||
351 | struct tx_agg tx_info[RTL8152_MAX_TX]; | 357 | struct tx_agg tx_info[RTL8152_MAX_TX]; |
352 | struct rx_agg rx_info[RTL8152_MAX_RX]; | 358 | struct rx_agg rx_info[RTL8152_MAX_RX]; |
353 | struct list_head rx_done, tx_free; | 359 | struct list_head rx_done, tx_free; |
@@ -355,8 +361,10 @@ struct r8152 { | |||
355 | spinlock_t rx_lock, tx_lock; | 361 | spinlock_t rx_lock, tx_lock; |
356 | struct delayed_work schedule; | 362 | struct delayed_work schedule; |
357 | struct mii_if_info mii; | 363 | struct mii_if_info mii; |
364 | int intr_interval; | ||
358 | u32 msg_enable; | 365 | u32 msg_enable; |
359 | u16 ocp_base; | 366 | u16 ocp_base; |
367 | u8 *intr_buff; | ||
360 | u8 version; | 368 | u8 version; |
361 | u8 speed; | 369 | u8 speed; |
362 | }; | 370 | }; |
@@ -860,6 +868,62 @@ static void write_bulk_callback(struct urb *urb) | |||
860 | tasklet_schedule(&tp->tl); | 868 | tasklet_schedule(&tp->tl); |
861 | } | 869 | } |
862 | 870 | ||
871 | static void intr_callback(struct urb *urb) | ||
872 | { | ||
873 | struct r8152 *tp; | ||
874 | __u16 *d; | ||
875 | int status = urb->status; | ||
876 | int res; | ||
877 | |||
878 | tp = urb->context; | ||
879 | if (!tp) | ||
880 | return; | ||
881 | |||
882 | if (!test_bit(WORK_ENABLE, &tp->flags)) | ||
883 | return; | ||
884 | |||
885 | if (test_bit(RTL8152_UNPLUG, &tp->flags)) | ||
886 | return; | ||
887 | |||
888 | switch (status) { | ||
889 | case 0: /* success */ | ||
890 | break; | ||
891 | case -ECONNRESET: /* unlink */ | ||
892 | case -ESHUTDOWN: | ||
893 | netif_device_detach(tp->netdev); | ||
894 | case -ENOENT: | ||
895 | return; | ||
896 | case -EOVERFLOW: | ||
897 | netif_info(tp, intr, tp->netdev, "intr status -EOVERFLOW\n"); | ||
898 | goto resubmit; | ||
899 | /* -EPIPE: should clear the halt */ | ||
900 | default: | ||
901 | netif_info(tp, intr, tp->netdev, "intr status %d\n", status); | ||
902 | goto resubmit; | ||
903 | } | ||
904 | |||
905 | d = urb->transfer_buffer; | ||
906 | if (INTR_LINK & __le16_to_cpu(d[0])) { | ||
907 | if (!(tp->speed & LINK_STATUS)) { | ||
908 | set_bit(RTL8152_LINK_CHG, &tp->flags); | ||
909 | schedule_delayed_work(&tp->schedule, 0); | ||
910 | } | ||
911 | } else { | ||
912 | if (tp->speed & LINK_STATUS) { | ||
913 | set_bit(RTL8152_LINK_CHG, &tp->flags); | ||
914 | schedule_delayed_work(&tp->schedule, 0); | ||
915 | } | ||
916 | } | ||
917 | |||
918 | resubmit: | ||
919 | res = usb_submit_urb(urb, GFP_ATOMIC); | ||
920 | if (res == -ENODEV) | ||
921 | netif_device_detach(tp->netdev); | ||
922 | else if (res) | ||
923 | netif_err(tp, intr, tp->netdev, | ||
924 | "can't resubmit intr, status %d\n", res); | ||
925 | } | ||
926 | |||
863 | static inline void *rx_agg_align(void *data) | 927 | static inline void *rx_agg_align(void *data) |
864 | { | 928 | { |
865 | return (void *)ALIGN((uintptr_t)data, 8); | 929 | return (void *)ALIGN((uintptr_t)data, 8); |
@@ -899,11 +963,24 @@ static void free_all_mem(struct r8152 *tp) | |||
899 | tp->tx_info[i].head = NULL; | 963 | tp->tx_info[i].head = NULL; |
900 | } | 964 | } |
901 | } | 965 | } |
966 | |||
967 | if (tp->intr_urb) { | ||
968 | usb_free_urb(tp->intr_urb); | ||
969 | tp->intr_urb = NULL; | ||
970 | } | ||
971 | |||
972 | if (tp->intr_buff) { | ||
973 | kfree(tp->intr_buff); | ||
974 | tp->intr_buff = NULL; | ||
975 | } | ||
902 | } | 976 | } |
903 | 977 | ||
904 | static int alloc_all_mem(struct r8152 *tp) | 978 | static int alloc_all_mem(struct r8152 *tp) |
905 | { | 979 | { |
906 | struct net_device *netdev = tp->netdev; | 980 | struct net_device *netdev = tp->netdev; |
981 | struct usb_interface *intf = tp->intf; | ||
982 | struct usb_host_interface *alt = intf->cur_altsetting; | ||
983 | struct usb_host_endpoint *ep_intr = alt->endpoint + 2; | ||
907 | struct urb *urb; | 984 | struct urb *urb; |
908 | int node, i; | 985 | int node, i; |
909 | u8 *buf; | 986 | u8 *buf; |
@@ -968,6 +1045,19 @@ static int alloc_all_mem(struct r8152 *tp) | |||
968 | list_add_tail(&tp->tx_info[i].list, &tp->tx_free); | 1045 | list_add_tail(&tp->tx_info[i].list, &tp->tx_free); |
969 | } | 1046 | } |
970 | 1047 | ||
1048 | tp->intr_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
1049 | if (!tp->intr_urb) | ||
1050 | goto err1; | ||
1051 | |||
1052 | tp->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL); | ||
1053 | if (!tp->intr_buff) | ||
1054 | goto err1; | ||
1055 | |||
1056 | tp->intr_interval = (int)ep_intr->desc.bInterval; | ||
1057 | usb_fill_int_urb(tp->intr_urb, tp->udev, usb_rcvintpipe(tp->udev, 3), | ||
1058 | tp->intr_buff, INTBUFSIZE, intr_callback, | ||
1059 | tp, tp->intr_interval); | ||
1060 | |||
971 | return 0; | 1061 | return 0; |
972 | 1062 | ||
973 | err1: | 1063 | err1: |
@@ -1228,8 +1318,10 @@ static void rtl8152_set_rx_mode(struct net_device *netdev) | |||
1228 | { | 1318 | { |
1229 | struct r8152 *tp = netdev_priv(netdev); | 1319 | struct r8152 *tp = netdev_priv(netdev); |
1230 | 1320 | ||
1231 | if (tp->speed & LINK_STATUS) | 1321 | if (tp->speed & LINK_STATUS) { |
1232 | set_bit(RTL8152_SET_RX_MODE, &tp->flags); | 1322 | set_bit(RTL8152_SET_RX_MODE, &tp->flags); |
1323 | schedule_delayed_work(&tp->schedule, 0); | ||
1324 | } | ||
1233 | } | 1325 | } |
1234 | 1326 | ||
1235 | static void _rtl8152_set_rx_mode(struct net_device *netdev) | 1327 | static void _rtl8152_set_rx_mode(struct net_device *netdev) |
@@ -1648,7 +1740,6 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex) | |||
1648 | r8152_mdio_write(tp, MII_BMCR, bmcr); | 1740 | r8152_mdio_write(tp, MII_BMCR, bmcr); |
1649 | 1741 | ||
1650 | out: | 1742 | out: |
1651 | schedule_delayed_work(&tp->schedule, 5 * HZ); | ||
1652 | 1743 | ||
1653 | return ret; | 1744 | return ret; |
1654 | } | 1745 | } |
@@ -1671,6 +1762,7 @@ static void set_carrier(struct r8152 *tp) | |||
1671 | struct net_device *netdev = tp->netdev; | 1762 | struct net_device *netdev = tp->netdev; |
1672 | u8 speed; | 1763 | u8 speed; |
1673 | 1764 | ||
1765 | clear_bit(RTL8152_LINK_CHG, &tp->flags); | ||
1674 | speed = rtl8152_get_speed(tp); | 1766 | speed = rtl8152_get_speed(tp); |
1675 | 1767 | ||
1676 | if (speed & LINK_STATUS) { | 1768 | if (speed & LINK_STATUS) { |
@@ -1700,13 +1792,12 @@ static void rtl_work_func_t(struct work_struct *work) | |||
1700 | if (test_bit(RTL8152_UNPLUG, &tp->flags)) | 1792 | if (test_bit(RTL8152_UNPLUG, &tp->flags)) |
1701 | goto out1; | 1793 | goto out1; |
1702 | 1794 | ||
1703 | set_carrier(tp); | 1795 | if (test_bit(RTL8152_LINK_CHG, &tp->flags)) |
1796 | set_carrier(tp); | ||
1704 | 1797 | ||
1705 | if (test_bit(RTL8152_SET_RX_MODE, &tp->flags)) | 1798 | if (test_bit(RTL8152_SET_RX_MODE, &tp->flags)) |
1706 | _rtl8152_set_rx_mode(tp->netdev); | 1799 | _rtl8152_set_rx_mode(tp->netdev); |
1707 | 1800 | ||
1708 | schedule_delayed_work(&tp->schedule, HZ); | ||
1709 | |||
1710 | out1: | 1801 | out1: |
1711 | return; | 1802 | return; |
1712 | } | 1803 | } |
@@ -1716,28 +1807,20 @@ static int rtl8152_open(struct net_device *netdev) | |||
1716 | struct r8152 *tp = netdev_priv(netdev); | 1807 | struct r8152 *tp = netdev_priv(netdev); |
1717 | int res = 0; | 1808 | int res = 0; |
1718 | 1809 | ||
1719 | tp->speed = rtl8152_get_speed(tp); | 1810 | res = usb_submit_urb(tp->intr_urb, GFP_KERNEL); |
1720 | if (tp->speed & LINK_STATUS) { | 1811 | if (res) { |
1721 | res = rtl8152_enable(tp); | 1812 | if (res == -ENODEV) |
1722 | if (res) { | 1813 | netif_device_detach(tp->netdev); |
1723 | if (res == -ENODEV) | 1814 | netif_warn(tp, ifup, netdev, |
1724 | netif_device_detach(tp->netdev); | 1815 | "intr_urb submit failed: %d\n", res); |
1725 | 1816 | return res; | |
1726 | netif_err(tp, ifup, netdev, | ||
1727 | "rtl8152_open failed: %d\n", res); | ||
1728 | return res; | ||
1729 | } | ||
1730 | |||
1731 | netif_carrier_on(netdev); | ||
1732 | } else { | ||
1733 | netif_stop_queue(netdev); | ||
1734 | netif_carrier_off(netdev); | ||
1735 | } | 1817 | } |
1736 | 1818 | ||
1737 | rtl8152_set_speed(tp, AUTONEG_ENABLE, SPEED_100, DUPLEX_FULL); | 1819 | rtl8152_set_speed(tp, AUTONEG_ENABLE, SPEED_100, DUPLEX_FULL); |
1820 | tp->speed = 0; | ||
1821 | netif_carrier_off(netdev); | ||
1738 | netif_start_queue(netdev); | 1822 | netif_start_queue(netdev); |
1739 | set_bit(WORK_ENABLE, &tp->flags); | 1823 | set_bit(WORK_ENABLE, &tp->flags); |
1740 | schedule_delayed_work(&tp->schedule, 0); | ||
1741 | 1824 | ||
1742 | return res; | 1825 | return res; |
1743 | } | 1826 | } |
@@ -1747,6 +1830,7 @@ static int rtl8152_close(struct net_device *netdev) | |||
1747 | struct r8152 *tp = netdev_priv(netdev); | 1830 | struct r8152 *tp = netdev_priv(netdev); |
1748 | int res = 0; | 1831 | int res = 0; |
1749 | 1832 | ||
1833 | usb_kill_urb(tp->intr_urb); | ||
1750 | clear_bit(WORK_ENABLE, &tp->flags); | 1834 | clear_bit(WORK_ENABLE, &tp->flags); |
1751 | cancel_delayed_work_sync(&tp->schedule); | 1835 | cancel_delayed_work_sync(&tp->schedule); |
1752 | netif_stop_queue(netdev); | 1836 | netif_stop_queue(netdev); |
@@ -1872,6 +1956,7 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) | |||
1872 | 1956 | ||
1873 | if (netif_running(tp->netdev)) { | 1957 | if (netif_running(tp->netdev)) { |
1874 | clear_bit(WORK_ENABLE, &tp->flags); | 1958 | clear_bit(WORK_ENABLE, &tp->flags); |
1959 | usb_kill_urb(tp->intr_urb); | ||
1875 | cancel_delayed_work_sync(&tp->schedule); | 1960 | cancel_delayed_work_sync(&tp->schedule); |
1876 | tasklet_disable(&tp->tl); | 1961 | tasklet_disable(&tp->tl); |
1877 | } | 1962 | } |
@@ -1888,10 +1973,11 @@ static int rtl8152_resume(struct usb_interface *intf) | |||
1888 | r8152b_init(tp); | 1973 | r8152b_init(tp); |
1889 | netif_device_attach(tp->netdev); | 1974 | netif_device_attach(tp->netdev); |
1890 | if (netif_running(tp->netdev)) { | 1975 | if (netif_running(tp->netdev)) { |
1891 | rtl8152_enable(tp); | 1976 | rtl8152_set_speed(tp, AUTONEG_ENABLE, SPEED_100, DUPLEX_FULL); |
1977 | tp->speed = 0; | ||
1978 | netif_carrier_off(tp->netdev); | ||
1892 | set_bit(WORK_ENABLE, &tp->flags); | 1979 | set_bit(WORK_ENABLE, &tp->flags); |
1893 | set_bit(RTL8152_SET_RX_MODE, &tp->flags); | 1980 | usb_submit_urb(tp->intr_urb, GFP_KERNEL); |
1894 | schedule_delayed_work(&tp->schedule, 0); | ||
1895 | tasklet_enable(&tp->tl); | 1981 | tasklet_enable(&tp->tl); |
1896 | } | 1982 | } |
1897 | 1983 | ||
@@ -2027,13 +2113,13 @@ static int rtl8152_probe(struct usb_interface *intf, | |||
2027 | 2113 | ||
2028 | tp->udev = udev; | 2114 | tp->udev = udev; |
2029 | tp->netdev = netdev; | 2115 | tp->netdev = netdev; |
2116 | tp->intf = intf; | ||
2030 | netdev->netdev_ops = &rtl8152_netdev_ops; | 2117 | netdev->netdev_ops = &rtl8152_netdev_ops; |
2031 | netdev->watchdog_timeo = RTL8152_TX_TIMEOUT; | 2118 | netdev->watchdog_timeo = RTL8152_TX_TIMEOUT; |
2032 | 2119 | ||
2033 | netdev->features |= NETIF_F_IP_CSUM; | 2120 | netdev->features |= NETIF_F_IP_CSUM; |
2034 | netdev->hw_features = NETIF_F_IP_CSUM; | 2121 | netdev->hw_features = NETIF_F_IP_CSUM; |
2035 | SET_ETHTOOL_OPS(netdev, &ops); | 2122 | SET_ETHTOOL_OPS(netdev, &ops); |
2036 | tp->speed = 0; | ||
2037 | 2123 | ||
2038 | tp->mii.dev = netdev; | 2124 | tp->mii.dev = netdev; |
2039 | tp->mii.mdio_read = read_mii_word; | 2125 | tp->mii.mdio_read = read_mii_word; |