diff options
Diffstat (limited to 'kernel/irq')
| -rw-r--r-- | kernel/irq/chip.c | 89 | ||||
| -rw-r--r-- | kernel/irq/devres.c | 4 | ||||
| -rw-r--r-- | kernel/irq/handle.c | 58 | ||||
| -rw-r--r-- | kernel/irq/internals.h | 6 | ||||
| -rw-r--r-- | kernel/irq/manage.c | 32 | ||||
| -rw-r--r-- | kernel/irq/numa_migrate.c | 5 | ||||
| -rw-r--r-- | kernel/irq/proc.c | 1 |
7 files changed, 135 insertions, 60 deletions
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index ecc3fa28f666..b7091d5ca2f8 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c | |||
| @@ -18,11 +18,7 @@ | |||
| 18 | 18 | ||
| 19 | #include "internals.h" | 19 | #include "internals.h" |
| 20 | 20 | ||
| 21 | /** | 21 | static void dynamic_irq_init_x(unsigned int irq, bool keep_chip_data) |
| 22 | * dynamic_irq_init - initialize a dynamically allocated irq | ||
| 23 | * @irq: irq number to initialize | ||
| 24 | */ | ||
| 25 | void dynamic_irq_init(unsigned int irq) | ||
| 26 | { | 22 | { |
| 27 | struct irq_desc *desc; | 23 | struct irq_desc *desc; |
| 28 | unsigned long flags; | 24 | unsigned long flags; |
| @@ -41,7 +37,8 @@ void dynamic_irq_init(unsigned int irq) | |||
| 41 | desc->depth = 1; | 37 | desc->depth = 1; |
| 42 | desc->msi_desc = NULL; | 38 | desc->msi_desc = NULL; |
| 43 | desc->handler_data = NULL; | 39 | desc->handler_data = NULL; |
| 44 | desc->chip_data = NULL; | 40 | if (!keep_chip_data) |
| 41 | desc->chip_data = NULL; | ||
| 45 | desc->action = NULL; | 42 | desc->action = NULL; |
| 46 | desc->irq_count = 0; | 43 | desc->irq_count = 0; |
| 47 | desc->irqs_unhandled = 0; | 44 | desc->irqs_unhandled = 0; |
| @@ -55,10 +52,26 @@ void dynamic_irq_init(unsigned int irq) | |||
| 55 | } | 52 | } |
| 56 | 53 | ||
| 57 | /** | 54 | /** |
| 58 | * dynamic_irq_cleanup - cleanup a dynamically allocated irq | 55 | * dynamic_irq_init - initialize a dynamically allocated irq |
| 59 | * @irq: irq number to initialize | 56 | * @irq: irq number to initialize |
| 60 | */ | 57 | */ |
| 61 | void dynamic_irq_cleanup(unsigned int irq) | 58 | void dynamic_irq_init(unsigned int irq) |
| 59 | { | ||
| 60 | dynamic_irq_init_x(irq, false); | ||
| 61 | } | ||
| 62 | |||
| 63 | /** | ||
| 64 | * dynamic_irq_init_keep_chip_data - initialize a dynamically allocated irq | ||
| 65 | * @irq: irq number to initialize | ||
| 66 | * | ||
| 67 | * does not set irq_to_desc(irq)->chip_data to NULL | ||
| 68 | */ | ||
| 69 | void dynamic_irq_init_keep_chip_data(unsigned int irq) | ||
| 70 | { | ||
| 71 | dynamic_irq_init_x(irq, true); | ||
| 72 | } | ||
| 73 | |||
| 74 | static void dynamic_irq_cleanup_x(unsigned int irq, bool keep_chip_data) | ||
| 62 | { | 75 | { |
| 63 | struct irq_desc *desc = irq_to_desc(irq); | 76 | struct irq_desc *desc = irq_to_desc(irq); |
| 64 | unsigned long flags; | 77 | unsigned long flags; |
| @@ -77,7 +90,8 @@ void dynamic_irq_cleanup(unsigned int irq) | |||
| 77 | } | 90 | } |
| 78 | desc->msi_desc = NULL; | 91 | desc->msi_desc = NULL; |
| 79 | desc->handler_data = NULL; | 92 | desc->handler_data = NULL; |
| 80 | desc->chip_data = NULL; | 93 | if (!keep_chip_data) |
| 94 | desc->chip_data = NULL; | ||
| 81 | desc->handle_irq = handle_bad_irq; | 95 | desc->handle_irq = handle_bad_irq; |
| 82 | desc->chip = &no_irq_chip; | 96 | desc->chip = &no_irq_chip; |
| 83 | desc->name = NULL; | 97 | desc->name = NULL; |
| @@ -85,6 +99,26 @@ void dynamic_irq_cleanup(unsigned int irq) | |||
| 85 | raw_spin_unlock_irqrestore(&desc->lock, flags); | 99 | raw_spin_unlock_irqrestore(&desc->lock, flags); |
| 86 | } | 100 | } |
| 87 | 101 | ||
| 102 | /** | ||
| 103 | * dynamic_irq_cleanup - cleanup a dynamically allocated irq | ||
| 104 | * @irq: irq number to initialize | ||
| 105 | */ | ||
| 106 | void dynamic_irq_cleanup(unsigned int irq) | ||
| 107 | { | ||
| 108 | dynamic_irq_cleanup_x(irq, false); | ||
| 109 | } | ||
| 110 | |||
| 111 | /** | ||
| 112 | * dynamic_irq_cleanup_keep_chip_data - cleanup a dynamically allocated irq | ||
| 113 | * @irq: irq number to initialize | ||
| 114 | * | ||
| 115 | * does not set irq_to_desc(irq)->chip_data to NULL | ||
| 116 | */ | ||
| 117 | void dynamic_irq_cleanup_keep_chip_data(unsigned int irq) | ||
| 118 | { | ||
| 119 | dynamic_irq_cleanup_x(irq, true); | ||
| 120 | } | ||
| 121 | |||
| 88 | 122 | ||
| 89 | /** | 123 | /** |
| 90 | * set_irq_chip - set the irq chip for an irq | 124 | * set_irq_chip - set the irq chip for an irq |
| @@ -325,6 +359,23 @@ static inline void mask_ack_irq(struct irq_desc *desc, int irq) | |||
| 325 | if (desc->chip->ack) | 359 | if (desc->chip->ack) |
| 326 | desc->chip->ack(irq); | 360 | desc->chip->ack(irq); |
| 327 | } | 361 | } |
| 362 | desc->status |= IRQ_MASKED; | ||
| 363 | } | ||
| 364 | |||
| 365 | static inline void mask_irq(struct irq_desc *desc, int irq) | ||
| 366 | { | ||
| 367 | if (desc->chip->mask) { | ||
| 368 | desc->chip->mask(irq); | ||
| 369 | desc->status |= IRQ_MASKED; | ||
| 370 | } | ||
| 371 | } | ||
| 372 | |||
| 373 | static inline void unmask_irq(struct irq_desc *desc, int irq) | ||
| 374 | { | ||
| 375 | if (desc->chip->unmask) { | ||
| 376 | desc->chip->unmask(irq); | ||
| 377 | desc->status &= ~IRQ_MASKED; | ||
| 378 | } | ||
| 328 | } | 379 | } |
| 329 | 380 | ||
| 330 | /* | 381 | /* |
| @@ -450,10 +501,8 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc) | |||
| 450 | raw_spin_lock(&desc->lock); | 501 | raw_spin_lock(&desc->lock); |
| 451 | desc->status &= ~IRQ_INPROGRESS; | 502 | desc->status &= ~IRQ_INPROGRESS; |
| 452 | 503 | ||
| 453 | if (unlikely(desc->status & IRQ_ONESHOT)) | 504 | if (!(desc->status & (IRQ_DISABLED | IRQ_ONESHOT))) |
| 454 | desc->status |= IRQ_MASKED; | 505 | unmask_irq(desc, irq); |
| 455 | else if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) | ||
| 456 | desc->chip->unmask(irq); | ||
| 457 | out_unlock: | 506 | out_unlock: |
| 458 | raw_spin_unlock(&desc->lock); | 507 | raw_spin_unlock(&desc->lock); |
| 459 | } | 508 | } |
| @@ -490,8 +539,7 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) | |||
| 490 | action = desc->action; | 539 | action = desc->action; |
| 491 | if (unlikely(!action || (desc->status & IRQ_DISABLED))) { | 540 | if (unlikely(!action || (desc->status & IRQ_DISABLED))) { |
| 492 | desc->status |= IRQ_PENDING; | 541 | desc->status |= IRQ_PENDING; |
| 493 | if (desc->chip->mask) | 542 | mask_irq(desc, irq); |
| 494 | desc->chip->mask(irq); | ||
| 495 | goto out; | 543 | goto out; |
| 496 | } | 544 | } |
| 497 | 545 | ||
| @@ -520,7 +568,7 @@ out: | |||
| 520 | * signal. The occurence is latched into the irq controller hardware | 568 | * signal. The occurence is latched into the irq controller hardware |
| 521 | * and must be acked in order to be reenabled. After the ack another | 569 | * and must be acked in order to be reenabled. After the ack another |
| 522 | * interrupt can happen on the same source even before the first one | 570 | * interrupt can happen on the same source even before the first one |
| 523 | * is handled by the assosiacted event handler. If this happens it | 571 | * is handled by the associated event handler. If this happens it |
| 524 | * might be necessary to disable (mask) the interrupt depending on the | 572 | * might be necessary to disable (mask) the interrupt depending on the |
| 525 | * controller hardware. This requires to reenable the interrupt inside | 573 | * controller hardware. This requires to reenable the interrupt inside |
| 526 | * of the loop which handles the interrupts which have arrived while | 574 | * of the loop which handles the interrupts which have arrived while |
| @@ -559,7 +607,7 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) | |||
| 559 | irqreturn_t action_ret; | 607 | irqreturn_t action_ret; |
| 560 | 608 | ||
| 561 | if (unlikely(!action)) { | 609 | if (unlikely(!action)) { |
| 562 | desc->chip->mask(irq); | 610 | mask_irq(desc, irq); |
| 563 | goto out_unlock; | 611 | goto out_unlock; |
| 564 | } | 612 | } |
| 565 | 613 | ||
| @@ -571,8 +619,7 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) | |||
| 571 | if (unlikely((desc->status & | 619 | if (unlikely((desc->status & |
| 572 | (IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) == | 620 | (IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) == |
| 573 | (IRQ_PENDING | IRQ_MASKED))) { | 621 | (IRQ_PENDING | IRQ_MASKED))) { |
| 574 | desc->chip->unmask(irq); | 622 | unmask_irq(desc, irq); |
| 575 | desc->status &= ~IRQ_MASKED; | ||
| 576 | } | 623 | } |
| 577 | 624 | ||
| 578 | desc->status &= ~IRQ_PENDING; | 625 | desc->status &= ~IRQ_PENDING; |
| @@ -682,7 +729,7 @@ set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip, | |||
| 682 | __set_irq_handler(irq, handle, 0, name); | 729 | __set_irq_handler(irq, handle, 0, name); |
| 683 | } | 730 | } |
| 684 | 731 | ||
| 685 | void __init set_irq_noprobe(unsigned int irq) | 732 | void set_irq_noprobe(unsigned int irq) |
| 686 | { | 733 | { |
| 687 | struct irq_desc *desc = irq_to_desc(irq); | 734 | struct irq_desc *desc = irq_to_desc(irq); |
| 688 | unsigned long flags; | 735 | unsigned long flags; |
| @@ -697,7 +744,7 @@ void __init set_irq_noprobe(unsigned int irq) | |||
| 697 | raw_spin_unlock_irqrestore(&desc->lock, flags); | 744 | raw_spin_unlock_irqrestore(&desc->lock, flags); |
| 698 | } | 745 | } |
| 699 | 746 | ||
| 700 | void __init set_irq_probe(unsigned int irq) | 747 | void set_irq_probe(unsigned int irq) |
| 701 | { | 748 | { |
| 702 | struct irq_desc *desc = irq_to_desc(irq); | 749 | struct irq_desc *desc = irq_to_desc(irq); |
| 703 | unsigned long flags; | 750 | unsigned long flags; |
diff --git a/kernel/irq/devres.c b/kernel/irq/devres.c index d06df9c41cba..1ef4ffcdfa55 100644 --- a/kernel/irq/devres.c +++ b/kernel/irq/devres.c | |||
| @@ -42,7 +42,7 @@ static int devm_irq_match(struct device *dev, void *res, void *data) | |||
| 42 | * automatically freed on driver detach. | 42 | * automatically freed on driver detach. |
| 43 | * | 43 | * |
| 44 | * If an IRQ allocated with this function needs to be freed | 44 | * If an IRQ allocated with this function needs to be freed |
| 45 | * separately, dev_free_irq() must be used. | 45 | * separately, devm_free_irq() must be used. |
| 46 | */ | 46 | */ |
| 47 | int devm_request_threaded_irq(struct device *dev, unsigned int irq, | 47 | int devm_request_threaded_irq(struct device *dev, unsigned int irq, |
| 48 | irq_handler_t handler, irq_handler_t thread_fn, | 48 | irq_handler_t handler, irq_handler_t thread_fn, |
| @@ -81,7 +81,7 @@ EXPORT_SYMBOL(devm_request_threaded_irq); | |||
| 81 | * Except for the extra @dev argument, this function takes the | 81 | * Except for the extra @dev argument, this function takes the |
| 82 | * same arguments and performs the same function as free_irq(). | 82 | * same arguments and performs the same function as free_irq(). |
| 83 | * This function instead of free_irq() should be used to manually | 83 | * This function instead of free_irq() should be used to manually |
| 84 | * free IRQs allocated with dev_request_irq(). | 84 | * free IRQs allocated with devm_request_irq(). |
| 85 | */ | 85 | */ |
| 86 | void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id) | 86 | void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id) |
| 87 | { | 87 | { |
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 814940e7f485..76d5a671bfe1 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c | |||
| @@ -19,7 +19,7 @@ | |||
| 19 | #include <linux/kernel_stat.h> | 19 | #include <linux/kernel_stat.h> |
| 20 | #include <linux/rculist.h> | 20 | #include <linux/rculist.h> |
| 21 | #include <linux/hash.h> | 21 | #include <linux/hash.h> |
| 22 | #include <linux/bootmem.h> | 22 | #include <linux/radix-tree.h> |
| 23 | #include <trace/events/irq.h> | 23 | #include <trace/events/irq.h> |
| 24 | 24 | ||
| 25 | #include "internals.h" | 25 | #include "internals.h" |
| @@ -87,12 +87,8 @@ void __ref init_kstat_irqs(struct irq_desc *desc, int node, int nr) | |||
| 87 | { | 87 | { |
| 88 | void *ptr; | 88 | void *ptr; |
| 89 | 89 | ||
| 90 | if (slab_is_available()) | 90 | ptr = kzalloc_node(nr * sizeof(*desc->kstat_irqs), |
| 91 | ptr = kzalloc_node(nr * sizeof(*desc->kstat_irqs), | 91 | GFP_ATOMIC, node); |
| 92 | GFP_ATOMIC, node); | ||
| 93 | else | ||
| 94 | ptr = alloc_bootmem_node(NODE_DATA(node), | ||
| 95 | nr * sizeof(*desc->kstat_irqs)); | ||
| 96 | 92 | ||
| 97 | /* | 93 | /* |
| 98 | * don't overwite if can not get new one | 94 | * don't overwite if can not get new one |
| @@ -132,7 +128,26 @@ static void init_one_irq_desc(int irq, struct irq_desc *desc, int node) | |||
| 132 | */ | 128 | */ |
| 133 | DEFINE_RAW_SPINLOCK(sparse_irq_lock); | 129 | DEFINE_RAW_SPINLOCK(sparse_irq_lock); |
| 134 | 130 | ||
| 135 | struct irq_desc **irq_desc_ptrs __read_mostly; | 131 | static RADIX_TREE(irq_desc_tree, GFP_ATOMIC); |
| 132 | |||
| 133 | static void set_irq_desc(unsigned int irq, struct irq_desc *desc) | ||
| 134 | { | ||
| 135 | radix_tree_insert(&irq_desc_tree, irq, desc); | ||
| 136 | } | ||
| 137 | |||
| 138 | struct irq_desc *irq_to_desc(unsigned int irq) | ||
| 139 | { | ||
| 140 | return radix_tree_lookup(&irq_desc_tree, irq); | ||
| 141 | } | ||
| 142 | |||
| 143 | void replace_irq_desc(unsigned int irq, struct irq_desc *desc) | ||
| 144 | { | ||
| 145 | void **ptr; | ||
| 146 | |||
| 147 | ptr = radix_tree_lookup_slot(&irq_desc_tree, irq); | ||
| 148 | if (ptr) | ||
| 149 | radix_tree_replace_slot(ptr, desc); | ||
| 150 | } | ||
| 136 | 151 | ||
| 137 | static struct irq_desc irq_desc_legacy[NR_IRQS_LEGACY] __cacheline_aligned_in_smp = { | 152 | static struct irq_desc irq_desc_legacy[NR_IRQS_LEGACY] __cacheline_aligned_in_smp = { |
| 138 | [0 ... NR_IRQS_LEGACY-1] = { | 153 | [0 ... NR_IRQS_LEGACY-1] = { |
| @@ -164,9 +179,6 @@ int __init early_irq_init(void) | |||
| 164 | legacy_count = ARRAY_SIZE(irq_desc_legacy); | 179 | legacy_count = ARRAY_SIZE(irq_desc_legacy); |
| 165 | node = first_online_node; | 180 | node = first_online_node; |
| 166 | 181 | ||
| 167 | /* allocate irq_desc_ptrs array based on nr_irqs */ | ||
| 168 | irq_desc_ptrs = kcalloc(nr_irqs, sizeof(void *), GFP_NOWAIT); | ||
| 169 | |||
| 170 | /* allocate based on nr_cpu_ids */ | 182 | /* allocate based on nr_cpu_ids */ |
| 171 | kstat_irqs_legacy = kzalloc_node(NR_IRQS_LEGACY * nr_cpu_ids * | 183 | kstat_irqs_legacy = kzalloc_node(NR_IRQS_LEGACY * nr_cpu_ids * |
| 172 | sizeof(int), GFP_NOWAIT, node); | 184 | sizeof(int), GFP_NOWAIT, node); |
| @@ -180,23 +192,12 @@ int __init early_irq_init(void) | |||
| 180 | lockdep_set_class(&desc[i].lock, &irq_desc_lock_class); | 192 | lockdep_set_class(&desc[i].lock, &irq_desc_lock_class); |
| 181 | alloc_desc_masks(&desc[i], node, true); | 193 | alloc_desc_masks(&desc[i], node, true); |
| 182 | init_desc_masks(&desc[i]); | 194 | init_desc_masks(&desc[i]); |
| 183 | irq_desc_ptrs[i] = desc + i; | 195 | set_irq_desc(i, &desc[i]); |
| 184 | } | 196 | } |
| 185 | 197 | ||
| 186 | for (i = legacy_count; i < nr_irqs; i++) | ||
| 187 | irq_desc_ptrs[i] = NULL; | ||
| 188 | |||
| 189 | return arch_early_irq_init(); | 198 | return arch_early_irq_init(); |
| 190 | } | 199 | } |
| 191 | 200 | ||
| 192 | struct irq_desc *irq_to_desc(unsigned int irq) | ||
| 193 | { | ||
| 194 | if (irq_desc_ptrs && irq < nr_irqs) | ||
| 195 | return irq_desc_ptrs[irq]; | ||
| 196 | |||
| 197 | return NULL; | ||
| 198 | } | ||
| 199 | |||
| 200 | struct irq_desc * __ref irq_to_desc_alloc_node(unsigned int irq, int node) | 201 | struct irq_desc * __ref irq_to_desc_alloc_node(unsigned int irq, int node) |
| 201 | { | 202 | { |
| 202 | struct irq_desc *desc; | 203 | struct irq_desc *desc; |
| @@ -208,21 +209,18 @@ struct irq_desc * __ref irq_to_desc_alloc_node(unsigned int irq, int node) | |||
| 208 | return NULL; | 209 | return NULL; |
| 209 | } | 210 | } |
| 210 | 211 | ||
| 211 | desc = irq_desc_ptrs[irq]; | 212 | desc = irq_to_desc(irq); |
| 212 | if (desc) | 213 | if (desc) |
| 213 | return desc; | 214 | return desc; |
| 214 | 215 | ||
| 215 | raw_spin_lock_irqsave(&sparse_irq_lock, flags); | 216 | raw_spin_lock_irqsave(&sparse_irq_lock, flags); |
| 216 | 217 | ||
| 217 | /* We have to check it to avoid races with another CPU */ | 218 | /* We have to check it to avoid races with another CPU */ |
| 218 | desc = irq_desc_ptrs[irq]; | 219 | desc = irq_to_desc(irq); |
| 219 | if (desc) | 220 | if (desc) |
| 220 | goto out_unlock; | 221 | goto out_unlock; |
| 221 | 222 | ||
| 222 | if (slab_is_available()) | 223 | desc = kzalloc_node(sizeof(*desc), GFP_ATOMIC, node); |
| 223 | desc = kzalloc_node(sizeof(*desc), GFP_ATOMIC, node); | ||
| 224 | else | ||
| 225 | desc = alloc_bootmem_node(NODE_DATA(node), sizeof(*desc)); | ||
| 226 | 224 | ||
| 227 | printk(KERN_DEBUG " alloc irq_desc for %d on node %d\n", irq, node); | 225 | printk(KERN_DEBUG " alloc irq_desc for %d on node %d\n", irq, node); |
| 228 | if (!desc) { | 226 | if (!desc) { |
| @@ -231,7 +229,7 @@ struct irq_desc * __ref irq_to_desc_alloc_node(unsigned int irq, int node) | |||
| 231 | } | 229 | } |
| 232 | init_one_irq_desc(irq, desc, node); | 230 | init_one_irq_desc(irq, desc, node); |
| 233 | 231 | ||
| 234 | irq_desc_ptrs[irq] = desc; | 232 | set_irq_desc(irq, desc); |
| 235 | 233 | ||
| 236 | out_unlock: | 234 | out_unlock: |
| 237 | raw_spin_unlock_irqrestore(&sparse_irq_lock, flags); | 235 | raw_spin_unlock_irqrestore(&sparse_irq_lock, flags); |
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index b2821f070a3d..c63f3bc88f0b 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h | |||
| @@ -21,11 +21,7 @@ extern void clear_kstat_irqs(struct irq_desc *desc); | |||
| 21 | extern raw_spinlock_t sparse_irq_lock; | 21 | extern raw_spinlock_t sparse_irq_lock; |
| 22 | 22 | ||
| 23 | #ifdef CONFIG_SPARSE_IRQ | 23 | #ifdef CONFIG_SPARSE_IRQ |
| 24 | /* irq_desc_ptrs allocated at boot time */ | 24 | void replace_irq_desc(unsigned int irq, struct irq_desc *desc); |
| 25 | extern struct irq_desc **irq_desc_ptrs; | ||
| 26 | #else | ||
| 27 | /* irq_desc_ptrs is a fixed size array */ | ||
| 28 | extern struct irq_desc *irq_desc_ptrs[NR_IRQS]; | ||
| 29 | #endif | 25 | #endif |
| 30 | 26 | ||
| 31 | #ifdef CONFIG_PROC_FS | 27 | #ifdef CONFIG_PROC_FS |
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index eb6078ca60c7..704e488730a5 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
| @@ -382,6 +382,7 @@ int can_request_irq(unsigned int irq, unsigned long irqflags) | |||
| 382 | { | 382 | { |
| 383 | struct irq_desc *desc = irq_to_desc(irq); | 383 | struct irq_desc *desc = irq_to_desc(irq); |
| 384 | struct irqaction *action; | 384 | struct irqaction *action; |
| 385 | unsigned long flags; | ||
| 385 | 386 | ||
| 386 | if (!desc) | 387 | if (!desc) |
| 387 | return 0; | 388 | return 0; |
| @@ -389,11 +390,14 @@ int can_request_irq(unsigned int irq, unsigned long irqflags) | |||
| 389 | if (desc->status & IRQ_NOREQUEST) | 390 | if (desc->status & IRQ_NOREQUEST) |
| 390 | return 0; | 391 | return 0; |
| 391 | 392 | ||
| 393 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
| 392 | action = desc->action; | 394 | action = desc->action; |
| 393 | if (action) | 395 | if (action) |
| 394 | if (irqflags & action->flags & IRQF_SHARED) | 396 | if (irqflags & action->flags & IRQF_SHARED) |
| 395 | action = NULL; | 397 | action = NULL; |
| 396 | 398 | ||
| 399 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
| 400 | |||
| 397 | return !action; | 401 | return !action; |
| 398 | } | 402 | } |
| 399 | 403 | ||
| @@ -483,8 +487,26 @@ static int irq_wait_for_interrupt(struct irqaction *action) | |||
| 483 | */ | 487 | */ |
| 484 | static void irq_finalize_oneshot(unsigned int irq, struct irq_desc *desc) | 488 | static void irq_finalize_oneshot(unsigned int irq, struct irq_desc *desc) |
| 485 | { | 489 | { |
| 490 | again: | ||
| 486 | chip_bus_lock(irq, desc); | 491 | chip_bus_lock(irq, desc); |
| 487 | raw_spin_lock_irq(&desc->lock); | 492 | raw_spin_lock_irq(&desc->lock); |
| 493 | |||
| 494 | /* | ||
| 495 | * Implausible though it may be we need to protect us against | ||
| 496 | * the following scenario: | ||
| 497 | * | ||
| 498 | * The thread is faster done than the hard interrupt handler | ||
| 499 | * on the other CPU. If we unmask the irq line then the | ||
| 500 | * interrupt can come in again and masks the line, leaves due | ||
| 501 | * to IRQ_INPROGRESS and the irq line is masked forever. | ||
| 502 | */ | ||
| 503 | if (unlikely(desc->status & IRQ_INPROGRESS)) { | ||
| 504 | raw_spin_unlock_irq(&desc->lock); | ||
| 505 | chip_bus_sync_unlock(irq, desc); | ||
| 506 | cpu_relax(); | ||
| 507 | goto again; | ||
| 508 | } | ||
| 509 | |||
| 488 | if (!(desc->status & IRQ_DISABLED) && (desc->status & IRQ_MASKED)) { | 510 | if (!(desc->status & IRQ_DISABLED) && (desc->status & IRQ_MASKED)) { |
| 489 | desc->status &= ~IRQ_MASKED; | 511 | desc->status &= ~IRQ_MASKED; |
| 490 | desc->chip->unmask(irq); | 512 | desc->chip->unmask(irq); |
| @@ -735,6 +757,16 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
| 735 | if (new->flags & IRQF_ONESHOT) | 757 | if (new->flags & IRQF_ONESHOT) |
| 736 | desc->status |= IRQ_ONESHOT; | 758 | desc->status |= IRQ_ONESHOT; |
| 737 | 759 | ||
| 760 | /* | ||
| 761 | * Force MSI interrupts to run with interrupts | ||
| 762 | * disabled. The multi vector cards can cause stack | ||
| 763 | * overflows due to nested interrupts when enough of | ||
| 764 | * them are directed to a core and fire at the same | ||
| 765 | * time. | ||
| 766 | */ | ||
| 767 | if (desc->msi_desc) | ||
| 768 | new->flags |= IRQF_DISABLED; | ||
| 769 | |||
| 738 | if (!(desc->status & IRQ_NOAUTOEN)) { | 770 | if (!(desc->status & IRQ_NOAUTOEN)) { |
| 739 | desc->depth = 0; | 771 | desc->depth = 0; |
| 740 | desc->status &= ~IRQ_DISABLED; | 772 | desc->status &= ~IRQ_DISABLED; |
diff --git a/kernel/irq/numa_migrate.c b/kernel/irq/numa_migrate.c index 26bac9d8f860..65d3845665ac 100644 --- a/kernel/irq/numa_migrate.c +++ b/kernel/irq/numa_migrate.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include <linux/irq.h> | 8 | #include <linux/irq.h> |
| 9 | #include <linux/slab.h> | ||
| 9 | #include <linux/module.h> | 10 | #include <linux/module.h> |
| 10 | #include <linux/random.h> | 11 | #include <linux/random.h> |
| 11 | #include <linux/interrupt.h> | 12 | #include <linux/interrupt.h> |
| @@ -70,7 +71,7 @@ static struct irq_desc *__real_move_irq_desc(struct irq_desc *old_desc, | |||
| 70 | raw_spin_lock_irqsave(&sparse_irq_lock, flags); | 71 | raw_spin_lock_irqsave(&sparse_irq_lock, flags); |
| 71 | 72 | ||
| 72 | /* We have to check it to avoid races with another CPU */ | 73 | /* We have to check it to avoid races with another CPU */ |
| 73 | desc = irq_desc_ptrs[irq]; | 74 | desc = irq_to_desc(irq); |
| 74 | 75 | ||
| 75 | if (desc && old_desc != desc) | 76 | if (desc && old_desc != desc) |
| 76 | goto out_unlock; | 77 | goto out_unlock; |
| @@ -90,7 +91,7 @@ static struct irq_desc *__real_move_irq_desc(struct irq_desc *old_desc, | |||
| 90 | goto out_unlock; | 91 | goto out_unlock; |
| 91 | } | 92 | } |
| 92 | 93 | ||
| 93 | irq_desc_ptrs[irq] = desc; | 94 | replace_irq_desc(irq, desc); |
| 94 | raw_spin_unlock_irqrestore(&sparse_irq_lock, flags); | 95 | raw_spin_unlock_irqrestore(&sparse_irq_lock, flags); |
| 95 | 96 | ||
| 96 | /* free the old one */ | 97 | /* free the old one */ |
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index 6f50eccc79c0..7a6eb04ef6b5 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include <linux/irq.h> | 9 | #include <linux/irq.h> |
| 10 | #include <linux/gfp.h> | ||
| 10 | #include <linux/proc_fs.h> | 11 | #include <linux/proc_fs.h> |
| 11 | #include <linux/seq_file.h> | 12 | #include <linux/seq_file.h> |
| 12 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
