diff options
-rw-r--r-- | drivers/s390/net/qeth.h | 35 | ||||
-rw-r--r-- | drivers/s390/net/qeth_main.c | 193 | ||||
-rw-r--r-- | drivers/s390/net/qeth_tso.h | 2 |
3 files changed, 114 insertions, 116 deletions
diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h index e8bd8c5ced1f..c04ee915dc1b 100644 --- a/drivers/s390/net/qeth.h +++ b/drivers/s390/net/qeth.h | |||
@@ -859,23 +859,18 @@ qeth_get_ipa_adp_type(enum qeth_link_types link_type) | |||
859 | } | 859 | } |
860 | } | 860 | } |
861 | 861 | ||
862 | static inline int | 862 | static inline struct sk_buff * |
863 | qeth_realloc_headroom(struct qeth_card *card, struct sk_buff **skb, int size) | 863 | qeth_realloc_headroom(struct qeth_card *card, struct sk_buff *skb, int size) |
864 | { | 864 | { |
865 | struct sk_buff *new_skb = NULL; | 865 | struct sk_buff *new_skb = skb; |
866 | 866 | ||
867 | if (skb_headroom(*skb) < size){ | 867 | if (skb_headroom(skb) >= size) |
868 | new_skb = skb_realloc_headroom(*skb, size); | 868 | return skb; |
869 | if (!new_skb) { | 869 | new_skb = skb_realloc_headroom(skb, size); |
870 | PRINT_ERR("qeth_prepare_skb: could " | 870 | if (!new_skb) |
871 | "not realloc headroom for qeth_hdr " | 871 | PRINT_ERR("Could not realloc headroom for qeth_hdr " |
872 | "on interface %s", QETH_CARD_IFNAME(card)); | 872 | "on interface %s", QETH_CARD_IFNAME(card)); |
873 | return -ENOMEM; | 873 | return new_skb; |
874 | } | ||
875 | kfree_skb(*skb); | ||
876 | *skb = new_skb; | ||
877 | } | ||
878 | return 0; | ||
879 | } | 874 | } |
880 | 875 | ||
881 | static inline struct sk_buff * | 876 | static inline struct sk_buff * |
@@ -885,16 +880,15 @@ qeth_pskb_unshare(struct sk_buff *skb, int pri) | |||
885 | if (!skb_cloned(skb)) | 880 | if (!skb_cloned(skb)) |
886 | return skb; | 881 | return skb; |
887 | nskb = skb_copy(skb, pri); | 882 | nskb = skb_copy(skb, pri); |
888 | kfree_skb(skb); /* free our shared copy */ | ||
889 | return nskb; | 883 | return nskb; |
890 | } | 884 | } |
891 | 885 | ||
892 | static inline void * | 886 | static inline void * |
893 | qeth_push_skb(struct qeth_card *card, struct sk_buff **skb, int size) | 887 | qeth_push_skb(struct qeth_card *card, struct sk_buff *skb, int size) |
894 | { | 888 | { |
895 | void *hdr; | 889 | void *hdr; |
896 | 890 | ||
897 | hdr = (void *) skb_push(*skb, size); | 891 | hdr = (void *) skb_push(skb, size); |
898 | /* | 892 | /* |
899 | * sanity check, the Linux memory allocation scheme should | 893 | * sanity check, the Linux memory allocation scheme should |
900 | * never present us cases like this one (the qdio header size plus | 894 | * never present us cases like this one (the qdio header size plus |
@@ -903,8 +897,7 @@ qeth_push_skb(struct qeth_card *card, struct sk_buff **skb, int size) | |||
903 | if ((((unsigned long) hdr) & (~(PAGE_SIZE - 1))) != | 897 | if ((((unsigned long) hdr) & (~(PAGE_SIZE - 1))) != |
904 | (((unsigned long) hdr + size + | 898 | (((unsigned long) hdr + size + |
905 | QETH_IP_HEADER_SIZE) & (~(PAGE_SIZE - 1)))) { | 899 | QETH_IP_HEADER_SIZE) & (~(PAGE_SIZE - 1)))) { |
906 | PRINT_ERR("qeth_prepare_skb: misaligned " | 900 | PRINT_ERR("Misaligned packet on interface %s. Discarded.", |
907 | "packet on interface %s. Discarded.", | ||
908 | QETH_CARD_IFNAME(card)); | 901 | QETH_CARD_IFNAME(card)); |
909 | return NULL; | 902 | return NULL; |
910 | } | 903 | } |
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index ffff7a12b54d..522fb9dd551e 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c | |||
@@ -3919,49 +3919,59 @@ qeth_get_ip_version(struct sk_buff *skb) | |||
3919 | } | 3919 | } |
3920 | } | 3920 | } |
3921 | 3921 | ||
3922 | static inline int | 3922 | static inline struct qeth_hdr * |
3923 | qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb, | 3923 | __qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, int ipv) |
3924 | struct qeth_hdr **hdr, int ipv) | ||
3925 | { | 3924 | { |
3926 | int rc = 0; | ||
3927 | #ifdef CONFIG_QETH_VLAN | 3925 | #ifdef CONFIG_QETH_VLAN |
3928 | u16 *tag; | 3926 | u16 *tag; |
3929 | #endif | 3927 | if (card->vlangrp && vlan_tx_tag_present(skb) && |
3930 | |||
3931 | QETH_DBF_TEXT(trace, 6, "prepskb"); | ||
3932 | if (card->info.type == QETH_CARD_TYPE_OSN) { | ||
3933 | *hdr = (struct qeth_hdr *)(*skb)->data; | ||
3934 | return rc; | ||
3935 | } | ||
3936 | rc = qeth_realloc_headroom(card, skb, sizeof(struct qeth_hdr)); | ||
3937 | if (rc) | ||
3938 | return rc; | ||
3939 | #ifdef CONFIG_QETH_VLAN | ||
3940 | if (card->vlangrp && vlan_tx_tag_present(*skb) && | ||
3941 | ((ipv == 6) || card->options.layer2) ) { | 3928 | ((ipv == 6) || card->options.layer2) ) { |
3942 | /* | 3929 | /* |
3943 | * Move the mac addresses (6 bytes src, 6 bytes dest) | 3930 | * Move the mac addresses (6 bytes src, 6 bytes dest) |
3944 | * to the beginning of the new header. We are using three | 3931 | * to the beginning of the new header. We are using three |
3945 | * memcpys instead of one memmove to save cycles. | 3932 | * memcpys instead of one memmove to save cycles. |
3946 | */ | 3933 | */ |
3947 | skb_push(*skb, VLAN_HLEN); | 3934 | skb_push(skb, VLAN_HLEN); |
3948 | memcpy((*skb)->data, (*skb)->data + 4, 4); | 3935 | memcpy(skb->data, skb->data + 4, 4); |
3949 | memcpy((*skb)->data + 4, (*skb)->data + 8, 4); | 3936 | memcpy(skb->data + 4, skb->data + 8, 4); |
3950 | memcpy((*skb)->data + 8, (*skb)->data + 12, 4); | 3937 | memcpy(skb->data + 8, skb->data + 12, 4); |
3951 | tag = (u16 *)((*skb)->data + 12); | 3938 | tag = (u16 *)(skb->data + 12); |
3952 | /* | 3939 | /* |
3953 | * first two bytes = ETH_P_8021Q (0x8100) | 3940 | * first two bytes = ETH_P_8021Q (0x8100) |
3954 | * second two bytes = VLANID | 3941 | * second two bytes = VLANID |
3955 | */ | 3942 | */ |
3956 | *tag = __constant_htons(ETH_P_8021Q); | 3943 | *tag = __constant_htons(ETH_P_8021Q); |
3957 | *(tag + 1) = htons(vlan_tx_tag_get(*skb)); | 3944 | *(tag + 1) = htons(vlan_tx_tag_get(skb)); |
3958 | } | 3945 | } |
3959 | #endif | 3946 | #endif |
3960 | *hdr = (struct qeth_hdr *) | 3947 | return ((struct qeth_hdr *) |
3961 | qeth_push_skb(card, skb, sizeof(struct qeth_hdr)); | 3948 | qeth_push_skb(card, skb, sizeof(struct qeth_hdr))); |
3962 | if (*hdr == NULL) | 3949 | } |
3963 | return -EINVAL; | 3950 | |
3964 | return 0; | 3951 | static inline void |
3952 | __qeth_free_new_skb(struct sk_buff *orig_skb, struct sk_buff *new_skb) | ||
3953 | { | ||
3954 | if (orig_skb != new_skb) | ||
3955 | dev_kfree_skb_any(new_skb); | ||
3956 | } | ||
3957 | |||
3958 | static inline struct sk_buff * | ||
3959 | qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, | ||
3960 | struct qeth_hdr **hdr, int ipv) | ||
3961 | { | ||
3962 | struct sk_buff *new_skb; | ||
3963 | |||
3964 | QETH_DBF_TEXT(trace, 6, "prepskb"); | ||
3965 | |||
3966 | new_skb = qeth_realloc_headroom(card, skb, sizeof(struct qeth_hdr)); | ||
3967 | if (new_skb == NULL) | ||
3968 | return NULL; | ||
3969 | *hdr = __qeth_prepare_skb(card, new_skb, ipv); | ||
3970 | if (*hdr == NULL) { | ||
3971 | __qeth_free_new_skb(skb, new_skb); | ||
3972 | return NULL; | ||
3973 | } | ||
3974 | return new_skb; | ||
3965 | } | 3975 | } |
3966 | 3976 | ||
3967 | static inline u8 | 3977 | static inline u8 |
@@ -4242,21 +4252,15 @@ qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue, | |||
4242 | * check if buffer is empty to make sure that we do not 'overtake' | 4252 | * check if buffer is empty to make sure that we do not 'overtake' |
4243 | * ourselves and try to fill a buffer that is already primed | 4253 | * ourselves and try to fill a buffer that is already primed |
4244 | */ | 4254 | */ |
4245 | if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) { | 4255 | if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) |
4246 | card->stats.tx_dropped++; | 4256 | goto out; |
4247 | atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); | ||
4248 | return -EBUSY; | ||
4249 | } | ||
4250 | if (ctx == NULL) | 4257 | if (ctx == NULL) |
4251 | queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % | 4258 | queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % |
4252 | QDIO_MAX_BUFFERS_PER_Q; | 4259 | QDIO_MAX_BUFFERS_PER_Q; |
4253 | else { | 4260 | else { |
4254 | buffers_needed = qeth_eddp_check_buffers_for_context(queue,ctx); | 4261 | buffers_needed = qeth_eddp_check_buffers_for_context(queue,ctx); |
4255 | if (buffers_needed < 0) { | 4262 | if (buffers_needed < 0) |
4256 | card->stats.tx_dropped++; | 4263 | goto out; |
4257 | atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); | ||
4258 | return -EBUSY; | ||
4259 | } | ||
4260 | queue->next_buf_to_fill = | 4264 | queue->next_buf_to_fill = |
4261 | (queue->next_buf_to_fill + buffers_needed) % | 4265 | (queue->next_buf_to_fill + buffers_needed) % |
4262 | QDIO_MAX_BUFFERS_PER_Q; | 4266 | QDIO_MAX_BUFFERS_PER_Q; |
@@ -4271,6 +4275,9 @@ qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue, | |||
4271 | qeth_flush_buffers(queue, 0, index, flush_cnt); | 4275 | qeth_flush_buffers(queue, 0, index, flush_cnt); |
4272 | } | 4276 | } |
4273 | return 0; | 4277 | return 0; |
4278 | out: | ||
4279 | atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); | ||
4280 | return -EBUSY; | ||
4274 | } | 4281 | } |
4275 | 4282 | ||
4276 | static inline int | 4283 | static inline int |
@@ -4296,8 +4303,7 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, | |||
4296 | * check if buffer is empty to make sure that we do not 'overtake' | 4303 | * check if buffer is empty to make sure that we do not 'overtake' |
4297 | * ourselves and try to fill a buffer that is already primed | 4304 | * ourselves and try to fill a buffer that is already primed |
4298 | */ | 4305 | */ |
4299 | if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY){ | 4306 | if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) { |
4300 | card->stats.tx_dropped++; | ||
4301 | atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); | 4307 | atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); |
4302 | return -EBUSY; | 4308 | return -EBUSY; |
4303 | } | 4309 | } |
@@ -4320,7 +4326,6 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, | |||
4320 | * again */ | 4326 | * again */ |
4321 | if (atomic_read(&buffer->state) != | 4327 | if (atomic_read(&buffer->state) != |
4322 | QETH_QDIO_BUF_EMPTY){ | 4328 | QETH_QDIO_BUF_EMPTY){ |
4323 | card->stats.tx_dropped++; | ||
4324 | qeth_flush_buffers(queue, 0, start_index, flush_count); | 4329 | qeth_flush_buffers(queue, 0, start_index, flush_count); |
4325 | atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); | 4330 | atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); |
4326 | return -EBUSY; | 4331 | return -EBUSY; |
@@ -4331,7 +4336,6 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, | |||
4331 | * free buffers) to handle eddp context */ | 4336 | * free buffers) to handle eddp context */ |
4332 | if (qeth_eddp_check_buffers_for_context(queue,ctx) < 0){ | 4337 | if (qeth_eddp_check_buffers_for_context(queue,ctx) < 0){ |
4333 | printk("eddp tx_dropped 1\n"); | 4338 | printk("eddp tx_dropped 1\n"); |
4334 | card->stats.tx_dropped++; | ||
4335 | rc = -EBUSY; | 4339 | rc = -EBUSY; |
4336 | goto out; | 4340 | goto out; |
4337 | } | 4341 | } |
@@ -4343,7 +4347,6 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, | |||
4343 | tmp = qeth_eddp_fill_buffer(queue,ctx,queue->next_buf_to_fill); | 4347 | tmp = qeth_eddp_fill_buffer(queue,ctx,queue->next_buf_to_fill); |
4344 | if (tmp < 0) { | 4348 | if (tmp < 0) { |
4345 | printk("eddp tx_dropped 2\n"); | 4349 | printk("eddp tx_dropped 2\n"); |
4346 | card->stats.tx_dropped++; | ||
4347 | rc = - EBUSY; | 4350 | rc = - EBUSY; |
4348 | goto out; | 4351 | goto out; |
4349 | } | 4352 | } |
@@ -4391,21 +4394,21 @@ qeth_get_elements_no(struct qeth_card *card, void *hdr, | |||
4391 | { | 4394 | { |
4392 | int elements_needed = 0; | 4395 | int elements_needed = 0; |
4393 | 4396 | ||
4394 | if (skb_shinfo(skb)->nr_frags > 0) { | 4397 | if (skb_shinfo(skb)->nr_frags > 0) |
4395 | elements_needed = (skb_shinfo(skb)->nr_frags + 1); | 4398 | elements_needed = (skb_shinfo(skb)->nr_frags + 1); |
4396 | } | 4399 | if (elements_needed == 0) |
4397 | if (elements_needed == 0 ) | ||
4398 | elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE) | 4400 | elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE) |
4399 | + skb->len) >> PAGE_SHIFT); | 4401 | + skb->len) >> PAGE_SHIFT); |
4400 | if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)){ | 4402 | if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)){ |
4401 | PRINT_ERR("qeth_do_send_packet: invalid size of " | 4403 | PRINT_ERR("Invalid size of IP packet " |
4402 | "IP packet (Number=%d / Length=%d). Discarded.\n", | 4404 | "(Number=%d / Length=%d). Discarded.\n", |
4403 | (elements_needed+elems), skb->len); | 4405 | (elements_needed+elems), skb->len); |
4404 | return 0; | 4406 | return 0; |
4405 | } | 4407 | } |
4406 | return elements_needed; | 4408 | return elements_needed; |
4407 | } | 4409 | } |
4408 | 4410 | ||
4411 | |||
4409 | static inline int | 4412 | static inline int |
4410 | qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) | 4413 | qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) |
4411 | { | 4414 | { |
@@ -4421,108 +4424,110 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) | |||
4421 | unsigned short nr_frags = skb_shinfo(skb)->nr_frags; | 4424 | unsigned short nr_frags = skb_shinfo(skb)->nr_frags; |
4422 | unsigned short tso_size = skb_shinfo(skb)->gso_size; | 4425 | unsigned short tso_size = skb_shinfo(skb)->gso_size; |
4423 | #endif | 4426 | #endif |
4427 | struct sk_buff *new_skb, *new_skb2; | ||
4424 | int rc; | 4428 | int rc; |
4425 | 4429 | ||
4426 | QETH_DBF_TEXT(trace, 6, "sendpkt"); | 4430 | QETH_DBF_TEXT(trace, 6, "sendpkt"); |
4427 | 4431 | ||
4432 | new_skb = skb; | ||
4433 | if ((card->info.type == QETH_CARD_TYPE_OSN) && | ||
4434 | (skb->protocol == htons(ETH_P_IPV6))) | ||
4435 | return -EPERM; | ||
4436 | cast_type = qeth_get_cast_type(card, skb); | ||
4437 | if ((cast_type == RTN_BROADCAST) && | ||
4438 | (card->info.broadcast_capable == 0)) | ||
4439 | return -EPERM; | ||
4440 | queue = card->qdio.out_qs | ||
4441 | [qeth_get_priority_queue(card, skb, ipv, cast_type)]; | ||
4428 | if (!card->options.layer2) { | 4442 | if (!card->options.layer2) { |
4429 | ipv = qeth_get_ip_version(skb); | 4443 | ipv = qeth_get_ip_version(skb); |
4430 | if ((card->dev->hard_header == qeth_fake_header) && ipv) { | 4444 | if ((card->dev->hard_header == qeth_fake_header) && ipv) { |
4431 | if ((skb = qeth_pskb_unshare(skb,GFP_ATOMIC)) == NULL) { | 4445 | new_skb = qeth_pskb_unshare(skb, GFP_ATOMIC); |
4432 | card->stats.tx_dropped++; | 4446 | if (!new_skb) |
4433 | dev_kfree_skb_irq(skb); | 4447 | return -ENOMEM; |
4434 | return 0; | ||
4435 | } | ||
4436 | if(card->dev->type == ARPHRD_IEEE802_TR){ | 4448 | if(card->dev->type == ARPHRD_IEEE802_TR){ |
4437 | skb_pull(skb, QETH_FAKE_LL_LEN_TR); | 4449 | skb_pull(new_skb, QETH_FAKE_LL_LEN_TR); |
4438 | } else { | 4450 | } else { |
4439 | skb_pull(skb, QETH_FAKE_LL_LEN_ETH); | 4451 | skb_pull(new_skb, QETH_FAKE_LL_LEN_ETH); |
4440 | } | 4452 | } |
4441 | } | 4453 | } |
4442 | } | 4454 | } |
4443 | if ((card->info.type == QETH_CARD_TYPE_OSN) && | ||
4444 | (skb->protocol == htons(ETH_P_IPV6))) { | ||
4445 | dev_kfree_skb_any(skb); | ||
4446 | return 0; | ||
4447 | } | ||
4448 | cast_type = qeth_get_cast_type(card, skb); | ||
4449 | if ((cast_type == RTN_BROADCAST) && | ||
4450 | (card->info.broadcast_capable == 0)){ | ||
4451 | card->stats.tx_dropped++; | ||
4452 | card->stats.tx_errors++; | ||
4453 | dev_kfree_skb_any(skb); | ||
4454 | return NETDEV_TX_OK; | ||
4455 | } | ||
4456 | queue = card->qdio.out_qs | ||
4457 | [qeth_get_priority_queue(card, skb, ipv, cast_type)]; | ||
4458 | |||
4459 | if (skb_is_gso(skb)) | 4455 | if (skb_is_gso(skb)) |
4460 | large_send = card->options.large_send; | 4456 | large_send = card->options.large_send; |
4461 | 4457 | /* check on OSN device*/ | |
4462 | /*are we able to do TSO ? If so ,prepare and send it from here */ | 4458 | if (card->info.type == QETH_CARD_TYPE_OSN) |
4459 | hdr = (struct qeth_hdr *)new_skb->data; | ||
4460 | /*are we able to do TSO ? */ | ||
4463 | if ((large_send == QETH_LARGE_SEND_TSO) && | 4461 | if ((large_send == QETH_LARGE_SEND_TSO) && |
4464 | (cast_type == RTN_UNSPEC)) { | 4462 | (cast_type == RTN_UNSPEC)) { |
4465 | rc = qeth_tso_prepare_packet(card, skb, ipv, cast_type); | 4463 | rc = qeth_tso_prepare_packet(card, new_skb, ipv, cast_type); |
4466 | if (rc) { | 4464 | if (rc) { |
4467 | card->stats.tx_dropped++; | 4465 | __qeth_free_new_skb(skb, new_skb); |
4468 | card->stats.tx_errors++; | 4466 | return rc; |
4469 | dev_kfree_skb_any(skb); | ||
4470 | return NETDEV_TX_OK; | ||
4471 | } | 4467 | } |
4472 | elements_needed++; | 4468 | elements_needed++; |
4473 | } else { | 4469 | } else if (card->info.type != QETH_CARD_TYPE_OSN) { |
4474 | if ((rc = qeth_prepare_skb(card, &skb, &hdr, ipv))) { | 4470 | new_skb2 = qeth_prepare_skb(card, new_skb, &hdr, ipv); |
4475 | QETH_DBF_TEXT_(trace, 4, "pskbe%d", rc); | 4471 | if (!new_skb2) { |
4476 | return rc; | 4472 | __qeth_free_new_skb(skb, new_skb); |
4473 | return -EINVAL; | ||
4477 | } | 4474 | } |
4478 | if (card->info.type != QETH_CARD_TYPE_OSN) | 4475 | if (new_skb != skb) |
4479 | qeth_fill_header(card, hdr, skb, ipv, cast_type); | 4476 | __qeth_free_new_skb(new_skb2, new_skb); |
4477 | new_skb = new_skb2; | ||
4478 | qeth_fill_header(card, hdr, new_skb, ipv, cast_type); | ||
4480 | } | 4479 | } |
4481 | |||
4482 | if (large_send == QETH_LARGE_SEND_EDDP) { | 4480 | if (large_send == QETH_LARGE_SEND_EDDP) { |
4483 | ctx = qeth_eddp_create_context(card, skb, hdr); | 4481 | ctx = qeth_eddp_create_context(card, new_skb, hdr); |
4484 | if (ctx == NULL) { | 4482 | if (ctx == NULL) { |
4483 | __qeth_free_new_skb(skb, new_skb); | ||
4485 | PRINT_WARN("could not create eddp context\n"); | 4484 | PRINT_WARN("could not create eddp context\n"); |
4486 | return -EINVAL; | 4485 | return -EINVAL; |
4487 | } | 4486 | } |
4488 | } else { | 4487 | } else { |
4489 | int elems = qeth_get_elements_no(card,(void*) hdr, skb, | 4488 | int elems = qeth_get_elements_no(card,(void*) hdr, new_skb, |
4490 | elements_needed); | 4489 | elements_needed); |
4491 | if (!elems) | 4490 | if (!elems) { |
4491 | __qeth_free_new_skb(skb, new_skb); | ||
4492 | return -EINVAL; | 4492 | return -EINVAL; |
4493 | } | ||
4493 | elements_needed += elems; | 4494 | elements_needed += elems; |
4494 | } | 4495 | } |
4495 | 4496 | ||
4496 | if (card->info.type != QETH_CARD_TYPE_IQD) | 4497 | if (card->info.type != QETH_CARD_TYPE_IQD) |
4497 | rc = qeth_do_send_packet(card, queue, skb, hdr, | 4498 | rc = qeth_do_send_packet(card, queue, new_skb, hdr, |
4498 | elements_needed, ctx); | 4499 | elements_needed, ctx); |
4499 | else | 4500 | else |
4500 | rc = qeth_do_send_packet_fast(card, queue, skb, hdr, | 4501 | rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, |
4501 | elements_needed, ctx); | 4502 | elements_needed, ctx); |
4502 | if (!rc){ | 4503 | if (!rc) { |
4503 | card->stats.tx_packets++; | 4504 | card->stats.tx_packets++; |
4504 | card->stats.tx_bytes += tx_bytes; | 4505 | card->stats.tx_bytes += tx_bytes; |
4506 | if (new_skb != skb) | ||
4507 | dev_kfree_skb_any(skb); | ||
4505 | #ifdef CONFIG_QETH_PERF_STATS | 4508 | #ifdef CONFIG_QETH_PERF_STATS |
4506 | if (tso_size && | 4509 | if (tso_size && |
4507 | !(large_send == QETH_LARGE_SEND_NO)) { | 4510 | !(large_send == QETH_LARGE_SEND_NO)) { |
4508 | card->perf_stats.large_send_bytes += tx_bytes; | 4511 | card->perf_stats.large_send_bytes += tx_bytes; |
4509 | card->perf_stats.large_send_cnt++; | 4512 | card->perf_stats.large_send_cnt++; |
4510 | } | 4513 | } |
4511 | if (nr_frags > 0){ | 4514 | if (nr_frags > 0) { |
4512 | card->perf_stats.sg_skbs_sent++; | 4515 | card->perf_stats.sg_skbs_sent++; |
4513 | /* nr_frags + skb->data */ | 4516 | /* nr_frags + skb->data */ |
4514 | card->perf_stats.sg_frags_sent += | 4517 | card->perf_stats.sg_frags_sent += |
4515 | nr_frags + 1; | 4518 | nr_frags + 1; |
4516 | } | 4519 | } |
4517 | #endif /* CONFIG_QETH_PERF_STATS */ | 4520 | #endif /* CONFIG_QETH_PERF_STATS */ |
4521 | } else { | ||
4522 | card->stats.tx_dropped++; | ||
4523 | __qeth_free_new_skb(skb, new_skb); | ||
4518 | } | 4524 | } |
4519 | if (ctx != NULL) { | 4525 | if (ctx != NULL) { |
4520 | /* drop creator's reference */ | 4526 | /* drop creator's reference */ |
4521 | qeth_eddp_put_context(ctx); | 4527 | qeth_eddp_put_context(ctx); |
4522 | /* free skb; it's not referenced by a buffer */ | 4528 | /* free skb; it's not referenced by a buffer */ |
4523 | if (rc == 0) | 4529 | if (!rc) |
4524 | dev_kfree_skb_any(skb); | 4530 | dev_kfree_skb_any(new_skb); |
4525 | |||
4526 | } | 4531 | } |
4527 | return rc; | 4532 | return rc; |
4528 | } | 4533 | } |
diff --git a/drivers/s390/net/qeth_tso.h b/drivers/s390/net/qeth_tso.h index 593f298142c1..14504afb044e 100644 --- a/drivers/s390/net/qeth_tso.h +++ b/drivers/s390/net/qeth_tso.h | |||
@@ -24,7 +24,7 @@ static inline struct qeth_hdr_tso * | |||
24 | qeth_tso_prepare_skb(struct qeth_card *card, struct sk_buff **skb) | 24 | qeth_tso_prepare_skb(struct qeth_card *card, struct sk_buff **skb) |
25 | { | 25 | { |
26 | QETH_DBF_TEXT(trace, 5, "tsoprsk"); | 26 | QETH_DBF_TEXT(trace, 5, "tsoprsk"); |
27 | return qeth_push_skb(card, skb, sizeof(struct qeth_hdr_tso)); | 27 | return qeth_push_skb(card, *skb, sizeof(struct qeth_hdr_tso)); |
28 | } | 28 | } |
29 | 29 | ||
30 | /** | 30 | /** |