/*
* arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling
*
* Copyright (C) 1997 Geert Uytterhoeven
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/sysdev.h>
#include <linux/errno.h>
#include <asm/ptrace.h>
#include <asm/signal.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/sections.h>
#include <asm/open_pic.h>
#include <asm/i8259.h>
#include "open_pic_defs.h"
#if defined(CONFIG_PRPMC800) || defined(CONFIG_85xx)
#define OPENPIC_BIG_ENDIAN
#endif
void __iomem *OpenPIC_Addr;
static volatile struct OpenPIC __iomem *OpenPIC = NULL;
/*
* We define OpenPIC_InitSenses table thusly:
* bit 0x1: sense, 0 for edge and 1 for level.
* bit 0x2: polarity, 0 for negative, 1 for positive.
*/
u_int OpenPIC_NumInitSenses __initdata = 0;
u_char *OpenPIC_InitSenses __initdata = NULL;
extern int use_of_interrupt_tree;
static u_int NumProcessors;
static u_int NumSources;
static int open_pic_irq_offset;
static volatile OpenPIC_Source __iomem *ISR[NR_IRQS];
static int openpic_cascade_irq = -1;
static int (*openpic_cascade_fn)(struct pt_regs *);
/* Global Operations */
static void openpic_disable_8259_pass_through(void);
static void openpic_set_spurious(u_int vector);
#ifdef CONFIG_SMP
/* Interprocessor Interrupts */
static void openpic_initipi(u_int ipi, u_int pri, u_int vector);
static irqreturn_t openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *);
#endif
/* Timer Interrupts */
static void openpic_inittimer(u_int timer, u_int pri, u_int vector);
static void openpic_maptimer(u_int timer, cpumask_t cpumask);
/* Interrupt Sources */
static void openpic_enable_irq(u_int irq);
static void openpic_disable_irq(u_int irq);
static void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity,
int is_level);
static void openpic_mapirq(u_int irq, cpumask_t cpumask, cpumask_t keepmask);
/*
* These functions are not used but the code is kept here
* for completeness and future reference.
*/
#ifdef notused
static void openpic_enable_8259_pass_through(void);
static u_int openpic_get_spurious(void);
static void openpic_set_sense(u_int irq, int sense);
#endif /* notused */
/*
* Description of the openpic for the higher-level irq code
*/
static void openpic_end_irq(unsigned int irq_nr);
static void openpic_ack_irq(unsigned int irq_nr);
static void openpic_set_affinity(unsigned int irq_nr, cpumask_t cpumask);
struct hw_interrupt_type open_pic = {
.typename = " OpenPIC ",
.enable = openpic_enable_irq,
.disable = openpic_disable_irq,
.ack = openpic_ack_irq,
.end = openpic_end_irq,
.set_affinity = openpic_set_affinity,
};
#ifdef CONFIG_SMP
static void openpic_end_ipi(unsigned int irq_nr);
static void openpic_ack_ipi(unsigned int irq_nr);
static void openpic_enable_ipi(unsigned int irq_nr);
static void openpic_disable_ipi(unsigned int irq_nr);
struct hw_interrupt_type open_pic_ipi = {
.typename = " OpenPIC ",
.enable = openpic_enable_ipi,
.disable = openpic_disable_ipi,
.ack = openpic_ack_ipi,
.end = openpic_end_ipi,
};
#endif /* CONFIG_SMP */
/*
* Accesses to the current processor's openpic registers
*/
#ifdef CONFIG_SMP
#define THIS_CPU Processor[cpu]
#define DECL_THIS_CPU int cpu = smp_hw_index[smp_processor_id()]
#define CHECK_THIS_CPU check_arg_cpu(cpu)
#else
#define THIS_CPU Processor[0]
#define DECL_THIS_CPU
#define CHECK_THIS_CPU
#endif /* CONFIG_SMP */
#if 1
#define check_arg_ipi(ipi) \
if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \
printk("open_pic.c:%d: invalid ipi %d\n", __LINE__, ipi);
#define check_arg_timer(timer) \
if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \
printk("open_pic.c:%d: invalid timer %d\n", __LINE__, timer);
#define check_arg_vec(vec) \
if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \
printk("open_pic.c:%d: invalid vector %d\n", __LINE__, vec);
#define check_arg_pri(pri) \
if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
printk("open_pic.c:%d: invalid priority %d\n", __LINE__, pri);
/*
* Print out a backtrace if it's out of range, since if it's larger than NR_IRQ's
* data has probably been corrupted and we're going to panic or deadlock later
* anyway --Troy
*/
#define check_arg_irq(irq) \
if (irq < open_pic_irq_offset || irq >= NumSources+open_pic_irq_offset \
|| ISR[irq - open_pic_irq_offset] == 0) { \
printk("open_pic.c:%d: invalid irq %d\n", __LINE__, irq); \
dump_stack(); }
#define check_arg_cpu(cpu) \
if (cpu < 0 || cpu >= NumProcessors){ \
printk("open_pic.c:%d: invalid cpu %d\n", __LINE__, cpu); \
dump_stack(); }
#else
#define check_arg_ipi(ipi) do {} while (0)
#define check_arg_timer(timer) do {} while (0)
#define check_arg