aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
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
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')
-rw-r--r--drivers/net/ibmveth.c53
-rw-r--r--drivers/net/ibmveth.h41
2 files changed, 92 insertions, 2 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) {
diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h
index e05694126f85..3f10f0f4447a 100644
--- a/drivers/net/ibmveth.h
+++ b/drivers/net/ibmveth.h
@@ -67,6 +67,21 @@ static inline long h_send_logical_lan(unsigned long unit_address,
67 return rc; 67 return rc;
68} 68}
69 69
70static inline long h_illan_attributes(unsigned long unit_address,
71 unsigned long reset_mask, unsigned long set_mask,
72 unsigned long *ret_attributes)
73{
74 long rc;
75 unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
76
77 rc = plpar_hcall(H_ILLAN_ATTRIBUTES, retbuf, unit_address,
78 reset_mask, set_mask);
79
80 *ret_attributes = retbuf[0];
81
82 return rc;
83}
84
70#define h_multicast_ctrl(ua, cmd, mac) \ 85#define h_multicast_ctrl(ua, cmd, mac) \
71 plpar_hcall_norets(H_MULTICAST_CTRL, ua, cmd, mac) 86 plpar_hcall_norets(H_MULTICAST_CTRL, ua, cmd, mac)
72 87
@@ -142,7 +157,9 @@ struct ibmveth_adapter {
142struct ibmveth_buf_desc_fields { 157struct ibmveth_buf_desc_fields {
143 u32 valid : 1; 158 u32 valid : 1;
144 u32 toggle : 1; 159 u32 toggle : 1;
145 u32 reserved : 6; 160 u32 reserved : 4;
161 u32 no_csum : 1;
162 u32 csum_good : 1;
146 u32 length : 24; 163 u32 length : 24;
147 u32 address; 164 u32 address;
148}; 165};
@@ -152,10 +169,30 @@ union ibmveth_buf_desc {
152 struct ibmveth_buf_desc_fields fields; 169 struct ibmveth_buf_desc_fields fields;
153}; 170};
154 171
172struct ibmveth_illan_attributes_fields {
173 u32 reserved;
174 u32 reserved2 : 18;
175 u32 csum_offload_padded_pkt_support : 1;
176 u32 reserved3 : 1;
177 u32 trunk_priority : 4;
178 u32 reserved4 : 5;
179 u32 tcp_csum_offload_ipv6 : 1;
180 u32 tcp_csum_offload_ipv4 : 1;
181 u32 active_trunk : 1;
182};
183
184union ibmveth_illan_attributes {
185 u64 desc;
186 struct ibmveth_illan_attributes_fields fields;
187};
188
155struct ibmveth_rx_q_entry { 189struct ibmveth_rx_q_entry {
156 u16 toggle : 1; 190 u16 toggle : 1;
157 u16 valid : 1; 191 u16 valid : 1;
158 u16 reserved : 14; 192 u16 reserved : 4;
193 u16 no_csum : 1;
194 u16 csum_good : 1;
195 u16 reserved2 : 8;
159 u16 offset; 196 u16 offset;
160 u32 length; 197 u32 length;
161 u64 correlator; 198 u64 correlator;