Skip to content

Commit f7b2927

Browse files
Steve Glendinningdavem330
Steve Glendinning
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 8761169 commit f7b2927

File tree

1 file changed

+65
-10
lines changed

1 file changed

+65
-10
lines changed

drivers/net/usb/smsc95xx.c

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
#include "smsc95xx.h"
3232

3333
#define SMSC_CHIPNAME "smsc95xx"
34-
#define SMSC_DRIVER_VERSION "1.0.3"
34+
#define SMSC_DRIVER_VERSION "1.0.4"
3535
#define HS_USB_PKT_SIZE (512)
3636
#define FS_USB_PKT_SIZE (64)
3737
#define DEFAULT_HS_BURST_CAP_SIZE (16 * 1024 + 5 * HS_USB_PKT_SIZE)
@@ -40,15 +40,18 @@
4040
#define MAX_SINGLE_PACKET_SIZE (2048)
4141
#define LAN95XX_EEPROM_MAGIC (0x9500)
4242
#define EEPROM_MAC_OFFSET (0x01)
43+
#define DEFAULT_TX_CSUM_ENABLE (true)
4344
#define DEFAULT_RX_CSUM_ENABLE (true)
4445
#define SMSC95XX_INTERNAL_PHY_ID (1)
4546
#define SMSC95XX_TX_OVERHEAD (8)
47+
#define SMSC95XX_TX_OVERHEAD_CSUM (12)
4648
#define FLOW_CTRL_TX (1)
4749
#define FLOW_CTRL_RX (2)
4850

4951
struct smsc95xx_priv {
5052
u32 mac_cr;
5153
spinlock_t mac_cr_lock;
54+
bool use_tx_csum;
5255
bool use_rx_csum;
5356
};
5457

@@ -556,17 +559,23 @@ static void smsc95xx_status(struct usbnet *dev, struct urb *urb)
556559
devwarn(dev, "unexpected interrupt, intdata=0x%08X", intdata);
557560
}
558561

559-
/* Enable or disable Rx checksum offload engine */
560-
static int smsc95xx_set_rx_csum(struct usbnet *dev, bool enable)
562+
/* Enable or disable Tx & Rx checksum offload engines */
563+
static int smsc95xx_set_csums(struct usbnet *dev)
561564
{
565+
struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
562566
u32 read_buf;
563567
int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf);
564568
if (ret < 0) {
565569
devwarn(dev, "Failed to read COE_CR: %d", ret);
566570
return ret;
567571
}
568572

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)
570579
read_buf |= Rx_COE_EN_;
571580
else
572581
read_buf &= ~Rx_COE_EN_;
@@ -626,7 +635,26 @@ static int smsc95xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val)
626635

627636
pdata->use_rx_csum = !!val;
628637

629-
return smsc95xx_set_rx_csum(dev, pdata->use_rx_csum);
638+
return smsc95xx_set_csums(dev);
639+
}
640+
641+
static 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+
649+
static 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);
630658
}
631659

632660
static struct ethtool_ops smsc95xx_ethtool_ops = {
@@ -640,6 +668,8 @@ static struct ethtool_ops smsc95xx_ethtool_ops = {
640668
.get_eeprom_len = smsc95xx_ethtool_get_eeprom_len,
641669
.get_eeprom = smsc95xx_ethtool_get_eeprom,
642670
.set_eeprom = smsc95xx_ethtool_set_eeprom,
671+
.get_tx_csum = smsc95xx_ethtool_get_tx_csum,
672+
.set_tx_csum = smsc95xx_ethtool_set_tx_csum,
643673
.get_rx_csum = smsc95xx_ethtool_get_rx_csum,
644674
.set_rx_csum = smsc95xx_ethtool_set_rx_csum,
645675
};
@@ -757,6 +787,7 @@ static int smsc95xx_phy_initialize(struct usbnet *dev)
757787
static int smsc95xx_reset(struct usbnet *dev)
758788
{
759789
struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
790+
struct net_device *netdev = dev->net;
760791
u32 read_buf, write_buf, burst_cap;
761792
int ret = 0, timeout;
762793

@@ -968,10 +999,11 @@ static int smsc95xx_reset(struct usbnet *dev)
968999
return ret;
9691000
}
9701001

971-
/* Enable or disable Rx checksum offload engine */
972-
ret = smsc95xx_set_rx_csum(dev, pdata->use_rx_csum);
1002+
/* Enable or disable checksum offload engines */
1003+
ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum);
1004+
ret = smsc95xx_set_csums(dev);
9731005
if (ret < 0) {
974-
devwarn(dev, "Failed to set Rx csum offload: %d", ret);
1006+
devwarn(dev, "Failed to set csum offload: %d", ret);
9751007
return ret;
9761008
}
9771009

@@ -1027,6 +1059,7 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
10271059

10281060
spin_lock_init(&pdata->mac_cr_lock);
10291061

1062+
pdata->use_tx_csum = DEFAULT_TX_CSUM_ENABLE;
10301063
pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE;
10311064

10321065
/* Init all registers */
@@ -1146,22 +1179,44 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
11461179
return 1;
11471180
}
11481181

1182+
static 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+
11491190
static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev,
11501191
struct sk_buff *skb, gfp_t flags)
11511192
{
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;
11521196
u32 tx_cmd_a, tx_cmd_b;
11531197

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) {
11551202
struct sk_buff *skb2 = skb_copy_expand(skb,
1156-
SMSC95XX_TX_OVERHEAD, 0, flags);
1203+
overhead, 0, flags);
11571204
dev_kfree_skb_any(skb);
11581205
skb = skb2;
11591206
if (!skb)
11601207
return NULL;
11611208
}
11621209

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+
11631216
skb_push(skb, 4);
11641217
tx_cmd_b = (u32)(skb->len - 4);
1218+
if (csum)
1219+
tx_cmd_b |= TX_CMD_B_CSUM_ENABLE;
11651220
cpu_to_le32s(&tx_cmd_b);
11661221
memcpy(skb->data, &tx_cmd_b, 4);
11671222

0 commit comments

Comments
 (0)