diff options
Diffstat (limited to 'drivers/net/usb/r8152.c')
-rw-r--r-- | drivers/net/usb/r8152.c | 229 |
1 files changed, 139 insertions, 90 deletions
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index bf405f134d3..5980ac6c48d 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -27,7 +27,7 @@ #include <linux/usb/cdc.h> /* Version Information */ -#define DRIVER_VERSION "v1.07.0 (2014/10/09)" +#define DRIVER_VERSION "v1.08.0 (2015/01/13)" #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>" #define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" #define MODULENAME "r8152" @@ -448,6 +448,7 @@ enum rtl_register_content { #define RTL8152_RMS (VLAN_ETH_FRAME_LEN + VLAN_HLEN) #define RTL8153_RMS RTL8153_MAX_PACKET #define RTL8152_TX_TIMEOUT (5 * HZ) +#define RTL8152_NAPI_WEIGHT 64 /* rtl8152 flags */ enum rtl8152_flags { @@ -457,7 +458,7 @@ enum rtl8152_flags { RTL8152_LINK_CHG, SELECTIVE_SUSPEND, PHY_RESET, - SCHEDULE_TASKLET, + SCHEDULE_NAPI, }; /* Define these values to match your device */ @@ -488,16 +489,16 @@ struct rx_desc { #define RX_LEN_MASK 0x7fff __le32 opts2; -#define RD_UDP_CS (1 << 23) -#define RD_TCP_CS (1 << 22) -#define RD_IPV6_CS (1 << 20) -#define RD_IPV4_CS (1 << 19) +#define RD_UDP_CS BIT(23) +#define RD_TCP_CS BIT(22) +#define RD_IPV6_CS BIT(20) +#define RD_IPV4_CS BIT(19) __le32 opts3; -#define IPF (1 << 23) /* IP checksum fail */ -#define UDPF (1 << 22) /* UDP checksum fail */ -#define TCPF (1 << 21) /* TCP checksum fail */ -#define RX_VLAN_TAG (1 << 16) +#define IPF BIT(23) /* IP checksum fail */ +#define UDPF BIT(22) /* UDP checksum fail */ +#define TCPF BIT(21) /* TCP checksum fail */ +#define RX_VLAN_TAG BIT(16) __le32 opts4; __le32 opts5; @@ -506,24 +507,24 @@ struct rx_desc { struct tx_desc { __le32 opts1; -#define TX_FS (1 << 31) /* First segment of a packet */ -#define TX_LS (1 << 30) /* Final segment of a packet */ -#define GTSENDV4 (1 << 28) -#define GTSENDV6 (1 << 27) +#define TX_FS BIT(31) /* First segment of a packet */ +#define TX_LS BIT(30) /* Final segment of a packet */ +#define GTSENDV4 BIT(28) +#define GTSENDV6 BIT(27) #define GTTCPHO_SHIFT 18 #define GTTCPHO_MAX 0x7fU #define TX_LEN_MAX 0x3ffffU __le32 opts2; -#define UDP_CS (1 << 31) /* Calculate UDP/IP checksum */ -#define TCP_CS (1 << 30) /* Calculate TCP/IP checksum */ -#define IPV4_CS (1 << 29) /* Calculate IPv4 checksum */ -#define IPV6_CS (1 << 28) /* Calculate IPv6 checksum */ +#define UDP_CS BIT(31) /* Calculate UDP/IP checksum */ +#define TCP_CS BIT(30) /* Calculate TCP/IP checksum */ +#define IPV4_CS BIT(29) /* Calculate IPv4 checksum */ +#define IPV6_CS BIT(28) /* Calculate IPv6 checksum */ #define MSS_SHIFT 17 #define MSS_MAX 0x7ffU #define TCPHO_SHIFT 17 #define TCPHO_MAX 0x7ffU -#define TX_VLAN_TAG (1 << 16) +#define TX_VLAN_TAG BIT(16) }; struct r8152; @@ -549,14 +550,14 @@ struct tx_agg { struct r8152 { unsigned long flags; struct usb_device *udev; - struct tasklet_struct tl; + struct napi_struct napi; struct usb_interface *intf; struct net_device *netdev; struct urb *intr_urb; struct tx_agg tx_info[RTL8152_MAX_TX]; struct rx_agg rx_info[RTL8152_MAX_RX]; struct list_head rx_done, tx_free; - struct sk_buff_head tx_queue; + struct sk_buff_head tx_queue, rx_queue; spinlock_t rx_lock, tx_lock; struct delayed_work schedule; struct mii_if_info mii; @@ -580,7 +581,6 @@ struct r8152 { u16 ocp_base; u8 *intr_buff; u8 version; - u8 speed; }; enum rtl_version { @@ -1050,7 +1050,7 @@ static void read_bulk_callback(struct urb *urb) spin_lock(&tp->rx_lock); list_add_tail(&agg->list, &tp->rx_done); spin_unlock(&tp->rx_lock); - tasklet_schedule(&tp->tl); + napi_schedule(&tp->napi); return; case -ESHUTDOWN: set_bit(RTL8152_UNPLUG, &tp->flags); @@ -1114,7 +1114,7 @@ static void write_bulk_callback(struct urb *urb) return; if (!skb_queue_empty(&tp->tx_queue)) - tasklet_schedule(&tp->tl); + napi_schedule(&tp->napi); } static void intr_callback(struct urb *urb) @@ -1156,12 +1156,12 @@ static void intr_callback(struct urb *urb) d = urb->transfer_buffer; if (INTR_LINK & __le16_to_cpu(d[0])) { - if (!(tp->speed & LINK_STATUS)) { + if (!netif_carrier_ok(tp->netdev)) { set_bit(RTL8152_LINK_CHG, &tp->flags); schedule_delayed_work(&tp->schedule, 0); } } else { - if (tp->speed & LINK_STATUS) { + if (netif_carrier_ok(tp->netdev)) { set_bit(RTL8152_LINK_CHG, &tp->flags); schedule_delayed_work(&tp->schedule, 0); } @@ -1233,6 +1233,7 @@ static int alloc_all_mem(struct r8152 *tp) spin_lock_init(&tp->tx_lock); INIT_LIST_HEAD(&tp->tx_free); skb_queue_head_init(&tp->tx_queue); + skb_queue_head_init(&tp->rx_queue); for (i = 0; i < RTL8152_MAX_RX; i++) { buf = kmalloc_node(agg_buf_sz, GFP_KERNEL, node); @@ -1329,18 +1330,6 @@ static struct tx_agg *r8152_get_tx_agg(struct r8152 *tp) return agg; } -static inline __be16 get_protocol(struct sk_buff *skb) -{ - __be16 protocol; - - if (skb->protocol == htons(ETH_P_8021Q)) - protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto; - else - protocol = skb->protocol; - - return protocol; -} - /* r8152_csum_workaround() * The hw limites the value the transport offset. When the offset is out of the * range, calculate the checksum by sw. @@ -1409,10 +1398,10 @@ static int msdn_giant_send_check(struct sk_buff *skb) static inline void rtl_tx_vlan_tag(struct tx_desc *desc, struct sk_buff *skb) { - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { u32 opts2; - opts2 = TX_VLAN_TAG | swab16(vlan_tx_tag_get(skb)); + opts2 = TX_VLAN_TAG | swab16(skb_vlan_tag_get(skb)); desc->opts2 |= cpu_to_le32(opts2); } } @@ -1446,7 +1435,7 @@ static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, goto unavailable; } - switch (get_protocol(skb)) { + switch (vlan_get_protocol(skb)) { case htons(ETH_P_IP): opts1 |= GTSENDV4; break; @@ -1477,7 +1466,7 @@ static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, goto unavailable; } - switch (get_protocol(skb)) { + switch (vlan_get_protocol(skb)) { case htons(ETH_P_IP): opts2 |= IPV4_CS; ip_protocol = ip_hdr(skb)->protocol; @@ -1637,13 +1626,32 @@ return_result: return checksum; } -static void rx_bottom(struct r8152 *tp) +static int rx_bottom(struct r8152 *tp, int budget) { unsigned long flags; struct list_head *cursor, *next, rx_queue; + int ret = 0, work_done = 0; + + if (!skb_queue_empty(&tp->rx_queue)) { + while (work_done < budget) { + struct sk_buff *skb = __skb_dequeue(&tp->rx_queue); + struct net_device *netdev = tp->netdev; + struct net_device_stats *stats = &netdev->stats; + unsigned int pkt_len; + + if (!skb) + break; + + pkt_len = skb->len; + napi_gro_receive(&tp->napi, skb); + work_done++; + stats->rx_packets++; + stats->rx_bytes += pkt_len; + } + } if (list_empty(&tp->rx_done)) - return; + goto out1; INIT_LIST_HEAD(&rx_queue); spin_lock_irqsave(&tp->rx_lock, flags); @@ -1696,9 +1704,14 @@ static void rx_bottom(struct r8152 *tp) skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, netdev); rtl_rx_vlan_tag(rx_desc, skb); - netif_receive_skb(skb); - stats->rx_packets++; - stats->rx_bytes += pkt_len; + if (work_done < budget) { + napi_gro_receive(&tp->napi, skb); + work_done++; + stats->rx_packets++; + stats->rx_bytes += pkt_len; + } else { + __skb_queue_tail(&tp->rx_queue, skb); + } find_next_rx: rx_data = rx_agg_align(rx_data + pkt_len + CRC_SIZE); @@ -1708,8 +1721,22 @@ find_next_rx: } submit: - r8152_submit_rx(tp, agg, GFP_ATOMIC); + if (!ret) { + ret = r8152_submit_rx(tp, agg, GFP_ATOMIC); + } else { + urb->actual_length = 0; + list_add_tail(&agg->list, next); + } } + + if (!list_empty(&rx_queue)) { + spin_lock_irqsave(&tp->rx_lock, flags); + list_splice_tail(&rx_queue, &tp->rx_done); + spin_unlock_irqrestore(&tp->rx_lock, flags); + } + +out1: + return work_done; } static void tx_bottom(struct r8152 *tp) @@ -1749,12 +1776,8 @@ static void tx_bottom(struct r8152 *tp) } while (res == 0); } -static void bottom_half(unsigned long data) +static void bottom_half(struct r8152 *tp) { - struct r8152 *tp; - - tp = (struct r8152 *)data; - if (test_bit(RTL8152_UNPLUG, &tp->flags)) return; @@ -1766,17 +1789,38 @@ static void bottom_half(unsigned long data) if (!netif_carrier_ok(tp->netdev)) return; - clear_bit(SCHEDULE_TASKLET, &tp->flags); + clear_bit(SCHEDULE_NAPI, &tp->flags); - rx_bottom(tp); tx_bottom(tp); } +static int r8152_poll(struct napi_struct *napi, int budget) +{ + struct r8152 *tp = container_of(napi, struct r8152, napi); + int work_done; + + work_done = rx_bottom(tp, budget); + bottom_half(tp); + + if (work_done < budget) { + napi_complete(napi); + if (!list_empty(&tp->rx_done)) + napi_schedule(napi); + } + + return work_done; +} + static int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags) { int ret; + /* The rx would be stopped, so skip submitting */ + if (test_bit(RTL8152_UNPLUG, &tp->flags) || + !test_bit(WORK_ENABLE, &tp->flags) || !netif_carrier_ok(tp->netdev)) + return 0; + usb_fill_bulk_urb(agg->urb, tp->udev, usb_rcvbulkpipe(tp->udev, 1), agg->head, agg_buf_sz, (usb_complete_t)read_bulk_callback, agg); @@ -1793,7 +1837,11 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags) spin_lock_irqsave(&tp->rx_lock, flags); list_add_tail(&agg->list, &tp->rx_done); spin_unlock_irqrestore(&tp->rx_lock, flags); - tasklet_schedule(&tp->tl); + + netif_err(tp, rx_err, tp->netdev, + "Couldn't submit rx[%p], ret = %d\n", agg, ret); + + napi_schedule(&tp->napi); } return ret; @@ -1833,7 +1881,7 @@ static void rtl8152_set_rx_mode(struct net_device *netdev) { struct r8152 *tp = netdev_priv(netdev); - if (tp->speed & LINK_STATUS) { + if (netif_carrier_ok(netdev)) { set_bit(RTL8152_SET_RX_MODE, &tp->flags); schedule_delayed_work(&tp->schedule, 0); } @@ -1912,11 +1960,11 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb, if (!list_empty(&tp->tx_free)) { if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { - set_bit(SCHEDULE_TASKLET, &tp->flags); + set_bit(SCHEDULE_NAPI, &tp->flags); schedule_delayed_work(&tp->schedule, 0); } else { usb_mark_last_busy(tp->udev); - tasklet_schedule(&tp->tl); + napi_schedule(&tp->napi); } } else if (skb_queue_len(&tp->tx_queue) > tp->tx_qlen) { netif_stop_queue(netdev); @@ -1995,6 +2043,7 @@ static int rtl_start_rx(struct r8152 *tp) { int i, ret = 0; + napi_disable(&tp->napi); INIT_LIST_HEAD(&tp->rx_done); for (i = 0; i < RTL8152_MAX_RX; i++) { INIT_LIST_HEAD(&tp->rx_info[i].list); @@ -2002,6 +2051,7 @@ static int rtl_start_rx(struct r8152 *tp) if (ret) break; } + napi_enable(&tp->napi); if (ret && ++i < RTL8152_MAX_RX) { struct list_head rx_queue; @@ -2032,6 +2082,9 @@ static int rtl_stop_rx(struct r8152 *tp) for (i = 0; i < RTL8152_MAX_RX; i++) usb_kill_urb(tp->rx_info[i].urb); + while (!skb_queue_empty(&tp->rx_queue)) + dev_kfree_skb(__skb_dequeue(&tp->rx_queue)); + return 0; } @@ -2047,7 +2100,7 @@ static int rtl_enable(struct r8152 *tp) rxdy_gated_en(tp, false); - return rtl_start_rx(tp); + return 0; } static int rtl8152_enable(struct r8152 *tp) @@ -2852,20 +2905,20 @@ static void set_carrier(struct r8152 *tp) speed = rtl8152_get_speed(tp); if (speed & LINK_STATUS) { - if (!(tp->speed & LINK_STATUS)) { + if (!netif_carrier_ok(netdev)) { tp->rtl_ops.enable(tp); set_bit(RTL8152_SET_RX_MODE, &tp->flags); netif_carrier_on(netdev); + rtl_start_rx(tp); } } else { - if (tp->speed & LINK_STATUS) { + if (netif_carrier_ok(netdev)) { netif_carrier_off(netdev); - tasklet_disable(&tp->tl); + napi_disable(&tp->napi); tp->rtl_ops.disable(tp); - tasklet_enable(&tp->tl); + napi_enable(&tp->napi); } } - tp->speed = speed; } static void rtl_work_func_t(struct work_struct *work) @@ -2895,10 +2948,11 @@ static void rtl_work_func_t(struct work_struct *work) if (test_bit(RTL8152_SET_RX_MODE, &tp->flags)) _rtl8152_set_rx_mode(tp->netdev); - if (test_bit(SCHEDULE_TASKLET, &tp->flags) && - (tp->speed & LINK_STATUS)) { - clear_bit(SCHEDULE_TASKLET, &tp->flags); - tasklet_schedule(&tp->tl); + /* don't schedule napi before linking */ + if (test_bit(SCHEDULE_NAPI, &tp->flags) && + netif_carrier_ok(tp->netdev)) { + clear_bit(SCHEDULE_NAPI, &tp->flags); + napi_schedule(&tp->napi); } if (test_bit(PHY_RESET, &tp->flags)) @@ -2919,8 +2973,7 @@ static int rtl8152_open(struct net_device *netdev) if (res) goto out; - /* set speed to 0 to avoid autoresume try to submit rx */ - tp->speed = 0; + netif_carrier_off(netdev); res = usb_autopm_get_interface(tp->intf); if (res < 0) { @@ -2937,7 +2990,7 @@ static int rtl8152_open(struct net_device *netdev) cancel_delayed_work_sync(&tp->schedule); /* disable the tx/rx, if the workqueue has enabled them. */ - if (tp->speed & LINK_STATUS) + if (netif_carrier_ok(netdev)) tp->rtl_ops.disable(tp); } @@ -2946,7 +2999,6 @@ static int rtl8152_open(struct net_device *netdev) rtl8152_set_speed(tp, AUTONEG_ENABLE, tp->mii.supports_gmii ? SPEED_1000 : SPEED_100, DUPLEX_FULL); - tp->speed = 0; netif_carrier_off(netdev); netif_start_queue(netdev); set_bit(WORK_ENABLE, &tp->flags); @@ -2959,7 +3011,7 @@ static int rtl8152_open(struct net_device *netdev) res); free_all_mem(tp); } else { - tasklet_enable(&tp->tl); + napi_enable(&tp->napi); } mutex_unlock(&tp->control); @@ -2975,15 +3027,16 @@ static int rtl8152_close(struct net_device *netdev) struct r8152 *tp = netdev_priv(netdev); int res = 0; - tasklet_disable(&tp->tl); + napi_disable(&tp->napi); clear_bit(WORK_ENABLE, &tp->flags); usb_kill_urb(tp->intr_urb); cancel_delayed_work_sync(&tp->schedule); netif_stop_queue(netdev); res = usb_autopm_get_interface(tp->intf); - if (res < 0) { + if (res < 0 || test_bit(RTL8152_UNPLUG, &tp->flags)) { rtl_drop_queued_tx(tp); + rtl_stop_rx(tp); } else { mutex_lock(&tp->control); @@ -3187,10 +3240,10 @@ static void r8153_init(struct r8152 *tp) ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_LPM_CTRL); ocp_data &= ~LPM_TIMER_MASK; - if (tp->udev->speed == USB_SPEED_SUPER) - ocp_data |= LPM_TIMER_500US; - else + if (tp->version == RTL_VER_04 && tp->udev->speed != USB_SPEED_SUPER) ocp_data |= LPM_TIMER_500MS; + else + ocp_data |= LPM_TIMER_500US; ocp_write_byte(tp, MCU_TYPE_USB, USB_LPM_CTRL, ocp_data); ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2); @@ -3239,7 +3292,7 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) { clear_bit(WORK_ENABLE, &tp->flags); usb_kill_urb(tp->intr_urb); - tasklet_disable(&tp->tl); + napi_disable(&tp->napi); if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { rtl_stop_rx(tp); rtl_runtime_suspend_enable(tp, true); @@ -3247,7 +3300,7 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) cancel_delayed_work_sync(&tp->schedule); tp->rtl_ops.down(tp); } - tasklet_enable(&tp->tl); + napi_enable(&tp->napi); } out1: mutex_unlock(&tp->control); @@ -3271,7 +3324,7 @@ static int rtl8152_resume(struct usb_interface *intf) rtl_runtime_suspend_enable(tp, false); clear_bit(SELECTIVE_SUSPEND, &tp->flags); set_bit(WORK_ENABLE, &tp->flags); - if (tp->speed & LINK_STATUS) + if (netif_carrier_ok(tp->netdev)) rtl_start_rx(tp); } else { tp->rtl_ops.up(tp); @@ -3279,7 +3332,6 @@ static int rtl8152_resume(struct usb_interface *intf) tp->mii.supports_gmii ? SPEED_1000 : SPEED_100, DUPLEX_FULL); - tp->speed = 0; netif_carrier_off(tp->netdev); set_bit(WORK_ENABLE, &tp->flags); } @@ -3831,7 +3883,6 @@ static int rtl8152_probe(struct usb_interface *intf, if (ret) goto out; - tasklet_init(&tp->tl, bottom_half, (unsigned long)tp); mutex_init(&tp->control); INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t); @@ -3845,8 +3896,7 @@ static int rtl8152_probe(struct usb_interface *intf, netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO | NETIF_F_FRAGLIST | NETIF_F_IPV6_CSUM | NETIF_F_TSO6 | - NETIF_F_HW_VLAN_CTAG_RX | - NETIF_F_HW_VLAN_CTAG_TX; + NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX; netdev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | NETIF_F_IPV6_CSUM | NETIF_F_TSO6; @@ -3867,6 +3917,7 @@ static int rtl8152_probe(struct usb_interface *intf, set_ethernet_addr(tp); usb_set_intfdata(intf, tp); + netif_napi_add(netdev, &tp->napi, r8152_poll, RTL8152_NAPI_WEIGHT); ret = register_netdev(netdev); if (ret != 0) { @@ -3880,15 +3931,13 @@ static int rtl8152_probe(struct usb_interface *intf, else device_set_wakeup_enable(&udev->dev, false); - tasklet_disable(&tp->tl); - netif_info(tp, probe, netdev, "%s\n", DRIVER_VERSION); return 0; out1: + netif_napi_del(&tp->napi); usb_set_intfdata(intf, NULL); - tasklet_kill(&tp->tl); out: free_netdev(netdev); return ret; @@ -3905,7 +3954,7 @@ static void rtl8152_disconnect(struct usb_interface *intf) if (udev->state == USB_STATE_NOTATTACHED) set_bit(RTL8152_UNPLUG, &tp->flags); - tasklet_kill(&tp->tl); + netif_napi_del(&tp->napi); unregister_netdev(tp->netdev); tp->rtl_ops.unload(tp); free_netdev(tp->netdev); |