diff options
Diffstat (limited to 'drivers/s390/net/qeth_l3_main.c')
-rw-r--r-- | drivers/s390/net/qeth_l3_main.c | 51 |
1 files changed, 38 insertions, 13 deletions
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 3e1d13857350..dd72c3c20165 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c | |||
@@ -2604,6 +2604,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2604 | int tx_bytes = skb->len; | 2604 | int tx_bytes = skb->len; |
2605 | enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; | 2605 | enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; |
2606 | struct qeth_eddp_context *ctx = NULL; | 2606 | struct qeth_eddp_context *ctx = NULL; |
2607 | int data_offset = -1; | ||
2607 | 2608 | ||
2608 | if ((card->info.type == QETH_CARD_TYPE_IQD) && | 2609 | if ((card->info.type == QETH_CARD_TYPE_IQD) && |
2609 | (skb->protocol != htons(ETH_P_IPV6)) && | 2610 | (skb->protocol != htons(ETH_P_IPV6)) && |
@@ -2624,14 +2625,28 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2624 | card->perf_stats.outbound_start_time = qeth_get_micros(); | 2625 | card->perf_stats.outbound_start_time = qeth_get_micros(); |
2625 | } | 2626 | } |
2626 | 2627 | ||
2627 | /* create a clone with writeable headroom */ | 2628 | if (skb_is_gso(skb)) |
2628 | new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr_tso) + | 2629 | large_send = card->options.large_send; |
2629 | VLAN_HLEN); | 2630 | |
2630 | if (!new_skb) | 2631 | if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) && |
2631 | goto tx_drop; | 2632 | (skb_shinfo(skb)->nr_frags == 0)) { |
2633 | new_skb = skb; | ||
2634 | data_offset = ETH_HLEN; | ||
2635 | hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC); | ||
2636 | if (!hdr) | ||
2637 | goto tx_drop; | ||
2638 | elements_needed++; | ||
2639 | } else { | ||
2640 | /* create a clone with writeable headroom */ | ||
2641 | new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr_tso) | ||
2642 | + VLAN_HLEN); | ||
2643 | if (!new_skb) | ||
2644 | goto tx_drop; | ||
2645 | } | ||
2632 | 2646 | ||
2633 | if (card->info.type == QETH_CARD_TYPE_IQD) { | 2647 | if (card->info.type == QETH_CARD_TYPE_IQD) { |
2634 | skb_pull(new_skb, ETH_HLEN); | 2648 | if (data_offset < 0) |
2649 | skb_pull(new_skb, ETH_HLEN); | ||
2635 | } else { | 2650 | } else { |
2636 | if (new_skb->protocol == htons(ETH_P_IP)) { | 2651 | if (new_skb->protocol == htons(ETH_P_IP)) { |
2637 | if (card->dev->type == ARPHRD_IEEE802_TR) | 2652 | if (card->dev->type == ARPHRD_IEEE802_TR) |
@@ -2657,9 +2672,6 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2657 | 2672 | ||
2658 | netif_stop_queue(dev); | 2673 | netif_stop_queue(dev); |
2659 | 2674 | ||
2660 | if (skb_is_gso(new_skb)) | ||
2661 | large_send = card->options.large_send; | ||
2662 | |||
2663 | /* fix hardware limitation: as long as we do not have sbal | 2675 | /* fix hardware limitation: as long as we do not have sbal |
2664 | * chaining we can not send long frag lists so we temporary | 2676 | * chaining we can not send long frag lists so we temporary |
2665 | * switch to EDDP | 2677 | * switch to EDDP |
@@ -2677,9 +2689,16 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2677 | qeth_tso_fill_header(card, hdr, new_skb); | 2689 | qeth_tso_fill_header(card, hdr, new_skb); |
2678 | elements_needed++; | 2690 | elements_needed++; |
2679 | } else { | 2691 | } else { |
2680 | hdr = (struct qeth_hdr *)skb_push(new_skb, | 2692 | if (data_offset < 0) { |
2693 | hdr = (struct qeth_hdr *)skb_push(new_skb, | ||
2681 | sizeof(struct qeth_hdr)); | 2694 | sizeof(struct qeth_hdr)); |
2682 | qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type); | 2695 | qeth_l3_fill_header(card, hdr, new_skb, ipv, |
2696 | cast_type); | ||
2697 | } else { | ||
2698 | qeth_l3_fill_header(card, hdr, new_skb, ipv, | ||
2699 | cast_type); | ||
2700 | hdr->hdr.l3.length = new_skb->len - data_offset; | ||
2701 | } | ||
2683 | } | 2702 | } |
2684 | 2703 | ||
2685 | if (large_send == QETH_LARGE_SEND_EDDP) { | 2704 | if (large_send == QETH_LARGE_SEND_EDDP) { |
@@ -2695,8 +2714,11 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2695 | } else { | 2714 | } else { |
2696 | int elems = qeth_get_elements_no(card, (void *)hdr, new_skb, | 2715 | int elems = qeth_get_elements_no(card, (void *)hdr, new_skb, |
2697 | elements_needed); | 2716 | elements_needed); |
2698 | if (!elems) | 2717 | if (!elems) { |
2718 | if (data_offset >= 0) | ||
2719 | kmem_cache_free(qeth_core_header_cache, hdr); | ||
2699 | goto tx_drop; | 2720 | goto tx_drop; |
2721 | } | ||
2700 | elements_needed += elems; | 2722 | elements_needed += elems; |
2701 | } | 2723 | } |
2702 | 2724 | ||
@@ -2709,7 +2731,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2709 | elements_needed, ctx); | 2731 | elements_needed, ctx); |
2710 | else | 2732 | else |
2711 | rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, | 2733 | rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, |
2712 | elements_needed, ctx); | 2734 | elements_needed, ctx, data_offset, 0); |
2713 | 2735 | ||
2714 | if (!rc) { | 2736 | if (!rc) { |
2715 | card->stats.tx_packets++; | 2737 | card->stats.tx_packets++; |
@@ -2737,6 +2759,9 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2737 | if (ctx != NULL) | 2759 | if (ctx != NULL) |
2738 | qeth_eddp_put_context(ctx); | 2760 | qeth_eddp_put_context(ctx); |
2739 | 2761 | ||
2762 | if (data_offset >= 0) | ||
2763 | kmem_cache_free(qeth_core_header_cache, hdr); | ||
2764 | |||
2740 | if (rc == -EBUSY) { | 2765 | if (rc == -EBUSY) { |
2741 | if (new_skb != skb) | 2766 | if (new_skb != skb) |
2742 | dev_kfree_skb_any(new_skb); | 2767 | dev_kfree_skb_any(new_skb); |