diff options
author | Tony Lindgren <tony@atomide.com> | 2017-08-10 18:05:53 +0200 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2017-08-10 18:05:53 +0200 |
commit | c002c27874faaa170b535d03d7efee89ecdd9be4 (patch) | |
tree | 70d91eba77a9c374e4f0bf9eb8636acba57ca173 /arch/mips/loongson64/loongson-3/irq.c | |
parent | ARM: dts: dra7: Add "max-frequency" property to MMC dt nodes (diff) | |
parent | Linux v4.13-rc1 (diff) | |
download | linux-c002c27874faaa170b535d03d7efee89ecdd9be4.tar.xz linux-c002c27874faaa170b535d03d7efee89ecdd9be4.zip |
Merge tag 'v4.13-rc1' into omap-for-v4.14/mmc-regulator
Linux v4.13-rc1
Diffstat (limited to 'arch/mips/loongson64/loongson-3/irq.c')
-rw-r--r-- | arch/mips/loongson64/loongson-3/irq.c | 58 |
1 files changed, 57 insertions, 1 deletions
diff --git a/arch/mips/loongson64/loongson-3/irq.c b/arch/mips/loongson64/loongson-3/irq.c index 548f759454dc..7202e52cd046 100644 --- a/arch/mips/loongson64/loongson-3/irq.c +++ b/arch/mips/loongson64/loongson-3/irq.c @@ -9,18 +9,69 @@ #include "smp.h" +extern void loongson3_send_irq_by_ipi(int cpu, int irqs); + +unsigned int irq_cpu[16] = {[0 ... 15] = -1}; unsigned int ht_irq[] = {0, 1, 3, 4, 5, 6, 7, 8, 12, 14, 15}; +unsigned int local_irq = 1<<0 | 1<<1 | 1<<2 | 1<<7 | 1<<8 | 1<<12; + +int plat_set_irq_affinity(struct irq_data *d, const struct cpumask *affinity, + bool force) +{ + unsigned int cpu; + struct cpumask new_affinity; + + /* I/O devices are connected on package-0 */ + cpumask_copy(&new_affinity, affinity); + for_each_cpu(cpu, affinity) + if (cpu_data[cpu].package > 0) + cpumask_clear_cpu(cpu, &new_affinity); + + if (cpumask_empty(&new_affinity)) + return -EINVAL; + + cpumask_copy(d->common->affinity, &new_affinity); + + return IRQ_SET_MASK_OK_NOCOPY; +} static void ht_irqdispatch(void) { unsigned int i, irq; + struct irq_data *irqd; + struct cpumask affinity; irq = LOONGSON_HT1_INT_VECTOR(0); LOONGSON_HT1_INT_VECTOR(0) = irq; /* Acknowledge the IRQs */ for (i = 0; i < ARRAY_SIZE(ht_irq); i++) { - if (irq & (0x1 << ht_irq[i])) + if (!(irq & (0x1 << ht_irq[i]))) + continue; + + /* handled by local core */ + if (local_irq & (0x1 << ht_irq[i])) { do_IRQ(ht_irq[i]); + continue; + } + + irqd = irq_get_irq_data(ht_irq[i]); + cpumask_and(&affinity, irqd->common->affinity, cpu_active_mask); + if (cpumask_empty(&affinity)) { + do_IRQ(ht_irq[i]); + continue; + } + + irq_cpu[ht_irq[i]] = cpumask_next(irq_cpu[ht_irq[i]], &affinity); + if (irq_cpu[ht_irq[i]] >= nr_cpu_ids) + irq_cpu[ht_irq[i]] = cpumask_first(&affinity); + + if (irq_cpu[ht_irq[i]] == 0) { + do_IRQ(ht_irq[i]); + continue; + } + + /* balanced by other cores */ + loongson3_send_irq_by_ipi(irq_cpu[ht_irq[i]], (0x1 << ht_irq[i])); } } @@ -120,11 +171,16 @@ void irq_router_init(void) void __init mach_init_irq(void) { + struct irq_chip *chip; + clear_c0_status(ST0_IM | ST0_BEV); irq_router_init(); mips_cpu_irq_init(); init_i8259_irqs(); + chip = irq_get_chip(I8259A_IRQ_BASE); + chip->irq_set_affinity = plat_set_irq_affinity; + irq_set_chip_and_handler(LOONGSON_UART_IRQ, &loongson_irq_chip, handle_level_irq); |