@@ -161,11 +161,166 @@ irq_hw_number_t ipi_get_hwirq(unsigned int irq, unsigned int cpu)
161
161
* Get the real hardware irq number if the underlying implementation
162
162
* uses a seperate irq per cpu. If the underlying implementation uses
163
163
* a single hardware irq for all cpus then the IPI send mechanism
164
- * needs to take care of this .
164
+ * needs to take care of the cpu destinations .
165
165
*/
166
166
if (irq_domain_is_ipi_per_cpu (data -> domain ))
167
167
data = irq_get_irq_data (irq + cpu - data -> common -> ipi_offset );
168
168
169
169
return data ? irqd_to_hwirq (data ) : INVALID_HWIRQ ;
170
170
}
171
171
EXPORT_SYMBOL_GPL (ipi_get_hwirq );
172
+
173
+ static int ipi_send_verify (struct irq_chip * chip , struct irq_data * data ,
174
+ const struct cpumask * dest , unsigned int cpu )
175
+ {
176
+ struct cpumask * ipimask = irq_data_get_affinity_mask (data );
177
+
178
+ if (!chip || !ipimask )
179
+ return - EINVAL ;
180
+
181
+ if (!chip -> ipi_send_single && !chip -> ipi_send_mask )
182
+ return - EINVAL ;
183
+
184
+ if (cpu > nr_cpu_ids )
185
+ return - EINVAL ;
186
+
187
+ if (dest ) {
188
+ if (!cpumask_subset (dest , ipimask ))
189
+ return - EINVAL ;
190
+ } else {
191
+ if (!cpumask_test_cpu (cpu , ipimask ))
192
+ return - EINVAL ;
193
+ }
194
+ return 0 ;
195
+ }
196
+
197
+ /**
198
+ * __ipi_send_single - send an IPI to a target Linux SMP CPU
199
+ * @desc: pointer to irq_desc of the IRQ
200
+ * @cpu: destination CPU, must in the destination mask passed to
201
+ * irq_reserve_ipi()
202
+ *
203
+ * This function is for architecture or core code to speed up IPI sending. Not
204
+ * usable from driver code.
205
+ *
206
+ * Returns zero on success and negative error number on failure.
207
+ */
208
+ int __ipi_send_single (struct irq_desc * desc , unsigned int cpu )
209
+ {
210
+ struct irq_data * data = irq_desc_get_irq_data (desc );
211
+ struct irq_chip * chip = irq_data_get_irq_chip (data );
212
+
213
+ #ifdef DEBUG
214
+ /*
215
+ * Minimise the overhead by omitting the checks for Linux SMP IPIs.
216
+ * Since the callers should be arch or core code which is generally
217
+ * trusted, only check for errors when debugging.
218
+ */
219
+ if (WARN_ON_ONCE (ipi_send_verify (chip , data , NULL , cpu )))
220
+ return - EINVAL ;
221
+ #endif
222
+ if (!chip -> ipi_send_single ) {
223
+ chip -> ipi_send_mask (data , cpumask_of (cpu ));
224
+ return 0 ;
225
+ }
226
+
227
+ /* FIXME: Store this information in irqdata flags */
228
+ if (irq_domain_is_ipi_per_cpu (data -> domain ) &&
229
+ cpu != data -> common -> ipi_offset ) {
230
+ /* use the correct data for that cpu */
231
+ unsigned irq = data -> irq + cpu - data -> common -> ipi_offset ;
232
+
233
+ data = irq_get_irq_data (irq );
234
+ }
235
+ chip -> ipi_send_single (data , cpu );
236
+ return 0 ;
237
+ }
238
+
239
+ /**
240
+ * ipi_send_mask - send an IPI to target Linux SMP CPU(s)
241
+ * @desc: pointer to irq_desc of the IRQ
242
+ * @dest: dest CPU(s), must be a subset of the mask passed to
243
+ * irq_reserve_ipi()
244
+ *
245
+ * This function is for architecture or core code to speed up IPI sending. Not
246
+ * usable from driver code.
247
+ *
248
+ * Returns zero on success and negative error number on failure.
249
+ */
250
+ int __ipi_send_mask (struct irq_desc * desc , const struct cpumask * dest )
251
+ {
252
+ struct irq_data * data = irq_desc_get_irq_data (desc );
253
+ struct irq_chip * chip = irq_data_get_irq_chip (data );
254
+ unsigned int cpu ;
255
+
256
+ #ifdef DEBUG
257
+ /*
258
+ * Minimise the overhead by omitting the checks for Linux SMP IPIs.
259
+ * Since the callers should be arch or core code which is generally
260
+ * trusted, only check for errors when debugging.
261
+ */
262
+ if (WARN_ON_ONCE (ipi_send_verify (chip , data , dest , 0 )))
263
+ return - EINVAL ;
264
+ #endif
265
+ if (chip -> ipi_send_mask ) {
266
+ chip -> ipi_send_mask (data , dest );
267
+ return 0 ;
268
+ }
269
+
270
+ if (irq_domain_is_ipi_per_cpu (data -> domain )) {
271
+ unsigned int base = data -> irq ;
272
+
273
+ for_each_cpu (cpu , dest ) {
274
+ unsigned irq = base + cpu - data -> common -> ipi_offset ;
275
+
276
+ data = irq_get_irq_data (irq );
277
+ chip -> ipi_send_single (data , cpu );
278
+ }
279
+ } else {
280
+ for_each_cpu (cpu , dest )
281
+ chip -> ipi_send_single (data , cpu );
282
+ }
283
+ return 0 ;
284
+ }
285
+
286
+ /**
287
+ * ipi_send_single - Send an IPI to a single CPU
288
+ * @virq: linux irq number from irq_reserve_ipi()
289
+ * @cpu: destination CPU, must in the destination mask passed to
290
+ * irq_reserve_ipi()
291
+ *
292
+ * Returns zero on success and negative error number on failure.
293
+ */
294
+ int ipi_send_single (unsigned int virq , unsigned int cpu )
295
+ {
296
+ struct irq_desc * desc = irq_to_desc (virq );
297
+ struct irq_data * data = desc ? irq_desc_get_irq_data (desc ) : NULL ;
298
+ struct irq_chip * chip = data ? irq_data_get_irq_chip (data ) : NULL ;
299
+
300
+ if (WARN_ON_ONCE (ipi_send_verify (chip , data , NULL , cpu )))
301
+ return - EINVAL ;
302
+
303
+ return __ipi_send_single (desc , cpu );
304
+ }
305
+ EXPORT_SYMBOL_GPL (ipi_send_single );
306
+
307
+ /**
308
+ * ipi_send_mask - Send an IPI to target CPU(s)
309
+ * @virq: linux irq number from irq_reserve_ipi()
310
+ * @dest: dest CPU(s), must be a subset of the mask passed to
311
+ * irq_reserve_ipi()
312
+ *
313
+ * Returns zero on success and negative error number on failure.
314
+ */
315
+ int ipi_send_mask (unsigned int virq , const struct cpumask * dest )
316
+ {
317
+ struct irq_desc * desc = irq_to_desc (virq );
318
+ struct irq_data * data = desc ? irq_desc_get_irq_data (desc ) : NULL ;
319
+ struct irq_chip * chip = data ? irq_data_get_irq_chip (data ) : NULL ;
320
+
321
+ if (WARN_ON_ONCE (ipi_send_verify (chip , data , dest , 0 )))
322
+ return - EINVAL ;
323
+
324
+ return __ipi_send_mask (desc , dest );
325
+ }
326
+ EXPORT_SYMBOL_GPL (ipi_send_mask );
0 commit comments