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