diff options
Diffstat (limited to 'kernel/irq')
| -rw-r--r-- | kernel/irq/autoprobe.c | 43 | ||||
| -rw-r--r-- | kernel/irq/chip.c | 102 | ||||
| -rw-r--r-- | kernel/irq/handle.c | 27 | ||||
| -rw-r--r-- | kernel/irq/internals.h | 7 | ||||
| -rw-r--r-- | kernel/irq/manage.c | 130 | ||||
| -rw-r--r-- | kernel/irq/migration.c | 14 | ||||
| -rw-r--r-- | kernel/irq/proc.c | 47 | ||||
| -rw-r--r-- | kernel/irq/resend.c | 6 | ||||
| -rw-r--r-- | kernel/irq/spurious.c | 162 |
9 files changed, 307 insertions, 231 deletions
diff --git a/kernel/irq/autoprobe.c b/kernel/irq/autoprobe.c index 533068cfb60..cc0f7321b8c 100644 --- a/kernel/irq/autoprobe.c +++ b/kernel/irq/autoprobe.c | |||
| @@ -30,17 +30,16 @@ static DEFINE_MUTEX(probing_active); | |||
| 30 | unsigned long probe_irq_on(void) | 30 | unsigned long probe_irq_on(void) |
| 31 | { | 31 | { |
| 32 | struct irq_desc *desc; | 32 | struct irq_desc *desc; |
| 33 | unsigned long mask; | 33 | unsigned long mask = 0; |
| 34 | unsigned int i; | 34 | unsigned int status; |
| 35 | int i; | ||
| 35 | 36 | ||
| 36 | mutex_lock(&probing_active); | 37 | mutex_lock(&probing_active); |
| 37 | /* | 38 | /* |
| 38 | * something may have generated an irq long ago and we want to | 39 | * something may have generated an irq long ago and we want to |
| 39 | * flush such a longstanding irq before considering it as spurious. | 40 | * flush such a longstanding irq before considering it as spurious. |
| 40 | */ | 41 | */ |
| 41 | for (i = NR_IRQS-1; i > 0; i--) { | 42 | for_each_irq_desc_reverse(i, desc) { |
| 42 | desc = irq_desc + i; | ||
| 43 | |||
| 44 | spin_lock_irq(&desc->lock); | 43 | spin_lock_irq(&desc->lock); |
| 45 | if (!desc->action && !(desc->status & IRQ_NOPROBE)) { | 44 | if (!desc->action && !(desc->status & IRQ_NOPROBE)) { |
| 46 | /* | 45 | /* |
| @@ -68,9 +67,7 @@ unsigned long probe_irq_on(void) | |||
| 68 | * (we must startup again here because if a longstanding irq | 67 | * (we must startup again here because if a longstanding irq |
| 69 | * happened in the previous stage, it may have masked itself) | 68 | * happened in the previous stage, it may have masked itself) |
| 70 | */ | 69 | */ |
| 71 | for (i = NR_IRQS-1; i > 0; i--) { | 70 | for_each_irq_desc_reverse(i, desc) { |
| 72 | desc = irq_desc + i; | ||
| 73 | |||
| 74 | spin_lock_irq(&desc->lock); | 71 | spin_lock_irq(&desc->lock); |
| 75 | if (!desc->action && !(desc->status & IRQ_NOPROBE)) { | 72 | if (!desc->action && !(desc->status & IRQ_NOPROBE)) { |
| 76 | desc->status |= IRQ_AUTODETECT | IRQ_WAITING; | 73 | desc->status |= IRQ_AUTODETECT | IRQ_WAITING; |
| @@ -88,11 +85,7 @@ unsigned long probe_irq_on(void) | |||
| 88 | /* | 85 | /* |
| 89 | * Now filter out any obviously spurious interrupts | 86 | * Now filter out any obviously spurious interrupts |
| 90 | */ | 87 | */ |
| 91 | mask = 0; | 88 | for_each_irq_desc(i, desc) { |
| 92 | for (i = 0; i < NR_IRQS; i++) { | ||
| 93 | unsigned int status; | ||
| 94 | |||
| 95 | desc = irq_desc + i; | ||
| 96 | spin_lock_irq(&desc->lock); | 89 | spin_lock_irq(&desc->lock); |
| 97 | status = desc->status; | 90 | status = desc->status; |
| 98 | 91 | ||
| @@ -126,14 +119,11 @@ EXPORT_SYMBOL(probe_irq_on); | |||
| 126 | */ | 119 | */ |
| 127 | unsigned int probe_irq_mask(unsigned long val) | 120 | unsigned int probe_irq_mask(unsigned long val) |
| 128 | { | 121 | { |
| 129 | unsigned int mask; | 122 | unsigned int status, mask = 0; |
| 123 | struct irq_desc *desc; | ||
| 130 | int i; | 124 | int i; |
| 131 | 125 | ||
| 132 | mask = 0; | 126 | for_each_irq_desc(i, desc) { |
| 133 | for (i = 0; i < NR_IRQS; i++) { | ||
| 134 | struct irq_desc *desc = irq_desc + i; | ||
| 135 | unsigned int status; | ||
| 136 | |||
| 137 | spin_lock_irq(&desc->lock); | 127 | spin_lock_irq(&desc->lock); |
| 138 | status = desc->status; | 128 | status = desc->status; |
| 139 | 129 | ||
| @@ -171,20 +161,19 @@ EXPORT_SYMBOL(probe_irq_mask); | |||
| 171 | */ | 161 | */ |
| 172 | int probe_irq_off(unsigned long val) | 162 | int probe_irq_off(unsigned long val) |
| 173 | { | 163 | { |
| 174 | int i, irq_found = 0, nr_irqs = 0; | 164 | int i, irq_found = 0, nr_of_irqs = 0; |
| 175 | 165 | struct irq_desc *desc; | |
| 176 | for (i = 0; i < NR_IRQS; i++) { | 166 | unsigned int status; |
| 177 | struct irq_desc *desc = irq_desc + i; | ||
| 178 | unsigned int status; | ||
| 179 | 167 | ||
| 168 | for_each_irq_desc(i, desc) { | ||
| 180 | spin_lock_irq(&desc->lock); | 169 | spin_lock_irq(&desc->lock); |
| 181 | status = desc->status; | 170 | status = desc->status; |
| 182 | 171 | ||
| 183 | if (status & IRQ_AUTODETECT) { | 172 | if (status & IRQ_AUTODETECT) { |
| 184 | if (!(status & IRQ_WAITING)) { | 173 | if (!(status & IRQ_WAITING)) { |
| 185 | if (!nr_irqs) | 174 | if (!nr_of_irqs) |
| 186 | irq_found = i; | 175 | irq_found = i; |
| 187 | nr_irqs++; | 176 | nr_of_irqs++; |
| 188 | } | 177 | } |
| 189 | desc->status = status & ~IRQ_AUTODETECT; | 178 | desc->status = status & ~IRQ_AUTODETECT; |
| 190 | desc->chip->shutdown(i); | 179 | desc->chip->shutdown(i); |
| @@ -193,7 +182,7 @@ int probe_irq_off(unsigned long val) | |||
| 193 | } | 182 | } |
| 194 | mutex_unlock(&probing_active); | 183 | mutex_unlock(&probing_active); |
| 195 | 184 | ||
| 196 | if (nr_irqs > 1) | 185 | if (nr_of_irqs > 1) |
| 197 | irq_found = -irq_found; | 186 | irq_found = -irq_found; |
| 198 | 187 | ||
| 199 | return irq_found; | 188 | return irq_found; |
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 3cd441ebf5d..10b5092e9bf 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c | |||
| @@ -24,16 +24,15 @@ | |||
| 24 | */ | 24 | */ |
| 25 | void dynamic_irq_init(unsigned int irq) | 25 | void dynamic_irq_init(unsigned int irq) |
| 26 | { | 26 | { |
| 27 | struct irq_desc *desc; | 27 | struct irq_desc *desc = irq_to_desc(irq); |
| 28 | unsigned long flags; | 28 | unsigned long flags; |
| 29 | 29 | ||
| 30 | if (irq >= NR_IRQS) { | 30 | if (!desc) { |
| 31 | WARN(1, KERN_ERR "Trying to initialize invalid IRQ%d\n", irq); | 31 | WARN(1, KERN_ERR "Trying to initialize invalid IRQ%d\n", irq); |
| 32 | return; | 32 | return; |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | /* Ensure we don't have left over values from a previous use of this irq */ | 35 | /* Ensure we don't have left over values from a previous use of this irq */ |
| 36 | desc = irq_desc + irq; | ||
| 37 | spin_lock_irqsave(&desc->lock, flags); | 36 | spin_lock_irqsave(&desc->lock, flags); |
| 38 | desc->status = IRQ_DISABLED; | 37 | desc->status = IRQ_DISABLED; |
| 39 | desc->chip = &no_irq_chip; | 38 | desc->chip = &no_irq_chip; |
| @@ -57,15 +56,14 @@ void dynamic_irq_init(unsigned int irq) | |||
| 57 | */ | 56 | */ |
| 58 | void dynamic_irq_cleanup(unsigned int irq) | 57 | void dynamic_irq_cleanup(unsigned int irq) |
| 59 | { | 58 | { |
| 60 | struct irq_desc *desc; | 59 | struct irq_desc *desc = irq_to_desc(irq); |
| 61 | unsigned long flags; | 60 | unsigned long flags; |
| 62 | 61 | ||
| 63 | if (irq >= NR_IRQS) { | 62 | if (!desc) { |
| 64 | WARN(1, KERN_ERR "Trying to cleanup invalid IRQ%d\n", irq); | 63 | WARN(1, KERN_ERR "Trying to cleanup invalid IRQ%d\n", irq); |
| 65 | return; | 64 | return; |
| 66 | } | 65 | } |
| 67 | 66 | ||
| 68 | desc = irq_desc + irq; | ||
| 69 | spin_lock_irqsave(&desc->lock, flags); | 67 | spin_lock_irqsave(&desc->lock, flags); |
| 70 | if (desc->action) { | 68 | if (desc->action) { |
| 71 | spin_unlock_irqrestore(&desc->lock, flags); | 69 | spin_unlock_irqrestore(&desc->lock, flags); |
| @@ -78,6 +76,7 @@ void dynamic_irq_cleanup(unsigned int irq) | |||
| 78 | desc->chip_data = NULL; | 76 | desc->chip_data = NULL; |
| 79 | desc->handle_irq = handle_bad_irq; | 77 | desc->handle_irq = handle_bad_irq; |
| 80 | desc->chip = &no_irq_chip; | 78 | desc->chip = &no_irq_chip; |
| 79 | desc->name = NULL; | ||
| 81 | spin_unlock_irqrestore(&desc->lock, flags); | 80 | spin_unlock_irqrestore(&desc->lock, flags); |
| 82 | } | 81 | } |
| 83 | 82 | ||
| @@ -89,10 +88,10 @@ void dynamic_irq_cleanup(unsigned int irq) | |||
| 89 | */ | 88 | */ |
| 90 | int set_irq_chip(unsigned int irq, struct irq_chip *chip) | 89 | int set_irq_chip(unsigned int irq, struct irq_chip *chip) |
| 91 | { | 90 | { |
| 92 | struct irq_desc *desc; | 91 | struct irq_desc *desc = irq_to_desc(irq); |
| 93 | unsigned long flags; | 92 | unsigned long flags; |
| 94 | 93 | ||
| 95 | if (irq >= NR_IRQS) { | 94 | if (!desc) { |
| 96 | WARN(1, KERN_ERR "Trying to install chip for IRQ%d\n", irq); | 95 | WARN(1, KERN_ERR "Trying to install chip for IRQ%d\n", irq); |
| 97 | return -EINVAL; | 96 | return -EINVAL; |
| 98 | } | 97 | } |
| @@ -100,7 +99,6 @@ int set_irq_chip(unsigned int irq, struct irq_chip *chip) | |||
| 100 | if (!chip) | 99 | if (!chip) |
| 101 | chip = &no_irq_chip; | 100 | chip = &no_irq_chip; |
| 102 | 101 | ||
| 103 | desc = irq_desc + irq; | ||
| 104 | spin_lock_irqsave(&desc->lock, flags); | 102 | spin_lock_irqsave(&desc->lock, flags); |
| 105 | irq_chip_set_defaults(chip); | 103 | irq_chip_set_defaults(chip); |
| 106 | desc->chip = chip; | 104 | desc->chip = chip; |
| @@ -111,27 +109,27 @@ int set_irq_chip(unsigned int irq, struct irq_chip *chip) | |||
| 111 | EXPORT_SYMBOL(set_irq_chip); | 109 | EXPORT_SYMBOL(set_irq_chip); |
| 112 | 110 | ||
| 113 | /** | 111 | /** |
| 114 | * set_irq_type - set the irq type for an irq | 112 | * set_irq_type - set the irq trigger type for an irq |
| 115 | * @irq: irq number | 113 | * @irq: irq number |
| 116 | * @type: interrupt type - see include/linux/interrupt.h | 114 | * @type: IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h |
| 117 | */ | 115 | */ |
| 118 | int set_irq_type(unsigned int irq, unsigned int type) | 116 | int set_irq_type(unsigned int irq, unsigned int type) |
| 119 | { | 117 | { |
| 120 | struct irq_desc *desc; | 118 | struct irq_desc *desc = irq_to_desc(irq); |
| 121 | unsigned long flags; | 119 | unsigned long flags; |
| 122 | int ret = -ENXIO; | 120 | int ret = -ENXIO; |
| 123 | 121 | ||
| 124 | if (irq >= NR_IRQS) { | 122 | if (!desc) { |
| 125 | printk(KERN_ERR "Trying to set irq type for IRQ%d\n", irq); | 123 | printk(KERN_ERR "Trying to set irq type for IRQ%d\n", irq); |
| 126 | return -ENODEV; | 124 | return -ENODEV; |
| 127 | } | 125 | } |
| 128 | 126 | ||
| 129 | desc = irq_desc + irq; | 127 | if (type == IRQ_TYPE_NONE) |
| 130 | if (desc->chip->set_type) { | 128 | return 0; |
| 131 | spin_lock_irqsave(&desc->lock, flags); | 129 | |
| 132 | ret = desc->chip->set_type(irq, type); | 130 | spin_lock_irqsave(&desc->lock, flags); |
| 133 | spin_unlock_irqrestore(&desc->lock, flags); | 131 | ret = __irq_set_trigger(desc, irq, type); |
| 134 | } | 132 | spin_unlock_irqrestore(&desc->lock, flags); |
| 135 | return ret; | 133 | return ret; |
| 136 | } | 134 | } |
| 137 | EXPORT_SYMBOL(set_irq_type); | 135 | EXPORT_SYMBOL(set_irq_type); |
| @@ -145,16 +143,15 @@ EXPORT_SYMBOL(set_irq_type); | |||
| 145 | */ | 143 | */ |
| 146 | int set_irq_data(unsigned int irq, void *data) | 144 | int set_irq_data(unsigned int irq, void *data) |
| 147 | { | 145 | { |
| 148 | struct irq_desc *desc; | 146 | struct irq_desc *desc = irq_to_desc(irq); |
| 149 | unsigned long flags; | 147 | unsigned long flags; |
| 150 | 148 | ||
| 151 | if (irq >= NR_IRQS) { | 149 | if (!desc) { |
| 152 | printk(KERN_ERR | 150 | printk(KERN_ERR |
| 153 | "Trying to install controller data for IRQ%d\n", irq); | 151 | "Trying to install controller data for IRQ%d\n", irq); |
| 154 | return -EINVAL; | 152 | return -EINVAL; |
| 155 | } | 153 | } |
| 156 | 154 | ||
| 157 | desc = irq_desc + irq; | ||
| 158 | spin_lock_irqsave(&desc->lock, flags); | 155 | spin_lock_irqsave(&desc->lock, flags); |
| 159 | desc->handler_data = data; | 156 | desc->handler_data = data; |
| 160 | spin_unlock_irqrestore(&desc->lock, flags); | 157 | spin_unlock_irqrestore(&desc->lock, flags); |
| @@ -171,15 +168,15 @@ EXPORT_SYMBOL(set_irq_data); | |||
| 171 | */ | 168 | */ |
| 172 | int set_irq_msi(unsigned int irq, struct msi_desc *entry) | 169 | int set_irq_msi(unsigned int irq, struct msi_desc *entry) |
| 173 | { | 170 | { |
| 174 | struct irq_desc *desc; | 171 | struct irq_desc *desc = irq_to_desc(irq); |
| 175 | unsigned long flags; | 172 | unsigned long flags; |
| 176 | 173 | ||
| 177 | if (irq >= NR_IRQS) { | 174 | if (!desc) { |
| 178 | printk(KERN_ERR | 175 | printk(KERN_ERR |
| 179 | "Trying to install msi data for IRQ%d\n", irq); | 176 | "Trying to install msi data for IRQ%d\n", irq); |
| 180 | return -EINVAL; | 177 | return -EINVAL; |
| 181 | } | 178 | } |
| 182 | desc = irq_desc + irq; | 179 | |
| 183 | spin_lock_irqsave(&desc->lock, flags); | 180 | spin_lock_irqsave(&desc->lock, flags); |
| 184 | desc->msi_desc = entry; | 181 | desc->msi_desc = entry; |
| 185 | if (entry) | 182 | if (entry) |
| @@ -197,10 +194,16 @@ int set_irq_msi(unsigned int irq, struct msi_desc *entry) | |||
| 197 | */ | 194 | */ |
| 198 | int set_irq_chip_data(unsigned int irq, void *data) | 195 | int set_irq_chip_data(unsigned int irq, void *data) |
| 199 | { | 196 | { |
| 200 | struct irq_desc *desc = irq_desc + irq; | 197 | struct irq_desc *desc = irq_to_desc(irq); |
| 201 | unsigned long flags; | 198 | unsigned long flags; |
| 202 | 199 | ||
| 203 | if (irq >= NR_IRQS || !desc->chip) { | 200 | if (!desc) { |
| 201 | printk(KERN_ERR | ||
| 202 | "Trying to install chip data for IRQ%d\n", irq); | ||
| 203 | return -EINVAL; | ||
| 204 | } | ||
| 205 | |||
| 206 | if (!desc->chip) { | ||
| 204 | printk(KERN_ERR "BUG: bad set_irq_chip_data(IRQ#%d)\n", irq); | 207 | printk(KERN_ERR "BUG: bad set_irq_chip_data(IRQ#%d)\n", irq); |
| 205 | return -EINVAL; | 208 | return -EINVAL; |
| 206 | } | 209 | } |
| @@ -218,7 +221,7 @@ EXPORT_SYMBOL(set_irq_chip_data); | |||
| 218 | */ | 221 | */ |
| 219 | static void default_enable(unsigned int irq) | 222 | static void default_enable(unsigned int irq) |
| 220 | { | 223 | { |
| 221 | struct irq_desc *desc = irq_desc + irq; | 224 | struct irq_desc *desc = irq_to_desc(irq); |
| 222 | 225 | ||
| 223 | desc->chip->unmask(irq); | 226 | desc->chip->unmask(irq); |
| 224 | desc->status &= ~IRQ_MASKED; | 227 | desc->status &= ~IRQ_MASKED; |
| @@ -236,8 +239,9 @@ static void default_disable(unsigned int irq) | |||
| 236 | */ | 239 | */ |
| 237 | static unsigned int default_startup(unsigned int irq) | 240 | static unsigned int default_startup(unsigned int irq) |
| 238 | { | 241 | { |
| 239 | irq_desc[irq].chip->enable(irq); | 242 | struct irq_desc *desc = irq_to_desc(irq); |
| 240 | 243 | ||
| 244 | desc->chip->enable(irq); | ||
| 241 | return 0; | 245 | return 0; |
| 242 | } | 246 | } |
| 243 | 247 | ||
| @@ -246,7 +250,7 @@ static unsigned int default_startup(unsigned int irq) | |||
| 246 | */ | 250 | */ |
| 247 | static void default_shutdown(unsigned int irq) | 251 | static void default_shutdown(unsigned int irq) |
| 248 | { | 252 | { |
| 249 | struct irq_desc *desc = irq_desc + irq; | 253 | struct irq_desc *desc = irq_to_desc(irq); |
| 250 | 254 | ||
| 251 | desc->chip->mask(irq); | 255 | desc->chip->mask(irq); |
| 252 | desc->status |= IRQ_MASKED; | 256 | desc->status |= IRQ_MASKED; |
| @@ -305,14 +309,13 @@ handle_simple_irq(unsigned int irq, struct irq_desc *desc) | |||
| 305 | { | 309 | { |
| 306 | struct irqaction *action; | 310 | struct irqaction *action; |
| 307 | irqreturn_t action_ret; | 311 | irqreturn_t action_ret; |
| 308 | const unsigned int cpu = smp_processor_id(); | ||
| 309 | 312 | ||
| 310 | spin_lock(&desc->lock); | 313 | spin_lock(&desc->lock); |
| 311 | 314 | ||
| 312 | if (unlikely(desc->status & IRQ_INPROGRESS)) | 315 | if (unlikely(desc->status & IRQ_INPROGRESS)) |
| 313 | goto out_unlock; | 316 | goto out_unlock; |
| 314 | desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); | 317 | desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); |
| 315 | kstat_cpu(cpu).irqs[irq]++; | 318 | kstat_incr_irqs_this_cpu(irq, desc); |
| 316 | 319 | ||
| 317 | action = desc->action; | 320 | action = desc->action; |
| 318 | if (unlikely(!action || (desc->status & IRQ_DISABLED))) | 321 | if (unlikely(!action || (desc->status & IRQ_DISABLED))) |
| @@ -344,7 +347,6 @@ out_unlock: | |||
| 344 | void | 347 | void |
| 345 | handle_level_irq(unsigned int irq, struct irq_desc *desc) | 348 | handle_level_irq(unsigned int irq, struct irq_desc *desc) |
| 346 | { | 349 | { |
| 347 | unsigned int cpu = smp_processor_id(); | ||
| 348 | struct irqaction *action; | 350 | struct irqaction *action; |
| 349 | irqreturn_t action_ret; | 351 | irqreturn_t action_ret; |
| 350 | 352 | ||
| @@ -354,7 +356,7 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc) | |||
| 354 | if (unlikely(desc->status & IRQ_INPROGRESS)) | 356 | if (unlikely(desc->status & IRQ_INPROGRESS)) |
| 355 | goto out_unlock; | 357 | goto out_unlock; |
| 356 | desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); | 358 | desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); |
| 357 | kstat_cpu(cpu).irqs[irq]++; | 359 | kstat_incr_irqs_this_cpu(irq, desc); |
| 358 | 360 | ||
| 359 | /* | 361 | /* |
| 360 | * If its disabled or no action available | 362 | * If its disabled or no action available |
| @@ -392,7 +394,6 @@ out_unlock: | |||
| 392 | void | 394 | void |
| 393 | handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) | 395 | handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) |
| 394 | { | 396 | { |
| 395 | unsigned int cpu = smp_processor_id(); | ||
| 396 | struct irqaction *action; | 397 | struct irqaction *action; |
| 397 | irqreturn_t action_ret; | 398 | irqreturn_t action_ret; |
| 398 | 399 | ||
| @@ -402,7 +403,7 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) | |||
| 402 | goto out; | 403 | goto out; |
| 403 | 404 | ||
| 404 | desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); | 405 | desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); |
| 405 | kstat_cpu(cpu).irqs[irq]++; | 406 | kstat_incr_irqs_this_cpu(irq, desc); |
| 406 | 407 | ||
| 407 | /* | 408 | /* |
| 408 | * If its disabled or no action available | 409 | * If its disabled or no action available |
| @@ -451,8 +452,6 @@ out: | |||
| 451 | void | 452 | void |
| 452 | handle_edge_irq(unsigned int irq, struct irq_desc *desc) | 453 | handle_edge_irq(unsigned int irq, struct irq_desc *desc) |
| 453 | { | 454 | { |
| 454 | const unsigned int cpu = smp_processor_id(); | ||
| 455 | |||
| 456 | spin_lock(&desc->lock); | 455 | spin_lock(&desc->lock); |
| 457 | 456 | ||
| 458 | desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); | 457 | desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); |
| @@ -468,8 +467,7 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) | |||
| 468 | mask_ack_irq(desc, irq); | 467 | mask_ack_irq(desc, irq); |
| 469 | goto out_unlock; | 468 | goto out_unlock; |
| 470 | } | 469 | } |
| 471 | 470 | kstat_incr_irqs_this_cpu(irq, desc); | |
| 472 | kstat_cpu(cpu).irqs[irq]++; | ||
| 473 | 471 | ||
| 474 | /* Start handling the irq */ | 472 | /* Start handling the irq */ |
| 475 | desc->chip->ack(irq); | 473 | desc->chip->ack(irq); |
| @@ -524,7 +522,7 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc) | |||
| 524 | { | 522 | { |
| 525 | irqreturn_t action_ret; | 523 | irqreturn_t action_ret; |
| 526 | 524 | ||
| 527 | kstat_this_cpu.irqs[irq]++; | 525 | kstat_incr_irqs_this_cpu(irq, desc); |
| 528 | 526 | ||
| 529 | if (desc->chip->ack) | 527 | if (desc->chip->ack) |
| 530 | desc->chip->ack(irq); | 528 | desc->chip->ack(irq); |
| @@ -541,17 +539,15 @@ void | |||
| 541 | __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, | 539 | __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, |
| 542 | const char *name) | 540 | const char *name) |
| 543 | { | 541 | { |
| 544 | struct irq_desc *desc; | 542 | struct irq_desc *desc = irq_to_desc(irq); |
| 545 | unsigned long flags; | 543 | unsigned long flags; |
| 546 | 544 | ||
| 547 | if (irq >= NR_IRQS) { | 545 | if (!desc) { |
| 548 | printk(KERN_ERR | 546 | printk(KERN_ERR |
| 549 | "Trying to install type control for IRQ%d\n", irq); | 547 | "Trying to install type control for IRQ%d\n", irq); |
| 550 | return; | 548 | return; |
| 551 | } | 549 | } |
| 552 | 550 | ||
| 553 | desc = irq_desc + irq; | ||
| 554 | |||
| 555 | if (!handle) | 551 | if (!handle) |
| 556 | handle = handle_bad_irq; | 552 | handle = handle_bad_irq; |
| 557 | else if (desc->chip == &no_irq_chip) { | 553 | else if (desc->chip == &no_irq_chip) { |
| @@ -583,7 +579,7 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, | |||
| 583 | desc->status &= ~IRQ_DISABLED; | 579 | desc->status &= ~IRQ_DISABLED; |
| 584 | desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE; | 580 | desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE; |
| 585 | desc->depth = 0; | 581 | desc->depth = 0; |
| 586 | desc->chip->unmask(irq); | 582 | desc->chip->startup(irq); |
| 587 | } | 583 | } |
| 588 | spin_unlock_irqrestore(&desc->lock, flags); | 584 | spin_unlock_irqrestore(&desc->lock, flags); |
| 589 | } | 585 | } |
| @@ -606,17 +602,14 @@ set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip, | |||
| 606 | 602 | ||
| 607 | void __init set_irq_noprobe(unsigned int irq) | 603 | void __init set_irq_noprobe(unsigned int irq) |
| 608 | { | 604 | { |
| 609 | struct irq_desc *desc; | 605 | struct irq_desc *desc = irq_to_desc(irq); |
| 610 | unsigned long flags; | 606 | unsigned long flags; |
| 611 | 607 | ||
| 612 | if (irq >= NR_IRQS) { | 608 | if (!desc) { |
| 613 | printk(KERN_ERR "Trying to mark IRQ%d non-probeable\n", irq); | 609 | printk(KERN_ERR "Trying to mark IRQ%d non-probeable\n", irq); |
| 614 | |||
| 615 | return; | 610 | return; |
| 616 | } | 611 | } |
| 617 | 612 | ||
| 618 | desc = irq_desc + irq; | ||
| 619 | |||
| 620 | spin_lock_irqsave(&desc->lock, flags); | 613 | spin_lock_irqsave(&desc->lock, flags); |
| 621 | desc->status |= IRQ_NOPROBE; | 614 | desc->status |= IRQ_NOPROBE; |
| 622 | spin_unlock_irqrestore(&desc->lock, flags); | 615 | spin_unlock_irqrestore(&desc->lock, flags); |
| @@ -624,17 +617,14 @@ void __init set_irq_noprobe(unsigned int irq) | |||
| 624 | 617 | ||
| 625 | void __init set_irq_probe(unsigned int irq) | 618 | void __init set_irq_probe(unsigned int irq) |
| 626 | { | 619 | { |
| 627 | struct irq_desc *desc; | 620 | struct irq_desc *desc = irq_to_desc(irq); |
| 628 | unsigned long flags; | 621 | unsigned long flags; |
| 629 | 622 | ||
| 630 | if (irq >= NR_IRQS) { | 623 | if (!desc) { |
| 631 | printk(KERN_ERR "Trying to mark IRQ%d probeable\n", irq); | 624 | printk(KERN_ERR "Trying to mark IRQ%d probeable\n", irq); |
| 632 | |||
| 633 | return; | 625 | return; |
| 634 | } | 626 | } |
| 635 | 627 | ||
| 636 | desc = irq_desc + irq; | ||
| 637 | |||
| 638 | spin_lock_irqsave(&desc->lock, flags); | 628 | spin_lock_irqsave(&desc->lock, flags); |
| 639 | desc->status &= ~IRQ_NOPROBE; | 629 | desc->status &= ~IRQ_NOPROBE; |
| 640 | spin_unlock_irqrestore(&desc->lock, flags); | 630 | spin_unlock_irqrestore(&desc->lock, flags); |
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 5fa6198e913..c815b42d0f5 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c | |||
| @@ -25,11 +25,10 @@ | |||
| 25 | * | 25 | * |
| 26 | * Handles spurious and unhandled IRQ's. It also prints a debugmessage. | 26 | * Handles spurious and unhandled IRQ's. It also prints a debugmessage. |
| 27 | */ | 27 | */ |
| 28 | void | 28 | void handle_bad_irq(unsigned int irq, struct irq_desc *desc) |
| 29 | handle_bad_irq(unsigned int irq, struct irq_desc *desc) | ||
| 30 | { | 29 | { |
| 31 | print_irq_desc(irq, desc); | 30 | print_irq_desc(irq, desc); |
| 32 | kstat_this_cpu.irqs[irq]++; | 31 | kstat_incr_irqs_this_cpu(irq, desc); |
| 33 | ack_bad_irq(irq); | 32 | ack_bad_irq(irq); |
| 34 | } | 33 | } |
| 35 | 34 | ||
| @@ -47,6 +46,9 @@ handle_bad_irq(unsigned int irq, struct irq_desc *desc) | |||
| 47 | * | 46 | * |
| 48 | * Controller mappings for all interrupt sources: | 47 | * Controller mappings for all interrupt sources: |
| 49 | */ | 48 | */ |
| 49 | int nr_irqs = NR_IRQS; | ||
| 50 | EXPORT_SYMBOL_GPL(nr_irqs); | ||
| 51 | |||
| 50 | struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = { | 52 | struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = { |
| 51 | [0 ... NR_IRQS-1] = { | 53 | [0 ... NR_IRQS-1] = { |
| 52 | .status = IRQ_DISABLED, | 54 | .status = IRQ_DISABLED, |
| @@ -66,7 +68,9 @@ struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = { | |||
| 66 | */ | 68 | */ |
| 67 | static void ack_bad(unsigned int irq) | 69 | static void ack_bad(unsigned int irq) |
| 68 | { | 70 | { |
| 69 | print_irq_desc(irq, irq_desc + irq); | 71 | struct irq_desc *desc = irq_to_desc(irq); |
| 72 | |||
| 73 | print_irq_desc(irq, desc); | ||
| 70 | ack_bad_irq(irq); | 74 | ack_bad_irq(irq); |
| 71 | } | 75 | } |
| 72 | 76 | ||
| @@ -131,8 +135,6 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action) | |||
| 131 | irqreturn_t ret, retval = IRQ_NONE; | 135 | irqreturn_t ret, retval = IRQ_NONE; |
| 132 | unsigned int status = 0; | 136 | unsigned int status = 0; |
| 133 | 137 | ||
| 134 | handle_dynamic_tick(action); | ||
| 135 | |||
| 136 | if (!(action->flags & IRQF_DISABLED)) | 138 | if (!(action->flags & IRQF_DISABLED)) |
| 137 | local_irq_enable_in_hardirq(); | 139 | local_irq_enable_in_hardirq(); |
| 138 | 140 | ||
| @@ -165,11 +167,12 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action) | |||
| 165 | */ | 167 | */ |
| 166 | unsigned int __do_IRQ(unsigned int irq) | 168 | unsigned int __do_IRQ(unsigned int irq) |
| 167 | { | 169 | { |
| 168 | struct irq_desc *desc = irq_desc + irq; | 170 | struct irq_desc *desc = irq_to_desc(irq); |
| 169 | struct irqaction *action; | 171 | struct irqaction *action; |
| 170 | unsigned int status; | 172 | unsigned int status; |
| 171 | 173 | ||
| 172 | kstat_this_cpu.irqs[irq]++; | 174 | kstat_incr_irqs_this_cpu(irq, desc); |
| 175 | |||
| 173 | if (CHECK_IRQ_PER_CPU(desc->status)) { | 176 | if (CHECK_IRQ_PER_CPU(desc->status)) { |
| 174 | irqreturn_t action_ret; | 177 | irqreturn_t action_ret; |
| 175 | 178 | ||
| @@ -256,8 +259,8 @@ out: | |||
| 256 | } | 259 | } |
| 257 | #endif | 260 | #endif |
| 258 | 261 | ||
| 259 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
| 260 | 262 | ||
| 263 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
| 261 | /* | 264 | /* |
| 262 | * lockdep: we want to handle all irq_desc locks as a single lock-class: | 265 | * lockdep: we want to handle all irq_desc locks as a single lock-class: |
| 263 | */ | 266 | */ |
| @@ -265,10 +268,10 @@ static struct lock_class_key irq_desc_lock_class; | |||
| 265 | 268 | ||
| 266 | void early_init_irq_lock_class(void) | 269 | void early_init_irq_lock_class(void) |
| 267 | { | 270 | { |
| 271 | struct irq_desc *desc; | ||
| 268 | int i; | 272 | int i; |
| 269 | 273 | ||
| 270 | for (i = 0; i < NR_IRQS; i++) | 274 | for_each_irq_desc(i, desc) |
| 271 | lockdep_set_class(&irq_desc[i].lock, &irq_desc_lock_class); | 275 | lockdep_set_class(&desc->lock, &irq_desc_lock_class); |
| 272 | } | 276 | } |
| 273 | |||
| 274 | #endif | 277 | #endif |
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 08a849a2244..c9767e64198 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h | |||
| @@ -10,12 +10,15 @@ extern void irq_chip_set_defaults(struct irq_chip *chip); | |||
| 10 | /* Set default handler: */ | 10 | /* Set default handler: */ |
| 11 | extern void compat_irq_chip_set_default_handler(struct irq_desc *desc); | 11 | extern void compat_irq_chip_set_default_handler(struct irq_desc *desc); |
| 12 | 12 | ||
| 13 | extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, | ||
| 14 | unsigned long flags); | ||
| 15 | |||
| 13 | #ifdef CONFIG_PROC_FS | 16 | #ifdef CONFIG_PROC_FS |
| 14 | extern void register_irq_proc(unsigned int irq); | 17 | extern void register_irq_proc(unsigned int irq, struct irq_desc *desc); |
| 15 | extern void register_handler_proc(unsigned int irq, struct irqaction *action); | 18 | extern void register_handler_proc(unsigned int irq, struct irqaction *action); |
| 16 | extern void unregister_handler_proc(unsigned int irq, struct irqaction *action); | 19 | extern void unregister_handler_proc(unsigned int irq, struct irqaction *action); |
| 17 | #else | 20 | #else |
| 18 | static inline void register_irq_proc(unsigned int irq) { } | 21 | static inline void register_irq_proc(unsigned int irq, struct irq_desc *desc) { } |
| 19 | static inline void register_handler_proc(unsigned int irq, | 22 | static inline void register_handler_proc(unsigned int irq, |
| 20 | struct irqaction *action) { } | 23 | struct irqaction *action) { } |
| 21 | static inline void unregister_handler_proc(unsigned int irq, | 24 | static inline void unregister_handler_proc(unsigned int irq, |
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 0314074fa23..c498a1b8c62 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
| @@ -31,10 +31,10 @@ cpumask_t irq_default_affinity = CPU_MASK_ALL; | |||
| 31 | */ | 31 | */ |
| 32 | void synchronize_irq(unsigned int irq) | 32 | void synchronize_irq(unsigned int irq) |
| 33 | { | 33 | { |
| 34 | struct irq_desc *desc = irq_desc + irq; | 34 | struct irq_desc *desc = irq_to_desc(irq); |
| 35 | unsigned int status; | 35 | unsigned int status; |
| 36 | 36 | ||
| 37 | if (irq >= NR_IRQS) | 37 | if (!desc) |
| 38 | return; | 38 | return; |
| 39 | 39 | ||
| 40 | do { | 40 | do { |
| @@ -64,7 +64,7 @@ EXPORT_SYMBOL(synchronize_irq); | |||
| 64 | */ | 64 | */ |
| 65 | int irq_can_set_affinity(unsigned int irq) | 65 | int irq_can_set_affinity(unsigned int irq) |
| 66 | { | 66 | { |
| 67 | struct irq_desc *desc = irq_desc + irq; | 67 | struct irq_desc *desc = irq_to_desc(irq); |
| 68 | 68 | ||
| 69 | if (CHECK_IRQ_PER_CPU(desc->status) || !desc->chip || | 69 | if (CHECK_IRQ_PER_CPU(desc->status) || !desc->chip || |
| 70 | !desc->chip->set_affinity) | 70 | !desc->chip->set_affinity) |
| @@ -81,15 +81,21 @@ int irq_can_set_affinity(unsigned int irq) | |||
| 81 | */ | 81 | */ |
| 82 | int irq_set_affinity(unsigned int irq, cpumask_t cpumask) | 82 | int irq_set_affinity(unsigned int irq, cpumask_t cpumask) |
| 83 | { | 83 | { |
| 84 | struct irq_desc *desc = irq_desc + irq; | 84 | struct irq_desc *desc = irq_to_desc(irq); |
| 85 | 85 | ||
| 86 | if (!desc->chip->set_affinity) | 86 | if (!desc->chip->set_affinity) |
| 87 | return -EINVAL; | 87 | return -EINVAL; |
| 88 | 88 | ||
| 89 | set_balance_irq_affinity(irq, cpumask); | ||
| 90 | |||
| 91 | #ifdef CONFIG_GENERIC_PENDING_IRQ | 89 | #ifdef CONFIG_GENERIC_PENDING_IRQ |
| 92 | set_pending_irq(irq, cpumask); | 90 | if (desc->status & IRQ_MOVE_PCNTXT || desc->status & IRQ_DISABLED) { |
| 91 | unsigned long flags; | ||
| 92 | |||
| 93 | spin_lock_irqsave(&desc->lock, flags); | ||
| 94 | desc->affinity = cpumask; | ||
| 95 | desc->chip->set_affinity(irq, cpumask); | ||
| 96 | spin_unlock_irqrestore(&desc->lock, flags); | ||
| 97 | } else | ||
| 98 | set_pending_irq(irq, cpumask); | ||
| 93 | #else | 99 | #else |
| 94 | desc->affinity = cpumask; | 100 | desc->affinity = cpumask; |
| 95 | desc->chip->set_affinity(irq, cpumask); | 101 | desc->chip->set_affinity(irq, cpumask); |
| @@ -104,16 +110,17 @@ int irq_set_affinity(unsigned int irq, cpumask_t cpumask) | |||
| 104 | int irq_select_affinity(unsigned int irq) | 110 | int irq_select_affinity(unsigned int irq) |
| 105 | { | 111 | { |
| 106 | cpumask_t mask; | 112 | cpumask_t mask; |
| 113 | struct irq_desc *desc; | ||
| 107 | 114 | ||
| 108 | if (!irq_can_set_affinity(irq)) | 115 | if (!irq_can_set_affinity(irq)) |
| 109 | return 0; | 116 | return 0; |
| 110 | 117 | ||
| 111 | cpus_and(mask, cpu_online_map, irq_default_affinity); | 118 | cpus_and(mask, cpu_online_map, irq_default_affinity); |
| 112 | 119 | ||
| 113 | irq_desc[irq].affinity = mask; | 120 | desc = irq_to_desc(irq); |
| 114 | irq_desc[irq].chip->set_affinity(irq, mask); | 121 | desc->affinity = mask; |
| 122 | desc->chip->set_affinity(irq, mask); | ||
| 115 | 123 | ||
| 116 | set_balance_irq_affinity(irq, mask); | ||
| 117 | return 0; | 124 | return 0; |
| 118 | } | 125 | } |
| 119 | #endif | 126 | #endif |
| @@ -133,10 +140,10 @@ int irq_select_affinity(unsigned int irq) | |||
| 133 | */ | 140 | */ |
| 134 | void disable_irq_nosync(unsigned int irq) | 141 | void disable_irq_nosync(unsigned int irq) |
| 135 | { | 142 | { |
| 136 | struct irq_desc *desc = irq_desc + irq; | 143 | struct irq_desc *desc = irq_to_desc(irq); |
| 137 | unsigned long flags; | 144 | unsigned long flags; |
| 138 | 145 | ||
| 139 | if (irq >= NR_IRQS) | 146 | if (!desc) |
| 140 | return; | 147 | return; |
| 141 | 148 | ||
| 142 | spin_lock_irqsave(&desc->lock, flags); | 149 | spin_lock_irqsave(&desc->lock, flags); |
| @@ -162,9 +169,9 @@ EXPORT_SYMBOL(disable_irq_nosync); | |||
| 162 | */ | 169 | */ |
| 163 | void disable_irq(unsigned int irq) | 170 | void disable_irq(unsigned int irq) |
| 164 | { | 171 | { |
| 165 | struct irq_desc *desc = irq_desc + irq; | 172 | struct irq_desc *desc = irq_to_desc(irq); |
| 166 | 173 | ||
| 167 | if (irq >= NR_IRQS) | 174 | if (!desc) |
| 168 | return; | 175 | return; |
| 169 | 176 | ||
| 170 | disable_irq_nosync(irq); | 177 | disable_irq_nosync(irq); |
| @@ -204,10 +211,10 @@ static void __enable_irq(struct irq_desc *desc, unsigned int irq) | |||
| 204 | */ | 211 | */ |
| 205 | void enable_irq(unsigned int irq) | 212 | void enable_irq(unsigned int irq) |
| 206 | { | 213 | { |
| 207 | struct irq_desc *desc = irq_desc + irq; | 214 | struct irq_desc *desc = irq_to_desc(irq); |
| 208 | unsigned long flags; | 215 | unsigned long flags; |
| 209 | 216 | ||
| 210 | if (irq >= NR_IRQS) | 217 | if (!desc) |
| 211 | return; | 218 | return; |
| 212 | 219 | ||
| 213 | spin_lock_irqsave(&desc->lock, flags); | 220 | spin_lock_irqsave(&desc->lock, flags); |
| @@ -216,9 +223,9 @@ void enable_irq(unsigned int irq) | |||
| 216 | } | 223 | } |
| 217 | EXPORT_SYMBOL(enable_irq); | 224 | EXPORT_SYMBOL(enable_irq); |
| 218 | 225 | ||
| 219 | int set_irq_wake_real(unsigned int irq, unsigned int on) | 226 | static int set_irq_wake_real(unsigned int irq, unsigned int on) |
| 220 | { | 227 | { |
| 221 | struct irq_desc *desc = irq_desc + irq; | 228 | struct irq_desc *desc = irq_to_desc(irq); |
| 222 | int ret = -ENXIO; | 229 | int ret = -ENXIO; |
| 223 | 230 | ||
| 224 | if (desc->chip->set_wake) | 231 | if (desc->chip->set_wake) |
| @@ -241,7 +248,7 @@ int set_irq_wake_real(unsigned int irq, unsigned int on) | |||
| 241 | */ | 248 | */ |
| 242 | int set_irq_wake(unsigned int irq, unsigned int on) | 249 | int set_irq_wake(unsigned int irq, unsigned int on) |
| 243 | { | 250 | { |
| 244 | struct irq_desc *desc = irq_desc + irq; | 251 | struct irq_desc *desc = irq_to_desc(irq); |
| 245 | unsigned long flags; | 252 | unsigned long flags; |
| 246 | int ret = 0; | 253 | int ret = 0; |
| 247 | 254 | ||
| @@ -281,12 +288,16 @@ EXPORT_SYMBOL(set_irq_wake); | |||
| 281 | */ | 288 | */ |
| 282 | int can_request_irq(unsigned int irq, unsigned long irqflags) | 289 | int can_request_irq(unsigned int irq, unsigned long irqflags) |
| 283 | { | 290 | { |
| 291 | struct irq_desc *desc = irq_to_desc(irq); | ||
| 284 | struct irqaction *action; | 292 | struct irqaction *action; |
| 285 | 293 | ||
| 286 | if (irq >= NR_IRQS || irq_desc[irq].status & IRQ_NOREQUEST) | 294 | if (!desc) |
| 295 | return 0; | ||
| 296 | |||
| 297 | if (desc->status & IRQ_NOREQUEST) | ||
| 287 | return 0; | 298 | return 0; |
| 288 | 299 | ||
| 289 | action = irq_desc[irq].action; | 300 | action = desc->action; |
| 290 | if (action) | 301 | if (action) |
| 291 | if (irqflags & action->flags & IRQF_SHARED) | 302 | if (irqflags & action->flags & IRQF_SHARED) |
| 292 | action = NULL; | 303 | action = NULL; |
| @@ -305,10 +316,11 @@ void compat_irq_chip_set_default_handler(struct irq_desc *desc) | |||
| 305 | desc->handle_irq = NULL; | 316 | desc->handle_irq = NULL; |
| 306 | } | 317 | } |
| 307 | 318 | ||
| 308 | static int __irq_set_trigger(struct irq_chip *chip, unsigned int irq, | 319 | int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, |
| 309 | unsigned long flags) | 320 | unsigned long flags) |
| 310 | { | 321 | { |
| 311 | int ret; | 322 | int ret; |
| 323 | struct irq_chip *chip = desc->chip; | ||
| 312 | 324 | ||
| 313 | if (!chip || !chip->set_type) { | 325 | if (!chip || !chip->set_type) { |
| 314 | /* | 326 | /* |
| @@ -326,6 +338,11 @@ static int __irq_set_trigger(struct irq_chip *chip, unsigned int irq, | |||
| 326 | pr_err("setting trigger mode %d for irq %u failed (%pF)\n", | 338 | pr_err("setting trigger mode %d for irq %u failed (%pF)\n", |
| 327 | (int)(flags & IRQF_TRIGGER_MASK), | 339 | (int)(flags & IRQF_TRIGGER_MASK), |
| 328 | irq, chip->set_type); | 340 | irq, chip->set_type); |
| 341 | else { | ||
| 342 | /* note that IRQF_TRIGGER_MASK == IRQ_TYPE_SENSE_MASK */ | ||
| 343 | desc->status &= ~IRQ_TYPE_SENSE_MASK; | ||
| 344 | desc->status |= flags & IRQ_TYPE_SENSE_MASK; | ||
| 345 | } | ||
| 329 | 346 | ||
| 330 | return ret; | 347 | return ret; |
| 331 | } | 348 | } |
| @@ -334,16 +351,16 @@ static int __irq_set_trigger(struct irq_chip *chip, unsigned int irq, | |||
| 334 | * Internal function to register an irqaction - typically used to | 351 | * Internal function to register an irqaction - typically used to |
| 335 | * allocate special interrupts that are part of the architecture. | 352 | * allocate special interrupts that are part of the architecture. |
| 336 | */ | 353 | */ |
| 337 | int setup_irq(unsigned int irq, struct irqaction *new) | 354 | static int |
| 355 | __setup_irq(unsigned int irq, struct irq_desc * desc, struct irqaction *new) | ||
| 338 | { | 356 | { |
| 339 | struct irq_desc *desc = irq_desc + irq; | ||
| 340 | struct irqaction *old, **p; | 357 | struct irqaction *old, **p; |
| 341 | const char *old_name = NULL; | 358 | const char *old_name = NULL; |
| 342 | unsigned long flags; | 359 | unsigned long flags; |
| 343 | int shared = 0; | 360 | int shared = 0; |
| 344 | int ret; | 361 | int ret; |
| 345 | 362 | ||
| 346 | if (irq >= NR_IRQS) | 363 | if (!desc) |
| 347 | return -EINVAL; | 364 | return -EINVAL; |
| 348 | 365 | ||
| 349 | if (desc->chip == &no_irq_chip) | 366 | if (desc->chip == &no_irq_chip) |
| @@ -404,7 +421,7 @@ int setup_irq(unsigned int irq, struct irqaction *new) | |||
| 404 | 421 | ||
| 405 | /* Setup the type (level, edge polarity) if configured: */ | 422 | /* Setup the type (level, edge polarity) if configured: */ |
| 406 | if (new->flags & IRQF_TRIGGER_MASK) { | 423 | if (new->flags & IRQF_TRIGGER_MASK) { |
| 407 | ret = __irq_set_trigger(desc->chip, irq, new->flags); | 424 | ret = __irq_set_trigger(desc, irq, new->flags); |
| 408 | 425 | ||
| 409 | if (ret) { | 426 | if (ret) { |
| 410 | spin_unlock_irqrestore(&desc->lock, flags); | 427 | spin_unlock_irqrestore(&desc->lock, flags); |
| @@ -423,16 +440,21 @@ int setup_irq(unsigned int irq, struct irqaction *new) | |||
| 423 | if (!(desc->status & IRQ_NOAUTOEN)) { | 440 | if (!(desc->status & IRQ_NOAUTOEN)) { |
| 424 | desc->depth = 0; | 441 | desc->depth = 0; |
| 425 | desc->status &= ~IRQ_DISABLED; | 442 | desc->status &= ~IRQ_DISABLED; |
| 426 | if (desc->chip->startup) | 443 | desc->chip->startup(irq); |
| 427 | desc->chip->startup(irq); | ||
| 428 | else | ||
| 429 | desc->chip->enable(irq); | ||
| 430 | } else | 444 | } else |
| 431 | /* Undo nested disables: */ | 445 | /* Undo nested disables: */ |
| 432 | desc->depth = 1; | 446 | desc->depth = 1; |
| 433 | 447 | ||
| 434 | /* Set default affinity mask once everything is setup */ | 448 | /* Set default affinity mask once everything is setup */ |
| 435 | irq_select_affinity(irq); | 449 | irq_select_affinity(irq); |
| 450 | |||
| 451 | } else if ((new->flags & IRQF_TRIGGER_MASK) | ||
| 452 | && (new->flags & IRQF_TRIGGER_MASK) | ||
| 453 | != (desc->status & IRQ_TYPE_SENSE_MASK)) { | ||
| 454 | /* hope the handler works with the actual trigger mode... */ | ||
| 455 | pr_warning("IRQ %d uses trigger mode %d; requested %d\n", | ||
| 456 | irq, (int)(desc->status & IRQ_TYPE_SENSE_MASK), | ||
| 457 | (int)(new->flags & IRQF_TRIGGER_MASK)); | ||
| 436 | } | 458 | } |
| 437 | 459 | ||
| 438 | *p = new; | 460 | *p = new; |
| @@ -457,7 +479,7 @@ int setup_irq(unsigned int irq, struct irqaction *new) | |||
| 457 | spin_unlock_irqrestore(&desc->lock, flags); | 479 | spin_unlock_irqrestore(&desc->lock, flags); |
| 458 | 480 | ||
| 459 | new->irq = irq; | 481 | new->irq = irq; |
| 460 | register_irq_proc(irq); | 482 | register_irq_proc(irq, desc); |
| 461 | new->dir = NULL; | 483 | new->dir = NULL; |
| 462 | register_handler_proc(irq, new); | 484 | register_handler_proc(irq, new); |
| 463 | 485 | ||
| @@ -477,6 +499,20 @@ mismatch: | |||
| 477 | } | 499 | } |
| 478 | 500 | ||
| 479 | /** | 501 | /** |
| 502 | * setup_irq - setup an interrupt | ||
| 503 | * @irq: Interrupt line to setup | ||
| 504 | * @act: irqaction for the interrupt | ||
| 505 | * | ||
| 506 | * Used to statically setup interrupts in the early boot process. | ||
| 507 | */ | ||
| 508 | int setup_irq(unsigned int irq, struct irqaction *act) | ||
| 509 | { | ||
| 510 | struct irq_desc *desc = irq_to_desc(irq); | ||
| 511 | |||
| 512 | return __setup_irq(irq, desc, act); | ||
| 513 | } | ||
| 514 | |||
| 515 | /** | ||
| 480 | * free_irq - free an interrupt | 516 | * free_irq - free an interrupt |
| 481 | * @irq: Interrupt line to free | 517 | * @irq: Interrupt line to free |
| 482 | * @dev_id: Device identity to free | 518 | * @dev_id: Device identity to free |
| @@ -492,15 +528,15 @@ mismatch: | |||
| 492 | */ | 528 | */ |
| 493 | void free_irq(unsigned int irq, void *dev_id) | 529 | void free_irq(unsigned int irq, void *dev_id) |
| 494 | { | 530 | { |
| 495 | struct irq_desc *desc; | 531 | struct irq_desc *desc = irq_to_desc(irq); |
| 496 | struct irqaction **p; | 532 | struct irqaction **p; |
| 497 | unsigned long flags; | 533 | unsigned long flags; |
| 498 | 534 | ||
| 499 | WARN_ON(in_interrupt()); | 535 | WARN_ON(in_interrupt()); |
| 500 | if (irq >= NR_IRQS) | 536 | |
| 537 | if (!desc) | ||
| 501 | return; | 538 | return; |
| 502 | 539 | ||
| 503 | desc = irq_desc + irq; | ||
| 504 | spin_lock_irqsave(&desc->lock, flags); | 540 | spin_lock_irqsave(&desc->lock, flags); |
| 505 | p = &desc->action; | 541 | p = &desc->action; |
| 506 | for (;;) { | 542 | for (;;) { |
| @@ -589,12 +625,14 @@ EXPORT_SYMBOL(free_irq); | |||
| 589 | * IRQF_SHARED Interrupt is shared | 625 | * IRQF_SHARED Interrupt is shared |
| 590 | * IRQF_DISABLED Disable local interrupts while processing | 626 | * IRQF_DISABLED Disable local interrupts while processing |
| 591 | * IRQF_SAMPLE_RANDOM The interrupt can be used for entropy | 627 | * IRQF_SAMPLE_RANDOM The interrupt can be used for entropy |
| 628 | * IRQF_TRIGGER_* Specify active edge(s) or level | ||
| 592 | * | 629 | * |
| 593 | */ | 630 | */ |
| 594 | int request_irq(unsigned int irq, irq_handler_t handler, | 631 | int request_irq(unsigned int irq, irq_handler_t handler, |
| 595 | unsigned long irqflags, const char *devname, void *dev_id) | 632 | unsigned long irqflags, const char *devname, void *dev_id) |
| 596 | { | 633 | { |
| 597 | struct irqaction *action; | 634 | struct irqaction *action; |
| 635 | struct irq_desc *desc; | ||
| 598 | int retval; | 636 | int retval; |
| 599 | 637 | ||
| 600 | #ifdef CONFIG_LOCKDEP | 638 | #ifdef CONFIG_LOCKDEP |
| @@ -611,9 +649,12 @@ int request_irq(unsigned int irq, irq_handler_t handler, | |||
| 611 | */ | 649 | */ |
| 612 | if ((irqflags & IRQF_SHARED) && !dev_id) | 650 | if ((irqflags & IRQF_SHARED) && !dev_id) |
| 613 | return -EINVAL; | 651 | return -EINVAL; |
| 614 | if (irq >= NR_IRQS) | 652 | |
| 653 | desc = irq_to_desc(irq); | ||
| 654 | if (!desc) | ||
| 615 | return -EINVAL; | 655 | return -EINVAL; |
| 616 | if (irq_desc[irq].status & IRQ_NOREQUEST) | 656 | |
| 657 | if (desc->status & IRQ_NOREQUEST) | ||
| 617 | return -EINVAL; | 658 | return -EINVAL; |
| 618 | if (!handler) | 659 | if (!handler) |
| 619 | return -EINVAL; | 660 | return -EINVAL; |
| @@ -629,26 +670,29 @@ int request_irq(unsigned int irq, irq_handler_t handler, | |||
| 629 | action->next = NULL; | 670 | action->next = NULL; |
| 630 | action->dev_id = dev_id; | 671 | action->dev_id = dev_id; |
| 631 | 672 | ||
| 673 | retval = __setup_irq(irq, desc, action); | ||
| 674 | if (retval) | ||
| 675 | kfree(action); | ||
| 676 | |||
| 632 | #ifdef CONFIG_DEBUG_SHIRQ | 677 | #ifdef CONFIG_DEBUG_SHIRQ |
| 633 | if (irqflags & IRQF_SHARED) { | 678 | if (irqflags & IRQF_SHARED) { |
| 634 | /* | 679 | /* |
| 635 | * It's a shared IRQ -- the driver ought to be prepared for it | 680 | * It's a shared IRQ -- the driver ought to be prepared for it |
| 636 | * to happen immediately, so let's make sure.... | 681 | * to happen immediately, so let's make sure.... |
| 637 | * We do this before actually registering it, to make sure that | 682 | * We disable the irq to make sure that a 'real' IRQ doesn't |
| 638 | * a 'real' IRQ doesn't run in parallel with our fake | 683 | * run in parallel with our fake. |
| 639 | */ | 684 | */ |
| 640 | unsigned long flags; | 685 | unsigned long flags; |
| 641 | 686 | ||
| 687 | disable_irq(irq); | ||
| 642 | local_irq_save(flags); | 688 | local_irq_save(flags); |
| 689 | |||
| 643 | handler(irq, dev_id); | 690 | handler(irq, dev_id); |
| 691 | |||
| 644 | local_irq_restore(flags); | 692 | local_irq_restore(flags); |
| 693 | enable_irq(irq); | ||
| 645 | } | 694 | } |
| 646 | #endif | 695 | #endif |
| 647 | |||
| 648 | retval = setup_irq(irq, action); | ||
| 649 | if (retval) | ||
| 650 | kfree(action); | ||
| 651 | |||
| 652 | return retval; | 696 | return retval; |
| 653 | } | 697 | } |
| 654 | EXPORT_SYMBOL(request_irq); | 698 | EXPORT_SYMBOL(request_irq); |
diff --git a/kernel/irq/migration.c b/kernel/irq/migration.c index 77b7acc875c..90b920d3f52 100644 --- a/kernel/irq/migration.c +++ b/kernel/irq/migration.c | |||
| @@ -3,18 +3,18 @@ | |||
| 3 | 3 | ||
| 4 | void set_pending_irq(unsigned int irq, cpumask_t mask) | 4 | void set_pending_irq(unsigned int irq, cpumask_t mask) |
| 5 | { | 5 | { |
| 6 | struct irq_desc *desc = irq_desc + irq; | 6 | struct irq_desc *desc = irq_to_desc(irq); |
| 7 | unsigned long flags; | 7 | unsigned long flags; |
| 8 | 8 | ||
| 9 | spin_lock_irqsave(&desc->lock, flags); | 9 | spin_lock_irqsave(&desc->lock, flags); |
| 10 | desc->status |= IRQ_MOVE_PENDING; | 10 | desc->status |= IRQ_MOVE_PENDING; |
| 11 | irq_desc[irq].pending_mask = mask; | 11 | desc->pending_mask = mask; |
| 12 | spin_unlock_irqrestore(&desc->lock, flags); | 12 | spin_unlock_irqrestore(&desc->lock, flags); |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | void move_masked_irq(int irq) | 15 | void move_masked_irq(int irq) |
| 16 | { | 16 | { |
| 17 | struct irq_desc *desc = irq_desc + irq; | 17 | struct irq_desc *desc = irq_to_desc(irq); |
| 18 | cpumask_t tmp; | 18 | cpumask_t tmp; |
| 19 | 19 | ||
| 20 | if (likely(!(desc->status & IRQ_MOVE_PENDING))) | 20 | if (likely(!(desc->status & IRQ_MOVE_PENDING))) |
| @@ -30,7 +30,7 @@ void move_masked_irq(int irq) | |||
| 30 | 30 | ||
| 31 | desc->status &= ~IRQ_MOVE_PENDING; | 31 | desc->status &= ~IRQ_MOVE_PENDING; |
| 32 | 32 | ||
| 33 | if (unlikely(cpus_empty(irq_desc[irq].pending_mask))) | 33 | if (unlikely(cpus_empty(desc->pending_mask))) |
| 34 | return; | 34 | return; |
| 35 | 35 | ||
| 36 | if (!desc->chip->set_affinity) | 36 | if (!desc->chip->set_affinity) |
| @@ -38,7 +38,7 @@ void move_masked_irq(int irq) | |||
| 38 | 38 | ||
| 39 | assert_spin_locked(&desc->lock); | 39 | assert_spin_locked(&desc->lock); |
| 40 | 40 | ||
| 41 | cpus_and(tmp, irq_desc[irq].pending_mask, cpu_online_map); | 41 | cpus_and(tmp, desc->pending_mask, cpu_online_map); |
| 42 | 42 | ||
| 43 | /* | 43 | /* |
| 44 | * If there was a valid mask to work with, please | 44 | * If there was a valid mask to work with, please |
| @@ -55,12 +55,12 @@ void move_masked_irq(int irq) | |||
| 55 | if (likely(!cpus_empty(tmp))) { | 55 | if (likely(!cpus_empty(tmp))) { |
| 56 | desc->chip->set_affinity(irq,tmp); | 56 | desc->chip->set_affinity(irq,tmp); |
| 57 | } | 57 | } |
| 58 | cpus_clear(irq_desc[irq].pending_mask); | 58 | cpus_clear(desc->pending_mask); |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | void move_native_irq(int irq) | 61 | void move_native_irq(int irq) |
| 62 | { | 62 | { |
| 63 | struct irq_desc *desc = irq_desc + irq; | 63 | struct irq_desc *desc = irq_to_desc(irq); |
| 64 | 64 | ||
| 65 | if (likely(!(desc->status & IRQ_MOVE_PENDING))) | 65 | if (likely(!(desc->status & IRQ_MOVE_PENDING))) |
| 66 | return; | 66 | return; |
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index a09dd29c2fd..4d161c70ba5 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c | |||
| @@ -19,7 +19,7 @@ static struct proc_dir_entry *root_irq_dir; | |||
| 19 | 19 | ||
| 20 | static int irq_affinity_proc_show(struct seq_file *m, void *v) | 20 | static int irq_affinity_proc_show(struct seq_file *m, void *v) |
| 21 | { | 21 | { |
| 22 | struct irq_desc *desc = irq_desc + (long)m->private; | 22 | struct irq_desc *desc = irq_to_desc((long)m->private); |
| 23 | cpumask_t *mask = &desc->affinity; | 23 | cpumask_t *mask = &desc->affinity; |
| 24 | 24 | ||
| 25 | #ifdef CONFIG_GENERIC_PENDING_IRQ | 25 | #ifdef CONFIG_GENERIC_PENDING_IRQ |
| @@ -43,7 +43,7 @@ static ssize_t irq_affinity_proc_write(struct file *file, | |||
| 43 | cpumask_t new_value; | 43 | cpumask_t new_value; |
| 44 | int err; | 44 | int err; |
| 45 | 45 | ||
| 46 | if (!irq_desc[irq].chip->set_affinity || no_irq_affinity || | 46 | if (!irq_to_desc(irq)->chip->set_affinity || no_irq_affinity || |
| 47 | irq_balancing_disabled(irq)) | 47 | irq_balancing_disabled(irq)) |
| 48 | return -EIO; | 48 | return -EIO; |
| 49 | 49 | ||
| @@ -132,20 +132,20 @@ static const struct file_operations default_affinity_proc_fops = { | |||
| 132 | static int irq_spurious_read(char *page, char **start, off_t off, | 132 | static int irq_spurious_read(char *page, char **start, off_t off, |
| 133 | int count, int *eof, void *data) | 133 | int count, int *eof, void *data) |
| 134 | { | 134 | { |
| 135 | struct irq_desc *d = &irq_desc[(long) data]; | 135 | struct irq_desc *desc = irq_to_desc((long) data); |
| 136 | return sprintf(page, "count %u\n" | 136 | return sprintf(page, "count %u\n" |
| 137 | "unhandled %u\n" | 137 | "unhandled %u\n" |
| 138 | "last_unhandled %u ms\n", | 138 | "last_unhandled %u ms\n", |
| 139 | d->irq_count, | 139 | desc->irq_count, |
| 140 | d->irqs_unhandled, | 140 | desc->irqs_unhandled, |
| 141 | jiffies_to_msecs(d->last_unhandled)); | 141 | jiffies_to_msecs(desc->last_unhandled)); |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | #define MAX_NAMELEN 128 | 144 | #define MAX_NAMELEN 128 |
| 145 | 145 | ||
| 146 | static int name_unique(unsigned int irq, struct irqaction *new_action) | 146 | static int name_unique(unsigned int irq, struct irqaction *new_action) |
| 147 | { | 147 | { |
| 148 | struct irq_desc *desc = irq_desc + irq; | 148 | struct irq_desc *desc = irq_to_desc(irq); |
| 149 | struct irqaction *action; | 149 | struct irqaction *action; |
| 150 | unsigned long flags; | 150 | unsigned long flags; |
| 151 | int ret = 1; | 151 | int ret = 1; |
| @@ -165,8 +165,9 @@ static int name_unique(unsigned int irq, struct irqaction *new_action) | |||
| 165 | void register_handler_proc(unsigned int irq, struct irqaction *action) | 165 | void register_handler_proc(unsigned int irq, struct irqaction *action) |
| 166 | { | 166 | { |
| 167 | char name [MAX_NAMELEN]; | 167 | char name [MAX_NAMELEN]; |
| 168 | struct irq_desc *desc = irq_to_desc(irq); | ||
| 168 | 169 | ||
| 169 | if (!irq_desc[irq].dir || action->dir || !action->name || | 170 | if (!desc->dir || action->dir || !action->name || |
| 170 | !name_unique(irq, action)) | 171 | !name_unique(irq, action)) |
| 171 | return; | 172 | return; |
| 172 | 173 | ||
| @@ -174,36 +175,34 @@ void register_handler_proc(unsigned int irq, struct irqaction *action) | |||
| 174 | snprintf(name, MAX_NAMELEN, "%s", action->name); | 175 | snprintf(name, MAX_NAMELEN, "%s", action->name); |
| 175 | 176 | ||
| 176 | /* create /proc/irq/1234/handler/ */ | 177 | /* create /proc/irq/1234/handler/ */ |
| 177 | action->dir = proc_mkdir(name, irq_desc[irq].dir); | 178 | action->dir = proc_mkdir(name, desc->dir); |
| 178 | } | 179 | } |
| 179 | 180 | ||
| 180 | #undef MAX_NAMELEN | 181 | #undef MAX_NAMELEN |
| 181 | 182 | ||
| 182 | #define MAX_NAMELEN 10 | 183 | #define MAX_NAMELEN 10 |
| 183 | 184 | ||
| 184 | void register_irq_proc(unsigned int irq) | 185 | void register_irq_proc(unsigned int irq, struct irq_desc *desc) |
| 185 | { | 186 | { |
| 186 | char name [MAX_NAMELEN]; | 187 | char name [MAX_NAMELEN]; |
| 187 | struct proc_dir_entry *entry; | 188 | struct proc_dir_entry *entry; |
| 188 | 189 | ||
| 189 | if (!root_irq_dir || | 190 | if (!root_irq_dir || (desc->chip == &no_irq_chip) || desc->dir) |
| 190 | (irq_desc[irq].chip == &no_irq_chip) || | ||
| 191 | irq_desc[irq].dir) | ||
| 192 | return; | 191 | return; |
| 193 | 192 | ||
| 194 | memset(name, 0, MAX_NAMELEN); | 193 | memset(name, 0, MAX_NAMELEN); |
| 195 | sprintf(name, "%d", irq); | 194 | sprintf(name, "%d", irq); |
| 196 | 195 | ||
| 197 | /* create /proc/irq/1234 */ | 196 | /* create /proc/irq/1234 */ |
| 198 | irq_desc[irq].dir = proc_mkdir(name, root_irq_dir); | 197 | desc->dir = proc_mkdir(name, root_irq_dir); |
| 199 | 198 | ||
| 200 | #ifdef CONFIG_SMP | 199 | #ifdef CONFIG_SMP |
| 201 | /* create /proc/irq/<irq>/smp_affinity */ | 200 | /* create /proc/irq/<irq>/smp_affinity */ |
| 202 | proc_create_data("smp_affinity", 0600, irq_desc[irq].dir, | 201 | proc_create_data("smp_affinity", 0600, desc->dir, |
| 203 | &irq_affinity_proc_fops, (void *)(long)irq); | 202 | &irq_affinity_proc_fops, (void *)(long)irq); |
| 204 | #endif | 203 | #endif |
| 205 | 204 | ||
| 206 | entry = create_proc_entry("spurious", 0444, irq_desc[irq].dir); | 205 | entry = create_proc_entry("spurious", 0444, desc->dir); |
| 207 | if (entry) { | 206 | if (entry) { |
| 208 | entry->data = (void *)(long)irq; | 207 | entry->data = (void *)(long)irq; |
| 209 | entry->read_proc = irq_spurious_read; | 208 | entry->read_proc = irq_spurious_read; |
| @@ -214,11 +213,14 @@ void register_irq_proc(unsigned int irq) | |||
| 214 | 213 | ||
| 215 | void unregister_handler_proc(unsigned int irq, struct irqaction *action) | 214 | void unregister_handler_proc(unsigned int irq, struct irqaction *action) |
| 216 | { | 215 | { |
| 217 | if (action->dir) | 216 | if (action->dir) { |
| 218 | remove_proc_entry(action->dir->name, irq_desc[irq].dir); | 217 | struct irq_desc *desc = irq_to_desc(irq); |
| 218 | |||
| 219 | remove_proc_entry(action->dir->name, desc->dir); | ||
| 220 | } | ||
| 219 | } | 221 | } |
| 220 | 222 | ||
| 221 | void register_default_affinity_proc(void) | 223 | static void register_default_affinity_proc(void) |
| 222 | { | 224 | { |
| 223 | #ifdef CONFIG_SMP | 225 | #ifdef CONFIG_SMP |
| 224 | proc_create("irq/default_smp_affinity", 0600, NULL, | 226 | proc_create("irq/default_smp_affinity", 0600, NULL, |
| @@ -228,7 +230,8 @@ void register_default_affinity_proc(void) | |||
| 228 | 230 | ||
| 229 | void init_irq_proc(void) | 231 | void init_irq_proc(void) |
| 230 | { | 232 | { |
| 231 | int i; | 233 | unsigned int irq; |
| 234 | struct irq_desc *desc; | ||
| 232 | 235 | ||
| 233 | /* create /proc/irq */ | 236 | /* create /proc/irq */ |
| 234 | root_irq_dir = proc_mkdir("irq", NULL); | 237 | root_irq_dir = proc_mkdir("irq", NULL); |
| @@ -240,7 +243,7 @@ void init_irq_proc(void) | |||
| 240 | /* | 243 | /* |
| 241 | * Create entries for all existing IRQs. | 244 | * Create entries for all existing IRQs. |
| 242 | */ | 245 | */ |
| 243 | for (i = 0; i < NR_IRQS; i++) | 246 | for_each_irq_desc(irq, desc) |
| 244 | register_irq_proc(i); | 247 | register_irq_proc(irq, desc); |
| 245 | } | 248 | } |
| 246 | 249 | ||
diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c index a8046791ba2..89c7117acf2 100644 --- a/kernel/irq/resend.c +++ b/kernel/irq/resend.c | |||
| @@ -33,10 +33,10 @@ static void resend_irqs(unsigned long arg) | |||
| 33 | struct irq_desc *desc; | 33 | struct irq_desc *desc; |
| 34 | int irq; | 34 | int irq; |
| 35 | 35 | ||
| 36 | while (!bitmap_empty(irqs_resend, NR_IRQS)) { | 36 | while (!bitmap_empty(irqs_resend, nr_irqs)) { |
| 37 | irq = find_first_bit(irqs_resend, NR_IRQS); | 37 | irq = find_first_bit(irqs_resend, nr_irqs); |
| 38 | clear_bit(irq, irqs_resend); | 38 | clear_bit(irq, irqs_resend); |
| 39 | desc = irq_desc + irq; | 39 | desc = irq_to_desc(irq); |
| 40 | local_irq_disable(); | 40 | local_irq_disable(); |
| 41 | desc->handle_irq(irq, desc); | 41 | desc->handle_irq(irq, desc); |
| 42 | local_irq_enable(); | 42 | local_irq_enable(); |
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c index c66d3f10e85..dd364c11e56 100644 --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c | |||
| @@ -12,83 +12,122 @@ | |||
| 12 | #include <linux/kallsyms.h> | 12 | #include <linux/kallsyms.h> |
| 13 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
| 14 | #include <linux/moduleparam.h> | 14 | #include <linux/moduleparam.h> |
| 15 | #include <linux/timer.h> | ||
| 15 | 16 | ||
| 16 | static int irqfixup __read_mostly; | 17 | static int irqfixup __read_mostly; |
| 17 | 18 | ||
| 19 | #define POLL_SPURIOUS_IRQ_INTERVAL (HZ/10) | ||
| 20 | static void poll_spurious_irqs(unsigned long dummy); | ||
| 21 | static DEFINE_TIMER(poll_spurious_irq_timer, poll_spurious_irqs, 0, 0); | ||
| 22 | |||
| 18 | /* | 23 | /* |
| 19 | * Recovery handler for misrouted interrupts. | 24 | * Recovery handler for misrouted interrupts. |
| 20 | */ | 25 | */ |
| 21 | static int misrouted_irq(int irq) | 26 | static int try_one_irq(int irq, struct irq_desc *desc) |
| 22 | { | 27 | { |
| 23 | int i; | 28 | struct irqaction *action; |
| 24 | int ok = 0; | 29 | int ok = 0, work = 0; |
| 25 | int work = 0; /* Did we do work for a real IRQ */ | ||
| 26 | |||
| 27 | for (i = 1; i < NR_IRQS; i++) { | ||
| 28 | struct irq_desc *desc = irq_desc + i; | ||
| 29 | struct irqaction *action; | ||
| 30 | |||
| 31 | if (i == irq) /* Already tried */ | ||
| 32 | continue; | ||
| 33 | 30 | ||
| 34 | spin_lock(&desc->lock); | 31 | spin_lock(&desc->lock); |
| 35 | /* Already running on another processor */ | 32 | /* Already running on another processor */ |
| 36 | if (desc->status & IRQ_INPROGRESS) { | 33 | if (desc->status & IRQ_INPROGRESS) { |
| 37 | /* | 34 | /* |
| 38 | * Already running: If it is shared get the other | 35 | * Already running: If it is shared get the other |
| 39 | * CPU to go looking for our mystery interrupt too | 36 | * CPU to go looking for our mystery interrupt too |
| 40 | */ | 37 | */ |
| 41 | if (desc->action && (desc->action->flags & IRQF_SHARED)) | 38 | if (desc->action && (desc->action->flags & IRQF_SHARED)) |
| 42 | desc->status |= IRQ_PENDING; | 39 | desc->status |= IRQ_PENDING; |
| 43 | spin_unlock(&desc->lock); | ||
| 44 | continue; | ||
| 45 | } | ||
| 46 | /* Honour the normal IRQ locking */ | ||
| 47 | desc->status |= IRQ_INPROGRESS; | ||
| 48 | action = desc->action; | ||
| 49 | spin_unlock(&desc->lock); | 40 | spin_unlock(&desc->lock); |
| 41 | return ok; | ||
| 42 | } | ||
| 43 | /* Honour the normal IRQ locking */ | ||
| 44 | desc->status |= IRQ_INPROGRESS; | ||
| 45 | action = desc->action; | ||
| 46 | spin_unlock(&desc->lock); | ||
| 50 | 47 | ||
| 51 | while (action) { | 48 | while (action) { |
| 52 | /* Only shared IRQ handlers are safe to call */ | 49 | /* Only shared IRQ handlers are safe to call */ |
| 53 | if (action->flags & IRQF_SHARED) { | 50 | if (action->flags & IRQF_SHARED) { |
| 54 | if (action->handler(i, action->dev_id) == | 51 | if (action->handler(irq, action->dev_id) == |
| 55 | IRQ_HANDLED) | 52 | IRQ_HANDLED) |
| 56 | ok = 1; | 53 | ok = 1; |
| 57 | } | ||
| 58 | action = action->next; | ||
| 59 | } | 54 | } |
| 60 | local_irq_disable(); | 55 | action = action->next; |
| 61 | /* Now clean up the flags */ | 56 | } |
| 62 | spin_lock(&desc->lock); | 57 | local_irq_disable(); |
| 63 | action = desc->action; | 58 | /* Now clean up the flags */ |
| 59 | spin_lock(&desc->lock); | ||
| 60 | action = desc->action; | ||
| 64 | 61 | ||
| 62 | /* | ||
| 63 | * While we were looking for a fixup someone queued a real | ||
| 64 | * IRQ clashing with our walk: | ||
| 65 | */ | ||
| 66 | while ((desc->status & IRQ_PENDING) && action) { | ||
| 65 | /* | 67 | /* |
| 66 | * While we were looking for a fixup someone queued a real | 68 | * Perform real IRQ processing for the IRQ we deferred |
| 67 | * IRQ clashing with our walk: | ||
| 68 | */ | ||
| 69 | while ((desc->status & IRQ_PENDING) && action) { | ||
| 70 | /* | ||
| 71 | * Perform real IRQ processing for the IRQ we deferred | ||
| 72 | */ | ||
| 73 | work = 1; | ||
| 74 | spin_unlock(&desc->lock); | ||
| 75 | handle_IRQ_event(i, action); | ||
| 76 | spin_lock(&desc->lock); | ||
| 77 | desc->status &= ~IRQ_PENDING; | ||
| 78 | } | ||
| 79 | desc->status &= ~IRQ_INPROGRESS; | ||
| 80 | /* | ||
| 81 | * If we did actual work for the real IRQ line we must let the | ||
| 82 | * IRQ controller clean up too | ||
| 83 | */ | 69 | */ |
| 84 | if (work && desc->chip && desc->chip->end) | 70 | work = 1; |
| 85 | desc->chip->end(i); | ||
| 86 | spin_unlock(&desc->lock); | 71 | spin_unlock(&desc->lock); |
| 72 | handle_IRQ_event(irq, action); | ||
| 73 | spin_lock(&desc->lock); | ||
| 74 | desc->status &= ~IRQ_PENDING; | ||
| 75 | } | ||
| 76 | desc->status &= ~IRQ_INPROGRESS; | ||
| 77 | /* | ||
| 78 | * If we did actual work for the real IRQ line we must let the | ||
| 79 | * IRQ controller clean up too | ||
| 80 | */ | ||
| 81 | if (work && desc->chip && desc->chip->end) | ||
| 82 | desc->chip->end(irq); | ||
| 83 | spin_unlock(&desc->lock); | ||
| 84 | |||
| 85 | return ok; | ||
| 86 | } | ||
| 87 | |||
| 88 | static int misrouted_irq(int irq) | ||
| 89 | { | ||
| 90 | struct irq_desc *desc; | ||
| 91 | int i, ok = 0; | ||
| 92 | |||
| 93 | for_each_irq_desc(i, desc) { | ||
| 94 | if (!i) | ||
| 95 | continue; | ||
| 96 | |||
| 97 | if (i == irq) /* Already tried */ | ||
| 98 | continue; | ||
| 99 | |||
| 100 | if (try_one_irq(i, desc)) | ||
| 101 | ok = 1; | ||
| 87 | } | 102 | } |
| 88 | /* So the caller can adjust the irq error counts */ | 103 | /* So the caller can adjust the irq error counts */ |
| 89 | return ok; | 104 | return ok; |
| 90 | } | 105 | } |
| 91 | 106 | ||
| 107 | static void poll_spurious_irqs(unsigned long dummy) | ||
| 108 | { | ||
| 109 | struct irq_desc *desc; | ||
| 110 | int i; | ||
| 111 | |||
| 112 | for_each_irq_desc(i, desc) { | ||
| 113 | unsigned int status; | ||
| 114 | |||
| 115 | if (!i) | ||
| 116 | continue; | ||
| 117 | |||
| 118 | /* Racy but it doesn't matter */ | ||
| 119 | status = desc->status; | ||
| 120 | barrier(); | ||
| 121 | if (!(status & IRQ_SPURIOUS_DISABLED)) | ||
| 122 | continue; | ||
| 123 | |||
| 124 | try_one_irq(i, desc); | ||
| 125 | } | ||
| 126 | |||
| 127 | mod_timer(&poll_spurious_irq_timer, | ||
| 128 | jiffies + POLL_SPURIOUS_IRQ_INTERVAL); | ||
| 129 | } | ||
| 130 | |||
| 92 | /* | 131 | /* |
| 93 | * If 99,900 of the previous 100,000 interrupts have not been handled | 132 | * If 99,900 of the previous 100,000 interrupts have not been handled |
| 94 | * then assume that the IRQ is stuck in some manner. Drop a diagnostic | 133 | * then assume that the IRQ is stuck in some manner. Drop a diagnostic |
| @@ -137,7 +176,9 @@ report_bad_irq(unsigned int irq, struct irq_desc *desc, irqreturn_t action_ret) | |||
| 137 | } | 176 | } |
| 138 | } | 177 | } |
| 139 | 178 | ||
| 140 | static inline int try_misrouted_irq(unsigned int irq, struct irq_desc *desc, irqreturn_t action_ret) | 179 | static inline int |
| 180 | try_misrouted_irq(unsigned int irq, struct irq_desc *desc, | ||
| 181 | irqreturn_t action_ret) | ||
| 141 | { | 182 | { |
| 142 | struct irqaction *action; | 183 | struct irqaction *action; |
| 143 | 184 | ||
| @@ -212,6 +253,9 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc, | |||
| 212 | desc->status |= IRQ_DISABLED | IRQ_SPURIOUS_DISABLED; | 253 | desc->status |= IRQ_DISABLED | IRQ_SPURIOUS_DISABLED; |
| 213 | desc->depth++; | 254 | desc->depth++; |
| 214 | desc->chip->disable(irq); | 255 | desc->chip->disable(irq); |
| 256 | |||
| 257 | mod_timer(&poll_spurious_irq_timer, | ||
| 258 | jiffies + POLL_SPURIOUS_IRQ_INTERVAL); | ||
| 215 | } | 259 | } |
| 216 | desc->irqs_unhandled = 0; | 260 | desc->irqs_unhandled = 0; |
| 217 | } | 261 | } |
| @@ -241,7 +285,7 @@ static int __init irqfixup_setup(char *str) | |||
| 241 | 285 | ||
| 242 | __setup("irqfixup", irqfixup_setup); | 286 | __setup("irqfixup", irqfixup_setup); |
| 243 | module_param(irqfixup, int, 0644); | 287 | module_param(irqfixup, int, 0644); |
| 244 | MODULE_PARM_DESC("irqfixup", "0: No fixup, 1: irqfixup mode 2: irqpoll mode"); | 288 | MODULE_PARM_DESC("irqfixup", "0: No fixup, 1: irqfixup mode, 2: irqpoll mode"); |
| 245 | 289 | ||
| 246 | static int __init irqpoll_setup(char *str) | 290 | static int __init irqpoll_setup(char *str) |
| 247 | { | 291 | { |
