diff options
-rw-r--r-- | drivers/s390/cio/qdio_thinint.c | 65 |
1 files changed, 21 insertions, 44 deletions
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index e122f780f5ee..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 | }; |
44 | static struct indicator_t *q_indicators; | 44 | static struct indicator_t *q_indicators; |
45 | 45 | ||
46 | static void tiqdio_tasklet_fn(unsigned long data); | ||
47 | static DECLARE_TASKLET(tiqdio_tasklet, tiqdio_tasklet_fn, 0); | ||
48 | |||
49 | static int css_qdio_omit_svs; | 46 | static int css_qdio_omit_svs; |
50 | 47 | ||
51 | static inline unsigned long do_clear_global_summary(void) | 48 | static 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 | */ | ||
111 | void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) | 103 | void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) |
112 | { | 104 | { |
113 | struct qdio_q *q; | 105 | struct qdio_q *q; |
@@ -131,17 +123,34 @@ static inline int shared_ind(struct qdio_irq *irq_ptr) | |||
131 | return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind; | 123 | return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind; |
132 | } | 124 | } |
133 | 125 | ||
134 | /* check for work on all inbound thinint queues */ | 126 | /** |
135 | static void tiqdio_tasklet_fn(unsigned long data) | 127 | * tiqdio_thinint_handler - thin interrupt handler for qdio |
128 | * @ind: pointer to adapter local summary indicator | ||
129 | * @drv_data: NULL | ||
130 | */ | ||
131 | static void tiqdio_thinint_handler(void *ind, void *drv_data) | ||
136 | { | 132 | { |
137 | struct qdio_q *q; | 133 | struct qdio_q *q; |
138 | 134 | ||
139 | qdio_perf_stat_inc(&perf_stats.tasklet_thinint); | 135 | qdio_perf_stat_inc(&perf_stats.thin_int); |
140 | again: | 136 | |
137 | /* | ||
138 | * SVS only when needed: issue SVS to benefit from iqdio interrupt | ||
139 | * avoidance (SVS clears adapter interrupt suppression overwrite) | ||
140 | */ | ||
141 | if (!css_qdio_omit_svs) | ||
142 | do_clear_global_summary(); | ||
143 | |||
144 | /* | ||
145 | * reset local summary indicator (tiqdio_alsi) to stop adapter | ||
146 | * interrupts for now | ||
147 | */ | ||
148 | xchg((u8 *)ind, 0); | ||
141 | 149 | ||
142 | /* protect tiq_list entries, only changed in activate or shutdown */ | 150 | /* protect tiq_list entries, only changed in activate or shutdown */ |
143 | rcu_read_lock(); | 151 | rcu_read_lock(); |
144 | 152 | ||
153 | /* check for work on all inbound thinint queues */ | ||
145 | list_for_each_entry_rcu(q, &tiq_list, entry) | 154 | list_for_each_entry_rcu(q, &tiq_list, entry) |
146 | /* only process queues from changed sets */ | 155 | /* only process queues from changed sets */ |
147 | if (*q->irq_ptr->dsci) { | 156 | if (*q->irq_ptr->dsci) { |
@@ -169,37 +178,6 @@ again: | |||
169 | if (*tiqdio_alsi) | 178 | if (*tiqdio_alsi) |
170 | xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 1); | 179 | xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 1); |
171 | } | 180 | } |
172 | |||
173 | /* check for more work */ | ||
174 | if (*tiqdio_alsi) { | ||
175 | xchg(tiqdio_alsi, 0); | ||
176 | qdio_perf_stat_inc(&perf_stats.tasklet_thinint_loop); | ||
177 | goto again; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | /** | ||
182 | * tiqdio_thinint_handler - thin interrupt handler for qdio | ||
183 | * @ind: pointer to adapter local summary indicator | ||
184 | * @drv_data: NULL | ||
185 | */ | ||
186 | static void tiqdio_thinint_handler(void *ind, void *drv_data) | ||
187 | { | ||
188 | qdio_perf_stat_inc(&perf_stats.thin_int); | ||
189 | |||
190 | /* | ||
191 | * SVS only when needed: issue SVS to benefit from iqdio interrupt | ||
192 | * avoidance (SVS clears adapter interrupt suppression overwrite) | ||
193 | */ | ||
194 | if (!css_qdio_omit_svs) | ||
195 | do_clear_global_summary(); | ||
196 | |||
197 | /* | ||
198 | * reset local summary indicator (tiqdio_alsi) to stop adapter | ||
199 | * interrupts for now, the tasklet will clean all dsci's | ||
200 | */ | ||
201 | xchg((u8 *)ind, 0); | ||
202 | tasklet_hi_schedule(&tiqdio_tasklet); | ||
203 | } | 181 | } |
204 | 182 | ||
205 | static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset) | 183 | static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset) |
@@ -319,5 +297,4 @@ void __exit tiqdio_unregister_thinints(void) | |||
319 | s390_unregister_adapter_interrupt(tiqdio_alsi, QDIO_AIRQ_ISC); | 297 | s390_unregister_adapter_interrupt(tiqdio_alsi, QDIO_AIRQ_ISC); |
320 | isc_unregister(QDIO_AIRQ_ISC); | 298 | isc_unregister(QDIO_AIRQ_ISC); |
321 | } | 299 | } |
322 | tasklet_kill(&tiqdio_tasklet); | ||
323 | } | 300 | } |