Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

s390/qdio: clear DSCI early for polling drivers

Polling drivers in a configuration with 1 Input Queue currently keep
their DSCI armed all the way through the poll cycle, until
qdio_start_irq() clears it.

_Any_ intermittent QDIO interrupt delivered to tiqdio_thinint_handler()
will thus cause
1) the 'adapter_int' statistic to be incremented,
2) a call to tiqdio_call_inq_handlers() for this device, and then
3) the 'int_discarded' statistics to be incremented.

This causes overhead & complexity in the IRQ path, along with ambiguity
in the statistics.
On the other hand the device should be in IRQ avoidance mode during a
poll cycle, so there won't be a lot of DSCI ping-pong that this
micro-optimization could prevent.

So align the DSCI handling with what we already do for devices with
multiple Input Queues: clear it right away while processing the IRQ.

For the non-polling path this means that we no longer need to handle
the 1-queue case separately.

Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>

authored by

Julian Wiedmann and committed by
Vasily Gorbik
9c159bbc a8a4ee27

+2 -26
-1
drivers/s390/cio/qdio.h
··· 374 374 void tiqdio_free_memory(void); 375 375 int tiqdio_register_thinints(void); 376 376 void tiqdio_unregister_thinints(void); 377 - void clear_nonshared_ind(struct qdio_irq *); 378 377 int test_nonshared_ind(struct qdio_irq *); 379 378 380 379 /* prototypes for setup */
-2
drivers/s390/cio/qdio_main.c
··· 1643 1643 if (!irq_ptr) 1644 1644 return -ENODEV; 1645 1645 1646 - clear_nonshared_ind(irq_ptr); 1647 - 1648 1646 for_each_input_queue(irq_ptr, q, i) 1649 1647 qdio_stop_polling(q); 1650 1648
+2 -23
drivers/s390/cio/qdio_thinint.c
··· 82 82 INIT_LIST_HEAD(&irq_ptr->entry); 83 83 } 84 84 85 - static inline int has_multiple_inq_on_dsci(struct qdio_irq *irq_ptr) 86 - { 87 - return irq_ptr->nr_input_qs > 1; 88 - } 89 - 90 85 static inline int references_shared_dsci(struct qdio_irq *irq_ptr) 91 86 { 92 87 return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind; 93 - } 94 - 95 - void clear_nonshared_ind(struct qdio_irq *irq_ptr) 96 - { 97 - if (!is_thinint_irq(irq_ptr)) 98 - return; 99 - if (references_shared_dsci(irq_ptr) || 100 - has_multiple_inq_on_dsci(irq_ptr)) 101 - return; 102 - xchg(irq_ptr->dsci, 0); 103 88 } 104 89 105 90 int test_nonshared_ind(struct qdio_irq *irq_ptr) 106 91 { 107 92 if (!is_thinint_irq(irq_ptr)) 108 93 return 0; 109 - if (references_shared_dsci(irq_ptr) || 110 - has_multiple_inq_on_dsci(irq_ptr)) 94 + if (references_shared_dsci(irq_ptr)) 111 95 return 0; 112 96 if (*irq_ptr->dsci) 113 97 return 1; ··· 111 127 struct qdio_q *q; 112 128 int i; 113 129 114 - if (!references_shared_dsci(irq) && 115 - has_multiple_inq_on_dsci(irq)) 130 + if (!references_shared_dsci(irq)) 116 131 xchg(irq->dsci, 0); 117 132 118 133 if (irq->irq_poll) { ··· 122 139 123 140 return; 124 141 } 125 - 126 - if (!references_shared_dsci(irq) && 127 - !has_multiple_inq_on_dsci(irq)) 128 - xchg(irq->dsci, 0); 129 142 130 143 for_each_input_queue(irq, q, i) { 131 144 /*