From 6ae58e5e004d38438416801cb5883809c0e2346a Mon Sep 17 00:00:00 2001 From: Hosung Kim Date: Sun, 9 Apr 2017 20:49:29 +0900 Subject: [PATCH] [COMMON] irqchip: gic: implement multiple cpu targeted interrupt 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 --- drivers/irqchip/irq-gic.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 651d726e8b12..04cb3c0a4c6f 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -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 -- 2.20.1