diff options
author | Frank Blaschka <frank.blaschka@de.ibm.com> | 2010-06-21 22:57:10 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-06-23 13:16:36 -0700 |
commit | 51aa165c9f27bbfff498e4d56f3eadf17d74c476 (patch) | |
tree | c2af4e7f534c697f1fc8c14e053f679596a507bf /drivers/s390/net/qeth_l3_main.c | |
parent | 43a65303fe530afe4daf1c0fd6875fdba7090f91 (diff) |
qeth: fix page breaks in hw headers
Turning on memory debugging showed there could be page breaks in
hardware headers. OSA does not allow this so we had to add code
to bounce the header in case there is a page break. This patch also
fixes a problem in case the skb->data part of a fragmented skb
spreads multiple pages.
Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/s390/net/qeth_l3_main.c')
-rw-r--r-- | drivers/s390/net/qeth_l3_main.c | 26 |
1 files changed, 13 insertions, 13 deletions
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index b5733e405ed9..61d348e51920 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2904,19 +2904,11 @@ static inline int qeth_l3_tso_elements(struct sk_buff *skb) unsigned long tcpd = (unsigned long)tcp_hdr(skb) + tcp_hdr(skb)->doff * 4; int tcpd_len = skb->len - (tcpd - (unsigned long)skb->data); - int elements = PFN_UP(tcpd + tcpd_len) - PFN_DOWN(tcpd); + int elements = PFN_UP(tcpd + tcpd_len - 1) - PFN_DOWN(tcpd); elements += skb_shinfo(skb)->nr_frags; return elements; } -static inline int qeth_l3_tso_check(struct sk_buff *skb) -{ - int len = ((unsigned long)tcp_hdr(skb) + tcp_hdr(skb)->doff * 4) - - (unsigned long)skb->data; - return (((unsigned long)skb->data & PAGE_MASK) != - (((unsigned long)skb->data + len) & PAGE_MASK)); -} - static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { int rc; @@ -3016,8 +3008,6 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) (cast_type == RTN_UNSPEC)) { hdr = (struct qeth_hdr *)skb_push(new_skb, sizeof(struct qeth_hdr_tso)); - if (qeth_l3_tso_check(new_skb)) - QETH_DBF_MESSAGE(2, "tso skb misaligned\n"); memset(hdr, 0, sizeof(struct qeth_hdr_tso)); qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type); qeth_tso_fill_header(card, hdr, new_skb); @@ -3048,10 +3038,20 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) elements_needed += elems; nr_frags = skb_shinfo(new_skb)->nr_frags; - if (card->info.type != QETH_CARD_TYPE_IQD) + if (card->info.type != QETH_CARD_TYPE_IQD) { + int len; + if (large_send == QETH_LARGE_SEND_TSO) + len = ((unsigned long)tcp_hdr(new_skb) + + tcp_hdr(new_skb)->doff * 4) - + (unsigned long)new_skb->data; + else + len = sizeof(struct qeth_hdr_layer3); + + if (qeth_hdr_chk_and_bounce(new_skb, len)) + goto tx_drop; rc = qeth_do_send_packet(card, queue, new_skb, hdr, elements_needed); - else + } else rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, elements_needed, data_offset, 0); |