1 From: Gerald Schaefer <geraldsc@de.ibm.com>
2 Subject: qdio: fix hipersocket busy error handling
3 References: bnc#484767,LTC#52204
5 Symptom: Lower performance of hipersocket connections in case of
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
11 Solution: Retry immediately after a busy condition and report SIGA errors
14 Acked-by: John Jolly <jjolly@suse.de>
16 drivers/s390/cio/qdio.h | 7 -
17 drivers/s390/cio/qdio_main.c | 181 ++++++++++++++-----------------------------
18 2 files changed, 63 insertions(+), 125 deletions(-)
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
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 */
32 @@ -195,12 +194,6 @@ struct qdio_input_q {
35 struct qdio_output_q {
36 - /* failed siga-w attempts*/
37 - atomic_t busy_siga_counter;
39 - /* start time of busy condition */
42 /* PCIs are enabled for the queue */
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.
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)
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))
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);
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);
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)
75 - unsigned int fc = 0;
77 + unsigned int fc = 0;
82 - schid = *((u32 *)&q->irq_ptr->schid);
85 schid = q->irq_ptr->sch_token;
88 - return do_siga_output(schid, q->mask, busy_bit, fc);
91 -static int qdio_siga_output(struct qdio_q *q)
97 + schid = *((u32 *)&q->irq_ptr->schid);
99 - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr);
100 - qdio_perf_stat_inc(&perf_stats.siga_out);
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);
108 + /* hipersocket busy condition */
110 + WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2);
113 start_time = get_usecs();
114 - else if ((get_usecs() - start_time) < QDIO_BUSY_BIT_PATIENCE)
117 + if ((get_usecs() - start_time) < QDIO_BUSY_BIT_PATIENCE)
121 - if (cc == 2 && busy_bit)
122 - cc |= QDIO_ERROR_SIGA_BUSY;
124 - DBF_ERROR("%4x SIGA-W:%2d", SCH_NO(q), cc);
128 @@ -390,7 +380,7 @@ inline void qdio_stop_polling(struct qdi
130 static void announce_buffer_error(struct qdio_q *q, int count)
132 - q->qdio_error = QDIO_ERROR_SLSB_STATE;
133 + q->qdio_error |= QDIO_ERROR_SLSB_STATE;
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(
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).
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.
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.
165 - * Called from outbound tasklet and do_QDIO handler.
167 -static void qdio_kick_outbound_q(struct qdio_q *q)
168 +static int qdio_kick_outbound_q(struct qdio_q *q)
172 - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kickoutq:%1d", q->nr);
173 + unsigned int busy_bit;
176 if (!need_siga_out(q))
180 - rc = qdio_siga_output(q);
182 + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr);
183 + qdio_perf_stat_inc(&perf_stats.siga_out);
185 + cc = qdio_siga_output(q, &busy_bit);
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;
195 - /* cc=2 and busy bit */
196 - case (2 | QDIO_ERROR_SIGA_BUSY):
197 - atomic_inc(&q->u.out.busy_siga_counter);
199 - /* if the last siga was successful, save timestamp here */
200 - if (!q->u.out.timestamp)
201 - q->u.out.timestamp = get_usecs();
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);
208 - DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr);
210 - /* for plain cc=1, 2 or 3 */
211 - q->qdio_error = rc;
214 + DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr);
215 + cc |= QDIO_ERROR_SIGA_BUSY;
217 + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr);
221 + DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc);
227 static void qdio_kick_outbound_handler(struct qdio_q *q)
228 @@ -799,17 +754,7 @@ static void qdio_kick_outbound_handler(s
230 static void __qdio_outbound_processing(struct qdio_q *q)
234 qdio_perf_stat_inc(&perf_stats.tasklet_outbound);
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);
243 BUG_ON(atomic_read(&q->nr_buf_used) < 0);
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
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)
255 - int used, rc, diff;
258 if (!q->u.in.polling)
260 @@ -1519,13 +1464,11 @@ set:
262 /* no need to signal as long as the adapter had free buffers */
267 - if (need_siga_in(q)) {
268 - rc = qdio_siga_input(q);
270 - q->qdio_error = rc;
272 + if (need_siga_in(q))
273 + return qdio_siga_input(q);
278 @@ -1535,11 +1478,11 @@ set:
279 * @bufnr: first buffer to process
280 * @count: how many buffers are filled
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)
291 qdio_perf_stat_inc(&perf_stats.outbound_handler);
293 @@ -1554,14 +1497,17 @@ static void handle_outbound(struct qdio_
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);
301 * One siga-w per buffer required for unicast
305 - qdio_kick_outbound_q(q);
307 + rc = qdio_kick_outbound_q(q);
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);
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_
325 /* Fixme: could wait forever if called from process context */
326 tasklet_schedule(&q->tasklet);
331 @@ -1619,14 +1566,12 @@ int do_QDIO(struct ccw_device *cdev, uns
334 if (callflags & QDIO_FLAG_SYNC_INPUT)
335 - handle_inbound(irq_ptr->input_qs[q_nr], callflags, bufnr,
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,
345 + return handle_outbound(irq_ptr->output_qs[q_nr],
346 + callflags, bufnr, count);
349 EXPORT_SYMBOL_GPL(do_QDIO);