diff options
author | Magnus Damm <damm@igel.co.jp> | 2007-08-16 11:50:44 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2007-09-20 22:57:50 -0400 |
commit | 3d37d94e5aab669f5a492bb3cda67bbbbbca50b8 (patch) | |
tree | 7066d6e40e2da4b9fdc9b169909ae65d88068df1 /arch/sh/kernel/cpu/irq | |
parent | 5c37e025352b993d8726b0207ff2270b2f2bc7d6 (diff) |
sh: intc - primary priority masking fixes
This patch contains various intc fixes for problems reported by
Markus Brunner on the linuxsh-dev mailing list:
http://marc.info/?l=linuxsh-dev&m=118701948224991&w=1
Apart from added comments, the fixes are:
- add intc_set_priority() function prototype to hw_irq.h
- fix off-by-one error in intc_set_priority()
- make sure _INTC_WIDTH() is set for primary priority masking
Big thanks to Markus for finding these problems. Version two fixes
a compile error and an inverted primary check.
Signed-off-by: Magnus Damm <damm@igel.co.jp>
Acked-by: Markus Brunner <super.firetwister@gmail.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel/cpu/irq')
-rw-r--r-- | arch/sh/kernel/cpu/irq/intc.c | 33 |
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 | ||