Commit d823ab68 authored by hayeswang's avatar hayeswang Committed by David S. Miller

r8152: replace tasklet with NAPI

Replace tasklet with NAPI.

Add rx_queue to queue the remaining rx packets if the number of the
rx packets is more than the request from poll().
Signed-off-by: default avatarHayes Wang <hayeswang@realtek.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 237de6ef
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include <linux/usb/cdc.h> #include <linux/usb/cdc.h>
/* Version Information */ /* 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_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
#define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" #define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters"
#define MODULENAME "r8152" #define MODULENAME "r8152"
...@@ -448,6 +448,7 @@ enum rtl_register_content { ...@@ -448,6 +448,7 @@ enum rtl_register_content {
#define RTL8152_RMS (VLAN_ETH_FRAME_LEN + VLAN_HLEN) #define RTL8152_RMS (VLAN_ETH_FRAME_LEN + VLAN_HLEN)
#define RTL8153_RMS RTL8153_MAX_PACKET #define RTL8153_RMS RTL8153_MAX_PACKET
#define RTL8152_TX_TIMEOUT (5 * HZ) #define RTL8152_TX_TIMEOUT (5 * HZ)
#define RTL8152_NAPI_WEIGHT 64
/* rtl8152 flags */ /* rtl8152 flags */
enum rtl8152_flags { enum rtl8152_flags {
...@@ -457,7 +458,7 @@ enum rtl8152_flags { ...@@ -457,7 +458,7 @@ enum rtl8152_flags {
RTL8152_LINK_CHG, RTL8152_LINK_CHG,
SELECTIVE_SUSPEND, SELECTIVE_SUSPEND,
PHY_RESET, PHY_RESET,
SCHEDULE_TASKLET, SCHEDULE_NAPI,
}; };
/* Define these values to match your device */ /* Define these values to match your device */
...@@ -549,14 +550,14 @@ struct tx_agg { ...@@ -549,14 +550,14 @@ struct tx_agg {
struct r8152 { struct r8152 {
unsigned long flags; unsigned long flags;
struct usb_device *udev; struct usb_device *udev;
struct tasklet_struct tl; struct napi_struct napi;
struct usb_interface *intf; struct usb_interface *intf;
struct net_device *netdev; struct net_device *netdev;
struct urb *intr_urb; struct urb *intr_urb;
struct tx_agg tx_info[RTL8152_MAX_TX]; struct tx_agg tx_info[RTL8152_MAX_TX];
struct rx_agg rx_info[RTL8152_MAX_RX]; struct rx_agg rx_info[RTL8152_MAX_RX];
struct list_head rx_done, tx_free; 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; spinlock_t rx_lock, tx_lock;
struct delayed_work schedule; struct delayed_work schedule;
struct mii_if_info mii; struct mii_if_info mii;
...@@ -1062,7 +1063,7 @@ static void read_bulk_callback(struct urb *urb) ...@@ -1062,7 +1063,7 @@ static void read_bulk_callback(struct urb *urb)
spin_lock(&tp->rx_lock); spin_lock(&tp->rx_lock);
list_add_tail(&agg->list, &tp->rx_done); list_add_tail(&agg->list, &tp->rx_done);
spin_unlock(&tp->rx_lock); spin_unlock(&tp->rx_lock);
tasklet_schedule(&tp->tl); napi_schedule(&tp->napi);
return; return;
case -ESHUTDOWN: case -ESHUTDOWN:
set_bit(RTL8152_UNPLUG, &tp->flags); set_bit(RTL8152_UNPLUG, &tp->flags);
...@@ -1126,7 +1127,7 @@ static void write_bulk_callback(struct urb *urb) ...@@ -1126,7 +1127,7 @@ static void write_bulk_callback(struct urb *urb)
return; return;
if (!skb_queue_empty(&tp->tx_queue)) if (!skb_queue_empty(&tp->tx_queue))
tasklet_schedule(&tp->tl); napi_schedule(&tp->napi);
} }
static void intr_callback(struct urb *urb) static void intr_callback(struct urb *urb)
...@@ -1245,6 +1246,7 @@ static int alloc_all_mem(struct r8152 *tp) ...@@ -1245,6 +1246,7 @@ static int alloc_all_mem(struct r8152 *tp)
spin_lock_init(&tp->tx_lock); spin_lock_init(&tp->tx_lock);
INIT_LIST_HEAD(&tp->tx_free); INIT_LIST_HEAD(&tp->tx_free);
skb_queue_head_init(&tp->tx_queue); skb_queue_head_init(&tp->tx_queue);
skb_queue_head_init(&tp->rx_queue);
for (i = 0; i < RTL8152_MAX_RX; i++) { for (i = 0; i < RTL8152_MAX_RX; i++) {
buf = kmalloc_node(agg_buf_sz, GFP_KERNEL, node); buf = kmalloc_node(agg_buf_sz, GFP_KERNEL, node);
...@@ -1649,13 +1651,32 @@ static u8 r8152_rx_csum(struct r8152 *tp, struct rx_desc *rx_desc) ...@@ -1649,13 +1651,32 @@ static u8 r8152_rx_csum(struct r8152 *tp, struct rx_desc *rx_desc)
return checksum; return checksum;
} }
static void rx_bottom(struct r8152 *tp) static int rx_bottom(struct r8152 *tp, int budget)
{ {
unsigned long flags; unsigned long flags;
struct list_head *cursor, *next, rx_queue; struct list_head *cursor, *next, rx_queue;
int 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)) if (list_empty(&tp->rx_done))
return; goto out1;
INIT_LIST_HEAD(&rx_queue); INIT_LIST_HEAD(&rx_queue);
spin_lock_irqsave(&tp->rx_lock, flags); spin_lock_irqsave(&tp->rx_lock, flags);
...@@ -1708,9 +1729,14 @@ static void rx_bottom(struct r8152 *tp) ...@@ -1708,9 +1729,14 @@ static void rx_bottom(struct r8152 *tp)
skb_put(skb, pkt_len); skb_put(skb, pkt_len);
skb->protocol = eth_type_trans(skb, netdev); skb->protocol = eth_type_trans(skb, netdev);
rtl_rx_vlan_tag(rx_desc, skb); rtl_rx_vlan_tag(rx_desc, skb);
netif_receive_skb(skb); if (work_done < budget) {
stats->rx_packets++; napi_gro_receive(&tp->napi, skb);
stats->rx_bytes += pkt_len; work_done++;
stats->rx_packets++;
stats->rx_bytes += pkt_len;
} else {
__skb_queue_tail(&tp->rx_queue, skb);
}
find_next_rx: find_next_rx:
rx_data = rx_agg_align(rx_data + pkt_len + CRC_SIZE); rx_data = rx_agg_align(rx_data + pkt_len + CRC_SIZE);
...@@ -1722,6 +1748,9 @@ static void rx_bottom(struct r8152 *tp) ...@@ -1722,6 +1748,9 @@ static void rx_bottom(struct r8152 *tp)
submit: submit:
r8152_submit_rx(tp, agg, GFP_ATOMIC); r8152_submit_rx(tp, agg, GFP_ATOMIC);
} }
out1:
return work_done;
} }
static void tx_bottom(struct r8152 *tp) static void tx_bottom(struct r8152 *tp)
...@@ -1761,12 +1790,8 @@ static void tx_bottom(struct r8152 *tp) ...@@ -1761,12 +1790,8 @@ static void tx_bottom(struct r8152 *tp)
} while (res == 0); } 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)) if (test_bit(RTL8152_UNPLUG, &tp->flags))
return; return;
...@@ -1778,12 +1803,28 @@ static void bottom_half(unsigned long data) ...@@ -1778,12 +1803,28 @@ static void bottom_half(unsigned long data)
if (!netif_carrier_ok(tp->netdev)) if (!netif_carrier_ok(tp->netdev))
return; return;
clear_bit(SCHEDULE_TASKLET, &tp->flags); clear_bit(SCHEDULE_NAPI, &tp->flags);
rx_bottom(tp);
tx_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 static
int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags) int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags)
{ {
...@@ -1810,7 +1851,11 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags) ...@@ -1810,7 +1851,11 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags)
spin_lock_irqsave(&tp->rx_lock, flags); spin_lock_irqsave(&tp->rx_lock, flags);
list_add_tail(&agg->list, &tp->rx_done); list_add_tail(&agg->list, &tp->rx_done);
spin_unlock_irqrestore(&tp->rx_lock, flags); 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; return ret;
...@@ -1929,11 +1974,11 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb, ...@@ -1929,11 +1974,11 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
if (!list_empty(&tp->tx_free)) { if (!list_empty(&tp->tx_free)) {
if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { 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); schedule_delayed_work(&tp->schedule, 0);
} else { } else {
usb_mark_last_busy(tp->udev); 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) { } else if (skb_queue_len(&tp->tx_queue) > tp->tx_qlen) {
netif_stop_queue(netdev); netif_stop_queue(netdev);
...@@ -2012,6 +2057,7 @@ static int rtl_start_rx(struct r8152 *tp) ...@@ -2012,6 +2057,7 @@ static int rtl_start_rx(struct r8152 *tp)
{ {
int i, ret = 0; int i, ret = 0;
napi_disable(&tp->napi);
INIT_LIST_HEAD(&tp->rx_done); INIT_LIST_HEAD(&tp->rx_done);
for (i = 0; i < RTL8152_MAX_RX; i++) { for (i = 0; i < RTL8152_MAX_RX; i++) {
INIT_LIST_HEAD(&tp->rx_info[i].list); INIT_LIST_HEAD(&tp->rx_info[i].list);
...@@ -2019,6 +2065,7 @@ static int rtl_start_rx(struct r8152 *tp) ...@@ -2019,6 +2065,7 @@ static int rtl_start_rx(struct r8152 *tp)
if (ret) if (ret)
break; break;
} }
napi_enable(&tp->napi);
if (ret && ++i < RTL8152_MAX_RX) { if (ret && ++i < RTL8152_MAX_RX) {
struct list_head rx_queue; struct list_head rx_queue;
...@@ -2049,6 +2096,9 @@ static int rtl_stop_rx(struct r8152 *tp) ...@@ -2049,6 +2096,9 @@ static int rtl_stop_rx(struct r8152 *tp)
for (i = 0; i < RTL8152_MAX_RX; i++) for (i = 0; i < RTL8152_MAX_RX; i++)
usb_kill_urb(tp->rx_info[i].urb); 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; return 0;
} }
...@@ -2884,9 +2934,9 @@ static void set_carrier(struct r8152 *tp) ...@@ -2884,9 +2934,9 @@ static void set_carrier(struct r8152 *tp)
} else { } else {
if (tp->speed & LINK_STATUS) { if (tp->speed & LINK_STATUS) {
netif_carrier_off(netdev); netif_carrier_off(netdev);
tasklet_disable(&tp->tl); napi_disable(&tp->napi);
tp->rtl_ops.disable(tp); tp->rtl_ops.disable(tp);
tasklet_enable(&tp->tl); napi_enable(&tp->napi);
} }
} }
tp->speed = speed; tp->speed = speed;
...@@ -2919,10 +2969,11 @@ static void rtl_work_func_t(struct work_struct *work) ...@@ -2919,10 +2969,11 @@ static void rtl_work_func_t(struct work_struct *work)
if (test_bit(RTL8152_SET_RX_MODE, &tp->flags)) if (test_bit(RTL8152_SET_RX_MODE, &tp->flags))
_rtl8152_set_rx_mode(tp->netdev); _rtl8152_set_rx_mode(tp->netdev);
if (test_bit(SCHEDULE_TASKLET, &tp->flags) && /* don't schedule napi before linking */
if (test_bit(SCHEDULE_NAPI, &tp->flags) &&
(tp->speed & LINK_STATUS)) { (tp->speed & LINK_STATUS)) {
clear_bit(SCHEDULE_TASKLET, &tp->flags); clear_bit(SCHEDULE_NAPI, &tp->flags);
tasklet_schedule(&tp->tl); napi_schedule(&tp->napi);
} }
if (test_bit(PHY_RESET, &tp->flags)) if (test_bit(PHY_RESET, &tp->flags))
...@@ -2983,7 +3034,7 @@ static int rtl8152_open(struct net_device *netdev) ...@@ -2983,7 +3034,7 @@ static int rtl8152_open(struct net_device *netdev)
res); res);
free_all_mem(tp); free_all_mem(tp);
} else { } else {
tasklet_enable(&tp->tl); napi_enable(&tp->napi);
} }
mutex_unlock(&tp->control); mutex_unlock(&tp->control);
...@@ -2999,7 +3050,7 @@ static int rtl8152_close(struct net_device *netdev) ...@@ -2999,7 +3050,7 @@ static int rtl8152_close(struct net_device *netdev)
struct r8152 *tp = netdev_priv(netdev); struct r8152 *tp = netdev_priv(netdev);
int res = 0; int res = 0;
tasklet_disable(&tp->tl); napi_disable(&tp->napi);
clear_bit(WORK_ENABLE, &tp->flags); clear_bit(WORK_ENABLE, &tp->flags);
usb_kill_urb(tp->intr_urb); usb_kill_urb(tp->intr_urb);
cancel_delayed_work_sync(&tp->schedule); cancel_delayed_work_sync(&tp->schedule);
...@@ -3008,6 +3059,7 @@ static int rtl8152_close(struct net_device *netdev) ...@@ -3008,6 +3059,7 @@ static int rtl8152_close(struct net_device *netdev)
res = usb_autopm_get_interface(tp->intf); res = usb_autopm_get_interface(tp->intf);
if (res < 0) { if (res < 0) {
rtl_drop_queued_tx(tp); rtl_drop_queued_tx(tp);
rtl_stop_rx(tp);
} else { } else {
mutex_lock(&tp->control); mutex_lock(&tp->control);
...@@ -3263,7 +3315,7 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) ...@@ -3263,7 +3315,7 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) { if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) {
clear_bit(WORK_ENABLE, &tp->flags); clear_bit(WORK_ENABLE, &tp->flags);
usb_kill_urb(tp->intr_urb); usb_kill_urb(tp->intr_urb);
tasklet_disable(&tp->tl); napi_disable(&tp->napi);
if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
rtl_stop_rx(tp); rtl_stop_rx(tp);
rtl_runtime_suspend_enable(tp, true); rtl_runtime_suspend_enable(tp, true);
...@@ -3271,7 +3323,7 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) ...@@ -3271,7 +3323,7 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
cancel_delayed_work_sync(&tp->schedule); cancel_delayed_work_sync(&tp->schedule);
tp->rtl_ops.down(tp); tp->rtl_ops.down(tp);
} }
tasklet_enable(&tp->tl); napi_enable(&tp->napi);
} }
out1: out1:
mutex_unlock(&tp->control); mutex_unlock(&tp->control);
...@@ -3855,7 +3907,6 @@ static int rtl8152_probe(struct usb_interface *intf, ...@@ -3855,7 +3907,6 @@ static int rtl8152_probe(struct usb_interface *intf,
if (ret) if (ret)
goto out; goto out;
tasklet_init(&tp->tl, bottom_half, (unsigned long)tp);
mutex_init(&tp->control); mutex_init(&tp->control);
INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t); INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t);
...@@ -3891,6 +3942,7 @@ static int rtl8152_probe(struct usb_interface *intf, ...@@ -3891,6 +3942,7 @@ static int rtl8152_probe(struct usb_interface *intf,
set_ethernet_addr(tp); set_ethernet_addr(tp);
usb_set_intfdata(intf, tp); usb_set_intfdata(intf, tp);
netif_napi_add(netdev, &tp->napi, r8152_poll, RTL8152_NAPI_WEIGHT);
ret = register_netdev(netdev); ret = register_netdev(netdev);
if (ret != 0) { if (ret != 0) {
...@@ -3904,15 +3956,13 @@ static int rtl8152_probe(struct usb_interface *intf, ...@@ -3904,15 +3956,13 @@ static int rtl8152_probe(struct usb_interface *intf,
else else
device_set_wakeup_enable(&udev->dev, false); device_set_wakeup_enable(&udev->dev, false);
tasklet_disable(&tp->tl);
netif_info(tp, probe, netdev, "%s\n", DRIVER_VERSION); netif_info(tp, probe, netdev, "%s\n", DRIVER_VERSION);
return 0; return 0;
out1: out1:
netif_napi_del(&tp->napi);
usb_set_intfdata(intf, NULL); usb_set_intfdata(intf, NULL);
tasklet_kill(&tp->tl);
out: out:
free_netdev(netdev); free_netdev(netdev);
return ret; return ret;
...@@ -3929,7 +3979,7 @@ static void rtl8152_disconnect(struct usb_interface *intf) ...@@ -3929,7 +3979,7 @@ static void rtl8152_disconnect(struct usb_interface *intf)
if (udev->state == USB_STATE_NOTATTACHED) if (udev->state == USB_STATE_NOTATTACHED)
set_bit(RTL8152_UNPLUG, &tp->flags); set_bit(RTL8152_UNPLUG, &tp->flags);
tasklet_kill(&tp->tl); netif_napi_del(&tp->napi);
unregister_netdev(tp->netdev); unregister_netdev(tp->netdev);
tp->rtl_ops.unload(tp); tp->rtl_ops.unload(tp);
free_netdev(tp->netdev); free_netdev(tp->netdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment