aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/usb/smsc95xx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/usb/smsc95xx.c')
-rw-r--r--drivers/net/usb/smsc95xx.c110
1 files changed, 70 insertions, 40 deletions
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 51e2f5d7d14e..5574abe29c73 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,16 @@
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)
46#define FLOW_CTRL_TX (1) 47#define SMSC95XX_TX_OVERHEAD_CSUM (12)
47#define FLOW_CTRL_RX (2)
48 48
49struct smsc95xx_priv { 49struct smsc95xx_priv {
50 u32 mac_cr; 50 u32 mac_cr;
51 spinlock_t mac_cr_lock; 51 spinlock_t mac_cr_lock;
52 bool use_tx_csum;
52 bool use_rx_csum; 53 bool use_rx_csum;
53}; 54};
54 55
@@ -310,9 +311,10 @@ static void smsc95xx_async_cmd_callback(struct urb *urb, struct pt_regs *regs)
310{ 311{
311 struct usb_context *usb_context = urb->context; 312 struct usb_context *usb_context = urb->context;
312 struct usbnet *dev = usb_context->dev; 313 struct usbnet *dev = usb_context->dev;
314 int status = urb->status;
313 315
314 if (urb->status < 0) 316 if (status < 0)
315 devwarn(dev, "async callback failed with %d", urb->status); 317 devwarn(dev, "async callback failed with %d", status);
316 318
317 complete(&usb_context->notify); 319 complete(&usb_context->notify);
318 320
@@ -434,28 +436,6 @@ static void smsc95xx_set_multicast(struct net_device *netdev)
434 smsc95xx_write_reg_async(dev, MAC_CR, &pdata->mac_cr); 436 smsc95xx_write_reg_async(dev, MAC_CR, &pdata->mac_cr);
435} 437}
436 438
437static u8 smsc95xx_resolve_flowctrl_fulldplx(u16 lcladv, u16 rmtadv)
438{
439 u8 cap = 0;
440
441 if (lcladv & ADVERTISE_PAUSE_CAP) {
442 if (lcladv & ADVERTISE_PAUSE_ASYM) {
443 if (rmtadv & LPA_PAUSE_CAP)
444 cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
445 else if (rmtadv & LPA_PAUSE_ASYM)
446 cap = FLOW_CTRL_RX;
447 } else {
448 if (rmtadv & LPA_PAUSE_CAP)
449 cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
450 }
451 } else if (lcladv & ADVERTISE_PAUSE_ASYM) {
452 if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM))
453 cap = FLOW_CTRL_TX;
454 }
455
456 return cap;
457}
458
459static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex, 439static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex,
460 u16 lcladv, u16 rmtadv) 440 u16 lcladv, u16 rmtadv)
461{ 441{
@@ -468,7 +448,7 @@ static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex,
468 } 448 }
469 449
470 if (duplex == DUPLEX_FULL) { 450 if (duplex == DUPLEX_FULL) {
471 u8 cap = smsc95xx_resolve_flowctrl_fulldplx(lcladv, rmtadv); 451 u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
472 452
473 if (cap & FLOW_CTRL_RX) 453 if (cap & FLOW_CTRL_RX)
474 flow = 0xFFFF0002; 454 flow = 0xFFFF0002;
@@ -556,9 +536,10 @@ static void smsc95xx_status(struct usbnet *dev, struct urb *urb)
556 devwarn(dev, "unexpected interrupt, intdata=0x%08X", intdata); 536 devwarn(dev, "unexpected interrupt, intdata=0x%08X", intdata);
557} 537}
558 538
559/* Enable or disable Rx checksum offload engine */ 539/* Enable or disable Tx & Rx checksum offload engines */
560static int smsc95xx_set_rx_csum(struct usbnet *dev, bool enable) 540static int smsc95xx_set_csums(struct usbnet *dev)
561{ 541{
542 struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
562 u32 read_buf; 543 u32 read_buf;
563 int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf); 544 int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf);
564 if (ret < 0) { 545 if (ret < 0) {
@@ -566,7 +547,12 @@ static int smsc95xx_set_rx_csum(struct usbnet *dev, bool enable)
566 return ret; 547 return ret;
567 } 548 }
568 549
569 if (enable) 550 if (pdata->use_tx_csum)
551 read_buf |= Tx_COE_EN_;
552 else
553 read_buf &= ~Tx_COE_EN_;
554
555 if (pdata->use_rx_csum)
570 read_buf |= Rx_COE_EN_; 556 read_buf |= Rx_COE_EN_;
571 else 557 else
572 read_buf &= ~Rx_COE_EN_; 558 read_buf &= ~Rx_COE_EN_;
@@ -626,7 +612,26 @@ static int smsc95xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val)
626 612
627 pdata->use_rx_csum = !!val; 613 pdata->use_rx_csum = !!val;
628 614
629 return smsc95xx_set_rx_csum(dev, pdata->use_rx_csum); 615 return smsc95xx_set_csums(dev);
616}
617
618static u32 smsc95xx_ethtool_get_tx_csum(struct net_device *netdev)
619{
620 struct usbnet *dev = netdev_priv(netdev);
621 struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
622
623 return pdata->use_tx_csum;
624}
625
626static int smsc95xx_ethtool_set_tx_csum(struct net_device *netdev, u32 val)
627{
628 struct usbnet *dev = netdev_priv(netdev);
629 struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
630
631 pdata->use_tx_csum = !!val;
632
633 ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum);
634 return smsc95xx_set_csums(dev);
630} 635}
631 636
632static struct ethtool_ops smsc95xx_ethtool_ops = { 637static struct ethtool_ops smsc95xx_ethtool_ops = {
@@ -640,6 +645,8 @@ static struct ethtool_ops smsc95xx_ethtool_ops = {
640 .get_eeprom_len = smsc95xx_ethtool_get_eeprom_len, 645 .get_eeprom_len = smsc95xx_ethtool_get_eeprom_len,
641 .get_eeprom = smsc95xx_ethtool_get_eeprom, 646 .get_eeprom = smsc95xx_ethtool_get_eeprom,
642 .set_eeprom = smsc95xx_ethtool_set_eeprom, 647 .set_eeprom = smsc95xx_ethtool_set_eeprom,
648 .get_tx_csum = smsc95xx_ethtool_get_tx_csum,
649 .set_tx_csum = smsc95xx_ethtool_set_tx_csum,
643 .get_rx_csum = smsc95xx_ethtool_get_rx_csum, 650 .get_rx_csum = smsc95xx_ethtool_get_rx_csum,
644 .set_rx_csum = smsc95xx_ethtool_set_rx_csum, 651 .set_rx_csum = smsc95xx_ethtool_set_rx_csum,
645}; 652};
@@ -757,9 +764,9 @@ static int smsc95xx_phy_initialize(struct usbnet *dev)
757static int smsc95xx_reset(struct usbnet *dev) 764static int smsc95xx_reset(struct usbnet *dev)
758{ 765{
759 struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); 766 struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
767 struct net_device *netdev = dev->net;
760 u32 read_buf, write_buf, burst_cap; 768 u32 read_buf, write_buf, burst_cap;
761 int ret = 0, timeout; 769 int ret = 0, timeout;
762 DECLARE_MAC_BUF(mac);
763 770
764 if (netif_msg_ifup(dev)) 771 if (netif_msg_ifup(dev))
765 devdbg(dev, "entering smsc95xx_reset"); 772 devdbg(dev, "entering smsc95xx_reset");
@@ -818,8 +825,7 @@ static int smsc95xx_reset(struct usbnet *dev)
818 return ret; 825 return ret;
819 826
820 if (netif_msg_ifup(dev)) 827 if (netif_msg_ifup(dev))
821 devdbg(dev, "MAC Address: %s", 828 devdbg(dev, "MAC Address: %pM", dev->net->dev_addr);
822 print_mac(mac, dev->net->dev_addr));
823 829
824 ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); 830 ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
825 if (ret < 0) { 831 if (ret < 0) {
@@ -970,10 +976,11 @@ static int smsc95xx_reset(struct usbnet *dev)
970 return ret; 976 return ret;
971 } 977 }
972 978
973 /* Enable or disable Rx checksum offload engine */ 979 /* Enable or disable checksum offload engines */
974 ret = smsc95xx_set_rx_csum(dev, pdata->use_rx_csum); 980 ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum);
981 ret = smsc95xx_set_csums(dev);
975 if (ret < 0) { 982 if (ret < 0) {
976 devwarn(dev, "Failed to set Rx csum offload: %d", ret); 983 devwarn(dev, "Failed to set csum offload: %d", ret);
977 return ret; 984 return ret;
978 } 985 }
979 986
@@ -1029,6 +1036,7 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
1029 1036
1030 spin_lock_init(&pdata->mac_cr_lock); 1037 spin_lock_init(&pdata->mac_cr_lock);
1031 1038
1039 pdata->use_tx_csum = DEFAULT_TX_CSUM_ENABLE;
1032 pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE; 1040 pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE;
1033 1041
1034 /* Init all registers */ 1042 /* Init all registers */
@@ -1148,22 +1156,44 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
1148 return 1; 1156 return 1;
1149} 1157}
1150 1158
1159static u32 smsc95xx_calc_csum_preamble(struct sk_buff *skb)
1160{
1161 int len = skb->data - skb->head;
1162 u16 high_16 = (u16)(skb->csum_offset + skb->csum_start - len);
1163 u16 low_16 = (u16)(skb->csum_start - len);
1164 return (high_16 << 16) | low_16;
1165}
1166
1151static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, 1167static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev,
1152 struct sk_buff *skb, gfp_t flags) 1168 struct sk_buff *skb, gfp_t flags)
1153{ 1169{
1170 struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
1171 bool csum = pdata->use_tx_csum && (skb->ip_summed == CHECKSUM_PARTIAL);
1172 int overhead = csum ? SMSC95XX_TX_OVERHEAD_CSUM : SMSC95XX_TX_OVERHEAD;
1154 u32 tx_cmd_a, tx_cmd_b; 1173 u32 tx_cmd_a, tx_cmd_b;
1155 1174
1156 if (skb_headroom(skb) < SMSC95XX_TX_OVERHEAD) { 1175 /* We do not advertise SG, so skbs should be already linearized */
1176 BUG_ON(skb_shinfo(skb)->nr_frags);
1177
1178 if (skb_headroom(skb) < overhead) {
1157 struct sk_buff *skb2 = skb_copy_expand(skb, 1179 struct sk_buff *skb2 = skb_copy_expand(skb,
1158 SMSC95XX_TX_OVERHEAD, 0, flags); 1180 overhead, 0, flags);
1159 dev_kfree_skb_any(skb); 1181 dev_kfree_skb_any(skb);
1160 skb = skb2; 1182 skb = skb2;
1161 if (!skb) 1183 if (!skb)
1162 return NULL; 1184 return NULL;
1163 } 1185 }
1164 1186
1187 if (csum) {
1188 u32 csum_preamble = smsc95xx_calc_csum_preamble(skb);
1189 skb_push(skb, 4);
1190 memcpy(skb->data, &csum_preamble, 4);
1191 }
1192
1165 skb_push(skb, 4); 1193 skb_push(skb, 4);
1166 tx_cmd_b = (u32)(skb->len - 4); 1194 tx_cmd_b = (u32)(skb->len - 4);
1195 if (csum)
1196 tx_cmd_b |= TX_CMD_B_CSUM_ENABLE;
1167 cpu_to_le32s(&tx_cmd_b); 1197 cpu_to_le32s(&tx_cmd_b);
1168 memcpy(skb->data, &tx_cmd_b, 4); 1198 memcpy(skb->data, &tx_cmd_b, 4);
1169 1199