Skip to content

Commit 1d3aec8

Browse files
John GarryMarc Zyngier
authored andcommitted
genirq/affinity: Add irq_update_affinity_desc()
Add a function to allow the affinity of an interrupt be switched to managed, such that interrupts allocated for platform devices may be managed. This new interface has certain limitations, and attempts to use it in the following circumstances will fail: - For when the kernel is configured for generic IRQ reservation mode (in config GENERIC_IRQ_RESERVATION_MODE). The reason being that it could conflict with managed vs. non-managed interrupt accounting. - The interrupt is already started, which should not be the case during init - The interrupt is already configured as managed, which means double init Suggested-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: John Garry <john.garry@huawei.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/1606905417-183214-2-git-send-email-john.garry@huawei.com
1 parent 34dd263 commit 1d3aec8

2 files changed

Lines changed: 78 additions & 0 deletions

File tree

include/linux/interrupt.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,8 @@ extern int irq_can_set_affinity(unsigned int irq);
352352
extern int irq_select_affinity(unsigned int irq);
353353

354354
extern int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m);
355+
extern int irq_update_affinity_desc(unsigned int irq,
356+
struct irq_affinity_desc *affinity);
355357

356358
extern int
357359
irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify);
@@ -387,6 +389,12 @@ static inline int irq_set_affinity_hint(unsigned int irq,
387389
return -EINVAL;
388390
}
389391

392+
static inline int irq_update_affinity_desc(unsigned int irq,
393+
struct irq_affinity_desc *affinity)
394+
{
395+
return -EINVAL;
396+
}
397+
390398
static inline int
391399
irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify)
392400
{

kernel/irq/manage.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,76 @@ int irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask,
371371
return ret;
372372
}
373373

374+
/**
375+
* irq_update_affinity_desc - Update affinity management for an interrupt
376+
* @irq: The interrupt number to update
377+
* @affinity: Pointer to the affinity descriptor
378+
*
379+
* This interface can be used to configure the affinity management of
380+
* interrupts which have been allocated already.
381+
*
382+
* There are certain limitations on when it may be used - attempts to use it
383+
* for when the kernel is configured for generic IRQ reservation mode (in
384+
* config GENERIC_IRQ_RESERVATION_MODE) will fail, as it may conflict with
385+
* managed/non-managed interrupt accounting. In addition, attempts to use it on
386+
* an interrupt which is already started or which has already been configured
387+
* as managed will also fail, as these mean invalid init state or double init.
388+
*/
389+
int irq_update_affinity_desc(unsigned int irq,
390+
struct irq_affinity_desc *affinity)
391+
{
392+
struct irq_desc *desc;
393+
unsigned long flags;
394+
bool activated;
395+
int ret = 0;
396+
397+
/*
398+
* Supporting this with the reservation scheme used by x86 needs
399+
* some more thought. Fail it for now.
400+
*/
401+
if (IS_ENABLED(CONFIG_GENERIC_IRQ_RESERVATION_MODE))
402+
return -EOPNOTSUPP;
403+
404+
desc = irq_get_desc_buslock(irq, &flags, 0);
405+
if (!desc)
406+
return -EINVAL;
407+
408+
/* Requires the interrupt to be shut down */
409+
if (irqd_is_started(&desc->irq_data)) {
410+
ret = -EBUSY;
411+
goto out_unlock;
412+
}
413+
414+
/* Interrupts which are already managed cannot be modified */
415+
if (irqd_affinity_is_managed(&desc->irq_data)) {
416+
ret = -EBUSY;
417+
goto out_unlock;
418+
}
419+
420+
/*
421+
* Deactivate the interrupt. That's required to undo
422+
* anything an earlier activation has established.
423+
*/
424+
activated = irqd_is_activated(&desc->irq_data);
425+
if (activated)
426+
irq_domain_deactivate_irq(&desc->irq_data);
427+
428+
if (affinity->is_managed) {
429+
irqd_set(&desc->irq_data, IRQD_AFFINITY_MANAGED);
430+
irqd_set(&desc->irq_data, IRQD_MANAGED_SHUTDOWN);
431+
}
432+
433+
cpumask_copy(desc->irq_common_data.affinity, &affinity->mask);
434+
435+
/* Restore the activation state */
436+
if (activated)
437+
irq_domain_activate_irq(&desc->irq_data, false);
438+
439+
out_unlock:
440+
irq_put_desc_busunlock(desc, flags);
441+
return ret;
442+
}
443+
374444
int __irq_set_affinity(unsigned int irq, const struct cpumask *mask, bool force)
375445
{
376446
struct irq_desc *desc = irq_to_desc(irq);

0 commit comments

Comments
 (0)