diff options
| -rw-r--r-- | include/linux/irqreturn.h | 6 | ||||
| -rw-r--r-- | kernel/irq/handle.c | 6 | ||||
| -rw-r--r-- | kernel/irq/irqdesc.c | 14 | ||||
| -rw-r--r-- | kernel/irq/manage.c | 24 | ||||
| -rw-r--r-- | kernel/irq/spurious.c | 31 |
5 files changed, 53 insertions, 28 deletions
diff --git a/include/linux/irqreturn.h b/include/linux/irqreturn.h index 819acaaac3f5..714ba08dc092 100644 --- a/include/linux/irqreturn.h +++ b/include/linux/irqreturn.h | |||
| @@ -8,9 +8,9 @@ | |||
| 8 | * @IRQ_WAKE_THREAD handler requests to wake the handler thread | 8 | * @IRQ_WAKE_THREAD handler requests to wake the handler thread |
| 9 | */ | 9 | */ |
| 10 | enum irqreturn { | 10 | enum irqreturn { |
| 11 | IRQ_NONE, | 11 | IRQ_NONE = (0 << 0), |
| 12 | IRQ_HANDLED, | 12 | IRQ_HANDLED = (1 << 0), |
| 13 | IRQ_WAKE_THREAD, | 13 | IRQ_WAKE_THREAD = (1 << 1), |
| 14 | }; | 14 | }; |
| 15 | 15 | ||
| 16 | typedef enum irqreturn irqreturn_t; | 16 | typedef enum irqreturn irqreturn_t; |
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 90cb55f6d7eb..470d08c82bbe 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c | |||
| @@ -133,12 +133,6 @@ handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action) | |||
| 133 | switch (res) { | 133 | switch (res) { |
| 134 | case IRQ_WAKE_THREAD: | 134 | case IRQ_WAKE_THREAD: |
| 135 | /* | 135 | /* |
| 136 | * Set result to handled so the spurious check | ||
| 137 | * does not trigger. | ||
| 138 | */ | ||
| 139 | res = IRQ_HANDLED; | ||
| 140 | |||
| 141 | /* | ||
| 142 | * Catch drivers which return WAKE_THREAD but | 136 | * Catch drivers which return WAKE_THREAD but |
| 143 | * did not set up a thread function | 137 | * did not set up a thread function |
| 144 | */ | 138 | */ |
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index 886e80347b32..4c60a50e66b2 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c | |||
| @@ -257,13 +257,11 @@ int __init early_irq_init(void) | |||
| 257 | count = ARRAY_SIZE(irq_desc); | 257 | count = ARRAY_SIZE(irq_desc); |
| 258 | 258 | ||
| 259 | for (i = 0; i < count; i++) { | 259 | for (i = 0; i < count; i++) { |
| 260 | desc[i].irq_data.irq = i; | ||
| 261 | desc[i].irq_data.chip = &no_irq_chip; | ||
| 262 | desc[i].kstat_irqs = alloc_percpu(unsigned int); | 260 | desc[i].kstat_irqs = alloc_percpu(unsigned int); |
| 263 | irq_settings_clr_and_set(desc, ~0, _IRQ_DEFAULT_INIT_FLAGS); | 261 | alloc_masks(&desc[i], GFP_KERNEL, node); |
| 264 | alloc_masks(desc + i, GFP_KERNEL, node); | 262 | raw_spin_lock_init(&desc[i].lock); |
| 265 | desc_smp_init(desc + i, node); | ||
| 266 | lockdep_set_class(&desc[i].lock, &irq_desc_lock_class); | 263 | lockdep_set_class(&desc[i].lock, &irq_desc_lock_class); |
| 264 | desc_set_defaults(i, &desc[i], node); | ||
| 267 | } | 265 | } |
| 268 | return arch_early_irq_init(); | 266 | return arch_early_irq_init(); |
| 269 | } | 267 | } |
| @@ -346,6 +344,12 @@ irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node) | |||
| 346 | if (!cnt) | 344 | if (!cnt) |
| 347 | return -EINVAL; | 345 | return -EINVAL; |
| 348 | 346 | ||
| 347 | if (irq >= 0) { | ||
| 348 | if (from > irq) | ||
| 349 | return -EINVAL; | ||
| 350 | from = irq; | ||
| 351 | } | ||
| 352 | |||
| 349 | mutex_lock(&sparse_irq_lock); | 353 | mutex_lock(&sparse_irq_lock); |
| 350 | 354 | ||
| 351 | start = bitmap_find_next_zero_area(allocated_irqs, IRQ_BITMAP_BITS, | 355 | start = bitmap_find_next_zero_area(allocated_irqs, IRQ_BITMAP_BITS, |
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index f7ce0021e1c4..d64bafb1afd0 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
| @@ -723,13 +723,16 @@ irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action) { } | |||
| 723 | * context. So we need to disable bh here to avoid deadlocks and other | 723 | * context. So we need to disable bh here to avoid deadlocks and other |
| 724 | * side effects. | 724 | * side effects. |
| 725 | */ | 725 | */ |
| 726 | static void | 726 | static irqreturn_t |
| 727 | irq_forced_thread_fn(struct irq_desc *desc, struct irqaction *action) | 727 | irq_forced_thread_fn(struct irq_desc *desc, struct irqaction *action) |
| 728 | { | 728 | { |
| 729 | irqreturn_t ret; | ||
| 730 | |||
| 729 | local_bh_disable(); | 731 | local_bh_disable(); |
| 730 | action->thread_fn(action->irq, action->dev_id); | 732 | ret = action->thread_fn(action->irq, action->dev_id); |
| 731 | irq_finalize_oneshot(desc, action, false); | 733 | irq_finalize_oneshot(desc, action, false); |
| 732 | local_bh_enable(); | 734 | local_bh_enable(); |
| 735 | return ret; | ||
| 733 | } | 736 | } |
| 734 | 737 | ||
| 735 | /* | 738 | /* |
| @@ -737,10 +740,14 @@ irq_forced_thread_fn(struct irq_desc *desc, struct irqaction *action) | |||
| 737 | * preemtible - many of them need to sleep and wait for slow busses to | 740 | * preemtible - many of them need to sleep and wait for slow busses to |
| 738 | * complete. | 741 | * complete. |
| 739 | */ | 742 | */ |
| 740 | static void irq_thread_fn(struct irq_desc *desc, struct irqaction *action) | 743 | static irqreturn_t irq_thread_fn(struct irq_desc *desc, |
| 744 | struct irqaction *action) | ||
| 741 | { | 745 | { |
| 742 | action->thread_fn(action->irq, action->dev_id); | 746 | irqreturn_t ret; |
| 747 | |||
| 748 | ret = action->thread_fn(action->irq, action->dev_id); | ||
| 743 | irq_finalize_oneshot(desc, action, false); | 749 | irq_finalize_oneshot(desc, action, false); |
| 750 | return ret; | ||
| 744 | } | 751 | } |
| 745 | 752 | ||
| 746 | /* | 753 | /* |
| @@ -753,7 +760,8 @@ static int irq_thread(void *data) | |||
| 753 | }; | 760 | }; |
| 754 | struct irqaction *action = data; | 761 | struct irqaction *action = data; |
| 755 | struct irq_desc *desc = irq_to_desc(action->irq); | 762 | struct irq_desc *desc = irq_to_desc(action->irq); |
| 756 | void (*handler_fn)(struct irq_desc *desc, struct irqaction *action); | 763 | irqreturn_t (*handler_fn)(struct irq_desc *desc, |
| 764 | struct irqaction *action); | ||
| 757 | int wake; | 765 | int wake; |
| 758 | 766 | ||
| 759 | if (force_irqthreads & test_bit(IRQTF_FORCED_THREAD, | 767 | if (force_irqthreads & test_bit(IRQTF_FORCED_THREAD, |
| @@ -783,8 +791,12 @@ static int irq_thread(void *data) | |||
| 783 | desc->istate |= IRQS_PENDING; | 791 | desc->istate |= IRQS_PENDING; |
| 784 | raw_spin_unlock_irq(&desc->lock); | 792 | raw_spin_unlock_irq(&desc->lock); |
| 785 | } else { | 793 | } else { |
| 794 | irqreturn_t action_ret; | ||
| 795 | |||
| 786 | raw_spin_unlock_irq(&desc->lock); | 796 | raw_spin_unlock_irq(&desc->lock); |
| 787 | handler_fn(desc, action); | 797 | action_ret = handler_fn(desc, action); |
| 798 | if (!noirqdebug) | ||
| 799 | note_interrupt(action->irq, desc, action_ret); | ||
| 788 | } | 800 | } |
| 789 | 801 | ||
| 790 | wake = atomic_dec_and_test(&desc->threads_active); | 802 | wake = atomic_dec_and_test(&desc->threads_active); |
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c index dfbd550401b2..aa57d5da18c1 100644 --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c | |||
| @@ -167,6 +167,13 @@ out: | |||
| 167 | jiffies + POLL_SPURIOUS_IRQ_INTERVAL); | 167 | jiffies + POLL_SPURIOUS_IRQ_INTERVAL); |
| 168 | } | 168 | } |
| 169 | 169 | ||
| 170 | static inline int bad_action_ret(irqreturn_t action_ret) | ||
| 171 | { | ||
| 172 | if (likely(action_ret <= (IRQ_HANDLED | IRQ_WAKE_THREAD))) | ||
| 173 | return 0; | ||
| 174 | return 1; | ||
| 175 | } | ||
| 176 | |||
| 170 | /* | 177 | /* |
| 171 | * If 99,900 of the previous 100,000 interrupts have not been handled | 178 | * If 99,900 of the previous 100,000 interrupts have not been handled |
| 172 | * then assume that the IRQ is stuck in some manner. Drop a diagnostic | 179 | * then assume that the IRQ is stuck in some manner. Drop a diagnostic |
| @@ -182,7 +189,7 @@ __report_bad_irq(unsigned int irq, struct irq_desc *desc, | |||
| 182 | struct irqaction *action; | 189 | struct irqaction *action; |
| 183 | unsigned long flags; | 190 | unsigned long flags; |
| 184 | 191 | ||
| 185 | if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) { | 192 | if (bad_action_ret(action_ret)) { |
| 186 | printk(KERN_ERR "irq event %d: bogus return value %x\n", | 193 | printk(KERN_ERR "irq event %d: bogus return value %x\n", |
| 187 | irq, action_ret); | 194 | irq, action_ret); |
| 188 | } else { | 195 | } else { |
| @@ -201,10 +208,11 @@ __report_bad_irq(unsigned int irq, struct irq_desc *desc, | |||
| 201 | raw_spin_lock_irqsave(&desc->lock, flags); | 208 | raw_spin_lock_irqsave(&desc->lock, flags); |
| 202 | action = desc->action; | 209 | action = desc->action; |
| 203 | while (action) { | 210 | while (action) { |
| 204 | printk(KERN_ERR "[<%p>]", action->handler); | 211 | printk(KERN_ERR "[<%p>] %pf", action->handler, action->handler); |
| 205 | print_symbol(" (%s)", | 212 | if (action->thread_fn) |
| 206 | (unsigned long)action->handler); | 213 | printk(KERN_CONT " threaded [<%p>] %pf", |
| 207 | printk("\n"); | 214 | action->thread_fn, action->thread_fn); |
| 215 | printk(KERN_CONT "\n"); | ||
| 208 | action = action->next; | 216 | action = action->next; |
| 209 | } | 217 | } |
| 210 | raw_spin_unlock_irqrestore(&desc->lock, flags); | 218 | raw_spin_unlock_irqrestore(&desc->lock, flags); |
| @@ -262,7 +270,16 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc, | |||
| 262 | if (desc->istate & IRQS_POLL_INPROGRESS) | 270 | if (desc->istate & IRQS_POLL_INPROGRESS) |
| 263 | return; | 271 | return; |
| 264 | 272 | ||
| 265 | if (unlikely(action_ret != IRQ_HANDLED)) { | 273 | /* we get here again via the threaded handler */ |
| 274 | if (action_ret == IRQ_WAKE_THREAD) | ||
| 275 | return; | ||
| 276 | |||
| 277 | if (bad_action_ret(action_ret)) { | ||
| 278 | report_bad_irq(irq, desc, action_ret); | ||
| 279 | return; | ||
| 280 | } | ||
| 281 | |||
| 282 | if (unlikely(action_ret == IRQ_NONE)) { | ||
| 266 | /* | 283 | /* |
| 267 | * If we are seeing only the odd spurious IRQ caused by | 284 | * If we are seeing only the odd spurious IRQ caused by |
| 268 | * bus asynchronicity then don't eventually trigger an error, | 285 | * bus asynchronicity then don't eventually trigger an error, |
| @@ -274,8 +291,6 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc, | |||
| 274 | else | 291 | else |
| 275 | desc->irqs_unhandled++; | 292 | desc->irqs_unhandled++; |
| 276 | desc->last_unhandled = jiffies; | 293 | desc->last_unhandled = jiffies; |
| 277 | if (unlikely(action_ret != IRQ_NONE)) | ||
| 278 | report_bad_irq(irq, desc, action_ret); | ||
| 279 | } | 294 | } |
| 280 | 295 | ||
| 281 | if (unlikely(try_misrouted_irq(irq, desc, action_ret))) { | 296 | if (unlikely(try_misrouted_irq(irq, desc, action_ret))) { |
