.. | .. |
---|
39 | 39 | static LIST_HEAD(tiq_list); |
---|
40 | 40 | static DEFINE_MUTEX(tiq_list_lock); |
---|
41 | 41 | |
---|
42 | | -/* Adapter interrupt definitions */ |
---|
43 | | -static void tiqdio_thinint_handler(struct airq_struct *airq); |
---|
44 | | - |
---|
45 | | -static struct airq_struct tiqdio_airq = { |
---|
46 | | - .handler = tiqdio_thinint_handler, |
---|
47 | | - .isc = QDIO_AIRQ_ISC, |
---|
48 | | -}; |
---|
49 | | - |
---|
50 | 42 | static struct indicator_t *q_indicators; |
---|
51 | 43 | |
---|
52 | 44 | u64 last_ai_time; |
---|
.. | .. |
---|
74 | 66 | atomic_dec(&ind->count); |
---|
75 | 67 | } |
---|
76 | 68 | |
---|
77 | | -void tiqdio_add_input_queues(struct qdio_irq *irq_ptr) |
---|
| 69 | +void tiqdio_add_device(struct qdio_irq *irq_ptr) |
---|
78 | 70 | { |
---|
79 | 71 | mutex_lock(&tiq_list_lock); |
---|
80 | | - list_add_rcu(&irq_ptr->input_qs[0]->entry, &tiq_list); |
---|
| 72 | + list_add_rcu(&irq_ptr->entry, &tiq_list); |
---|
81 | 73 | mutex_unlock(&tiq_list_lock); |
---|
82 | 74 | } |
---|
83 | 75 | |
---|
84 | | -void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) |
---|
| 76 | +void tiqdio_remove_device(struct qdio_irq *irq_ptr) |
---|
85 | 77 | { |
---|
86 | | - struct qdio_q *q; |
---|
87 | | - |
---|
88 | | - q = irq_ptr->input_qs[0]; |
---|
89 | | - if (!q) |
---|
90 | | - return; |
---|
91 | | - |
---|
92 | 78 | mutex_lock(&tiq_list_lock); |
---|
93 | | - list_del_rcu(&q->entry); |
---|
| 79 | + list_del_rcu(&irq_ptr->entry); |
---|
94 | 80 | mutex_unlock(&tiq_list_lock); |
---|
95 | 81 | synchronize_rcu(); |
---|
96 | | - INIT_LIST_HEAD(&q->entry); |
---|
97 | | -} |
---|
98 | | - |
---|
99 | | -static inline int has_multiple_inq_on_dsci(struct qdio_irq *irq_ptr) |
---|
100 | | -{ |
---|
101 | | - return irq_ptr->nr_input_qs > 1; |
---|
| 82 | + INIT_LIST_HEAD(&irq_ptr->entry); |
---|
102 | 83 | } |
---|
103 | 84 | |
---|
104 | 85 | static inline int references_shared_dsci(struct qdio_irq *irq_ptr) |
---|
.. | .. |
---|
106 | 87 | return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind; |
---|
107 | 88 | } |
---|
108 | 89 | |
---|
109 | | -static inline int shared_ind(struct qdio_irq *irq_ptr) |
---|
110 | | -{ |
---|
111 | | - return references_shared_dsci(irq_ptr) || |
---|
112 | | - has_multiple_inq_on_dsci(irq_ptr); |
---|
113 | | -} |
---|
114 | | - |
---|
115 | | -void clear_nonshared_ind(struct qdio_irq *irq_ptr) |
---|
116 | | -{ |
---|
117 | | - if (!is_thinint_irq(irq_ptr)) |
---|
118 | | - return; |
---|
119 | | - if (shared_ind(irq_ptr)) |
---|
120 | | - return; |
---|
121 | | - xchg(irq_ptr->dsci, 0); |
---|
122 | | -} |
---|
123 | | - |
---|
124 | 90 | int test_nonshared_ind(struct qdio_irq *irq_ptr) |
---|
125 | 91 | { |
---|
126 | 92 | if (!is_thinint_irq(irq_ptr)) |
---|
127 | 93 | return 0; |
---|
128 | | - if (shared_ind(irq_ptr)) |
---|
| 94 | + if (references_shared_dsci(irq_ptr)) |
---|
129 | 95 | return 0; |
---|
130 | 96 | if (*irq_ptr->dsci) |
---|
131 | 97 | return 1; |
---|
.. | .. |
---|
145 | 111 | struct qdio_q *q; |
---|
146 | 112 | int i; |
---|
147 | 113 | |
---|
148 | | - if (!references_shared_dsci(irq) && |
---|
149 | | - has_multiple_inq_on_dsci(irq)) |
---|
| 114 | + if (!references_shared_dsci(irq)) |
---|
150 | 115 | xchg(irq->dsci, 0); |
---|
151 | 116 | |
---|
| 117 | + if (irq->irq_poll) { |
---|
| 118 | + if (!test_and_set_bit(QDIO_IRQ_DISABLED, &irq->poll_state)) |
---|
| 119 | + irq->irq_poll(irq->cdev, irq->int_parm); |
---|
| 120 | + else |
---|
| 121 | + QDIO_PERF_STAT_INC(irq, int_discarded); |
---|
| 122 | + |
---|
| 123 | + return; |
---|
| 124 | + } |
---|
| 125 | + |
---|
152 | 126 | for_each_input_queue(irq, q, i) { |
---|
153 | | - if (q->u.in.queue_start_poll) { |
---|
154 | | - /* skip if polling is enabled or already in work */ |
---|
155 | | - if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED, |
---|
156 | | - &q->u.in.queue_irq_state)) { |
---|
157 | | - qperf_inc(q, int_discarded); |
---|
158 | | - continue; |
---|
159 | | - } |
---|
160 | | - |
---|
161 | | - /* avoid dsci clear here, done after processing */ |
---|
162 | | - q->u.in.queue_start_poll(irq->cdev, q->nr, |
---|
163 | | - irq->int_parm); |
---|
164 | | - } else { |
---|
165 | | - if (!shared_ind(irq)) |
---|
166 | | - xchg(irq->dsci, 0); |
---|
167 | | - |
---|
168 | | - /* |
---|
169 | | - * Call inbound processing but not directly |
---|
170 | | - * since that could starve other thinint queues. |
---|
171 | | - */ |
---|
172 | | - tasklet_schedule(&q->tasklet); |
---|
173 | | - } |
---|
| 127 | + /* |
---|
| 128 | + * Call inbound processing but not directly |
---|
| 129 | + * since that could starve other thinint queues. |
---|
| 130 | + */ |
---|
| 131 | + tasklet_schedule(&q->tasklet); |
---|
174 | 132 | } |
---|
175 | 133 | } |
---|
176 | 134 | |
---|
177 | 135 | /** |
---|
178 | 136 | * tiqdio_thinint_handler - thin interrupt handler for qdio |
---|
179 | 137 | * @airq: pointer to adapter interrupt descriptor |
---|
| 138 | + * @floating: flag to recognize floating vs. directed interrupts (unused) |
---|
180 | 139 | */ |
---|
181 | | -static void tiqdio_thinint_handler(struct airq_struct *airq) |
---|
| 140 | +static void tiqdio_thinint_handler(struct airq_struct *airq, bool floating) |
---|
182 | 141 | { |
---|
183 | 142 | u32 si_used = clear_shared_ind(); |
---|
184 | | - struct qdio_q *q; |
---|
| 143 | + struct qdio_irq *irq; |
---|
185 | 144 | |
---|
186 | 145 | last_ai_time = S390_lowcore.int_clock; |
---|
187 | 146 | inc_irq_stat(IRQIO_QAI); |
---|
.. | .. |
---|
189 | 148 | /* protect tiq_list entries, only changed in activate or shutdown */ |
---|
190 | 149 | rcu_read_lock(); |
---|
191 | 150 | |
---|
192 | | - /* check for work on all inbound thinint queues */ |
---|
193 | | - list_for_each_entry_rcu(q, &tiq_list, entry) { |
---|
194 | | - struct qdio_irq *irq; |
---|
195 | | - |
---|
| 151 | + list_for_each_entry_rcu(irq, &tiq_list, entry) { |
---|
196 | 152 | /* only process queues from changed sets */ |
---|
197 | | - irq = q->irq_ptr; |
---|
198 | 153 | if (unlikely(references_shared_dsci(irq))) { |
---|
199 | 154 | if (!si_used) |
---|
200 | 155 | continue; |
---|
.. | .. |
---|
203 | 158 | |
---|
204 | 159 | tiqdio_call_inq_handlers(irq); |
---|
205 | 160 | |
---|
206 | | - qperf_inc(q, adapter_int); |
---|
| 161 | + QDIO_PERF_STAT_INC(irq, adapter_int); |
---|
207 | 162 | } |
---|
208 | 163 | rcu_read_unlock(); |
---|
209 | 164 | } |
---|
| 165 | + |
---|
| 166 | +static struct airq_struct tiqdio_airq = { |
---|
| 167 | + .handler = tiqdio_thinint_handler, |
---|
| 168 | + .isc = QDIO_AIRQ_ISC, |
---|
| 169 | +}; |
---|
210 | 170 | |
---|
211 | 171 | static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset) |
---|
212 | 172 | { |
---|
.. | .. |
---|
223 | 183 | } |
---|
224 | 184 | |
---|
225 | 185 | rc = chsc_sadc(irq_ptr->schid, scssc, summary_indicator_addr, |
---|
226 | | - subchannel_indicator_addr); |
---|
| 186 | + subchannel_indicator_addr, tiqdio_airq.isc); |
---|
227 | 187 | if (rc) { |
---|
228 | 188 | DBF_ERROR("%4x SSI r:%4x", irq_ptr->schid.sch_no, |
---|
229 | 189 | scssc->response.code); |
---|
.. | .. |
---|
235 | 195 | DBF_HEX(&subchannel_indicator_addr, sizeof(subchannel_indicator_addr)); |
---|
236 | 196 | out: |
---|
237 | 197 | return rc; |
---|
238 | | -} |
---|
239 | | - |
---|
240 | | -/* allocate non-shared indicators and shared indicator */ |
---|
241 | | -int __init tiqdio_allocate_memory(void) |
---|
242 | | -{ |
---|
243 | | - q_indicators = kcalloc(TIQDIO_NR_INDICATORS, |
---|
244 | | - sizeof(struct indicator_t), |
---|
245 | | - GFP_KERNEL); |
---|
246 | | - if (!q_indicators) |
---|
247 | | - return -ENOMEM; |
---|
248 | | - return 0; |
---|
249 | | -} |
---|
250 | | - |
---|
251 | | -void tiqdio_free_memory(void) |
---|
252 | | -{ |
---|
253 | | - kfree(q_indicators); |
---|
254 | | -} |
---|
255 | | - |
---|
256 | | -int __init tiqdio_register_thinints(void) |
---|
257 | | -{ |
---|
258 | | - int rc; |
---|
259 | | - |
---|
260 | | - rc = register_adapter_interrupt(&tiqdio_airq); |
---|
261 | | - if (rc) { |
---|
262 | | - DBF_EVENT("RTI:%x", rc); |
---|
263 | | - return rc; |
---|
264 | | - } |
---|
265 | | - return 0; |
---|
266 | 198 | } |
---|
267 | 199 | |
---|
268 | 200 | int qdio_establish_thinint(struct qdio_irq *irq_ptr) |
---|
.. | .. |
---|
292 | 224 | put_indicator(irq_ptr->dsci); |
---|
293 | 225 | } |
---|
294 | 226 | |
---|
295 | | -void __exit tiqdio_unregister_thinints(void) |
---|
| 227 | +int __init qdio_thinint_init(void) |
---|
| 228 | +{ |
---|
| 229 | + int rc; |
---|
| 230 | + |
---|
| 231 | + q_indicators = kcalloc(TIQDIO_NR_INDICATORS, sizeof(struct indicator_t), |
---|
| 232 | + GFP_KERNEL); |
---|
| 233 | + if (!q_indicators) |
---|
| 234 | + return -ENOMEM; |
---|
| 235 | + |
---|
| 236 | + rc = register_adapter_interrupt(&tiqdio_airq); |
---|
| 237 | + if (rc) { |
---|
| 238 | + DBF_EVENT("RTI:%x", rc); |
---|
| 239 | + kfree(q_indicators); |
---|
| 240 | + return rc; |
---|
| 241 | + } |
---|
| 242 | + return 0; |
---|
| 243 | +} |
---|
| 244 | + |
---|
| 245 | +void __exit qdio_thinint_exit(void) |
---|
296 | 246 | { |
---|
297 | 247 | WARN_ON(!list_empty(&tiq_list)); |
---|
298 | 248 | unregister_adapter_interrupt(&tiqdio_airq); |
---|
| 249 | + kfree(q_indicators); |
---|
299 | 250 | } |
---|