aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/cpu/irq
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/kernel/cpu/irq')
-rw-r--r--arch/sh/kernel/cpu/irq/intc.c33
1 files changed, 28 insertions, 5 deletions
diff --git a/arch/sh/kernel/cpu/irq/intc.c b/arch/sh/kernel/cpu/irq/intc.c
index d609a8ccd456..481871fee1a8 100644
--- a/arch/sh/kernel/cpu/irq/intc.c
+++ b/arch/sh/kernel/cpu/irq/intc.c
@@ -206,6 +206,18 @@ static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
206{ 206{
207 int i; 207 int i;
208 208
209 /* this doesn't scale well, but...
210 *
211 * this function should only be used for cerain uncommon
212 * operations such as intc_set_priority() and intc_set_sense()
213 * and in those rare cases performance doesn't matter that much.
214 * keeping the memory footprint low is more important.
215 *
216 * one rather simple way to speed this up and still keep the
217 * memory footprint down is to make sure the array is sorted
218 * and then perform a bisect to lookup the irq.
219 */
220
209 for (i = 0; i < nr_hp; i++) { 221 for (i = 0; i < nr_hp; i++) {
210 if ((hp + i)->irq != irq) 222 if ((hp + i)->irq != irq)
211 continue; 223 continue;
@@ -226,7 +238,7 @@ int intc_set_priority(unsigned int irq, unsigned int prio)
226 238
227 ihp = intc_find_irq(d->prio, d->nr_prio, irq); 239 ihp = intc_find_irq(d->prio, d->nr_prio, irq);
228 if (ihp) { 240 if (ihp) {
229 if (prio >= ((1 << _INTC_WIDTH(ihp->handle)) - 1)) 241 if (prio >= (1 << _INTC_WIDTH(ihp->handle)))
230 return -EINVAL; 242 return -EINVAL;
231 243
232 intc_prio_level[irq] = prio; 244 intc_prio_level[irq] = prio;
@@ -237,7 +249,7 @@ int intc_set_priority(unsigned int irq, unsigned int prio)
237 * priority level will be set during next enable() 249 * priority level will be set during next enable()
238 */ 250 */
239 251
240 if (ihp->handle) 252 if (_INTC_FN(ihp->handle) != REG_FN_ERR)
241 _intc_enable(irq, ihp->handle); 253 _intc_enable(irq, ihp->handle);
242 } 254 }
243 return 0; 255 return 0;
@@ -457,6 +469,7 @@ static void __init intc_register_irq(struct intc_desc *desc,
457 intc_enum enum_id, 469 intc_enum enum_id,
458 unsigned int irq) 470 unsigned int irq)
459{ 471{
472 struct intc_handle_int *hp;
460 unsigned int data[2], primary; 473 unsigned int data[2], primary;
461 474
462 /* Prefer single interrupt source bitmap over other combinations: 475 /* Prefer single interrupt source bitmap over other combinations:
@@ -495,9 +508,19 @@ static void __init intc_register_irq(struct intc_desc *desc,
495 508
496 /* add irq to d->prio list if priority is available */ 509 /* add irq to d->prio list if priority is available */
497 if (data[1]) { 510 if (data[1]) {
498 (d->prio + d->nr_prio)->irq = irq; 511 hp = d->prio + d->nr_prio;
499 if (!primary) /* only secondary priority can access regs */ 512 hp->irq = irq;
500 (d->prio + d->nr_prio)->handle = data[1]; 513 hp->handle = data[1];
514
515 if (primary) {
516 /*
517 * only secondary priority should access registers, so
518 * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority()
519 */
520
521 hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0);
522 hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0);
523 }
501 d->nr_prio++; 524 d->nr_prio++;
502 } 525 }
503 526