arm: mvebu: Improve the SMP support of the interrupt controller
This patch makes the interrupt controller driver more SMP aware for the Armada XP SoCs. It adds the support for the per-CPU irq. It also adds the implementation for the set_affinity hook. Patch initialy wrote by Yehuda Yitschak and reworked by Gregory CLEMENT. Signed-off-by: Yehuda Yitschak <yehuday@marvell.com> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> Signed-off-by: Jason Cooper <jason@lakedaemon.net>
This commit is contained in:
parent
48be9ac930
commit
3202bf0157
@ -30,7 +30,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
mpic: interrupt-controller@d0020000 {
|
mpic: interrupt-controller@d0020000 {
|
||||||
reg = <0xd0020a00 0x1d0>,
|
reg = <0xd0020a00 0x2d0>,
|
||||||
<0xd0021070 0x58>;
|
<0xd0021070 0x58>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#define ARMADA_370_XP_INT_CONTROL (0x00)
|
#define ARMADA_370_XP_INT_CONTROL (0x00)
|
||||||
#define ARMADA_370_XP_INT_SET_ENABLE_OFFS (0x30)
|
#define ARMADA_370_XP_INT_SET_ENABLE_OFFS (0x30)
|
||||||
#define ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS (0x34)
|
#define ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS (0x34)
|
||||||
|
#define ARMADA_370_XP_INT_SOURCE_CTL(irq) (0x100 + irq*4)
|
||||||
|
|
||||||
#define ARMADA_370_XP_CPU_INTACK_OFFS (0x44)
|
#define ARMADA_370_XP_CPU_INTACK_OFFS (0x44)
|
||||||
|
|
||||||
@ -41,28 +42,90 @@
|
|||||||
#define ARMADA_370_XP_IN_DRBEL_MSK_OFFS (0xc)
|
#define ARMADA_370_XP_IN_DRBEL_MSK_OFFS (0xc)
|
||||||
#define ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS (0x8)
|
#define ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS (0x8)
|
||||||
|
|
||||||
|
#define ARMADA_370_XP_MAX_PER_CPU_IRQS (28)
|
||||||
|
|
||||||
#define ACTIVE_DOORBELLS (8)
|
#define ACTIVE_DOORBELLS (8)
|
||||||
|
|
||||||
|
static DEFINE_RAW_SPINLOCK(irq_controller_lock);
|
||||||
|
|
||||||
static void __iomem *per_cpu_int_base;
|
static void __iomem *per_cpu_int_base;
|
||||||
static void __iomem *main_int_base;
|
static void __iomem *main_int_base;
|
||||||
static struct irq_domain *armada_370_xp_mpic_domain;
|
static struct irq_domain *armada_370_xp_mpic_domain;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In SMP mode:
|
||||||
|
* For shared global interrupts, mask/unmask global enable bit
|
||||||
|
* For CPU interrtups, mask/unmask the calling CPU's bit
|
||||||
|
*/
|
||||||
static void armada_370_xp_irq_mask(struct irq_data *d)
|
static void armada_370_xp_irq_mask(struct irq_data *d)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
irq_hw_number_t hwirq = irqd_to_hwirq(d);
|
||||||
|
|
||||||
|
if (hwirq > ARMADA_370_XP_MAX_PER_CPU_IRQS)
|
||||||
|
writel(hwirq, main_int_base +
|
||||||
|
ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS);
|
||||||
|
else
|
||||||
|
writel(hwirq, per_cpu_int_base +
|
||||||
|
ARMADA_370_XP_INT_SET_MASK_OFFS);
|
||||||
|
#else
|
||||||
writel(irqd_to_hwirq(d),
|
writel(irqd_to_hwirq(d),
|
||||||
per_cpu_int_base + ARMADA_370_XP_INT_SET_MASK_OFFS);
|
per_cpu_int_base + ARMADA_370_XP_INT_SET_MASK_OFFS);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void armada_370_xp_irq_unmask(struct irq_data *d)
|
static void armada_370_xp_irq_unmask(struct irq_data *d)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
irq_hw_number_t hwirq = irqd_to_hwirq(d);
|
||||||
|
|
||||||
|
if (hwirq > ARMADA_370_XP_MAX_PER_CPU_IRQS)
|
||||||
|
writel(hwirq, main_int_base +
|
||||||
|
ARMADA_370_XP_INT_SET_ENABLE_OFFS);
|
||||||
|
else
|
||||||
|
writel(hwirq, per_cpu_int_base +
|
||||||
|
ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
|
||||||
|
#else
|
||||||
writel(irqd_to_hwirq(d),
|
writel(irqd_to_hwirq(d),
|
||||||
per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
|
per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
static int armada_xp_set_affinity(struct irq_data *d,
|
static int armada_xp_set_affinity(struct irq_data *d,
|
||||||
const struct cpumask *mask_val, bool force)
|
const struct cpumask *mask_val, bool force)
|
||||||
{
|
{
|
||||||
|
unsigned long reg;
|
||||||
|
unsigned long new_mask = 0;
|
||||||
|
unsigned long online_mask = 0;
|
||||||
|
unsigned long count = 0;
|
||||||
|
irq_hw_number_t hwirq = irqd_to_hwirq(d);
|
||||||
|
int cpu;
|
||||||
|
|
||||||
|
for_each_cpu(cpu, mask_val) {
|
||||||
|
new_mask |= 1 << cpu_logical_map(cpu);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Forbid mutlicore interrupt affinity
|
||||||
|
* This is required since the MPIC HW doesn't limit
|
||||||
|
* several CPUs from acknowledging the same interrupt.
|
||||||
|
*/
|
||||||
|
if (count > 1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
for_each_cpu(cpu, cpu_online_mask)
|
||||||
|
online_mask |= 1 << cpu_logical_map(cpu);
|
||||||
|
|
||||||
|
raw_spin_lock(&irq_controller_lock);
|
||||||
|
|
||||||
|
reg = readl(main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq));
|
||||||
|
reg = (reg & (~online_mask)) | new_mask;
|
||||||
|
writel(reg, main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq));
|
||||||
|
|
||||||
|
raw_spin_unlock(&irq_controller_lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -155,6 +218,15 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
|
|||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
armada_xp_mpic_smp_cpu_init();
|
armada_xp_mpic_smp_cpu_init();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the default affinity from all CPUs to the boot cpu.
|
||||||
|
* This is required since the MPIC doesn't limit several CPUs
|
||||||
|
* from acknowledging the same interrupt.
|
||||||
|
*/
|
||||||
|
cpumask_clear(irq_default_affinity);
|
||||||
|
cpumask_set_cpu(smp_processor_id(), irq_default_affinity);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user