From 5d1646d90e1f2cceb9f0828f4b28318cd0ec7744 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 12:05:51 +0200 Subject: Adding upstream version 5.10.209. Signed-off-by: Daniel Baumann --- arch/mips/sibyte/sb1250/irq.c | 324 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 324 insertions(+) create mode 100644 arch/mips/sibyte/sb1250/irq.c (limited to 'arch/mips/sibyte/sb1250/irq.c') diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c new file mode 100644 index 000000000..86f49c48f --- /dev/null +++ b/arch/mips/sibyte/sb1250/irq.c @@ -0,0 +1,324 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2000, 2001, 2002, 2003 Broadcom Corporation + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * These are the routines that handle all the low level interrupt stuff. + * Actions handled here are: initialization of the interrupt map, requesting of + * interrupt lines by handlers, dispatching if interrupts to handlers, probing + * for interrupt lines + */ + +#ifdef CONFIG_SIBYTE_HAS_LDT +extern unsigned long ldt_eoi_space; +#endif + +/* Store the CPU id (not the logical number) */ +int sb1250_irq_owner[SB1250_NR_IRQS]; + +static DEFINE_RAW_SPINLOCK(sb1250_imr_lock); + +void sb1250_mask_irq(int cpu, int irq) +{ + unsigned long flags; + u64 cur_ints; + + raw_spin_lock_irqsave(&sb1250_imr_lock, flags); + cur_ints = ____raw_readq(IOADDR(A_IMR_MAPPER(cpu) + + R_IMR_INTERRUPT_MASK)); + cur_ints |= (((u64) 1) << irq); + ____raw_writeq(cur_ints, IOADDR(A_IMR_MAPPER(cpu) + + R_IMR_INTERRUPT_MASK)); + raw_spin_unlock_irqrestore(&sb1250_imr_lock, flags); +} + +void sb1250_unmask_irq(int cpu, int irq) +{ + unsigned long flags; + u64 cur_ints; + + raw_spin_lock_irqsave(&sb1250_imr_lock, flags); + cur_ints = ____raw_readq(IOADDR(A_IMR_MAPPER(cpu) + + R_IMR_INTERRUPT_MASK)); + cur_ints &= ~(((u64) 1) << irq); + ____raw_writeq(cur_ints, IOADDR(A_IMR_MAPPER(cpu) + + R_IMR_INTERRUPT_MASK)); + raw_spin_unlock_irqrestore(&sb1250_imr_lock, flags); +} + +#ifdef CONFIG_SMP +static int sb1250_set_affinity(struct irq_data *d, const struct cpumask *mask, + bool force) +{ + int i = 0, old_cpu, cpu, int_on; + unsigned int irq = d->irq; + u64 cur_ints; + unsigned long flags; + + i = cpumask_first_and(mask, cpu_online_mask); + + /* Convert logical CPU to physical CPU */ + cpu = cpu_logical_map(i); + + /* Protect against other affinity changers and IMR manipulation */ + raw_spin_lock_irqsave(&sb1250_imr_lock, flags); + + /* Swizzle each CPU's IMR (but leave the IP selection alone) */ + old_cpu = sb1250_irq_owner[irq]; + cur_ints = ____raw_readq(IOADDR(A_IMR_MAPPER(old_cpu) + + R_IMR_INTERRUPT_MASK)); + int_on = !(cur_ints & (((u64) 1) << irq)); + if (int_on) { + /* If it was on, mask it */ + cur_ints |= (((u64) 1) << irq); + ____raw_writeq(cur_ints, IOADDR(A_IMR_MAPPER(old_cpu) + + R_IMR_INTERRUPT_MASK)); + } + sb1250_irq_owner[irq] = cpu; + if (int_on) { + /* unmask for the new CPU */ + cur_ints = ____raw_readq(IOADDR(A_IMR_MAPPER(cpu) + + R_IMR_INTERRUPT_MASK)); + cur_ints &= ~(((u64) 1) << irq); + ____raw_writeq(cur_ints, IOADDR(A_IMR_MAPPER(cpu) + + R_IMR_INTERRUPT_MASK)); + } + raw_spin_unlock_irqrestore(&sb1250_imr_lock, flags); + + return 0; +} +#endif + +static void disable_sb1250_irq(struct irq_data *d) +{ + unsigned int irq = d->irq; + + sb1250_mask_irq(sb1250_irq_owner[irq], irq); +} + +static void enable_sb1250_irq(struct irq_data *d) +{ + unsigned int irq = d->irq; + + sb1250_unmask_irq(sb1250_irq_owner[irq], irq); +} + + +static void ack_sb1250_irq(struct irq_data *d) +{ + unsigned int irq = d->irq; +#ifdef CONFIG_SIBYTE_HAS_LDT + u64 pending; + + /* + * If the interrupt was an HT interrupt, now is the time to + * clear it. NOTE: we assume the HT bridge was set up to + * deliver the interrupts to all CPUs (which makes affinity + * changing easier for us) + */ + pending = __raw_readq(IOADDR(A_IMR_REGISTER(sb1250_irq_owner[irq], + R_IMR_LDT_INTERRUPT))); + pending &= ((u64)1 << (irq)); + if (pending) { + int i; + for (i=0; i