aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorFrank Blaschka <frank.blaschka@de.ibm.com>2009-11-11 19:11:44 -0500
committerDavid S. Miller <davem@davemloft.net>2009-11-16 05:42:08 -0500
commitc3b4a740db3688b245282ac957a01f3fb8d1186d (patch)
treeca05c6e683b5b2371ba265aa6db9536441f94f1a /drivers
parentaa90922479513db0d080239324d0d04701418ba5 (diff)
qeth: rework TSO functions
The maximum TSO size OSA can handle is 15 * PAGE_SIZE. This patch reduces gso_max_size to this value and adds some sanity checks and statistics to the TSO implementation. Since only layer 3 is able to do TSO move all TSO related functions to the qeth_l3 module. Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/s390/net/qeth_core.h2
-rw-r--r--drivers/s390/net/qeth_core_main.c37
-rw-r--r--drivers/s390/net/qeth_core_sys.c48
-rw-r--r--drivers/s390/net/qeth_l2_main.c1
-rw-r--r--drivers/s390/net/qeth_l3.h1
-rw-r--r--drivers/s390/net/qeth_l3_main.c71
-rw-r--r--drivers/s390/net/qeth_l3_sys.c48
7 files changed, 110 insertions, 98 deletions
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 84c5c8f30c47..b232693378cd 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -134,6 +134,7 @@ struct qeth_perf_stats {
134 unsigned int sg_frags_rx; 134 unsigned int sg_frags_rx;
135 unsigned int sg_alloc_page_rx; 135 unsigned int sg_alloc_page_rx;
136 unsigned int tx_csum; 136 unsigned int tx_csum;
137 unsigned int tx_lin;
137}; 138};
138 139
139/* Routing stuff */ 140/* Routing stuff */
@@ -835,7 +836,6 @@ void qeth_prepare_ipa_cmd(struct qeth_card *, struct qeth_cmd_buffer *, char);
835struct qeth_cmd_buffer *qeth_wait_for_buffer(struct qeth_channel *); 836struct qeth_cmd_buffer *qeth_wait_for_buffer(struct qeth_channel *);
836int qeth_mdio_read(struct net_device *, int, int); 837int qeth_mdio_read(struct net_device *, int, int);
837int qeth_snmp_command(struct qeth_card *, char __user *); 838int qeth_snmp_command(struct qeth_card *, char __user *);
838int qeth_set_large_send(struct qeth_card *, enum qeth_large_send_types);
839struct qeth_cmd_buffer *qeth_get_adapter_cmd(struct qeth_card *, __u32, __u32); 839struct qeth_cmd_buffer *qeth_get_adapter_cmd(struct qeth_card *, __u32, __u32);
840int qeth_default_setadapterparms_cb(struct qeth_card *, struct qeth_reply *, 840int qeth_default_setadapterparms_cb(struct qeth_card *, struct qeth_reply *,
841 unsigned long); 841 unsigned long);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 819a3b5a647d..d34804d5ece1 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -270,41 +270,6 @@ int qeth_realloc_buffer_pool(struct qeth_card *card, int bufcnt)
270 return qeth_alloc_buffer_pool(card); 270 return qeth_alloc_buffer_pool(card);
271} 271}
272 272
273int qeth_set_large_send(struct qeth_card *card,
274 enum qeth_large_send_types type)
275{
276 int rc = 0;
277
278 if (card->dev == NULL) {
279 card->options.large_send = type;
280 return 0;
281 }
282 if (card->state == CARD_STATE_UP)
283 netif_tx_disable(card->dev);
284 card->options.large_send = type;
285 switch (card->options.large_send) {
286 case QETH_LARGE_SEND_TSO:
287 if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) {
288 card->dev->features |= NETIF_F_TSO | NETIF_F_SG |
289 NETIF_F_HW_CSUM;
290 } else {
291 card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG |
292 NETIF_F_HW_CSUM);
293 card->options.large_send = QETH_LARGE_SEND_NO;
294 rc = -EOPNOTSUPP;
295 }
296 break;
297 default: /* includes QETH_LARGE_SEND_NO */
298 card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG |
299 NETIF_F_HW_CSUM);
300 break;
301 }
302 if (card->state == CARD_STATE_UP)
303 netif_wake_queue(card->dev);
304 return rc;
305}
306EXPORT_SYMBOL_GPL(qeth_set_large_send);
307
308static int qeth_issue_next_read(struct qeth_card *card) 273static int qeth_issue_next_read(struct qeth_card *card)
309{ 274{
310 int rc; 275 int rc;
@@ -4460,6 +4425,7 @@ static struct {
4460 {"tx do_QDIO time"}, 4425 {"tx do_QDIO time"},
4461 {"tx do_QDIO count"}, 4426 {"tx do_QDIO count"},
4462 {"tx csum"}, 4427 {"tx csum"},
4428 {"tx lin"},
4463}; 4429};
4464 4430
4465int qeth_core_get_sset_count(struct net_device *dev, int stringset) 4431int qeth_core_get_sset_count(struct net_device *dev, int stringset)
@@ -4517,6 +4483,7 @@ void qeth_core_get_ethtool_stats(struct net_device *dev,
4517 data[31] = card->perf_stats.outbound_do_qdio_time; 4483 data[31] = card->perf_stats.outbound_do_qdio_time;
4518 data[32] = card->perf_stats.outbound_do_qdio_cnt; 4484 data[32] = card->perf_stats.outbound_do_qdio_cnt;
4519 data[33] = card->perf_stats.tx_csum; 4485 data[33] = card->perf_stats.tx_csum;
4486 data[34] = card->perf_stats.tx_lin;
4520} 4487}
4521EXPORT_SYMBOL_GPL(qeth_core_get_ethtool_stats); 4488EXPORT_SYMBOL_GPL(qeth_core_get_ethtool_stats);
4522 4489
diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c
index f2358a75ed0c..9ff2b36fdc43 100644
--- a/drivers/s390/net/qeth_core_sys.c
+++ b/drivers/s390/net/qeth_core_sys.c
@@ -416,53 +416,6 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
416static DEVICE_ATTR(layer2, 0644, qeth_dev_layer2_show, 416static DEVICE_ATTR(layer2, 0644, qeth_dev_layer2_show,
417 qeth_dev_layer2_store); 417 qeth_dev_layer2_store);
418 418
419static ssize_t qeth_dev_large_send_show(struct device *dev,
420 struct device_attribute *attr, char *buf)
421{
422 struct qeth_card *card = dev_get_drvdata(dev);
423
424 if (!card)
425 return -EINVAL;
426
427 switch (card->options.large_send) {
428 case QETH_LARGE_SEND_NO:
429 return sprintf(buf, "%s\n", "no");
430 case QETH_LARGE_SEND_TSO:
431 return sprintf(buf, "%s\n", "TSO");
432 default:
433 return sprintf(buf, "%s\n", "N/A");
434 }
435}
436
437static ssize_t qeth_dev_large_send_store(struct device *dev,
438 struct device_attribute *attr, const char *buf, size_t count)
439{
440 struct qeth_card *card = dev_get_drvdata(dev);
441 enum qeth_large_send_types type;
442 int rc = 0;
443 char *tmp;
444
445 if (!card)
446 return -EINVAL;
447 tmp = strsep((char **) &buf, "\n");
448 if (!strcmp(tmp, "no")) {
449 type = QETH_LARGE_SEND_NO;
450 } else if (!strcmp(tmp, "TSO")) {
451 type = QETH_LARGE_SEND_TSO;
452 } else {
453 return -EINVAL;
454 }
455 if (card->options.large_send == type)
456 return count;
457 rc = qeth_set_large_send(card, type);
458 if (rc)
459 return rc;
460 return count;
461}
462
463static DEVICE_ATTR(large_send, 0644, qeth_dev_large_send_show,
464 qeth_dev_large_send_store);
465
466#define ATTR_QETH_ISOLATION_NONE ("none") 419#define ATTR_QETH_ISOLATION_NONE ("none")
467#define ATTR_QETH_ISOLATION_FWD ("forward") 420#define ATTR_QETH_ISOLATION_FWD ("forward")
468#define ATTR_QETH_ISOLATION_DROP ("drop") 421#define ATTR_QETH_ISOLATION_DROP ("drop")
@@ -658,7 +611,6 @@ static struct attribute *qeth_device_attrs[] = {
658 &dev_attr_recover.attr, 611 &dev_attr_recover.attr,
659 &dev_attr_performance_stats.attr, 612 &dev_attr_performance_stats.attr,
660 &dev_attr_layer2.attr, 613 &dev_attr_layer2.attr,
661 &dev_attr_large_send.attr,
662 &dev_attr_isolation.attr, 614 &dev_attr_isolation.attr,
663 NULL, 615 NULL,
664}; 616};
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 372f2c0cd547..0b763396d5d1 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -978,7 +978,6 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
978 if (card->info.type != QETH_CARD_TYPE_OSN) { 978 if (card->info.type != QETH_CARD_TYPE_OSN) {
979 /* configure isolation level */ 979 /* configure isolation level */
980 qeth_set_access_ctrl_online(card); 980 qeth_set_access_ctrl_online(card);
981 qeth_set_large_send(card, card->options.large_send);
982 qeth_l2_process_vlans(card, 0); 981 qeth_l2_process_vlans(card, 0);
983 } 982 }
984 983
diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h
index 9f143c83bba3..ffa6fe4da26a 100644
--- a/drivers/s390/net/qeth_l3.h
+++ b/drivers/s390/net/qeth_l3.h
@@ -60,5 +60,6 @@ void qeth_l3_del_vipa(struct qeth_card *, enum qeth_prot_versions, const u8 *);
60int qeth_l3_add_rxip(struct qeth_card *, enum qeth_prot_versions, const u8 *); 60int qeth_l3_add_rxip(struct qeth_card *, enum qeth_prot_versions, const u8 *);
61void qeth_l3_del_rxip(struct qeth_card *card, enum qeth_prot_versions, 61void qeth_l3_del_rxip(struct qeth_card *card, enum qeth_prot_versions,
62 const u8 *); 62 const u8 *);
63int qeth_l3_set_large_send(struct qeth_card *, enum qeth_large_send_types);
63 64
64#endif /* __QETH_L3_H__ */ 65#endif /* __QETH_L3_H__ */
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 03f67bb51e99..2048b4354216 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -41,6 +41,32 @@ static int qeth_l3_deregister_addr_entry(struct qeth_card *,
41static int __qeth_l3_set_online(struct ccwgroup_device *, int); 41static int __qeth_l3_set_online(struct ccwgroup_device *, int);
42static int __qeth_l3_set_offline(struct ccwgroup_device *, int); 42static int __qeth_l3_set_offline(struct ccwgroup_device *, int);
43 43
44int qeth_l3_set_large_send(struct qeth_card *card,
45 enum qeth_large_send_types type)
46{
47 int rc = 0;
48
49 card->options.large_send = type;
50 if (card->dev == NULL)
51 return 0;
52
53 if (card->options.large_send == QETH_LARGE_SEND_TSO) {
54 if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) {
55 card->dev->features |= NETIF_F_TSO | NETIF_F_SG |
56 NETIF_F_HW_CSUM;
57 } else {
58 card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG |
59 NETIF_F_HW_CSUM);
60 card->options.large_send = QETH_LARGE_SEND_NO;
61 rc = -EOPNOTSUPP;
62 }
63 } else {
64 card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG |
65 NETIF_F_HW_CSUM);
66 card->options.large_send = QETH_LARGE_SEND_NO;
67 }
68 return rc;
69}
44 70
45static int qeth_l3_isxdigit(char *buf) 71static int qeth_l3_isxdigit(char *buf)
46{ 72{
@@ -2686,6 +2712,24 @@ static void qeth_tx_csum(struct sk_buff *skb)
2686 *(__sum16 *)(skb->data + offset) = csum_fold(csum); 2712 *(__sum16 *)(skb->data + offset) = csum_fold(csum);
2687} 2713}
2688 2714
2715static inline int qeth_l3_tso_elements(struct sk_buff *skb)
2716{
2717 unsigned long tcpd = (unsigned long)tcp_hdr(skb) +
2718 tcp_hdr(skb)->doff * 4;
2719 int tcpd_len = skb->len - (tcpd - (unsigned long)skb->data);
2720 int elements = PFN_UP(tcpd + tcpd_len) - PFN_DOWN(tcpd);
2721 elements += skb_shinfo(skb)->nr_frags;
2722 return elements;
2723}
2724
2725static inline int qeth_l3_tso_check(struct sk_buff *skb)
2726{
2727 int len = ((unsigned long)tcp_hdr(skb) + tcp_hdr(skb)->doff * 4) -
2728 (unsigned long)skb->data;
2729 return (((unsigned long)skb->data & PAGE_MASK) !=
2730 (((unsigned long)skb->data + len) & PAGE_MASK));
2731}
2732
2689static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) 2733static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
2690{ 2734{
2691 int rc; 2735 int rc;
@@ -2779,16 +2823,21 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
2779 /* fix hardware limitation: as long as we do not have sbal 2823 /* fix hardware limitation: as long as we do not have sbal
2780 * chaining we can not send long frag lists 2824 * chaining we can not send long frag lists
2781 */ 2825 */
2782 if ((large_send == QETH_LARGE_SEND_TSO) && 2826 if (large_send == QETH_LARGE_SEND_TSO) {
2783 ((skb_shinfo(new_skb)->nr_frags + 2) > 16)) { 2827 if (qeth_l3_tso_elements(new_skb) + 1 > 16) {
2784 if (skb_linearize(new_skb)) 2828 if (skb_linearize(new_skb))
2785 goto tx_drop; 2829 goto tx_drop;
2830 if (card->options.performance_stats)
2831 card->perf_stats.tx_lin++;
2832 }
2786 } 2833 }
2787 2834
2788 if ((large_send == QETH_LARGE_SEND_TSO) && 2835 if ((large_send == QETH_LARGE_SEND_TSO) &&
2789 (cast_type == RTN_UNSPEC)) { 2836 (cast_type == RTN_UNSPEC)) {
2790 hdr = (struct qeth_hdr *)skb_push(new_skb, 2837 hdr = (struct qeth_hdr *)skb_push(new_skb,
2791 sizeof(struct qeth_hdr_tso)); 2838 sizeof(struct qeth_hdr_tso));
2839 if (qeth_l3_tso_check(new_skb))
2840 QETH_DBF_MESSAGE(2, "tso skb misaligned\n");
2792 memset(hdr, 0, sizeof(struct qeth_hdr_tso)); 2841 memset(hdr, 0, sizeof(struct qeth_hdr_tso));
2793 qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type); 2842 qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type);
2794 qeth_tso_fill_header(card, hdr, new_skb); 2843 qeth_tso_fill_header(card, hdr, new_skb);
@@ -2931,20 +2980,15 @@ static int qeth_l3_ethtool_set_rx_csum(struct net_device *dev, u32 data)
2931static int qeth_l3_ethtool_set_tso(struct net_device *dev, u32 data) 2980static int qeth_l3_ethtool_set_tso(struct net_device *dev, u32 data)
2932{ 2981{
2933 struct qeth_card *card = dev->ml_priv; 2982 struct qeth_card *card = dev->ml_priv;
2983 int rc = 0;
2934 2984
2935 if (data) { 2985 if (data) {
2936 if (card->options.large_send == QETH_LARGE_SEND_NO) { 2986 rc = qeth_l3_set_large_send(card, QETH_LARGE_SEND_TSO);
2937 if (card->info.type == QETH_CARD_TYPE_IQD)
2938 return -EPERM;
2939 else
2940 card->options.large_send = QETH_LARGE_SEND_TSO;
2941 dev->features |= NETIF_F_TSO;
2942 }
2943 } else { 2987 } else {
2944 dev->features &= ~NETIF_F_TSO; 2988 dev->features &= ~NETIF_F_TSO;
2945 card->options.large_send = QETH_LARGE_SEND_NO; 2989 card->options.large_send = QETH_LARGE_SEND_NO;
2946 } 2990 }
2947 return 0; 2991 return rc;
2948} 2992}
2949 2993
2950static const struct ethtool_ops qeth_l3_ethtool_ops = { 2994static const struct ethtool_ops qeth_l3_ethtool_ops = {
@@ -3060,6 +3104,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
3060 NETIF_F_HW_VLAN_RX | 3104 NETIF_F_HW_VLAN_RX |
3061 NETIF_F_HW_VLAN_FILTER; 3105 NETIF_F_HW_VLAN_FILTER;
3062 card->dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; 3106 card->dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
3107 card->dev->gso_max_size = 15 * PAGE_SIZE;
3063 3108
3064 SET_NETDEV_DEV(card->dev, &card->gdev->dev); 3109 SET_NETDEV_DEV(card->dev, &card->gdev->dev);
3065 return register_netdev(card->dev); 3110 return register_netdev(card->dev);
@@ -3189,7 +3234,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
3189 goto out_remove; 3234 goto out_remove;
3190 } else 3235 } else
3191 card->lan_online = 1; 3236 card->lan_online = 1;
3192 qeth_set_large_send(card, card->options.large_send); 3237 qeth_l3_set_large_send(card, card->options.large_send);
3193 3238
3194 rc = qeth_l3_setadapter_parms(card); 3239 rc = qeth_l3_setadapter_parms(card);
3195 if (rc) 3240 if (rc)
diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c
index c144b9924d52..88f200c8ea3c 100644
--- a/drivers/s390/net/qeth_l3_sys.c
+++ b/drivers/s390/net/qeth_l3_sys.c
@@ -318,6 +318,53 @@ static ssize_t qeth_l3_dev_checksum_store(struct device *dev,
318static DEVICE_ATTR(checksumming, 0644, qeth_l3_dev_checksum_show, 318static DEVICE_ATTR(checksumming, 0644, qeth_l3_dev_checksum_show,
319 qeth_l3_dev_checksum_store); 319 qeth_l3_dev_checksum_store);
320 320
321static ssize_t qeth_l3_dev_large_send_show(struct device *dev,
322 struct device_attribute *attr, char *buf)
323{
324 struct qeth_card *card = dev_get_drvdata(dev);
325
326 if (!card)
327 return -EINVAL;
328
329 switch (card->options.large_send) {
330 case QETH_LARGE_SEND_NO:
331 return sprintf(buf, "%s\n", "no");
332 case QETH_LARGE_SEND_TSO:
333 return sprintf(buf, "%s\n", "TSO");
334 default:
335 return sprintf(buf, "%s\n", "N/A");
336 }
337}
338
339static ssize_t qeth_l3_dev_large_send_store(struct device *dev,
340 struct device_attribute *attr, const char *buf, size_t count)
341{
342 struct qeth_card *card = dev_get_drvdata(dev);
343 enum qeth_large_send_types type;
344 int rc = 0;
345 char *tmp;
346
347 if (!card)
348 return -EINVAL;
349 tmp = strsep((char **) &buf, "\n");
350 if (!strcmp(tmp, "no"))
351 type = QETH_LARGE_SEND_NO;
352 else if (!strcmp(tmp, "TSO"))
353 type = QETH_LARGE_SEND_TSO;
354 else
355 return -EINVAL;
356
357 if (card->options.large_send == type)
358 return count;
359 rc = qeth_l3_set_large_send(card, type);
360 if (rc)
361 return rc;
362 return count;
363}
364
365static DEVICE_ATTR(large_send, 0644, qeth_l3_dev_large_send_show,
366 qeth_l3_dev_large_send_store);
367
321static struct attribute *qeth_l3_device_attrs[] = { 368static struct attribute *qeth_l3_device_attrs[] = {
322 &dev_attr_route4.attr, 369 &dev_attr_route4.attr,
323 &dev_attr_route6.attr, 370 &dev_attr_route6.attr,
@@ -325,6 +372,7 @@ static struct attribute *qeth_l3_device_attrs[] = {
325 &dev_attr_broadcast_mode.attr, 372 &dev_attr_broadcast_mode.attr,
326 &dev_attr_canonical_macaddr.attr, 373 &dev_attr_canonical_macaddr.attr,
327 &dev_attr_checksumming.attr, 374 &dev_attr_checksumming.attr,
375 &dev_attr_large_send.attr,
328 NULL, 376 NULL,
329}; 377};
330 378