]> git.ipfire.org Git - ipfire-2.x.git/blob - src/patches/suse-2.6.27.31/patches.arch/s390-11-05-qdio_error_reporting_hs.patch
Add a patch to fix Intel E100 wake-on-lan problems.
[ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.arch / s390-11-05-qdio_error_reporting_hs.patch
1 From: Gerald Schaefer <geraldsc@de.ibm.com>
2 Subject: qdio: fix hipersocket busy error handling
3 References: bnc#484767,LTC#52204
4
5 Symptom: Lower performance of hipersocket connections in case of
6 busy errors.
7 Problem: The immediate retry for a busy condition is missing and the
8 qeth notification about a failed send operation may indicate
9 a wrong buffer position since a temporary SIGA error is not
10 reported immediately.
11 Solution: Retry immediately after a busy condition and report SIGA errors
12 directly to qeth.
13
14 Acked-by: John Jolly <jjolly@suse.de>
15 ---
16 drivers/s390/cio/qdio.h | 7 -
17 drivers/s390/cio/qdio_main.c | 181 ++++++++++++++-----------------------------
18 2 files changed, 63 insertions(+), 125 deletions(-)
19
20 Index: linux-2.6.27-SLE11_BRANCH/drivers/s390/cio/qdio.h
21 ===================================================================
22 --- linux-2.6.27-SLE11_BRANCH.orig/drivers/s390/cio/qdio.h
23 +++ linux-2.6.27-SLE11_BRANCH/drivers/s390/cio/qdio.h
24 @@ -14,7 +14,6 @@
25 #include "chsc.h"
26
27 #define QDIO_BUSY_BIT_PATIENCE 100 /* 100 microseconds */
28 -#define QDIO_BUSY_BIT_GIVE_UP 2000000 /* 2 seconds = eternity */
29 #define QDIO_INPUT_THRESHOLD 500 /* 500 microseconds */
30
31 /*
32 @@ -195,12 +194,6 @@ struct qdio_input_q {
33 };
34
35 struct qdio_output_q {
36 - /* failed siga-w attempts*/
37 - atomic_t busy_siga_counter;
38 -
39 - /* start time of busy condition */
40 - u64 timestamp;
41 -
42 /* PCIs are enabled for the queue */
43 int pci_out_enabled;
44
45 Index: linux-2.6.27-SLE11_BRANCH/drivers/s390/cio/qdio_main.c
46 ===================================================================
47 --- linux-2.6.27-SLE11_BRANCH.orig/drivers/s390/cio/qdio_main.c
48 +++ linux-2.6.27-SLE11_BRANCH/drivers/s390/cio/qdio_main.c
49 @@ -74,7 +74,7 @@ static inline int do_siga_input(struct s
50 * Note: For IQDC unicast queues only the highest priority queue is processed.
51 */
52 static inline int do_siga_output(unsigned long schid, unsigned long mask,
53 - u32 *bb, unsigned int fc)
54 + unsigned int *bb, unsigned int fc)
55 {
56 register unsigned long __fc asm("0") = fc;
57 register unsigned long __schid asm("1") = schid;
58 @@ -278,8 +278,7 @@ static int qdio_siga_sync(struct qdio_q
59 if (!need_siga_sync(q))
60 return 0;
61
62 - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-s:");
63 - DBF_DEV_HEX(DBF_INFO, q->irq_ptr, q, sizeof(void *));
64 + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-s:%1d", q->nr);
65 qdio_perf_stat_inc(&perf_stats.siga_sync);
66
67 cc = do_siga_sync(q->irq_ptr->schid, output, input);
68 @@ -306,43 +305,34 @@ static inline int qdio_siga_sync_all(str
69 return qdio_siga_sync(q, ~0U, ~0U);
70 }
71
72 -static inline int qdio_do_siga_output(struct qdio_q *q, unsigned int *busy_bit)
73 +static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit)
74 {
75 - unsigned int fc = 0;
76 unsigned long schid;
77 + unsigned int fc = 0;
78 + u64 start_time = 0;
79 + int cc;
80
81 - if (!is_qebsm(q))
82 - schid = *((u32 *)&q->irq_ptr->schid);
83 - else {
84 + if (is_qebsm(q)) {
85 schid = q->irq_ptr->sch_token;
86 fc |= 0x80;
87 }
88 - return do_siga_output(schid, q->mask, busy_bit, fc);
89 -}
90 -
91 -static int qdio_siga_output(struct qdio_q *q)
92 -{
93 - int cc;
94 - u32 busy_bit;
95 - u64 start_time = 0;
96 + else
97 + schid = *((u32 *)&q->irq_ptr->schid);
98
99 - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr);
100 - qdio_perf_stat_inc(&perf_stats.siga_out);
101 again:
102 - cc = qdio_do_siga_output(q, &busy_bit);
103 - if (queue_type(q) == QDIO_IQDIO_QFMT && cc == 2 && busy_bit) {
104 - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w bb:%2d", q->nr);
105 + cc = do_siga_output(schid, q->mask, busy_bit, fc);
106
107 - if (!start_time)
108 + /* hipersocket busy condition */
109 + if (*busy_bit) {
110 + WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2);
111 +
112 + if (!start_time) {
113 start_time = get_usecs();
114 - else if ((get_usecs() - start_time) < QDIO_BUSY_BIT_PATIENCE)
115 + goto again;
116 + }
117 + if ((get_usecs() - start_time) < QDIO_BUSY_BIT_PATIENCE)
118 goto again;
119 }
120 -
121 - if (cc == 2 && busy_bit)
122 - cc |= QDIO_ERROR_SIGA_BUSY;
123 - if (cc)
124 - DBF_ERROR("%4x SIGA-W:%2d", SCH_NO(q), cc);
125 return cc;
126 }
127
128 @@ -390,7 +380,7 @@ inline void qdio_stop_polling(struct qdi
129
130 static void announce_buffer_error(struct qdio_q *q, int count)
131 {
132 - q->qdio_error = QDIO_ERROR_SLSB_STATE;
133 + q->qdio_error |= QDIO_ERROR_SLSB_STATE;
134
135 /* special handling for no target buffer empty */
136 if ((!q->is_input_q &&
137 @@ -707,69 +697,34 @@ static inline int qdio_outbound_q_moved(
138 return 0;
139 }
140
141 -/*
142 - * VM could present us cc=2 and busy bit set on SIGA-write
143 - * during reconfiguration of their Guest LAN (only in iqdio mode,
144 - * otherwise qdio is asynchronous and cc=2 and busy bit there will take
145 - * the queues down immediately).
146 - *
147 - * Therefore qdio_siga_output will try for a short time constantly,
148 - * if such a condition occurs. If it doesn't change, it will
149 - * increase the busy_siga_counter and save the timestamp, and
150 - * schedule the queue for later processing. qdio_outbound_processing
151 - * will check out the counter. If non-zero, it will call qdio_kick_outbound_q
152 - * as often as the value of the counter. This will attempt further SIGA
153 - * instructions. For each successful SIGA, the counter is
154 - * decreased, for failing SIGAs the counter remains the same, after
155 - * all. After some time of no movement, qdio_kick_outbound_q will
156 - * finally fail and reflect corresponding error codes to call
157 - * the upper layer module and have it take the queues down.
158 - *
159 - * Note that this is a change from the original HiperSockets design
160 - * (saying cc=2 and busy bit means take the queues down), but in
161 - * these days Guest LAN didn't exist... excessive cc=2 with busy bit
162 - * conditions will still take the queues down, but the threshold is
163 - * higher due to the Guest LAN environment.
164 - *
165 - * Called from outbound tasklet and do_QDIO handler.
166 - */
167 -static void qdio_kick_outbound_q(struct qdio_q *q)
168 +static int qdio_kick_outbound_q(struct qdio_q *q)
169 {
170 - int rc;
171 -
172 - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kickoutq:%1d", q->nr);
173 + unsigned int busy_bit;
174 + int cc;
175
176 if (!need_siga_out(q))
177 - return;
178 + return 0;
179
180 - rc = qdio_siga_output(q);
181 - switch (rc) {
182 + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr);
183 + qdio_perf_stat_inc(&perf_stats.siga_out);
184 +
185 + cc = qdio_siga_output(q, &busy_bit);
186 + switch (cc) {
187 case 0:
188 - /* TODO: improve error handling for CC=0 case */
189 - if (q->u.out.timestamp)
190 - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "cc2 rslv:%4x",
191 - atomic_read(&q->u.out.busy_siga_counter));
192 - /* went smooth this time, reset timestamp */
193 - q->u.out.timestamp = 0;
194 break;
195 - /* cc=2 and busy bit */
196 - case (2 | QDIO_ERROR_SIGA_BUSY):
197 - atomic_inc(&q->u.out.busy_siga_counter);
198 -
199 - /* if the last siga was successful, save timestamp here */
200 - if (!q->u.out.timestamp)
201 - q->u.out.timestamp = get_usecs();
202 -
203 - /* if we're in time, don't touch qdio_error */
204 - if (get_usecs() - q->u.out.timestamp < QDIO_BUSY_BIT_GIVE_UP) {
205 - tasklet_schedule(&q->tasklet);
206 - break;
207 - }
208 - DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr);
209 - default:
210 - /* for plain cc=1, 2 or 3 */
211 - q->qdio_error = rc;
212 + case 2:
213 + if (busy_bit) {
214 + DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr);
215 + cc |= QDIO_ERROR_SIGA_BUSY;
216 + } else
217 + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr);
218 + break;
219 + case 1:
220 + case 3:
221 + DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc);
222 + break;
223 }
224 + return cc;
225 }
226
227 static void qdio_kick_outbound_handler(struct qdio_q *q)
228 @@ -799,17 +754,7 @@ static void qdio_kick_outbound_handler(s
229
230 static void __qdio_outbound_processing(struct qdio_q *q)
231 {
232 - int siga_attempts;
233 -
234 qdio_perf_stat_inc(&perf_stats.tasklet_outbound);
235 -
236 - /* see comment in qdio_kick_outbound_q */
237 - siga_attempts = atomic_read(&q->u.out.busy_siga_counter);
238 - while (siga_attempts--) {
239 - atomic_dec(&q->u.out.busy_siga_counter);
240 - qdio_kick_outbound_q(q);
241 - }
242 -
243 BUG_ON(atomic_read(&q->nr_buf_used) < 0);
244
245 if (qdio_outbound_q_moved(q))
246 @@ -1478,10 +1423,10 @@ static inline int buf_in_between(int buf
247 * @bufnr: first buffer to process
248 * @count: how many buffers are emptied
249 */
250 -static void handle_inbound(struct qdio_q *q, unsigned int callflags,
251 - int bufnr, int count)
252 +static int handle_inbound(struct qdio_q *q, unsigned int callflags,
253 + int bufnr, int count)
254 {
255 - int used, rc, diff;
256 + int used, diff;
257
258 if (!q->u.in.polling)
259 goto set;
260 @@ -1519,13 +1464,11 @@ set:
261
262 /* no need to signal as long as the adapter had free buffers */
263 if (used)
264 - return;
265 + return 0;
266
267 - if (need_siga_in(q)) {
268 - rc = qdio_siga_input(q);
269 - if (rc)
270 - q->qdio_error = rc;
271 - }
272 + if (need_siga_in(q))
273 + return qdio_siga_input(q);
274 + return 0;
275 }
276
277 /**
278 @@ -1535,11 +1478,11 @@ set:
279 * @bufnr: first buffer to process
280 * @count: how many buffers are filled
281 */
282 -static void handle_outbound(struct qdio_q *q, unsigned int callflags,
283 - int bufnr, int count)
284 +static int handle_outbound(struct qdio_q *q, unsigned int callflags,
285 + int bufnr, int count)
286 {
287 unsigned char state;
288 - int used;
289 + int used, rc = 0;
290
291 qdio_perf_stat_inc(&perf_stats.outbound_handler);
292
293 @@ -1554,14 +1497,17 @@ static void handle_outbound(struct qdio_
294
295 if (queue_type(q) == QDIO_IQDIO_QFMT) {
296 if (multicast_outbound(q))
297 - qdio_kick_outbound_q(q);
298 + rc = qdio_kick_outbound_q(q);
299 else
300 /*
301 * One siga-w per buffer required for unicast
302 * HiperSockets.
303 */
304 - while (count--)
305 - qdio_kick_outbound_q(q);
306 + while (count--) {
307 + rc = qdio_kick_outbound_q(q);
308 + if (rc)
309 + goto out;
310 + }
311 goto out;
312 }
313
314 @@ -1573,7 +1519,7 @@ static void handle_outbound(struct qdio_
315 /* try to fast requeue buffers */
316 get_buf_state(q, prev_buf(bufnr), &state, 0);
317 if (state != SLSB_CU_OUTPUT_PRIMED)
318 - qdio_kick_outbound_q(q);
319 + rc = qdio_kick_outbound_q(q);
320 else {
321 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "fast-req");
322 qdio_perf_stat_inc(&perf_stats.fast_requeue);
323 @@ -1581,6 +1527,7 @@ static void handle_outbound(struct qdio_
324 out:
325 /* Fixme: could wait forever if called from process context */
326 tasklet_schedule(&q->tasklet);
327 + return rc;
328 }
329
330 /**
331 @@ -1619,14 +1566,12 @@ int do_QDIO(struct ccw_device *cdev, uns
332 return -EBUSY;
333
334 if (callflags & QDIO_FLAG_SYNC_INPUT)
335 - handle_inbound(irq_ptr->input_qs[q_nr], callflags, bufnr,
336 - count);
337 + return handle_inbound(irq_ptr->input_qs[q_nr],
338 + callflags, bufnr, count);
339 else if (callflags & QDIO_FLAG_SYNC_OUTPUT)
340 - handle_outbound(irq_ptr->output_qs[q_nr], callflags, bufnr,
341 - count);
342 - else
343 - return -EINVAL;
344 - return 0;
345 + return handle_outbound(irq_ptr->output_qs[q_nr],
346 + callflags, bufnr, count);
347 + return -EINVAL;
348 }
349 EXPORT_SYMBOL_GPL(do_QDIO);
350