@@ -32,7 +32,8 @@ struct apic_chip_data {
32
32
unsigned int prev_cpu ;
33
33
unsigned int irq ;
34
34
struct hlist_node clist ;
35
- u8 move_in_progress : 1 ;
35
+ unsigned int move_in_progress : 1 ,
36
+ is_managed : 1 ;
36
37
};
37
38
38
39
struct irq_domain * x86_vector_domain ;
@@ -152,6 +153,28 @@ static void apic_update_vector(struct irq_data *irqd, unsigned int newvec,
152
153
per_cpu (vector_irq , newcpu )[newvec ] = desc ;
153
154
}
154
155
156
+ static void vector_assign_managed_shutdown (struct irq_data * irqd )
157
+ {
158
+ unsigned int cpu = cpumask_first (cpu_online_mask );
159
+
160
+ apic_update_irq_cfg (irqd , MANAGED_IRQ_SHUTDOWN_VECTOR , cpu );
161
+ }
162
+
163
+ static int reserve_managed_vector (struct irq_data * irqd )
164
+ {
165
+ const struct cpumask * affmsk = irq_data_get_affinity_mask (irqd );
166
+ struct apic_chip_data * apicd = apic_chip_data (irqd );
167
+ unsigned long flags ;
168
+ int ret ;
169
+
170
+ raw_spin_lock_irqsave (& vector_lock , flags );
171
+ apicd -> is_managed = true;
172
+ ret = irq_matrix_reserve_managed (vector_matrix , affmsk );
173
+ raw_spin_unlock_irqrestore (& vector_lock , flags );
174
+ trace_vector_reserve_managed (irqd -> irq , ret );
175
+ return ret ;
176
+ }
177
+
155
178
static int allocate_vector (struct irq_data * irqd , const struct cpumask * dest )
156
179
{
157
180
struct apic_chip_data * apicd = apic_chip_data (irqd );
@@ -200,20 +223,65 @@ static int assign_irq_vector(struct irq_data *irqd, const struct cpumask *dest)
200
223
return ret ;
201
224
}
202
225
203
- static int assign_irq_vector_policy (struct irq_data * irqd ,
204
- struct irq_alloc_info * info , int node )
226
+ static int assign_irq_vector_any_locked (struct irq_data * irqd )
227
+ {
228
+ int node = irq_data_get_node (irqd );
229
+
230
+ if (node != NUMA_NO_NODE ) {
231
+ if (!assign_vector_locked (irqd , cpumask_of_node (node )))
232
+ return 0 ;
233
+ }
234
+ return assign_vector_locked (irqd , cpu_online_mask );
235
+ }
236
+
237
+ static int assign_irq_vector_any (struct irq_data * irqd )
238
+ {
239
+ unsigned long flags ;
240
+ int ret ;
241
+
242
+ raw_spin_lock_irqsave (& vector_lock , flags );
243
+ ret = assign_irq_vector_any_locked (irqd );
244
+ raw_spin_unlock_irqrestore (& vector_lock , flags );
245
+ return ret ;
246
+ }
247
+
248
+ static int
249
+ assign_irq_vector_policy (struct irq_data * irqd , struct irq_alloc_info * info )
205
250
{
251
+ if (irqd_affinity_is_managed (irqd ))
252
+ return reserve_managed_vector (irqd );
206
253
if (info -> mask )
207
254
return assign_irq_vector (irqd , info -> mask );
208
- if (node != NUMA_NO_NODE &&
209
- !assign_irq_vector (irqd , cpumask_of_node (node )))
255
+ return assign_irq_vector_any (irqd );
256
+ }
257
+
258
+ static int
259
+ assign_managed_vector (struct irq_data * irqd , const struct cpumask * dest )
260
+ {
261
+ const struct cpumask * affmsk = irq_data_get_affinity_mask (irqd );
262
+ struct apic_chip_data * apicd = apic_chip_data (irqd );
263
+ int vector , cpu ;
264
+
265
+ cpumask_and (vector_searchmask , vector_searchmask , affmsk );
266
+ cpu = cpumask_first (vector_searchmask );
267
+ if (cpu >= nr_cpu_ids )
268
+ return - EINVAL ;
269
+ /* set_affinity might call here for nothing */
270
+ if (apicd -> vector && cpumask_test_cpu (apicd -> cpu , vector_searchmask ))
210
271
return 0 ;
211
- return assign_irq_vector (irqd , cpu_online_mask );
272
+ vector = irq_matrix_alloc_managed (vector_matrix , cpu );
273
+ trace_vector_alloc_managed (irqd -> irq , vector , vector );
274
+ if (vector < 0 )
275
+ return vector ;
276
+ apic_update_vector (irqd , vector , cpu );
277
+ apic_update_irq_cfg (irqd , vector , cpu );
278
+ return 0 ;
212
279
}
213
280
214
281
static void clear_irq_vector (struct irq_data * irqd )
215
282
{
216
283
struct apic_chip_data * apicd = apic_chip_data (irqd );
284
+ bool managed = irqd_affinity_is_managed (irqd );
217
285
unsigned int vector = apicd -> vector ;
218
286
219
287
lockdep_assert_held (& vector_lock );
@@ -225,7 +293,7 @@ static void clear_irq_vector(struct irq_data *irqd)
225
293
apicd -> prev_cpu );
226
294
227
295
per_cpu (vector_irq , apicd -> cpu )[vector ] = VECTOR_UNUSED ;
228
- irq_matrix_free (vector_matrix , apicd -> cpu , vector , false );
296
+ irq_matrix_free (vector_matrix , apicd -> cpu , vector , managed );
229
297
apicd -> vector = 0 ;
230
298
231
299
/* Clean up move in progress */
@@ -234,12 +302,86 @@ static void clear_irq_vector(struct irq_data *irqd)
234
302
return ;
235
303
236
304
per_cpu (vector_irq , apicd -> prev_cpu )[vector ] = VECTOR_UNUSED ;
237
- irq_matrix_free (vector_matrix , apicd -> prev_cpu , vector , false );
305
+ irq_matrix_free (vector_matrix , apicd -> prev_cpu , vector , managed );
238
306
apicd -> prev_vector = 0 ;
239
307
apicd -> move_in_progress = 0 ;
240
308
hlist_del_init (& apicd -> clist );
241
309
}
242
310
311
+ static void x86_vector_deactivate (struct irq_domain * dom , struct irq_data * irqd )
312
+ {
313
+ struct apic_chip_data * apicd = apic_chip_data (irqd );
314
+ unsigned long flags ;
315
+
316
+ trace_vector_deactivate (irqd -> irq , apicd -> is_managed ,
317
+ false, false);
318
+
319
+ if (apicd -> is_managed )
320
+ return ;
321
+
322
+ raw_spin_lock_irqsave (& vector_lock , flags );
323
+ clear_irq_vector (irqd );
324
+ vector_assign_managed_shutdown (irqd );
325
+ raw_spin_unlock_irqrestore (& vector_lock , flags );
326
+ }
327
+
328
+ static int activate_managed (struct irq_data * irqd )
329
+ {
330
+ const struct cpumask * dest = irq_data_get_affinity_mask (irqd );
331
+ int ret ;
332
+
333
+ cpumask_and (vector_searchmask , dest , cpu_online_mask );
334
+ if (WARN_ON_ONCE (cpumask_empty (vector_searchmask ))) {
335
+ /* Something in the core code broke! Survive gracefully */
336
+ pr_err ("Managed startup for irq %u, but no CPU\n" , irqd -> irq );
337
+ return EINVAL ;
338
+ }
339
+
340
+ ret = assign_managed_vector (irqd , vector_searchmask );
341
+ /*
342
+ * This should not happen. The vector reservation got buggered. Handle
343
+ * it gracefully.
344
+ */
345
+ if (WARN_ON_ONCE (ret < 0 )) {
346
+ pr_err ("Managed startup irq %u, no vector available\n" ,
347
+ irqd -> irq );
348
+ }
349
+ return ret ;
350
+ }
351
+
352
+ static int x86_vector_activate (struct irq_domain * dom , struct irq_data * irqd ,
353
+ bool early )
354
+ {
355
+ struct apic_chip_data * apicd = apic_chip_data (irqd );
356
+ unsigned long flags ;
357
+ int ret = 0 ;
358
+
359
+ trace_vector_activate (irqd -> irq , apicd -> is_managed ,
360
+ false, early );
361
+
362
+ if (!apicd -> is_managed )
363
+ return 0 ;
364
+
365
+ raw_spin_lock_irqsave (& vector_lock , flags );
366
+ if (early || irqd_is_managed_and_shutdown (irqd ))
367
+ vector_assign_managed_shutdown (irqd );
368
+ else
369
+ ret = activate_managed (irqd );
370
+ raw_spin_unlock_irqrestore (& vector_lock , flags );
371
+ return ret ;
372
+ }
373
+
374
+ static void vector_free_reserved_and_managed (struct irq_data * irqd )
375
+ {
376
+ const struct cpumask * dest = irq_data_get_affinity_mask (irqd );
377
+ struct apic_chip_data * apicd = apic_chip_data (irqd );
378
+
379
+ trace_vector_teardown (irqd -> irq , apicd -> is_managed , false);
380
+
381
+ if (apicd -> is_managed )
382
+ irq_matrix_remove_managed (vector_matrix , dest );
383
+ }
384
+
243
385
static void x86_vector_free_irqs (struct irq_domain * domain ,
244
386
unsigned int virq , unsigned int nr_irqs )
245
387
{
@@ -253,6 +395,7 @@ static void x86_vector_free_irqs(struct irq_domain *domain,
253
395
if (irqd && irqd -> chip_data ) {
254
396
raw_spin_lock_irqsave (& vector_lock , flags );
255
397
clear_irq_vector (irqd );
398
+ vector_free_reserved_and_managed (irqd );
256
399
apicd = irqd -> chip_data ;
257
400
irq_domain_reset_irq_data (irqd );
258
401
raw_spin_unlock_irqrestore (& vector_lock , flags );
@@ -310,7 +453,7 @@ static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq,
310
453
continue ;
311
454
}
312
455
313
- err = assign_irq_vector_policy (irqd , info , node );
456
+ err = assign_irq_vector_policy (irqd , info );
314
457
trace_vector_setup (virq + i , false, err );
315
458
if (err )
316
459
goto error ;
@@ -368,6 +511,8 @@ void x86_vector_debug_show(struct seq_file *m, struct irq_domain *d,
368
511
static const struct irq_domain_ops x86_vector_domain_ops = {
369
512
.alloc = x86_vector_alloc_irqs ,
370
513
.free = x86_vector_free_irqs ,
514
+ .activate = x86_vector_activate ,
515
+ .deactivate = x86_vector_deactivate ,
371
516
#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
372
517
.debug_show = x86_vector_debug_show ,
373
518
#endif
@@ -531,13 +676,13 @@ static int apic_set_affinity(struct irq_data *irqd,
531
676
{
532
677
int err ;
533
678
534
- if (! IS_ENABLED ( CONFIG_SMP ))
535
- return - EPERM ;
536
-
537
- if (! cpumask_intersects ( dest , cpu_online_mask ))
538
- return - EINVAL ;
539
-
540
- err = assign_irq_vector ( irqd , dest );
679
+ raw_spin_lock ( & vector_lock );
680
+ cpumask_and ( vector_searchmask , dest , cpu_online_mask ) ;
681
+ if ( irqd_affinity_is_managed ( irqd ))
682
+ err = assign_managed_vector ( irqd , vector_searchmask );
683
+ else
684
+ err = assign_vector_locked ( irqd , vector_searchmask );
685
+ raw_spin_unlock ( & vector_lock );
541
686
return err ? err : IRQ_SET_MASK_OK ;
542
687
}
543
688
@@ -577,9 +722,18 @@ static void free_moved_vector(struct apic_chip_data *apicd)
577
722
{
578
723
unsigned int vector = apicd -> prev_vector ;
579
724
unsigned int cpu = apicd -> prev_cpu ;
725
+ bool managed = apicd -> is_managed ;
726
+
727
+ /*
728
+ * This should never happen. Managed interrupts are not
729
+ * migrated except on CPU down, which does not involve the
730
+ * cleanup vector. But try to keep the accounting correct
731
+ * nevertheless.
732
+ */
733
+ WARN_ON_ONCE (managed );
580
734
581
- trace_vector_free_moved (apicd -> irq , vector , false );
582
- irq_matrix_free (vector_matrix , cpu , vector , false );
735
+ trace_vector_free_moved (apicd -> irq , vector , managed );
736
+ irq_matrix_free (vector_matrix , cpu , vector , managed );
583
737
__this_cpu_write (vector_irq [vector ], VECTOR_UNUSED );
584
738
hlist_del_init (& apicd -> clist );
585
739
apicd -> prev_vector = 0 ;
0 commit comments