irqchip/mips-gic: Get rid of the reliance on irq_cpu_online()
The MIPS GIC driver uses irq_cpu_online() to go and program the per-CPU interrupts. However, this method iterates over all IRQs in the system, despite only 3 per-CPU interrupts being of interest. Let's be terribly bold and do the iteration ourselves. To ensure mutual exclusion, hold the gic_lock spinlock that is otherwise taken while dealing with these interrupts. Signed-off-by: Marc Zyngier <maz@kernel.org> Reviewed-by: Serge Semin <fancer.lancer@gmail.com> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Tested-by: Serge Semin <fancer.lancer@gmail.com> Link: https://lore.kernel.org/r/20211021170414.3341522-3-maz@kernel.org
This commit is contained in:
Родитель
eb5411334c
Коммит
dd098a0e03
|
@ -381,24 +381,35 @@ static void gic_unmask_local_irq_all_vpes(struct irq_data *d)
|
||||||
spin_unlock_irqrestore(&gic_lock, flags);
|
spin_unlock_irqrestore(&gic_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gic_all_vpes_irq_cpu_online(struct irq_data *d)
|
static void gic_all_vpes_irq_cpu_online(void)
|
||||||
{
|
{
|
||||||
struct gic_all_vpes_chip_data *cd;
|
static const unsigned int local_intrs[] = {
|
||||||
unsigned int intr;
|
GIC_LOCAL_INT_TIMER,
|
||||||
|
GIC_LOCAL_INT_PERFCTR,
|
||||||
|
GIC_LOCAL_INT_FDC,
|
||||||
|
};
|
||||||
|
unsigned long flags;
|
||||||
|
int i;
|
||||||
|
|
||||||
intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
|
spin_lock_irqsave(&gic_lock, flags);
|
||||||
cd = irq_data_get_irq_chip_data(d);
|
|
||||||
|
|
||||||
write_gic_vl_map(mips_gic_vx_map_reg(intr), cd->map);
|
for (i = 0; i < ARRAY_SIZE(local_intrs); i++) {
|
||||||
if (cd->mask)
|
unsigned int intr = local_intrs[i];
|
||||||
write_gic_vl_smask(BIT(intr));
|
struct gic_all_vpes_chip_data *cd;
|
||||||
|
|
||||||
|
cd = &gic_all_vpes_chip_data[intr];
|
||||||
|
write_gic_vl_map(mips_gic_vx_map_reg(intr), cd->map);
|
||||||
|
if (cd->mask)
|
||||||
|
write_gic_vl_smask(BIT(intr));
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&gic_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct irq_chip gic_all_vpes_local_irq_controller = {
|
static struct irq_chip gic_all_vpes_local_irq_controller = {
|
||||||
.name = "MIPS GIC Local",
|
.name = "MIPS GIC Local",
|
||||||
.irq_mask = gic_mask_local_irq_all_vpes,
|
.irq_mask = gic_mask_local_irq_all_vpes,
|
||||||
.irq_unmask = gic_unmask_local_irq_all_vpes,
|
.irq_unmask = gic_unmask_local_irq_all_vpes,
|
||||||
.irq_cpu_online = gic_all_vpes_irq_cpu_online,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __gic_irq_dispatch(void)
|
static void __gic_irq_dispatch(void)
|
||||||
|
@ -477,6 +488,10 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
|
||||||
intr = GIC_HWIRQ_TO_LOCAL(hwirq);
|
intr = GIC_HWIRQ_TO_LOCAL(hwirq);
|
||||||
map = GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin;
|
map = GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If adding support for more per-cpu interrupts, keep the the
|
||||||
|
* array in gic_all_vpes_irq_cpu_online() in sync.
|
||||||
|
*/
|
||||||
switch (intr) {
|
switch (intr) {
|
||||||
case GIC_LOCAL_INT_TIMER:
|
case GIC_LOCAL_INT_TIMER:
|
||||||
/* CONFIG_MIPS_CMP workaround (see __gic_init) */
|
/* CONFIG_MIPS_CMP workaround (see __gic_init) */
|
||||||
|
@ -663,8 +678,8 @@ static int gic_cpu_startup(unsigned int cpu)
|
||||||
/* Clear all local IRQ masks (ie. disable all local interrupts) */
|
/* Clear all local IRQ masks (ie. disable all local interrupts) */
|
||||||
write_gic_vl_rmask(~0);
|
write_gic_vl_rmask(~0);
|
||||||
|
|
||||||
/* Invoke irq_cpu_online callbacks to enable desired interrupts */
|
/* Enable desired interrupts */
|
||||||
irq_cpu_online();
|
gic_all_vpes_irq_cpu_online();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче