aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/cpu/irq/intc.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/kernel/cpu/irq/intc.c')
-rw-r--r--arch/sh/kernel/cpu/irq/intc.c562
1 files changed, 394 insertions, 168 deletions
diff --git a/arch/sh/kernel/cpu/irq/intc.c b/arch/sh/kernel/cpu/irq/intc.c
index 9345a7130e9e..6ac018c15e03 100644
--- a/arch/sh/kernel/cpu/irq/intc.c
+++ b/arch/sh/kernel/cpu/irq/intc.c
@@ -20,145 +20,258 @@
20#include <linux/module.h> 20#include <linux/module.h>
21#include <linux/io.h> 21#include <linux/io.h>
22#include <linux/interrupt.h> 22#include <linux/interrupt.h>
23#include <linux/bootmem.h>
24
25#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
26 ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \
27 ((addr_e) << 16) | ((addr_d << 24)))
28
29#define _INTC_SHIFT(h) (h & 0x1f)
30#define _INTC_WIDTH(h) ((h >> 5) & 0xf)
31#define _INTC_FN(h) ((h >> 9) & 0xf)
32#define _INTC_MODE(h) ((h >> 13) & 0x7)
33#define _INTC_ADDR_E(h) ((h >> 16) & 0xff)
34#define _INTC_ADDR_D(h) ((h >> 24) & 0xff)
35
36struct intc_handle_int {
37 unsigned int irq;
38 unsigned long handle;
39};
40
41struct intc_desc_int {
42 unsigned long *reg;
43#ifdef CONFIG_SMP
44 unsigned long *smp;
45#endif
46 unsigned int nr_reg;
47 struct intc_handle_int *prio;
48 unsigned int nr_prio;
49 struct intc_handle_int *sense;
50 unsigned int nr_sense;
51 struct irq_chip chip;
52};
23 53
24#define _INTC_MK(fn, idx, bit, value) \ 54#ifdef CONFIG_SMP
25 ((fn) << 24 | ((value) << 16) | ((idx) << 8) | (bit)) 55#define IS_SMP(x) x.smp
26#define _INTC_FN(h) (h >> 24) 56#define INTC_REG(d, x, c) (d->reg[(x)] + ((d->smp[(x)] & 0xff) * c))
27#define _INTC_VALUE(h) ((h >> 16) & 0xff) 57#define SMP_NR(d, x) ((d->smp[(x)] >> 8) ? (d->smp[(x)] >> 8) : 1)
28#define _INTC_IDX(h) ((h >> 8) & 0xff) 58#else
29#define _INTC_BIT(h) (h & 0xff) 59#define IS_SMP(x) 0
60#define INTC_REG(d, x, c) (d->reg[(x)])
61#define SMP_NR(d, x) 1
62#endif
30 63
31#define _INTC_PTR(desc, member, data) \ 64static unsigned int intc_prio_level[NR_IRQS]; /* for now */
32 (desc->member + _INTC_IDX(data))
33 65
34static inline struct intc_desc *get_intc_desc(unsigned int irq) 66static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
35{ 67{
36 struct irq_chip *chip = get_irq_chip(irq); 68 struct irq_chip *chip = get_irq_chip(irq);
37 return (void *)((char *)chip - offsetof(struct intc_desc, chip)); 69 return (void *)((char *)chip - offsetof(struct intc_desc_int, chip));
38} 70}
39 71
40static inline unsigned int set_field(unsigned int value, 72static inline unsigned int set_field(unsigned int value,
41 unsigned int field_value, 73 unsigned int field_value,
42 unsigned int width, 74 unsigned int handle)
43 unsigned int shift)
44{ 75{
76 unsigned int width = _INTC_WIDTH(handle);
77 unsigned int shift = _INTC_SHIFT(handle);
78
45 value &= ~(((1 << width) - 1) << shift); 79 value &= ~(((1 << width) - 1) << shift);
46 value |= field_value << shift; 80 value |= field_value << shift;
47 return value; 81 return value;
48} 82}
49 83
50static inline unsigned int set_prio_field(struct intc_desc *desc, 84static void write_8(unsigned long addr, unsigned long h, unsigned long data)
51 unsigned int value,
52 unsigned int priority,
53 unsigned int data)
54{ 85{
55 unsigned int width = _INTC_PTR(desc, prio_regs, data)->field_width; 86 ctrl_outb(set_field(0, data, h), addr);
56
57 return set_field(value, priority, width, _INTC_BIT(data));
58} 87}
59 88
60static void disable_prio_16(struct intc_desc *desc, unsigned int data) 89static void write_16(unsigned long addr, unsigned long h, unsigned long data)
61{ 90{
62 unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg; 91 ctrl_outw(set_field(0, data, h), addr);
63
64 ctrl_outw(set_prio_field(desc, ctrl_inw(addr), 0, data), addr);
65} 92}
66 93
67static void enable_prio_16(struct intc_desc *desc, unsigned int data) 94static void write_32(unsigned long addr, unsigned long h, unsigned long data)
68{ 95{
69 unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg; 96 ctrl_outl(set_field(0, data, h), addr);
70 unsigned int prio = _INTC_VALUE(data);
71
72 ctrl_outw(set_prio_field(desc, ctrl_inw(addr), prio, data), addr);
73} 97}
74 98
75static void disable_prio_32(struct intc_desc *desc, unsigned int data) 99static void modify_8(unsigned long addr, unsigned long h, unsigned long data)
76{ 100{
77 unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg; 101 ctrl_outb(set_field(ctrl_inb(addr), data, h), addr);
78
79 ctrl_outl(set_prio_field(desc, ctrl_inl(addr), 0, data), addr);
80} 102}
81 103
82static void enable_prio_32(struct intc_desc *desc, unsigned int data) 104static void modify_16(unsigned long addr, unsigned long h, unsigned long data)
83{ 105{
84 unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg; 106 ctrl_outw(set_field(ctrl_inw(addr), data, h), addr);
85 unsigned int prio = _INTC_VALUE(data);
86
87 ctrl_outl(set_prio_field(desc, ctrl_inl(addr), prio, data), addr);
88} 107}
89 108
90static void disable_mask_8(struct intc_desc *desc, unsigned int data) 109static void modify_32(unsigned long addr, unsigned long h, unsigned long data)
91{ 110{
92 ctrl_outb(1 << _INTC_BIT(data), 111 ctrl_outl(set_field(ctrl_inl(addr), data, h), addr);
93 _INTC_PTR(desc, mask_regs, data)->set_reg);
94} 112}
95 113
96static void enable_mask_8(struct intc_desc *desc, unsigned int data) 114enum { REG_FN_ERR = 0, REG_FN_WRITE_BASE = 1, REG_FN_MODIFY_BASE = 5 };
115
116static void (*intc_reg_fns[])(unsigned long addr,
117 unsigned long h,
118 unsigned long data) = {
119 [REG_FN_WRITE_BASE + 0] = write_8,
120 [REG_FN_WRITE_BASE + 1] = write_16,
121 [REG_FN_WRITE_BASE + 3] = write_32,
122 [REG_FN_MODIFY_BASE + 0] = modify_8,
123 [REG_FN_MODIFY_BASE + 1] = modify_16,
124 [REG_FN_MODIFY_BASE + 3] = modify_32,
125};
126
127enum { MODE_ENABLE_REG = 0, /* Bit(s) set -> interrupt enabled */
128 MODE_MASK_REG, /* Bit(s) set -> interrupt disabled */
129 MODE_DUAL_REG, /* Two registers, set bit to enable / disable */
130 MODE_PRIO_REG, /* Priority value written to enable interrupt */
131 MODE_PCLR_REG, /* Above plus all bits set to disable interrupt */
132};
133
134static void intc_mode_field(unsigned long addr,
135 unsigned long handle,
136 void (*fn)(unsigned long,
137 unsigned long,
138 unsigned long),
139 unsigned int irq)
97{ 140{
98 ctrl_outb(1 << _INTC_BIT(data), 141 fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1));
99 _INTC_PTR(desc, mask_regs, data)->clr_reg);
100} 142}
101 143
102static void disable_mask_32(struct intc_desc *desc, unsigned int data) 144static void intc_mode_zero(unsigned long addr,
145 unsigned long handle,
146 void (*fn)(unsigned long,
147 unsigned long,
148 unsigned long),
149 unsigned int irq)
103{ 150{
104 ctrl_outl(1 << _INTC_BIT(data), 151 fn(addr, handle, 0);
105 _INTC_PTR(desc, mask_regs, data)->set_reg);
106} 152}
107 153
108static void enable_mask_32(struct intc_desc *desc, unsigned int data) 154static void intc_mode_prio(unsigned long addr,
155 unsigned long handle,
156 void (*fn)(unsigned long,
157 unsigned long,
158 unsigned long),
159 unsigned int irq)
109{ 160{
110 ctrl_outl(1 << _INTC_BIT(data), 161 fn(addr, handle, intc_prio_level[irq]);
111 _INTC_PTR(desc, mask_regs, data)->clr_reg);
112} 162}
113 163
114enum { REG_FN_ERROR=0, 164static void (*intc_enable_fns[])(unsigned long addr,
115 REG_FN_MASK_8, REG_FN_MASK_32, 165 unsigned long handle,
116 REG_FN_PRIO_16, REG_FN_PRIO_32 }; 166 void (*fn)(unsigned long,
117 167 unsigned long,
118static struct { 168 unsigned long),
119 void (*enable)(struct intc_desc *, unsigned int); 169 unsigned int irq) = {
120 void (*disable)(struct intc_desc *, unsigned int); 170 [MODE_ENABLE_REG] = intc_mode_field,
121} intc_reg_fns[] = { 171 [MODE_MASK_REG] = intc_mode_zero,
122 [REG_FN_MASK_8] = { enable_mask_8, disable_mask_8 }, 172 [MODE_DUAL_REG] = intc_mode_field,
123 [REG_FN_MASK_32] = { enable_mask_32, disable_mask_32 }, 173 [MODE_PRIO_REG] = intc_mode_prio,
124 [REG_FN_PRIO_16] = { enable_prio_16, disable_prio_16 }, 174 [MODE_PCLR_REG] = intc_mode_prio,
125 [REG_FN_PRIO_32] = { enable_prio_32, disable_prio_32 },
126}; 175};
127 176
128static void intc_enable(unsigned int irq) 177static void (*intc_disable_fns[])(unsigned long addr,
178 unsigned long handle,
179 void (*fn)(unsigned long,
180 unsigned long,
181 unsigned long),
182 unsigned int irq) = {
183 [MODE_ENABLE_REG] = intc_mode_zero,
184 [MODE_MASK_REG] = intc_mode_field,
185 [MODE_DUAL_REG] = intc_mode_field,
186 [MODE_PRIO_REG] = intc_mode_zero,
187 [MODE_PCLR_REG] = intc_mode_field,
188};
189
190static inline void _intc_enable(unsigned int irq, unsigned long handle)
129{ 191{
130 struct intc_desc *desc = get_intc_desc(irq); 192 struct intc_desc_int *d = get_intc_desc(irq);
131 unsigned int data = (unsigned int) get_irq_chip_data(irq); 193 unsigned long addr;
194 unsigned int cpu;
195
196 for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
197 addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
198 intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
199 [_INTC_FN(handle)], irq);
200 }
201}
132 202
133 intc_reg_fns[_INTC_FN(data)].enable(desc, data); 203static void intc_enable(unsigned int irq)
204{
205 _intc_enable(irq, (unsigned long)get_irq_chip_data(irq));
134} 206}
135 207
136static void intc_disable(unsigned int irq) 208static void intc_disable(unsigned int irq)
137{ 209{
138 struct intc_desc *desc = get_intc_desc(irq); 210 struct intc_desc_int *d = get_intc_desc(irq);
139 unsigned int data = (unsigned int) get_irq_chip_data(irq); 211 unsigned long handle = (unsigned long) get_irq_chip_data(irq);
140 212 unsigned long addr;
141 intc_reg_fns[_INTC_FN(data)].disable(desc, data); 213 unsigned int cpu;
214
215 for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
216 addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
217 intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\
218 [_INTC_FN(handle)], irq);
219 }
142} 220}
143 221
144static void set_sense_16(struct intc_desc *desc, unsigned int data) 222static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
223 unsigned int nr_hp,
224 unsigned int irq)
145{ 225{
146 unsigned long addr = _INTC_PTR(desc, sense_regs, data)->reg; 226 int i;
147 unsigned int width = _INTC_PTR(desc, sense_regs, data)->field_width; 227
148 unsigned int bit = _INTC_BIT(data); 228 /* this doesn't scale well, but...
149 unsigned int value = _INTC_VALUE(data); 229 *
230 * this function should only be used for cerain uncommon
231 * operations such as intc_set_priority() and intc_set_sense()
232 * and in those rare cases performance doesn't matter that much.
233 * keeping the memory footprint low is more important.
234 *
235 * one rather simple way to speed this up and still keep the
236 * memory footprint down is to make sure the array is sorted
237 * and then perform a bisect to lookup the irq.
238 */
150 239
151 ctrl_outw(set_field(ctrl_inw(addr), value, width, bit), addr); 240 for (i = 0; i < nr_hp; i++) {
241 if ((hp + i)->irq != irq)
242 continue;
243
244 return hp + i;
245 }
246
247 return NULL;
152} 248}
153 249
154static void set_sense_32(struct intc_desc *desc, unsigned int data) 250int intc_set_priority(unsigned int irq, unsigned int prio)
155{ 251{
156 unsigned long addr = _INTC_PTR(desc, sense_regs, data)->reg; 252 struct intc_desc_int *d = get_intc_desc(irq);
157 unsigned int width = _INTC_PTR(desc, sense_regs, data)->field_width; 253 struct intc_handle_int *ihp;
158 unsigned int bit = _INTC_BIT(data); 254
159 unsigned int value = _INTC_VALUE(data); 255 if (!intc_prio_level[irq] || prio <= 1)
256 return -EINVAL;
257
258 ihp = intc_find_irq(d->prio, d->nr_prio, irq);
259 if (ihp) {
260 if (prio >= (1 << _INTC_WIDTH(ihp->handle)))
261 return -EINVAL;
160 262
161 ctrl_outl(set_field(ctrl_inl(addr), value, width, bit), addr); 263 intc_prio_level[irq] = prio;
264
265 /*
266 * only set secondary masking method directly
267 * primary masking method is using intc_prio_level[irq]
268 * priority level will be set during next enable()
269 */
270
271 if (_INTC_FN(ihp->handle) != REG_FN_ERR)
272 _intc_enable(irq, ihp->handle);
273 }
274 return 0;
162} 275}
163 276
164#define VALID(x) (x | 0x80) 277#define VALID(x) (x | 0x80)
@@ -172,79 +285,38 @@ static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
172 285
173static int intc_set_sense(unsigned int irq, unsigned int type) 286static int intc_set_sense(unsigned int irq, unsigned int type)
174{ 287{
175 struct intc_desc *desc = get_intc_desc(irq); 288 struct intc_desc_int *d = get_intc_desc(irq);
176 unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK]; 289 unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK];
177 unsigned int i, j, data, bit; 290 struct intc_handle_int *ihp;
178 intc_enum enum_id = 0; 291 unsigned long addr;
179
180 for (i = 0; i < desc->nr_vectors; i++) {
181 struct intc_vect *vect = desc->vectors + i;
182
183 if (evt2irq(vect->vect) != irq)
184 continue;
185 292
186 enum_id = vect->enum_id; 293 if (!value)
187 break;
188 }
189
190 if (!enum_id || !value)
191 return -EINVAL; 294 return -EINVAL;
192 295
193 value ^= VALID(0); 296 ihp = intc_find_irq(d->sense, d->nr_sense, irq);
194 297 if (ihp) {
195 for (i = 0; i < desc->nr_sense_regs; i++) { 298 addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0);
196 struct intc_sense_reg *sr = desc->sense_regs + i; 299 intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value);
197
198 for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) {
199 if (sr->enum_ids[j] != enum_id)
200 continue;
201
202 bit = sr->reg_width - ((j + 1) * sr->field_width);
203 data = _INTC_MK(0, i, bit, value);
204
205 switch(sr->reg_width) {
206 case 16:
207 set_sense_16(desc, data);
208 break;
209 case 32:
210 set_sense_32(desc, data);
211 break;
212 }
213
214 return 0;
215 }
216 } 300 }
217 301 return 0;
218 return -EINVAL;
219} 302}
220 303
221static unsigned int __init intc_find_mask_handler(unsigned int width) 304static unsigned int __init intc_get_reg(struct intc_desc_int *d,
305 unsigned long address)
222{ 306{
223 switch (width) { 307 unsigned int k;
224 case 8:
225 return REG_FN_MASK_8;
226 case 32:
227 return REG_FN_MASK_32;
228 }
229 308
230 BUG(); 309 for (k = 0; k < d->nr_reg; k++) {
231 return REG_FN_ERROR; 310 if (d->reg[k] == address)
232} 311 return k;
233
234static unsigned int __init intc_find_prio_handler(unsigned int width)
235{
236 switch (width) {
237 case 16:
238 return REG_FN_PRIO_16;
239 case 32:
240 return REG_FN_PRIO_32;
241 } 312 }
242 313
243 BUG(); 314 BUG();
244 return REG_FN_ERROR; 315 return 0;
245} 316}
246 317
247static intc_enum __init intc_grp_id(struct intc_desc *desc, intc_enum enum_id) 318static intc_enum __init intc_grp_id(struct intc_desc *desc,
319 intc_enum enum_id)
248{ 320{
249 struct intc_group *g = desc->groups; 321 struct intc_group *g = desc->groups;
250 unsigned int i, j; 322 unsigned int i, j;
@@ -289,10 +361,12 @@ static unsigned int __init intc_prio_value(struct intc_desc *desc,
289} 361}
290 362
291static unsigned int __init intc_mask_data(struct intc_desc *desc, 363static unsigned int __init intc_mask_data(struct intc_desc *desc,
364 struct intc_desc_int *d,
292 intc_enum enum_id, int do_grps) 365 intc_enum enum_id, int do_grps)
293{ 366{
294 struct intc_mask_reg *mr = desc->mask_regs; 367 struct intc_mask_reg *mr = desc->mask_regs;
295 unsigned int i, j, fn; 368 unsigned int i, j, fn, mode;
369 unsigned long reg_e, reg_d;
296 370
297 for (i = 0; mr && enum_id && i < desc->nr_mask_regs; i++) { 371 for (i = 0; mr && enum_id && i < desc->nr_mask_regs; i++) {
298 mr = desc->mask_regs + i; 372 mr = desc->mask_regs + i;
@@ -301,25 +375,46 @@ static unsigned int __init intc_mask_data(struct intc_desc *desc,
301 if (mr->enum_ids[j] != enum_id) 375 if (mr->enum_ids[j] != enum_id)
302 continue; 376 continue;
303 377
304 fn = intc_find_mask_handler(mr->reg_width); 378 if (mr->set_reg && mr->clr_reg) {
305 if (fn == REG_FN_ERROR) 379 fn = REG_FN_WRITE_BASE;
306 return 0; 380 mode = MODE_DUAL_REG;
381 reg_e = mr->clr_reg;
382 reg_d = mr->set_reg;
383 } else {
384 fn = REG_FN_MODIFY_BASE;
385 if (mr->set_reg) {
386 mode = MODE_ENABLE_REG;
387 reg_e = mr->set_reg;
388 reg_d = mr->set_reg;
389 } else {
390 mode = MODE_MASK_REG;
391 reg_e = mr->clr_reg;
392 reg_d = mr->clr_reg;
393 }
394 }
307 395
308 return _INTC_MK(fn, i, (mr->reg_width - 1) - j, 0); 396 fn += (mr->reg_width >> 3) - 1;
397 return _INTC_MK(fn, mode,
398 intc_get_reg(d, reg_e),
399 intc_get_reg(d, reg_d),
400 1,
401 (mr->reg_width - 1) - j);
309 } 402 }
310 } 403 }
311 404
312 if (do_grps) 405 if (do_grps)
313 return intc_mask_data(desc, intc_grp_id(desc, enum_id), 0); 406 return intc_mask_data(desc, d, intc_grp_id(desc, enum_id), 0);
314 407
315 return 0; 408 return 0;
316} 409}
317 410
318static unsigned int __init intc_prio_data(struct intc_desc *desc, 411static unsigned int __init intc_prio_data(struct intc_desc *desc,
412 struct intc_desc_int *d,
319 intc_enum enum_id, int do_grps) 413 intc_enum enum_id, int do_grps)
320{ 414{
321 struct intc_prio_reg *pr = desc->prio_regs; 415 struct intc_prio_reg *pr = desc->prio_regs;
322 unsigned int i, j, fn, bit, prio; 416 unsigned int i, j, fn, mode, bit;
417 unsigned long reg_e, reg_d;
323 418
324 for (i = 0; pr && enum_id && i < desc->nr_prio_regs; i++) { 419 for (i = 0; pr && enum_id && i < desc->nr_prio_regs; i++) {
325 pr = desc->prio_regs + i; 420 pr = desc->prio_regs + i;
@@ -328,28 +423,72 @@ static unsigned int __init intc_prio_data(struct intc_desc *desc,
328 if (pr->enum_ids[j] != enum_id) 423 if (pr->enum_ids[j] != enum_id)
329 continue; 424 continue;
330 425
331 fn = intc_find_prio_handler(pr->reg_width); 426 if (pr->set_reg && pr->clr_reg) {
332 if (fn == REG_FN_ERROR) 427 fn = REG_FN_WRITE_BASE;
333 return 0; 428 mode = MODE_PCLR_REG;
429 reg_e = pr->set_reg;
430 reg_d = pr->clr_reg;
431 } else {
432 fn = REG_FN_MODIFY_BASE;
433 mode = MODE_PRIO_REG;
434 if (!pr->set_reg)
435 BUG();
436 reg_e = pr->set_reg;
437 reg_d = pr->set_reg;
438 }
334 439
335 prio = intc_prio_value(desc, enum_id, 1); 440 fn += (pr->reg_width >> 3) - 1;
336 bit = pr->reg_width - ((j + 1) * pr->field_width); 441 bit = pr->reg_width - ((j + 1) * pr->field_width);
337 442
338 BUG_ON(bit < 0); 443 BUG_ON(bit < 0);
339 444
340 return _INTC_MK(fn, i, bit, prio); 445 return _INTC_MK(fn, mode,
446 intc_get_reg(d, reg_e),
447 intc_get_reg(d, reg_d),
448 pr->field_width, bit);
341 } 449 }
342 } 450 }
343 451
344 if (do_grps) 452 if (do_grps)
345 return intc_prio_data(desc, intc_grp_id(desc, enum_id), 0); 453 return intc_prio_data(desc, d, intc_grp_id(desc, enum_id), 0);
346 454
347 return 0; 455 return 0;
348} 456}
349 457
350static void __init intc_register_irq(struct intc_desc *desc, intc_enum enum_id, 458static unsigned int __init intc_sense_data(struct intc_desc *desc,
459 struct intc_desc_int *d,
460 intc_enum enum_id)
461{
462 struct intc_sense_reg *sr = desc->sense_regs;
463 unsigned int i, j, fn, bit;
464
465 for (i = 0; sr && enum_id && i < desc->nr_sense_regs; i++) {
466 sr = desc->sense_regs + i;
467
468 for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) {
469 if (sr->enum_ids[j] != enum_id)
470 continue;
471
472 fn = REG_FN_MODIFY_BASE;
473 fn += (sr->reg_width >> 3) - 1;
474 bit = sr->reg_width - ((j + 1) * sr->field_width);
475
476 BUG_ON(bit < 0);
477
478 return _INTC_MK(fn, 0, intc_get_reg(d, sr->reg),
479 0, sr->field_width, bit);
480 }
481 }
482
483 return 0;
484}
485
486static void __init intc_register_irq(struct intc_desc *desc,
487 struct intc_desc_int *d,
488 intc_enum enum_id,
351 unsigned int irq) 489 unsigned int irq)
352{ 490{
491 struct intc_handle_int *hp;
353 unsigned int data[2], primary; 492 unsigned int data[2], primary;
354 493
355 /* Prefer single interrupt source bitmap over other combinations: 494 /* Prefer single interrupt source bitmap over other combinations:
@@ -359,15 +498,15 @@ static void __init intc_register_irq(struct intc_desc *desc, intc_enum enum_id,
359 * 4. priority, multiple interrupt sources (groups) 498 * 4. priority, multiple interrupt sources (groups)
360 */ 499 */
361 500
362 data[0] = intc_mask_data(desc, enum_id, 0); 501 data[0] = intc_mask_data(desc, d, enum_id, 0);
363 data[1] = intc_prio_data(desc, enum_id, 0); 502 data[1] = intc_prio_data(desc, d, enum_id, 0);
364 503
365 primary = 0; 504 primary = 0;
366 if (!data[0] && data[1]) 505 if (!data[0] && data[1])
367 primary = 1; 506 primary = 1;
368 507
369 data[0] = data[0] ? data[0] : intc_mask_data(desc, enum_id, 1); 508 data[0] = data[0] ? data[0] : intc_mask_data(desc, d, enum_id, 1);
370 data[1] = data[1] ? data[1] : intc_prio_data(desc, enum_id, 1); 509 data[1] = data[1] ? data[1] : intc_prio_data(desc, d, enum_id, 1);
371 510
372 if (!data[primary]) 511 if (!data[primary])
373 primary ^= 1; 512 primary ^= 1;
@@ -375,31 +514,118 @@ static void __init intc_register_irq(struct intc_desc *desc, intc_enum enum_id,
375 BUG_ON(!data[primary]); /* must have primary masking method */ 514 BUG_ON(!data[primary]); /* must have primary masking method */
376 515
377 disable_irq_nosync(irq); 516 disable_irq_nosync(irq);
378 set_irq_chip_and_handler_name(irq, &desc->chip, 517 set_irq_chip_and_handler_name(irq, &d->chip,
379 handle_level_irq, "level"); 518 handle_level_irq, "level");
380 set_irq_chip_data(irq, (void *)data[primary]); 519 set_irq_chip_data(irq, (void *)data[primary]);
381 520
521 /* record the desired priority level */
522 intc_prio_level[irq] = intc_prio_value(desc, enum_id, 1);
523
382 /* enable secondary masking method if present */ 524 /* enable secondary masking method if present */
383 if (data[!primary]) 525 if (data[!primary])
384 intc_reg_fns[_INTC_FN(data[!primary])].enable(desc, 526 _intc_enable(irq, data[!primary]);
385 data[!primary]); 527
528 /* add irq to d->prio list if priority is available */
529 if (data[1]) {
530 hp = d->prio + d->nr_prio;
531 hp->irq = irq;
532 hp->handle = data[1];
533
534 if (primary) {
535 /*
536 * only secondary priority should access registers, so
537 * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority()
538 */
539
540 hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0);
541 hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0);
542 }
543 d->nr_prio++;
544 }
545
546 /* add irq to d->sense list if sense is available */
547 data[0] = intc_sense_data(desc, d, enum_id);
548 if (data[0]) {
549 (d->sense + d->nr_sense)->irq = irq;
550 (d->sense + d->nr_sense)->handle = data[0];
551 d->nr_sense++;
552 }
386 553
387 /* irq should be disabled by default */ 554 /* irq should be disabled by default */
388 desc->chip.mask(irq); 555 d->chip.mask(irq);
389} 556}
390 557
558static unsigned int __init save_reg(struct intc_desc_int *d,
559 unsigned int cnt,
560 unsigned long value,
561 unsigned int smp)
562{
563 if (value) {
564 d->reg[cnt] = value;
565#ifdef CONFIG_SMP
566 d->smp[cnt] = smp;
567#endif
568 return 1;
569 }
570
571 return 0;
572}
573
574
391void __init register_intc_controller(struct intc_desc *desc) 575void __init register_intc_controller(struct intc_desc *desc)
392{ 576{
393 unsigned int i; 577 unsigned int i, k, smp;
578 struct intc_desc_int *d;
579
580 d = alloc_bootmem(sizeof(*d));
581
582 d->nr_reg = desc->mask_regs ? desc->nr_mask_regs * 2 : 0;
583 d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0;
584 d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0;
585
586 d->reg = alloc_bootmem(d->nr_reg * sizeof(*d->reg));
587#ifdef CONFIG_SMP
588 d->smp = alloc_bootmem(d->nr_reg * sizeof(*d->smp));
589#endif
590 k = 0;
591
592 if (desc->mask_regs) {
593 for (i = 0; i < desc->nr_mask_regs; i++) {
594 smp = IS_SMP(desc->mask_regs[i]);
595 k += save_reg(d, k, desc->mask_regs[i].set_reg, smp);
596 k += save_reg(d, k, desc->mask_regs[i].clr_reg, smp);
597 }
598 }
599
600 if (desc->prio_regs) {
601 d->prio = alloc_bootmem(desc->nr_vectors * sizeof(*d->prio));
602
603 for (i = 0; i < desc->nr_prio_regs; i++) {
604 smp = IS_SMP(desc->prio_regs[i]);
605 k += save_reg(d, k, desc->prio_regs[i].set_reg, smp);
606 k += save_reg(d, k, desc->prio_regs[i].clr_reg, smp);
607 }
608 }
609
610 if (desc->sense_regs) {
611 d->sense = alloc_bootmem(desc->nr_vectors * sizeof(*d->sense));
612
613 for (i = 0; i < desc->nr_sense_regs; i++) {
614 k += save_reg(d, k, desc->sense_regs[i].reg, 0);
615 }
616 }
617
618 BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
394 619
395 desc->chip.mask = intc_disable; 620 d->chip.name = desc->name;
396 desc->chip.unmask = intc_enable; 621 d->chip.mask = intc_disable;
397 desc->chip.mask_ack = intc_disable; 622 d->chip.unmask = intc_enable;
398 desc->chip.set_type = intc_set_sense; 623 d->chip.mask_ack = intc_disable;
624 d->chip.set_type = intc_set_sense;
399 625
400 for (i = 0; i < desc->nr_vectors; i++) { 626 for (i = 0; i < desc->nr_vectors; i++) {
401 struct intc_vect *vect = desc->vectors + i; 627 struct intc_vect *vect = desc->vectors + i;
402 628
403 intc_register_irq(desc, vect->enum_id, evt2irq(vect->vect)); 629 intc_register_irq(desc, d, vect->enum_id, evt2irq(vect->vect));
404 } 630 }
405} 631}