aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/qdio_thinint.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/cio/qdio_thinint.c')
-rw-r--r--drivers/s390/cio/qdio_thinint.c114
1 files changed, 17 insertions, 97 deletions
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c
index c655d011a78d..981a77ea7ee2 100644
--- a/drivers/s390/cio/qdio_thinint.c
+++ b/drivers/s390/cio/qdio_thinint.c
@@ -43,9 +43,6 @@ struct indicator_t {
43}; 43};
44static struct indicator_t *q_indicators; 44static struct indicator_t *q_indicators;
45 45
46static void tiqdio_tasklet_fn(unsigned long data);
47static DECLARE_TASKLET(tiqdio_tasklet, tiqdio_tasklet_fn, 0);
48
49static int css_qdio_omit_svs; 46static int css_qdio_omit_svs;
50 47
51static inline unsigned long do_clear_global_summary(void) 48static inline unsigned long do_clear_global_summary(void)
@@ -103,11 +100,6 @@ void tiqdio_add_input_queues(struct qdio_irq *irq_ptr)
103 xchg(irq_ptr->dsci, 1); 100 xchg(irq_ptr->dsci, 1);
104} 101}
105 102
106/*
107 * we cannot stop the tiqdio tasklet here since it is for all
108 * thinint qdio devices and it must run as long as there is a
109 * thinint device left
110 */
111void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) 103void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr)
112{ 104{
113 struct qdio_q *q; 105 struct qdio_q *q;
@@ -126,79 +118,39 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr)
126 } 118 }
127} 119}
128 120
129static inline int tiqdio_inbound_q_done(struct qdio_q *q)
130{
131 unsigned char state = 0;
132
133 if (!atomic_read(&q->nr_buf_used))
134 return 1;
135
136 qdio_siga_sync_q(q);
137 get_buf_state(q, q->first_to_check, &state, 0);
138
139 if (state == SLSB_P_INPUT_PRIMED)
140 /* more work coming */
141 return 0;
142 return 1;
143}
144
145static inline int shared_ind(struct qdio_irq *irq_ptr) 121static inline int shared_ind(struct qdio_irq *irq_ptr)
146{ 122{
147 return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind; 123 return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind;
148} 124}
149 125
150static void __tiqdio_inbound_processing(struct qdio_q *q) 126/**
127 * tiqdio_thinint_handler - thin interrupt handler for qdio
128 * @ind: pointer to adapter local summary indicator
129 * @drv_data: NULL
130 */
131static void tiqdio_thinint_handler(void *ind, void *drv_data)
151{ 132{
152 qdio_perf_stat_inc(&perf_stats.thinint_inbound); 133 struct qdio_q *q;
153 qdio_sync_after_thinint(q); 134
135 qdio_perf_stat_inc(&perf_stats.thin_int);
154 136
155 /* 137 /*
156 * Maybe we have work on our outbound queues... at least 138 * SVS only when needed: issue SVS to benefit from iqdio interrupt
157 * we have to check the PCI capable queues. 139 * avoidance (SVS clears adapter interrupt suppression overwrite)
158 */ 140 */
159 qdio_check_outbound_after_thinint(q); 141 if (!css_qdio_omit_svs)
160 142 do_clear_global_summary();
161 if (!qdio_inbound_q_moved(q))
162 return;
163
164 qdio_kick_handler(q);
165
166 if (!tiqdio_inbound_q_done(q)) {
167 qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop);
168 if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED))
169 tasklet_schedule(&q->tasklet);
170 }
171 143
172 qdio_stop_polling(q);
173 /* 144 /*
174 * We need to check again to not lose initiative after 145 * reset local summary indicator (tiqdio_alsi) to stop adapter
175 * resetting the ACK state. 146 * interrupts for now
176 */ 147 */
177 if (!tiqdio_inbound_q_done(q)) { 148 xchg((u8 *)ind, 0);
178 qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop2);
179 if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED))
180 tasklet_schedule(&q->tasklet);
181 }
182}
183
184void tiqdio_inbound_processing(unsigned long data)
185{
186 struct qdio_q *q = (struct qdio_q *)data;
187
188 __tiqdio_inbound_processing(q);
189}
190
191/* check for work on all inbound thinint queues */
192static void tiqdio_tasklet_fn(unsigned long data)
193{
194 struct qdio_q *q;
195
196 qdio_perf_stat_inc(&perf_stats.tasklet_thinint);
197again:
198 149
199 /* protect tiq_list entries, only changed in activate or shutdown */ 150 /* protect tiq_list entries, only changed in activate or shutdown */
200 rcu_read_lock(); 151 rcu_read_lock();
201 152
153 /* check for work on all inbound thinint queues */
202 list_for_each_entry_rcu(q, &tiq_list, entry) 154 list_for_each_entry_rcu(q, &tiq_list, entry)
203 /* only process queues from changed sets */ 155 /* only process queues from changed sets */
204 if (*q->irq_ptr->dsci) { 156 if (*q->irq_ptr->dsci) {
@@ -226,37 +178,6 @@ again:
226 if (*tiqdio_alsi) 178 if (*tiqdio_alsi)
227 xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 1); 179 xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 1);
228 } 180 }
229
230 /* check for more work */
231 if (*tiqdio_alsi) {
232 xchg(tiqdio_alsi, 0);
233 qdio_perf_stat_inc(&perf_stats.tasklet_thinint_loop);
234 goto again;
235 }
236}
237
238/**
239 * tiqdio_thinint_handler - thin interrupt handler for qdio
240 * @ind: pointer to adapter local summary indicator
241 * @drv_data: NULL
242 */
243static void tiqdio_thinint_handler(void *ind, void *drv_data)
244{
245 qdio_perf_stat_inc(&perf_stats.thin_int);
246
247 /*
248 * SVS only when needed: issue SVS to benefit from iqdio interrupt
249 * avoidance (SVS clears adapter interrupt suppression overwrite)
250 */
251 if (!css_qdio_omit_svs)
252 do_clear_global_summary();
253
254 /*
255 * reset local summary indicator (tiqdio_alsi) to stop adapter
256 * interrupts for now, the tasklet will clean all dsci's
257 */
258 xchg((u8 *)ind, 0);
259 tasklet_hi_schedule(&tiqdio_tasklet);
260} 181}
261 182
262static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset) 183static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset)
@@ -376,5 +297,4 @@ void __exit tiqdio_unregister_thinints(void)
376 s390_unregister_adapter_interrupt(tiqdio_alsi, QDIO_AIRQ_ISC); 297 s390_unregister_adapter_interrupt(tiqdio_alsi, QDIO_AIRQ_ISC);
377 isc_unregister(QDIO_AIRQ_ISC); 298 isc_unregister(QDIO_AIRQ_ISC);
378 } 299 }
379 tasklet_kill(&tiqdio_tasklet);
380} 300}