diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 2aed04396210..e1b81d35e7a3 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -348,7 +348,7 @@ int irq_domain_xlate_onetwocell(struct irq_domain *d, struct device_node *ctrlr, /* IPI functions */ unsigned int irq_reserve_ipi(struct irq_domain *domain, const struct cpumask *dest); -void irq_destroy_ipi(unsigned int irq); +void irq_destroy_ipi(unsigned int irq, const struct cpumask *dest); /* V2 interfaces to support hierarchy IRQ domains. */ extern struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain, diff --git a/kernel/irq/ipi.c b/kernel/irq/ipi.c index 14777af8e097..bedc995ae214 100644 --- a/kernel/irq/ipi.c +++ b/kernel/irq/ipi.c @@ -106,11 +106,12 @@ unsigned int irq_reserve_ipi(struct irq_domain *domain, /** * irq_destroy_ipi() - unreserve an IPI that was previously allocated * @irq: linux irq number to be destroyed + * @dest: cpumask of cpus which should have the IPI removed * * Return the IPIs allocated with irq_reserve_ipi() to the system destroying * all virqs associated with them. */ -void irq_destroy_ipi(unsigned int irq) +void irq_destroy_ipi(unsigned int irq, const struct cpumask *dest) { struct irq_data *data = irq_get_irq_data(irq); struct cpumask *ipimask = data ? irq_data_get_affinity_mask(data) : NULL; @@ -129,10 +130,19 @@ void irq_destroy_ipi(unsigned int irq) return; } - if (irq_domain_is_ipi_per_cpu(domain)) - nr_irqs = cpumask_weight(ipimask); - else + if (WARN_ON(!cpumask_subset(dest, ipimask))) + /* + * Must be destroying a subset of CPUs to which this IPI + * was set up to target + */ + return; + + if (irq_domain_is_ipi_per_cpu(domain)) { + irq = irq + cpumask_first(dest) - data->common->ipi_offset; + nr_irqs = cpumask_weight(dest); + } else { nr_irqs = 1; + } irq_domain_free_irqs(irq, nr_irqs); }