diff options
Diffstat (limited to 'arch/arm/common/vic.c')
-rw-r--r-- | arch/arm/common/vic.c | 70 |
1 files changed, 36 insertions, 34 deletions
diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c index 5feb004aaea6..49af6187885f 100644 --- a/arch/arm/common/vic.c +++ b/arch/arm/common/vic.c | |||
@@ -83,6 +83,8 @@ static struct vic_device vic_devices[CONFIG_ARM_VIC_NR]; | |||
83 | 83 | ||
84 | static int vic_id; | 84 | static int vic_id; |
85 | 85 | ||
86 | static void vic_handle_irq(struct pt_regs *regs); | ||
87 | |||
86 | /** | 88 | /** |
87 | * vic_init2 - common initialisation code | 89 | * vic_init2 - common initialisation code |
88 | * @base: Base of the VIC. | 90 | * @base: Base of the VIC. |
@@ -199,6 +201,40 @@ static int vic_irqdomain_map(struct irq_domain *d, unsigned int irq, | |||
199 | return 0; | 201 | return 0; |
200 | } | 202 | } |
201 | 203 | ||
204 | /* | ||
205 | * Handle each interrupt in a single VIC. Returns non-zero if we've | ||
206 | * handled at least one interrupt. This reads the status register | ||
207 | * before handling each interrupt, which is necessary given that | ||
208 | * handle_IRQ may briefly re-enable interrupts for soft IRQ handling. | ||
209 | */ | ||
210 | static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs) | ||
211 | { | ||
212 | u32 stat, irq; | ||
213 | int handled = 0; | ||
214 | |||
215 | while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) { | ||
216 | irq = ffs(stat) - 1; | ||
217 | handle_IRQ(irq_find_mapping(vic->domain, irq), regs); | ||
218 | handled = 1; | ||
219 | } | ||
220 | |||
221 | return handled; | ||
222 | } | ||
223 | |||
224 | /* | ||
225 | * Keep iterating over all registered VIC's until there are no pending | ||
226 | * interrupts. | ||
227 | */ | ||
228 | static asmlinkage void __exception_irq_entry vic_handle_irq(struct pt_regs *regs) | ||
229 | { | ||
230 | int i, handled; | ||
231 | |||
232 | do { | ||
233 | for (i = 0, handled = 0; i < vic_id; ++i) | ||
234 | handled |= handle_one_vic(&vic_devices[i], regs); | ||
235 | } while (handled); | ||
236 | } | ||
237 | |||
202 | static struct irq_domain_ops vic_irqdomain_ops = { | 238 | static struct irq_domain_ops vic_irqdomain_ops = { |
203 | .map = vic_irqdomain_map, | 239 | .map = vic_irqdomain_map, |
204 | .xlate = irq_domain_xlate_onetwocell, | 240 | .xlate = irq_domain_xlate_onetwocell, |
@@ -446,37 +482,3 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent) | |||
446 | return 0; | 482 | return 0; |
447 | } | 483 | } |
448 | #endif /* CONFIG OF */ | 484 | #endif /* CONFIG OF */ |
449 | |||
450 | /* | ||
451 | * Handle each interrupt in a single VIC. Returns non-zero if we've | ||
452 | * handled at least one interrupt. This reads the status register | ||
453 | * before handling each interrupt, which is necessary given that | ||
454 | * handle_IRQ may briefly re-enable interrupts for soft IRQ handling. | ||
455 | */ | ||
456 | static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs) | ||
457 | { | ||
458 | u32 stat, irq; | ||
459 | int handled = 0; | ||
460 | |||
461 | while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) { | ||
462 | irq = ffs(stat) - 1; | ||
463 | handle_IRQ(irq_find_mapping(vic->domain, irq), regs); | ||
464 | handled = 1; | ||
465 | } | ||
466 | |||
467 | return handled; | ||
468 | } | ||
469 | |||
470 | /* | ||
471 | * Keep iterating over all registered VIC's until there are no pending | ||
472 | * interrupts. | ||
473 | */ | ||
474 | asmlinkage void __exception_irq_entry vic_handle_irq(struct pt_regs *regs) | ||
475 | { | ||
476 | int i, handled; | ||
477 | |||
478 | do { | ||
479 | for (i = 0, handled = 0; i < vic_id; ++i) | ||
480 | handled |= handle_one_vic(&vic_devices[i], regs); | ||
481 | } while (handled); | ||
482 | } | ||