diff options
author | Michał Mirosław <mirq-linux@rere.qmqm.pl> | 2011-04-01 23:56:23 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-04-01 23:56:23 -0400 |
commit | 78e47fe4194ca7fac2cc29d25f1327db86922724 (patch) | |
tree | c4901a2d82fca5c1df8ebee8f7184a90e5e59e72 /drivers | |
parent | 98e778c9aa4f4f75550fa3a31358304e4ce67b96 (diff) |
net: convert SMSC USB net drivers to hw_features
There's a race (not fixed here) in smsc75xx in setting RFE_CTL that's not
properly handled via rfe_ctl_lock. Spinlock is not a good tool here, as
this has to wait for URB completion (or maybe just submission) after issuing
register write request. Otherwise, the rfe_ctl might be changed just after
spin_unlock() and device left programmed with other value.
smsc95xx has increased hard_header_len for the case of TX checksumming.
smsc75xx is fixed to advertise IP+IPV6_CSUM instead of HW_CSUM as it does
not use csum_start/csum_offset.
Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/usb/smsc75xx.c | 124 | ||||
-rw-r--r-- | drivers/net/usb/smsc95xx.c | 83 |
2 files changed, 63 insertions, 144 deletions
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 753ee6eb7edd..860a20c938b4 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c | |||
@@ -65,7 +65,6 @@ struct smsc75xx_priv { | |||
65 | struct usbnet *dev; | 65 | struct usbnet *dev; |
66 | u32 rfe_ctl; | 66 | u32 rfe_ctl; |
67 | u32 multicast_hash_table[DP_SEL_VHF_HASH_LEN]; | 67 | u32 multicast_hash_table[DP_SEL_VHF_HASH_LEN]; |
68 | bool use_rx_csum; | ||
69 | struct mutex dataport_mutex; | 68 | struct mutex dataport_mutex; |
70 | spinlock_t rfe_ctl_lock; | 69 | spinlock_t rfe_ctl_lock; |
71 | struct work_struct set_multicast; | 70 | struct work_struct set_multicast; |
@@ -548,28 +547,6 @@ static void smsc75xx_status(struct usbnet *dev, struct urb *urb) | |||
548 | "unexpected interrupt, intdata=0x%08X", intdata); | 547 | "unexpected interrupt, intdata=0x%08X", intdata); |
549 | } | 548 | } |
550 | 549 | ||
551 | /* Enable or disable Rx checksum offload engine */ | ||
552 | static int smsc75xx_set_rx_csum_offload(struct usbnet *dev) | ||
553 | { | ||
554 | struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | ||
555 | unsigned long flags; | ||
556 | int ret; | ||
557 | |||
558 | spin_lock_irqsave(&pdata->rfe_ctl_lock, flags); | ||
559 | |||
560 | if (pdata->use_rx_csum) | ||
561 | pdata->rfe_ctl |= RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM; | ||
562 | else | ||
563 | pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM); | ||
564 | |||
565 | spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags); | ||
566 | |||
567 | ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); | ||
568 | check_warn_return(ret, "Error writing RFE_CTL"); | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | static int smsc75xx_ethtool_get_eeprom_len(struct net_device *net) | 550 | static int smsc75xx_ethtool_get_eeprom_len(struct net_device *net) |
574 | { | 551 | { |
575 | return MAX_EEPROM_SIZE; | 552 | return MAX_EEPROM_SIZE; |
@@ -599,34 +576,6 @@ static int smsc75xx_ethtool_set_eeprom(struct net_device *netdev, | |||
599 | return smsc75xx_write_eeprom(dev, ee->offset, ee->len, data); | 576 | return smsc75xx_write_eeprom(dev, ee->offset, ee->len, data); |
600 | } | 577 | } |
601 | 578 | ||
602 | static u32 smsc75xx_ethtool_get_rx_csum(struct net_device *netdev) | ||
603 | { | ||
604 | struct usbnet *dev = netdev_priv(netdev); | ||
605 | struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | ||
606 | |||
607 | return pdata->use_rx_csum; | ||
608 | } | ||
609 | |||
610 | static int smsc75xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val) | ||
611 | { | ||
612 | struct usbnet *dev = netdev_priv(netdev); | ||
613 | struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | ||
614 | |||
615 | pdata->use_rx_csum = !!val; | ||
616 | |||
617 | return smsc75xx_set_rx_csum_offload(dev); | ||
618 | } | ||
619 | |||
620 | static int smsc75xx_ethtool_set_tso(struct net_device *netdev, u32 data) | ||
621 | { | ||
622 | if (data) | ||
623 | netdev->features |= NETIF_F_TSO | NETIF_F_TSO6; | ||
624 | else | ||
625 | netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); | ||
626 | |||
627 | return 0; | ||
628 | } | ||
629 | |||
630 | static const struct ethtool_ops smsc75xx_ethtool_ops = { | 579 | static const struct ethtool_ops smsc75xx_ethtool_ops = { |
631 | .get_link = usbnet_get_link, | 580 | .get_link = usbnet_get_link, |
632 | .nway_reset = usbnet_nway_reset, | 581 | .nway_reset = usbnet_nway_reset, |
@@ -638,12 +587,6 @@ static const struct ethtool_ops smsc75xx_ethtool_ops = { | |||
638 | .get_eeprom_len = smsc75xx_ethtool_get_eeprom_len, | 587 | .get_eeprom_len = smsc75xx_ethtool_get_eeprom_len, |
639 | .get_eeprom = smsc75xx_ethtool_get_eeprom, | 588 | .get_eeprom = smsc75xx_ethtool_get_eeprom, |
640 | .set_eeprom = smsc75xx_ethtool_set_eeprom, | 589 | .set_eeprom = smsc75xx_ethtool_set_eeprom, |
641 | .get_tx_csum = ethtool_op_get_tx_csum, | ||
642 | .set_tx_csum = ethtool_op_set_tx_hw_csum, | ||
643 | .get_rx_csum = smsc75xx_ethtool_get_rx_csum, | ||
644 | .set_rx_csum = smsc75xx_ethtool_set_rx_csum, | ||
645 | .get_tso = ethtool_op_get_tso, | ||
646 | .set_tso = smsc75xx_ethtool_set_tso, | ||
647 | }; | 590 | }; |
648 | 591 | ||
649 | static int smsc75xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) | 592 | static int smsc75xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) |
@@ -782,6 +725,30 @@ static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu) | |||
782 | return usbnet_change_mtu(netdev, new_mtu); | 725 | return usbnet_change_mtu(netdev, new_mtu); |
783 | } | 726 | } |
784 | 727 | ||
728 | /* Enable or disable Rx checksum offload engine */ | ||
729 | static int smsc75xx_set_features(struct net_device *netdev, u32 features) | ||
730 | { | ||
731 | struct usbnet *dev = netdev_priv(netdev); | ||
732 | struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | ||
733 | unsigned long flags; | ||
734 | int ret; | ||
735 | |||
736 | spin_lock_irqsave(&pdata->rfe_ctl_lock, flags); | ||
737 | |||
738 | if (features & NETIF_F_RXCSUM) | ||
739 | pdata->rfe_ctl |= RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM; | ||
740 | else | ||
741 | pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM); | ||
742 | |||
743 | spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags); | ||
744 | /* it's racing here! */ | ||
745 | |||
746 | ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); | ||
747 | check_warn_return(ret, "Error writing RFE_CTL"); | ||
748 | |||
749 | return 0; | ||
750 | } | ||
751 | |||
785 | static int smsc75xx_reset(struct usbnet *dev) | 752 | static int smsc75xx_reset(struct usbnet *dev) |
786 | { | 753 | { |
787 | struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | 754 | struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); |
@@ -960,11 +927,7 @@ static int smsc75xx_reset(struct usbnet *dev) | |||
960 | netif_dbg(dev, ifup, dev->net, "RFE_CTL set to 0x%08x", pdata->rfe_ctl); | 927 | netif_dbg(dev, ifup, dev->net, "RFE_CTL set to 0x%08x", pdata->rfe_ctl); |
961 | 928 | ||
962 | /* Enable or disable checksum offload engines */ | 929 | /* Enable or disable checksum offload engines */ |
963 | ethtool_op_set_tx_hw_csum(dev->net, DEFAULT_TX_CSUM_ENABLE); | 930 | smsc75xx_set_features(dev->net, dev->net->features); |
964 | ret = smsc75xx_set_rx_csum_offload(dev); | ||
965 | check_warn_return(ret, "Failed to set rx csum offload: %d", ret); | ||
966 | |||
967 | smsc75xx_ethtool_set_tso(dev->net, DEFAULT_TSO_ENABLE); | ||
968 | 931 | ||
969 | smsc75xx_set_multicast(dev->net); | 932 | smsc75xx_set_multicast(dev->net); |
970 | 933 | ||
@@ -1037,6 +1000,7 @@ static const struct net_device_ops smsc75xx_netdev_ops = { | |||
1037 | .ndo_validate_addr = eth_validate_addr, | 1000 | .ndo_validate_addr = eth_validate_addr, |
1038 | .ndo_do_ioctl = smsc75xx_ioctl, | 1001 | .ndo_do_ioctl = smsc75xx_ioctl, |
1039 | .ndo_set_multicast_list = smsc75xx_set_multicast, | 1002 | .ndo_set_multicast_list = smsc75xx_set_multicast, |
1003 | .ndo_set_features = smsc75xx_set_features, | ||
1040 | }; | 1004 | }; |
1041 | 1005 | ||
1042 | static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf) | 1006 | static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf) |
@@ -1065,10 +1029,17 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf) | |||
1065 | 1029 | ||
1066 | INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write); | 1030 | INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write); |
1067 | 1031 | ||
1068 | pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE; | 1032 | if (DEFAULT_TX_CSUM_ENABLE) { |
1033 | dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; | ||
1034 | if (DEFAULT_TSO_ENABLE) | ||
1035 | dev->net->features |= NETIF_F_SG | | ||
1036 | NETIF_F_TSO | NETIF_F_TSO6; | ||
1037 | } | ||
1038 | if (DEFAULT_RX_CSUM_ENABLE) | ||
1039 | dev->net->features |= NETIF_F_RXCSUM; | ||
1069 | 1040 | ||
1070 | /* We have to advertise SG otherwise TSO cannot be enabled */ | 1041 | dev->net->hw_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | |
1071 | dev->net->features |= NETIF_F_SG; | 1042 | NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_RXCSUM; |
1072 | 1043 | ||
1073 | /* Init all registers */ | 1044 | /* Init all registers */ |
1074 | ret = smsc75xx_reset(dev); | 1045 | ret = smsc75xx_reset(dev); |
@@ -1091,10 +1062,11 @@ static void smsc75xx_unbind(struct usbnet *dev, struct usb_interface *intf) | |||
1091 | } | 1062 | } |
1092 | } | 1063 | } |
1093 | 1064 | ||
1094 | static void smsc75xx_rx_csum_offload(struct sk_buff *skb, u32 rx_cmd_a, | 1065 | static void smsc75xx_rx_csum_offload(struct usbnet *dev, struct sk_buff *skb, |
1095 | u32 rx_cmd_b) | 1066 | u32 rx_cmd_a, u32 rx_cmd_b) |
1096 | { | 1067 | { |
1097 | if (unlikely(rx_cmd_a & RX_CMD_A_LCSM)) { | 1068 | if (!(dev->net->features & NETIF_F_RXCSUM) || |
1069 | unlikely(rx_cmd_a & RX_CMD_A_LCSM)) { | ||
1098 | skb->ip_summed = CHECKSUM_NONE; | 1070 | skb->ip_summed = CHECKSUM_NONE; |
1099 | } else { | 1071 | } else { |
1100 | skb->csum = ntohs((u16)(rx_cmd_b >> RX_CMD_B_CSUM_SHIFT)); | 1072 | skb->csum = ntohs((u16)(rx_cmd_b >> RX_CMD_B_CSUM_SHIFT)); |
@@ -1104,8 +1076,6 @@ static void smsc75xx_rx_csum_offload(struct sk_buff *skb, u32 rx_cmd_a, | |||
1104 | 1076 | ||
1105 | static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | 1077 | static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) |
1106 | { | 1078 | { |
1107 | struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | ||
1108 | |||
1109 | while (skb->len > 0) { | 1079 | while (skb->len > 0) { |
1110 | u32 rx_cmd_a, rx_cmd_b, align_count, size; | 1080 | u32 rx_cmd_a, rx_cmd_b, align_count, size; |
1111 | struct sk_buff *ax_skb; | 1081 | struct sk_buff *ax_skb; |
@@ -1145,11 +1115,8 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |||
1145 | 1115 | ||
1146 | /* last frame in this batch */ | 1116 | /* last frame in this batch */ |
1147 | if (skb->len == size) { | 1117 | if (skb->len == size) { |
1148 | if (pdata->use_rx_csum) | 1118 | smsc75xx_rx_csum_offload(dev, skb, rx_cmd_a, |
1149 | smsc75xx_rx_csum_offload(skb, rx_cmd_a, | 1119 | rx_cmd_b); |
1150 | rx_cmd_b); | ||
1151 | else | ||
1152 | skb->ip_summed = CHECKSUM_NONE; | ||
1153 | 1120 | ||
1154 | skb_trim(skb, skb->len - 4); /* remove fcs */ | 1121 | skb_trim(skb, skb->len - 4); /* remove fcs */ |
1155 | skb->truesize = size + sizeof(struct sk_buff); | 1122 | skb->truesize = size + sizeof(struct sk_buff); |
@@ -1167,11 +1134,8 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |||
1167 | ax_skb->data = packet; | 1134 | ax_skb->data = packet; |
1168 | skb_set_tail_pointer(ax_skb, size); | 1135 | skb_set_tail_pointer(ax_skb, size); |
1169 | 1136 | ||
1170 | if (pdata->use_rx_csum) | 1137 | smsc75xx_rx_csum_offload(dev, ax_skb, rx_cmd_a, |
1171 | smsc75xx_rx_csum_offload(ax_skb, rx_cmd_a, | 1138 | rx_cmd_b); |
1172 | rx_cmd_b); | ||
1173 | else | ||
1174 | ax_skb->ip_summed = CHECKSUM_NONE; | ||
1175 | 1139 | ||
1176 | skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ | 1140 | skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ |
1177 | ax_skb->truesize = size + sizeof(struct sk_buff); | 1141 | ax_skb->truesize = size + sizeof(struct sk_buff); |
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 727874d9deb6..708f2083898b 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c | |||
@@ -52,8 +52,6 @@ struct smsc95xx_priv { | |||
52 | u32 hash_hi; | 52 | u32 hash_hi; |
53 | u32 hash_lo; | 53 | u32 hash_lo; |
54 | spinlock_t mac_cr_lock; | 54 | spinlock_t mac_cr_lock; |
55 | bool use_tx_csum; | ||
56 | bool use_rx_csum; | ||
57 | }; | 55 | }; |
58 | 56 | ||
59 | struct usb_context { | 57 | struct usb_context { |
@@ -517,22 +515,24 @@ static void smsc95xx_status(struct usbnet *dev, struct urb *urb) | |||
517 | } | 515 | } |
518 | 516 | ||
519 | /* Enable or disable Tx & Rx checksum offload engines */ | 517 | /* Enable or disable Tx & Rx checksum offload engines */ |
520 | static int smsc95xx_set_csums(struct usbnet *dev) | 518 | static int smsc95xx_set_features(struct net_device *netdev, u32 features) |
521 | { | 519 | { |
522 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | 520 | struct usbnet *dev = netdev_priv(netdev); |
523 | u32 read_buf; | 521 | u32 read_buf; |
524 | int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf); | 522 | int ret; |
523 | |||
524 | ret = smsc95xx_read_reg(dev, COE_CR, &read_buf); | ||
525 | if (ret < 0) { | 525 | if (ret < 0) { |
526 | netdev_warn(dev->net, "Failed to read COE_CR: %d\n", ret); | 526 | netdev_warn(dev->net, "Failed to read COE_CR: %d\n", ret); |
527 | return ret; | 527 | return ret; |
528 | } | 528 | } |
529 | 529 | ||
530 | if (pdata->use_tx_csum) | 530 | if (features & NETIF_F_HW_CSUM) |
531 | read_buf |= Tx_COE_EN_; | 531 | read_buf |= Tx_COE_EN_; |
532 | else | 532 | else |
533 | read_buf &= ~Tx_COE_EN_; | 533 | read_buf &= ~Tx_COE_EN_; |
534 | 534 | ||
535 | if (pdata->use_rx_csum) | 535 | if (features & NETIF_F_RXCSUM) |
536 | read_buf |= Rx_COE_EN_; | 536 | read_buf |= Rx_COE_EN_; |
537 | else | 537 | else |
538 | read_buf &= ~Rx_COE_EN_; | 538 | read_buf &= ~Rx_COE_EN_; |
@@ -576,43 +576,6 @@ static int smsc95xx_ethtool_set_eeprom(struct net_device *netdev, | |||
576 | return smsc95xx_write_eeprom(dev, ee->offset, ee->len, data); | 576 | return smsc95xx_write_eeprom(dev, ee->offset, ee->len, data); |
577 | } | 577 | } |
578 | 578 | ||
579 | static u32 smsc95xx_ethtool_get_rx_csum(struct net_device *netdev) | ||
580 | { | ||
581 | struct usbnet *dev = netdev_priv(netdev); | ||
582 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | ||
583 | |||
584 | return pdata->use_rx_csum; | ||
585 | } | ||
586 | |||
587 | static int smsc95xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val) | ||
588 | { | ||
589 | struct usbnet *dev = netdev_priv(netdev); | ||
590 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | ||
591 | |||
592 | pdata->use_rx_csum = !!val; | ||
593 | |||
594 | return smsc95xx_set_csums(dev); | ||
595 | } | ||
596 | |||
597 | static u32 smsc95xx_ethtool_get_tx_csum(struct net_device *netdev) | ||
598 | { | ||
599 | struct usbnet *dev = netdev_priv(netdev); | ||
600 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | ||
601 | |||
602 | return pdata->use_tx_csum; | ||
603 | } | ||
604 | |||
605 | static int smsc95xx_ethtool_set_tx_csum(struct net_device *netdev, u32 val) | ||
606 | { | ||
607 | struct usbnet *dev = netdev_priv(netdev); | ||
608 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | ||
609 | |||
610 | pdata->use_tx_csum = !!val; | ||
611 | |||
612 | ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum); | ||
613 | return smsc95xx_set_csums(dev); | ||
614 | } | ||
615 | |||
616 | static const struct ethtool_ops smsc95xx_ethtool_ops = { | 579 | static const struct ethtool_ops smsc95xx_ethtool_ops = { |
617 | .get_link = usbnet_get_link, | 580 | .get_link = usbnet_get_link, |
618 | .nway_reset = usbnet_nway_reset, | 581 | .nway_reset = usbnet_nway_reset, |
@@ -624,10 +587,6 @@ static const struct ethtool_ops smsc95xx_ethtool_ops = { | |||
624 | .get_eeprom_len = smsc95xx_ethtool_get_eeprom_len, | 587 | .get_eeprom_len = smsc95xx_ethtool_get_eeprom_len, |
625 | .get_eeprom = smsc95xx_ethtool_get_eeprom, | 588 | .get_eeprom = smsc95xx_ethtool_get_eeprom, |
626 | .set_eeprom = smsc95xx_ethtool_set_eeprom, | 589 | .set_eeprom = smsc95xx_ethtool_set_eeprom, |
627 | .get_tx_csum = smsc95xx_ethtool_get_tx_csum, | ||
628 | .set_tx_csum = smsc95xx_ethtool_set_tx_csum, | ||
629 | .get_rx_csum = smsc95xx_ethtool_get_rx_csum, | ||
630 | .set_rx_csum = smsc95xx_ethtool_set_rx_csum, | ||
631 | }; | 590 | }; |
632 | 591 | ||
633 | static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) | 592 | static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) |
@@ -755,7 +714,6 @@ static int smsc95xx_phy_initialize(struct usbnet *dev) | |||
755 | static int smsc95xx_reset(struct usbnet *dev) | 714 | static int smsc95xx_reset(struct usbnet *dev) |
756 | { | 715 | { |
757 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | 716 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); |
758 | struct net_device *netdev = dev->net; | ||
759 | u32 read_buf, write_buf, burst_cap; | 717 | u32 read_buf, write_buf, burst_cap; |
760 | int ret = 0, timeout; | 718 | int ret = 0, timeout; |
761 | 719 | ||
@@ -975,12 +933,7 @@ static int smsc95xx_reset(struct usbnet *dev) | |||
975 | } | 933 | } |
976 | 934 | ||
977 | /* Enable or disable checksum offload engines */ | 935 | /* Enable or disable checksum offload engines */ |
978 | ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum); | 936 | smsc95xx_set_features(dev->net, dev->net->features); |
979 | ret = smsc95xx_set_csums(dev); | ||
980 | if (ret < 0) { | ||
981 | netdev_warn(dev->net, "Failed to set csum offload: %d\n", ret); | ||
982 | return ret; | ||
983 | } | ||
984 | 937 | ||
985 | smsc95xx_set_multicast(dev->net); | 938 | smsc95xx_set_multicast(dev->net); |
986 | 939 | ||
@@ -1019,6 +972,7 @@ static const struct net_device_ops smsc95xx_netdev_ops = { | |||
1019 | .ndo_validate_addr = eth_validate_addr, | 972 | .ndo_validate_addr = eth_validate_addr, |
1020 | .ndo_do_ioctl = smsc95xx_ioctl, | 973 | .ndo_do_ioctl = smsc95xx_ioctl, |
1021 | .ndo_set_multicast_list = smsc95xx_set_multicast, | 974 | .ndo_set_multicast_list = smsc95xx_set_multicast, |
975 | .ndo_set_features = smsc95xx_set_features, | ||
1022 | }; | 976 | }; |
1023 | 977 | ||
1024 | static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) | 978 | static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) |
@@ -1045,8 +999,12 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) | |||
1045 | 999 | ||
1046 | spin_lock_init(&pdata->mac_cr_lock); | 1000 | spin_lock_init(&pdata->mac_cr_lock); |
1047 | 1001 | ||
1048 | pdata->use_tx_csum = DEFAULT_TX_CSUM_ENABLE; | 1002 | if (DEFAULT_TX_CSUM_ENABLE) |
1049 | pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE; | 1003 | dev->net->features |= NETIF_F_HW_CSUM; |
1004 | if (DEFAULT_RX_CSUM_ENABLE) | ||
1005 | dev->net->features |= NETIF_F_RXCSUM; | ||
1006 | |||
1007 | dev->net->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM; | ||
1050 | 1008 | ||
1051 | smsc95xx_init_mac_address(dev); | 1009 | smsc95xx_init_mac_address(dev); |
1052 | 1010 | ||
@@ -1056,7 +1014,7 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) | |||
1056 | dev->net->netdev_ops = &smsc95xx_netdev_ops; | 1014 | dev->net->netdev_ops = &smsc95xx_netdev_ops; |
1057 | dev->net->ethtool_ops = &smsc95xx_ethtool_ops; | 1015 | dev->net->ethtool_ops = &smsc95xx_ethtool_ops; |
1058 | dev->net->flags |= IFF_MULTICAST; | 1016 | dev->net->flags |= IFF_MULTICAST; |
1059 | dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD; | 1017 | dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD_CSUM; |
1060 | return 0; | 1018 | return 0; |
1061 | } | 1019 | } |
1062 | 1020 | ||
@@ -1080,8 +1038,6 @@ static void smsc95xx_rx_csum_offload(struct sk_buff *skb) | |||
1080 | 1038 | ||
1081 | static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | 1039 | static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) |
1082 | { | 1040 | { |
1083 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | ||
1084 | |||
1085 | while (skb->len > 0) { | 1041 | while (skb->len > 0) { |
1086 | u32 header, align_count; | 1042 | u32 header, align_count; |
1087 | struct sk_buff *ax_skb; | 1043 | struct sk_buff *ax_skb; |
@@ -1123,7 +1079,7 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |||
1123 | 1079 | ||
1124 | /* last frame in this batch */ | 1080 | /* last frame in this batch */ |
1125 | if (skb->len == size) { | 1081 | if (skb->len == size) { |
1126 | if (pdata->use_rx_csum) | 1082 | if (dev->net->features & NETIF_F_RXCSUM) |
1127 | smsc95xx_rx_csum_offload(skb); | 1083 | smsc95xx_rx_csum_offload(skb); |
1128 | skb_trim(skb, skb->len - 4); /* remove fcs */ | 1084 | skb_trim(skb, skb->len - 4); /* remove fcs */ |
1129 | skb->truesize = size + sizeof(struct sk_buff); | 1085 | skb->truesize = size + sizeof(struct sk_buff); |
@@ -1141,7 +1097,7 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |||
1141 | ax_skb->data = packet; | 1097 | ax_skb->data = packet; |
1142 | skb_set_tail_pointer(ax_skb, size); | 1098 | skb_set_tail_pointer(ax_skb, size); |
1143 | 1099 | ||
1144 | if (pdata->use_rx_csum) | 1100 | if (dev->net->features & NETIF_F_RXCSUM) |
1145 | smsc95xx_rx_csum_offload(ax_skb); | 1101 | smsc95xx_rx_csum_offload(ax_skb); |
1146 | skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ | 1102 | skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ |
1147 | ax_skb->truesize = size + sizeof(struct sk_buff); | 1103 | ax_skb->truesize = size + sizeof(struct sk_buff); |
@@ -1174,8 +1130,7 @@ static u32 smsc95xx_calc_csum_preamble(struct sk_buff *skb) | |||
1174 | static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, | 1130 | static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, |
1175 | struct sk_buff *skb, gfp_t flags) | 1131 | struct sk_buff *skb, gfp_t flags) |
1176 | { | 1132 | { |
1177 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | 1133 | bool csum = skb->ip_summed == CHECKSUM_PARTIAL; |
1178 | bool csum = pdata->use_tx_csum && (skb->ip_summed == CHECKSUM_PARTIAL); | ||
1179 | int overhead = csum ? SMSC95XX_TX_OVERHEAD_CSUM : SMSC95XX_TX_OVERHEAD; | 1134 | int overhead = csum ? SMSC95XX_TX_OVERHEAD_CSUM : SMSC95XX_TX_OVERHEAD; |
1180 | u32 tx_cmd_a, tx_cmd_b; | 1135 | u32 tx_cmd_a, tx_cmd_b; |
1181 | 1136 | ||