Setup_frame is now returning a success value.
[linux-2.6] / arch / mips / kernel / irq_cpu.c
1 /*
2  * Copyright 2001 MontaVista Software Inc.
3  * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
4  *
5  * Copyright (C) 2001 Ralf Baechle
6  * Copyright (C) 2005  MIPS Technologies, Inc.  All rights reserved.
7  *      Author: Maciej W. Rozycki <macro@mips.com>
8  *
9  * This file define the irq handler for MIPS CPU interrupts.
10  *
11  * This program is free software; you can redistribute  it and/or modify it
12  * under  the terms of  the GNU General  Public License as published by the
13  * Free Software Foundation;  either version 2 of the  License, or (at your
14  * option) any later version.
15  */
16
17 /*
18  * Almost all MIPS CPUs define 8 interrupt sources.  They are typically
19  * level triggered (i.e., cannot be cleared from CPU; must be cleared from
20  * device).  The first two are software interrupts which we don't really
21  * use or support.  The last one is usually the CPU timer interrupt if
22  * counter register is present or, for CPUs with an external FPU, by
23  * convention it's the FPU exception interrupt.
24  *
25  * Don't even think about using this on SMP.  You have been warned.
26  *
27  * This file exports one global function:
28  *      void mips_cpu_irq_init(int irq_base);
29  */
30 #include <linux/init.h>
31 #include <linux/interrupt.h>
32 #include <linux/kernel.h>
33
34 #include <asm/irq_cpu.h>
35 #include <asm/mipsregs.h>
36 #include <asm/system.h>
37
38 static int mips_cpu_irq_base;
39
40 static inline void unmask_mips_irq(unsigned int irq)
41 {
42         set_c0_status(0x100 << (irq - mips_cpu_irq_base));
43 }
44
45 static inline void mask_mips_irq(unsigned int irq)
46 {
47         clear_c0_status(0x100 << (irq - mips_cpu_irq_base));
48 }
49
50 static inline void mips_cpu_irq_enable(unsigned int irq)
51 {
52         unsigned long flags;
53
54         local_irq_save(flags);
55         unmask_mips_irq(irq);
56         local_irq_restore(flags);
57 }
58
59 static void mips_cpu_irq_disable(unsigned int irq)
60 {
61         unsigned long flags;
62
63         local_irq_save(flags);
64         mask_mips_irq(irq);
65         local_irq_restore(flags);
66 }
67
68 static unsigned int mips_cpu_irq_startup(unsigned int irq)
69 {
70         mips_cpu_irq_enable(irq);
71
72         return 0;
73 }
74
75 #define mips_cpu_irq_shutdown   mips_cpu_irq_disable
76
77 /*
78  * While we ack the interrupt interrupts are disabled and thus we don't need
79  * to deal with concurrency issues.  Same for mips_cpu_irq_end.
80  */
81 static void mips_cpu_irq_ack(unsigned int irq)
82 {
83         /* Only necessary for soft interrupts */
84         clear_c0_cause(0x100 << (irq - mips_cpu_irq_base));
85
86         mask_mips_irq(irq);
87 }
88
89 static void mips_cpu_irq_end(unsigned int irq)
90 {
91         if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
92                 unmask_mips_irq(irq);
93 }
94
95 static hw_irq_controller mips_cpu_irq_controller = {
96         .typename = "MIPS",
97         .startup = mips_cpu_irq_startup,
98         .shutdown = mips_cpu_irq_shutdown,
99         .enable = mips_cpu_irq_enable,
100         .disable = mips_cpu_irq_disable,
101         .ack = mips_cpu_irq_ack,
102         .end = mips_cpu_irq_end,
103 };
104
105
106 void __init mips_cpu_irq_init(int irq_base)
107 {
108         int i;
109
110         /* Mask interrupts. */
111         clear_c0_status(ST0_IM);
112         clear_c0_cause(CAUSEF_IP);
113
114         for (i = irq_base; i < irq_base + 8; i++) {
115                 irq_desc[i].status = IRQ_DISABLED;
116                 irq_desc[i].action = NULL;
117                 irq_desc[i].depth = 1;
118                 irq_desc[i].handler = &mips_cpu_irq_controller;
119         }
120
121         mips_cpu_irq_base = irq_base;
122 }