diff options
author | Jan-Bernd Themann <themann@de.ibm.com> | 2007-09-25 19:16:34 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-10 19:47:47 -0400 |
commit | d4dc4ec9d84e0578b9bfbe56a11fafdb7cbac771 (patch) | |
tree | 03813a60023b75752ebcb8b3217018d472b21c86 /drivers/net | |
parent | 71c87e0cedca843162206c698cfa02e5fea9e2e3 (diff) |
[EHEA]: Use LRO.
Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/Kconfig | 1 | ||||
-rw-r--r-- | drivers/net/ehea/ehea.h | 7 | ||||
-rw-r--r-- | drivers/net/ehea/ehea_ethtool.c | 15 | ||||
-rw-r--r-- | drivers/net/ehea/ehea_main.c | 84 |
4 files changed, 100 insertions, 7 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index e0a979184c0a..61dedfeed62a 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig | |||
@@ -2507,6 +2507,7 @@ config CHELSIO_T3 | |||
2507 | config EHEA | 2507 | config EHEA |
2508 | tristate "eHEA Ethernet support" | 2508 | tristate "eHEA Ethernet support" |
2509 | depends on IBMEBUS | 2509 | depends on IBMEBUS |
2510 | select INET_LRO | ||
2510 | ---help--- | 2511 | ---help--- |
2511 | This driver supports the IBM pSeries eHEA ethernet adapter. | 2512 | This driver supports the IBM pSeries eHEA ethernet adapter. |
2512 | 2513 | ||
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index a154681165b9..c0cbd949e336 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/ethtool.h> | 33 | #include <linux/ethtool.h> |
34 | #include <linux/vmalloc.h> | 34 | #include <linux/vmalloc.h> |
35 | #include <linux/if_vlan.h> | 35 | #include <linux/if_vlan.h> |
36 | #include <linux/inet_lro.h> | ||
36 | 37 | ||
37 | #include <asm/ibmebus.h> | 38 | #include <asm/ibmebus.h> |
38 | #include <asm/abs_addr.h> | 39 | #include <asm/abs_addr.h> |
@@ -58,6 +59,7 @@ | |||
58 | 59 | ||
59 | #define EHEA_SMALL_QUEUES | 60 | #define EHEA_SMALL_QUEUES |
60 | #define EHEA_NUM_TX_QP 1 | 61 | #define EHEA_NUM_TX_QP 1 |
62 | #define EHEA_LRO_MAX_AGGR 64 | ||
61 | 63 | ||
62 | #ifdef EHEA_SMALL_QUEUES | 64 | #ifdef EHEA_SMALL_QUEUES |
63 | #define EHEA_MAX_CQE_COUNT 1023 | 65 | #define EHEA_MAX_CQE_COUNT 1023 |
@@ -84,6 +86,8 @@ | |||
84 | #define EHEA_RQ2_PKT_SIZE 1522 | 86 | #define EHEA_RQ2_PKT_SIZE 1522 |
85 | #define EHEA_L_PKT_SIZE 256 /* low latency */ | 87 | #define EHEA_L_PKT_SIZE 256 /* low latency */ |
86 | 88 | ||
89 | #define MAX_LRO_DESCRIPTORS 8 | ||
90 | |||
87 | /* Send completion signaling */ | 91 | /* Send completion signaling */ |
88 | 92 | ||
89 | /* Protection Domain Identifier */ | 93 | /* Protection Domain Identifier */ |
@@ -376,6 +380,8 @@ struct ehea_port_res { | |||
376 | u64 tx_packets; | 380 | u64 tx_packets; |
377 | u64 rx_packets; | 381 | u64 rx_packets; |
378 | u32 poll_counter; | 382 | u32 poll_counter; |
383 | struct net_lro_mgr lro_mgr; | ||
384 | struct net_lro_desc lro_desc[MAX_LRO_DESCRIPTORS]; | ||
379 | }; | 385 | }; |
380 | 386 | ||
381 | 387 | ||
@@ -429,6 +435,7 @@ struct ehea_port { | |||
429 | u32 msg_enable; | 435 | u32 msg_enable; |
430 | u32 sig_comp_iv; | 436 | u32 sig_comp_iv; |
431 | u32 state; | 437 | u32 state; |
438 | u32 lro_max_aggr; | ||
432 | u8 phy_link; | 439 | u8 phy_link; |
433 | u8 full_duplex; | 440 | u8 full_duplex; |
434 | u8 autoneg; | 441 | u8 autoneg; |
diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c index decec8cfe96b..29ef7a98f8be 100644 --- a/drivers/net/ehea/ehea_ethtool.c +++ b/drivers/net/ehea/ehea_ethtool.c | |||
@@ -183,6 +183,9 @@ static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = { | |||
183 | {"PR5 free_swqes"}, | 183 | {"PR5 free_swqes"}, |
184 | {"PR6 free_swqes"}, | 184 | {"PR6 free_swqes"}, |
185 | {"PR7 free_swqes"}, | 185 | {"PR7 free_swqes"}, |
186 | {"LRO aggregated"}, | ||
187 | {"LRO flushed"}, | ||
188 | {"LRO no_desc"}, | ||
186 | }; | 189 | }; |
187 | 190 | ||
188 | static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data) | 191 | static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data) |
@@ -239,6 +242,18 @@ static void ehea_get_ethtool_stats(struct net_device *dev, | |||
239 | for (k = 0; k < 8; k++) | 242 | for (k = 0; k < 8; k++) |
240 | data[i++] = atomic_read(&port->port_res[k].swqe_avail); | 243 | data[i++] = atomic_read(&port->port_res[k].swqe_avail); |
241 | 244 | ||
245 | for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) | ||
246 | tmp |= port->port_res[k].lro_mgr.stats.aggregated; | ||
247 | data[i++] = tmp; | ||
248 | |||
249 | for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) | ||
250 | tmp |= port->port_res[k].lro_mgr.stats.flushed; | ||
251 | data[i++] = tmp; | ||
252 | |||
253 | for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) | ||
254 | tmp |= port->port_res[k].lro_mgr.stats.no_desc; | ||
255 | data[i++] = tmp; | ||
256 | |||
242 | } | 257 | } |
243 | 258 | ||
244 | const struct ethtool_ops ehea_ethtool_ops = { | 259 | const struct ethtool_ops ehea_ethtool_ops = { |
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 5ebd545ab04e..b8e00391a5e3 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c | |||
@@ -52,6 +52,8 @@ static int rq2_entries = EHEA_DEF_ENTRIES_RQ2; | |||
52 | static int rq3_entries = EHEA_DEF_ENTRIES_RQ3; | 52 | static int rq3_entries = EHEA_DEF_ENTRIES_RQ3; |
53 | static int sq_entries = EHEA_DEF_ENTRIES_SQ; | 53 | static int sq_entries = EHEA_DEF_ENTRIES_SQ; |
54 | static int use_mcs = 0; | 54 | static int use_mcs = 0; |
55 | static int use_lro = 0; | ||
56 | static int lro_max_aggr = EHEA_LRO_MAX_AGGR; | ||
55 | static int num_tx_qps = EHEA_NUM_TX_QP; | 57 | static int num_tx_qps = EHEA_NUM_TX_QP; |
56 | static int prop_carrier_state = 0; | 58 | static int prop_carrier_state = 0; |
57 | 59 | ||
@@ -62,6 +64,8 @@ module_param(rq3_entries, int, 0); | |||
62 | module_param(sq_entries, int, 0); | 64 | module_param(sq_entries, int, 0); |
63 | module_param(prop_carrier_state, int, 0); | 65 | module_param(prop_carrier_state, int, 0); |
64 | module_param(use_mcs, int, 0); | 66 | module_param(use_mcs, int, 0); |
67 | module_param(use_lro, int, 0); | ||
68 | module_param(lro_max_aggr, int, 0); | ||
65 | module_param(num_tx_qps, int, 0); | 69 | module_param(num_tx_qps, int, 0); |
66 | 70 | ||
67 | MODULE_PARM_DESC(num_tx_qps, "Number of TX-QPS"); | 71 | MODULE_PARM_DESC(num_tx_qps, "Number of TX-QPS"); |
@@ -82,6 +86,11 @@ MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue " | |||
82 | __MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")"); | 86 | __MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")"); |
83 | MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 0 "); | 87 | MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 0 "); |
84 | 88 | ||
89 | MODULE_PARM_DESC(lro_max_aggr, " LRO: Max packets to be aggregated. Default = " | ||
90 | __MODULE_STRING(EHEA_LRO_MAX_AGGR)); | ||
91 | MODULE_PARM_DESC(use_lro, " Large Receive Offload, 1: enable, 0: disable, " | ||
92 | "Default = 0"); | ||
93 | |||
85 | static int port_name_cnt = 0; | 94 | static int port_name_cnt = 0; |
86 | static LIST_HEAD(adapter_list); | 95 | static LIST_HEAD(adapter_list); |
87 | u64 ehea_driver_flags = 0; | 96 | u64 ehea_driver_flags = 0; |
@@ -393,6 +402,60 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq, | |||
393 | return 0; | 402 | return 0; |
394 | } | 403 | } |
395 | 404 | ||
405 | static int get_skb_hdr(struct sk_buff *skb, void **iphdr, | ||
406 | void **tcph, u64 *hdr_flags, void *priv) | ||
407 | { | ||
408 | struct ehea_cqe *cqe = priv; | ||
409 | unsigned int ip_len; | ||
410 | struct iphdr *iph; | ||
411 | |||
412 | /* non tcp/udp packets */ | ||
413 | if (!cqe->header_length) | ||
414 | return -1; | ||
415 | |||
416 | /* non tcp packet */ | ||
417 | skb_reset_network_header(skb); | ||
418 | iph = ip_hdr(skb); | ||
419 | if (iph->protocol != IPPROTO_TCP) | ||
420 | return -1; | ||
421 | |||
422 | ip_len = ip_hdrlen(skb); | ||
423 | skb_set_transport_header(skb, ip_len); | ||
424 | *tcph = tcp_hdr(skb); | ||
425 | |||
426 | /* check if ip header and tcp header are complete */ | ||
427 | if (iph->tot_len < ip_len + tcp_hdrlen(skb)) | ||
428 | return -1; | ||
429 | |||
430 | *hdr_flags = LRO_IPV4 | LRO_TCP; | ||
431 | *iphdr = iph; | ||
432 | |||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | static void ehea_proc_skb(struct ehea_port_res *pr, struct ehea_cqe *cqe, | ||
437 | struct sk_buff *skb) | ||
438 | { | ||
439 | int vlan_extracted = (cqe->status & EHEA_CQE_VLAN_TAG_XTRACT) | ||
440 | && pr->port->vgrp; | ||
441 | |||
442 | if (use_lro) { | ||
443 | if (vlan_extracted) | ||
444 | lro_vlan_hwaccel_receive_skb(&pr->lro_mgr, skb, | ||
445 | pr->port->vgrp, | ||
446 | cqe->vlan_tag, | ||
447 | cqe); | ||
448 | else | ||
449 | lro_receive_skb(&pr->lro_mgr, skb, cqe); | ||
450 | } else { | ||
451 | if (vlan_extracted) | ||
452 | vlan_hwaccel_receive_skb(skb, pr->port->vgrp, | ||
453 | cqe->vlan_tag); | ||
454 | else | ||
455 | netif_receive_skb(skb); | ||
456 | } | ||
457 | } | ||
458 | |||
396 | static int ehea_proc_rwqes(struct net_device *dev, | 459 | static int ehea_proc_rwqes(struct net_device *dev, |
397 | struct ehea_port_res *pr, | 460 | struct ehea_port_res *pr, |
398 | int budget) | 461 | int budget) |
@@ -462,13 +525,7 @@ static int ehea_proc_rwqes(struct net_device *dev, | |||
462 | processed_rq3++; | 525 | processed_rq3++; |
463 | } | 526 | } |
464 | 527 | ||
465 | if ((cqe->status & EHEA_CQE_VLAN_TAG_XTRACT) | 528 | ehea_proc_skb(pr, cqe, skb); |
466 | && port->vgrp) | ||
467 | vlan_hwaccel_receive_skb(skb, port->vgrp, | ||
468 | cqe->vlan_tag); | ||
469 | else | ||
470 | netif_receive_skb(skb); | ||
471 | |||
472 | dev->last_rx = jiffies; | 529 | dev->last_rx = jiffies; |
473 | } else { | 530 | } else { |
474 | pr->p_stats.poll_receive_errors++; | 531 | pr->p_stats.poll_receive_errors++; |
@@ -480,6 +537,8 @@ static int ehea_proc_rwqes(struct net_device *dev, | |||
480 | } | 537 | } |
481 | cqe = ehea_poll_rq1(qp, &wqe_index); | 538 | cqe = ehea_poll_rq1(qp, &wqe_index); |
482 | } | 539 | } |
540 | if (use_lro) | ||
541 | lro_flush_all(&pr->lro_mgr); | ||
483 | 542 | ||
484 | pr->rx_packets += processed; | 543 | pr->rx_packets += processed; |
485 | 544 | ||
@@ -1231,6 +1290,15 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr, | |||
1231 | 1290 | ||
1232 | netif_napi_add(pr->port->netdev, &pr->napi, ehea_poll, 64); | 1291 | netif_napi_add(pr->port->netdev, &pr->napi, ehea_poll, 64); |
1233 | 1292 | ||
1293 | pr->lro_mgr.max_aggr = pr->port->lro_max_aggr; | ||
1294 | pr->lro_mgr.max_desc = MAX_LRO_DESCRIPTORS; | ||
1295 | pr->lro_mgr.lro_arr = pr->lro_desc; | ||
1296 | pr->lro_mgr.get_skb_header = get_skb_hdr; | ||
1297 | pr->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID; | ||
1298 | pr->lro_mgr.dev = port->netdev; | ||
1299 | pr->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY; | ||
1300 | pr->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; | ||
1301 | |||
1234 | ret = 0; | 1302 | ret = 0; |
1235 | goto out; | 1303 | goto out; |
1236 | 1304 | ||
@@ -2682,6 +2750,8 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, | |||
2682 | goto out_dereg_bc; | 2750 | goto out_dereg_bc; |
2683 | } | 2751 | } |
2684 | 2752 | ||
2753 | port->lro_max_aggr = lro_max_aggr; | ||
2754 | |||
2685 | ret = ehea_get_jumboframe_status(port, &jumbo); | 2755 | ret = ehea_get_jumboframe_status(port, &jumbo); |
2686 | if (ret) | 2756 | if (ret) |
2687 | ehea_error("failed determining jumbo frame status for %s", | 2757 | ehea_error("failed determining jumbo frame status for %s", |