aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorFrank Blaschka <frank.blaschka@de.ibm.com>2010-06-21 18:57:10 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-23 16:16:36 -0400
commit51aa165c9f27bbfff498e4d56f3eadf17d74c476 (patch)
treec2af4e7f534c697f1fc8c14e053f679596a507bf /drivers
parent43a65303fe530afe4daf1c0fd6875fdba7090f91 (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')
-rw-r--r--drivers/s390/net/qeth_core.h1
-rw-r--r--drivers/s390/net/qeth_core_main.c104
-rw-r--r--drivers/s390/net/qeth_l2_main.c7
-rw-r--r--drivers/s390/net/qeth_l3_main.c26
4 files changed, 65 insertions, 73 deletions
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 0b4250d3a25d..d79892782a2b 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -869,6 +869,7 @@ void qeth_core_get_drvinfo(struct net_device *, struct ethtool_drvinfo *);
869void qeth_dbf_longtext(debug_info_t *id, int level, char *text, ...); 869void qeth_dbf_longtext(debug_info_t *id, int level, char *text, ...);
870int qeth_core_ethtool_get_settings(struct net_device *, struct ethtool_cmd *); 870int qeth_core_ethtool_get_settings(struct net_device *, struct ethtool_cmd *);
871int qeth_set_access_ctrl_online(struct qeth_card *card); 871int qeth_set_access_ctrl_online(struct qeth_card *card);
872int qeth_hdr_chk_and_bounce(struct sk_buff *, int);
872 873
873/* exports for OSN */ 874/* exports for OSN */
874int qeth_osn_assist(struct net_device *, void *, int); 875int qeth_osn_assist(struct net_device *, void *, int);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 3cdd2705b75a..656a6e78a2ee 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -57,48 +57,6 @@ static void qeth_free_buffer_pool(struct qeth_card *);
57static int qeth_qdio_establish(struct qeth_card *); 57static int qeth_qdio_establish(struct qeth_card *);
58 58
59 59
60static 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
102static inline const char *qeth_get_cardname(struct qeth_card *card) 60static inline const char *qeth_get_cardname(struct qeth_card *card)
103{ 61{
104 if (card->info.guestlan) { 62 if (card->info.guestlan) {
@@ -3020,13 +2978,11 @@ EXPORT_SYMBOL_GPL(qeth_get_priority_queue);
3020int qeth_get_elements_no(struct qeth_card *card, void *hdr, 2978int qeth_get_elements_no(struct qeth_card *card, void *hdr,
3021 struct sk_buff *skb, int elems) 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) 2985 elements_needed += skb_shinfo(skb)->nr_frags;
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);
3030 if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { 2986 if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) {
3031 QETH_DBF_MESSAGE(2, "Invalid size of IP packet " 2987 QETH_DBF_MESSAGE(2, "Invalid size of IP packet "
3032 "(Number=%d / Length=%d). Discarded.\n", 2988 "(Number=%d / Length=%d). Discarded.\n",
@@ -3037,15 +2993,35 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr,
3037} 2993}
3038EXPORT_SYMBOL_GPL(qeth_get_elements_no); 2994EXPORT_SYMBOL_GPL(qeth_get_elements_no);
3039 2995
2996int 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}
3013EXPORT_SYMBOL_GPL(qeth_hdr_chk_and_bounce);
3014
3040static inline void __qeth_fill_buffer(struct sk_buff *skb, 3015static inline void __qeth_fill_buffer(struct sk_buff *skb,
3041 struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill, 3016 struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill,
3042 int offset) 3017 int offset)
3043{ 3018{
3044 int length = skb->len; 3019 int length = skb->len - skb->data_len;
3045 int length_here; 3020 int length_here;
3046 int element; 3021 int element;
3047 char *data; 3022 char *data;
3048 int first_lap ; 3023 int first_lap, cnt;
3024 struct skb_frag_struct *frag;
3049 3025
3050 element = *next_element_to_fill; 3026 element = *next_element_to_fill;
3051 data = skb->data; 3027 data = skb->data;
@@ -3068,10 +3044,14 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb,
3068 length -= length_here; 3044 length -= length_here;
3069 if (!length) { 3045 if (!length) {
3070 if (first_lap) 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 else 3052 else
3073 buffer->element[element].flags = 3053 buffer->element[element].flags =
3074 SBAL_FLAGS_LAST_FRAG; 3054 SBAL_FLAGS_MIDDLE_FRAG;
3075 } else { 3055 } else {
3076 if (first_lap) 3056 if (first_lap)
3077 buffer->element[element].flags = 3057 buffer->element[element].flags =
@@ -3084,6 +3064,18 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb,
3084 element++; 3064 element++;
3085 first_lap = 0; 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 *next_element_to_fill = element; 3079 *next_element_to_fill = element;
3088} 3080}
3089 3081
@@ -3124,12 +3116,8 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue,
3124 buf->next_element_to_fill++; 3116 buf->next_element_to_fill++;
3125 } 3117 }
3126 3118
3127 if (skb_shinfo(skb)->nr_frags == 0) 3119 __qeth_fill_buffer(skb, buffer, large_send,
3128 __qeth_fill_buffer(skb, buffer, large_send, 3120 (int *)&buf->next_element_to_fill, offset);
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);
3133 3121
3134 if (!queue->do_pack) { 3122 if (!queue->do_pack) {
3135 QETH_CARD_TEXT(queue->card, 6, "fillbfnp"); 3123 QETH_CARD_TEXT(queue->card, 6, "fillbfnp");
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index e7942ccab987..32d07c2dcc67 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -712,10 +712,13 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
712 goto tx_drop; 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 rc = qeth_do_send_packet(card, queue, new_skb, hdr, 719 rc = qeth_do_send_packet(card, queue, new_skb, hdr,
717 elements); 720 elements);
718 else 721 } else
719 rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, 722 rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr,
720 elements, data_offset, hd_len); 723 elements, data_offset, hd_len);
721 if (!rc) { 724 if (!rc) {
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)
2904 unsigned long tcpd = (unsigned long)tcp_hdr(skb) + 2904 unsigned long tcpd = (unsigned long)tcp_hdr(skb) +
2905 tcp_hdr(skb)->doff * 4; 2905 tcp_hdr(skb)->doff * 4;
2906 int tcpd_len = skb->len - (tcpd - (unsigned long)skb->data); 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 elements += skb_shinfo(skb)->nr_frags; 2908 elements += skb_shinfo(skb)->nr_frags;
2909 return elements; 2909 return elements;
2910} 2910}
2911 2911
2912static 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
2920static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) 2912static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
2921{ 2913{
2922 int rc; 2914 int rc;
@@ -3016,8 +3008,6 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
3016 (cast_type == RTN_UNSPEC)) { 3008 (cast_type == RTN_UNSPEC)) {
3017 hdr = (struct qeth_hdr *)skb_push(new_skb, 3009 hdr = (struct qeth_hdr *)skb_push(new_skb,
3018 sizeof(struct qeth_hdr_tso)); 3010 sizeof(struct qeth_hdr_tso));
3019 if (qeth_l3_tso_check(new_skb))
3020 QETH_DBF_MESSAGE(2, "tso skb misaligned\n");
3021 memset(hdr, 0, sizeof(struct qeth_hdr_tso)); 3011 memset(hdr, 0, sizeof(struct qeth_hdr_tso));
3022 qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type); 3012 qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type);
3023 qeth_tso_fill_header(card, hdr, new_skb); 3013 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)
3048 elements_needed += elems; 3038 elements_needed += elems;
3049 nr_frags = skb_shinfo(new_skb)->nr_frags; 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 rc = qeth_do_send_packet(card, queue, new_skb, hdr, 3052 rc = qeth_do_send_packet(card, queue, new_skb, hdr,
3053 elements_needed); 3053 elements_needed);
3054 else 3054 } else
3055 rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, 3055 rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr,
3056 elements_needed, data_offset, 0); 3056 elements_needed, data_offset, 0);
3057 3057