From 57f0f512b273f60d52568b8c6b77e17f5636edc0 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Wed, 5 Aug 2015 17:04:01 -0300 Subject: Initial import --- arch/mips/sibyte/sb1250/irq.c | 337 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 337 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..6d8dba5cf --- /dev/null +++ b/arch/mips/sibyte/sb1250/irq.c @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#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