summaryrefslogtreecommitdiff
path: root/drivers/net/usb/r8152.c
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2014-04-07 23:49:35 (GMT)
committerScott Wood <scottwood@freescale.com>2014-04-07 23:49:35 (GMT)
commit62b8c978ee6b8d135d9e7953221de58000dba986 (patch)
tree683b04b2e627f6710c22c151b23c8cc9a165315e /drivers/net/usb/r8152.c
parent78fd82238d0e5716578c326404184a27ba67fd6e (diff)
downloadlinux-fsl-qoriq-62b8c978ee6b8d135d9e7953221de58000dba986.tar.xz
Rewind v3.13-rc3+ (78fd82238d0e5716) to v3.12
Diffstat (limited to 'drivers/net/usb/r8152.c')
-rw-r--r--drivers/net/usb/r8152.c114
1 files changed, 64 insertions, 50 deletions
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 5107372..f3fce41 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -24,7 +24,7 @@
#include <linux/ipv6.h>
/* Version Information */
-#define DRIVER_VERSION "v1.02.0 (2013/10/28)"
+#define DRIVER_VERSION "v1.01.0 (2013/08/12)"
#define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
#define DRIVER_DESC "Realtek RTL8152 Based USB 2.0 Ethernet Adapters"
#define MODULENAME "r8152"
@@ -307,22 +307,22 @@ enum rtl8152_flags {
#define MCU_TYPE_USB 0x0000
struct rx_desc {
- __le32 opts1;
+ u32 opts1;
#define RX_LEN_MASK 0x7fff
- __le32 opts2;
- __le32 opts3;
- __le32 opts4;
- __le32 opts5;
- __le32 opts6;
+ u32 opts2;
+ u32 opts3;
+ u32 opts4;
+ u32 opts5;
+ u32 opts6;
};
struct tx_desc {
- __le32 opts1;
+ u32 opts1;
#define TX_FS (1 << 31) /* First segment of a packet */
#define TX_LS (1 << 30) /* Final segment of a packet */
#define TX_LEN_MASK 0x3ffff
- __le32 opts2;
+ u32 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 */
@@ -365,7 +365,6 @@ struct r8152 {
struct mii_if_info mii;
int intr_interval;
u32 msg_enable;
- u32 tx_qlen;
u16 ocp_base;
u8 *intr_buff;
u8 version;
@@ -877,7 +876,7 @@ static void write_bulk_callback(struct urb *urb)
static void intr_callback(struct urb *urb)
{
struct r8152 *tp;
- __le16 *d;
+ __u16 *d;
int status = urb->status;
int res;
@@ -1137,14 +1136,14 @@ r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, struct sk_buff *skb)
static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
{
- int remain;
+ u32 remain;
u8 *tx_data;
tx_data = agg->head;
agg->skb_num = agg->skb_len = 0;
- remain = rx_buf_sz;
+ remain = rx_buf_sz - sizeof(struct tx_desc);
- while (remain >= ETH_ZLEN + sizeof(struct tx_desc)) {
+ while (remain >= ETH_ZLEN) {
struct tx_desc *tx_desc;
struct sk_buff *skb;
unsigned int len;
@@ -1153,14 +1152,12 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
if (!skb)
break;
- remain -= sizeof(*tx_desc);
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);
@@ -1170,18 +1167,11 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
agg->skb_len += len;
dev_kfree_skb_any(skb);
- tx_data += len;
- remain = rx_buf_sz - (int)(tx_agg_align(tx_data) - agg->head);
+ tx_data = tx_agg_align(tx_data + len);
+ remain = rx_buf_sz - sizeof(*tx_desc) -
+ (u32)((void *)tx_data - agg->head);
}
- netif_tx_lock(tp->netdev);
-
- if (netif_queue_stopped(tp->netdev) &&
- skb_queue_len(&tp->tx_queue) < tp->tx_qlen)
- netif_wake_queue(tp->netdev);
-
- netif_tx_unlock(tp->netdev);
-
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);
@@ -1198,6 +1188,7 @@ static void rx_bottom(struct r8152 *tp)
list_for_each_safe(cursor, next, &tp->rx_done) {
struct rx_desc *rx_desc;
struct rx_agg *agg;
+ unsigned pkt_len;
int len_used = 0;
struct urb *urb;
u8 *rx_data;
@@ -1213,22 +1204,17 @@ static void rx_bottom(struct r8152 *tp)
rx_desc = agg->head;
rx_data = agg->head;
- len_used += sizeof(struct rx_desc);
+ 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) {
+ while (urb->actual_length >= len_used) {
struct net_device *netdev = tp->netdev;
struct net_device_stats *stats;
- unsigned int pkt_len;
struct sk_buff *skb;
- pkt_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK;
if (pkt_len < ETH_ZLEN)
break;
- len_used += pkt_len;
- if (urb->actual_length < len_used)
- break;
-
stats = rtl8152_get_stats(netdev);
pkt_len -= 4; /* CRC */
@@ -1248,8 +1234,9 @@ static void rx_bottom(struct r8152 *tp)
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);
+ len_used += sizeof(struct rx_desc) + pkt_len;
}
submit:
@@ -1397,17 +1384,53 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
struct r8152 *tp = netdev_priv(netdev);
+ struct net_device_stats *stats = rtl8152_get_stats(netdev);
+ unsigned long flags;
+ struct tx_agg *agg = NULL;
+ struct tx_desc *tx_desc;
+ unsigned int len;
+ u8 *tx_data;
+ int res;
skb_tx_timestamp(skb);
- skb_queue_tail(&tp->tx_queue, skb);
+ /* If tx_queue is not empty, it means at least one previous packt */
+ /* is waiting for sending. Don't send current one before it. */
+ if (skb_queue_empty(&tp->tx_queue))
+ agg = r8152_get_tx_agg(tp);
- if (list_empty(&tp->tx_free) &&
- skb_queue_len(&tp->tx_queue) > tp->tx_qlen)
- netif_stop_queue(netdev);
+ if (!agg) {
+ skb_queue_tail(&tp->tx_queue, skb);
+ return NETDEV_TX_OK;
+ }
- if (!list_empty(&tp->tx_free))
- tasklet_schedule(&tp->tl);
+ tx_desc = (struct tx_desc *)agg->head;
+ tx_data = agg->head + sizeof(*tx_desc);
+ agg->skb_num = agg->skb_len = 0;
+
+ len = skb->len;
+ r8152_tx_csum(tp, tx_desc, skb);
+ 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) {
+ /* Can we get/handle EPIPE here? */
+ if (res == -ENODEV) {
+ netif_device_detach(tp->netdev);
+ } else {
+ netif_warn(tp, tx_err, netdev,
+ "failed tx_urb %d\n", res);
+ stats->tx_dropped++;
+ spin_lock_irqsave(&tp->tx_lock, flags);
+ list_add_tail(&agg->list, &tp->tx_free);
+ spin_unlock_irqrestore(&tp->tx_lock, flags);
+ }
+ }
return NETDEV_TX_OK;
}
@@ -1436,14 +1459,6 @@ static void rtl8152_nic_reset(struct r8152 *tp)
}
}
-static void set_tx_qlen(struct r8152 *tp)
-{
- struct net_device *netdev = tp->netdev;
-
- tp->tx_qlen = rx_buf_sz / (netdev->mtu + VLAN_ETH_HLEN + VLAN_HLEN +
- sizeof(struct tx_desc));
-}
-
static inline u8 rtl8152_get_speed(struct r8152 *tp)
{
return ocp_read_byte(tp, MCU_TYPE_PLA, PLA_PHYSTATUS);
@@ -1455,7 +1470,6 @@ static int rtl8152_enable(struct r8152 *tp)
int i, ret;
u8 speed;
- set_tx_qlen(tp);
speed = rtl8152_get_speed(tp);
if (speed & _10bps) {
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR);