On Mon, Nov 02 2020 at 21:35, Thomas Gleixner wrote: > On Mon, Nov 02 2020 at 17:32, John Garry wrote: > Correct. I have a halfways working solution for that, but I need to fix > some other thing first. Sorry for the delay. Supporting this truly on x86 needs some more thought and surgery, but for ARM it should not matter. I made a few tweaks to your original code. See below. Thanks, tglx --- From: John Garry <john.garry@xxxxxxxxxx> Subject: genirq/affinity: Add irq_update_affinity_desc() Date: Wed, 28 Oct 2020 20:33:05 +0800 From: John Garry <john.garry@xxxxxxxxxx> Add a function to allow the affinity of an interrupt be switched to managed, such that interrupts allocated for platform devices may be managed. Suggested-by: Thomas Gleixner <tglx@xxxxxxxxxxxxx> Signed-off-by: John Garry <john.garry@xxxxxxxxxx> --- include/linux/interrupt.h | 8 ++++++ kernel/irq/manage.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -352,6 +352,8 @@ extern int irq_can_set_affinity(unsigned extern int irq_select_affinity(unsigned int irq); extern int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m); +extern int irq_update_affinity_desc(unsigned int irq, + struct irq_affinity_desc *affinity); extern int irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify); @@ -386,6 +388,12 @@ static inline int irq_set_affinity_hint( { return -EINVAL; } + +static inline int irq_update_affinity_desc(unsigned int irq, + struct irq_affinity_desc *affinity) +{ + return -EINVAL; +} static inline int irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify) --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -371,6 +371,62 @@ int irq_set_affinity_locked(struct irq_d return ret; } +/** + * irq_update_affinity_desc - Update affinity management for an interrupt + * @irq: The interrupt number to update + * @affinity: Pointer to the affinity descriptor + * + * This interface can be used to configure the affinity management of + * interrupts which have been allocated already. + */ +int irq_update_affinity_desc(unsigned int irq, + struct irq_affinity_desc *affinity) +{ + struct irq_desc *desc; + unsigned long flags; + bool activated; + + /* + * Supporting this with the reservation scheme used by x86 needs + * some more thought. Fail it for now. + */ + if (IS_ENABLED(CONFIG_GENERIC_IRQ_RESERVATION_MODE)) + return -EOPNOTSUPP; + + desc = irq_get_desc_buslock(irq, &flags, 0); + if (!desc) + return -EINVAL; + + /* Requires the interrupt to be shut down */ + if (irqd_is_started(&desc->irq_data)) + return -EBUSY; + + /* Interrupts which are already managed cannot be modified */ + if (irqd_is_managed(&desc->irq_data)) + return -EBUSY; + + /* + * Deactivate the interrupt. That's required to undo + * anything an earlier activation has established. + */ + activated = irqd_is_activated(&desc->irq_data); + if (activated) + irq_domain_deactivate_irq(&desc->irq_data); + + if (affinity->is_managed) { + irqd_set(&desc->irq_data, IRQD_AFFINITY_MANAGED); + irqd_set(&desc->irq_data, IRQD_MANAGED_SHUTDOWN); + } + + cpumask_copy(desc->irq_common_data.affinity, &affinity->mask); + + /* Restore the activation state */ + if (activated) + irq_domain_deactivate_irq(&desc->irq_data); + irq_put_desc_busunlock(desc, flags); + return 0; +} + int __irq_set_affinity(unsigned int irq, const struct cpumask *mask, bool force) { struct irq_desc *desc = irq_to_desc(irq);