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, |
