Path: blob/master/arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c
15118 views
/*1* Copyright 2010 PMC-Sierra, Inc, derived from irq_cpu.c2*3* This file define the irq handler for MSP CIC subsystem interrupts.4*5* This program is free software; you can redistribute it and/or modify it6* under the terms of the GNU General Public License as published by the7* Free Software Foundation; either version 2 of the License, or (at your8* option) any later version.9*/1011#include <linux/init.h>12#include <linux/interrupt.h>13#include <linux/kernel.h>14#include <linux/bitops.h>15#include <linux/irq.h>1617#include <asm/mipsregs.h>18#include <asm/system.h>1920#include <msp_cic_int.h>21#include <msp_regs.h>2223/*24* External API25*/26extern void msp_per_irq_init(void);27extern void msp_per_irq_dispatch(void);282930/*31* Convenience Macro. Should be somewhere generic.32*/33#define get_current_vpe() \34((read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & TCBIND_CURVPE)3536#ifdef CONFIG_SMP3738#define LOCK_VPE(flags, mtflags) \39do { \40local_irq_save(flags); \41mtflags = dmt(); \42} while (0)4344#define UNLOCK_VPE(flags, mtflags) \45do { \46emt(mtflags); \47local_irq_restore(flags);\48} while (0)4950#define LOCK_CORE(flags, mtflags) \51do { \52local_irq_save(flags); \53mtflags = dvpe(); \54} while (0)5556#define UNLOCK_CORE(flags, mtflags) \57do { \58evpe(mtflags); \59local_irq_restore(flags);\60} while (0)6162#else6364#define LOCK_VPE(flags, mtflags)65#define UNLOCK_VPE(flags, mtflags)66#endif6768/* ensure writes to cic are completed */69static inline void cic_wmb(void)70{71const volatile void __iomem *cic_mem = CIC_VPE0_MSK_REG;72volatile u32 dummy_read;7374wmb();75dummy_read = __raw_readl(cic_mem);76dummy_read++;77}7879static void unmask_cic_irq(struct irq_data *d)80{81volatile u32 *cic_msk_reg = CIC_VPE0_MSK_REG;82int vpe;83#ifdef CONFIG_SMP84unsigned int mtflags;85unsigned long flags;8687/*88* Make sure we have IRQ affinity. It may have changed while89* we were processing the IRQ.90*/91if (!cpumask_test_cpu(smp_processor_id(), d->affinity))92return;93#endif9495vpe = get_current_vpe();96LOCK_VPE(flags, mtflags);97cic_msk_reg[vpe] |= (1 << (d->irq - MSP_CIC_INTBASE));98UNLOCK_VPE(flags, mtflags);99cic_wmb();100}101102static void mask_cic_irq(struct irq_data *d)103{104volatile u32 *cic_msk_reg = CIC_VPE0_MSK_REG;105int vpe = get_current_vpe();106#ifdef CONFIG_SMP107unsigned long flags, mtflags;108#endif109LOCK_VPE(flags, mtflags);110cic_msk_reg[vpe] &= ~(1 << (d->irq - MSP_CIC_INTBASE));111UNLOCK_VPE(flags, mtflags);112cic_wmb();113}114static void msp_cic_irq_ack(struct irq_data *d)115{116mask_cic_irq(d);117/*118* Only really necessary for 18, 16-14 and sometimes 3:0119* (since these can be edge sensitive) but it doesn't120* hurt for the others121*/122*CIC_STS_REG = (1 << (d->irq - MSP_CIC_INTBASE));123smtc_im_ack_irq(d->irq);124}125126/*Note: Limiting to VSMP . Not tested in SMTC */127128#ifdef CONFIG_MIPS_MT_SMP129static int msp_cic_irq_set_affinity(struct irq_data *d,130const struct cpumask *cpumask, bool force)131{132int cpu;133unsigned long flags;134unsigned int mtflags;135unsigned long imask = (1 << (irq - MSP_CIC_INTBASE));136volatile u32 *cic_mask = (volatile u32 *)CIC_VPE0_MSK_REG;137138/* timer balancing should be disabled in kernel code */139BUG_ON(irq == MSP_INT_VPE0_TIMER || irq == MSP_INT_VPE1_TIMER);140141LOCK_CORE(flags, mtflags);142/* enable if any of each VPE's TCs require this IRQ */143for_each_online_cpu(cpu) {144if (cpumask_test_cpu(cpu, cpumask))145cic_mask[cpu] |= imask;146else147cic_mask[cpu] &= ~imask;148149}150151UNLOCK_CORE(flags, mtflags);152return 0;153154}155#endif156157static struct irq_chip msp_cic_irq_controller = {158.name = "MSP_CIC",159.irq_mask = mask_cic_irq,160.irq_mask_ack = msp_cic_irq_ack,161.irq_unmask = unmask_cic_irq,162.irq_ack = msp_cic_irq_ack,163#ifdef CONFIG_MIPS_MT_SMP164.irq_set_affinity = msp_cic_irq_set_affinity,165#endif166};167168void __init msp_cic_irq_init(void)169{170int i;171/* Mask/clear interrupts. */172*CIC_VPE0_MSK_REG = 0x00000000;173*CIC_VPE1_MSK_REG = 0x00000000;174*CIC_STS_REG = 0xFFFFFFFF;175/*176* The MSP7120 RG and EVBD boards use IRQ[6:4] for PCI.177* These inputs map to EXT_INT_POL[6:4] inside the CIC.178* They are to be active low, level sensitive.179*/180*CIC_EXT_CFG_REG &= 0xFFFF8F8F;181182/* initialize all the IRQ descriptors */183for (i = MSP_CIC_INTBASE ; i < MSP_CIC_INTBASE + 32 ; i++) {184irq_set_chip_and_handler(i, &msp_cic_irq_controller,185handle_level_irq);186#ifdef CONFIG_MIPS_MT_SMTC187/* Mask of CIC interrupt */188irq_hwmask[i] = C_IRQ4;189#endif190}191192/* Initialize the PER interrupt sub-system */193msp_per_irq_init();194}195196/* CIC masked by CIC vector processing before dispatch called */197void msp_cic_irq_dispatch(void)198{199volatile u32 *cic_msk_reg = (volatile u32 *)CIC_VPE0_MSK_REG;200u32 cic_mask;201u32 pending;202int cic_status = *CIC_STS_REG;203cic_mask = cic_msk_reg[get_current_vpe()];204pending = cic_status & cic_mask;205if (pending & (1 << (MSP_INT_VPE0_TIMER - MSP_CIC_INTBASE))) {206do_IRQ(MSP_INT_VPE0_TIMER);207} else if (pending & (1 << (MSP_INT_VPE1_TIMER - MSP_CIC_INTBASE))) {208do_IRQ(MSP_INT_VPE1_TIMER);209} else if (pending & (1 << (MSP_INT_PER - MSP_CIC_INTBASE))) {210msp_per_irq_dispatch();211} else if (pending) {212do_IRQ(ffs(pending) + MSP_CIC_INTBASE - 1);213} else{214spurious_interrupt();215}216}217218219