提交 ebc2ec48 编写于 作者: H hayeswang 提交者: David S. Miller

net/usb/r8152: support aggregation

Enable the tx/rx aggregation which could contain one or more packets
for each bulk in/out. This could reduce the loading of the host
controller by sending less bulk transfer.

The rx packets in the bulk in buffer should be 8-byte aligned, and
the tx packets in the bulk out buffer should be 4-byte aligned.
Signed-off-by: NHayes Wang <hayeswang@realtek.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 fce9b9be
...@@ -19,9 +19,10 @@ ...@@ -19,9 +19,10 @@
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/list.h>
/* Version Information */ /* Version Information */
#define DRIVER_VERSION "v1.0.0 (2013/05/03)" #define DRIVER_VERSION "v1.01.0 (2013/08/12)"
#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 Based USB 2.0 Ethernet Adapters" #define DRIVER_DESC "Realtek RTL8152 Based USB 2.0 Ethernet Adapters"
#define MODULENAME "r8152" #define MODULENAME "r8152"
...@@ -267,6 +268,9 @@ enum rtl_register_content { ...@@ -267,6 +268,9 @@ enum rtl_register_content {
FULL_DUP = 0x01, FULL_DUP = 0x01,
}; };
#define RTL8152_MAX_TX 10
#define RTL8152_MAX_RX 10
#define RTL8152_REQT_READ 0xc0 #define RTL8152_REQT_READ 0xc0
#define RTL8152_REQT_WRITE 0x40 #define RTL8152_REQT_WRITE 0x40
#define RTL8152_REQ_GET_REGS 0x05 #define RTL8152_REQ_GET_REGS 0x05
...@@ -285,7 +289,6 @@ enum rtl_register_content { ...@@ -285,7 +289,6 @@ enum rtl_register_content {
/* rtl8152 flags */ /* rtl8152 flags */
enum rtl8152_flags { enum rtl8152_flags {
RTL8152_UNPLUG = 0, RTL8152_UNPLUG = 0,
RX_URB_FAIL,
RTL8152_SET_RX_MODE, RTL8152_SET_RX_MODE,
WORK_ENABLE WORK_ENABLE
}; };
...@@ -315,13 +318,34 @@ struct tx_desc { ...@@ -315,13 +318,34 @@ struct tx_desc {
u32 opts2; u32 opts2;
}; };
struct rx_agg {
struct list_head list;
struct urb *urb;
void *context;
void *buffer;
void *head;
};
struct tx_agg {
struct list_head list;
struct urb *urb;
void *context;
void *buffer;
void *head;
u32 skb_num;
u32 skb_len;
};
struct r8152 { struct r8152 {
unsigned long flags; unsigned long flags;
struct usb_device *udev; struct usb_device *udev;
struct tasklet_struct tl; struct tasklet_struct tl;
struct net_device *netdev; struct net_device *netdev;
struct urb *rx_urb, *tx_urb; struct tx_agg tx_info[RTL8152_MAX_TX];
struct sk_buff *tx_skb, *rx_skb; struct rx_agg rx_info[RTL8152_MAX_RX];
struct list_head rx_done, tx_free;
struct sk_buff_head tx_queue;
spinlock_t rx_lock, tx_lock;
struct delayed_work schedule; struct delayed_work schedule;
struct mii_if_info mii; struct mii_if_info mii;
u32 msg_enable; u32 msg_enable;
...@@ -340,6 +364,7 @@ enum rtl_version { ...@@ -340,6 +364,7 @@ enum rtl_version {
* The RTL chips use a 64 element hash table based on the Ethernet CRC. * The RTL chips use a 64 element hash table based on the Ethernet CRC.
*/ */
static const int multicast_filter_limit = 32; static const int multicast_filter_limit = 32;
static unsigned int rx_buf_sz = 16384;
static static
int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
...@@ -686,6 +711,9 @@ static void ocp_reg_write(struct r8152 *tp, u16 addr, u16 data) ...@@ -686,6 +711,9 @@ static void ocp_reg_write(struct r8152 *tp, u16 addr, u16 data)
ocp_write_word(tp, MCU_TYPE_PLA, ocp_index, data); ocp_write_word(tp, MCU_TYPE_PLA, ocp_index, data);
} }
static
int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags);
static inline void set_ethernet_addr(struct r8152 *tp) static inline void set_ethernet_addr(struct r8152 *tp)
{ {
struct net_device *dev = tp->netdev; struct net_device *dev = tp->netdev;
...@@ -716,26 +744,6 @@ static int rtl8152_set_mac_address(struct net_device *netdev, void *p) ...@@ -716,26 +744,6 @@ static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
return 0; return 0;
} }
static int alloc_all_urbs(struct r8152 *tp)
{
tp->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!tp->rx_urb)
return 0;
tp->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!tp->tx_urb) {
usb_free_urb(tp->rx_urb);
return 0;
}
return 1;
}
static void free_all_urbs(struct r8152 *tp)
{
usb_free_urb(tp->rx_urb);
usb_free_urb(tp->tx_urb);
}
static struct net_device_stats *rtl8152_get_stats(struct net_device *dev) static struct net_device_stats *rtl8152_get_stats(struct net_device *dev)
{ {
return &dev->stats; return &dev->stats;
...@@ -743,129 +751,425 @@ static struct net_device_stats *rtl8152_get_stats(struct net_device *dev) ...@@ -743,129 +751,425 @@ static struct net_device_stats *rtl8152_get_stats(struct net_device *dev)
static void read_bulk_callback(struct urb *urb) static void read_bulk_callback(struct urb *urb)
{ {
struct r8152 *tp;
unsigned pkt_len;
struct sk_buff *skb;
struct net_device *netdev; struct net_device *netdev;
struct net_device_stats *stats; unsigned long lockflags;
int status = urb->status; int status = urb->status;
struct rx_agg *agg;
struct r8152 *tp;
int result; int result;
struct rx_desc *rx_desc;
tp = urb->context; agg = urb->context;
if (!agg)
return;
tp = agg->context;
if (!tp) if (!tp)
return; return;
if (test_bit(RTL8152_UNPLUG, &tp->flags)) if (test_bit(RTL8152_UNPLUG, &tp->flags))
return; return;
if (!test_bit(WORK_ENABLE, &tp->flags))
return;
netdev = tp->netdev; netdev = tp->netdev;
if (!netif_device_present(netdev)) if (!netif_carrier_ok(netdev))
return; return;
stats = rtl8152_get_stats(netdev);
switch (status) { switch (status) {
case 0: case 0:
break; if (urb->actual_length < ETH_ZLEN)
break;
spin_lock_irqsave(&tp->rx_lock, lockflags);
list_add_tail(&agg->list, &tp->rx_done);
spin_unlock_irqrestore(&tp->rx_lock, lockflags);
tasklet_schedule(&tp->tl);
return;
case -ESHUTDOWN: case -ESHUTDOWN:
set_bit(RTL8152_UNPLUG, &tp->flags); set_bit(RTL8152_UNPLUG, &tp->flags);
netif_device_detach(tp->netdev); netif_device_detach(tp->netdev);
return;
case -ENOENT: case -ENOENT:
return; /* the urb is in unlink state */ return; /* the urb is in unlink state */
case -ETIME: case -ETIME:
pr_warn_ratelimited("may be reset is needed?..\n"); pr_warn_ratelimited("may be reset is needed?..\n");
goto goon; break;
default: default:
pr_warn_ratelimited("Rx status %d\n", status); pr_warn_ratelimited("Rx status %d\n", status);
goto goon; break;
} }
/* protect against short packets (tell me why we got some?!?) */ result = r8152_submit_rx(tp, agg, GFP_ATOMIC);
if (urb->actual_length < sizeof(*rx_desc))
goto goon;
rx_desc = (struct rx_desc *)urb->transfer_buffer;
pkt_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK;
if (urb->actual_length < sizeof(struct rx_desc) + pkt_len)
goto goon;
skb = netdev_alloc_skb_ip_align(netdev, pkt_len);
if (!skb)
goto goon;
memcpy(skb->data, tp->rx_skb->data + sizeof(struct rx_desc), pkt_len);
skb_put(skb, pkt_len);
skb->protocol = eth_type_trans(skb, netdev);
netif_rx(skb);
stats->rx_packets++;
stats->rx_bytes += pkt_len;
goon:
usb_fill_bulk_urb(tp->rx_urb, tp->udev, usb_rcvbulkpipe(tp->udev, 1),
tp->rx_skb->data, RTL8152_RMS + sizeof(struct rx_desc),
(usb_complete_t)read_bulk_callback, tp);
result = usb_submit_urb(tp->rx_urb, GFP_ATOMIC);
if (result == -ENODEV) { if (result == -ENODEV) {
netif_device_detach(tp->netdev); netif_device_detach(tp->netdev);
} else if (result) { } else if (result) {
set_bit(RX_URB_FAIL, &tp->flags); spin_lock_irqsave(&tp->rx_lock, lockflags);
goto resched; list_add_tail(&agg->list, &tp->rx_done);
} else { spin_unlock_irqrestore(&tp->rx_lock, lockflags);
clear_bit(RX_URB_FAIL, &tp->flags); tasklet_schedule(&tp->tl);
} }
return;
resched:
tasklet_schedule(&tp->tl);
} }
static void rx_fixup(unsigned long data) static void write_bulk_callback(struct urb *urb)
{ {
struct net_device_stats *stats;
unsigned long lockflags;
struct tx_agg *agg;
struct r8152 *tp; struct r8152 *tp;
int status; int status = urb->status;
tp = (struct r8152 *)data; agg = urb->context;
if (!test_bit(WORK_ENABLE, &tp->flags)) if (!agg)
return; return;
status = usb_submit_urb(tp->rx_urb, GFP_ATOMIC); tp = agg->context;
if (status == -ENODEV) { if (!tp)
netif_device_detach(tp->netdev); return;
} else if (status) {
set_bit(RX_URB_FAIL, &tp->flags); stats = rtl8152_get_stats(tp->netdev);
goto tlsched; if (status) {
pr_warn_ratelimited("Tx status %d\n", status);
stats->tx_errors += agg->skb_num;
} else { } else {
clear_bit(RX_URB_FAIL, &tp->flags); stats->tx_packets += agg->skb_num;
stats->tx_bytes += agg->skb_len;
} }
return; spin_lock_irqsave(&tp->tx_lock, lockflags);
tlsched: list_add_tail(&agg->list, &tp->tx_free);
tasklet_schedule(&tp->tl); spin_unlock_irqrestore(&tp->tx_lock, lockflags);
if (!netif_carrier_ok(tp->netdev))
return;
if (!test_bit(WORK_ENABLE, &tp->flags))
return;
if (test_bit(RTL8152_UNPLUG, &tp->flags))
return;
if (!skb_queue_empty(&tp->tx_queue))
tasklet_schedule(&tp->tl);
} }
static void write_bulk_callback(struct urb *urb) static inline void *rx_agg_align(void *data)
{
return (void *)ALIGN((uintptr_t)data, 8);
}
static inline void *tx_agg_align(void *data)
{
return (void *)ALIGN((uintptr_t)data, 4);
}
static void free_all_mem(struct r8152 *tp)
{
int i;
for (i = 0; i < RTL8152_MAX_RX; i++) {
if (tp->rx_info[i].urb) {
usb_free_urb(tp->rx_info[i].urb);
tp->rx_info[i].urb = NULL;
}
if (tp->rx_info[i].buffer) {
kfree(tp->rx_info[i].buffer);
tp->rx_info[i].buffer = NULL;
tp->rx_info[i].head = NULL;
}
}
for (i = 0; i < RTL8152_MAX_TX; i++) {
if (tp->tx_info[i].urb) {
usb_free_urb(tp->tx_info[i].urb);
tp->tx_info[i].urb = NULL;
}
if (tp->tx_info[i].buffer) {
kfree(tp->tx_info[i].buffer);
tp->tx_info[i].buffer = NULL;
tp->tx_info[i].head = NULL;
}
}
}
static int alloc_all_mem(struct r8152 *tp)
{
struct net_device *netdev = tp->netdev;
struct urb *urb;
int node, i;
u8 *buf;
node = netdev->dev.parent ? dev_to_node(netdev->dev.parent) : -1;
spin_lock_init(&tp->rx_lock);
spin_lock_init(&tp->tx_lock);
INIT_LIST_HEAD(&tp->rx_done);
INIT_LIST_HEAD(&tp->tx_free);
skb_queue_head_init(&tp->tx_queue);
for (i = 0; i < RTL8152_MAX_RX; i++) {
buf = kmalloc_node(rx_buf_sz, GFP_KERNEL, node);
if (!buf)
goto err1;
if (buf != rx_agg_align(buf)) {
kfree(buf);
buf = kmalloc_node(rx_buf_sz + 8, GFP_KERNEL, node);
if (!buf)
goto err1;
}
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
kfree(buf);
goto err1;
}
INIT_LIST_HEAD(&tp->rx_info[i].list);
tp->rx_info[i].context = tp;
tp->rx_info[i].urb = urb;
tp->rx_info[i].buffer = buf;
tp->rx_info[i].head = rx_agg_align(buf);
}
for (i = 0; i < RTL8152_MAX_TX; i++) {
buf = kmalloc_node(rx_buf_sz, GFP_KERNEL, node);
if (!buf)
goto err1;
if (buf != tx_agg_align(buf)) {
kfree(buf);
buf = kmalloc_node(rx_buf_sz + 4, GFP_KERNEL, node);
if (!buf)
goto err1;
}
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
kfree(buf);
goto err1;
}
INIT_LIST_HEAD(&tp->tx_info[i].list);
tp->tx_info[i].context = tp;
tp->tx_info[i].urb = urb;
tp->tx_info[i].buffer = buf;
tp->tx_info[i].head = tx_agg_align(buf);
list_add_tail(&tp->tx_info[i].list, &tp->tx_free);
}
return 0;
err1:
free_all_mem(tp);
return -ENOMEM;
}
static void rx_bottom(struct r8152 *tp)
{
struct net_device_stats *stats;
struct net_device *netdev;
struct rx_agg *agg;
struct rx_desc *rx_desc;
unsigned long lockflags;
struct list_head *cursor, *next;
struct sk_buff *skb;
struct urb *urb;
unsigned pkt_len;
int len_used;
u8 *rx_data;
int ret;
netdev = tp->netdev;
stats = rtl8152_get_stats(netdev);
spin_lock_irqsave(&tp->rx_lock, lockflags);
list_for_each_safe(cursor, next, &tp->rx_done) {
list_del_init(cursor);
spin_unlock_irqrestore(&tp->rx_lock, lockflags);
agg = list_entry(cursor, struct rx_agg, list);
urb = agg->urb;
if (urb->actual_length < ETH_ZLEN) {
ret = r8152_submit_rx(tp, agg, GFP_ATOMIC);
spin_lock_irqsave(&tp->rx_lock, lockflags);
if (ret && ret != -ENODEV) {
list_add_tail(&agg->list, next);
tasklet_schedule(&tp->tl);
}
continue;
}
len_used = 0;
rx_desc = agg->head;
rx_data = agg->head;
pkt_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK;
len_used += sizeof(struct rx_desc) + pkt_len;
while (urb->actual_length >= len_used) {
if (pkt_len < ETH_ZLEN)
break;
pkt_len -= 4; /* CRC */
rx_data += sizeof(struct rx_desc);
skb = netdev_alloc_skb_ip_align(netdev, pkt_len);
if (!skb) {
stats->rx_dropped++;
break;
}
memcpy(skb->data, rx_data, pkt_len);
skb_put(skb, pkt_len);
skb->protocol = eth_type_trans(skb, netdev);
netif_rx(skb);
stats->rx_packets++;
stats->rx_bytes += pkt_len;
rx_data = rx_agg_align(rx_data + pkt_len + 4);
rx_desc = (struct rx_desc *)rx_data;
pkt_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK;
len_used = (int)(rx_data - (u8 *)agg->head);
len_used += sizeof(struct rx_desc) + pkt_len;
}
ret = r8152_submit_rx(tp, agg, GFP_ATOMIC);
spin_lock_irqsave(&tp->rx_lock, lockflags);
if (ret && ret != -ENODEV) {
list_add_tail(&agg->list, next);
tasklet_schedule(&tp->tl);
}
}
spin_unlock_irqrestore(&tp->rx_lock, lockflags);
}
static void tx_bottom(struct r8152 *tp)
{
struct net_device_stats *stats;
struct net_device *netdev;
struct tx_agg *agg;
unsigned long lockflags;
u32 remain, total;
u8 *tx_data;
int res;
netdev = tp->netdev;
next_agg:
agg = NULL;
spin_lock_irqsave(&tp->tx_lock, lockflags);
if (!skb_queue_empty(&tp->tx_queue) && !list_empty(&tp->tx_free)) {
struct list_head *cursor;
cursor = tp->tx_free.next;
list_del_init(cursor);
agg = list_entry(cursor, struct tx_agg, list);
}
spin_unlock_irqrestore(&tp->tx_lock, lockflags);
if (!agg)
return;
tx_data = agg->head;
agg->skb_num = agg->skb_len = 0;
remain = rx_buf_sz - sizeof(struct tx_desc);
total = 0;
while (remain >= ETH_ZLEN) {
struct tx_desc *tx_desc;
struct sk_buff *skb;
unsigned int len;
skb = skb_dequeue(&tp->tx_queue);
if (!skb)
break;
len = skb->len;
if (remain < len) {
skb_queue_head(&tp->tx_queue, skb);
break;
}
tx_data = tx_agg_align(tx_data);
tx_desc = (struct tx_desc *)tx_data;
tx_data += sizeof(*tx_desc);
tx_desc->opts1 = cpu_to_le32((skb->len & TX_LEN_MASK) | TX_FS |
TX_LS);
memcpy(tx_data, skb->data, len);
agg->skb_num++;
agg->skb_len += len;
dev_kfree_skb_any(skb);
tx_data += len;
remain = rx_buf_sz - sizeof(*tx_desc) -
(u32)(tx_agg_align(tx_data) - agg->head);
}
usb_fill_bulk_urb(agg->urb, tp->udev, usb_sndbulkpipe(tp->udev, 2),
agg->head, (int)(tx_data - (u8 *)agg->head),
(usb_complete_t)write_bulk_callback, agg);
res = usb_submit_urb(agg->urb, GFP_ATOMIC);
stats = rtl8152_get_stats(netdev);
if (res) {
/* Can we get/handle EPIPE here? */
if (res == -ENODEV) {
netif_device_detach(netdev);
} else {
netif_warn(tp, tx_err, netdev,
"failed tx_urb %d\n", res);
stats->tx_dropped += agg->skb_num;
spin_lock_irqsave(&tp->tx_lock, lockflags);
list_add_tail(&agg->list, &tp->tx_free);
spin_unlock_irqrestore(&tp->tx_lock, lockflags);
}
return;
}
goto next_agg;
}
static void bottom_half(unsigned long data)
{ {
struct r8152 *tp; struct r8152 *tp;
int status = urb->status;
tp = urb->context; tp = (struct r8152 *)data;
if (!tp)
if (test_bit(RTL8152_UNPLUG, &tp->flags))
return;
if (!test_bit(WORK_ENABLE, &tp->flags))
return; return;
dev_kfree_skb_irq(tp->tx_skb);
if (!netif_device_present(tp->netdev)) if (!netif_carrier_ok(tp->netdev))
return; return;
if (status)
dev_info(&urb->dev->dev, "%s: Tx status %d\n", rx_bottom(tp);
tp->netdev->name, status); tx_bottom(tp);
tp->netdev->trans_start = jiffies; }
netif_wake_queue(tp->netdev);
static
int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags)
{
usb_fill_bulk_urb(agg->urb, tp->udev, usb_rcvbulkpipe(tp->udev, 1),
agg->head, rx_buf_sz,
(usb_complete_t)read_bulk_callback, agg);
return usb_submit_urb(agg->urb, mem_flags);
} }
static void rtl8152_tx_timeout(struct net_device *netdev) static void rtl8152_tx_timeout(struct net_device *netdev)
{ {
struct r8152 *tp = netdev_priv(netdev); struct r8152 *tp = netdev_priv(netdev);
struct net_device_stats *stats = rtl8152_get_stats(netdev); int i;
netif_warn(tp, tx_err, netdev, "Tx timeout.\n"); netif_warn(tp, tx_err, netdev, "Tx timeout.\n");
usb_unlink_urb(tp->tx_urb); for (i = 0; i < RTL8152_MAX_TX; i++)
stats->tx_errors++; usb_unlink_urb(tp->tx_info[i].urb);
} }
static void rtl8152_set_rx_mode(struct net_device *netdev) static void rtl8152_set_rx_mode(struct net_device *netdev)
...@@ -923,33 +1227,44 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb, ...@@ -923,33 +1227,44 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
{ {
struct r8152 *tp = netdev_priv(netdev); struct r8152 *tp = netdev_priv(netdev);
struct net_device_stats *stats = rtl8152_get_stats(netdev); struct net_device_stats *stats = rtl8152_get_stats(netdev);
unsigned long lockflags;
struct tx_agg *agg = NULL;
struct tx_desc *tx_desc; struct tx_desc *tx_desc;
unsigned int len; unsigned int len;
u8 *tx_data;
int res; int res;
netif_stop_queue(netdev); skb_tx_timestamp(skb);
len = skb->len;
if (skb_header_cloned(skb) || skb_headroom(skb) < sizeof(*tx_desc)) {
struct sk_buff *tx_skb;
tx_skb = skb_copy_expand(skb, sizeof(*tx_desc), 0, GFP_ATOMIC); spin_lock_irqsave(&tp->tx_lock, lockflags);
dev_kfree_skb_any(skb); if (!list_empty(&tp->tx_free) && skb_queue_empty(&tp->tx_queue)) {
if (!tx_skb) { struct list_head *cursor;
stats->tx_dropped++;
netif_wake_queue(netdev); cursor = tp->tx_free.next;
return NETDEV_TX_OK; list_del_init(cursor);
} agg = list_entry(cursor, struct tx_agg, list);
skb = tx_skb;
} }
tx_desc = (struct tx_desc *)skb_push(skb, sizeof(*tx_desc)); spin_unlock_irqrestore(&tp->tx_lock, lockflags);
memset(tx_desc, 0, sizeof(*tx_desc));
tx_desc->opts1 = cpu_to_le32((len & TX_LEN_MASK) | TX_FS | TX_LS); if (!agg) {
tp->tx_skb = skb; skb_queue_tail(&tp->tx_queue, skb);
skb_tx_timestamp(skb); return NETDEV_TX_OK;
usb_fill_bulk_urb(tp->tx_urb, tp->udev, usb_sndbulkpipe(tp->udev, 2), }
skb->data, skb->len,
(usb_complete_t)write_bulk_callback, tp); tx_desc = (struct tx_desc *)agg->head;
res = usb_submit_urb(tp->tx_urb, GFP_ATOMIC); tx_data = agg->head + sizeof(*tx_desc);
agg->skb_num = agg->skb_len = 0;
len = skb->len;
tx_desc->opts1 = cpu_to_le32((skb->len & TX_LEN_MASK) | TX_FS | TX_LS);
memcpy(tx_data, skb->data, len);
dev_kfree_skb_any(skb);
agg->skb_num++;
agg->skb_len += len;
usb_fill_bulk_urb(agg->urb, tp->udev, usb_sndbulkpipe(tp->udev, 2),
agg->head, len + sizeof(*tx_desc),
(usb_complete_t)write_bulk_callback, agg);
res = usb_submit_urb(agg->urb, GFP_ATOMIC);
if (res) { if (res) {
/* Can we get/handle EPIPE here? */ /* Can we get/handle EPIPE here? */
if (res == -ENODEV) { if (res == -ENODEV) {
...@@ -957,12 +1272,11 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb, ...@@ -957,12 +1272,11 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
} else { } else {
netif_warn(tp, tx_err, netdev, netif_warn(tp, tx_err, netdev,
"failed tx_urb %d\n", res); "failed tx_urb %d\n", res);
stats->tx_errors++; stats->tx_dropped++;
netif_start_queue(netdev); spin_lock_irqsave(&tp->tx_lock, lockflags);
list_add_tail(&agg->list, &tp->tx_free);
spin_unlock_irqrestore(&tp->tx_lock, lockflags);
} }
} else {
stats->tx_packets++;
stats->tx_bytes += skb->len;
} }
return NETDEV_TX_OK; return NETDEV_TX_OK;
...@@ -999,17 +1313,18 @@ static inline u8 rtl8152_get_speed(struct r8152 *tp) ...@@ -999,17 +1313,18 @@ static inline u8 rtl8152_get_speed(struct r8152 *tp)
static int rtl8152_enable(struct r8152 *tp) static int rtl8152_enable(struct r8152 *tp)
{ {
u32 ocp_data; u32 ocp_data;
int i, ret;
u8 speed; u8 speed;
speed = rtl8152_get_speed(tp); speed = rtl8152_get_speed(tp);
if (speed & _100bps) { if (speed & _10bps) {
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR); ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR);
ocp_data &= ~EEEP_CR_EEEP_TX; ocp_data |= EEEP_CR_EEEP_TX;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data); ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data);
} else { } else {
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR); ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR);
ocp_data |= EEEP_CR_EEEP_TX; ocp_data &= ~EEEP_CR_EEEP_TX;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data); ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data);
} }
...@@ -1023,23 +1338,34 @@ static int rtl8152_enable(struct r8152 *tp) ...@@ -1023,23 +1338,34 @@ static int rtl8152_enable(struct r8152 *tp)
ocp_data &= ~RXDY_GATED_EN; ocp_data &= ~RXDY_GATED_EN;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data); ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
usb_fill_bulk_urb(tp->rx_urb, tp->udev, usb_rcvbulkpipe(tp->udev, 1), INIT_LIST_HEAD(&tp->rx_done);
tp->rx_skb->data, RTL8152_RMS + sizeof(struct rx_desc), ret = 0;
(usb_complete_t)read_bulk_callback, tp); for (i = 0; i < RTL8152_MAX_RX; i++) {
INIT_LIST_HEAD(&tp->rx_info[i].list);
ret |= r8152_submit_rx(tp, &tp->rx_info[i], GFP_KERNEL);
}
return usb_submit_urb(tp->rx_urb, GFP_KERNEL); return ret;
} }
static void rtl8152_disable(struct r8152 *tp) static void rtl8152_disable(struct r8152 *tp)
{ {
u32 ocp_data; struct net_device_stats *stats = rtl8152_get_stats(tp->netdev);
int i; struct sk_buff *skb;
u32 ocp_data;
int i;
ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
ocp_data &= ~RCR_ACPT_ALL; ocp_data &= ~RCR_ACPT_ALL;
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
usb_kill_urb(tp->tx_urb); while ((skb = skb_dequeue(&tp->tx_queue))) {
dev_kfree_skb(skb);
stats->tx_dropped++;
}
for (i = 0; i < RTL8152_MAX_TX; i++)
usb_kill_urb(tp->tx_info[i].urb);
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1); ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
ocp_data |= RXDY_GATED_EN; ocp_data |= RXDY_GATED_EN;
...@@ -1058,7 +1384,8 @@ static void rtl8152_disable(struct r8152 *tp) ...@@ -1058,7 +1384,8 @@ static void rtl8152_disable(struct r8152 *tp)
mdelay(1); mdelay(1);
} }
usb_kill_urb(tp->rx_urb); for (i = 0; i < RTL8152_MAX_RX; i++)
usb_kill_urb(tp->rx_info[i].urb);
rtl8152_nic_reset(tp); rtl8152_nic_reset(tp);
} }
...@@ -1303,7 +1630,9 @@ static void set_carrier(struct r8152 *tp) ...@@ -1303,7 +1630,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);
rtl8152_disable(tp); rtl8152_disable(tp);
tasklet_enable(&tp->tl);
} }
} }
tp->speed = speed; tp->speed = speed;
...@@ -1369,7 +1698,9 @@ static int rtl8152_close(struct net_device *netdev) ...@@ -1369,7 +1698,9 @@ static int rtl8152_close(struct net_device *netdev)
clear_bit(WORK_ENABLE, &tp->flags); clear_bit(WORK_ENABLE, &tp->flags);
cancel_delayed_work_sync(&tp->schedule); cancel_delayed_work_sync(&tp->schedule);
netif_stop_queue(netdev); netif_stop_queue(netdev);
tasklet_disable(&tp->tl);
rtl8152_disable(tp); rtl8152_disable(tp);
tasklet_enable(&tp->tl);
return res; return res;
} }
...@@ -1429,8 +1760,8 @@ static void r8152b_hw_phy_cfg(struct r8152 *tp) ...@@ -1429,8 +1760,8 @@ static void r8152b_hw_phy_cfg(struct r8152 *tp)
static void r8152b_init(struct r8152 *tp) static void r8152b_init(struct r8152 *tp)
{ {
u32 ocp_data; u32 ocp_data;
int i; int i;
rtl_clear_bp(tp); rtl_clear_bp(tp);
...@@ -1475,9 +1806,9 @@ static void r8152b_init(struct r8152 *tp) ...@@ -1475,9 +1806,9 @@ static void r8152b_init(struct r8152 *tp)
break; break;
} }
/* disable rx aggregation */ /* enable rx aggregation */
ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
ocp_data |= RX_AGG_DISABLE; ocp_data &= ~RX_AGG_DISABLE;
ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
} }
...@@ -1490,6 +1821,7 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) ...@@ -1490,6 +1821,7 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
if (netif_running(tp->netdev)) { if (netif_running(tp->netdev)) {
clear_bit(WORK_ENABLE, &tp->flags); clear_bit(WORK_ENABLE, &tp->flags);
cancel_delayed_work_sync(&tp->schedule); cancel_delayed_work_sync(&tp->schedule);
tasklet_disable(&tp->tl);
} }
rtl8152_down(tp); rtl8152_down(tp);
...@@ -1508,6 +1840,7 @@ static int rtl8152_resume(struct usb_interface *intf) ...@@ -1508,6 +1840,7 @@ static int rtl8152_resume(struct usb_interface *intf)
set_bit(WORK_ENABLE, &tp->flags); set_bit(WORK_ENABLE, &tp->flags);
set_bit(RTL8152_SET_RX_MODE, &tp->flags); set_bit(RTL8152_SET_RX_MODE, &tp->flags);
schedule_delayed_work(&tp->schedule, 0); schedule_delayed_work(&tp->schedule, 0);
tasklet_enable(&tp->tl);
} }
return 0; return 0;
...@@ -1619,6 +1952,7 @@ static int rtl8152_probe(struct usb_interface *intf, ...@@ -1619,6 +1952,7 @@ static int rtl8152_probe(struct usb_interface *intf,
struct usb_device *udev = interface_to_usbdev(intf); struct usb_device *udev = interface_to_usbdev(intf);
struct r8152 *tp; struct r8152 *tp;
struct net_device *netdev; struct net_device *netdev;
int ret;
if (udev->actconfig->desc.bConfigurationValue != 1) { if (udev->actconfig->desc.bConfigurationValue != 1) {
usb_driver_set_configuration(udev, 1); usb_driver_set_configuration(udev, 1);
...@@ -1631,10 +1965,12 @@ static int rtl8152_probe(struct usb_interface *intf, ...@@ -1631,10 +1965,12 @@ static int rtl8152_probe(struct usb_interface *intf,
return -ENOMEM; return -ENOMEM;
} }
SET_NETDEV_DEV(netdev, &intf->dev);
tp = netdev_priv(netdev); tp = netdev_priv(netdev);
memset(tp, 0, sizeof(*tp));
tp->msg_enable = 0x7FFF; tp->msg_enable = 0x7FFF;
tasklet_init(&tp->tl, rx_fixup, (unsigned long)tp); tasklet_init(&tp->tl, bottom_half, (unsigned long)tp);
INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t); INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t);
tp->udev = udev; tp->udev = udev;
...@@ -1657,37 +1993,27 @@ static int rtl8152_probe(struct usb_interface *intf, ...@@ -1657,37 +1993,27 @@ static int rtl8152_probe(struct usb_interface *intf,
r8152b_init(tp); r8152b_init(tp);
set_ethernet_addr(tp); set_ethernet_addr(tp);
if (!alloc_all_urbs(tp)) { ret = alloc_all_mem(tp);
netif_err(tp, probe, netdev, "out of memory"); if (ret)
goto out; goto out;
}
tp->rx_skb = netdev_alloc_skb(netdev,
RTL8152_RMS + sizeof(struct rx_desc));
if (!tp->rx_skb)
goto out1;
usb_set_intfdata(intf, tp); usb_set_intfdata(intf, tp);
SET_NETDEV_DEV(netdev, &intf->dev);
ret = register_netdev(netdev);
if (register_netdev(netdev) != 0) { if (ret != 0) {
netif_err(tp, probe, netdev, "couldn't register the device"); netif_err(tp, probe, netdev, "couldn't register the device");
goto out2; goto out1;
} }
netif_info(tp, probe, netdev, "%s", DRIVER_VERSION); netif_info(tp, probe, netdev, "%s", DRIVER_VERSION);
return 0; return 0;
out2:
usb_set_intfdata(intf, NULL);
dev_kfree_skb(tp->rx_skb);
out1: out1:
free_all_urbs(tp); usb_set_intfdata(intf, NULL);
out: out:
free_netdev(netdev); free_netdev(netdev);
return -EIO; return ret;
} }
static void rtl8152_unload(struct r8152 *tp) static void rtl8152_unload(struct r8152 *tp)
...@@ -1715,9 +2041,7 @@ static void rtl8152_disconnect(struct usb_interface *intf) ...@@ -1715,9 +2041,7 @@ static void rtl8152_disconnect(struct usb_interface *intf)
tasklet_kill(&tp->tl); tasklet_kill(&tp->tl);
unregister_netdev(tp->netdev); unregister_netdev(tp->netdev);
rtl8152_unload(tp); rtl8152_unload(tp);
free_all_urbs(tp); free_all_mem(tp);
if (tp->rx_skb)
dev_kfree_skb(tp->rx_skb);
free_netdev(tp->netdev); free_netdev(tp->netdev);
} }
} }
...@@ -1732,11 +2056,12 @@ MODULE_DEVICE_TABLE(usb, rtl8152_table); ...@@ -1732,11 +2056,12 @@ MODULE_DEVICE_TABLE(usb, rtl8152_table);
static struct usb_driver rtl8152_driver = { static struct usb_driver rtl8152_driver = {
.name = MODULENAME, .name = MODULENAME,
.id_table = rtl8152_table,
.probe = rtl8152_probe, .probe = rtl8152_probe,
.disconnect = rtl8152_disconnect, .disconnect = rtl8152_disconnect,
.id_table = rtl8152_table,
.suspend = rtl8152_suspend, .suspend = rtl8152_suspend,
.resume = rtl8152_resume .resume = rtl8152_resume,
.reset_resume = rtl8152_resume,
}; };
module_usb_driver(rtl8152_driver); module_usb_driver(rtl8152_driver);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册