aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/s390/cio/qdio.h8
-rw-r--r--drivers/s390/cio/qdio_main.c150
-rw-r--r--drivers/s390/cio/qdio_setup.c1
3 files changed, 56 insertions, 103 deletions
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index c60f2566d28c..42f2b09631b6 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -14,7 +14,6 @@
14#include "chsc.h" 14#include "chsc.h"
15 15
16#define QDIO_BUSY_BIT_PATIENCE 100 /* 100 microseconds */ 16#define QDIO_BUSY_BIT_PATIENCE 100 /* 100 microseconds */
17#define QDIO_BUSY_BIT_GIVE_UP 2000000 /* 2 seconds = eternity */
18#define QDIO_INPUT_THRESHOLD 500 /* 500 microseconds */ 17#define QDIO_INPUT_THRESHOLD 500 /* 500 microseconds */
19 18
20/* 19/*
@@ -195,12 +194,6 @@ struct qdio_input_q {
195}; 194};
196 195
197struct qdio_output_q { 196struct qdio_output_q {
198 /* failed siga-w attempts*/
199 atomic_t busy_siga_counter;
200
201 /* start time of busy condition */
202 u64 timestamp;
203
204 /* PCIs are enabled for the queue */ 197 /* PCIs are enabled for the queue */
205 int pci_out_enabled; 198 int pci_out_enabled;
206 199
@@ -251,6 +244,7 @@ struct qdio_q {
251 244
252 struct qdio_irq *irq_ptr; 245 struct qdio_irq *irq_ptr;
253 struct tasklet_struct tasklet; 246 struct tasklet_struct tasklet;
247 spinlock_t lock;
254 248
255 /* error condition during a data transfer */ 249 /* error condition during a data transfer */
256 unsigned int qdio_error; 250 unsigned int qdio_error;
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 0b4c09cf6a47..744f928a59ea 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -74,7 +74,7 @@ static inline int do_siga_input(struct subchannel_id schid, unsigned int mask)
74 * Note: For IQDC unicast queues only the highest priority queue is processed. 74 * Note: For IQDC unicast queues only the highest priority queue is processed.
75 */ 75 */
76static inline int do_siga_output(unsigned long schid, unsigned long mask, 76static inline int do_siga_output(unsigned long schid, unsigned long mask,
77 u32 *bb, unsigned int fc) 77 unsigned int *bb, unsigned int fc)
78{ 78{
79 register unsigned long __fc asm("0") = fc; 79 register unsigned long __fc asm("0") = fc;
80 register unsigned long __schid asm("1") = schid; 80 register unsigned long __schid asm("1") = schid;
@@ -284,8 +284,7 @@ static int qdio_siga_sync(struct qdio_q *q, unsigned int output,
284 if (!need_siga_sync(q)) 284 if (!need_siga_sync(q))
285 return 0; 285 return 0;
286 286
287 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-s:"); 287 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-s:%1d", q->nr);
288 DBF_DEV_HEX(DBF_INFO, q->irq_ptr, q, sizeof(void *));
289 qdio_perf_stat_inc(&perf_stats.siga_sync); 288 qdio_perf_stat_inc(&perf_stats.siga_sync);
290 289
291 cc = do_siga_sync(q->irq_ptr->schid, output, input); 290 cc = do_siga_sync(q->irq_ptr->schid, output, input);
@@ -312,46 +311,37 @@ static inline int qdio_siga_sync_all(struct qdio_q *q)
312 return qdio_siga_sync(q, ~0U, ~0U); 311 return qdio_siga_sync(q, ~0U, ~0U);
313} 312}
314 313
315static inline int qdio_do_siga_output(struct qdio_q *q, unsigned int *busy_bit) 314static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit)
316{ 315{
317 unsigned int fc = 0;
318 unsigned long schid; 316 unsigned long schid;
317 unsigned int fc = 0;
318 u64 start_time = 0;
319 int cc;
319 320
320 if (q->u.out.use_enh_siga) { 321 if (q->u.out.use_enh_siga)
321 fc = 3; 322 fc = 3;
322 } 323
323 if (!is_qebsm(q)) 324 if (is_qebsm(q)) {
324 schid = *((u32 *)&q->irq_ptr->schid);
325 else {
326 schid = q->irq_ptr->sch_token; 325 schid = q->irq_ptr->sch_token;
327 fc |= 0x80; 326 fc |= 0x80;
328 } 327 }
329 return do_siga_output(schid, q->mask, busy_bit, fc); 328 else
330} 329 schid = *((u32 *)&q->irq_ptr->schid);
331
332static int qdio_siga_output(struct qdio_q *q)
333{
334 int cc;
335 u32 busy_bit;
336 u64 start_time = 0;
337 330
338 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr);
339 qdio_perf_stat_inc(&perf_stats.siga_out);
340again: 331again:
341 cc = qdio_do_siga_output(q, &busy_bit); 332 cc = do_siga_output(schid, q->mask, busy_bit, fc);
342 if (queue_type(q) == QDIO_IQDIO_QFMT && cc == 2 && busy_bit) { 333
343 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w bb:%2d", q->nr); 334 /* hipersocket busy condition */
335 if (*busy_bit) {
336 WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2);
344 337
345 if (!start_time) 338 if (!start_time) {
346 start_time = get_usecs(); 339 start_time = get_usecs();
347 else if ((get_usecs() - start_time) < QDIO_BUSY_BIT_PATIENCE) 340 goto again;
341 }
342 if ((get_usecs() - start_time) < QDIO_BUSY_BIT_PATIENCE)
348 goto again; 343 goto again;
349 } 344 }
350
351 if (cc == 2 && busy_bit)
352 cc |= QDIO_ERROR_SIGA_BUSY;
353 if (cc)
354 DBF_ERROR("%4x SIGA-W:%2d", SCH_NO(q), cc);
355 return cc; 345 return cc;
356} 346}
357 347
@@ -399,7 +389,7 @@ inline void qdio_stop_polling(struct qdio_q *q)
399 389
400static void announce_buffer_error(struct qdio_q *q, int count) 390static void announce_buffer_error(struct qdio_q *q, int count)
401{ 391{
402 q->qdio_error = QDIO_ERROR_SLSB_STATE; 392 q->qdio_error |= QDIO_ERROR_SLSB_STATE;
403 393
404 /* special handling for no target buffer empty */ 394 /* special handling for no target buffer empty */
405 if ((!q->is_input_q && 395 if ((!q->is_input_q &&
@@ -716,68 +706,36 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q)
716 return 0; 706 return 0;
717} 707}
718 708
719/*
720 * VM could present us cc=2 and busy bit set on SIGA-write
721 * during reconfiguration of their Guest LAN (only in iqdio mode,
722 * otherwise qdio is asynchronous and cc=2 and busy bit there will take
723 * the queues down immediately).
724 *
725 * Therefore qdio_siga_output will try for a short time constantly,
726 * if such a condition occurs. If it doesn't change, it will
727 * increase the busy_siga_counter and save the timestamp, and
728 * schedule the queue for later processing. qdio_outbound_processing
729 * will check out the counter. If non-zero, it will call qdio_kick_outbound_q
730 * as often as the value of the counter. This will attempt further SIGA
731 * instructions. For each successful SIGA, the counter is
732 * decreased, for failing SIGAs the counter remains the same, after
733 * all. After some time of no movement, qdio_kick_outbound_q will
734 * finally fail and reflect corresponding error codes to call
735 * the upper layer module and have it take the queues down.
736 *
737 * Note that this is a change from the original HiperSockets design
738 * (saying cc=2 and busy bit means take the queues down), but in
739 * these days Guest LAN didn't exist... excessive cc=2 with busy bit
740 * conditions will still take the queues down, but the threshold is
741 * higher due to the Guest LAN environment.
742 *
743 * Called from outbound tasklet and do_QDIO handler.
744 */
745static void qdio_kick_outbound_q(struct qdio_q *q) 709static void qdio_kick_outbound_q(struct qdio_q *q)
746{ 710{
747 int rc; 711 unsigned int busy_bit;
748 712 int cc;
749 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kickoutq:%1d", q->nr);
750 713
751 if (!need_siga_out(q)) 714 if (!need_siga_out(q))
752 return; 715 return;
753 716
754 rc = qdio_siga_output(q); 717 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr);
755 switch (rc) { 718 qdio_perf_stat_inc(&perf_stats.siga_out);
719
720 cc = qdio_siga_output(q, &busy_bit);
721 switch (cc) {
756 case 0: 722 case 0:
757 /* TODO: improve error handling for CC=0 case */
758 if (q->u.out.timestamp)
759 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "cc2 rslv:%4x",
760 atomic_read(&q->u.out.busy_siga_counter));
761 /* went smooth this time, reset timestamp */
762 q->u.out.timestamp = 0;
763 break; 723 break;
764 /* cc=2 and busy bit */ 724 case 2:
765 case (2 | QDIO_ERROR_SIGA_BUSY): 725 if (busy_bit) {
766 atomic_inc(&q->u.out.busy_siga_counter); 726 DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr);
767 727 q->qdio_error = cc | QDIO_ERROR_SIGA_BUSY;
768 /* if the last siga was successful, save timestamp here */ 728 } else {
769 if (!q->u.out.timestamp) 729 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d",
770 q->u.out.timestamp = get_usecs(); 730 q->nr);
771 731 q->qdio_error = cc;
772 /* if we're in time, don't touch qdio_error */
773 if (get_usecs() - q->u.out.timestamp < QDIO_BUSY_BIT_GIVE_UP) {
774 tasklet_schedule(&q->tasklet);
775 break;
776 } 732 }
777 DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr); 733 break;
778 default: 734 case 1:
779 /* for plain cc=1, 2 or 3 */ 735 case 3:
780 q->qdio_error = rc; 736 DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc);
737 q->qdio_error = cc;
738 break;
781 } 739 }
782} 740}
783 741
@@ -808,22 +766,18 @@ static void qdio_kick_outbound_handler(struct qdio_q *q)
808 766
809static void __qdio_outbound_processing(struct qdio_q *q) 767static void __qdio_outbound_processing(struct qdio_q *q)
810{ 768{
811 int siga_attempts; 769 unsigned long flags;
812 770
813 qdio_perf_stat_inc(&perf_stats.tasklet_outbound); 771 qdio_perf_stat_inc(&perf_stats.tasklet_outbound);
814 772 spin_lock_irqsave(&q->lock, flags);
815 /* see comment in qdio_kick_outbound_q */
816 siga_attempts = atomic_read(&q->u.out.busy_siga_counter);
817 while (siga_attempts--) {
818 atomic_dec(&q->u.out.busy_siga_counter);
819 qdio_kick_outbound_q(q);
820 }
821 773
822 BUG_ON(atomic_read(&q->nr_buf_used) < 0); 774 BUG_ON(atomic_read(&q->nr_buf_used) < 0);
823 775
824 if (qdio_outbound_q_moved(q)) 776 if (qdio_outbound_q_moved(q))
825 qdio_kick_outbound_handler(q); 777 qdio_kick_outbound_handler(q);
826 778
779 spin_unlock_irqrestore(&q->lock, flags);
780
827 if (queue_type(q) == QDIO_ZFCP_QFMT) { 781 if (queue_type(q) == QDIO_ZFCP_QFMT) {
828 if (!pci_out_supported(q) && !qdio_outbound_q_done(q)) 782 if (!pci_out_supported(q) && !qdio_outbound_q_done(q))
829 tasklet_schedule(&q->tasklet); 783 tasklet_schedule(&q->tasklet);
@@ -1491,7 +1445,7 @@ static inline int buf_in_between(int bufnr, int start, int count)
1491static void handle_inbound(struct qdio_q *q, unsigned int callflags, 1445static void handle_inbound(struct qdio_q *q, unsigned int callflags,
1492 int bufnr, int count) 1446 int bufnr, int count)
1493{ 1447{
1494 int used, rc, diff; 1448 int used, cc, diff;
1495 1449
1496 if (!q->u.in.polling) 1450 if (!q->u.in.polling)
1497 goto set; 1451 goto set;
@@ -1532,9 +1486,9 @@ set:
1532 return; 1486 return;
1533 1487
1534 if (need_siga_in(q)) { 1488 if (need_siga_in(q)) {
1535 rc = qdio_siga_input(q); 1489 cc = qdio_siga_input(q);
1536 if (rc) 1490 if (cc)
1537 q->qdio_error = rc; 1491 q->qdio_error = cc;
1538 } 1492 }
1539} 1493}
1540 1494
@@ -1581,6 +1535,10 @@ static void handle_outbound(struct qdio_q *q, unsigned int callflags,
1581 while (count--) 1535 while (count--)
1582 qdio_kick_outbound_q(q); 1536 qdio_kick_outbound_q(q);
1583 } 1537 }
1538
1539 /* report CC=2 conditions synchronously */
1540 if (q->qdio_error)
1541 __qdio_outbound_processing(q);
1584 goto out; 1542 goto out;
1585 } 1543 }
1586 1544
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c
index 18d54fc21ce9..c08356b95bf5 100644
--- a/drivers/s390/cio/qdio_setup.c
+++ b/drivers/s390/cio/qdio_setup.c
@@ -117,6 +117,7 @@ static void setup_queues_misc(struct qdio_q *q, struct qdio_irq *irq_ptr,
117 q->mask = 1 << (31 - i); 117 q->mask = 1 << (31 - i);
118 q->nr = i; 118 q->nr = i;
119 q->handler = handler; 119 q->handler = handler;
120 spin_lock_init(&q->lock);
120} 121}
121 122
122static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr, 123static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr,