summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHuacai Chen <chenhc@lemote.com>2017-06-22 23:06:53 +0800
committerRalf Baechle <ralf@linux-mips.org>2017-06-29 02:42:23 +0200
commitecc38a0968ec3e0605079e49d276d9a4186abdb7 (patch)
tree03d2f2af1605a17d7371a54b61b56b318903bf7a
parente1b88ca8d72193e48bac026b19b8c686cc7fea25 (diff)
downloadlinux-ecc38a0968ec3e0605079e49d276d9a4186abdb7.tar.gz
linux-ecc38a0968ec3e0605079e49d276d9a4186abdb7.tar.bz2
linux-ecc38a0968ec3e0605079e49d276d9a4186abdb7.zip
MIPS: Loongson-3: support irq_set_affinity() in i8259 chip
With this patch we can set irq affinity via procfs, so as to improve network performance. Signed-off-by: Huacai Chen <chenhc@lemote.com> Cc: John Crispin <john@phrozen.org> Cc: Steven J . Hill <Steven.Hill@cavium.com> Cc: Fuxin Zhang <zhangfx@lemote.com> Cc: Zhangjin Wu <wuzhangjin@gmail.com> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16590/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/loongson64/loongson-3/irq.c67
1 files changed, 54 insertions, 13 deletions
diff --git a/arch/mips/loongson64/loongson-3/irq.c b/arch/mips/loongson64/loongson-3/irq.c
index 2e6e205ed9b9..7202e52cd046 100644
--- a/arch/mips/loongson64/loongson-3/irq.c
+++ b/arch/mips/loongson64/loongson-3/irq.c
@@ -10,32 +10,68 @@
#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, irq0, irq1;
- static unsigned int dest_cpu = 0;
+ 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 */
- irq0 = irq & local_irq; /* handled by local core */
- irq1 = irq & ~local_irq; /* balanced by other cores */
+ for (i = 0; i < ARRAY_SIZE(ht_irq); i++) {
+ if (!(irq & (0x1 << ht_irq[i])))
+ continue;
- if (dest_cpu == 0 || !cpu_online(dest_cpu))
- irq0 |= irq1;
- else
- loongson3_send_irq_by_ipi(dest_cpu, irq1);
+ /* handled by local core */
+ if (local_irq & (0x1 << ht_irq[i])) {
+ do_IRQ(ht_irq[i]);
+ continue;
+ }
- dest_cpu = dest_cpu + 1;
- if (dest_cpu >= num_possible_cpus() || cpu_data[dest_cpu].package > 0)
- dest_cpu = 0;
+ 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;
+ }
- for (i = 0; i < ARRAY_SIZE(ht_irq); i++) {
- if (irq0 & (0x1 << ht_irq[i]))
+ 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]));
}
}
@@ -135,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);