diff options
Diffstat (limited to 'drivers/s390/net/qeth_eddp.c')
-rw-r--r-- | drivers/s390/net/qeth_eddp.c | 51 |
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 | |||
85 | qeth_eddp_buf_release_contexts(struct qeth_qdio_out_buffer *buf) | 85 | qeth_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 | ||
205 | static inline int | ||
206 | qeth_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 | |||
216 | static inline void | 205 | static inline void |
217 | qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx, | 206 | qeth_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 | ||
478 | static inline int | 467 | static inline int |
479 | qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx, | 468 | qeth_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, |