aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSantiago Leon <santil@linux.vnet.ibm.com>2010-09-03 14:28:52 -0400
committerDavid S. Miller <davem@davemloft.net>2010-09-06 21:21:50 -0400
commitab78df75cac4d90b5b5471af795a64141243c02a (patch)
treed645048489a624d90687cb1d90747927150f3f80 /drivers
parentbc4c6f54e4e9971717d84c630acef0c7c3c75a97 (diff)
ibmveth: Enable IPv6 checksum offload
This patch enables TCP checksum offload support for IPv6 on ibmveth. This completely eliminates the generation and checking of the checksum for IPv6 packets that are completely virtual and never touch a physical network. A basic TCPIPV6_STREAM netperf run showed a ~30% throughput improvement when an MTU of 64000 was used. This featured is enabled by default, as is the case for IPv4 checksum offload. When checksum offload is enabled the driver will negotiate IPv4 and IPv6 offload with the firmware separately and enable what is available. As long as either IPv4 or IPv6 offload is supported and enabled the device will report that checksum offload is enabled. The device stats, available through ethtool, will display which checksum offload features are supported/enabled by firmware. Performance testing against a stock kernel shows no regression for IPv4 or IPv6 in terms of throughput or processor utilization with checksum disabled or enabled. Signed-off-by: Robert Jennings <rcj@linux.vnet.ibm.com> Signed-off-by: Santiago Leon <santil@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/ibmveth.c59
-rw-r--r--drivers/net/ibmveth.h2
2 files changed, 50 insertions, 11 deletions
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index ab80d8fcccbf..25cf7e0476d0 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -50,6 +50,7 @@
50#include <linux/proc_fs.h> 50#include <linux/proc_fs.h>
51#include <linux/in.h> 51#include <linux/in.h>
52#include <linux/ip.h> 52#include <linux/ip.h>
53#include <linux/ipv6.h>
53#include <linux/slab.h> 54#include <linux/slab.h>
54#include <net/net_namespace.h> 55#include <net/net_namespace.h>
55#include <asm/hvcall.h> 56#include <asm/hvcall.h>
@@ -148,6 +149,8 @@ struct ibmveth_stat ibmveth_stats[] = {
148 { "rx_no_buffer", IBMVETH_STAT_OFF(rx_no_buffer) }, 149 { "rx_no_buffer", IBMVETH_STAT_OFF(rx_no_buffer) },
149 { "tx_map_failed", IBMVETH_STAT_OFF(tx_map_failed) }, 150 { "tx_map_failed", IBMVETH_STAT_OFF(tx_map_failed) },
150 { "tx_send_failed", IBMVETH_STAT_OFF(tx_send_failed) }, 151 { "tx_send_failed", IBMVETH_STAT_OFF(tx_send_failed) },
152 { "fw_enabled_ipv4_csum", IBMVETH_STAT_OFF(fw_ipv4_csum_support) },
153 { "fw_enabled_ipv6_csum", IBMVETH_STAT_OFF(fw_ipv6_csum_support) },
151}; 154};
152 155
153/* simple methods of getting data from the current rxq entry */ 156/* simple methods of getting data from the current rxq entry */
@@ -773,6 +776,7 @@ static void ibmveth_set_rx_csum_flags(struct net_device *dev, u32 data)
773 */ 776 */
774 adapter->rx_csum = 0; 777 adapter->rx_csum = 0;
775 dev->features &= ~NETIF_F_IP_CSUM; 778 dev->features &= ~NETIF_F_IP_CSUM;
779 dev->features &= ~NETIF_F_IPV6_CSUM;
776 } 780 }
777} 781}
778 782
@@ -781,10 +785,15 @@ static void ibmveth_set_tx_csum_flags(struct net_device *dev, u32 data)
781 struct ibmveth_adapter *adapter = netdev_priv(dev); 785 struct ibmveth_adapter *adapter = netdev_priv(dev);
782 786
783 if (data) { 787 if (data) {
784 dev->features |= NETIF_F_IP_CSUM; 788 if (adapter->fw_ipv4_csum_support)
789 dev->features |= NETIF_F_IP_CSUM;
790 if (adapter->fw_ipv6_csum_support)
791 dev->features |= NETIF_F_IPV6_CSUM;
785 adapter->rx_csum = 1; 792 adapter->rx_csum = 1;
786 } else 793 } else {
787 dev->features &= ~NETIF_F_IP_CSUM; 794 dev->features &= ~NETIF_F_IP_CSUM;
795 dev->features &= ~NETIF_F_IPV6_CSUM;
796 }
788} 797}
789 798
790static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, 799static int ibmveth_set_csum_offload(struct net_device *dev, u32 data,
@@ -792,7 +801,8 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data,
792{ 801{
793 struct ibmveth_adapter *adapter = netdev_priv(dev); 802 struct ibmveth_adapter *adapter = netdev_priv(dev);
794 unsigned long set_attr, clr_attr, ret_attr; 803 unsigned long set_attr, clr_attr, ret_attr;
795 long ret; 804 unsigned long set_attr6, clr_attr6;
805 long ret, ret6;
796 int rc1 = 0, rc2 = 0; 806 int rc1 = 0, rc2 = 0;
797 int restart = 0; 807 int restart = 0;
798 808
@@ -806,10 +816,13 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data,
806 set_attr = 0; 816 set_attr = 0;
807 clr_attr = 0; 817 clr_attr = 0;
808 818
809 if (data) 819 if (data) {
810 set_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM; 820 set_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM;
811 else 821 set_attr6 = IBMVETH_ILLAN_IPV6_TCP_CSUM;
822 } else {
812 clr_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM; 823 clr_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM;
824 clr_attr6 = IBMVETH_ILLAN_IPV6_TCP_CSUM;
825 }
813 826
814 ret = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr); 827 ret = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr);
815 828
@@ -820,14 +833,33 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data,
820 set_attr, &ret_attr); 833 set_attr, &ret_attr);
821 834
822 if (ret != H_SUCCESS) { 835 if (ret != H_SUCCESS) {
823 rc1 = -EIO; 836 ibmveth_error_printk("unable to change IPv4 checksum "
824 ibmveth_error_printk("unable to change checksum offload settings." 837 "offload settings. %d rc=%ld\n",
825 " %d rc=%ld\n", data, ret); 838 data, ret);
826 839
827 ret = h_illan_attributes(adapter->vdev->unit_address, 840 ret = h_illan_attributes(adapter->vdev->unit_address,
828 set_attr, clr_attr, &ret_attr); 841 set_attr, clr_attr, &ret_attr);
829 } else 842 } else
843 adapter->fw_ipv4_csum_support = data;
844
845 ret6 = h_illan_attributes(adapter->vdev->unit_address,
846 clr_attr6, set_attr6, &ret_attr);
847
848 if (ret6 != H_SUCCESS) {
849 ibmveth_error_printk("unable to change IPv6 checksum "
850 "offload settings. %d rc=%ld\n",
851 data, ret);
852
853 ret = h_illan_attributes(adapter->vdev->unit_address,
854 set_attr6, clr_attr6,
855 &ret_attr);
856 } else
857 adapter->fw_ipv6_csum_support = data;
858
859 if (ret == H_SUCCESS || ret6 == H_SUCCESS)
830 done(dev, data); 860 done(dev, data);
861 else
862 rc1 = -EIO;
831 } else { 863 } else {
832 rc1 = -EIO; 864 rc1 = -EIO;
833 ibmveth_error_printk("unable to change checksum offload settings." 865 ibmveth_error_printk("unable to change checksum offload settings."
@@ -855,9 +887,9 @@ static int ibmveth_set_tx_csum(struct net_device *dev, u32 data)
855 struct ibmveth_adapter *adapter = netdev_priv(dev); 887 struct ibmveth_adapter *adapter = netdev_priv(dev);
856 int rc = 0; 888 int rc = 0;
857 889
858 if (data && (dev->features & NETIF_F_IP_CSUM)) 890 if (data && (dev->features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)))
859 return 0; 891 return 0;
860 if (!data && !(dev->features & NETIF_F_IP_CSUM)) 892 if (!data && !(dev->features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)))
861 return 0; 893 return 0;
862 894
863 if (data && !adapter->rx_csum) 895 if (data && !adapter->rx_csum)
@@ -975,7 +1007,12 @@ static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb,
975 1007
976 /* veth can't checksum offload UDP */ 1008 /* veth can't checksum offload UDP */
977 if (skb->ip_summed == CHECKSUM_PARTIAL && 1009 if (skb->ip_summed == CHECKSUM_PARTIAL &&
978 ip_hdr(skb)->protocol != IPPROTO_TCP && skb_checksum_help(skb)) { 1010 ((skb->protocol == htons(ETH_P_IP) &&
1011 ip_hdr(skb)->protocol != IPPROTO_TCP) ||
1012 (skb->protocol == htons(ETH_P_IPV6) &&
1013 ipv6_hdr(skb)->nexthdr != IPPROTO_TCP)) &&
1014 skb_checksum_help(skb)) {
1015
979 ibmveth_error_printk("tx: failed to checksum packet\n"); 1016 ibmveth_error_printk("tx: failed to checksum packet\n");
980 netdev->stats.tx_dropped++; 1017 netdev->stats.tx_dropped++;
981 goto out; 1018 goto out;
diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h
index d5651c79e199..84e4ab224124 100644
--- a/drivers/net/ibmveth.h
+++ b/drivers/net/ibmveth.h
@@ -149,6 +149,8 @@ struct ibmveth_adapter {
149 void *bounce_buffer; 149 void *bounce_buffer;
150 dma_addr_t bounce_buffer_dma; 150 dma_addr_t bounce_buffer_dma;
151 151
152 u64 fw_ipv6_csum_support;
153 u64 fw_ipv4_csum_support;
152 /* adapter specific stats */ 154 /* adapter specific stats */
153 u64 replenish_task_cycles; 155 u64 replenish_task_cycles;
154 u64 replenish_no_mem; 156 u64 replenish_no_mem;