Commit 51aa165c9f27bbfff498e4d56f3eadf17d74c476

Authored by Frank Blaschka
Committed by David S. Miller
1 parent 43a65303fe

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>

Showing 4 changed files with 65 additions and 73 deletions Side-by-side Diff

drivers/s390/net/qeth_core.h
... ... @@ -869,6 +869,7 @@
869 869 void qeth_dbf_longtext(debug_info_t *id, int level, char *text, ...);
870 870 int qeth_core_ethtool_get_settings(struct net_device *, struct ethtool_cmd *);
871 871 int qeth_set_access_ctrl_online(struct qeth_card *card);
  872 +int qeth_hdr_chk_and_bounce(struct sk_buff *, int);
872 873  
873 874 /* exports for OSN */
874 875 int qeth_osn_assist(struct net_device *, void *, int);
drivers/s390/net/qeth_core_main.c
... ... @@ -57,48 +57,6 @@
57 57 static int qeth_qdio_establish(struct qeth_card *);
58 58  
59 59  
60   -static inline void __qeth_fill_buffer_frag(struct sk_buff *skb,
61   - struct qdio_buffer *buffer, int is_tso,
62   - int *next_element_to_fill)
63   -{
64   - struct skb_frag_struct *frag;
65   - int fragno;
66   - unsigned long addr;
67   - int element, cnt, dlen;
68   -
69   - fragno = skb_shinfo(skb)->nr_frags;
70   - element = *next_element_to_fill;
71   - dlen = 0;
72   -
73   - if (is_tso)
74   - buffer->element[element].flags =
75   - SBAL_FLAGS_MIDDLE_FRAG;
76   - else
77   - buffer->element[element].flags =
78   - SBAL_FLAGS_FIRST_FRAG;
79   - dlen = skb->len - skb->data_len;
80   - if (dlen) {
81   - buffer->element[element].addr = skb->data;
82   - buffer->element[element].length = dlen;
83   - element++;
84   - }
85   - for (cnt = 0; cnt < fragno; cnt++) {
86   - frag = &skb_shinfo(skb)->frags[cnt];
87   - addr = (page_to_pfn(frag->page) << PAGE_SHIFT) +
88   - frag->page_offset;
89   - buffer->element[element].addr = (char *)addr;
90   - buffer->element[element].length = frag->size;
91   - if (cnt < (fragno - 1))
92   - buffer->element[element].flags =
93   - SBAL_FLAGS_MIDDLE_FRAG;
94   - else
95   - buffer->element[element].flags =
96   - SBAL_FLAGS_LAST_FRAG;
97   - element++;
98   - }
99   - *next_element_to_fill = element;
100   -}
101   -
102 60 static inline const char *qeth_get_cardname(struct qeth_card *card)
103 61 {
104 62 if (card->info.guestlan) {
105 63  
... ... @@ -3020,13 +2978,11 @@
3020 2978 int qeth_get_elements_no(struct qeth_card *card, void *hdr,
3021 2979 struct sk_buff *skb, int elems)
3022 2980 {
3023   - int elements_needed = 0;
  2981 + int dlen = skb->len - skb->data_len;
  2982 + int elements_needed = PFN_UP((unsigned long)skb->data + dlen - 1) -
  2983 + PFN_DOWN((unsigned long)skb->data);
3024 2984  
3025   - if (skb_shinfo(skb)->nr_frags > 0)
3026   - elements_needed = (skb_shinfo(skb)->nr_frags + 1);
3027   - if (elements_needed == 0)
3028   - elements_needed = 1 + (((((unsigned long) skb->data) %
3029   - PAGE_SIZE) + skb->len) >> PAGE_SHIFT);
  2985 + elements_needed += skb_shinfo(skb)->nr_frags;
3030 2986 if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) {
3031 2987 QETH_DBF_MESSAGE(2, "Invalid size of IP packet "
3032 2988 "(Number=%d / Length=%d). Discarded.\n",
3033 2989  
3034 2990  
... ... @@ -3037,15 +2993,35 @@
3037 2993 }
3038 2994 EXPORT_SYMBOL_GPL(qeth_get_elements_no);
3039 2995  
  2996 +int qeth_hdr_chk_and_bounce(struct sk_buff *skb, int len)
  2997 +{
  2998 + int hroom, inpage, rest;
  2999 +
  3000 + if (((unsigned long)skb->data & PAGE_MASK) !=
  3001 + (((unsigned long)skb->data + len - 1) & PAGE_MASK)) {
  3002 + hroom = skb_headroom(skb);
  3003 + inpage = PAGE_SIZE - ((unsigned long) skb->data % PAGE_SIZE);
  3004 + rest = len - inpage;
  3005 + if (rest > hroom)
  3006 + return 1;
  3007 + memmove(skb->data - rest, skb->data, skb->len - skb->data_len);
  3008 + skb->data -= rest;
  3009 + QETH_DBF_MESSAGE(2, "skb bounce len: %d rest: %d\n", len, rest);
  3010 + }
  3011 + return 0;
  3012 +}
  3013 +EXPORT_SYMBOL_GPL(qeth_hdr_chk_and_bounce);
  3014 +
3040 3015 static inline void __qeth_fill_buffer(struct sk_buff *skb,
3041 3016 struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill,
3042 3017 int offset)
3043 3018 {
3044   - int length = skb->len;
  3019 + int length = skb->len - skb->data_len;
3045 3020 int length_here;
3046 3021 int element;
3047 3022 char *data;
3048   - int first_lap ;
  3023 + int first_lap, cnt;
  3024 + struct skb_frag_struct *frag;
3049 3025  
3050 3026 element = *next_element_to_fill;
3051 3027 data = skb->data;
3052 3028  
... ... @@ -3068,10 +3044,14 @@
3068 3044 length -= length_here;
3069 3045 if (!length) {
3070 3046 if (first_lap)
3071   - buffer->element[element].flags = 0;
  3047 + if (skb_shinfo(skb)->nr_frags)
  3048 + buffer->element[element].flags =
  3049 + SBAL_FLAGS_FIRST_FRAG;
  3050 + else
  3051 + buffer->element[element].flags = 0;
3072 3052 else
3073 3053 buffer->element[element].flags =
3074   - SBAL_FLAGS_LAST_FRAG;
  3054 + SBAL_FLAGS_MIDDLE_FRAG;
3075 3055 } else {
3076 3056 if (first_lap)
3077 3057 buffer->element[element].flags =
... ... @@ -3084,6 +3064,18 @@
3084 3064 element++;
3085 3065 first_lap = 0;
3086 3066 }
  3067 +
  3068 + for (cnt = 0; cnt < skb_shinfo(skb)->nr_frags; cnt++) {
  3069 + frag = &skb_shinfo(skb)->frags[cnt];
  3070 + buffer->element[element].addr = (char *)page_to_phys(frag->page)
  3071 + + frag->page_offset;
  3072 + buffer->element[element].length = frag->size;
  3073 + buffer->element[element].flags = SBAL_FLAGS_MIDDLE_FRAG;
  3074 + element++;
  3075 + }
  3076 +
  3077 + if (buffer->element[element - 1].flags)
  3078 + buffer->element[element - 1].flags = SBAL_FLAGS_LAST_FRAG;
3087 3079 *next_element_to_fill = element;
3088 3080 }
3089 3081  
... ... @@ -3124,12 +3116,8 @@
3124 3116 buf->next_element_to_fill++;
3125 3117 }
3126 3118  
3127   - if (skb_shinfo(skb)->nr_frags == 0)
3128   - __qeth_fill_buffer(skb, buffer, large_send,
3129   - (int *)&buf->next_element_to_fill, offset);
3130   - else
3131   - __qeth_fill_buffer_frag(skb, buffer, large_send,
3132   - (int *)&buf->next_element_to_fill);
  3119 + __qeth_fill_buffer(skb, buffer, large_send,
  3120 + (int *)&buf->next_element_to_fill, offset);
3133 3121  
3134 3122 if (!queue->do_pack) {
3135 3123 QETH_CARD_TEXT(queue->card, 6, "fillbfnp");
drivers/s390/net/qeth_l2_main.c
... ... @@ -712,10 +712,13 @@
712 712 goto tx_drop;
713 713 }
714 714  
715   - if (card->info.type != QETH_CARD_TYPE_IQD)
  715 + if (card->info.type != QETH_CARD_TYPE_IQD) {
  716 + if (qeth_hdr_chk_and_bounce(new_skb,
  717 + sizeof(struct qeth_hdr_layer2)))
  718 + goto tx_drop;
716 719 rc = qeth_do_send_packet(card, queue, new_skb, hdr,
717 720 elements);
718   - else
  721 + } else
719 722 rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr,
720 723 elements, data_offset, hd_len);
721 724 if (!rc) {
drivers/s390/net/qeth_l3_main.c
... ... @@ -2904,19 +2904,11 @@
2904 2904 unsigned long tcpd = (unsigned long)tcp_hdr(skb) +
2905 2905 tcp_hdr(skb)->doff * 4;
2906 2906 int tcpd_len = skb->len - (tcpd - (unsigned long)skb->data);
2907   - int elements = PFN_UP(tcpd + tcpd_len) - PFN_DOWN(tcpd);
  2907 + int elements = PFN_UP(tcpd + tcpd_len - 1) - PFN_DOWN(tcpd);
2908 2908 elements += skb_shinfo(skb)->nr_frags;
2909 2909 return elements;
2910 2910 }
2911 2911  
2912   -static inline int qeth_l3_tso_check(struct sk_buff *skb)
2913   -{
2914   - int len = ((unsigned long)tcp_hdr(skb) + tcp_hdr(skb)->doff * 4) -
2915   - (unsigned long)skb->data;
2916   - return (((unsigned long)skb->data & PAGE_MASK) !=
2917   - (((unsigned long)skb->data + len) & PAGE_MASK));
2918   -}
2919   -
2920 2912 static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
2921 2913 {
2922 2914 int rc;
... ... @@ -3016,8 +3008,6 @@
3016 3008 (cast_type == RTN_UNSPEC)) {
3017 3009 hdr = (struct qeth_hdr *)skb_push(new_skb,
3018 3010 sizeof(struct qeth_hdr_tso));
3019   - if (qeth_l3_tso_check(new_skb))
3020   - QETH_DBF_MESSAGE(2, "tso skb misaligned\n");
3021 3011 memset(hdr, 0, sizeof(struct qeth_hdr_tso));
3022 3012 qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type);
3023 3013 qeth_tso_fill_header(card, hdr, new_skb);
3024 3014  
... ... @@ -3048,10 +3038,20 @@
3048 3038 elements_needed += elems;
3049 3039 nr_frags = skb_shinfo(new_skb)->nr_frags;
3050 3040  
3051   - if (card->info.type != QETH_CARD_TYPE_IQD)
  3041 + if (card->info.type != QETH_CARD_TYPE_IQD) {
  3042 + int len;
  3043 + if (large_send == QETH_LARGE_SEND_TSO)
  3044 + len = ((unsigned long)tcp_hdr(new_skb) +
  3045 + tcp_hdr(new_skb)->doff * 4) -
  3046 + (unsigned long)new_skb->data;
  3047 + else
  3048 + len = sizeof(struct qeth_hdr_layer3);
  3049 +
  3050 + if (qeth_hdr_chk_and_bounce(new_skb, len))
  3051 + goto tx_drop;
3052 3052 rc = qeth_do_send_packet(card, queue, new_skb, hdr,
3053 3053 elements_needed);
3054   - else
  3054 + } else
3055 3055 rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr,
3056 3056 elements_needed, data_offset, 0);
3057 3057