aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/s390/net/Makefile2
-rw-r--r--drivers/s390/net/qeth.h41
-rw-r--r--drivers/s390/net/qeth_eddp.c40
-rw-r--r--drivers/s390/net/qeth_main.c145
-rw-r--r--drivers/s390/net/qeth_tso.c256
-rw-r--r--drivers/s390/net/qeth_tso.h193
6 files changed, 273 insertions, 404 deletions
diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile
index 85b590c5701d..90d4d0ef3dd4 100644
--- a/drivers/s390/net/Makefile
+++ b/drivers/s390/net/Makefile
@@ -10,6 +10,6 @@ obj-$(CONFIG_SMSGIUCV) += smsgiucv.o
10obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o 10obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o
11obj-$(CONFIG_LCS) += lcs.o cu3088.o 11obj-$(CONFIG_LCS) += lcs.o cu3088.o
12obj-$(CONFIG_CLAW) += claw.o cu3088.o 12obj-$(CONFIG_CLAW) += claw.o cu3088.o
13qeth-y := qeth_main.o qeth_mpc.o qeth_sys.o qeth_eddp.o qeth_tso.o 13qeth-y := qeth_main.o qeth_mpc.o qeth_sys.o qeth_eddp.o
14qeth-$(CONFIG_PROC_FS) += qeth_proc.o 14qeth-$(CONFIG_PROC_FS) += qeth_proc.o
15obj-$(CONFIG_QETH) += qeth.o 15obj-$(CONFIG_QETH) += qeth.o
diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h
index d13c105f74e6..a755b57db46b 100644
--- a/drivers/s390/net/qeth.h
+++ b/drivers/s390/net/qeth.h
@@ -24,7 +24,7 @@
24 24
25#include "qeth_mpc.h" 25#include "qeth_mpc.h"
26 26
27#define VERSION_QETH_H "$Revision: 1.137 $" 27#define VERSION_QETH_H "$Revision: 1.139 $"
28 28
29#ifdef CONFIG_QETH_IPV6 29#ifdef CONFIG_QETH_IPV6
30#define QETH_VERSION_IPV6 ":IPv6" 30#define QETH_VERSION_IPV6 ":IPv6"
@@ -370,6 +370,25 @@ struct qeth_hdr {
370 } hdr; 370 } hdr;
371} __attribute__ ((packed)); 371} __attribute__ ((packed));
372 372
373/*TCP Segmentation Offload header*/
374struct qeth_hdr_ext_tso {
375 __u16 hdr_tot_len;
376 __u8 imb_hdr_no;
377 __u8 reserved;
378 __u8 hdr_type;
379 __u8 hdr_version;
380 __u16 hdr_len;
381 __u32 payload_len;
382 __u16 mss;
383 __u16 dg_hdr_len;
384 __u8 padding[16];
385} __attribute__ ((packed));
386
387struct qeth_hdr_tso {
388 struct qeth_hdr hdr; /*hdr->hdr.l3.xxx*/
389 struct qeth_hdr_ext_tso ext;
390} __attribute__ ((packed));
391
373 392
374/* flags for qeth_hdr.flags */ 393/* flags for qeth_hdr.flags */
375#define QETH_HDR_PASSTHRU 0x10 394#define QETH_HDR_PASSTHRU 0x10
@@ -867,16 +886,6 @@ qeth_push_skb(struct qeth_card *card, struct sk_buff **skb, int size)
867 return hdr; 886 return hdr;
868} 887}
869 888
870static inline int
871qeth_get_skb_data_len(struct sk_buff *skb)
872{
873 int len = skb->len;
874 int i;
875
876 for (i = 0; i < skb_shinfo(skb)->nr_frags; ++i)
877 len -= skb_shinfo(skb)->frags[i].size;
878 return len;
879}
880 889
881inline static int 890inline static int
882qeth_get_hlen(__u8 link_type) 891qeth_get_hlen(__u8 link_type)
@@ -885,19 +894,19 @@ qeth_get_hlen(__u8 link_type)
885 switch (link_type) { 894 switch (link_type) {
886 case QETH_LINK_TYPE_HSTR: 895 case QETH_LINK_TYPE_HSTR:
887 case QETH_LINK_TYPE_LANE_TR: 896 case QETH_LINK_TYPE_LANE_TR:
888 return sizeof(struct qeth_hdr) + TR_HLEN; 897 return sizeof(struct qeth_hdr_tso) + TR_HLEN;
889 default: 898 default:
890#ifdef CONFIG_QETH_VLAN 899#ifdef CONFIG_QETH_VLAN
891 return sizeof(struct qeth_hdr) + VLAN_ETH_HLEN; 900 return sizeof(struct qeth_hdr_tso) + VLAN_ETH_HLEN;
892#else 901#else
893 return sizeof(struct qeth_hdr) + ETH_HLEN; 902 return sizeof(struct qeth_hdr_tso) + ETH_HLEN;
894#endif 903#endif
895 } 904 }
896#else /* CONFIG_QETH_IPV6 */ 905#else /* CONFIG_QETH_IPV6 */
897#ifdef CONFIG_QETH_VLAN 906#ifdef CONFIG_QETH_VLAN
898 return sizeof(struct qeth_hdr) + VLAN_HLEN; 907 return sizeof(struct qeth_hdr_tso) + VLAN_HLEN;
899#else 908#else
900 return sizeof(struct qeth_hdr); 909 return sizeof(struct qeth_hdr_tso);
901#endif 910#endif
902#endif /* CONFIG_QETH_IPV6 */ 911#endif /* CONFIG_QETH_IPV6 */
903} 912}
diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c
index 45aa4a962daf..f94f1f25eec6 100644
--- a/drivers/s390/net/qeth_eddp.c
+++ b/drivers/s390/net/qeth_eddp.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * 2 *
3 * linux/drivers/s390/net/qeth_eddp.c ($Revision: 1.12 $) 3 * linux/drivers/s390/net/qeth_eddp.c ($Revision: 1.13 $)
4 * 4 *
5 * Enhanced Device Driver Packing (EDDP) support for the qeth driver. 5 * Enhanced Device Driver Packing (EDDP) support for the qeth driver.
6 * 6 *
@@ -8,7 +8,7 @@
8 * 8 *
9 * Author(s): Thomas Spatzier <tspat@de.ibm.com> 9 * Author(s): Thomas Spatzier <tspat@de.ibm.com>
10 * 10 *
11 * $Revision: 1.12 $ $Date: 2005/04/01 21:40:40 $ 11 * $Revision: 1.13 $ $Date: 2005/05/04 20:19:18 $
12 * 12 *
13 */ 13 */
14#include <linux/config.h> 14#include <linux/config.h>
@@ -85,7 +85,7 @@ void
85qeth_eddp_buf_release_contexts(struct qeth_qdio_out_buffer *buf) 85qeth_eddp_buf_release_contexts(struct qeth_qdio_out_buffer *buf)
86{ 86{
87 struct qeth_eddp_context_reference *ref; 87 struct qeth_eddp_context_reference *ref;
88 88
89 QETH_DBF_TEXT(trace, 6, "eddprctx"); 89 QETH_DBF_TEXT(trace, 6, "eddprctx");
90 while (!list_empty(&buf->ctx_list)){ 90 while (!list_empty(&buf->ctx_list)){
91 ref = list_entry(buf->ctx_list.next, 91 ref = list_entry(buf->ctx_list.next,
@@ -139,7 +139,7 @@ qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue,
139 "buffer!\n"); 139 "buffer!\n");
140 goto out; 140 goto out;
141 } 141 }
142 } 142 }
143 /* check if the whole next skb fits into current buffer */ 143 /* check if the whole next skb fits into current buffer */
144 if ((QETH_MAX_BUFFER_ELEMENTS(queue->card) - 144 if ((QETH_MAX_BUFFER_ELEMENTS(queue->card) -
145 buf->next_element_to_fill) 145 buf->next_element_to_fill)
@@ -152,7 +152,7 @@ qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue,
152 * and increment ctx's refcnt */ 152 * and increment ctx's refcnt */
153 must_refcnt = 1; 153 must_refcnt = 1;
154 continue; 154 continue;
155 } 155 }
156 if (must_refcnt){ 156 if (must_refcnt){
157 must_refcnt = 0; 157 must_refcnt = 0;
158 if (qeth_eddp_buf_ref_context(buf, ctx)){ 158 if (qeth_eddp_buf_ref_context(buf, ctx)){
@@ -204,27 +204,27 @@ out:
204 204
205static inline void 205static inline void
206qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx, 206qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx,
207 struct qeth_eddp_data *eddp) 207 struct qeth_eddp_data *eddp, int data_len)
208{ 208{
209 u8 *page; 209 u8 *page;
210 int page_remainder; 210 int page_remainder;
211 int page_offset; 211 int page_offset;
212 int hdr_len; 212 int pkt_len;
213 struct qeth_eddp_element *element; 213 struct qeth_eddp_element *element;
214 214
215 QETH_DBF_TEXT(trace, 5, "eddpcrsh"); 215 QETH_DBF_TEXT(trace, 5, "eddpcrsh");
216 page = ctx->pages[ctx->offset >> PAGE_SHIFT]; 216 page = ctx->pages[ctx->offset >> PAGE_SHIFT];
217 page_offset = ctx->offset % PAGE_SIZE; 217 page_offset = ctx->offset % PAGE_SIZE;
218 element = &ctx->elements[ctx->num_elements]; 218 element = &ctx->elements[ctx->num_elements];
219 hdr_len = eddp->nhl + eddp->thl; 219 pkt_len = eddp->nhl + eddp->thl + data_len;
220 /* FIXME: layer2 and VLAN !!! */ 220 /* FIXME: layer2 and VLAN !!! */
221 if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2) 221 if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2)
222 hdr_len += ETH_HLEN; 222 pkt_len += ETH_HLEN;
223 if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q)) 223 if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q))
224 hdr_len += VLAN_HLEN; 224 pkt_len += VLAN_HLEN;
225 /* does complete header fit in current page ? */ 225 /* does complete packet fit in current page ? */
226 page_remainder = PAGE_SIZE - page_offset; 226 page_remainder = PAGE_SIZE - page_offset;
227 if (page_remainder < (sizeof(struct qeth_hdr) + hdr_len)){ 227 if (page_remainder < (sizeof(struct qeth_hdr) + pkt_len)){
228 /* no -> go to start of next page */ 228 /* no -> go to start of next page */
229 ctx->offset += page_remainder; 229 ctx->offset += page_remainder;
230 page = ctx->pages[ctx->offset >> PAGE_SHIFT]; 230 page = ctx->pages[ctx->offset >> PAGE_SHIFT];
@@ -270,7 +270,7 @@ qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
270 int left_in_frag; 270 int left_in_frag;
271 int copy_len; 271 int copy_len;
272 u8 *src; 272 u8 *src;
273 273
274 QETH_DBF_TEXT(trace, 5, "eddpcdtc"); 274 QETH_DBF_TEXT(trace, 5, "eddpcdtc");
275 if (skb_shinfo(eddp->skb)->nr_frags == 0) { 275 if (skb_shinfo(eddp->skb)->nr_frags == 0) {
276 memcpy(dst, eddp->skb->data + eddp->skb_offset, len); 276 memcpy(dst, eddp->skb->data + eddp->skb_offset, len);
@@ -281,7 +281,7 @@ qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
281 while (len > 0) { 281 while (len > 0) {
282 if (eddp->frag < 0) { 282 if (eddp->frag < 0) {
283 /* we're in skb->data */ 283 /* we're in skb->data */
284 left_in_frag = qeth_get_skb_data_len(eddp->skb) 284 left_in_frag = (eddp->skb->len - eddp->skb->data_len)
285 - eddp->skb_offset; 285 - eddp->skb_offset;
286 src = eddp->skb->data + eddp->skb_offset; 286 src = eddp->skb->data + eddp->skb_offset;
287 } else { 287 } else {
@@ -413,7 +413,7 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
413 struct tcphdr *tcph; 413 struct tcphdr *tcph;
414 int data_len; 414 int data_len;
415 u32 hcsum; 415 u32 hcsum;
416 416
417 QETH_DBF_TEXT(trace, 5, "eddpftcp"); 417 QETH_DBF_TEXT(trace, 5, "eddpftcp");
418 eddp->skb_offset = sizeof(struct qeth_hdr) + eddp->nhl + eddp->thl; 418 eddp->skb_offset = sizeof(struct qeth_hdr) + eddp->nhl + eddp->thl;
419 tcph = eddp->skb->h.th; 419 tcph = eddp->skb->h.th;
@@ -453,7 +453,7 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
453 else 453 else
454 hcsum = qeth_eddp_check_tcp6_hdr(eddp, data_len); 454 hcsum = qeth_eddp_check_tcp6_hdr(eddp, data_len);
455 /* fill the next segment into the context */ 455 /* fill the next segment into the context */
456 qeth_eddp_create_segment_hdrs(ctx, eddp); 456 qeth_eddp_create_segment_hdrs(ctx, eddp, data_len);
457 qeth_eddp_create_segment_data_tcp(ctx, eddp, data_len, hcsum); 457 qeth_eddp_create_segment_data_tcp(ctx, eddp, data_len, hcsum);
458 if (eddp->skb_offset >= eddp->skb->len) 458 if (eddp->skb_offset >= eddp->skb->len)
459 break; 459 break;
@@ -463,13 +463,13 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
463 eddp->th.tcp.h.seq += data_len; 463 eddp->th.tcp.h.seq += data_len;
464 } 464 }
465} 465}
466 466
467static inline int 467static inline int
468qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx, 468qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
469 struct sk_buff *skb, struct qeth_hdr *qhdr) 469 struct sk_buff *skb, struct qeth_hdr *qhdr)
470{ 470{
471 struct qeth_eddp_data *eddp = NULL; 471 struct qeth_eddp_data *eddp = NULL;
472 472
473 QETH_DBF_TEXT(trace, 5, "eddpficx"); 473 QETH_DBF_TEXT(trace, 5, "eddpficx");
474 /* create our segmentation headers and copy original headers */ 474 /* create our segmentation headers and copy original headers */
475 if (skb->protocol == ETH_P_IP) 475 if (skb->protocol == ETH_P_IP)
@@ -509,7 +509,7 @@ qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb,
509 int hdr_len) 509 int hdr_len)
510{ 510{
511 int skbs_per_page; 511 int skbs_per_page;
512 512
513 QETH_DBF_TEXT(trace, 5, "eddpcanp"); 513 QETH_DBF_TEXT(trace, 5, "eddpcanp");
514 /* can we put multiple skbs in one page? */ 514 /* can we put multiple skbs in one page? */
515 skbs_per_page = PAGE_SIZE / (skb_shinfo(skb)->tso_size + hdr_len); 515 skbs_per_page = PAGE_SIZE / (skb_shinfo(skb)->tso_size + hdr_len);
@@ -589,7 +589,7 @@ qeth_eddp_create_context_tcp(struct qeth_card *card, struct sk_buff *skb,
589 struct qeth_hdr *qhdr) 589 struct qeth_hdr *qhdr)
590{ 590{
591 struct qeth_eddp_context *ctx = NULL; 591 struct qeth_eddp_context *ctx = NULL;
592 592
593 QETH_DBF_TEXT(trace, 5, "creddpct"); 593 QETH_DBF_TEXT(trace, 5, "creddpct");
594 if (skb->protocol == ETH_P_IP) 594 if (skb->protocol == ETH_P_IP)
595 ctx = qeth_eddp_create_context_generic(card, skb, 595 ctx = qeth_eddp_create_context_generic(card, skb,
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index e18bcf9fb588..208127a5033a 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * 2 *
3 * linux/drivers/s390/net/qeth_main.c ($Revision: 1.210 $) 3 * linux/drivers/s390/net/qeth_main.c ($Revision: 1.214 $)
4 * 4 *
5 * Linux on zSeries OSA Express and HiperSockets support 5 * Linux on zSeries OSA Express and HiperSockets support
6 * 6 *
@@ -12,7 +12,7 @@
12 * Frank Pavlic (pavlic@de.ibm.com) and 12 * Frank Pavlic (pavlic@de.ibm.com) and
13 * Thomas Spatzier <tspat@de.ibm.com> 13 * Thomas Spatzier <tspat@de.ibm.com>
14 * 14 *
15 * $Revision: 1.210 $ $Date: 2005/04/18 17:27:39 $ 15 * $Revision: 1.214 $ $Date: 2005/05/04 20:19:18 $
16 * 16 *
17 * This program is free software; you can redistribute it and/or modify 17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by 18 * it under the terms of the GNU General Public License as published by
@@ -80,7 +80,7 @@ qeth_eyecatcher(void)
80#include "qeth_eddp.h" 80#include "qeth_eddp.h"
81#include "qeth_tso.h" 81#include "qeth_tso.h"
82 82
83#define VERSION_QETH_C "$Revision: 1.210 $" 83#define VERSION_QETH_C "$Revision: 1.214 $"
84static const char *version = "qeth S/390 OSA-Express driver"; 84static const char *version = "qeth S/390 OSA-Express driver";
85 85
86/** 86/**
@@ -158,6 +158,9 @@ qeth_irq_tasklet(unsigned long);
158static int 158static int
159qeth_set_online(struct ccwgroup_device *); 159qeth_set_online(struct ccwgroup_device *);
160 160
161static int
162__qeth_set_online(struct ccwgroup_device *gdev, int recovery_mode);
163
161static struct qeth_ipaddr * 164static struct qeth_ipaddr *
162qeth_get_addr_buffer(enum qeth_prot_versions); 165qeth_get_addr_buffer(enum qeth_prot_versions);
163 166
@@ -510,10 +513,10 @@ qeth_irq_tasklet(unsigned long data)
510 wake_up(&card->wait_q); 513 wake_up(&card->wait_q);
511} 514}
512 515
513static int qeth_stop_card(struct qeth_card *); 516static int qeth_stop_card(struct qeth_card *, int);
514 517
515static int 518static int
516qeth_set_offline(struct ccwgroup_device *cgdev) 519__qeth_set_offline(struct ccwgroup_device *cgdev, int recovery_mode)
517{ 520{
518 struct qeth_card *card = (struct qeth_card *) cgdev->dev.driver_data; 521 struct qeth_card *card = (struct qeth_card *) cgdev->dev.driver_data;
519 int rc = 0; 522 int rc = 0;
@@ -523,7 +526,7 @@ qeth_set_offline(struct ccwgroup_device *cgdev)
523 QETH_DBF_HEX(setup, 3, &card, sizeof(void *)); 526 QETH_DBF_HEX(setup, 3, &card, sizeof(void *));
524 527
525 recover_flag = card->state; 528 recover_flag = card->state;
526 if (qeth_stop_card(card) == -ERESTARTSYS){ 529 if (qeth_stop_card(card, recovery_mode) == -ERESTARTSYS){
527 PRINT_WARN("Stopping card %s interrupted by user!\n", 530 PRINT_WARN("Stopping card %s interrupted by user!\n",
528 CARD_BUS_ID(card)); 531 CARD_BUS_ID(card));
529 return -ERESTARTSYS; 532 return -ERESTARTSYS;
@@ -540,6 +543,12 @@ qeth_set_offline(struct ccwgroup_device *cgdev)
540} 543}
541 544
542static int 545static int
546qeth_set_offline(struct ccwgroup_device *cgdev)
547{
548 return __qeth_set_offline(cgdev, 0);
549}
550
551static int
543qeth_wait_for_threads(struct qeth_card *card, unsigned long threads); 552qeth_wait_for_threads(struct qeth_card *card, unsigned long threads);
544 553
545 554
@@ -953,8 +962,8 @@ qeth_recover(void *ptr)
953 PRINT_WARN("Recovery of device %s started ...\n", 962 PRINT_WARN("Recovery of device %s started ...\n",
954 CARD_BUS_ID(card)); 963 CARD_BUS_ID(card));
955 card->use_hard_stop = 1; 964 card->use_hard_stop = 1;
956 qeth_set_offline(card->gdev); 965 __qeth_set_offline(card->gdev,1);
957 rc = qeth_set_online(card->gdev); 966 rc = __qeth_set_online(card->gdev,1);
958 if (!rc) 967 if (!rc)
959 PRINT_INFO("Device %s successfully recovered!\n", 968 PRINT_INFO("Device %s successfully recovered!\n",
960 CARD_BUS_ID(card)); 969 CARD_BUS_ID(card));
@@ -3786,16 +3795,12 @@ static inline int
3786qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb, 3795qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb,
3787 struct qeth_hdr **hdr, int ipv) 3796 struct qeth_hdr **hdr, int ipv)
3788{ 3797{
3789 int rc = 0;
3790#ifdef CONFIG_QETH_VLAN 3798#ifdef CONFIG_QETH_VLAN
3791 u16 *tag; 3799 u16 *tag;
3792#endif 3800#endif
3793 3801
3794 QETH_DBF_TEXT(trace, 6, "prepskb"); 3802 QETH_DBF_TEXT(trace, 6, "prepskb");
3795 3803
3796 rc = qeth_realloc_headroom(card, skb, sizeof(struct qeth_hdr));
3797 if (rc)
3798 return rc;
3799#ifdef CONFIG_QETH_VLAN 3804#ifdef CONFIG_QETH_VLAN
3800 if (card->vlangrp && vlan_tx_tag_present(*skb) && 3805 if (card->vlangrp && vlan_tx_tag_present(*skb) &&
3801 ((ipv == 6) || card->options.layer2) ) { 3806 ((ipv == 6) || card->options.layer2) ) {
@@ -3977,25 +3982,28 @@ qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
3977 3982
3978static inline void 3983static inline void
3979__qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer, 3984__qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer,
3980 int *next_element_to_fill) 3985 int is_tso, int *next_element_to_fill)
3981{ 3986{
3982 int length = skb->len; 3987 int length = skb->len;
3983 int length_here; 3988 int length_here;
3984 int element; 3989 int element;
3985 char *data; 3990 char *data;
3986 int first_lap = 1; 3991 int first_lap ;
3987 3992
3988 element = *next_element_to_fill; 3993 element = *next_element_to_fill;
3989 data = skb->data; 3994 data = skb->data;
3995 first_lap = (is_tso == 0 ? 1 : 0);
3996
3990 while (length > 0) { 3997 while (length > 0) {
3991 /* length_here is the remaining amount of data in this page */ 3998 /* length_here is the remaining amount of data in this page */
3992 length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE); 3999 length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE);
3993 if (length < length_here) 4000 if (length < length_here)
3994 length_here = length; 4001 length_here = length;
4002
3995 buffer->element[element].addr = data; 4003 buffer->element[element].addr = data;
3996 buffer->element[element].length = length_here; 4004 buffer->element[element].length = length_here;
3997 length -= length_here; 4005 length -= length_here;
3998 if (!length){ 4006 if (!length) {
3999 if (first_lap) 4007 if (first_lap)
4000 buffer->element[element].flags = 0; 4008 buffer->element[element].flags = 0;
4001 else 4009 else
@@ -4022,17 +4030,35 @@ qeth_fill_buffer(struct qeth_qdio_out_q *queue,
4022 struct sk_buff *skb) 4030 struct sk_buff *skb)
4023{ 4031{
4024 struct qdio_buffer *buffer; 4032 struct qdio_buffer *buffer;
4025 int flush_cnt = 0; 4033 struct qeth_hdr_tso *hdr;
4034 int flush_cnt = 0, hdr_len, large_send = 0;
4026 4035
4027 QETH_DBF_TEXT(trace, 6, "qdfillbf"); 4036 QETH_DBF_TEXT(trace, 6, "qdfillbf");
4037
4028 buffer = buf->buffer; 4038 buffer = buf->buffer;
4029 atomic_inc(&skb->users); 4039 atomic_inc(&skb->users);
4030 skb_queue_tail(&buf->skb_list, skb); 4040 skb_queue_tail(&buf->skb_list, skb);
4041
4042 hdr = (struct qeth_hdr_tso *) skb->data;
4043 /*check first on TSO ....*/
4044 if (hdr->hdr.hdr.l3.id == QETH_HEADER_TYPE_TSO) {
4045 int element = buf->next_element_to_fill;
4046
4047 hdr_len = sizeof(struct qeth_hdr_tso) + hdr->ext.dg_hdr_len;
4048 /*fill first buffer entry only with header information */
4049 buffer->element[element].addr = skb->data;
4050 buffer->element[element].length = hdr_len;
4051 buffer->element[element].flags = SBAL_FLAGS_FIRST_FRAG;
4052 buf->next_element_to_fill++;
4053 skb->data += hdr_len;
4054 skb->len -= hdr_len;
4055 large_send = 1;
4056 }
4031 if (skb_shinfo(skb)->nr_frags == 0) 4057 if (skb_shinfo(skb)->nr_frags == 0)
4032 __qeth_fill_buffer(skb, buffer, 4058 __qeth_fill_buffer(skb, buffer, large_send,
4033 (int *)&buf->next_element_to_fill); 4059 (int *)&buf->next_element_to_fill);
4034 else 4060 else
4035 __qeth_fill_buffer_frag(skb, buffer, 0, 4061 __qeth_fill_buffer_frag(skb, buffer, large_send,
4036 (int *)&buf->next_element_to_fill); 4062 (int *)&buf->next_element_to_fill);
4037 4063
4038 if (!queue->do_pack) { 4064 if (!queue->do_pack) {
@@ -4225,6 +4251,25 @@ out:
4225} 4251}
4226 4252
4227static inline int 4253static inline int
4254qeth_get_elements_no(struct qeth_card *card, void *hdr, struct sk_buff *skb)
4255{
4256 int elements_needed = 0;
4257
4258 if (skb_shinfo(skb)->nr_frags > 0) {
4259 elements_needed = (skb_shinfo(skb)->nr_frags + 1);
4260 }
4261 if (elements_needed == 0 )
4262 elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE)
4263 + skb->len) >> PAGE_SHIFT);
4264 if (elements_needed > QETH_MAX_BUFFER_ELEMENTS(card)){
4265 PRINT_ERR("qeth_do_send_packet: invalid size of "
4266 "IP packet. Discarded.");
4267 return 0;
4268 }
4269 return elements_needed;
4270}
4271
4272static inline int
4228qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) 4273qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
4229{ 4274{
4230 int ipv = 0; 4275 int ipv = 0;
@@ -4266,19 +4311,25 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
4266 if (skb_shinfo(skb)->tso_size) 4311 if (skb_shinfo(skb)->tso_size)
4267 large_send = card->options.large_send; 4312 large_send = card->options.large_send;
4268 4313
4269 if ((rc = qeth_prepare_skb(card, &skb, &hdr, ipv))){
4270 QETH_DBF_TEXT_(trace, 4, "pskbe%d", rc);
4271 return rc;
4272 }
4273 /*are we able to do TSO ? If so ,prepare and send it from here */ 4314 /*are we able to do TSO ? If so ,prepare and send it from here */
4274 if ((large_send == QETH_LARGE_SEND_TSO) && 4315 if ((large_send == QETH_LARGE_SEND_TSO) &&
4275 (cast_type == RTN_UNSPEC)) { 4316 (cast_type == RTN_UNSPEC)) {
4276 rc = qeth_tso_send_packet(card, skb, queue, 4317 rc = qeth_tso_prepare_packet(card, skb, ipv, cast_type);
4277 ipv, cast_type); 4318 if (rc) {
4278 goto do_statistics; 4319 card->stats.tx_dropped++;
4320 card->stats.tx_errors++;
4321 dev_kfree_skb_any(skb);
4322 return NETDEV_TX_OK;
4323 }
4324 elements_needed++;
4325 } else {
4326 if ((rc = qeth_prepare_skb(card, &skb, &hdr, ipv))) {
4327 QETH_DBF_TEXT_(trace, 4, "pskbe%d", rc);
4328 return rc;
4329 }
4330 qeth_fill_header(card, hdr, skb, ipv, cast_type);
4279 } 4331 }
4280 4332
4281 qeth_fill_header(card, hdr, skb, ipv, cast_type);
4282 if (large_send == QETH_LARGE_SEND_EDDP) { 4333 if (large_send == QETH_LARGE_SEND_EDDP) {
4283 ctx = qeth_eddp_create_context(card, skb, hdr); 4334 ctx = qeth_eddp_create_context(card, skb, hdr);
4284 if (ctx == NULL) { 4335 if (ctx == NULL) {
@@ -4286,7 +4337,7 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
4286 return -EINVAL; 4337 return -EINVAL;
4287 } 4338 }
4288 } else { 4339 } else {
4289 elements_needed = qeth_get_elements_no(card,(void*) hdr, skb); 4340 elements_needed += qeth_get_elements_no(card,(void*) hdr, skb);
4290 if (!elements_needed) 4341 if (!elements_needed)
4291 return -EINVAL; 4342 return -EINVAL;
4292 } 4343 }
@@ -4297,12 +4348,12 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
4297 else 4348 else
4298 rc = qeth_do_send_packet_fast(card, queue, skb, hdr, 4349 rc = qeth_do_send_packet_fast(card, queue, skb, hdr,
4299 elements_needed, ctx); 4350 elements_needed, ctx);
4300do_statistics:
4301 if (!rc){ 4351 if (!rc){
4302 card->stats.tx_packets++; 4352 card->stats.tx_packets++;
4303 card->stats.tx_bytes += skb->len; 4353 card->stats.tx_bytes += skb->len;
4304#ifdef CONFIG_QETH_PERF_STATS 4354#ifdef CONFIG_QETH_PERF_STATS
4305 if (skb_shinfo(skb)->tso_size) { 4355 if (skb_shinfo(skb)->tso_size &&
4356 !(large_send == QETH_LARGE_SEND_NO)) {
4306 card->perf_stats.large_send_bytes += skb->len; 4357 card->perf_stats.large_send_bytes += skb->len;
4307 card->perf_stats.large_send_cnt++; 4358 card->perf_stats.large_send_cnt++;
4308 } 4359 }
@@ -7199,7 +7250,7 @@ qeth_wait_for_threads(struct qeth_card *card, unsigned long threads)
7199} 7250}
7200 7251
7201static int 7252static int
7202qeth_stop_card(struct qeth_card *card) 7253qeth_stop_card(struct qeth_card *card, int recovery_mode)
7203{ 7254{
7204 int rc = 0; 7255 int rc = 0;
7205 7256
@@ -7212,9 +7263,13 @@ qeth_stop_card(struct qeth_card *card)
7212 if (card->read.state == CH_STATE_UP && 7263 if (card->read.state == CH_STATE_UP &&
7213 card->write.state == CH_STATE_UP && 7264 card->write.state == CH_STATE_UP &&
7214 (card->state == CARD_STATE_UP)) { 7265 (card->state == CARD_STATE_UP)) {
7215 rtnl_lock(); 7266 if(recovery_mode) {
7216 dev_close(card->dev); 7267 qeth_stop(card->dev);
7217 rtnl_unlock(); 7268 } else {
7269 rtnl_lock();
7270 dev_close(card->dev);
7271 rtnl_unlock();
7272 }
7218 if (!card->use_hard_stop) { 7273 if (!card->use_hard_stop) {
7219 __u8 *mac = &card->dev->dev_addr[0]; 7274 __u8 *mac = &card->dev->dev_addr[0];
7220 rc = qeth_layer2_send_delmac(card, mac); 7275 rc = qeth_layer2_send_delmac(card, mac);
@@ -7386,13 +7441,17 @@ qeth_register_netdev(struct qeth_card *card)
7386} 7441}
7387 7442
7388static void 7443static void
7389qeth_start_again(struct qeth_card *card) 7444qeth_start_again(struct qeth_card *card, int recovery_mode)
7390{ 7445{
7391 QETH_DBF_TEXT(setup ,2, "startag"); 7446 QETH_DBF_TEXT(setup ,2, "startag");
7392 7447
7393 rtnl_lock(); 7448 if(recovery_mode) {
7394 dev_open(card->dev); 7449 qeth_open(card->dev);
7395 rtnl_unlock(); 7450 } else {
7451 rtnl_lock();
7452 dev_open(card->dev);
7453 rtnl_unlock();
7454 }
7396 /* this also sets saved unicast addresses */ 7455 /* this also sets saved unicast addresses */
7397 qeth_set_multicast_list(card->dev); 7456 qeth_set_multicast_list(card->dev);
7398} 7457}
@@ -7449,7 +7508,7 @@ static void qeth_make_parameters_consistent(struct qeth_card *card)
7449 7508
7450 7509
7451static int 7510static int
7452qeth_set_online(struct ccwgroup_device *gdev) 7511__qeth_set_online(struct ccwgroup_device *gdev, int recovery_mode)
7453{ 7512{
7454 struct qeth_card *card = gdev->dev.driver_data; 7513 struct qeth_card *card = gdev->dev.driver_data;
7455 int rc = 0; 7514 int rc = 0;
@@ -7509,12 +7568,12 @@ qeth_set_online(struct ccwgroup_device *gdev)
7509 * we can also use this state for recovery purposes*/ 7568 * we can also use this state for recovery purposes*/
7510 qeth_set_allowed_threads(card, 0xffffffff, 0); 7569 qeth_set_allowed_threads(card, 0xffffffff, 0);
7511 if (recover_flag == CARD_STATE_RECOVER) 7570 if (recover_flag == CARD_STATE_RECOVER)
7512 qeth_start_again(card); 7571 qeth_start_again(card, recovery_mode);
7513 qeth_notify_processes(); 7572 qeth_notify_processes();
7514 return 0; 7573 return 0;
7515out_remove: 7574out_remove:
7516 card->use_hard_stop = 1; 7575 card->use_hard_stop = 1;
7517 qeth_stop_card(card); 7576 qeth_stop_card(card, 0);
7518 ccw_device_set_offline(CARD_DDEV(card)); 7577 ccw_device_set_offline(CARD_DDEV(card));
7519 ccw_device_set_offline(CARD_WDEV(card)); 7578 ccw_device_set_offline(CARD_WDEV(card));
7520 ccw_device_set_offline(CARD_RDEV(card)); 7579 ccw_device_set_offline(CARD_RDEV(card));
@@ -7525,6 +7584,12 @@ out_remove:
7525 return -ENODEV; 7584 return -ENODEV;
7526} 7585}
7527 7586
7587static int
7588qeth_set_online(struct ccwgroup_device *gdev)
7589{
7590 return __qeth_set_online(gdev, 0);
7591}
7592
7528static struct ccw_device_id qeth_ids[] = { 7593static struct ccw_device_id qeth_ids[] = {
7529 {CCW_DEVICE(0x1731, 0x01), driver_info:QETH_CARD_TYPE_OSAE}, 7594 {CCW_DEVICE(0x1731, 0x01), driver_info:QETH_CARD_TYPE_OSAE},
7530 {CCW_DEVICE(0x1731, 0x05), driver_info:QETH_CARD_TYPE_IQD}, 7595 {CCW_DEVICE(0x1731, 0x05), driver_info:QETH_CARD_TYPE_IQD},
diff --git a/drivers/s390/net/qeth_tso.c b/drivers/s390/net/qeth_tso.c
deleted file mode 100644
index 4e58f19cb71c..000000000000
--- a/drivers/s390/net/qeth_tso.c
+++ /dev/null
@@ -1,256 +0,0 @@
1/*
2 * linux/drivers/s390/net/qeth_tso.c ($Revision: 1.7 $)
3 *
4 * Header file for qeth TCP Segmentation Offload support.
5 *
6 * Copyright 2004 IBM Corporation
7 *
8 * Author(s): Frank Pavlic <pavlic@de.ibm.com>
9 *
10 * $Revision: 1.7 $ $Date: 2005/04/01 21:40:41 $
11 *
12 */
13
14#include <linux/skbuff.h>
15#include <linux/tcp.h>
16#include <linux/ip.h>
17#include <linux/ipv6.h>
18#include <net/ip6_checksum.h>
19#include "qeth.h"
20#include "qeth_mpc.h"
21#include "qeth_tso.h"
22
23/**
24 * skb already partially prepared
25 * classic qdio header in skb->data
26 * */
27static inline struct qeth_hdr_tso *
28qeth_tso_prepare_skb(struct qeth_card *card, struct sk_buff **skb)
29{
30 int rc = 0;
31
32 QETH_DBF_TEXT(trace, 5, "tsoprsk");
33 rc = qeth_realloc_headroom(card, skb,sizeof(struct qeth_hdr_ext_tso));
34 if (rc)
35 return NULL;
36
37 return qeth_push_skb(card, skb, sizeof(struct qeth_hdr_ext_tso));
38}
39
40/**
41 * fill header for a TSO packet
42 */
43static inline void
44qeth_tso_fill_header(struct qeth_card *card, struct sk_buff *skb)
45{
46 struct qeth_hdr_tso *hdr;
47 struct tcphdr *tcph;
48 struct iphdr *iph;
49
50 QETH_DBF_TEXT(trace, 5, "tsofhdr");
51
52 hdr = (struct qeth_hdr_tso *) skb->data;
53 iph = skb->nh.iph;
54 tcph = skb->h.th;
55 /*fix header to TSO values ...*/
56 hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO;
57 /*set values which are fix for the first approach ...*/
58 hdr->ext.hdr_tot_len = (__u16) sizeof(struct qeth_hdr_ext_tso);
59 hdr->ext.imb_hdr_no = 1;
60 hdr->ext.hdr_type = 1;
61 hdr->ext.hdr_version = 1;
62 hdr->ext.hdr_len = 28;
63 /*insert non-fix values */
64 hdr->ext.mss = skb_shinfo(skb)->tso_size;
65 hdr->ext.dg_hdr_len = (__u16)(iph->ihl*4 + tcph->doff*4);
66 hdr->ext.payload_len = (__u16)(skb->len - hdr->ext.dg_hdr_len -
67 sizeof(struct qeth_hdr_tso));
68}
69
70/**
71 * change some header values as requested by hardware
72 */
73static inline void
74qeth_tso_set_tcpip_header(struct qeth_card *card, struct sk_buff *skb)
75{
76 struct iphdr *iph;
77 struct ipv6hdr *ip6h;
78 struct tcphdr *tcph;
79
80 iph = skb->nh.iph;
81 ip6h = skb->nh.ipv6h;
82 tcph = skb->h.th;
83
84 tcph->check = 0;
85 if (skb->protocol == ETH_P_IPV6) {
86 ip6h->payload_len = 0;
87 tcph->check = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
88 0, IPPROTO_TCP, 0);
89 return;
90 }
91 /*OSA want us to set these values ...*/
92 tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
93 0, IPPROTO_TCP, 0);
94 iph->tot_len = 0;
95 iph->check = 0;
96}
97
98static inline struct qeth_hdr_tso *
99qeth_tso_prepare_packet(struct qeth_card *card, struct sk_buff *skb,
100 int ipv, int cast_type)
101{
102 struct qeth_hdr_tso *hdr;
103 int rc = 0;
104
105 QETH_DBF_TEXT(trace, 5, "tsoprep");
106
107 /*get headroom for tso qdio header */
108 hdr = (struct qeth_hdr_tso *) qeth_tso_prepare_skb(card, &skb);
109 if (hdr == NULL) {
110 QETH_DBF_TEXT_(trace, 4, "2err%d", rc);
111 return NULL;
112 }
113 memset(hdr, 0, sizeof(struct qeth_hdr_tso));
114 /*fill first 32 bytes of qdio header as used
115 *FIXME: TSO has two struct members
116 * with different names but same size
117 * */
118 qeth_fill_header(card, &hdr->hdr, skb, ipv, cast_type);
119 qeth_tso_fill_header(card, skb);
120 qeth_tso_set_tcpip_header(card, skb);
121 return hdr;
122}
123
124static inline int
125qeth_tso_get_queue_buffer(struct qeth_qdio_out_q *queue)
126{
127 struct qeth_qdio_out_buffer *buffer;
128 int flush_cnt = 0;
129
130 QETH_DBF_TEXT(trace, 5, "tsobuf");
131
132 /* force to non-packing*/
133 if (queue->do_pack)
134 queue->do_pack = 0;
135 buffer = &queue->bufs[queue->next_buf_to_fill];
136 /* get a new buffer if current is already in use*/
137 if ((atomic_read(&buffer->state) == QETH_QDIO_BUF_EMPTY) &&
138 (buffer->next_element_to_fill > 0)) {
139 atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED);
140 queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
141 QDIO_MAX_BUFFERS_PER_Q;
142 flush_cnt++;
143 }
144 return flush_cnt;
145}
146
147
148static inline int
149qeth_tso_fill_buffer(struct qeth_qdio_out_buffer *buf,
150 struct sk_buff *skb)
151{
152 int length, length_here, element;
153 int hdr_len;
154 struct qdio_buffer *buffer;
155 struct qeth_hdr_tso *hdr;
156 char *data;
157
158 QETH_DBF_TEXT(trace, 3, "tsfilbuf");
159
160 /*increment user count and queue skb ...*/
161 atomic_inc(&skb->users);
162 skb_queue_tail(&buf->skb_list, skb);
163
164 /*initialize all variables...*/
165 buffer = buf->buffer;
166 hdr = (struct qeth_hdr_tso *)skb->data;
167 hdr_len = sizeof(struct qeth_hdr_tso) + hdr->ext.dg_hdr_len;
168 data = skb->data + hdr_len;
169 length = skb->len - hdr_len;
170 element = buf->next_element_to_fill;
171 /*fill first buffer entry only with header information */
172 buffer->element[element].addr = skb->data;
173 buffer->element[element].length = hdr_len;
174 buffer->element[element].flags = SBAL_FLAGS_FIRST_FRAG;
175 buf->next_element_to_fill++;
176 /*check if we have frags ...*/
177 if (skb_shinfo(skb)->nr_frags > 0) {
178 skb->len = length;
179 skb->data = data;
180 __qeth_fill_buffer_frag(skb, buffer,1,
181 (int *)&buf->next_element_to_fill);
182 goto out;
183 }
184
185 /*... if not, use this */
186 element++;
187 while (length > 0) {
188 /* length_here is the remaining amount of data in this page */
189 length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE);
190 if (length < length_here)
191 length_here = length;
192 buffer->element[element].addr = data;
193 buffer->element[element].length = length_here;
194 length -= length_here;
195 if (!length)
196 buffer->element[element].flags =
197 SBAL_FLAGS_LAST_FRAG;
198 else
199 buffer->element[element].flags =
200 SBAL_FLAGS_MIDDLE_FRAG;
201 data += length_here;
202 element++;
203 }
204 buf->next_element_to_fill = element;
205out:
206 /*prime buffer now ...*/
207 atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED);
208 return 1;
209}
210
211int
212qeth_tso_send_packet(struct qeth_card *card, struct sk_buff *skb,
213 struct qeth_qdio_out_q *queue, int ipv, int cast_type)
214{
215 int flush_cnt = 0;
216 struct qeth_hdr_tso *hdr;
217 struct qeth_qdio_out_buffer *buffer;
218 int start_index;
219
220 QETH_DBF_TEXT(trace, 3, "tsosend");
221
222 if (!(hdr = qeth_tso_prepare_packet(card, skb, ipv, cast_type)))
223 return -ENOMEM;
224 /*check if skb fits in one SBAL ...*/
225 if (!(qeth_get_elements_no(card, (void*)hdr, skb)))
226 return -EINVAL;
227 /*lock queue, force switching to non-packing and send it ...*/
228 while (atomic_compare_and_swap(QETH_OUT_Q_UNLOCKED,
229 QETH_OUT_Q_LOCKED,
230 &queue->state));
231 start_index = queue->next_buf_to_fill;
232 buffer = &queue->bufs[queue->next_buf_to_fill];
233 /*check if card is too busy ...*/
234 if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY){
235 card->stats.tx_dropped++;
236 goto out;
237 }
238 /*let's force to non-packing and get a new SBAL*/
239 flush_cnt += qeth_tso_get_queue_buffer(queue);
240 buffer = &queue->bufs[queue->next_buf_to_fill];
241 if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) {
242 card->stats.tx_dropped++;
243 goto out;
244 }
245 flush_cnt += qeth_tso_fill_buffer(buffer, skb);
246 queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
247 QDIO_MAX_BUFFERS_PER_Q;
248out:
249 atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
250 if (flush_cnt)
251 qeth_flush_buffers(queue, 0, start_index, flush_cnt);
252 /*do some statistics */
253 card->stats.tx_packets++;
254 card->stats.tx_bytes += skb->len;
255 return 0;
256}
diff --git a/drivers/s390/net/qeth_tso.h b/drivers/s390/net/qeth_tso.h
index ff585ae49b6c..ad33e6f466f1 100644
--- a/drivers/s390/net/qeth_tso.h
+++ b/drivers/s390/net/qeth_tso.h
@@ -1,5 +1,5 @@
1/* 1/*
2 * linux/drivers/s390/net/qeth_tso.h ($Revision: 1.5 $) 2 * linux/drivers/s390/net/qeth_tso.h ($Revision: 1.7 $)
3 * 3 *
4 * Header file for qeth TCP Segmentation Offload support. 4 * Header file for qeth TCP Segmentation Offload support.
5 * 5 *
@@ -7,97 +7,148 @@
7 * 7 *
8 * Author(s): Frank Pavlic <pavlic@de.ibm.com> 8 * Author(s): Frank Pavlic <pavlic@de.ibm.com>
9 * 9 *
10 * $Revision: 1.5 $ $Date: 2005/04/01 21:40:41 $ 10 * $Revision: 1.7 $ $Date: 2005/05/04 20:19:18 $
11 * 11 *
12 */ 12 */
13#ifndef __QETH_TSO_H__ 13#ifndef __QETH_TSO_H__
14#define __QETH_TSO_H__ 14#define __QETH_TSO_H__
15 15
16#include <linux/skbuff.h>
17#include <linux/tcp.h>
18#include <linux/ip.h>
19#include <linux/ipv6.h>
20#include <net/ip6_checksum.h>
21#include "qeth.h"
22#include "qeth_mpc.h"
16 23
17extern int
18qeth_tso_send_packet(struct qeth_card *, struct sk_buff *,
19 struct qeth_qdio_out_q *, int , int);
20 24
21struct qeth_hdr_ext_tso { 25static inline struct qeth_hdr_tso *
22 __u16 hdr_tot_len; 26qeth_tso_prepare_skb(struct qeth_card *card, struct sk_buff **skb)
23 __u8 imb_hdr_no; 27{
24 __u8 reserved; 28 QETH_DBF_TEXT(trace, 5, "tsoprsk");
25 __u8 hdr_type; 29 return qeth_push_skb(card, skb, sizeof(struct qeth_hdr_tso));
26 __u8 hdr_version; 30}
27 __u16 hdr_len; 31
28 __u32 payload_len; 32/**
29 __u16 mss; 33 * fill header for a TSO packet
30 __u16 dg_hdr_len; 34 */
31 __u8 padding[16]; 35static inline void
32} __attribute__ ((packed)); 36qeth_tso_fill_header(struct qeth_card *card, struct sk_buff *skb)
37{
38 struct qeth_hdr_tso *hdr;
39 struct tcphdr *tcph;
40 struct iphdr *iph;
33 41
34struct qeth_hdr_tso { 42 QETH_DBF_TEXT(trace, 5, "tsofhdr");
35 struct qeth_hdr hdr; /*hdr->hdr.l3.xxx*/ 43
36 struct qeth_hdr_ext_tso ext; 44 hdr = (struct qeth_hdr_tso *) skb->data;
37} __attribute__ ((packed)); 45 iph = skb->nh.iph;
46 tcph = skb->h.th;
47 /*fix header to TSO values ...*/
48 hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO;
49 /*set values which are fix for the first approach ...*/
50 hdr->ext.hdr_tot_len = (__u16) sizeof(struct qeth_hdr_ext_tso);
51 hdr->ext.imb_hdr_no = 1;
52 hdr->ext.hdr_type = 1;
53 hdr->ext.hdr_version = 1;
54 hdr->ext.hdr_len = 28;
55 /*insert non-fix values */
56 hdr->ext.mss = skb_shinfo(skb)->tso_size;
57 hdr->ext.dg_hdr_len = (__u16)(iph->ihl*4 + tcph->doff*4);
58 hdr->ext.payload_len = (__u16)(skb->len - hdr->ext.dg_hdr_len -
59 sizeof(struct qeth_hdr_tso));
60}
61
62/**
63 * change some header values as requested by hardware
64 */
65static inline void
66qeth_tso_set_tcpip_header(struct qeth_card *card, struct sk_buff *skb)
67{
68 struct iphdr *iph;
69 struct ipv6hdr *ip6h;
70 struct tcphdr *tcph;
71
72 iph = skb->nh.iph;
73 ip6h = skb->nh.ipv6h;
74 tcph = skb->h.th;
75
76 tcph->check = 0;
77 if (skb->protocol == ETH_P_IPV6) {
78 ip6h->payload_len = 0;
79 tcph->check = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
80 0, IPPROTO_TCP, 0);
81 return;
82 }
83 /*OSA want us to set these values ...*/
84 tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
85 0, IPPROTO_TCP, 0);
86 iph->tot_len = 0;
87 iph->check = 0;
88}
38 89
39/*some helper functions*/
40static inline int 90static inline int
41qeth_get_elements_no(struct qeth_card *card, void *hdr, struct sk_buff *skb) 91qeth_tso_prepare_packet(struct qeth_card *card, struct sk_buff *skb,
92 int ipv, int cast_type)
42{ 93{
43 int elements_needed = 0; 94 struct qeth_hdr_tso *hdr;
44 95
45 if (skb_shinfo(skb)->nr_frags > 0) 96 QETH_DBF_TEXT(trace, 5, "tsoprep");
46 elements_needed = (skb_shinfo(skb)->nr_frags + 1); 97
47 if (elements_needed == 0 ) 98 hdr = (struct qeth_hdr_tso *) qeth_tso_prepare_skb(card, &skb);
48 elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE) 99 if (hdr == NULL) {
49 + skb->len) >> PAGE_SHIFT); 100 QETH_DBF_TEXT(trace, 4, "tsoperr");
50 if (elements_needed > QETH_MAX_BUFFER_ELEMENTS(card)){ 101 return -ENOMEM;
51 PRINT_ERR("qeth_do_send_packet: invalid size of " 102 }
52 "IP packet. Discarded."); 103 memset(hdr, 0, sizeof(struct qeth_hdr_tso));
53 return 0; 104 /*fill first 32 bytes of qdio header as used
54 } 105 *FIXME: TSO has two struct members
55 return elements_needed; 106 * with different names but same size
107 * */
108 qeth_fill_header(card, &hdr->hdr, skb, ipv, cast_type);
109 qeth_tso_fill_header(card, skb);
110 qeth_tso_set_tcpip_header(card, skb);
111 return 0;
56} 112}
57 113
58static inline void 114static inline void
59__qeth_fill_buffer_frag(struct sk_buff *skb, struct qdio_buffer *buffer, 115__qeth_fill_buffer_frag(struct sk_buff *skb, struct qdio_buffer *buffer,
60 int is_tso, int *next_element_to_fill) 116 int is_tso, int *next_element_to_fill)
61{ 117{
62 int length = skb->len;
63 struct skb_frag_struct *frag; 118 struct skb_frag_struct *frag;
64 int fragno; 119 int fragno;
65 unsigned long addr; 120 unsigned long addr;
66 int element; 121 int element, cnt, dlen;
67 int first_lap = 1; 122
68 123 fragno = skb_shinfo(skb)->nr_frags;
69 fragno = skb_shinfo(skb)->nr_frags; /* start with last frag */ 124 element = *next_element_to_fill;
70 element = *next_element_to_fill + fragno; 125 dlen = 0;
71 while (length > 0) { 126
72 if (fragno > 0) { 127 if (is_tso)
73 frag = &skb_shinfo(skb)->frags[fragno - 1]; 128 buffer->element[element].flags =
74 addr = (page_to_pfn(frag->page) << PAGE_SHIFT) + 129 SBAL_FLAGS_MIDDLE_FRAG;
75 frag->page_offset; 130 else
76 buffer->element[element].addr = (char *)addr; 131 buffer->element[element].flags =
77 buffer->element[element].length = frag->size; 132 SBAL_FLAGS_FIRST_FRAG;
78 length -= frag->size; 133 if ( (dlen = (skb->len - skb->data_len)) ) {
79 if (first_lap) 134 buffer->element[element].addr = skb->data;
80 buffer->element[element].flags = 135 buffer->element[element].length = dlen;
81 SBAL_FLAGS_LAST_FRAG; 136 element++;
82 else
83 buffer->element[element].flags =
84 SBAL_FLAGS_MIDDLE_FRAG;
85 } else {
86 buffer->element[element].addr = skb->data;
87 buffer->element[element].length = length;
88 length = 0;
89 if (is_tso)
90 buffer->element[element].flags =
91 SBAL_FLAGS_MIDDLE_FRAG;
92 else
93 buffer->element[element].flags =
94 SBAL_FLAGS_FIRST_FRAG;
95 }
96 element--;
97 fragno--;
98 first_lap = 0;
99 } 137 }
100 *next_element_to_fill += skb_shinfo(skb)->nr_frags + 1; 138 for (cnt = 0; cnt < fragno; cnt++) {
139 frag = &skb_shinfo(skb)->frags[cnt];
140 addr = (page_to_pfn(frag->page) << PAGE_SHIFT) +
141 frag->page_offset;
142 buffer->element[element].addr = (char *)addr;
143 buffer->element[element].length = frag->size;
144 if (cnt < (fragno - 1))
145 buffer->element[element].flags =
146 SBAL_FLAGS_MIDDLE_FRAG;
147 else
148 buffer->element[element].flags =
149 SBAL_FLAGS_LAST_FRAG;
150 element++;
151 }
152 *next_element_to_fill = element;
101} 153}
102
103#endif /* __QETH_TSO_H__ */ 154#endif /* __QETH_TSO_H__ */