irq-rm9000.c 2.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 * Copyright (C) 2003 Ralf Baechle
 *
 * 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.
 *
 * Handler for RM9000 extended interrupts.  These are a non-standard
 * feature so we handle them separately from standard interrupts.
 */
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>

#include <asm/irq_cpu.h>
#include <asm/mipsregs.h>
#include <asm/system.h>

static inline void unmask_rm9k_irq(unsigned int irq)
{
23
	set_c0_intcontrol(0x1000 << (irq - RM9K_CPU_IRQ_BASE));
L
Linus Torvalds 已提交
24 25 26 27
}

static inline void mask_rm9k_irq(unsigned int irq)
{
28
	clear_c0_intcontrol(0x1000 << (irq - RM9K_CPU_IRQ_BASE));
L
Linus Torvalds 已提交
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
}

static inline void rm9k_cpu_irq_enable(unsigned int irq)
{
	unsigned long flags;

	local_irq_save(flags);
	unmask_rm9k_irq(irq);
	local_irq_restore(flags);
}

/*
 * Performance counter interrupts are global on all processors.
 */
static void local_rm9k_perfcounter_irq_startup(void *args)
{
	unsigned int irq = (unsigned int) args;

	rm9k_cpu_irq_enable(irq);
}

static unsigned int rm9k_perfcounter_irq_startup(unsigned int irq)
{
	on_each_cpu(local_rm9k_perfcounter_irq_startup, (void *) irq, 0, 1);

	return 0;
}

static void local_rm9k_perfcounter_irq_shutdown(void *args)
{
	unsigned int irq = (unsigned int) args;
	unsigned long flags;

	local_irq_save(flags);
	mask_rm9k_irq(irq);
	local_irq_restore(flags);
}

static void rm9k_perfcounter_irq_shutdown(unsigned int irq)
{
	on_each_cpu(local_rm9k_perfcounter_irq_shutdown, (void *) irq, 0, 1);
}

72
static struct irq_chip rm9k_irq_controller = {
73
	.name = "RM9000",
A
Atsushi Nemoto 已提交
74 75 76 77
	.ack = mask_rm9k_irq,
	.mask = mask_rm9k_irq,
	.mask_ack = mask_rm9k_irq,
	.unmask = unmask_rm9k_irq,
L
Linus Torvalds 已提交
78 79
};

80
static struct irq_chip rm9k_perfcounter_irq = {
81
	.name = "RM9000",
82 83
	.startup = rm9k_perfcounter_irq_startup,
	.shutdown = rm9k_perfcounter_irq_shutdown,
A
Atsushi Nemoto 已提交
84 85 86 87
	.ack = mask_rm9k_irq,
	.mask = mask_rm9k_irq,
	.mask_ack = mask_rm9k_irq,
	.unmask = unmask_rm9k_irq,
L
Linus Torvalds 已提交
88 89 90 91 92 93
};

unsigned int rm9000_perfcount_irq;

EXPORT_SYMBOL(rm9000_perfcount_irq);

94
void __init rm9k_cpu_irq_init(void)
L
Linus Torvalds 已提交
95
{
96
	int base = RM9K_CPU_IRQ_BASE;
L
Linus Torvalds 已提交
97 98 99 100
	int i;

	clear_c0_intcontrol(0x0000f000);		/* Mask all */

A
Atsushi Nemoto 已提交
101
	for (i = base; i < base + 4; i++)
102 103
		set_irq_chip_and_handler(i, &rm9k_irq_controller,
					 handle_level_irq);
L
Linus Torvalds 已提交
104 105

	rm9000_perfcount_irq = base + 1;
106
	set_irq_chip_and_handler(rm9000_perfcount_irq, &rm9k_perfcounter_irq,
107
				 handle_percpu_irq);
L
Linus Torvalds 已提交
108
}