diff options
-rw-r--r-- | drivers/net/usb/smsc95xx.c | 75 |
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 | ||
49 | struct smsc95xx_priv { | 51 | struct 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 */ |
560 | static int smsc95xx_set_rx_csum(struct usbnet *dev, bool enable) | 563 | static 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 | |||
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); | ||
630 | } | 658 | } |
631 | 659 | ||
632 | static struct ethtool_ops smsc95xx_ethtool_ops = { | 660 | static 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) | |||
757 | static int smsc95xx_reset(struct usbnet *dev) | 787 | static 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 | ||
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 | |||
1149 | static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, | 1190 | static 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 | ||