aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/usb')
-rw-r--r--drivers/net/usb/smsc95xx.c75
1 files changed, 65 insertions, 10 deletions
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index e0d349f74642..4638a7bb471e 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -31,7 +31,7 @@
31#include "smsc95xx.h" 31#include "smsc95xx.h"
32 32
33#define SMSC_CHIPNAME "smsc95xx" 33#define SMSC_CHIPNAME "smsc95xx"
34#define SMSC_DRIVER_VERSION "1.0.3" 34#define SMSC_DRIVER_VERSION "1.0.4"
35#define HS_USB_PKT_SIZE (512) 35#define HS_USB_PKT_SIZE (512)
36#define FS_USB_PKT_SIZE (64) 36#define FS_USB_PKT_SIZE (64)
37#define DEFAULT_HS_BURST_CAP_SIZE (16 * 1024 + 5 * HS_USB_PKT_SIZE) 37#define DEFAULT_HS_BURST_CAP_SIZE (16 * 1024 + 5 * HS_USB_PKT_SIZE)
@@ -40,15 +40,18 @@
40#define MAX_SINGLE_PACKET_SIZE (2048) 40#define MAX_SINGLE_PACKET_SIZE (2048)
41#define LAN95XX_EEPROM_MAGIC (0x9500) 41#define LAN95XX_EEPROM_MAGIC (0x9500)
42#define EEPROM_MAC_OFFSET (0x01) 42#define EEPROM_MAC_OFFSET (0x01)
43#define DEFAULT_TX_CSUM_ENABLE (true)
43#define DEFAULT_RX_CSUM_ENABLE (true) 44#define DEFAULT_RX_CSUM_ENABLE (true)
44#define SMSC95XX_INTERNAL_PHY_ID (1) 45#define SMSC95XX_INTERNAL_PHY_ID (1)
45#define SMSC95XX_TX_OVERHEAD (8) 46#define SMSC95XX_TX_OVERHEAD (8)
47#define SMSC95XX_TX_OVERHEAD_CSUM (12)
46#define FLOW_CTRL_TX (1) 48#define FLOW_CTRL_TX (1)
47#define FLOW_CTRL_RX (2) 49#define FLOW_CTRL_RX (2)
48 50
49struct smsc95xx_priv { 51struct smsc95xx_priv {
50 u32 mac_cr; 52 u32 mac_cr;
51 spinlock_t mac_cr_lock; 53 spinlock_t mac_cr_lock;
54 bool use_tx_csum;
52 bool use_rx_csum; 55 bool use_rx_csum;
53}; 56};
54 57
@@ -556,9 +559,10 @@ static void smsc95xx_status(struct usbnet *dev, struct urb *urb)
556 devwarn(dev, "unexpected interrupt, intdata=0x%08X", intdata); 559 devwarn(dev, "unexpected interrupt, intdata=0x%08X", intdata);
557} 560}
558 561
559/* Enable or disable Rx checksum offload engine */ 562/* Enable or disable Tx & Rx checksum offload engines */
560static int smsc95xx_set_rx_csum(struct usbnet *dev, bool enable) 563static int smsc95xx_set_csums(struct usbnet *dev)
561{ 564{
565 struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
562 u32 read_buf; 566 u32 read_buf;
563 int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf); 567 int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf);
564 if (ret < 0) { 568 if (ret < 0) {
@@ -566,7 +570,12 @@ static int smsc95xx_set_rx_csum(struct usbnet *dev, bool enable)
566 return ret; 570 return ret;
567 } 571 }
568 572
569 if (enable) 573 if (pdata->use_tx_csum)
574 read_buf |= Tx_COE_EN_;
575 else
576 read_buf &= ~Tx_COE_EN_;
577
578 if (pdata->use_rx_csum)
570 read_buf |= Rx_COE_EN_; 579 read_buf |= Rx_COE_EN_;
571 else 580 else
572 read_buf &= ~Rx_COE_EN_; 581 read_buf &= ~Rx_COE_EN_;
@@ -626,7 +635,26 @@ static int smsc95xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val)
626 635
627 pdata->use_rx_csum = !!val; 636 pdata->use_rx_csum = !!val;
628 637
629 return smsc95xx_set_rx_csum(dev, pdata->use_rx_csum); 638 return smsc95xx_set_csums(dev);
639}
640
641static u32 smsc95xx_ethtool_get_tx_csum(struct net_device *netdev)
642{
643 struct usbnet *dev = netdev_priv(netdev);
644 struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
645
646 return pdata->use_tx_csum;
647}
648
649static int smsc95xx_ethtool_set_tx_csum(struct net_device *netdev, u32 val)
650{
651 struct usbnet *dev = netdev_priv(netdev);
652 struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
653
654 pdata->use_tx_csum = !!val;
655
656 ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum);
657 return smsc95xx_set_csums(dev);
630} 658}
631 659
632static struct ethtool_ops smsc95xx_ethtool_ops = { 660static struct ethtool_ops smsc95xx_ethtool_ops = {
@@ -640,6 +668,8 @@ static struct ethtool_ops smsc95xx_ethtool_ops = {
640 .get_eeprom_len = smsc95xx_ethtool_get_eeprom_len, 668 .get_eeprom_len = smsc95xx_ethtool_get_eeprom_len,
641 .get_eeprom = smsc95xx_ethtool_get_eeprom, 669 .get_eeprom = smsc95xx_ethtool_get_eeprom,
642 .set_eeprom = smsc95xx_ethtool_set_eeprom, 670 .set_eeprom = smsc95xx_ethtool_set_eeprom,
671 .get_tx_csum = smsc95xx_ethtool_get_tx_csum,
672 .set_tx_csum = smsc95xx_ethtool_set_tx_csum,
643 .get_rx_csum = smsc95xx_ethtool_get_rx_csum, 673 .get_rx_csum = smsc95xx_ethtool_get_rx_csum,
644 .set_rx_csum = smsc95xx_ethtool_set_rx_csum, 674 .set_rx_csum = smsc95xx_ethtool_set_rx_csum,
645}; 675};
@@ -757,6 +787,7 @@ static int smsc95xx_phy_initialize(struct usbnet *dev)
757static int smsc95xx_reset(struct usbnet *dev) 787static int smsc95xx_reset(struct usbnet *dev)
758{ 788{
759 struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); 789 struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
790 struct net_device *netdev = dev->net;
760 u32 read_buf, write_buf, burst_cap; 791 u32 read_buf, write_buf, burst_cap;
761 int ret = 0, timeout; 792 int ret = 0, timeout;
762 793
@@ -968,10 +999,11 @@ static int smsc95xx_reset(struct usbnet *dev)
968 return ret; 999 return ret;
969 } 1000 }
970 1001
971 /* Enable or disable Rx checksum offload engine */ 1002 /* Enable or disable checksum offload engines */
972 ret = smsc95xx_set_rx_csum(dev, pdata->use_rx_csum); 1003 ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum);
1004 ret = smsc95xx_set_csums(dev);
973 if (ret < 0) { 1005 if (ret < 0) {
974 devwarn(dev, "Failed to set Rx csum offload: %d", ret); 1006 devwarn(dev, "Failed to set csum offload: %d", ret);
975 return ret; 1007 return ret;
976 } 1008 }
977 1009
@@ -1027,6 +1059,7 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
1027 1059
1028 spin_lock_init(&pdata->mac_cr_lock); 1060 spin_lock_init(&pdata->mac_cr_lock);
1029 1061
1062 pdata->use_tx_csum = DEFAULT_TX_CSUM_ENABLE;
1030 pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE; 1063 pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE;
1031 1064
1032 /* Init all registers */ 1065 /* Init all registers */
@@ -1146,22 +1179,44 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
1146 return 1; 1179 return 1;
1147} 1180}
1148 1181
1182static u32 smsc95xx_calc_csum_preamble(struct sk_buff *skb)
1183{
1184 int len = skb->data - skb->head;
1185 u16 high_16 = (u16)(skb->csum_offset + skb->csum_start - len);
1186 u16 low_16 = (u16)(skb->csum_start - len);
1187 return (high_16 << 16) | low_16;
1188}
1189
1149static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, 1190static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev,
1150 struct sk_buff *skb, gfp_t flags) 1191 struct sk_buff *skb, gfp_t flags)
1151{ 1192{
1193 struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
1194 bool csum = pdata->use_tx_csum && (skb->ip_summed == CHECKSUM_PARTIAL);
1195 int overhead = csum ? SMSC95XX_TX_OVERHEAD_CSUM : SMSC95XX_TX_OVERHEAD;
1152 u32 tx_cmd_a, tx_cmd_b; 1196 u32 tx_cmd_a, tx_cmd_b;
1153 1197
1154 if (skb_headroom(skb) < SMSC95XX_TX_OVERHEAD) { 1198 /* We do not advertise SG, so skbs should be already linearized */
1199 BUG_ON(skb_shinfo(skb)->nr_frags);
1200
1201 if (skb_headroom(skb) < overhead) {
1155 struct sk_buff *skb2 = skb_copy_expand(skb, 1202 struct sk_buff *skb2 = skb_copy_expand(skb,
1156 SMSC95XX_TX_OVERHEAD, 0, flags); 1203 overhead, 0, flags);
1157 dev_kfree_skb_any(skb); 1204 dev_kfree_skb_any(skb);
1158 skb = skb2; 1205 skb = skb2;
1159 if (!skb) 1206 if (!skb)
1160 return NULL; 1207 return NULL;
1161 } 1208 }
1162 1209
1210 if (csum) {
1211 u32 csum_preamble = smsc95xx_calc_csum_preamble(skb);
1212 skb_push(skb, 4);
1213 memcpy(skb->data, &csum_preamble, 4);
1214 }
1215
1163 skb_push(skb, 4); 1216 skb_push(skb, 4);
1164 tx_cmd_b = (u32)(skb->len - 4); 1217 tx_cmd_b = (u32)(skb->len - 4);
1218 if (csum)
1219 tx_cmd_b |= TX_CMD_B_CSUM_ENABLE;
1165 cpu_to_le32s(&tx_cmd_b); 1220 cpu_to_le32s(&tx_cmd_b);
1166 memcpy(skb->data, &tx_cmd_b, 4); 1221 memcpy(skb->data, &tx_cmd_b, 4);
1167 1222