aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/net/qeth_eddp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/net/qeth_eddp.c')
-rw-r--r--drivers/s390/net/qeth_eddp.c51
1 files changed, 20 insertions, 31 deletions
diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c
index 7ee1c06ed68a..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.11 $) 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.11 $ $Date: 2005/03/24 09:04:18 $ 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)){
@@ -202,40 +202,29 @@ out:
202 return flush_cnt; 202 return flush_cnt;
203} 203}
204 204
205static inline int
206qeth_get_skb_data_len(struct sk_buff *skb)
207{
208 int len = skb->len;
209 int i;
210
211 for (i = 0; i < skb_shinfo(skb)->nr_frags; ++i)
212 len -= skb_shinfo(skb)->frags[i].size;
213 return len;
214}
215
216static inline void 205static inline void
217qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx, 206qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx,
218 struct qeth_eddp_data *eddp) 207 struct qeth_eddp_data *eddp, int data_len)
219{ 208{
220 u8 *page; 209 u8 *page;
221 int page_remainder; 210 int page_remainder;
222 int page_offset; 211 int page_offset;
223 int hdr_len; 212 int pkt_len;
224 struct qeth_eddp_element *element; 213 struct qeth_eddp_element *element;
225 214
226 QETH_DBF_TEXT(trace, 5, "eddpcrsh"); 215 QETH_DBF_TEXT(trace, 5, "eddpcrsh");
227 page = ctx->pages[ctx->offset >> PAGE_SHIFT]; 216 page = ctx->pages[ctx->offset >> PAGE_SHIFT];
228 page_offset = ctx->offset % PAGE_SIZE; 217 page_offset = ctx->offset % PAGE_SIZE;
229 element = &ctx->elements[ctx->num_elements]; 218 element = &ctx->elements[ctx->num_elements];
230 hdr_len = eddp->nhl + eddp->thl; 219 pkt_len = eddp->nhl + eddp->thl + data_len;
231 /* FIXME: layer2 and VLAN !!! */ 220 /* FIXME: layer2 and VLAN !!! */
232 if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2) 221 if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2)
233 hdr_len += ETH_HLEN; 222 pkt_len += ETH_HLEN;
234 if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q)) 223 if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q))
235 hdr_len += VLAN_HLEN; 224 pkt_len += VLAN_HLEN;
236 /* does complete header fit in current page ? */ 225 /* does complete packet fit in current page ? */
237 page_remainder = PAGE_SIZE - page_offset; 226 page_remainder = PAGE_SIZE - page_offset;
238 if (page_remainder < (sizeof(struct qeth_hdr) + hdr_len)){ 227 if (page_remainder < (sizeof(struct qeth_hdr) + pkt_len)){
239 /* no -> go to start of next page */ 228 /* no -> go to start of next page */
240 ctx->offset += page_remainder; 229 ctx->offset += page_remainder;
241 page = ctx->pages[ctx->offset >> PAGE_SHIFT]; 230 page = ctx->pages[ctx->offset >> PAGE_SHIFT];
@@ -281,7 +270,7 @@ qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
281 int left_in_frag; 270 int left_in_frag;
282 int copy_len; 271 int copy_len;
283 u8 *src; 272 u8 *src;
284 273
285 QETH_DBF_TEXT(trace, 5, "eddpcdtc"); 274 QETH_DBF_TEXT(trace, 5, "eddpcdtc");
286 if (skb_shinfo(eddp->skb)->nr_frags == 0) { 275 if (skb_shinfo(eddp->skb)->nr_frags == 0) {
287 memcpy(dst, eddp->skb->data + eddp->skb_offset, len); 276 memcpy(dst, eddp->skb->data + eddp->skb_offset, len);
@@ -292,7 +281,7 @@ qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
292 while (len > 0) { 281 while (len > 0) {
293 if (eddp->frag < 0) { 282 if (eddp->frag < 0) {
294 /* we're in skb->data */ 283 /* we're in skb->data */
295 left_in_frag = qeth_get_skb_data_len(eddp->skb) 284 left_in_frag = (eddp->skb->len - eddp->skb->data_len)
296 - eddp->skb_offset; 285 - eddp->skb_offset;
297 src = eddp->skb->data + eddp->skb_offset; 286 src = eddp->skb->data + eddp->skb_offset;
298 } else { 287 } else {
@@ -424,7 +413,7 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
424 struct tcphdr *tcph; 413 struct tcphdr *tcph;
425 int data_len; 414 int data_len;
426 u32 hcsum; 415 u32 hcsum;
427 416
428 QETH_DBF_TEXT(trace, 5, "eddpftcp"); 417 QETH_DBF_TEXT(trace, 5, "eddpftcp");
429 eddp->skb_offset = sizeof(struct qeth_hdr) + eddp->nhl + eddp->thl; 418 eddp->skb_offset = sizeof(struct qeth_hdr) + eddp->nhl + eddp->thl;
430 tcph = eddp->skb->h.th; 419 tcph = eddp->skb->h.th;
@@ -464,7 +453,7 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
464 else 453 else
465 hcsum = qeth_eddp_check_tcp6_hdr(eddp, data_len); 454 hcsum = qeth_eddp_check_tcp6_hdr(eddp, data_len);
466 /* fill the next segment into the context */ 455 /* fill the next segment into the context */
467 qeth_eddp_create_segment_hdrs(ctx, eddp); 456 qeth_eddp_create_segment_hdrs(ctx, eddp, data_len);
468 qeth_eddp_create_segment_data_tcp(ctx, eddp, data_len, hcsum); 457 qeth_eddp_create_segment_data_tcp(ctx, eddp, data_len, hcsum);
469 if (eddp->skb_offset >= eddp->skb->len) 458 if (eddp->skb_offset >= eddp->skb->len)
470 break; 459 break;
@@ -474,13 +463,13 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
474 eddp->th.tcp.h.seq += data_len; 463 eddp->th.tcp.h.seq += data_len;
475 } 464 }
476} 465}
477 466
478static inline int 467static inline int
479qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx, 468qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
480 struct sk_buff *skb, struct qeth_hdr *qhdr) 469 struct sk_buff *skb, struct qeth_hdr *qhdr)
481{ 470{
482 struct qeth_eddp_data *eddp = NULL; 471 struct qeth_eddp_data *eddp = NULL;
483 472
484 QETH_DBF_TEXT(trace, 5, "eddpficx"); 473 QETH_DBF_TEXT(trace, 5, "eddpficx");
485 /* create our segmentation headers and copy original headers */ 474 /* create our segmentation headers and copy original headers */
486 if (skb->protocol == ETH_P_IP) 475 if (skb->protocol == ETH_P_IP)
@@ -520,7 +509,7 @@ qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb,
520 int hdr_len) 509 int hdr_len)
521{ 510{
522 int skbs_per_page; 511 int skbs_per_page;
523 512
524 QETH_DBF_TEXT(trace, 5, "eddpcanp"); 513 QETH_DBF_TEXT(trace, 5, "eddpcanp");
525 /* can we put multiple skbs in one page? */ 514 /* can we put multiple skbs in one page? */
526 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);
@@ -600,7 +589,7 @@ qeth_eddp_create_context_tcp(struct qeth_card *card, struct sk_buff *skb,
600 struct qeth_hdr *qhdr) 589 struct qeth_hdr *qhdr)
601{ 590{
602 struct qeth_eddp_context *ctx = NULL; 591 struct qeth_eddp_context *ctx = NULL;
603 592
604 QETH_DBF_TEXT(trace, 5, "creddpct"); 593 QETH_DBF_TEXT(trace, 5, "creddpct");
605 if (skb->protocol == ETH_P_IP) 594 if (skb->protocol == ETH_P_IP)
606 ctx = qeth_eddp_create_context_generic(card, skb, 595 ctx = qeth_eddp_create_context_generic(card, skb,