[PATCH] V850: user ARRAY_SIZE macro when appropriate
[sfrench/cifs-2.6.git] / arch / v850 / kernel / gbus_int.c
1 /*
2  * arch/v850/kernel/gbus_int.c -- Midas labs GBUS interrupt support
3  *
4  *  Copyright (C) 2001,02,03  NEC Electronics Corporation
5  *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
6  *
7  * This file is subject to the terms and conditions of the GNU General
8  * Public License.  See the file COPYING in the main directory of this
9  * archive for more details.
10  *
11  * Written by Miles Bader <miles@gnu.org>
12  */
13
14 #include <linux/types.h>
15 #include <linux/init.h>
16 #include <linux/irq.h>
17 #include <linux/interrupt.h>
18 #include <linux/signal.h>
19 #include <linux/kernel.h>
20
21 #include <asm/machdep.h>
22
23
24 /* The number of shared GINT interrupts. */
25 #define NUM_GINTS       4
26
27 /* For each GINT interrupt, how many GBUS interrupts are using it.  */
28 static unsigned gint_num_active_irqs[NUM_GINTS] = { 0 };
29
30 /* A table of GINTn interrupts we actually use.
31    Note that we don't use GINT0 because all the boards we support treat it
32    specially.  */
33 struct used_gint {
34         unsigned gint;
35         unsigned priority;
36 } used_gint[] = {
37         { 1, GBUS_INT_PRIORITY_HIGH },
38         { 3, GBUS_INT_PRIORITY_LOW }
39 };
40 #define NUM_USED_GINTS ARRAY_SIZE(used_gint)
41
42 /* A table of which GINT is used by each GBUS interrupts (they are
43    assigned based on priority).  */
44 static unsigned char gbus_int_gint[IRQ_GBUS_INT_NUM];
45
46 \f
47 /* Interrupt enabling/disabling.  */
48
49 /* Enable interrupt handling for interrupt IRQ.  */
50 void gbus_int_enable_irq (unsigned irq)
51 {
52         unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ];
53         GBUS_INT_ENABLE (GBUS_INT_IRQ_WORD(irq), gint)
54                 |= GBUS_INT_IRQ_MASK (irq);
55 }
56
57 /* Disable interrupt handling for interrupt IRQ.  Note that any
58    interrupts received while disabled will be delivered once the
59    interrupt is enabled again, unless they are explicitly cleared using
60    `gbus_int_clear_pending_irq'.  */
61 void gbus_int_disable_irq (unsigned irq)
62 {
63         unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ];
64         GBUS_INT_ENABLE (GBUS_INT_IRQ_WORD(irq), gint)
65                 &= ~GBUS_INT_IRQ_MASK (irq);
66 }
67
68 /* Return true if interrupt handling for interrupt IRQ is enabled.  */
69 int gbus_int_irq_enabled (unsigned irq)
70 {
71         unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ];
72         return (GBUS_INT_ENABLE (GBUS_INT_IRQ_WORD(irq), gint)
73                 & GBUS_INT_IRQ_MASK(irq));
74 }
75
76 /* Disable all GBUS irqs.  */
77 void gbus_int_disable_irqs ()
78 {
79         unsigned w, n;
80         for (w = 0; w < GBUS_INT_NUM_WORDS; w++)
81                 for (n = 0; n < IRQ_GINT_NUM; n++)
82                         GBUS_INT_ENABLE (w, n) = 0;
83 }
84
85 /* Clear any pending interrupts for IRQ.  */
86 void gbus_int_clear_pending_irq (unsigned irq)
87 {
88         GBUS_INT_CLEAR (GBUS_INT_IRQ_WORD(irq)) = GBUS_INT_IRQ_MASK (irq);
89 }
90
91 /* Return true if interrupt IRQ is pending (but disabled).  */
92 int gbus_int_irq_pending (unsigned irq)
93 {
94         return (GBUS_INT_STATUS (GBUS_INT_IRQ_WORD(irq))
95                 & GBUS_INT_IRQ_MASK(irq));
96 }
97
98 \f
99 /* Delegating interrupts.  */
100
101 /* Handle a shared GINT interrupt by passing to the appropriate GBUS
102    interrupt handler.  */
103 static irqreturn_t gbus_int_handle_irq (int irq, void *dev_id,
104                                         struct pt_regs *regs)
105 {
106         unsigned w;
107         irqreturn_t rval = IRQ_NONE;
108         unsigned gint = irq - IRQ_GINT (0);
109
110         for (w = 0; w < GBUS_INT_NUM_WORDS; w++) {
111                 unsigned status = GBUS_INT_STATUS (w);
112                 unsigned enable = GBUS_INT_ENABLE (w, gint);
113
114                 /* Only pay attention to enabled interrupts.  */
115                 status &= enable;
116                 if (status) {
117                         irq = IRQ_GBUS_INT (w * GBUS_INT_BITS_PER_WORD);
118                         do {
119                                 /* There's an active interrupt in word
120                                    W, find out which one, and call its
121                                    handler.  */
122
123                                 while (! (status & 0x1)) {
124                                         irq++;
125                                         status >>= 1;
126                                 }
127                                 status &= ~0x1;
128
129                                 /* Recursively call handle_irq to handle it. */
130                                 handle_irq (irq, regs);
131                                 rval = IRQ_HANDLED;
132                         } while (status);
133                 }
134         }
135
136         /* Toggle the `all enable' bit back and forth, which should cause
137            another edge transition if there are any other interrupts
138            still pending, and so result in another CPU interrupt.  */
139         GBUS_INT_ENABLE (0, gint) &= ~0x1;
140         GBUS_INT_ENABLE (0, gint) |=  0x1;
141
142         return rval;
143 }
144
145 \f
146 /* Initialize GBUS interrupt sources.  */
147
148 static void irq_nop (unsigned irq) { }
149
150 static unsigned gbus_int_startup_irq (unsigned irq)
151 {
152         unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ];
153
154         if (gint_num_active_irqs[gint] == 0) {
155                 /* First enable the CPU interrupt.  */
156                 int rval =
157                         request_irq (IRQ_GINT(gint), gbus_int_handle_irq,
158                                      IRQF_DISABLED,
159                                      "gbus_int_handler",
160                                      &gint_num_active_irqs[gint]);
161                 if (rval != 0)
162                         return rval;
163         }
164
165         gint_num_active_irqs[gint]++;
166
167         gbus_int_clear_pending_irq (irq);
168         gbus_int_enable_irq (irq);
169
170         return 0;
171 }
172
173 static void gbus_int_shutdown_irq (unsigned irq)
174 {
175         unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ];
176
177         gbus_int_disable_irq (irq);
178
179         if (--gint_num_active_irqs[gint] == 0)
180                 /* Disable the CPU interrupt.  */
181                 free_irq (IRQ_GINT(gint), &gint_num_active_irqs[gint]);
182 }
183
184 /* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array
185    INITS (which is terminated by an entry with the name field == 0).  */
186 void __init gbus_int_init_irq_types (struct gbus_int_irq_init *inits,
187                                      struct hw_interrupt_type *hw_irq_types)
188 {
189         struct gbus_int_irq_init *init;
190         for (init = inits; init->name; init++) {
191                 unsigned i;
192                 struct hw_interrupt_type *hwit = hw_irq_types++;
193
194                 hwit->typename = init->name;
195
196                 hwit->startup  = gbus_int_startup_irq;
197                 hwit->shutdown = gbus_int_shutdown_irq;
198                 hwit->enable   = gbus_int_enable_irq;
199                 hwit->disable  = gbus_int_disable_irq;
200                 hwit->ack      = irq_nop;
201                 hwit->end      = irq_nop;
202                 
203                 /* Initialize kernel IRQ infrastructure for this interrupt.  */
204                 init_irq_handlers(init->base, init->num, init->interval, hwit);
205
206                 /* Set the interrupt priorities.  */
207                 for (i = 0; i < init->num; i++) {
208                         unsigned j;
209                         for (j = 0; j < NUM_USED_GINTS; j++)
210                                 if (used_gint[j].priority > init->priority)
211                                         break;
212                         /* Wherever we stopped looking is one past the
213                            GINT we want. */
214                         gbus_int_gint[init->base + i * init->interval
215                                       - GBUS_INT_BASE_IRQ]
216                                 = used_gint[j > 0 ? j - 1 : 0].gint;
217                 }
218         }
219 }
220
221 \f
222 /* Initialize IRQS.  */
223
224 /* Chip interrupts (GINTn) shared among GBUS interrupts.  */
225 static struct hw_interrupt_type gint_hw_itypes[NUM_USED_GINTS];
226
227
228 /* GBUS interrupts themselves.  */
229
230 struct gbus_int_irq_init gbus_irq_inits[] __initdata = {
231         /* First set defaults.  */
232         { "GBUS_INT", IRQ_GBUS_INT(0), IRQ_GBUS_INT_NUM, 1, 6},
233         { 0 }
234 };
235 #define NUM_GBUS_IRQ_INITS (ARRAY_SIZE(gbus_irq_inits) - 1)
236
237 static struct hw_interrupt_type gbus_hw_itypes[NUM_GBUS_IRQ_INITS];
238
239
240 /* Initialize GBUS interrupts.  */
241 void __init gbus_int_init_irqs (void)
242 {
243         unsigned i;
244
245         /* First initialize the shared gint interrupts.  */
246         for (i = 0; i < NUM_USED_GINTS; i++) {
247                 unsigned gint = used_gint[i].gint;
248                 struct v850e_intc_irq_init gint_irq_init[2];
249
250                 /* We initialize one GINT interrupt at a time.  */
251                 gint_irq_init[0].name = "GINT";
252                 gint_irq_init[0].base = IRQ_GINT (gint);
253                 gint_irq_init[0].num = 1;
254                 gint_irq_init[0].interval = 1;
255                 gint_irq_init[0].priority = used_gint[i].priority;
256
257                 gint_irq_init[1].name = 0; /* Terminate the vector.  */
258
259                 v850e_intc_init_irq_types (gint_irq_init, gint_hw_itypes);
260         }
261
262         /* Then the GBUS interrupts.  */
263         gbus_int_disable_irqs ();
264         gbus_int_init_irq_types (gbus_irq_inits, gbus_hw_itypes);
265         /* Turn on the `all enable' bits, which are ANDed with
266            individual interrupt enable bits; we only want to bother with
267            the latter.  They are the first bit in the first word of each
268            interrupt-enable area.  */
269         for (i = 0; i < NUM_USED_GINTS; i++)
270                 GBUS_INT_ENABLE (0, used_gint[i].gint) = 0x1;
271 }