aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/cpu/irq/intc.c
diff options
context:
space:
mode:
authorMagnus Damm <damm@igel.co.jp>2007-07-19 23:09:29 -0400
committerPaul Mundt <lethal@linux-sh.org>2007-07-19 23:18:21 -0400
commit680c45981ae2b4029878806d76aa17bb62d3c674 (patch)
tree57d0f10573fb577d1330f15ac6177666fe3cfb25 /arch/sh/kernel/cpu/irq/intc.c
parentd0afa579698f33a65bc5c21d3d667dbb46f9e440 (diff)
sh: intc - improve group support
This patch improves intc group support, ie it makes it possible to group interrupts together and mask / unmask the entire group. This also works with priorities, so setting a priority for an entire group is also possible. This patch is needed to properly support certain processors such as the 7780. Fixes for NULL pointers in DECLARE_INTC_DESC() are also included. Signed-off-by: Magnus Damm <damm@igel.co.jp> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel/cpu/irq/intc.c')
-rw-r--r--arch/sh/kernel/cpu/irq/intc.c93
1 files changed, 73 insertions, 20 deletions
diff --git a/arch/sh/kernel/cpu/irq/intc.c b/arch/sh/kernel/cpu/irq/intc.c
index 626b4d8d7932..9345a7130e9e 100644
--- a/arch/sh/kernel/cpu/irq/intc.c
+++ b/arch/sh/kernel/cpu/irq/intc.c
@@ -244,13 +244,33 @@ static unsigned int __init intc_find_prio_handler(unsigned int width)
244 return REG_FN_ERROR; 244 return REG_FN_ERROR;
245} 245}
246 246
247static intc_enum __init intc_grp_id(struct intc_desc *desc, intc_enum enum_id)
248{
249 struct intc_group *g = desc->groups;
250 unsigned int i, j;
251
252 for (i = 0; g && enum_id && i < desc->nr_groups; i++) {
253 g = desc->groups + i;
254
255 for (j = 0; g->enum_ids[j]; j++) {
256 if (g->enum_ids[j] != enum_id)
257 continue;
258
259 return g->enum_id;
260 }
261 }
262
263 return 0;
264}
265
247static unsigned int __init intc_prio_value(struct intc_desc *desc, 266static unsigned int __init intc_prio_value(struct intc_desc *desc,
248 intc_enum enum_id) 267 intc_enum enum_id, int do_grps)
249{ 268{
269 struct intc_prio *p = desc->priorities;
250 unsigned int i; 270 unsigned int i;
251 271
252 for (i = 0; i < desc->nr_priorities; i++) { 272 for (i = 0; p && enum_id && i < desc->nr_priorities; i++) {
253 struct intc_prio *p = desc->priorities + i; 273 p = desc->priorities + i;
254 274
255 if (p->enum_id != enum_id) 275 if (p->enum_id != enum_id)
256 continue; 276 continue;
@@ -258,16 +278,24 @@ static unsigned int __init intc_prio_value(struct intc_desc *desc,
258 return p->priority; 278 return p->priority;
259 } 279 }
260 280
261 return 1; /* default to the lowest priority if no priority is set */ 281 if (do_grps)
282 return intc_prio_value(desc, intc_grp_id(desc, enum_id), 0);
283
284 /* default to the lowest priority possible if no priority is set
285 * - this needs to be at least 2 for 5-bit priorities on 7780
286 */
287
288 return 2;
262} 289}
263 290
264static unsigned int __init intc_mask_data(struct intc_desc *desc, 291static unsigned int __init intc_mask_data(struct intc_desc *desc,
265 intc_enum enum_id) 292 intc_enum enum_id, int do_grps)
266{ 293{
294 struct intc_mask_reg *mr = desc->mask_regs;
267 unsigned int i, j, fn; 295 unsigned int i, j, fn;
268 296
269 for (i = 0; i < desc->nr_mask_regs; i++) { 297 for (i = 0; mr && enum_id && i < desc->nr_mask_regs; i++) {
270 struct intc_mask_reg *mr = desc->mask_regs + i; 298 mr = desc->mask_regs + i;
271 299
272 for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) { 300 for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
273 if (mr->enum_ids[j] != enum_id) 301 if (mr->enum_ids[j] != enum_id)
@@ -281,16 +309,20 @@ static unsigned int __init intc_mask_data(struct intc_desc *desc,
281 } 309 }
282 } 310 }
283 311
312 if (do_grps)
313 return intc_mask_data(desc, intc_grp_id(desc, enum_id), 0);
314
284 return 0; 315 return 0;
285} 316}
286 317
287static unsigned int __init intc_prio_data(struct intc_desc *desc, 318static unsigned int __init intc_prio_data(struct intc_desc *desc,
288 intc_enum enum_id) 319 intc_enum enum_id, int do_grps)
289{ 320{
321 struct intc_prio_reg *pr = desc->prio_regs;
290 unsigned int i, j, fn, bit, prio; 322 unsigned int i, j, fn, bit, prio;
291 323
292 for (i = 0; i < desc->nr_prio_regs; i++) { 324 for (i = 0; pr && enum_id && i < desc->nr_prio_regs; i++) {
293 struct intc_prio_reg *pr = desc->prio_regs + i; 325 pr = desc->prio_regs + i;
294 326
295 for (j = 0; j < ARRAY_SIZE(pr->enum_ids); j++) { 327 for (j = 0; j < ARRAY_SIZE(pr->enum_ids); j++) {
296 if (pr->enum_ids[j] != enum_id) 328 if (pr->enum_ids[j] != enum_id)
@@ -300,7 +332,7 @@ static unsigned int __init intc_prio_data(struct intc_desc *desc,
300 if (fn == REG_FN_ERROR) 332 if (fn == REG_FN_ERROR)
301 return 0; 333 return 0;
302 334
303 prio = intc_prio_value(desc, enum_id); 335 prio = intc_prio_value(desc, enum_id, 1);
304 bit = pr->reg_width - ((j + 1) * pr->field_width); 336 bit = pr->reg_width - ((j + 1) * pr->field_width);
305 337
306 BUG_ON(bit < 0); 338 BUG_ON(bit < 0);
@@ -309,27 +341,48 @@ static unsigned int __init intc_prio_data(struct intc_desc *desc,
309 } 341 }
310 } 342 }
311 343
344 if (do_grps)
345 return intc_prio_data(desc, intc_grp_id(desc, enum_id), 0);
346
312 return 0; 347 return 0;
313} 348}
314 349
315static void __init intc_register_irq(struct intc_desc *desc, intc_enum enum_id, 350static void __init intc_register_irq(struct intc_desc *desc, intc_enum enum_id,
316 unsigned int irq) 351 unsigned int irq)
317{ 352{
318 unsigned int mask_data = intc_mask_data(desc, enum_id); 353 unsigned int data[2], primary;
319 unsigned int prio_data = intc_prio_data(desc, enum_id); 354
320 unsigned int data = mask_data ? mask_data : prio_data; 355 /* Prefer single interrupt source bitmap over other combinations:
356 * 1. bitmap, single interrupt source
357 * 2. priority, single interrupt source
358 * 3. bitmap, multiple interrupt sources (groups)
359 * 4. priority, multiple interrupt sources (groups)
360 */
321 361
322 BUG_ON(!data); 362 data[0] = intc_mask_data(desc, enum_id, 0);
363 data[1] = intc_prio_data(desc, enum_id, 0);
364
365 primary = 0;
366 if (!data[0] && data[1])
367 primary = 1;
368
369 data[0] = data[0] ? data[0] : intc_mask_data(desc, enum_id, 1);
370 data[1] = data[1] ? data[1] : intc_prio_data(desc, enum_id, 1);
371
372 if (!data[primary])
373 primary ^= 1;
374
375 BUG_ON(!data[primary]); /* must have primary masking method */
323 376
324 disable_irq_nosync(irq); 377 disable_irq_nosync(irq);
325 set_irq_chip_and_handler_name(irq, &desc->chip, 378 set_irq_chip_and_handler_name(irq, &desc->chip,
326 handle_level_irq, "level"); 379 handle_level_irq, "level");
327 set_irq_chip_data(irq, (void *)data); 380 set_irq_chip_data(irq, (void *)data[primary]);
328
329 /* set priority */
330 381
331 if (prio_data) 382 /* enable secondary masking method if present */
332 intc_reg_fns[_INTC_FN(prio_data)].enable(desc, prio_data); 383 if (data[!primary])
384 intc_reg_fns[_INTC_FN(data[!primary])].enable(desc,
385 data[!primary]);
333 386
334 /* irq should be disabled by default */ 387 /* irq should be disabled by default */
335 desc->chip.mask(irq); 388 desc->chip.mask(irq);