diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2012-03-13 11:34:48 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2012-03-13 11:35:16 -0400 |
commit | df8d291f28aa1e8437c8f7816328a6516379c71b (patch) | |
tree | 26ae585aa259584ddd0d9088933547c065c37086 /kernel/irq | |
parent | 5234ffb9f74cfa8993d174782bc861dd9b7b5bfb (diff) | |
parent | fde7d9049e55ab85a390be7f415d74c9f62dd0f9 (diff) |
Merge branch 'linus' into irq/core
Reason: Get upstream fixes integrated before further modifications.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/irq')
-rw-r--r-- | kernel/irq/autoprobe.c | 4 | ||||
-rw-r--r-- | kernel/irq/chip.c | 42 | ||||
-rw-r--r-- | kernel/irq/internals.h | 2 | ||||
-rw-r--r-- | kernel/irq/manage.c | 46 |
4 files changed, 75 insertions, 19 deletions
diff --git a/kernel/irq/autoprobe.c b/kernel/irq/autoprobe.c index 342d8f44e401..0119b9d467ae 100644 --- a/kernel/irq/autoprobe.c +++ b/kernel/irq/autoprobe.c | |||
@@ -53,7 +53,7 @@ unsigned long probe_irq_on(void) | |||
53 | if (desc->irq_data.chip->irq_set_type) | 53 | if (desc->irq_data.chip->irq_set_type) |
54 | desc->irq_data.chip->irq_set_type(&desc->irq_data, | 54 | desc->irq_data.chip->irq_set_type(&desc->irq_data, |
55 | IRQ_TYPE_PROBE); | 55 | IRQ_TYPE_PROBE); |
56 | irq_startup(desc); | 56 | irq_startup(desc, false); |
57 | } | 57 | } |
58 | raw_spin_unlock_irq(&desc->lock); | 58 | raw_spin_unlock_irq(&desc->lock); |
59 | } | 59 | } |
@@ -70,7 +70,7 @@ unsigned long probe_irq_on(void) | |||
70 | raw_spin_lock_irq(&desc->lock); | 70 | raw_spin_lock_irq(&desc->lock); |
71 | if (!desc->action && irq_settings_can_probe(desc)) { | 71 | if (!desc->action && irq_settings_can_probe(desc)) { |
72 | desc->istate |= IRQS_AUTODETECT | IRQS_WAITING; | 72 | desc->istate |= IRQS_AUTODETECT | IRQS_WAITING; |
73 | if (irq_startup(desc)) | 73 | if (irq_startup(desc, false)) |
74 | desc->istate |= IRQS_PENDING; | 74 | desc->istate |= IRQS_PENDING; |
75 | } | 75 | } |
76 | raw_spin_unlock_irq(&desc->lock); | 76 | raw_spin_unlock_irq(&desc->lock); |
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 4dbc9c9d641b..25784d630a12 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c | |||
@@ -156,19 +156,22 @@ static void irq_state_set_masked(struct irq_desc *desc) | |||
156 | irqd_set(&desc->irq_data, IRQD_IRQ_MASKED); | 156 | irqd_set(&desc->irq_data, IRQD_IRQ_MASKED); |
157 | } | 157 | } |
158 | 158 | ||
159 | int irq_startup(struct irq_desc *desc) | 159 | int irq_startup(struct irq_desc *desc, bool resend) |
160 | { | 160 | { |
161 | int ret = 0; | ||
162 | |||
161 | irq_state_clr_disabled(desc); | 163 | irq_state_clr_disabled(desc); |
162 | desc->depth = 0; | 164 | desc->depth = 0; |
163 | 165 | ||
164 | if (desc->irq_data.chip->irq_startup) { | 166 | if (desc->irq_data.chip->irq_startup) { |
165 | int ret = desc->irq_data.chip->irq_startup(&desc->irq_data); | 167 | ret = desc->irq_data.chip->irq_startup(&desc->irq_data); |
166 | irq_state_clr_masked(desc); | 168 | irq_state_clr_masked(desc); |
167 | return ret; | 169 | } else { |
170 | irq_enable(desc); | ||
168 | } | 171 | } |
169 | 172 | if (resend) | |
170 | irq_enable(desc); | 173 | check_irq_resend(desc, desc->irq_data.irq); |
171 | return 0; | 174 | return ret; |
172 | } | 175 | } |
173 | 176 | ||
174 | void irq_shutdown(struct irq_desc *desc) | 177 | void irq_shutdown(struct irq_desc *desc) |
@@ -329,6 +332,24 @@ out_unlock: | |||
329 | } | 332 | } |
330 | EXPORT_SYMBOL_GPL(handle_simple_irq); | 333 | EXPORT_SYMBOL_GPL(handle_simple_irq); |
331 | 334 | ||
335 | /* | ||
336 | * Called unconditionally from handle_level_irq() and only for oneshot | ||
337 | * interrupts from handle_fasteoi_irq() | ||
338 | */ | ||
339 | static void cond_unmask_irq(struct irq_desc *desc) | ||
340 | { | ||
341 | /* | ||
342 | * We need to unmask in the following cases: | ||
343 | * - Standard level irq (IRQF_ONESHOT is not set) | ||
344 | * - Oneshot irq which did not wake the thread (caused by a | ||
345 | * spurious interrupt or a primary handler handling it | ||
346 | * completely). | ||
347 | */ | ||
348 | if (!irqd_irq_disabled(&desc->irq_data) && | ||
349 | irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot) | ||
350 | unmask_irq(desc); | ||
351 | } | ||
352 | |||
332 | /** | 353 | /** |
333 | * handle_level_irq - Level type irq handler | 354 | * handle_level_irq - Level type irq handler |
334 | * @irq: the interrupt number | 355 | * @irq: the interrupt number |
@@ -361,8 +382,8 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc) | |||
361 | 382 | ||
362 | handle_irq_event(desc); | 383 | handle_irq_event(desc); |
363 | 384 | ||
364 | if (!irqd_irq_disabled(&desc->irq_data) && !(desc->istate & IRQS_ONESHOT)) | 385 | cond_unmask_irq(desc); |
365 | unmask_irq(desc); | 386 | |
366 | out_unlock: | 387 | out_unlock: |
367 | raw_spin_unlock(&desc->lock); | 388 | raw_spin_unlock(&desc->lock); |
368 | } | 389 | } |
@@ -416,6 +437,9 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) | |||
416 | preflow_handler(desc); | 437 | preflow_handler(desc); |
417 | handle_irq_event(desc); | 438 | handle_irq_event(desc); |
418 | 439 | ||
440 | if (desc->istate & IRQS_ONESHOT) | ||
441 | cond_unmask_irq(desc); | ||
442 | |||
419 | out_eoi: | 443 | out_eoi: |
420 | desc->irq_data.chip->irq_eoi(&desc->irq_data); | 444 | desc->irq_data.chip->irq_eoi(&desc->irq_data); |
421 | out_unlock: | 445 | out_unlock: |
@@ -624,7 +648,7 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, | |||
624 | irq_settings_set_noprobe(desc); | 648 | irq_settings_set_noprobe(desc); |
625 | irq_settings_set_norequest(desc); | 649 | irq_settings_set_norequest(desc); |
626 | irq_settings_set_nothread(desc); | 650 | irq_settings_set_nothread(desc); |
627 | irq_startup(desc); | 651 | irq_startup(desc, true); |
628 | } | 652 | } |
629 | out: | 653 | out: |
630 | irq_put_desc_busunlock(desc, flags); | 654 | irq_put_desc_busunlock(desc, flags); |
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 5c233e0ea2c3..8e5c56b3b7d9 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h | |||
@@ -65,7 +65,7 @@ extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, | |||
65 | extern void __disable_irq(struct irq_desc *desc, unsigned int irq, bool susp); | 65 | extern void __disable_irq(struct irq_desc *desc, unsigned int irq, bool susp); |
66 | extern void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume); | 66 | extern void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume); |
67 | 67 | ||
68 | extern int irq_startup(struct irq_desc *desc); | 68 | extern int irq_startup(struct irq_desc *desc, bool resend); |
69 | extern void irq_shutdown(struct irq_desc *desc); | 69 | extern void irq_shutdown(struct irq_desc *desc); |
70 | extern void irq_enable(struct irq_desc *desc); | 70 | extern void irq_enable(struct irq_desc *desc); |
71 | extern void irq_disable(struct irq_desc *desc); | 71 | extern void irq_disable(struct irq_desc *desc); |
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index a94466db73b2..1786cf7dac54 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
@@ -979,6 +979,11 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
979 | 979 | ||
980 | /* add new interrupt at end of irq queue */ | 980 | /* add new interrupt at end of irq queue */ |
981 | do { | 981 | do { |
982 | /* | ||
983 | * Or all existing action->thread_mask bits, | ||
984 | * so we can find the next zero bit for this | ||
985 | * new action. | ||
986 | */ | ||
982 | thread_mask |= old->thread_mask; | 987 | thread_mask |= old->thread_mask; |
983 | old_ptr = &old->next; | 988 | old_ptr = &old->next; |
984 | old = *old_ptr; | 989 | old = *old_ptr; |
@@ -987,14 +992,41 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
987 | } | 992 | } |
988 | 993 | ||
989 | /* | 994 | /* |
990 | * Setup the thread mask for this irqaction. Unlikely to have | 995 | * Setup the thread mask for this irqaction for ONESHOT. For |
991 | * 32 resp 64 irqs sharing one line, but who knows. | 996 | * !ONESHOT irqs the thread mask is 0 so we can avoid a |
997 | * conditional in irq_wake_thread(). | ||
992 | */ | 998 | */ |
993 | if (new->flags & IRQF_ONESHOT && thread_mask == ~0UL) { | 999 | if (new->flags & IRQF_ONESHOT) { |
994 | ret = -EBUSY; | 1000 | /* |
995 | goto out_mask; | 1001 | * Unlikely to have 32 resp 64 irqs sharing one line, |
1002 | * but who knows. | ||
1003 | */ | ||
1004 | if (thread_mask == ~0UL) { | ||
1005 | ret = -EBUSY; | ||
1006 | goto out_mask; | ||
1007 | } | ||
1008 | /* | ||
1009 | * The thread_mask for the action is or'ed to | ||
1010 | * desc->thread_active to indicate that the | ||
1011 | * IRQF_ONESHOT thread handler has been woken, but not | ||
1012 | * yet finished. The bit is cleared when a thread | ||
1013 | * completes. When all threads of a shared interrupt | ||
1014 | * line have completed desc->threads_active becomes | ||
1015 | * zero and the interrupt line is unmasked. See | ||
1016 | * handle.c:irq_wake_thread() for further information. | ||
1017 | * | ||
1018 | * If no thread is woken by primary (hard irq context) | ||
1019 | * interrupt handlers, then desc->threads_active is | ||
1020 | * also checked for zero to unmask the irq line in the | ||
1021 | * affected hard irq flow handlers | ||
1022 | * (handle_[fasteoi|level]_irq). | ||
1023 | * | ||
1024 | * The new action gets the first zero bit of | ||
1025 | * thread_mask assigned. See the loop above which or's | ||
1026 | * all existing action->thread_mask bits. | ||
1027 | */ | ||
1028 | new->thread_mask = 1 << ffz(thread_mask); | ||
996 | } | 1029 | } |
997 | new->thread_mask = 1 << ffz(thread_mask); | ||
998 | 1030 | ||
999 | if (!shared) { | 1031 | if (!shared) { |
1000 | init_waitqueue_head(&desc->wait_for_threads); | 1032 | init_waitqueue_head(&desc->wait_for_threads); |
@@ -1021,7 +1053,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
1021 | desc->istate |= IRQS_ONESHOT; | 1053 | desc->istate |= IRQS_ONESHOT; |
1022 | 1054 | ||
1023 | if (irq_settings_can_autoenable(desc)) | 1055 | if (irq_settings_can_autoenable(desc)) |
1024 | irq_startup(desc); | 1056 | irq_startup(desc, true); |
1025 | else | 1057 | else |
1026 | /* Undo nested disables: */ | 1058 | /* Undo nested disables: */ |
1027 | desc->depth = 1; | 1059 | desc->depth = 1; |