]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - src/patches/suse-2.6.27.25/patches.arch/s390-11-05-qdio_error_reporting_hs.patch
Reenabled linux-xen and xen-image build
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.25 / patches.arch / s390-11-05-qdio_error_reporting_hs.patch
CommitLineData
00e5a55c
BS
1From: Gerald Schaefer <geraldsc@de.ibm.com>
2Subject: qdio: fix hipersocket busy error handling
3References: bnc#484767,LTC#52204
4
5Symptom: Lower performance of hipersocket connections in case of
6 busy errors.
7Problem: 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.
11Solution: Retry immediately after a busy condition and report SIGA errors
12 directly to qeth.
13
14Acked-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
20Index: 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
45Index: 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