]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - src/patches/suse-2.6.27.25/patches.arch/s390-06-06-qdio_inbound_ack.patch
Revert "Move xen patchset to new version's subdir."
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.25 / patches.arch / s390-06-06-qdio_inbound_ack.patch
CommitLineData
00e5a55c
BS
1From: Gerald Schaefer <geraldsc@de.ibm.com>
2Subject: qdio: rework inbound buffer acknowledgement
3References: bnc#458339
4
5Symptom: Inbound network traffic stall.
6Problem: Under high load the qdio buffer that specifies the acknowledge
7 mode can be overwritten.
8Solution: Use automatic acknowledgement of incoming buffers in QEBSM mode
9 to improve performance with QIOASSIST.
10 Move ACK for non-QEBSM mode always to the newest buffer to prevent
11 a race with qdio_stop_polling.
12 Remove the polling spinlock, the upper layer drivers return new
13 buffers in the same code path and could not run in parallel.
14 Don't flood the error log in case of no-target-buffer-empty.
15 In handle_inbound we check if we would overwrite an ACK'ed buffer,
16 if so advance the pointer to the oldest ACK'ed buffer so we don't
17 overwrite an empty buffer in qdio_stop_polling.
18
19Acked-by: John Jolly <jjolly@suse.de>
20
21---
22 drivers/s390/cio/qdio.h | 19 ++--
23 drivers/s390/cio/qdio_debug.c | 7 +
24 drivers/s390/cio/qdio_main.c | 181 ++++++++++++++++++++++++++--------------
25 drivers/s390/cio/qdio_perf.c | 2
26 drivers/s390/cio/qdio_perf.h | 1
27 drivers/s390/cio/qdio_setup.c | 1
28 drivers/s390/cio/qdio_thinint.c | 2
29 7 files changed, 139 insertions(+), 74 deletions(-)
30
31Index: linux-sles11/drivers/s390/cio/qdio.h
32===================================================================
33--- linux-sles11.orig/drivers/s390/cio/qdio.h
34+++ linux-sles11/drivers/s390/cio/qdio.h
35@@ -112,12 +112,12 @@ static inline int do_sqbs(u64 token, uns
36 }
37
38 static inline int do_eqbs(u64 token, unsigned char *state, int queue,
39- int *start, int *count)
40+ int *start, int *count, int ack)
41 {
42 register unsigned long _ccq asm ("0") = *count;
43 register unsigned long _token asm ("1") = token;
44 unsigned long _queuestart = ((unsigned long)queue << 32) | *start;
45- unsigned long _state = 0;
46+ unsigned long _state = (unsigned long)ack << 63;
47
48 asm volatile(
49 " .insn rrf,0xB99c0000,%1,%2,0,0"
50@@ -134,7 +134,7 @@ static inline int do_eqbs(u64 token, uns
51 static inline int do_sqbs(u64 token, unsigned char state, int queue,
52 int *start, int *count) { return 0; }
53 static inline int do_eqbs(u64 token, unsigned char *state, int queue,
54- int *start, int *count) { return 0; }
55+ int *start, int *count, int ack) { return 0; }
56 #endif /* CONFIG_64BIT */
57
58 struct qdio_irq;
59@@ -187,11 +187,11 @@ struct qdio_input_q {
60 /* input buffer acknowledgement flag */
61 int polling;
62
63+ /* how much sbals are acknowledged with qebsm */
64+ int ack_count;
65+
66 /* last time of noticing incoming data */
67 u64 timestamp;
68-
69- /* lock for clearing the acknowledgement */
70- spinlock_t lock;
71 };
72
73 struct qdio_output_q {
74@@ -348,10 +348,13 @@ static inline unsigned long long get_use
75 ((bufnr + 1) & QDIO_MAX_BUFFERS_MASK)
76 #define add_buf(bufnr, inc) \
77 ((bufnr + inc) & QDIO_MAX_BUFFERS_MASK)
78+#define sub_buf(bufnr, dec) \
79+ ((bufnr - dec) & QDIO_MAX_BUFFERS_MASK)
80
81 /* prototypes for thin interrupt */
82 void qdio_sync_after_thinint(struct qdio_q *q);
83-int get_buf_state(struct qdio_q *q, unsigned int bufnr, unsigned char *state);
84+int get_buf_state(struct qdio_q *q, unsigned int bufnr, unsigned char *state,
85+ int auto_ack);
86 void qdio_check_outbound_after_thinint(struct qdio_q *q);
87 int qdio_inbound_q_moved(struct qdio_q *q);
88 void qdio_kick_inbound_handler(struct qdio_q *q);
89@@ -385,6 +388,8 @@ int qdio_setup_irq(struct qdio_initializ
90 void qdio_print_subchannel_info(struct qdio_irq *irq_ptr,
91 struct ccw_device *cdev);
92 void qdio_release_memory(struct qdio_irq *irq_ptr);
93+int qdio_setup_create_sysfs(struct ccw_device *cdev);
94+void qdio_setup_destroy_sysfs(struct ccw_device *cdev);
95 int qdio_setup_init(void);
96 void qdio_setup_exit(void);
97
98Index: linux-sles11/drivers/s390/cio/qdio_debug.c
99===================================================================
100--- linux-sles11.orig/drivers/s390/cio/qdio_debug.c
101+++ linux-sles11/drivers/s390/cio/qdio_debug.c
102@@ -59,16 +59,18 @@ static int qstat_show(struct seq_file *m
103 if (!q)
104 return 0;
105
106- seq_printf(m, "device state indicator: %d\n", *q->irq_ptr->dsci);
107+ seq_printf(m, "device state indicator: %d\n", *(u32 *)q->irq_ptr->dsci);
108 seq_printf(m, "nr_used: %d\n", atomic_read(&q->nr_buf_used));
109 seq_printf(m, "ftc: %d\n", q->first_to_check);
110 seq_printf(m, "last_move_ftc: %d\n", q->last_move_ftc);
111 seq_printf(m, "polling: %d\n", q->u.in.polling);
112+ seq_printf(m, "ack count: %d\n", q->u.in.ack_count);
113 seq_printf(m, "slsb buffer states:\n");
114+ seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n");
115
116 qdio_siga_sync_q(q);
117 for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
118- get_buf_state(q, i, &state);
119+ get_buf_state(q, i, &state, 0);
120 switch (state) {
121 case SLSB_P_INPUT_NOT_INIT:
122 case SLSB_P_OUTPUT_NOT_INIT:
123@@ -100,6 +102,7 @@ static int qstat_show(struct seq_file *m
124 seq_printf(m, "\n");
125 }
126 seq_printf(m, "\n");
127+ seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n");
128 return 0;
129 }
130
131Index: linux-sles11/drivers/s390/cio/qdio_main.c
132===================================================================
133--- linux-sles11.orig/drivers/s390/cio/qdio_main.c
134+++ linux-sles11/drivers/s390/cio/qdio_main.c
135@@ -112,12 +112,13 @@ static inline int qdio_check_ccq(struct
136 * @state: state of the extracted buffers
137 * @start: buffer number to start at
138 * @count: count of buffers to examine
139+ * @auto_ack: automatically acknowledge buffers
140 *
141 * Returns the number of successfull extracted equal buffer states.
142 * Stops processing if a state is different from the last buffers state.
143 */
144 static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state,
145- int start, int count)
146+ int start, int count, int auto_ack)
147 {
148 unsigned int ccq = 0;
149 int tmp_count = count, tmp_start = start;
150@@ -129,7 +130,8 @@ static int qdio_do_eqbs(struct qdio_q *q
151 if (!q->is_input_q)
152 nr += q->irq_ptr->nr_input_qs;
153 again:
154- ccq = do_eqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count);
155+ ccq = do_eqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count,
156+ auto_ack);
157 rc = qdio_check_ccq(q, ccq);
158
159 /* At least one buffer was processed, return and extract the remaining
160@@ -172,6 +174,9 @@ static int qdio_do_sqbs(struct qdio_q *q
161 int nr = q->nr;
162 int rc;
163
164+ if (!count)
165+ return 0;
166+
167 BUG_ON(!q->irq_ptr->sch_token);
168
169 if (!q->is_input_q)
170@@ -197,7 +202,8 @@ again:
171
172 /* returns number of examined buffers and their common state in *state */
173 static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr,
174- unsigned char *state, unsigned int count)
175+ unsigned char *state, unsigned int count,
176+ int auto_ack)
177 {
178 unsigned char __state = 0;
179 int i;
180@@ -206,7 +212,7 @@ static inline int get_buf_states(struct
181 BUG_ON(count > QDIO_MAX_BUFFERS_PER_Q);
182
183 if (is_qebsm(q))
184- return qdio_do_eqbs(q, state, bufnr, count);
185+ return qdio_do_eqbs(q, state, bufnr, count, auto_ack);
186
187 for (i = 0; i < count; i++) {
188 if (!__state)
189@@ -220,9 +226,9 @@ static inline int get_buf_states(struct
190 }
191
192 inline int get_buf_state(struct qdio_q *q, unsigned int bufnr,
193- unsigned char *state)
194+ unsigned char *state, int auto_ack)
195 {
196- return get_buf_states(q, bufnr, state, 1);
197+ return get_buf_states(q, bufnr, state, 1, auto_ack);
198 }
199
200 /* wrap-around safe setting of slsb states, returns number of changed buffers */
201@@ -367,29 +373,91 @@ void qdio_sync_after_thinint(struct qdio
202
203 inline void qdio_stop_polling(struct qdio_q *q)
204 {
205- spin_lock_bh(&q->u.in.lock);
206- if (!q->u.in.polling) {
207- spin_unlock_bh(&q->u.in.lock);
208+ if (!q->u.in.polling)
209 return;
210- }
211+
212 q->u.in.polling = 0;
213 qdio_perf_stat_inc(&perf_stats.debug_stop_polling);
214
215 /* show the card that we are not polling anymore */
216- set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT);
217- spin_unlock_bh(&q->u.in.lock);
218+ if (is_qebsm(q)) {
219+ set_buf_states(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT,
220+ q->u.in.ack_count);
221+ q->u.in.ack_count = 0;
222+ } else
223+ set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT);
224 }
225
226-static void announce_buffer_error(struct qdio_q *q)
227+static void announce_buffer_error(struct qdio_q *q, int count)
228 {
229+ q->qdio_error = QDIO_ERROR_SLSB_STATE;
230+
231+ /* special handling for no target buffer empty */
232+ if ((!q->is_input_q &&
233+ (q->sbal[q->first_to_check]->element[15].flags & 0xff) == 0x10)) {
234+ qdio_perf_stat_inc(&perf_stats.outbound_target_full);
235+ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "OUTFULL FTC:%3d",
236+ q->first_to_check);
237+ return;
238+ }
239+
240 DBF_ERROR("%4x BUF ERROR", SCH_NO(q));
241 DBF_ERROR((q->is_input_q) ? "IN:%2d" : "OUT:%2d", q->nr);
242- DBF_ERROR("FTC:%3d", q->first_to_check);
243+ DBF_ERROR("FTC:%3d C:%3d", q->first_to_check, count);
244 DBF_ERROR("F14:%2x F15:%2x",
245 q->sbal[q->first_to_check]->element[14].flags & 0xff,
246 q->sbal[q->first_to_check]->element[15].flags & 0xff);
247+}
248
249- q->qdio_error = QDIO_ERROR_SLSB_STATE;
250+static inline void inbound_primed(struct qdio_q *q, int count)
251+{
252+ int new;
253+
254+ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in prim: %3d", count);
255+
256+ /* for QEBSM the ACK was already set by EQBS */
257+ if (is_qebsm(q)) {
258+ if (!q->u.in.polling) {
259+ q->u.in.polling = 1;
260+ q->u.in.ack_count = count;
261+ q->last_move_ftc = q->first_to_check;
262+ return;
263+ }
264+
265+ /* delete the previous ACK's */
266+ set_buf_states(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT,
267+ q->u.in.ack_count);
268+ q->u.in.ack_count = count;
269+ q->last_move_ftc = q->first_to_check;
270+ return;
271+ }
272+
273+ /*
274+ * ACK the newest buffer. The ACK will be removed in qdio_stop_polling
275+ * or by the next inbound run.
276+ */
277+ new = add_buf(q->first_to_check, count - 1);
278+ if (q->u.in.polling) {
279+ /* reset the previous ACK but first set the new one */
280+ set_buf_state(q, new, SLSB_P_INPUT_ACK);
281+ set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT);
282+ }
283+ else {
284+ q->u.in.polling = 1;
285+ set_buf_state(q, q->first_to_check, SLSB_P_INPUT_ACK);
286+ }
287+
288+ q->last_move_ftc = new;
289+ count--;
290+ if (!count)
291+ return;
292+
293+ /*
294+ * Need to change all PRIMED buffers to NOT_INIT, otherwise
295+ * we're loosing initiative in the thinint code.
296+ */
297+ set_buf_states(q, next_buf(q->first_to_check), SLSB_P_INPUT_NOT_INIT,
298+ count);
299 }
300
301 static int get_inbound_buffer_frontier(struct qdio_q *q)
302@@ -398,13 +466,6 @@ static int get_inbound_buffer_frontier(s
303 unsigned char state;
304
305 /*
306- * If we still poll don't update last_move_ftc, keep the
307- * previously ACK buffer there.
308- */
309- if (!q->u.in.polling)
310- q->last_move_ftc = q->first_to_check;
311-
312- /*
313 * Don't check 128 buffers, as otherwise qdio_inbound_q_moved
314 * would return 0.
315 */
316@@ -424,34 +485,13 @@ check_next:
317 if (q->first_to_check == stop)
318 goto out;
319
320- count = get_buf_states(q, q->first_to_check, &state, count);
321+ count = get_buf_states(q, q->first_to_check, &state, count, 1);
322 if (!count)
323 goto out;
324
325 switch (state) {
326 case SLSB_P_INPUT_PRIMED:
327- DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in prim: %3d", count);
328-
329- /*
330- * Only ACK the first buffer. The ACK will be removed in
331- * qdio_stop_polling.
332- */
333- if (q->u.in.polling)
334- state = SLSB_P_INPUT_NOT_INIT;
335- else {
336- q->u.in.polling = 1;
337- state = SLSB_P_INPUT_ACK;
338- }
339- set_buf_state(q, q->first_to_check, state);
340-
341- /*
342- * Need to change all PRIMED buffers to NOT_INIT, otherwise
343- * we're loosing initiative in the thinint code.
344- */
345- if (count > 1)
346- set_buf_states(q, next_buf(q->first_to_check),
347- SLSB_P_INPUT_NOT_INIT, count - 1);
348-
349+ inbound_primed(q, count);
350 /*
351 * No siga-sync needed for non-qebsm here, as the inbound queue
352 * will be synced on the next siga-r, resp.
353@@ -461,7 +501,7 @@ check_next:
354 atomic_sub(count, &q->nr_buf_used);
355 goto check_next;
356 case SLSB_P_INPUT_ERROR:
357- announce_buffer_error(q);
358+ announce_buffer_error(q, count);
359 /* process the buffer, the upper layer will take care of it */
360 q->first_to_check = add_buf(q->first_to_check, count);
361 atomic_sub(count, &q->nr_buf_used);
362@@ -507,7 +547,7 @@ static int qdio_inbound_q_done(struct qd
363 */
364 qdio_siga_sync_q(q);
365
366- get_buf_state(q, q->first_to_check, &state);
367+ get_buf_state(q, q->first_to_check, &state, 0);
368 if (state == SLSB_P_INPUT_PRIMED)
369 /* we got something to do */
370 return 0;
371@@ -610,7 +650,7 @@ check_next:
372 if (q->first_to_check == stop)
373 return q->first_to_check;
374
375- count = get_buf_states(q, q->first_to_check, &state, count);
376+ count = get_buf_states(q, q->first_to_check, &state, count, 0);
377 if (!count)
378 return q->first_to_check;
379
380@@ -629,7 +669,7 @@ check_next:
381 break;
382 goto check_next;
383 case SLSB_P_OUTPUT_ERROR:
384- announce_buffer_error(q);
385+ announce_buffer_error(q, count);
386 /* process the buffer, the upper layer will take care of it */
387 q->first_to_check = add_buf(q->first_to_check, count);
388 atomic_sub(count, &q->nr_buf_used);
389@@ -1441,23 +1481,38 @@ static inline int buf_in_between(int buf
390 static void handle_inbound(struct qdio_q *q, unsigned int callflags,
391 int bufnr, int count)
392 {
393- unsigned long flags;
394- int used, rc;
395+ int used, rc, diff;
396
397- /*
398- * do_QDIO could run in parallel with the queue tasklet so the
399- * upper-layer programm could empty the ACK'ed buffer here.
400- * If that happens we must clear the polling flag, otherwise
401- * qdio_stop_polling() could set the buffer to NOT_INIT after
402- * it was set to EMPTY which would kill us.
403- */
404- spin_lock_irqsave(&q->u.in.lock, flags);
405- if (q->u.in.polling)
406- if (buf_in_between(q->last_move_ftc, bufnr, count))
407+ if (!q->u.in.polling)
408+ goto set;
409+
410+ /* protect against stop polling setting an ACK for an emptied slsb */
411+ if (count == QDIO_MAX_BUFFERS_PER_Q) {
412+ /* overwriting everything, just delete polling status */
413+ q->u.in.polling = 0;
414+ q->u.in.ack_count = 0;
415+ goto set;
416+ } else if (buf_in_between(q->last_move_ftc, bufnr, count)) {
417+ if (is_qebsm(q)) {
418+ /* partial overwrite, just update last_move_ftc */
419+ diff = add_buf(bufnr, count);
420+ diff = sub_buf(diff, q->last_move_ftc);
421+ q->u.in.ack_count -= diff;
422+ if (q->u.in.ack_count <= 0) {
423+ q->u.in.polling = 0;
424+ q->u.in.ack_count = 0;
425+ /* TODO: must we set last_move_ftc to something meaningful? */
426+ goto set;
427+ }
428+ q->last_move_ftc = add_buf(q->last_move_ftc, diff);
429+ }
430+ else
431+ /* the only ACK will be deleted, so stop polling */
432 q->u.in.polling = 0;
433+ }
434
435+set:
436 count = set_buf_states(q, bufnr, SLSB_CU_INPUT_EMPTY, count);
437- spin_unlock_irqrestore(&q->u.in.lock, flags);
438
439 used = atomic_add_return(count, &q->nr_buf_used) - count;
440 BUG_ON(used + count > QDIO_MAX_BUFFERS_PER_Q);
441@@ -1516,7 +1571,7 @@ static void handle_outbound(struct qdio_
442 }
443
444 /* try to fast requeue buffers */
445- get_buf_state(q, prev_buf(bufnr), &state);
446+ get_buf_state(q, prev_buf(bufnr), &state, 0);
447 if (state != SLSB_CU_OUTPUT_PRIMED)
448 qdio_kick_outbound_q(q);
449 else {
450Index: linux-sles11/drivers/s390/cio/qdio_perf.c
451===================================================================
452--- linux-sles11.orig/drivers/s390/cio/qdio_perf.c
453+++ linux-sles11/drivers/s390/cio/qdio_perf.c
454@@ -74,6 +74,8 @@ static int qdio_perf_proc_show(struct se
455 seq_printf(m, "\n");
456 seq_printf(m, "Number of fast requeues (outg. SBAL w/o SIGA)\t: %li\n",
457 (long)atomic_long_read(&perf_stats.fast_requeue));
458+ seq_printf(m, "Number of outbound target full condition\t: %li\n",
459+ (long)atomic_long_read(&perf_stats.outbound_target_full));
460 seq_printf(m, "Number of outbound tasklet mod_timer calls\t: %li\n",
461 (long)atomic_long_read(&perf_stats.debug_tl_out_timer));
462 seq_printf(m, "Number of stop polling calls\t\t\t: %li\n",
463Index: linux-sles11/drivers/s390/cio/qdio_perf.h
464===================================================================
465--- linux-sles11.orig/drivers/s390/cio/qdio_perf.h
466+++ linux-sles11/drivers/s390/cio/qdio_perf.h
467@@ -36,6 +36,7 @@ struct qdio_perf_stats {
468 atomic_long_t inbound_handler;
469 atomic_long_t outbound_handler;
470 atomic_long_t fast_requeue;
471+ atomic_long_t outbound_target_full;
472
473 /* for debugging */
474 atomic_long_t debug_tl_out_timer;
475Index: linux-sles11/drivers/s390/cio/qdio_setup.c
476===================================================================
477--- linux-sles11.orig/drivers/s390/cio/qdio_setup.c
478+++ linux-sles11/drivers/s390/cio/qdio_setup.c
479@@ -167,7 +167,6 @@ static void setup_queues(struct qdio_irq
480 setup_queues_misc(q, irq_ptr, qdio_init->input_handler, i);
481
482 q->is_input_q = 1;
483- spin_lock_init(&q->u.in.lock);
484 setup_storage_lists(q, irq_ptr, input_sbal_array, i);
485 input_sbal_array += QDIO_MAX_BUFFERS_PER_Q;
486
487Index: linux-sles11/drivers/s390/cio/qdio_thinint.c
488===================================================================
489--- linux-sles11.orig/drivers/s390/cio/qdio_thinint.c
490+++ linux-sles11/drivers/s390/cio/qdio_thinint.c
491@@ -131,7 +131,7 @@ static inline int tiqdio_inbound_q_done(
492 return 1;
493
494 qdio_siga_sync_q(q);
495- get_buf_state(q, q->first_to_check, &state);
496+ get_buf_state(q, q->first_to_check, &state, 0);
497
498 if (state == SLSB_P_INPUT_PRIMED)
499 /* more work coming */