diff options
Diffstat (limited to 'drivers/net/usb/lan78xx.c')
-rw-r--r-- | drivers/net/usb/lan78xx.c | 44 |
1 files changed, 38 insertions, 6 deletions
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index f20890ee03f3..f64778ad9753 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c | |||
@@ -269,6 +269,7 @@ struct skb_data { /* skb->cb is one of these */ | |||
269 | struct lan78xx_net *dev; | 269 | struct lan78xx_net *dev; |
270 | enum skb_state state; | 270 | enum skb_state state; |
271 | size_t length; | 271 | size_t length; |
272 | int num_of_packet; | ||
272 | }; | 273 | }; |
273 | 274 | ||
274 | struct usb_context { | 275 | struct usb_context { |
@@ -1803,7 +1804,34 @@ static void lan78xx_remove_mdio(struct lan78xx_net *dev) | |||
1803 | 1804 | ||
1804 | static void lan78xx_link_status_change(struct net_device *net) | 1805 | static void lan78xx_link_status_change(struct net_device *net) |
1805 | { | 1806 | { |
1806 | /* nothing to do */ | 1807 | struct phy_device *phydev = net->phydev; |
1808 | int ret, temp; | ||
1809 | |||
1810 | /* At forced 100 F/H mode, chip may fail to set mode correctly | ||
1811 | * when cable is switched between long(~50+m) and short one. | ||
1812 | * As workaround, set to 10 before setting to 100 | ||
1813 | * at forced 100 F/H mode. | ||
1814 | */ | ||
1815 | if (!phydev->autoneg && (phydev->speed == 100)) { | ||
1816 | /* disable phy interrupt */ | ||
1817 | temp = phy_read(phydev, LAN88XX_INT_MASK); | ||
1818 | temp &= ~LAN88XX_INT_MASK_MDINTPIN_EN_; | ||
1819 | ret = phy_write(phydev, LAN88XX_INT_MASK, temp); | ||
1820 | |||
1821 | temp = phy_read(phydev, MII_BMCR); | ||
1822 | temp &= ~(BMCR_SPEED100 | BMCR_SPEED1000); | ||
1823 | phy_write(phydev, MII_BMCR, temp); /* set to 10 first */ | ||
1824 | temp |= BMCR_SPEED100; | ||
1825 | phy_write(phydev, MII_BMCR, temp); /* set to 100 later */ | ||
1826 | |||
1827 | /* clear pending interrupt generated while workaround */ | ||
1828 | temp = phy_read(phydev, LAN88XX_INT_STS); | ||
1829 | |||
1830 | /* enable phy interrupt back */ | ||
1831 | temp = phy_read(phydev, LAN88XX_INT_MASK); | ||
1832 | temp |= LAN88XX_INT_MASK_MDINTPIN_EN_; | ||
1833 | ret = phy_write(phydev, LAN88XX_INT_MASK, temp); | ||
1834 | } | ||
1807 | } | 1835 | } |
1808 | 1836 | ||
1809 | static int lan78xx_phy_init(struct lan78xx_net *dev) | 1837 | static int lan78xx_phy_init(struct lan78xx_net *dev) |
@@ -2464,7 +2492,7 @@ static void tx_complete(struct urb *urb) | |||
2464 | struct lan78xx_net *dev = entry->dev; | 2492 | struct lan78xx_net *dev = entry->dev; |
2465 | 2493 | ||
2466 | if (urb->status == 0) { | 2494 | if (urb->status == 0) { |
2467 | dev->net->stats.tx_packets++; | 2495 | dev->net->stats.tx_packets += entry->num_of_packet; |
2468 | dev->net->stats.tx_bytes += entry->length; | 2496 | dev->net->stats.tx_bytes += entry->length; |
2469 | } else { | 2497 | } else { |
2470 | dev->net->stats.tx_errors++; | 2498 | dev->net->stats.tx_errors++; |
@@ -2681,10 +2709,11 @@ void lan78xx_skb_return(struct lan78xx_net *dev, struct sk_buff *skb) | |||
2681 | return; | 2709 | return; |
2682 | } | 2710 | } |
2683 | 2711 | ||
2684 | skb->protocol = eth_type_trans(skb, dev->net); | ||
2685 | dev->net->stats.rx_packets++; | 2712 | dev->net->stats.rx_packets++; |
2686 | dev->net->stats.rx_bytes += skb->len; | 2713 | dev->net->stats.rx_bytes += skb->len; |
2687 | 2714 | ||
2715 | skb->protocol = eth_type_trans(skb, dev->net); | ||
2716 | |||
2688 | netif_dbg(dev, rx_status, dev->net, "< rx, len %zu, type 0x%x\n", | 2717 | netif_dbg(dev, rx_status, dev->net, "< rx, len %zu, type 0x%x\n", |
2689 | skb->len + sizeof(struct ethhdr), skb->protocol); | 2718 | skb->len + sizeof(struct ethhdr), skb->protocol); |
2690 | memset(skb->cb, 0, sizeof(struct skb_data)); | 2719 | memset(skb->cb, 0, sizeof(struct skb_data)); |
@@ -2934,13 +2963,16 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev) | |||
2934 | 2963 | ||
2935 | skb_totallen = 0; | 2964 | skb_totallen = 0; |
2936 | pkt_cnt = 0; | 2965 | pkt_cnt = 0; |
2966 | count = 0; | ||
2967 | length = 0; | ||
2937 | for (skb = tqp->next; pkt_cnt < tqp->qlen; skb = skb->next) { | 2968 | for (skb = tqp->next; pkt_cnt < tqp->qlen; skb = skb->next) { |
2938 | if (skb_is_gso(skb)) { | 2969 | if (skb_is_gso(skb)) { |
2939 | if (pkt_cnt) { | 2970 | if (pkt_cnt) { |
2940 | /* handle previous packets first */ | 2971 | /* handle previous packets first */ |
2941 | break; | 2972 | break; |
2942 | } | 2973 | } |
2943 | length = skb->len; | 2974 | count = 1; |
2975 | length = skb->len - TX_OVERHEAD; | ||
2944 | skb2 = skb_dequeue(tqp); | 2976 | skb2 = skb_dequeue(tqp); |
2945 | goto gso_skb; | 2977 | goto gso_skb; |
2946 | } | 2978 | } |
@@ -2961,14 +2993,13 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev) | |||
2961 | for (count = pos = 0; count < pkt_cnt; count++) { | 2993 | for (count = pos = 0; count < pkt_cnt; count++) { |
2962 | skb2 = skb_dequeue(tqp); | 2994 | skb2 = skb_dequeue(tqp); |
2963 | if (skb2) { | 2995 | if (skb2) { |
2996 | length += (skb2->len - TX_OVERHEAD); | ||
2964 | memcpy(skb->data + pos, skb2->data, skb2->len); | 2997 | memcpy(skb->data + pos, skb2->data, skb2->len); |
2965 | pos += roundup(skb2->len, sizeof(u32)); | 2998 | pos += roundup(skb2->len, sizeof(u32)); |
2966 | dev_kfree_skb(skb2); | 2999 | dev_kfree_skb(skb2); |
2967 | } | 3000 | } |
2968 | } | 3001 | } |
2969 | 3002 | ||
2970 | length = skb_totallen; | ||
2971 | |||
2972 | gso_skb: | 3003 | gso_skb: |
2973 | urb = usb_alloc_urb(0, GFP_ATOMIC); | 3004 | urb = usb_alloc_urb(0, GFP_ATOMIC); |
2974 | if (!urb) { | 3005 | if (!urb) { |
@@ -2980,6 +3011,7 @@ gso_skb: | |||
2980 | entry->urb = urb; | 3011 | entry->urb = urb; |
2981 | entry->dev = dev; | 3012 | entry->dev = dev; |
2982 | entry->length = length; | 3013 | entry->length = length; |
3014 | entry->num_of_packet = count; | ||
2983 | 3015 | ||
2984 | spin_lock_irqsave(&dev->txq.lock, flags); | 3016 | spin_lock_irqsave(&dev->txq.lock, flags); |
2985 | ret = usb_autopm_get_interface_async(dev->intf); | 3017 | ret = usb_autopm_get_interface_async(dev->intf); |