diff options
Diffstat (limited to 'drivers/net/usb/smsc95xx.c')
-rw-r--r-- | drivers/net/usb/smsc95xx.c | 90 |
1 files changed, 23 insertions, 67 deletions
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 48d4efdb495..f74f3ce7152 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 { |
@@ -459,7 +457,7 @@ static int smsc95xx_link_reset(struct usbnet *dev) | |||
459 | { | 457 | { |
460 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | 458 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); |
461 | struct mii_if_info *mii = &dev->mii; | 459 | struct mii_if_info *mii = &dev->mii; |
462 | struct ethtool_cmd ecmd; | 460 | struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; |
463 | unsigned long flags; | 461 | unsigned long flags; |
464 | u16 lcladv, rmtadv; | 462 | u16 lcladv, rmtadv; |
465 | u32 intdata; | 463 | u32 intdata; |
@@ -474,8 +472,9 @@ static int smsc95xx_link_reset(struct usbnet *dev) | |||
474 | lcladv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); | 472 | lcladv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); |
475 | rmtadv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_LPA); | 473 | rmtadv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_LPA); |
476 | 474 | ||
477 | netif_dbg(dev, link, dev->net, "speed: %d duplex: %d lcladv: %04x rmtadv: %04x\n", | 475 | netif_dbg(dev, link, dev->net, |
478 | ecmd.speed, ecmd.duplex, lcladv, rmtadv); | 476 | "speed: %u duplex: %d lcladv: %04x rmtadv: %04x\n", |
477 | ethtool_cmd_speed(&ecmd), ecmd.duplex, lcladv, rmtadv); | ||
479 | 478 | ||
480 | spin_lock_irqsave(&pdata->mac_cr_lock, flags); | 479 | spin_lock_irqsave(&pdata->mac_cr_lock, flags); |
481 | if (ecmd.duplex != DUPLEX_FULL) { | 480 | if (ecmd.duplex != DUPLEX_FULL) { |
@@ -517,22 +516,24 @@ static void smsc95xx_status(struct usbnet *dev, struct urb *urb) | |||
517 | } | 516 | } |
518 | 517 | ||
519 | /* Enable or disable Tx & Rx checksum offload engines */ | 518 | /* Enable or disable Tx & Rx checksum offload engines */ |
520 | static int smsc95xx_set_csums(struct usbnet *dev) | 519 | static int smsc95xx_set_features(struct net_device *netdev, u32 features) |
521 | { | 520 | { |
522 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | 521 | struct usbnet *dev = netdev_priv(netdev); |
523 | u32 read_buf; | 522 | u32 read_buf; |
524 | int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf); | 523 | int ret; |
524 | |||
525 | ret = smsc95xx_read_reg(dev, COE_CR, &read_buf); | ||
525 | if (ret < 0) { | 526 | if (ret < 0) { |
526 | netdev_warn(dev->net, "Failed to read COE_CR: %d\n", ret); | 527 | netdev_warn(dev->net, "Failed to read COE_CR: %d\n", ret); |
527 | return ret; | 528 | return ret; |
528 | } | 529 | } |
529 | 530 | ||
530 | if (pdata->use_tx_csum) | 531 | if (features & NETIF_F_HW_CSUM) |
531 | read_buf |= Tx_COE_EN_; | 532 | read_buf |= Tx_COE_EN_; |
532 | else | 533 | else |
533 | read_buf &= ~Tx_COE_EN_; | 534 | read_buf &= ~Tx_COE_EN_; |
534 | 535 | ||
535 | if (pdata->use_rx_csum) | 536 | if (features & NETIF_F_RXCSUM) |
536 | read_buf |= Rx_COE_EN_; | 537 | read_buf |= Rx_COE_EN_; |
537 | else | 538 | else |
538 | read_buf &= ~Rx_COE_EN_; | 539 | read_buf &= ~Rx_COE_EN_; |
@@ -576,43 +577,6 @@ static int smsc95xx_ethtool_set_eeprom(struct net_device *netdev, | |||
576 | return smsc95xx_write_eeprom(dev, ee->offset, ee->len, data); | 577 | return smsc95xx_write_eeprom(dev, ee->offset, ee->len, data); |
577 | } | 578 | } |
578 | 579 | ||
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 = { | 580 | static const struct ethtool_ops smsc95xx_ethtool_ops = { |
617 | .get_link = usbnet_get_link, | 581 | .get_link = usbnet_get_link, |
618 | .nway_reset = usbnet_nway_reset, | 582 | .nway_reset = usbnet_nway_reset, |
@@ -624,10 +588,6 @@ static const struct ethtool_ops smsc95xx_ethtool_ops = { | |||
624 | .get_eeprom_len = smsc95xx_ethtool_get_eeprom_len, | 588 | .get_eeprom_len = smsc95xx_ethtool_get_eeprom_len, |
625 | .get_eeprom = smsc95xx_ethtool_get_eeprom, | 589 | .get_eeprom = smsc95xx_ethtool_get_eeprom, |
626 | .set_eeprom = smsc95xx_ethtool_set_eeprom, | 590 | .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 | }; | 591 | }; |
632 | 592 | ||
633 | static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) | 593 | static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) |
@@ -755,7 +715,6 @@ static int smsc95xx_phy_initialize(struct usbnet *dev) | |||
755 | static int smsc95xx_reset(struct usbnet *dev) | 715 | static int smsc95xx_reset(struct usbnet *dev) |
756 | { | 716 | { |
757 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | 717 | 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; | 718 | u32 read_buf, write_buf, burst_cap; |
760 | int ret = 0, timeout; | 719 | int ret = 0, timeout; |
761 | 720 | ||
@@ -975,12 +934,7 @@ static int smsc95xx_reset(struct usbnet *dev) | |||
975 | } | 934 | } |
976 | 935 | ||
977 | /* Enable or disable checksum offload engines */ | 936 | /* Enable or disable checksum offload engines */ |
978 | ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum); | 937 | 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 | 938 | ||
985 | smsc95xx_set_multicast(dev->net); | 939 | smsc95xx_set_multicast(dev->net); |
986 | 940 | ||
@@ -1019,6 +973,7 @@ static const struct net_device_ops smsc95xx_netdev_ops = { | |||
1019 | .ndo_validate_addr = eth_validate_addr, | 973 | .ndo_validate_addr = eth_validate_addr, |
1020 | .ndo_do_ioctl = smsc95xx_ioctl, | 974 | .ndo_do_ioctl = smsc95xx_ioctl, |
1021 | .ndo_set_multicast_list = smsc95xx_set_multicast, | 975 | .ndo_set_multicast_list = smsc95xx_set_multicast, |
976 | .ndo_set_features = smsc95xx_set_features, | ||
1022 | }; | 977 | }; |
1023 | 978 | ||
1024 | static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) | 979 | static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) |
@@ -1045,8 +1000,12 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) | |||
1045 | 1000 | ||
1046 | spin_lock_init(&pdata->mac_cr_lock); | 1001 | spin_lock_init(&pdata->mac_cr_lock); |
1047 | 1002 | ||
1048 | pdata->use_tx_csum = DEFAULT_TX_CSUM_ENABLE; | 1003 | if (DEFAULT_TX_CSUM_ENABLE) |
1049 | pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE; | 1004 | dev->net->features |= NETIF_F_HW_CSUM; |
1005 | if (DEFAULT_RX_CSUM_ENABLE) | ||
1006 | dev->net->features |= NETIF_F_RXCSUM; | ||
1007 | |||
1008 | dev->net->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM; | ||
1050 | 1009 | ||
1051 | smsc95xx_init_mac_address(dev); | 1010 | smsc95xx_init_mac_address(dev); |
1052 | 1011 | ||
@@ -1056,7 +1015,7 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) | |||
1056 | dev->net->netdev_ops = &smsc95xx_netdev_ops; | 1015 | dev->net->netdev_ops = &smsc95xx_netdev_ops; |
1057 | dev->net->ethtool_ops = &smsc95xx_ethtool_ops; | 1016 | dev->net->ethtool_ops = &smsc95xx_ethtool_ops; |
1058 | dev->net->flags |= IFF_MULTICAST; | 1017 | dev->net->flags |= IFF_MULTICAST; |
1059 | dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD; | 1018 | dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD_CSUM; |
1060 | return 0; | 1019 | return 0; |
1061 | } | 1020 | } |
1062 | 1021 | ||
@@ -1080,8 +1039,6 @@ static void smsc95xx_rx_csum_offload(struct sk_buff *skb) | |||
1080 | 1039 | ||
1081 | static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | 1040 | static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) |
1082 | { | 1041 | { |
1083 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | ||
1084 | |||
1085 | while (skb->len > 0) { | 1042 | while (skb->len > 0) { |
1086 | u32 header, align_count; | 1043 | u32 header, align_count; |
1087 | struct sk_buff *ax_skb; | 1044 | struct sk_buff *ax_skb; |
@@ -1123,7 +1080,7 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |||
1123 | 1080 | ||
1124 | /* last frame in this batch */ | 1081 | /* last frame in this batch */ |
1125 | if (skb->len == size) { | 1082 | if (skb->len == size) { |
1126 | if (pdata->use_rx_csum) | 1083 | if (dev->net->features & NETIF_F_RXCSUM) |
1127 | smsc95xx_rx_csum_offload(skb); | 1084 | smsc95xx_rx_csum_offload(skb); |
1128 | skb_trim(skb, skb->len - 4); /* remove fcs */ | 1085 | skb_trim(skb, skb->len - 4); /* remove fcs */ |
1129 | skb->truesize = size + sizeof(struct sk_buff); | 1086 | skb->truesize = size + sizeof(struct sk_buff); |
@@ -1141,7 +1098,7 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |||
1141 | ax_skb->data = packet; | 1098 | ax_skb->data = packet; |
1142 | skb_set_tail_pointer(ax_skb, size); | 1099 | skb_set_tail_pointer(ax_skb, size); |
1143 | 1100 | ||
1144 | if (pdata->use_rx_csum) | 1101 | if (dev->net->features & NETIF_F_RXCSUM) |
1145 | smsc95xx_rx_csum_offload(ax_skb); | 1102 | smsc95xx_rx_csum_offload(ax_skb); |
1146 | skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ | 1103 | skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ |
1147 | ax_skb->truesize = size + sizeof(struct sk_buff); | 1104 | ax_skb->truesize = size + sizeof(struct sk_buff); |
@@ -1174,8 +1131,7 @@ static u32 smsc95xx_calc_csum_preamble(struct sk_buff *skb) | |||
1174 | static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, | 1131 | static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, |
1175 | struct sk_buff *skb, gfp_t flags) | 1132 | struct sk_buff *skb, gfp_t flags) |
1176 | { | 1133 | { |
1177 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | 1134 | 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; | 1135 | int overhead = csum ? SMSC95XX_TX_OVERHEAD_CSUM : SMSC95XX_TX_OVERHEAD; |
1180 | u32 tx_cmd_a, tx_cmd_b; | 1136 | u32 tx_cmd_a, tx_cmd_b; |
1181 | 1137 | ||