forked from Minki/linux
0ca71737fe
The current interrupt handling code for the MSP4200 always masks an interrupt before acknowledging it. This is not required, as that will be handled by the level interrupt handler. This change simplifies the MSP4200 code to remove the masking in the ack routine, and makes sure that the minimum required operation is performed for masking and acking, rather than always both masking and acking the interrupt. Signed-off-by: Shane McDonald <mcdonald.shane@gmail.com> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
102 lines
2.6 KiB
C
102 lines
2.6 KiB
C
/*
|
|
* This file define the irq handler for MSP SLM subsystem interrupts.
|
|
*
|
|
* Copyright 2005-2006 PMC-Sierra, Inc, derived from irq_cpu.c
|
|
* Author: Andrew Hughes, Andrew_Hughes@pmc-sierra.com
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include <linux/init.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/bitops.h>
|
|
|
|
#include <asm/mipsregs.h>
|
|
#include <asm/system.h>
|
|
|
|
#include <msp_slp_int.h>
|
|
#include <msp_regs.h>
|
|
|
|
static inline void unmask_msp_slp_irq(unsigned int irq)
|
|
{
|
|
/* check for PER interrupt range */
|
|
if (irq < MSP_PER_INTBASE)
|
|
*SLP_INT_MSK_REG |= (1 << (irq - MSP_SLP_INTBASE));
|
|
else
|
|
*PER_INT_MSK_REG |= (1 << (irq - MSP_PER_INTBASE));
|
|
}
|
|
|
|
static inline void mask_msp_slp_irq(unsigned int irq)
|
|
{
|
|
/* check for PER interrupt range */
|
|
if (irq < MSP_PER_INTBASE)
|
|
*SLP_INT_MSK_REG &= ~(1 << (irq - MSP_SLP_INTBASE));
|
|
else
|
|
*PER_INT_MSK_REG &= ~(1 << (irq - MSP_PER_INTBASE));
|
|
}
|
|
|
|
/*
|
|
* While we ack the interrupt interrupts are disabled and thus we don't need
|
|
* to deal with concurrency issues. Same for msp_slp_irq_end.
|
|
*/
|
|
static inline void ack_msp_slp_irq(unsigned int irq)
|
|
{
|
|
/* check for PER interrupt range */
|
|
if (irq < MSP_PER_INTBASE)
|
|
*SLP_INT_STS_REG = (1 << (irq - MSP_SLP_INTBASE));
|
|
else
|
|
*PER_INT_STS_REG = (1 << (irq - MSP_PER_INTBASE));
|
|
}
|
|
|
|
static struct irq_chip msp_slp_irq_controller = {
|
|
.name = "MSP_SLP",
|
|
.ack = ack_msp_slp_irq,
|
|
.mask = mask_msp_slp_irq,
|
|
.unmask = unmask_msp_slp_irq,
|
|
};
|
|
|
|
void __init msp_slp_irq_init(void)
|
|
{
|
|
int i;
|
|
|
|
/* Mask/clear interrupts. */
|
|
*SLP_INT_MSK_REG = 0x00000000;
|
|
*PER_INT_MSK_REG = 0x00000000;
|
|
*SLP_INT_STS_REG = 0xFFFFFFFF;
|
|
*PER_INT_STS_REG = 0xFFFFFFFF;
|
|
|
|
/* initialize all the IRQ descriptors */
|
|
for (i = MSP_SLP_INTBASE; i < MSP_PER_INTBASE + 32; i++)
|
|
set_irq_chip_and_handler(i, &msp_slp_irq_controller,
|
|
handle_level_irq);
|
|
}
|
|
|
|
void msp_slp_irq_dispatch(void)
|
|
{
|
|
u32 pending;
|
|
int intbase;
|
|
|
|
intbase = MSP_SLP_INTBASE;
|
|
pending = *SLP_INT_STS_REG & *SLP_INT_MSK_REG;
|
|
|
|
/* check for PER interrupt */
|
|
if (pending == (1 << (MSP_INT_PER - MSP_SLP_INTBASE))) {
|
|
intbase = MSP_PER_INTBASE;
|
|
pending = *PER_INT_STS_REG & *PER_INT_MSK_REG;
|
|
}
|
|
|
|
/* check for spurious interrupt */
|
|
if (pending == 0x00000000) {
|
|
printk(KERN_ERR "Spurious %s interrupt?\n",
|
|
(intbase == MSP_SLP_INTBASE) ? "SLP" : "PER");
|
|
return;
|
|
}
|
|
|
|
/* dispatch the irq */
|
|
do_IRQ(ffs(pending) + intbase - 1);
|
|
}
|