aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ibmveth.c
diff options
context:
space:
mode:
authorBrian King <brking@linux.vnet.ibm.com>2007-09-15 16:36:07 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:50:43 -0400
commitf4ff28720f45354573dcf4e0eb5a2dc5452cb3e1 (patch)
treebdd8f33e738962c44f1172a3fd3a3aebb0246f61 /drivers/net/ibmveth.c
parentdf950828b0ee51ff63c49c67d561bfd3d6096788 (diff)
ibmveth: Enable TCP checksum offload
This patchset enables TCP checksum offload support for IPV4 on ibmveth. This completely eliminates the generation and checking of the checksum for packets that are completely virtual and never touch a physical network. A simple TCP_STREAM netperf run on a virtual network with maximum mtu set yielded a ~30% increase in throughput. This feature is enabled by default on systems that support it, but can be disabled with a module option. Signed-off-by: Brian King <brking@linux.vnet.ibm.com> Signed-off-by: Jeff Garzik <jeff@garzik.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ibmveth.c')
-rw-r--r--drivers/net/ibmveth.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 0c35d72f5f8d..9353890dcda0 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -47,6 +47,8 @@
47#include <linux/mm.h> 47#include <linux/mm.h>
48#include <linux/ethtool.h> 48#include <linux/ethtool.h>
49#include <linux/proc_fs.h> 49#include <linux/proc_fs.h>
50#include <linux/in.h>
51#include <linux/ip.h>
50#include <net/net_namespace.h> 52#include <net/net_namespace.h>
51#include <asm/semaphore.h> 53#include <asm/semaphore.h>
52#include <asm/hvcall.h> 54#include <asm/hvcall.h>
@@ -132,6 +134,11 @@ static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter)
132 return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].length); 134 return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].length);
133} 135}
134 136
137static inline int ibmveth_rxq_csum_good(struct ibmveth_adapter *adapter)
138{
139 return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].csum_good);
140}
141
135/* setup the initial settings for a buffer pool */ 142/* setup the initial settings for a buffer pool */
136static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool, u32 pool_index, u32 pool_size, u32 buff_size, u32 pool_active) 143static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool, u32 pool_index, u32 pool_size, u32 buff_size, u32 pool_active)
137{ 144{
@@ -695,6 +702,24 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev)
695 desc[0].fields.length, DMA_TO_DEVICE); 702 desc[0].fields.length, DMA_TO_DEVICE);
696 desc[0].fields.valid = 1; 703 desc[0].fields.valid = 1;
697 704
705 if (skb->ip_summed == CHECKSUM_PARTIAL &&
706 ip_hdr(skb)->protocol != IPPROTO_TCP && skb_checksum_help(skb)) {
707 ibmveth_error_printk("tx: failed to checksum packet\n");
708 tx_dropped++;
709 goto out;
710 }
711
712 if (skb->ip_summed == CHECKSUM_PARTIAL) {
713 unsigned char *buf = skb_transport_header(skb) + skb->csum_offset;
714
715 desc[0].fields.no_csum = 1;
716 desc[0].fields.csum_good = 1;
717
718 /* Need to zero out the checksum */
719 buf[0] = 0;
720 buf[1] = 0;
721 }
722
698 if(dma_mapping_error(desc[0].fields.address)) { 723 if(dma_mapping_error(desc[0].fields.address)) {
699 ibmveth_error_printk("tx: unable to map initial fragment\n"); 724 ibmveth_error_printk("tx: unable to map initial fragment\n");
700 tx_map_failed++; 725 tx_map_failed++;
@@ -713,6 +738,10 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev)
713 frag->size, DMA_TO_DEVICE); 738 frag->size, DMA_TO_DEVICE);
714 desc[curfrag+1].fields.length = frag->size; 739 desc[curfrag+1].fields.length = frag->size;
715 desc[curfrag+1].fields.valid = 1; 740 desc[curfrag+1].fields.valid = 1;
741 if (skb->ip_summed == CHECKSUM_PARTIAL) {
742 desc[curfrag+1].fields.no_csum = 1;
743 desc[curfrag+1].fields.csum_good = 1;
744 }
716 745
717 if(dma_mapping_error(desc[curfrag+1].fields.address)) { 746 if(dma_mapping_error(desc[curfrag+1].fields.address)) {
718 ibmveth_error_printk("tx: unable to map fragment %d\n", curfrag); 747 ibmveth_error_printk("tx: unable to map fragment %d\n", curfrag);
@@ -801,7 +830,11 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
801 } else { 830 } else {
802 int length = ibmveth_rxq_frame_length(adapter); 831 int length = ibmveth_rxq_frame_length(adapter);
803 int offset = ibmveth_rxq_frame_offset(adapter); 832 int offset = ibmveth_rxq_frame_offset(adapter);
833 int csum_good = ibmveth_rxq_csum_good(adapter);
834
804 skb = ibmveth_rxq_get_buffer(adapter); 835 skb = ibmveth_rxq_get_buffer(adapter);
836 if (csum_good)
837 skb->ip_summed = CHECKSUM_UNNECESSARY;
805 838
806 ibmveth_rxq_harvest_buffer(adapter); 839 ibmveth_rxq_harvest_buffer(adapter);
807 840
@@ -962,8 +995,10 @@ static void ibmveth_poll_controller(struct net_device *dev)
962static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) 995static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
963{ 996{
964 int rc, i; 997 int rc, i;
998 long ret;
965 struct net_device *netdev; 999 struct net_device *netdev;
966 struct ibmveth_adapter *adapter; 1000 struct ibmveth_adapter *adapter;
1001 union ibmveth_illan_attributes set_attr, ret_attr;
967 1002
968 unsigned char *mac_addr_p; 1003 unsigned char *mac_addr_p;
969 unsigned int *mcastFilterSize_p; 1004 unsigned int *mcastFilterSize_p;
@@ -1057,6 +1092,24 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
1057 1092
1058 ibmveth_debug_printk("registering netdev...\n"); 1093 ibmveth_debug_printk("registering netdev...\n");
1059 1094
1095 ret = h_illan_attributes(dev->unit_address, 0, 0, &ret_attr.desc);
1096
1097 if (ret == H_SUCCESS && !ret_attr.fields.active_trunk &&
1098 !ret_attr.fields.trunk_priority &&
1099 ret_attr.fields.csum_offload_padded_pkt_support) {
1100 set_attr.desc = 0;
1101 set_attr.fields.tcp_csum_offload_ipv4 = 1;
1102
1103 ret = h_illan_attributes(dev->unit_address, 0, set_attr.desc,
1104 &ret_attr.desc);
1105
1106 if (ret == H_SUCCESS)
1107 netdev->features |= NETIF_F_IP_CSUM;
1108 else
1109 ret = h_illan_attributes(dev->unit_address, set_attr.desc,
1110 0, &ret_attr.desc);
1111 }
1112
1060 rc = register_netdev(netdev); 1113 rc = register_netdev(netdev);
1061 1114
1062 if(rc) { 1115 if(rc) {