diff options
author | Frank Blaschka <blaschka@linux.vnet.ibm.com> | 2013-03-18 16:04:44 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-03-19 10:09:40 -0400 |
commit | 271648b4c610eed540daaf9ff366209825757565 (patch) | |
tree | ee2c52b04d138bf6a2e0b837fc3187949c7d2066 /drivers | |
parent | 82e2e782a3e486e3bfcc6130f0ebc28453af9955 (diff) |
qeth: Fix scatter-gather regression
This patch fixes a scatter-gather regression introduced with
commit 5640f768 net: use a per task frag allocator
Now the qeth driver can cope with bigger framents and split a fragment in
sub framents if required.
Signed-off-by: Frank Blaschka <blaschka@linux.vnet.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/s390/net/qeth_core.h | 1 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_main.c | 45 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l3_main.c | 4 |
3 files changed, 42 insertions, 8 deletions
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index d87961d4c0de..8c0622399fcd 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h | |||
@@ -916,6 +916,7 @@ int qeth_send_control_data(struct qeth_card *, int, struct qeth_cmd_buffer *, | |||
916 | void *reply_param); | 916 | void *reply_param); |
917 | int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int); | 917 | int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int); |
918 | int qeth_get_elements_no(struct qeth_card *, void *, struct sk_buff *, int); | 918 | int qeth_get_elements_no(struct qeth_card *, void *, struct sk_buff *, int); |
919 | int qeth_get_elements_for_frags(struct sk_buff *); | ||
919 | int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *, | 920 | int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *, |
920 | struct sk_buff *, struct qeth_hdr *, int, int, int); | 921 | struct sk_buff *, struct qeth_hdr *, int, int, int); |
921 | int qeth_do_send_packet(struct qeth_card *, struct qeth_qdio_out_q *, | 922 | int qeth_do_send_packet(struct qeth_card *, struct qeth_qdio_out_q *, |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 0d8cdff81813..0d73a999983d 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
@@ -3679,6 +3679,25 @@ int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb, | |||
3679 | } | 3679 | } |
3680 | EXPORT_SYMBOL_GPL(qeth_get_priority_queue); | 3680 | EXPORT_SYMBOL_GPL(qeth_get_priority_queue); |
3681 | 3681 | ||
3682 | int qeth_get_elements_for_frags(struct sk_buff *skb) | ||
3683 | { | ||
3684 | int cnt, length, e, elements = 0; | ||
3685 | struct skb_frag_struct *frag; | ||
3686 | char *data; | ||
3687 | |||
3688 | for (cnt = 0; cnt < skb_shinfo(skb)->nr_frags; cnt++) { | ||
3689 | frag = &skb_shinfo(skb)->frags[cnt]; | ||
3690 | data = (char *)page_to_phys(skb_frag_page(frag)) + | ||
3691 | frag->page_offset; | ||
3692 | length = frag->size; | ||
3693 | e = PFN_UP((unsigned long)data + length - 1) - | ||
3694 | PFN_DOWN((unsigned long)data); | ||
3695 | elements += e; | ||
3696 | } | ||
3697 | return elements; | ||
3698 | } | ||
3699 | EXPORT_SYMBOL_GPL(qeth_get_elements_for_frags); | ||
3700 | |||
3682 | int qeth_get_elements_no(struct qeth_card *card, void *hdr, | 3701 | int qeth_get_elements_no(struct qeth_card *card, void *hdr, |
3683 | struct sk_buff *skb, int elems) | 3702 | struct sk_buff *skb, int elems) |
3684 | { | 3703 | { |
@@ -3686,7 +3705,8 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr, | |||
3686 | int elements_needed = PFN_UP((unsigned long)skb->data + dlen - 1) - | 3705 | int elements_needed = PFN_UP((unsigned long)skb->data + dlen - 1) - |
3687 | PFN_DOWN((unsigned long)skb->data); | 3706 | PFN_DOWN((unsigned long)skb->data); |
3688 | 3707 | ||
3689 | elements_needed += skb_shinfo(skb)->nr_frags; | 3708 | elements_needed += qeth_get_elements_for_frags(skb); |
3709 | |||
3690 | if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { | 3710 | if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { |
3691 | QETH_DBF_MESSAGE(2, "Invalid size of IP packet " | 3711 | QETH_DBF_MESSAGE(2, "Invalid size of IP packet " |
3692 | "(Number=%d / Length=%d). Discarded.\n", | 3712 | "(Number=%d / Length=%d). Discarded.\n", |
@@ -3771,12 +3791,23 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb, | |||
3771 | 3791 | ||
3772 | for (cnt = 0; cnt < skb_shinfo(skb)->nr_frags; cnt++) { | 3792 | for (cnt = 0; cnt < skb_shinfo(skb)->nr_frags; cnt++) { |
3773 | frag = &skb_shinfo(skb)->frags[cnt]; | 3793 | frag = &skb_shinfo(skb)->frags[cnt]; |
3774 | buffer->element[element].addr = (char *) | 3794 | data = (char *)page_to_phys(skb_frag_page(frag)) + |
3775 | page_to_phys(skb_frag_page(frag)) | 3795 | frag->page_offset; |
3776 | + frag->page_offset; | 3796 | length = frag->size; |
3777 | buffer->element[element].length = frag->size; | 3797 | while (length > 0) { |
3778 | buffer->element[element].eflags = SBAL_EFLAGS_MIDDLE_FRAG; | 3798 | length_here = PAGE_SIZE - |
3779 | element++; | 3799 | ((unsigned long) data % PAGE_SIZE); |
3800 | if (length < length_here) | ||
3801 | length_here = length; | ||
3802 | |||
3803 | buffer->element[element].addr = data; | ||
3804 | buffer->element[element].length = length_here; | ||
3805 | buffer->element[element].eflags = | ||
3806 | SBAL_EFLAGS_MIDDLE_FRAG; | ||
3807 | length -= length_here; | ||
3808 | data += length_here; | ||
3809 | element++; | ||
3810 | } | ||
3780 | } | 3811 | } |
3781 | 3812 | ||
3782 | if (buffer->element[element - 1].eflags) | 3813 | if (buffer->element[element - 1].eflags) |
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index b6da6cec9c3e..8710337dab3e 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c | |||
@@ -2903,7 +2903,9 @@ static inline int qeth_l3_tso_elements(struct sk_buff *skb) | |||
2903 | tcp_hdr(skb)->doff * 4; | 2903 | tcp_hdr(skb)->doff * 4; |
2904 | int tcpd_len = skb->len - (tcpd - (unsigned long)skb->data); | 2904 | int tcpd_len = skb->len - (tcpd - (unsigned long)skb->data); |
2905 | int elements = PFN_UP(tcpd + tcpd_len - 1) - PFN_DOWN(tcpd); | 2905 | int elements = PFN_UP(tcpd + tcpd_len - 1) - PFN_DOWN(tcpd); |
2906 | elements += skb_shinfo(skb)->nr_frags; | 2906 | |
2907 | elements += qeth_get_elements_for_frags(skb); | ||
2908 | |||
2907 | return elements; | 2909 | return elements; |
2908 | } | 2910 | } |
2909 | 2911 | ||