diff options
author | Thomas Falcon <tlfalcon@linux.vnet.ibm.com> | 2017-10-17 13:36:55 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-10-19 08:20:32 -0400 |
commit | fdb061056f57e849a05cac072a4998c7f33d797e (patch) | |
tree | caaab1f2413f48ef728f4221f741de9ac6b1eb94 /drivers/net/ethernet/ibm/ibmvnic.c | |
parent | 154820563dd4621c78e03e98e70216e832422f8e (diff) |
ibmvnic: Enable TSO support
This patch enables TSO support. It includes additional
buffers reserved exclusively for large packets. Throughput
is greatly increased with TSO enabled, from about 1 Gb/s to
9 Gb/s on our test systems.
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/ibmvnic.c')
-rw-r--r-- | drivers/net/ethernet/ibm/ibmvnic.c | 56 |
1 files changed, 48 insertions, 8 deletions
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index b508877397e1..aedb81c230a6 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c | |||
@@ -553,6 +553,10 @@ static int reset_tx_pools(struct ibmvnic_adapter *adapter) | |||
553 | if (rc) | 553 | if (rc) |
554 | return rc; | 554 | return rc; |
555 | 555 | ||
556 | rc = reset_long_term_buff(adapter, &tx_pool->tso_ltb); | ||
557 | if (rc) | ||
558 | return rc; | ||
559 | |||
556 | memset(tx_pool->tx_buff, 0, | 560 | memset(tx_pool->tx_buff, 0, |
557 | adapter->req_tx_entries_per_subcrq * | 561 | adapter->req_tx_entries_per_subcrq * |
558 | sizeof(struct ibmvnic_tx_buff)); | 562 | sizeof(struct ibmvnic_tx_buff)); |
@@ -562,6 +566,7 @@ static int reset_tx_pools(struct ibmvnic_adapter *adapter) | |||
562 | 566 | ||
563 | tx_pool->consumer_index = 0; | 567 | tx_pool->consumer_index = 0; |
564 | tx_pool->producer_index = 0; | 568 | tx_pool->producer_index = 0; |
569 | tx_pool->tso_index = 0; | ||
565 | } | 570 | } |
566 | 571 | ||
567 | return 0; | 572 | return 0; |
@@ -581,6 +586,7 @@ static void release_tx_pools(struct ibmvnic_adapter *adapter) | |||
581 | tx_pool = &adapter->tx_pool[i]; | 586 | tx_pool = &adapter->tx_pool[i]; |
582 | kfree(tx_pool->tx_buff); | 587 | kfree(tx_pool->tx_buff); |
583 | free_long_term_buff(adapter, &tx_pool->long_term_buff); | 588 | free_long_term_buff(adapter, &tx_pool->long_term_buff); |
589 | free_long_term_buff(adapter, &tx_pool->tso_ltb); | ||
584 | kfree(tx_pool->free_map); | 590 | kfree(tx_pool->free_map); |
585 | } | 591 | } |
586 | 592 | ||
@@ -625,6 +631,16 @@ static int init_tx_pools(struct net_device *netdev) | |||
625 | return -1; | 631 | return -1; |
626 | } | 632 | } |
627 | 633 | ||
634 | /* alloc TSO ltb */ | ||
635 | if (alloc_long_term_buff(adapter, &tx_pool->tso_ltb, | ||
636 | IBMVNIC_TSO_BUFS * | ||
637 | IBMVNIC_TSO_BUF_SZ)) { | ||
638 | release_tx_pools(adapter); | ||
639 | return -1; | ||
640 | } | ||
641 | |||
642 | tx_pool->tso_index = 0; | ||
643 | |||
628 | tx_pool->free_map = kcalloc(adapter->req_tx_entries_per_subcrq, | 644 | tx_pool->free_map = kcalloc(adapter->req_tx_entries_per_subcrq, |
629 | sizeof(int), GFP_KERNEL); | 645 | sizeof(int), GFP_KERNEL); |
630 | if (!tx_pool->free_map) { | 646 | if (!tx_pool->free_map) { |
@@ -1201,10 +1217,21 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev) | |||
1201 | be32_to_cpu(adapter->login_rsp_buf->off_txsubm_subcrqs)); | 1217 | be32_to_cpu(adapter->login_rsp_buf->off_txsubm_subcrqs)); |
1202 | 1218 | ||
1203 | index = tx_pool->free_map[tx_pool->consumer_index]; | 1219 | index = tx_pool->free_map[tx_pool->consumer_index]; |
1204 | offset = index * adapter->req_mtu; | 1220 | |
1205 | dst = tx_pool->long_term_buff.buff + offset; | 1221 | if (skb_is_gso(skb)) { |
1206 | memset(dst, 0, adapter->req_mtu); | 1222 | offset = tx_pool->tso_index * IBMVNIC_TSO_BUF_SZ; |
1207 | data_dma_addr = tx_pool->long_term_buff.addr + offset; | 1223 | dst = tx_pool->tso_ltb.buff + offset; |
1224 | memset(dst, 0, IBMVNIC_TSO_BUF_SZ); | ||
1225 | data_dma_addr = tx_pool->tso_ltb.addr + offset; | ||
1226 | tx_pool->tso_index++; | ||
1227 | if (tx_pool->tso_index == IBMVNIC_TSO_BUFS) | ||
1228 | tx_pool->tso_index = 0; | ||
1229 | } else { | ||
1230 | offset = index * adapter->req_mtu; | ||
1231 | dst = tx_pool->long_term_buff.buff + offset; | ||
1232 | memset(dst, 0, adapter->req_mtu); | ||
1233 | data_dma_addr = tx_pool->long_term_buff.addr + offset; | ||
1234 | } | ||
1208 | 1235 | ||
1209 | if (skb_shinfo(skb)->nr_frags) { | 1236 | if (skb_shinfo(skb)->nr_frags) { |
1210 | int cur, i; | 1237 | int cur, i; |
@@ -1245,7 +1272,10 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev) | |||
1245 | tx_crq.v1.n_sge = 1; | 1272 | tx_crq.v1.n_sge = 1; |
1246 | tx_crq.v1.flags1 = IBMVNIC_TX_COMP_NEEDED; | 1273 | tx_crq.v1.flags1 = IBMVNIC_TX_COMP_NEEDED; |
1247 | tx_crq.v1.correlator = cpu_to_be32(index); | 1274 | tx_crq.v1.correlator = cpu_to_be32(index); |
1248 | tx_crq.v1.dma_reg = cpu_to_be16(tx_pool->long_term_buff.map_id); | 1275 | if (skb_is_gso(skb)) |
1276 | tx_crq.v1.dma_reg = cpu_to_be16(tx_pool->tso_ltb.map_id); | ||
1277 | else | ||
1278 | tx_crq.v1.dma_reg = cpu_to_be16(tx_pool->long_term_buff.map_id); | ||
1249 | tx_crq.v1.sge_len = cpu_to_be32(skb->len); | 1279 | tx_crq.v1.sge_len = cpu_to_be32(skb->len); |
1250 | tx_crq.v1.ioba = cpu_to_be64(data_dma_addr); | 1280 | tx_crq.v1.ioba = cpu_to_be64(data_dma_addr); |
1251 | 1281 | ||
@@ -1270,6 +1300,11 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev) | |||
1270 | tx_crq.v1.flags1 |= IBMVNIC_TX_CHKSUM_OFFLOAD; | 1300 | tx_crq.v1.flags1 |= IBMVNIC_TX_CHKSUM_OFFLOAD; |
1271 | hdrs += 2; | 1301 | hdrs += 2; |
1272 | } | 1302 | } |
1303 | if (skb_is_gso(skb)) { | ||
1304 | tx_crq.v1.flags1 |= IBMVNIC_TX_LSO; | ||
1305 | tx_crq.v1.mss = cpu_to_be16(skb_shinfo(skb)->gso_size); | ||
1306 | hdrs += 2; | ||
1307 | } | ||
1273 | /* determine if l2/3/4 headers are sent to firmware */ | 1308 | /* determine if l2/3/4 headers are sent to firmware */ |
1274 | if ((*hdrs >> 7) & 1 && | 1309 | if ((*hdrs >> 7) & 1 && |
1275 | (skb->protocol == htons(ETH_P_IP) || | 1310 | (skb->protocol == htons(ETH_P_IP) || |
@@ -2960,10 +2995,10 @@ static void handle_query_ip_offload_rsp(struct ibmvnic_adapter *adapter) | |||
2960 | adapter->ip_offload_ctrl.udp_ipv4_chksum = buf->udp_ipv4_chksum; | 2995 | adapter->ip_offload_ctrl.udp_ipv4_chksum = buf->udp_ipv4_chksum; |
2961 | adapter->ip_offload_ctrl.tcp_ipv6_chksum = buf->tcp_ipv6_chksum; | 2996 | adapter->ip_offload_ctrl.tcp_ipv6_chksum = buf->tcp_ipv6_chksum; |
2962 | adapter->ip_offload_ctrl.udp_ipv6_chksum = buf->udp_ipv6_chksum; | 2997 | adapter->ip_offload_ctrl.udp_ipv6_chksum = buf->udp_ipv6_chksum; |
2998 | adapter->ip_offload_ctrl.large_tx_ipv4 = buf->large_tx_ipv4; | ||
2999 | adapter->ip_offload_ctrl.large_tx_ipv6 = buf->large_tx_ipv6; | ||
2963 | 3000 | ||
2964 | /* large_tx/rx disabled for now, additional features needed */ | 3001 | /* large_rx disabled for now, additional features needed */ |
2965 | adapter->ip_offload_ctrl.large_tx_ipv4 = 0; | ||
2966 | adapter->ip_offload_ctrl.large_tx_ipv6 = 0; | ||
2967 | adapter->ip_offload_ctrl.large_rx_ipv4 = 0; | 3002 | adapter->ip_offload_ctrl.large_rx_ipv4 = 0; |
2968 | adapter->ip_offload_ctrl.large_rx_ipv6 = 0; | 3003 | adapter->ip_offload_ctrl.large_rx_ipv6 = 0; |
2969 | 3004 | ||
@@ -2979,6 +3014,11 @@ static void handle_query_ip_offload_rsp(struct ibmvnic_adapter *adapter) | |||
2979 | (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM))) | 3014 | (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM))) |
2980 | adapter->netdev->features |= NETIF_F_RXCSUM; | 3015 | adapter->netdev->features |= NETIF_F_RXCSUM; |
2981 | 3016 | ||
3017 | if (buf->large_tx_ipv4) | ||
3018 | adapter->netdev->features |= NETIF_F_TSO; | ||
3019 | if (buf->large_tx_ipv6) | ||
3020 | adapter->netdev->features |= NETIF_F_TSO6; | ||
3021 | |||
2982 | memset(&crq, 0, sizeof(crq)); | 3022 | memset(&crq, 0, sizeof(crq)); |
2983 | crq.control_ip_offload.first = IBMVNIC_CRQ_CMD; | 3023 | crq.control_ip_offload.first = IBMVNIC_CRQ_CMD; |
2984 | crq.control_ip_offload.cmd = CONTROL_IP_OFFLOAD; | 3024 | crq.control_ip_offload.cmd = CONTROL_IP_OFFLOAD; |