aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/qdio_thinint.c
diff options
context:
space:
mode:
authorJan Glauber <jang@linux.vnet.ibm.com>2010-09-07 17:14:39 -0400
committerDavid S. Miller <davem@davemloft.net>2010-09-08 17:31:00 -0400
commitd36deae75011a7890f0e730dd0f867c64081cb50 (patch)
treed24672cf5cc40c637186362187450362cabefd24 /drivers/s390/cio/qdio_thinint.c
parente508be174ad36b0cf9b324cd04978c2b13c21502 (diff)
qdio: extend API to allow polling
Extend the qdio API to allow polling in the upper-layer driver. This is needed by qeth to use NAPI. To use the new interface the upper-layer driver must specify the queue_start_poll(). This callback is used to signal the upper-layer driver that is has initiative and must process the inbound queue by calling qdio_get_next_buffers(). If the upper-layer driver wants to stop polling it calls qdio_start_irq(). Since adapter interrupts are not completely stoppable qdio implements a software bit QDIO_QUEUE_IRQS_DISABLED to safely disable interrupts for an input queue. The old interface is preserved and will be used as is by zfcp. Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/s390/cio/qdio_thinint.c')
-rw-r--r--drivers/s390/cio/qdio_thinint.c66
1 files changed, 38 insertions, 28 deletions
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c
index 8daf1b99f153..752dbee06af5 100644
--- a/drivers/s390/cio/qdio_thinint.c
+++ b/drivers/s390/cio/qdio_thinint.c
@@ -25,24 +25,20 @@
25 */ 25 */
26#define TIQDIO_NR_NONSHARED_IND 63 26#define TIQDIO_NR_NONSHARED_IND 63
27#define TIQDIO_NR_INDICATORS (TIQDIO_NR_NONSHARED_IND + 1) 27#define TIQDIO_NR_INDICATORS (TIQDIO_NR_NONSHARED_IND + 1)
28#define TIQDIO_SHARED_IND 63
29 28
30/* list of thin interrupt input queues */ 29/* list of thin interrupt input queues */
31static LIST_HEAD(tiq_list); 30static LIST_HEAD(tiq_list);
32DEFINE_MUTEX(tiq_list_lock); 31DEFINE_MUTEX(tiq_list_lock);
33 32
34/* adapter local summary indicator */ 33/* adapter local summary indicator */
35static unsigned char *tiqdio_alsi; 34static u8 *tiqdio_alsi;
36 35
37/* device state change indicators */ 36struct indicator_t *q_indicators;
38struct indicator_t {
39 u32 ind; /* u32 because of compare-and-swap performance */
40 atomic_t count; /* use count, 0 or 1 for non-shared indicators */
41};
42static struct indicator_t *q_indicators;
43 37
44static int css_qdio_omit_svs; 38static int css_qdio_omit_svs;
45 39
40static u64 last_ai_time;
41
46static inline unsigned long do_clear_global_summary(void) 42static inline unsigned long do_clear_global_summary(void)
47{ 43{
48 register unsigned long __fn asm("1") = 3; 44 register unsigned long __fn asm("1") = 3;
@@ -116,59 +112,73 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr)
116 } 112 }
117} 113}
118 114
119static inline int shared_ind(struct qdio_irq *irq_ptr) 115static inline int shared_ind_used(void)
120{ 116{
121 return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind; 117 return atomic_read(&q_indicators[TIQDIO_SHARED_IND].count);
122} 118}
123 119
124/** 120/**
125 * tiqdio_thinint_handler - thin interrupt handler for qdio 121 * tiqdio_thinint_handler - thin interrupt handler for qdio
126 * @ind: pointer to adapter local summary indicator 122 * @alsi: pointer to adapter local summary indicator
127 * @drv_data: NULL 123 * @data: NULL
128 */ 124 */
129static void tiqdio_thinint_handler(void *ind, void *drv_data) 125static void tiqdio_thinint_handler(void *alsi, void *data)
130{ 126{
131 struct qdio_q *q; 127 struct qdio_q *q;
132 128
129 last_ai_time = S390_lowcore.int_clock;
130
133 /* 131 /*
134 * SVS only when needed: issue SVS to benefit from iqdio interrupt 132 * SVS only when needed: issue SVS to benefit from iqdio interrupt
135 * avoidance (SVS clears adapter interrupt suppression overwrite) 133 * avoidance (SVS clears adapter interrupt suppression overwrite).
136 */ 134 */
137 if (!css_qdio_omit_svs) 135 if (!css_qdio_omit_svs)
138 do_clear_global_summary(); 136 do_clear_global_summary();
139 137
140 /* 138 /* reset local summary indicator */
141 * reset local summary indicator (tiqdio_alsi) to stop adapter 139 if (shared_ind_used())
142 * interrupts for now 140 xchg(tiqdio_alsi, 0);
143 */
144 xchg((u8 *)ind, 0);
145 141
146 /* protect tiq_list entries, only changed in activate or shutdown */ 142 /* protect tiq_list entries, only changed in activate or shutdown */
147 rcu_read_lock(); 143 rcu_read_lock();
148 144
149 /* check for work on all inbound thinint queues */ 145 /* check for work on all inbound thinint queues */
150 list_for_each_entry_rcu(q, &tiq_list, entry) 146 list_for_each_entry_rcu(q, &tiq_list, entry) {
147
151 /* only process queues from changed sets */ 148 /* only process queues from changed sets */
152 if (*q->irq_ptr->dsci) { 149 if (!*q->irq_ptr->dsci)
153 qperf_inc(q, adapter_int); 150 continue;
154 151
152 if (q->u.in.queue_start_poll) {
153 /* skip if polling is enabled or already in work */
154 if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED,
155 &q->u.in.queue_irq_state)) {
156 qperf_inc(q, int_discarded);
157 continue;
158 }
159
160 /* avoid dsci clear here, done after processing */
161 q->u.in.queue_start_poll(q->irq_ptr->cdev, q->nr,
162 q->irq_ptr->int_parm);
163 } else {
155 /* only clear it if the indicator is non-shared */ 164 /* only clear it if the indicator is non-shared */
156 if (!shared_ind(q->irq_ptr)) 165 if (!shared_ind(q->irq_ptr))
157 xchg(q->irq_ptr->dsci, 0); 166 xchg(q->irq_ptr->dsci, 0);
158 /* 167 /*
159 * don't call inbound processing directly since 168 * Call inbound processing but not directly
160 * that could starve other thinint queues 169 * since that could starve other thinint queues.
161 */ 170 */
162 tasklet_schedule(&q->tasklet); 171 tasklet_schedule(&q->tasklet);
163 } 172 }
164 173 qperf_inc(q, adapter_int);
174 }
165 rcu_read_unlock(); 175 rcu_read_unlock();
166 176
167 /* 177 /*
168 * if we used the shared indicator clear it now after all queues 178 * If the shared indicator was used clear it now after all queues
169 * were processed 179 * were processed.
170 */ 180 */
171 if (atomic_read(&q_indicators[TIQDIO_SHARED_IND].count)) { 181 if (shared_ind_used()) {
172 xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 0); 182 xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 0);
173 183
174 /* prevent racing */ 184 /* prevent racing */