diff options
author | Thomas Falcon <tlfalcon@linux.vnet.ibm.com> | 2015-07-14 11:51:51 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-07-16 00:34:56 -0400 |
commit | 07e6a97da1eba064bb35cfd5c121e90865393a60 (patch) | |
tree | 1239911c74e7f15a61a64360e26e4786a72f59c9 /drivers/net/ethernet/ibm | |
parent | 2de8530ba0c71a2fba02590681af0f3a2a187a9b (diff) |
ibmveth: add support for TSO6
This patch adds support for a new method of signalling the firmware
that TSO packets are being sent. The new method removes the need to
alter the ip and tcp checksums and allows TSO6 support.
Signed-off-by: Thomas Falcon <tlfalcon@linux.vnet.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/ibm')
-rw-r--r-- | drivers/net/ethernet/ibm/ibmveth.c | 145 | ||||
-rw-r--r-- | drivers/net/ethernet/ibm/ibmveth.h | 18 |
2 files changed, 135 insertions, 28 deletions
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index 29bbb628d712..7af870a3c549 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c | |||
@@ -79,6 +79,11 @@ static unsigned int rx_flush __read_mostly = 0; | |||
79 | module_param(rx_flush, uint, 0644); | 79 | module_param(rx_flush, uint, 0644); |
80 | MODULE_PARM_DESC(rx_flush, "Flush receive buffers before use"); | 80 | MODULE_PARM_DESC(rx_flush, "Flush receive buffers before use"); |
81 | 81 | ||
82 | static bool old_large_send __read_mostly; | ||
83 | module_param(old_large_send, bool, S_IRUGO); | ||
84 | MODULE_PARM_DESC(old_large_send, | ||
85 | "Use old large send method on firmware that supports the new method"); | ||
86 | |||
82 | struct ibmveth_stat { | 87 | struct ibmveth_stat { |
83 | char name[ETH_GSTRING_LEN]; | 88 | char name[ETH_GSTRING_LEN]; |
84 | int offset; | 89 | int offset; |
@@ -101,7 +106,8 @@ struct ibmveth_stat ibmveth_stats[] = { | |||
101 | { "fw_enabled_ipv4_csum", IBMVETH_STAT_OFF(fw_ipv4_csum_support) }, | 106 | { "fw_enabled_ipv4_csum", IBMVETH_STAT_OFF(fw_ipv4_csum_support) }, |
102 | { "fw_enabled_ipv6_csum", IBMVETH_STAT_OFF(fw_ipv6_csum_support) }, | 107 | { "fw_enabled_ipv6_csum", IBMVETH_STAT_OFF(fw_ipv6_csum_support) }, |
103 | { "tx_large_packets", IBMVETH_STAT_OFF(tx_large_packets) }, | 108 | { "tx_large_packets", IBMVETH_STAT_OFF(tx_large_packets) }, |
104 | { "rx_large_packets", IBMVETH_STAT_OFF(rx_large_packets) } | 109 | { "rx_large_packets", IBMVETH_STAT_OFF(rx_large_packets) }, |
110 | { "fw_enabled_large_send", IBMVETH_STAT_OFF(fw_large_send_support) } | ||
105 | }; | 111 | }; |
106 | 112 | ||
107 | /* simple methods of getting data from the current rxq entry */ | 113 | /* simple methods of getting data from the current rxq entry */ |
@@ -848,25 +854,91 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data) | |||
848 | return rc1 ? rc1 : rc2; | 854 | return rc1 ? rc1 : rc2; |
849 | } | 855 | } |
850 | 856 | ||
857 | static int ibmveth_set_tso(struct net_device *dev, u32 data) | ||
858 | { | ||
859 | struct ibmveth_adapter *adapter = netdev_priv(dev); | ||
860 | unsigned long set_attr, clr_attr, ret_attr; | ||
861 | long ret1, ret2; | ||
862 | int rc1 = 0, rc2 = 0; | ||
863 | int restart = 0; | ||
864 | |||
865 | if (netif_running(dev)) { | ||
866 | restart = 1; | ||
867 | adapter->pool_config = 1; | ||
868 | ibmveth_close(dev); | ||
869 | adapter->pool_config = 0; | ||
870 | } | ||
871 | |||
872 | set_attr = 0; | ||
873 | clr_attr = 0; | ||
874 | |||
875 | if (data) | ||
876 | set_attr = IBMVETH_ILLAN_LRG_SR_ENABLED; | ||
877 | else | ||
878 | clr_attr = IBMVETH_ILLAN_LRG_SR_ENABLED; | ||
879 | |||
880 | ret1 = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr); | ||
881 | |||
882 | if (ret1 == H_SUCCESS && (ret_attr & IBMVETH_ILLAN_LRG_SND_SUPPORT) && | ||
883 | !old_large_send) { | ||
884 | ret2 = h_illan_attributes(adapter->vdev->unit_address, clr_attr, | ||
885 | set_attr, &ret_attr); | ||
886 | |||
887 | if (ret2 != H_SUCCESS) { | ||
888 | netdev_err(dev, "unable to change tso settings. %d rc=%ld\n", | ||
889 | data, ret2); | ||
890 | |||
891 | h_illan_attributes(adapter->vdev->unit_address, | ||
892 | set_attr, clr_attr, &ret_attr); | ||
893 | |||
894 | if (data == 1) | ||
895 | dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); | ||
896 | rc1 = -EIO; | ||
897 | |||
898 | } else { | ||
899 | adapter->fw_large_send_support = data; | ||
900 | adapter->large_send = data; | ||
901 | } | ||
902 | } else { | ||
903 | /* Older firmware version of large send offload does not | ||
904 | * support tcp6/ipv6 | ||
905 | */ | ||
906 | if (data == 1) { | ||
907 | dev->features &= ~NETIF_F_TSO6; | ||
908 | netdev_info(dev, "TSO feature requires all partitions to have updated driver"); | ||
909 | } | ||
910 | adapter->large_send = data; | ||
911 | } | ||
912 | |||
913 | if (restart) | ||
914 | rc2 = ibmveth_open(dev); | ||
915 | |||
916 | return rc1 ? rc1 : rc2; | ||
917 | } | ||
918 | |||
851 | static int ibmveth_set_features(struct net_device *dev, | 919 | static int ibmveth_set_features(struct net_device *dev, |
852 | netdev_features_t features) | 920 | netdev_features_t features) |
853 | { | 921 | { |
854 | struct ibmveth_adapter *adapter = netdev_priv(dev); | 922 | struct ibmveth_adapter *adapter = netdev_priv(dev); |
855 | int rx_csum = !!(features & NETIF_F_RXCSUM); | 923 | int rx_csum = !!(features & NETIF_F_RXCSUM); |
856 | int rc; | 924 | int large_send = !!(features & (NETIF_F_TSO | NETIF_F_TSO6)); |
857 | netdev_features_t changed = features ^ dev->features; | 925 | int rc1 = 0, rc2 = 0; |
858 | |||
859 | if (features & NETIF_F_TSO & changed) | ||
860 | netdev_info(dev, "TSO feature requires all partitions to have updated driver"); | ||
861 | 926 | ||
862 | if (rx_csum == adapter->rx_csum) | 927 | if (rx_csum != adapter->rx_csum) { |
863 | return 0; | 928 | rc1 = ibmveth_set_csum_offload(dev, rx_csum); |
929 | if (rc1 && !adapter->rx_csum) | ||
930 | dev->features = | ||
931 | features & ~(NETIF_F_ALL_CSUM | NETIF_F_RXCSUM); | ||
932 | } | ||
864 | 933 | ||
865 | rc = ibmveth_set_csum_offload(dev, rx_csum); | 934 | if (large_send != adapter->large_send) { |
866 | if (rc && !adapter->rx_csum) | 935 | rc2 = ibmveth_set_tso(dev, large_send); |
867 | dev->features = features & ~(NETIF_F_ALL_CSUM | NETIF_F_RXCSUM); | 936 | if (rc2 && !adapter->large_send) |
937 | dev->features = | ||
938 | features & ~(NETIF_F_TSO | NETIF_F_TSO6); | ||
939 | } | ||
868 | 940 | ||
869 | return rc; | 941 | return rc1 ? rc1 : rc2; |
870 | } | 942 | } |
871 | 943 | ||
872 | static void ibmveth_get_strings(struct net_device *dev, u32 stringset, u8 *data) | 944 | static void ibmveth_get_strings(struct net_device *dev, u32 stringset, u8 *data) |
@@ -917,7 +989,7 @@ static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
917 | #define page_offset(v) ((unsigned long)(v) & ((1 << 12) - 1)) | 989 | #define page_offset(v) ((unsigned long)(v) & ((1 << 12) - 1)) |
918 | 990 | ||
919 | static int ibmveth_send(struct ibmveth_adapter *adapter, | 991 | static int ibmveth_send(struct ibmveth_adapter *adapter, |
920 | union ibmveth_buf_desc *descs) | 992 | union ibmveth_buf_desc *descs, unsigned long mss) |
921 | { | 993 | { |
922 | unsigned long correlator; | 994 | unsigned long correlator; |
923 | unsigned int retry_count; | 995 | unsigned int retry_count; |
@@ -934,7 +1006,8 @@ static int ibmveth_send(struct ibmveth_adapter *adapter, | |||
934 | descs[0].desc, descs[1].desc, | 1006 | descs[0].desc, descs[1].desc, |
935 | descs[2].desc, descs[3].desc, | 1007 | descs[2].desc, descs[3].desc, |
936 | descs[4].desc, descs[5].desc, | 1008 | descs[4].desc, descs[5].desc, |
937 | correlator, &correlator); | 1009 | correlator, &correlator, mss, |
1010 | adapter->fw_large_send_support); | ||
938 | } while ((ret == H_BUSY) && (retry_count--)); | 1011 | } while ((ret == H_BUSY) && (retry_count--)); |
939 | 1012 | ||
940 | if (ret != H_SUCCESS && ret != H_DROPPED) { | 1013 | if (ret != H_SUCCESS && ret != H_DROPPED) { |
@@ -955,6 +1028,7 @@ static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb, | |||
955 | int last, i; | 1028 | int last, i; |
956 | int force_bounce = 0; | 1029 | int force_bounce = 0; |
957 | dma_addr_t dma_addr; | 1030 | dma_addr_t dma_addr; |
1031 | unsigned long mss = 0; | ||
958 | 1032 | ||
959 | /* | 1033 | /* |
960 | * veth handles a maximum of 6 segments including the header, so | 1034 | * veth handles a maximum of 6 segments including the header, so |
@@ -980,6 +1054,9 @@ static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb, | |||
980 | 1054 | ||
981 | desc_flags = IBMVETH_BUF_VALID; | 1055 | desc_flags = IBMVETH_BUF_VALID; |
982 | 1056 | ||
1057 | if (skb_is_gso(skb) && adapter->fw_large_send_support) | ||
1058 | desc_flags |= IBMVETH_BUF_LRG_SND; | ||
1059 | |||
983 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | 1060 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
984 | unsigned char *buf = skb_transport_header(skb) + | 1061 | unsigned char *buf = skb_transport_header(skb) + |
985 | skb->csum_offset; | 1062 | skb->csum_offset; |
@@ -1007,7 +1084,7 @@ retry_bounce: | |||
1007 | descs[0].fields.flags_len = desc_flags | skb->len; | 1084 | descs[0].fields.flags_len = desc_flags | skb->len; |
1008 | descs[0].fields.address = adapter->bounce_buffer_dma; | 1085 | descs[0].fields.address = adapter->bounce_buffer_dma; |
1009 | 1086 | ||
1010 | if (ibmveth_send(adapter, descs)) { | 1087 | if (ibmveth_send(adapter, descs, 0)) { |
1011 | adapter->tx_send_failed++; | 1088 | adapter->tx_send_failed++; |
1012 | netdev->stats.tx_dropped++; | 1089 | netdev->stats.tx_dropped++; |
1013 | } else { | 1090 | } else { |
@@ -1041,16 +1118,23 @@ retry_bounce: | |||
1041 | descs[i+1].fields.address = dma_addr; | 1118 | descs[i+1].fields.address = dma_addr; |
1042 | } | 1119 | } |
1043 | 1120 | ||
1044 | if (skb_is_gso(skb) && !skb_is_gso_v6(skb)) { | 1121 | if (skb_is_gso(skb)) { |
1045 | /* Put -1 in the IP checksum to tell phyp it | 1122 | if (adapter->fw_large_send_support) { |
1046 | * is a largesend packet and put the mss in the TCP checksum. | 1123 | mss = (unsigned long)skb_shinfo(skb)->gso_size; |
1047 | */ | 1124 | adapter->tx_large_packets++; |
1048 | ip_hdr(skb)->check = 0xffff; | 1125 | } else if (!skb_is_gso_v6(skb)) { |
1049 | tcp_hdr(skb)->check = cpu_to_be16(skb_shinfo(skb)->gso_size); | 1126 | /* Put -1 in the IP checksum to tell phyp it |
1050 | adapter->tx_large_packets++; | 1127 | * is a largesend packet. Put the mss in |
1128 | * the TCP checksum. | ||
1129 | */ | ||
1130 | ip_hdr(skb)->check = 0xffff; | ||
1131 | tcp_hdr(skb)->check = | ||
1132 | cpu_to_be16(skb_shinfo(skb)->gso_size); | ||
1133 | adapter->tx_large_packets++; | ||
1134 | } | ||
1051 | } | 1135 | } |
1052 | 1136 | ||
1053 | if (ibmveth_send(adapter, descs)) { | 1137 | if (ibmveth_send(adapter, descs, mss)) { |
1054 | adapter->tx_send_failed++; | 1138 | adapter->tx_send_failed++; |
1055 | netdev->stats.tx_dropped++; | 1139 | netdev->stats.tx_dropped++; |
1056 | } else { | 1140 | } else { |
@@ -1401,6 +1485,8 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) | |||
1401 | struct ibmveth_adapter *adapter; | 1485 | struct ibmveth_adapter *adapter; |
1402 | unsigned char *mac_addr_p; | 1486 | unsigned char *mac_addr_p; |
1403 | unsigned int *mcastFilterSize_p; | 1487 | unsigned int *mcastFilterSize_p; |
1488 | long ret; | ||
1489 | unsigned long ret_attr; | ||
1404 | 1490 | ||
1405 | dev_dbg(&dev->dev, "entering ibmveth_probe for UA 0x%x\n", | 1491 | dev_dbg(&dev->dev, "entering ibmveth_probe for UA 0x%x\n", |
1406 | dev->unit_address); | 1492 | dev->unit_address); |
@@ -1449,10 +1535,19 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) | |||
1449 | SET_NETDEV_DEV(netdev, &dev->dev); | 1535 | SET_NETDEV_DEV(netdev, &dev->dev); |
1450 | netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | | 1536 | netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | |
1451 | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; | 1537 | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; |
1538 | |||
1452 | netdev->features |= netdev->hw_features; | 1539 | netdev->features |= netdev->hw_features; |
1453 | 1540 | ||
1454 | /* TSO is disabled by default */ | 1541 | ret = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr); |
1455 | netdev->hw_features |= NETIF_F_TSO; | 1542 | |
1543 | /* If running older firmware, TSO should not be enabled by default */ | ||
1544 | if (ret == H_SUCCESS && (ret_attr & IBMVETH_ILLAN_LRG_SND_SUPPORT) && | ||
1545 | !old_large_send) { | ||
1546 | netdev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; | ||
1547 | netdev->features |= netdev->hw_features; | ||
1548 | } else { | ||
1549 | netdev->hw_features |= NETIF_F_TSO; | ||
1550 | } | ||
1456 | 1551 | ||
1457 | memcpy(netdev->dev_addr, mac_addr_p, ETH_ALEN); | 1552 | memcpy(netdev->dev_addr, mac_addr_p, ETH_ALEN); |
1458 | 1553 | ||
diff --git a/drivers/net/ethernet/ibm/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h index 41dedb1fb2ae..4eade67fe30c 100644 --- a/drivers/net/ethernet/ibm/ibmveth.h +++ b/drivers/net/ethernet/ibm/ibmveth.h | |||
@@ -40,6 +40,8 @@ | |||
40 | #define IbmVethMcastRemoveFilter 0x2UL | 40 | #define IbmVethMcastRemoveFilter 0x2UL |
41 | #define IbmVethMcastClearFilterTable 0x3UL | 41 | #define IbmVethMcastClearFilterTable 0x3UL |
42 | 42 | ||
43 | #define IBMVETH_ILLAN_LRG_SR_ENABLED 0x0000000000010000UL | ||
44 | #define IBMVETH_ILLAN_LRG_SND_SUPPORT 0x0000000000008000UL | ||
43 | #define IBMVETH_ILLAN_PADDED_PKT_CSUM 0x0000000000002000UL | 45 | #define IBMVETH_ILLAN_PADDED_PKT_CSUM 0x0000000000002000UL |
44 | #define IBMVETH_ILLAN_TRUNK_PRI_MASK 0x0000000000000F00UL | 46 | #define IBMVETH_ILLAN_TRUNK_PRI_MASK 0x0000000000000F00UL |
45 | #define IBMVETH_ILLAN_IPV6_TCP_CSUM 0x0000000000000004UL | 47 | #define IBMVETH_ILLAN_IPV6_TCP_CSUM 0x0000000000000004UL |
@@ -59,13 +61,20 @@ | |||
59 | static inline long h_send_logical_lan(unsigned long unit_address, | 61 | static inline long h_send_logical_lan(unsigned long unit_address, |
60 | unsigned long desc1, unsigned long desc2, unsigned long desc3, | 62 | unsigned long desc1, unsigned long desc2, unsigned long desc3, |
61 | unsigned long desc4, unsigned long desc5, unsigned long desc6, | 63 | unsigned long desc4, unsigned long desc5, unsigned long desc6, |
62 | unsigned long corellator_in, unsigned long *corellator_out) | 64 | unsigned long corellator_in, unsigned long *corellator_out, |
65 | unsigned long mss, unsigned long large_send_support) | ||
63 | { | 66 | { |
64 | long rc; | 67 | long rc; |
65 | unsigned long retbuf[PLPAR_HCALL9_BUFSIZE]; | 68 | unsigned long retbuf[PLPAR_HCALL9_BUFSIZE]; |
66 | 69 | ||
67 | rc = plpar_hcall9(H_SEND_LOGICAL_LAN, retbuf, unit_address, desc1, | 70 | if (large_send_support) |
68 | desc2, desc3, desc4, desc5, desc6, corellator_in); | 71 | rc = plpar_hcall9(H_SEND_LOGICAL_LAN, retbuf, unit_address, |
72 | desc1, desc2, desc3, desc4, desc5, desc6, | ||
73 | corellator_in, mss); | ||
74 | else | ||
75 | rc = plpar_hcall9(H_SEND_LOGICAL_LAN, retbuf, unit_address, | ||
76 | desc1, desc2, desc3, desc4, desc5, desc6, | ||
77 | corellator_in); | ||
69 | 78 | ||
70 | *corellator_out = retbuf[0]; | 79 | *corellator_out = retbuf[0]; |
71 | 80 | ||
@@ -147,11 +156,13 @@ struct ibmveth_adapter { | |||
147 | struct ibmveth_rx_q rx_queue; | 156 | struct ibmveth_rx_q rx_queue; |
148 | int pool_config; | 157 | int pool_config; |
149 | int rx_csum; | 158 | int rx_csum; |
159 | int large_send; | ||
150 | void *bounce_buffer; | 160 | void *bounce_buffer; |
151 | dma_addr_t bounce_buffer_dma; | 161 | dma_addr_t bounce_buffer_dma; |
152 | 162 | ||
153 | u64 fw_ipv6_csum_support; | 163 | u64 fw_ipv6_csum_support; |
154 | u64 fw_ipv4_csum_support; | 164 | u64 fw_ipv4_csum_support; |
165 | u64 fw_large_send_support; | ||
155 | /* adapter specific stats */ | 166 | /* adapter specific stats */ |
156 | u64 replenish_task_cycles; | 167 | u64 replenish_task_cycles; |
157 | u64 replenish_no_mem; | 168 | u64 replenish_no_mem; |
@@ -182,6 +193,7 @@ struct ibmveth_buf_desc_fields { | |||
182 | #endif | 193 | #endif |
183 | #define IBMVETH_BUF_VALID 0x80000000 | 194 | #define IBMVETH_BUF_VALID 0x80000000 |
184 | #define IBMVETH_BUF_TOGGLE 0x40000000 | 195 | #define IBMVETH_BUF_TOGGLE 0x40000000 |
196 | #define IBMVETH_BUF_LRG_SND 0x04000000 | ||
185 | #define IBMVETH_BUF_NO_CSUM 0x02000000 | 197 | #define IBMVETH_BUF_NO_CSUM 0x02000000 |
186 | #define IBMVETH_BUF_CSUM_GOOD 0x01000000 | 198 | #define IBMVETH_BUF_CSUM_GOOD 0x01000000 |
187 | #define IBMVETH_BUF_LEN_MASK 0x00FFFFFF | 199 | #define IBMVETH_BUF_LEN_MASK 0x00FFFFFF |