Merge tag 'irq-core-2022-05-23' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / kernel / irq / manage.c
index e3e245a..8c39631 100644 (file)
@@ -222,11 +222,16 @@ int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask,
 {
        struct irq_desc *desc = irq_data_to_desc(data);
        struct irq_chip *chip = irq_data_get_irq_chip(data);
+       const struct cpumask  *prog_mask;
        int ret;
 
+       static DEFINE_RAW_SPINLOCK(tmp_mask_lock);
+       static struct cpumask tmp_mask;
+
        if (!chip || !chip->irq_set_affinity)
                return -EINVAL;
 
+       raw_spin_lock(&tmp_mask_lock);
        /*
         * If this is a managed interrupt and housekeeping is enabled on
         * it check whether the requested affinity mask intersects with
@@ -248,24 +253,34 @@ int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask,
         */
        if (irqd_affinity_is_managed(data) &&
            housekeeping_enabled(HK_TYPE_MANAGED_IRQ)) {
-               const struct cpumask *hk_mask, *prog_mask;
-
-               static DEFINE_RAW_SPINLOCK(tmp_mask_lock);
-               static struct cpumask tmp_mask;
+               const struct cpumask *hk_mask;
 
                hk_mask = housekeeping_cpumask(HK_TYPE_MANAGED_IRQ);
 
-               raw_spin_lock(&tmp_mask_lock);
                cpumask_and(&tmp_mask, mask, hk_mask);
                if (!cpumask_intersects(&tmp_mask, cpu_online_mask))
                        prog_mask = mask;
                else
                        prog_mask = &tmp_mask;
-               ret = chip->irq_set_affinity(data, prog_mask, force);
-               raw_spin_unlock(&tmp_mask_lock);
        } else {
-               ret = chip->irq_set_affinity(data, mask, force);
+               prog_mask = mask;
        }
+
+       /*
+        * Make sure we only provide online CPUs to the irqchip,
+        * unless we are being asked to force the affinity (in which
+        * case we do as we are told).
+        */
+       cpumask_and(&tmp_mask, prog_mask, cpu_online_mask);
+       if (!force && !cpumask_empty(&tmp_mask))
+               ret = chip->irq_set_affinity(data, &tmp_mask, force);
+       else if (force)
+               ret = chip->irq_set_affinity(data, mask, force);
+       else
+               ret = -EINVAL;
+
+       raw_spin_unlock(&tmp_mask_lock);
+
        switch (ret) {
        case IRQ_SET_MASK_OK:
        case IRQ_SET_MASK_OK_DONE: