diff options
-rw-r--r-- | drivers/s390/net/qeth_core.h | 5 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_main.c | 59 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l2_main.c | 50 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l3_main.c | 51 |
4 files changed, 126 insertions, 39 deletions
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 1895dbb553cd..80971c21ea1a 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h | |||
@@ -419,6 +419,7 @@ struct qeth_qdio_out_buffer { | |||
419 | int next_element_to_fill; | 419 | int next_element_to_fill; |
420 | struct sk_buff_head skb_list; | 420 | struct sk_buff_head skb_list; |
421 | struct list_head ctx_list; | 421 | struct list_head ctx_list; |
422 | int is_header[16]; | ||
422 | }; | 423 | }; |
423 | 424 | ||
424 | struct qeth_card; | 425 | struct qeth_card; |
@@ -785,7 +786,7 @@ void qeth_core_remove_osn_attributes(struct device *); | |||
785 | 786 | ||
786 | /* exports for qeth discipline device drivers */ | 787 | /* exports for qeth discipline device drivers */ |
787 | extern struct qeth_card_list_struct qeth_core_card_list; | 788 | extern struct qeth_card_list_struct qeth_core_card_list; |
788 | 789 | extern struct kmem_cache *qeth_core_header_cache; | |
789 | extern struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS]; | 790 | extern struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS]; |
790 | 791 | ||
791 | void qeth_set_allowed_threads(struct qeth_card *, unsigned long , int); | 792 | void qeth_set_allowed_threads(struct qeth_card *, unsigned long , int); |
@@ -843,7 +844,7 @@ int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int); | |||
843 | int qeth_get_elements_no(struct qeth_card *, void *, struct sk_buff *, int); | 844 | int qeth_get_elements_no(struct qeth_card *, void *, struct sk_buff *, int); |
844 | int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *, | 845 | int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *, |
845 | struct sk_buff *, struct qeth_hdr *, int, | 846 | struct sk_buff *, struct qeth_hdr *, int, |
846 | struct qeth_eddp_context *); | 847 | struct qeth_eddp_context *, int, int); |
847 | int qeth_do_send_packet(struct qeth_card *, struct qeth_qdio_out_q *, | 848 | int qeth_do_send_packet(struct qeth_card *, struct qeth_qdio_out_q *, |
848 | struct sk_buff *, struct qeth_hdr *, | 849 | struct sk_buff *, struct qeth_hdr *, |
849 | int, struct qeth_eddp_context *); | 850 | int, struct qeth_eddp_context *); |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index cebb25e36e82..7a5549919717 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
@@ -48,6 +48,8 @@ EXPORT_SYMBOL_GPL(qeth_dbf); | |||
48 | 48 | ||
49 | struct qeth_card_list_struct qeth_core_card_list; | 49 | struct qeth_card_list_struct qeth_core_card_list; |
50 | EXPORT_SYMBOL_GPL(qeth_core_card_list); | 50 | EXPORT_SYMBOL_GPL(qeth_core_card_list); |
51 | struct kmem_cache *qeth_core_header_cache; | ||
52 | EXPORT_SYMBOL_GPL(qeth_core_header_cache); | ||
51 | 53 | ||
52 | static struct device *qeth_core_root_dev; | 54 | static struct device *qeth_core_root_dev; |
53 | static unsigned int known_devices[][10] = QETH_MODELLIST_ARRAY; | 55 | static unsigned int known_devices[][10] = QETH_MODELLIST_ARRAY; |
@@ -933,6 +935,10 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, | |||
933 | } | 935 | } |
934 | qeth_eddp_buf_release_contexts(buf); | 936 | qeth_eddp_buf_release_contexts(buf); |
935 | for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(queue->card); ++i) { | 937 | for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(queue->card); ++i) { |
938 | if (buf->buffer->element[i].addr && buf->is_header[i]) | ||
939 | kmem_cache_free(qeth_core_header_cache, | ||
940 | buf->buffer->element[i].addr); | ||
941 | buf->is_header[i] = 0; | ||
936 | buf->buffer->element[i].length = 0; | 942 | buf->buffer->element[i].length = 0; |
937 | buf->buffer->element[i].addr = NULL; | 943 | buf->buffer->element[i].addr = NULL; |
938 | buf->buffer->element[i].flags = 0; | 944 | buf->buffer->element[i].flags = 0; |
@@ -3002,8 +3008,8 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr, | |||
3002 | if (skb_shinfo(skb)->nr_frags > 0) | 3008 | if (skb_shinfo(skb)->nr_frags > 0) |
3003 | elements_needed = (skb_shinfo(skb)->nr_frags + 1); | 3009 | elements_needed = (skb_shinfo(skb)->nr_frags + 1); |
3004 | if (elements_needed == 0) | 3010 | if (elements_needed == 0) |
3005 | elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE) | 3011 | elements_needed = 1 + (((((unsigned long) skb->data) % |
3006 | + skb->len) >> PAGE_SHIFT); | 3012 | PAGE_SIZE) + skb->len) >> PAGE_SHIFT); |
3007 | if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { | 3013 | if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { |
3008 | QETH_DBF_MESSAGE(2, "Invalid size of IP packet " | 3014 | QETH_DBF_MESSAGE(2, "Invalid size of IP packet " |
3009 | "(Number=%d / Length=%d). Discarded.\n", | 3015 | "(Number=%d / Length=%d). Discarded.\n", |
@@ -3015,7 +3021,8 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr, | |||
3015 | EXPORT_SYMBOL_GPL(qeth_get_elements_no); | 3021 | EXPORT_SYMBOL_GPL(qeth_get_elements_no); |
3016 | 3022 | ||
3017 | static inline void __qeth_fill_buffer(struct sk_buff *skb, | 3023 | static inline void __qeth_fill_buffer(struct sk_buff *skb, |
3018 | struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill) | 3024 | struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill, |
3025 | int offset) | ||
3019 | { | 3026 | { |
3020 | int length = skb->len; | 3027 | int length = skb->len; |
3021 | int length_here; | 3028 | int length_here; |
@@ -3027,6 +3034,11 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb, | |||
3027 | data = skb->data; | 3034 | data = skb->data; |
3028 | first_lap = (is_tso == 0 ? 1 : 0); | 3035 | first_lap = (is_tso == 0 ? 1 : 0); |
3029 | 3036 | ||
3037 | if (offset >= 0) { | ||
3038 | data = skb->data + offset; | ||
3039 | first_lap = 0; | ||
3040 | } | ||
3041 | |||
3030 | while (length > 0) { | 3042 | while (length > 0) { |
3031 | /* length_here is the remaining amount of data in this page */ | 3043 | /* length_here is the remaining amount of data in this page */ |
3032 | length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE); | 3044 | length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE); |
@@ -3058,22 +3070,22 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb, | |||
3058 | } | 3070 | } |
3059 | 3071 | ||
3060 | static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue, | 3072 | static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue, |
3061 | struct qeth_qdio_out_buffer *buf, struct sk_buff *skb) | 3073 | struct qeth_qdio_out_buffer *buf, struct sk_buff *skb, |
3074 | struct qeth_hdr *hdr, int offset, int hd_len) | ||
3062 | { | 3075 | { |
3063 | struct qdio_buffer *buffer; | 3076 | struct qdio_buffer *buffer; |
3064 | struct qeth_hdr_tso *hdr; | ||
3065 | int flush_cnt = 0, hdr_len, large_send = 0; | 3077 | int flush_cnt = 0, hdr_len, large_send = 0; |
3066 | 3078 | ||
3067 | buffer = buf->buffer; | 3079 | buffer = buf->buffer; |
3068 | atomic_inc(&skb->users); | 3080 | atomic_inc(&skb->users); |
3069 | skb_queue_tail(&buf->skb_list, skb); | 3081 | skb_queue_tail(&buf->skb_list, skb); |
3070 | 3082 | ||
3071 | hdr = (struct qeth_hdr_tso *) skb->data; | ||
3072 | /*check first on TSO ....*/ | 3083 | /*check first on TSO ....*/ |
3073 | if (hdr->hdr.hdr.l3.id == QETH_HEADER_TYPE_TSO) { | 3084 | if (hdr->hdr.l3.id == QETH_HEADER_TYPE_TSO) { |
3074 | int element = buf->next_element_to_fill; | 3085 | int element = buf->next_element_to_fill; |
3075 | 3086 | ||
3076 | hdr_len = sizeof(struct qeth_hdr_tso) + hdr->ext.dg_hdr_len; | 3087 | hdr_len = sizeof(struct qeth_hdr_tso) + |
3088 | ((struct qeth_hdr_tso *)hdr)->ext.dg_hdr_len; | ||
3077 | /*fill first buffer entry only with header information */ | 3089 | /*fill first buffer entry only with header information */ |
3078 | buffer->element[element].addr = skb->data; | 3090 | buffer->element[element].addr = skb->data; |
3079 | buffer->element[element].length = hdr_len; | 3091 | buffer->element[element].length = hdr_len; |
@@ -3083,9 +3095,20 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue, | |||
3083 | skb->len -= hdr_len; | 3095 | skb->len -= hdr_len; |
3084 | large_send = 1; | 3096 | large_send = 1; |
3085 | } | 3097 | } |
3098 | |||
3099 | if (offset >= 0) { | ||
3100 | int element = buf->next_element_to_fill; | ||
3101 | buffer->element[element].addr = hdr; | ||
3102 | buffer->element[element].length = sizeof(struct qeth_hdr) + | ||
3103 | hd_len; | ||
3104 | buffer->element[element].flags = SBAL_FLAGS_FIRST_FRAG; | ||
3105 | buf->is_header[element] = 1; | ||
3106 | buf->next_element_to_fill++; | ||
3107 | } | ||
3108 | |||
3086 | if (skb_shinfo(skb)->nr_frags == 0) | 3109 | if (skb_shinfo(skb)->nr_frags == 0) |
3087 | __qeth_fill_buffer(skb, buffer, large_send, | 3110 | __qeth_fill_buffer(skb, buffer, large_send, |
3088 | (int *)&buf->next_element_to_fill); | 3111 | (int *)&buf->next_element_to_fill, offset); |
3089 | else | 3112 | else |
3090 | __qeth_fill_buffer_frag(skb, buffer, large_send, | 3113 | __qeth_fill_buffer_frag(skb, buffer, large_send, |
3091 | (int *)&buf->next_element_to_fill); | 3114 | (int *)&buf->next_element_to_fill); |
@@ -3115,7 +3138,7 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue, | |||
3115 | int qeth_do_send_packet_fast(struct qeth_card *card, | 3138 | int qeth_do_send_packet_fast(struct qeth_card *card, |
3116 | struct qeth_qdio_out_q *queue, struct sk_buff *skb, | 3139 | struct qeth_qdio_out_q *queue, struct sk_buff *skb, |
3117 | struct qeth_hdr *hdr, int elements_needed, | 3140 | struct qeth_hdr *hdr, int elements_needed, |
3118 | struct qeth_eddp_context *ctx) | 3141 | struct qeth_eddp_context *ctx, int offset, int hd_len) |
3119 | { | 3142 | { |
3120 | struct qeth_qdio_out_buffer *buffer; | 3143 | struct qeth_qdio_out_buffer *buffer; |
3121 | int buffers_needed = 0; | 3144 | int buffers_needed = 0; |
@@ -3148,7 +3171,7 @@ int qeth_do_send_packet_fast(struct qeth_card *card, | |||
3148 | } | 3171 | } |
3149 | atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); | 3172 | atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); |
3150 | if (ctx == NULL) { | 3173 | if (ctx == NULL) { |
3151 | qeth_fill_buffer(queue, buffer, skb); | 3174 | qeth_fill_buffer(queue, buffer, skb, hdr, offset, hd_len); |
3152 | qeth_flush_buffers(queue, index, 1); | 3175 | qeth_flush_buffers(queue, index, 1); |
3153 | } else { | 3176 | } else { |
3154 | flush_cnt = qeth_eddp_fill_buffer(queue, ctx, index); | 3177 | flush_cnt = qeth_eddp_fill_buffer(queue, ctx, index); |
@@ -3224,7 +3247,7 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, | |||
3224 | } | 3247 | } |
3225 | } | 3248 | } |
3226 | if (ctx == NULL) | 3249 | if (ctx == NULL) |
3227 | tmp = qeth_fill_buffer(queue, buffer, skb); | 3250 | tmp = qeth_fill_buffer(queue, buffer, skb, hdr, -1, 0); |
3228 | else { | 3251 | else { |
3229 | tmp = qeth_eddp_fill_buffer(queue, ctx, | 3252 | tmp = qeth_eddp_fill_buffer(queue, ctx, |
3230 | queue->next_buf_to_fill); | 3253 | queue->next_buf_to_fill); |
@@ -4443,8 +4466,17 @@ static int __init qeth_core_init(void) | |||
4443 | rc = IS_ERR(qeth_core_root_dev) ? PTR_ERR(qeth_core_root_dev) : 0; | 4466 | rc = IS_ERR(qeth_core_root_dev) ? PTR_ERR(qeth_core_root_dev) : 0; |
4444 | if (rc) | 4467 | if (rc) |
4445 | goto register_err; | 4468 | goto register_err; |
4446 | return 0; | ||
4447 | 4469 | ||
4470 | qeth_core_header_cache = kmem_cache_create("qeth_hdr", | ||
4471 | sizeof(struct qeth_hdr) + ETH_HLEN, 64, 0, NULL); | ||
4472 | if (!qeth_core_header_cache) { | ||
4473 | rc = -ENOMEM; | ||
4474 | goto slab_err; | ||
4475 | } | ||
4476 | |||
4477 | return 0; | ||
4478 | slab_err: | ||
4479 | s390_root_dev_unregister(qeth_core_root_dev); | ||
4448 | register_err: | 4480 | register_err: |
4449 | driver_remove_file(&qeth_core_ccwgroup_driver.driver, | 4481 | driver_remove_file(&qeth_core_ccwgroup_driver.driver, |
4450 | &driver_attr_group); | 4482 | &driver_attr_group); |
@@ -4466,6 +4498,7 @@ static void __exit qeth_core_exit(void) | |||
4466 | &driver_attr_group); | 4498 | &driver_attr_group); |
4467 | ccwgroup_driver_unregister(&qeth_core_ccwgroup_driver); | 4499 | ccwgroup_driver_unregister(&qeth_core_ccwgroup_driver); |
4468 | ccw_driver_unregister(&qeth_ccw_driver); | 4500 | ccw_driver_unregister(&qeth_ccw_driver); |
4501 | kmem_cache_destroy(qeth_core_header_cache); | ||
4469 | qeth_unregister_dbf_views(); | 4502 | qeth_unregister_dbf_views(); |
4470 | PRINT_INFO("core functions removed\n"); | 4503 | PRINT_INFO("core functions removed\n"); |
4471 | } | 4504 | } |
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index a8b069cd9a4c..b3cee032f578 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c | |||
@@ -243,8 +243,7 @@ static void qeth_l2_get_packet_type(struct qeth_card *card, | |||
243 | static void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, | 243 | static void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, |
244 | struct sk_buff *skb, int ipv, int cast_type) | 244 | struct sk_buff *skb, int ipv, int cast_type) |
245 | { | 245 | { |
246 | struct vlan_ethhdr *veth = (struct vlan_ethhdr *)((skb->data) + | 246 | struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb); |
247 | QETH_HEADER_SIZE); | ||
248 | 247 | ||
249 | memset(hdr, 0, sizeof(struct qeth_hdr)); | 248 | memset(hdr, 0, sizeof(struct qeth_hdr)); |
250 | hdr->hdr.l2.id = QETH_HEADER_TYPE_LAYER2; | 249 | hdr->hdr.l2.id = QETH_HEADER_TYPE_LAYER2; |
@@ -621,6 +620,9 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
621 | int tx_bytes = skb->len; | 620 | int tx_bytes = skb->len; |
622 | enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; | 621 | enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; |
623 | struct qeth_eddp_context *ctx = NULL; | 622 | struct qeth_eddp_context *ctx = NULL; |
623 | int data_offset = -1; | ||
624 | int elements_needed = 0; | ||
625 | int hd_len = 0; | ||
624 | 626 | ||
625 | if ((card->state != CARD_STATE_UP) || !card->lan_online) { | 627 | if ((card->state != CARD_STATE_UP) || !card->lan_online) { |
626 | card->stats.tx_carrier_errors++; | 628 | card->stats.tx_carrier_errors++; |
@@ -643,13 +645,32 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
643 | if (card->info.type == QETH_CARD_TYPE_OSN) | 645 | if (card->info.type == QETH_CARD_TYPE_OSN) |
644 | hdr = (struct qeth_hdr *)skb->data; | 646 | hdr = (struct qeth_hdr *)skb->data; |
645 | else { | 647 | else { |
646 | /* create a clone with writeable headroom */ | 648 | if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) && |
647 | new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr)); | 649 | (skb_shinfo(skb)->nr_frags == 0)) { |
648 | if (!new_skb) | 650 | new_skb = skb; |
649 | goto tx_drop; | 651 | data_offset = ETH_HLEN; |
650 | hdr = (struct qeth_hdr *)skb_push(new_skb, | 652 | hd_len = ETH_HLEN; |
653 | hdr = kmem_cache_alloc(qeth_core_header_cache, | ||
654 | GFP_ATOMIC); | ||
655 | if (!hdr) | ||
656 | goto tx_drop; | ||
657 | elements_needed++; | ||
658 | skb_reset_mac_header(new_skb); | ||
659 | qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type); | ||
660 | hdr->hdr.l2.pkt_length = new_skb->len; | ||
661 | memcpy(((char *)hdr) + sizeof(struct qeth_hdr), | ||
662 | skb_mac_header(new_skb), ETH_HLEN); | ||
663 | } else { | ||
664 | /* create a clone with writeable headroom */ | ||
665 | new_skb = skb_realloc_headroom(skb, | ||
666 | sizeof(struct qeth_hdr)); | ||
667 | if (!new_skb) | ||
668 | goto tx_drop; | ||
669 | hdr = (struct qeth_hdr *)skb_push(new_skb, | ||
651 | sizeof(struct qeth_hdr)); | 670 | sizeof(struct qeth_hdr)); |
652 | qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type); | 671 | skb_set_mac_header(new_skb, sizeof(struct qeth_hdr)); |
672 | qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type); | ||
673 | } | ||
653 | } | 674 | } |
654 | 675 | ||
655 | if (large_send == QETH_LARGE_SEND_EDDP) { | 676 | if (large_send == QETH_LARGE_SEND_EDDP) { |
@@ -660,9 +681,13 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
660 | goto tx_drop; | 681 | goto tx_drop; |
661 | } | 682 | } |
662 | } else { | 683 | } else { |
663 | elements = qeth_get_elements_no(card, (void *)hdr, new_skb, 0); | 684 | elements = qeth_get_elements_no(card, (void *)hdr, new_skb, |
664 | if (!elements) | 685 | elements_needed); |
686 | if (!elements) { | ||
687 | if (data_offset >= 0) | ||
688 | kmem_cache_free(qeth_core_header_cache, hdr); | ||
665 | goto tx_drop; | 689 | goto tx_drop; |
690 | } | ||
666 | } | 691 | } |
667 | 692 | ||
668 | if ((large_send == QETH_LARGE_SEND_NO) && | 693 | if ((large_send == QETH_LARGE_SEND_NO) && |
@@ -674,7 +699,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
674 | elements, ctx); | 699 | elements, ctx); |
675 | else | 700 | else |
676 | rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, | 701 | rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, |
677 | elements, ctx); | 702 | elements, ctx, data_offset, hd_len); |
678 | if (!rc) { | 703 | if (!rc) { |
679 | card->stats.tx_packets++; | 704 | card->stats.tx_packets++; |
680 | card->stats.tx_bytes += tx_bytes; | 705 | card->stats.tx_bytes += tx_bytes; |
@@ -701,6 +726,9 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
701 | if (ctx != NULL) | 726 | if (ctx != NULL) |
702 | qeth_eddp_put_context(ctx); | 727 | qeth_eddp_put_context(ctx); |
703 | 728 | ||
729 | if (data_offset >= 0) | ||
730 | kmem_cache_free(qeth_core_header_cache, hdr); | ||
731 | |||
704 | if (rc == -EBUSY) { | 732 | if (rc == -EBUSY) { |
705 | if (new_skb != skb) | 733 | if (new_skb != skb) |
706 | dev_kfree_skb_any(new_skb); | 734 | dev_kfree_skb_any(new_skb); |
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); |