[COMMON] irqchip: gic: implement multiple cpu targeted interrupt
authorHosung Kim <hosung0.kim@samsung.com>
Sun, 9 Apr 2017 11:49:29 +0000 (20:49 +0900)
committerJaehyoung Choi <jkkkkk.choi@samsung.com>
Mon, 14 May 2018 05:04:20 +0000 (14:04 +0900)
Current gic driver only supports single cpu targeted interrupt
though GIC HW supports multiple cpu targeted interrupt.
This patch implements this multiple cpu targeted interrupt
by controlling interrupt processor target registers in GIC HW.

Because use of multiple cpu targeted interrupt can cause
unnecessary wakeups of targeted cpus, use this feature
only when minimal interrupt latency is required

Change-Id: Iefb8625564e790eede677190aa2190290f7aee00
Signed-off-by: Hosung Kim <hosung0.kim@samsung.com>
drivers/irqchip/irq-gic.c

index 651d726e8b123f541281504ed14e4d7ed6cea5e6..04cb3c0a4c6f825c4beee34aea59664031aedf7b 100644 (file)
@@ -329,17 +329,32 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
        u32 val, mask, bit;
        unsigned long flags;
 
-       if (!force)
-               cpu = cpumask_any_and(mask_val, cpu_online_mask);
-       else
-               cpu = cpumask_first(mask_val);
+       gic_lock_irqsave(flags);
+       if (unlikely(d->common->state_use_accessors & IRQD_GIC_MULTI_TARGET)) {
+               struct cpumask temp_mask;
 
-       if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids)
-               return -EINVAL;
+               bit = 0;
+               if (!cpumask_and(&temp_mask, mask_val, cpu_online_mask))
+                       goto err_out;
 
-       gic_lock_irqsave(flags);
+               for_each_cpu(cpu, &temp_mask) {
+                       if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids)
+                               goto err_out;
+                       bit |= gic_cpu_map[cpu];
+               }
+               bit <<= shift;
+       } else {
+               if (!force)
+                       cpu = cpumask_any_and(mask_val, cpu_online_mask);
+               else
+                       cpu = cpumask_first(mask_val);
+
+               if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids)
+                               goto err_out;
+
+               bit = gic_cpu_map[cpu] << shift;
+       }
        mask = 0xff << shift;
-       bit = gic_cpu_map[cpu] << shift;
        val = readl_relaxed(reg) & ~mask;
        writel_relaxed(val | bit, reg);
        gic_unlock_irqrestore(flags);
@@ -347,6 +362,9 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
        irq_data_update_effective_affinity(d, cpumask_of(cpu));
 
        return IRQ_SET_MASK_OK_DONE;
+err_out:
+       gic_unlock_irqrestore(flags);
+       return -EINVAL;
 }
 #endif