aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/usb
diff options
context:
space:
mode:
authorSteve Glendinning <steve.glendinning@smsc.com>2008-11-20 07:19:21 -0500
committerDavid S. Miller <davem@davemloft.net>2008-11-20 07:19:21 -0500
commitf7b29271c35ed38f990ca3419696ca148349c2d3 (patch)
tree8f50d875b7e101f75c98f358a9f963ef1c024242 /drivers/net/usb
parent8761169cf15fdc9336abfddbb9c8dda59d974190 (diff)
smsc95xx: add tx checksum offload support
LAN9500 supports tx checksum offload, which slightly decreases cpu utilisation. The benefit isn't very large because we still require the skb to be linearized, but it does save a few cycles. This patch adds support for it, and enables it by default. Signed-off-by: Steve Glendinning <steve.glendinning@smsc.com> Signed-off-by: David S. Miller <davem@davemloft.net>
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