diff options
Diffstat (limited to 'kernel/irq/manage.c')
-rw-r--r-- | kernel/irq/manage.c | 103 |
1 files changed, 69 insertions, 34 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 909b2231fa93..63b93a935565 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
@@ -224,6 +224,17 @@ void enable_irq(unsigned int irq) | |||
224 | } | 224 | } |
225 | EXPORT_SYMBOL(enable_irq); | 225 | EXPORT_SYMBOL(enable_irq); |
226 | 226 | ||
227 | int set_irq_wake_real(unsigned int irq, unsigned int on) | ||
228 | { | ||
229 | struct irq_desc *desc = irq_desc + irq; | ||
230 | int ret = -ENXIO; | ||
231 | |||
232 | if (desc->chip->set_wake) | ||
233 | ret = desc->chip->set_wake(irq, on); | ||
234 | |||
235 | return ret; | ||
236 | } | ||
237 | |||
227 | /** | 238 | /** |
228 | * set_irq_wake - control irq power management wakeup | 239 | * set_irq_wake - control irq power management wakeup |
229 | * @irq: interrupt to control | 240 | * @irq: interrupt to control |
@@ -240,30 +251,34 @@ int set_irq_wake(unsigned int irq, unsigned int on) | |||
240 | { | 251 | { |
241 | struct irq_desc *desc = irq_desc + irq; | 252 | struct irq_desc *desc = irq_desc + irq; |
242 | unsigned long flags; | 253 | unsigned long flags; |
243 | int ret = -ENXIO; | 254 | int ret = 0; |
244 | int (*set_wake)(unsigned, unsigned) = desc->chip->set_wake; | ||
245 | 255 | ||
246 | /* wakeup-capable irqs can be shared between drivers that | 256 | /* wakeup-capable irqs can be shared between drivers that |
247 | * don't need to have the same sleep mode behaviors. | 257 | * don't need to have the same sleep mode behaviors. |
248 | */ | 258 | */ |
249 | spin_lock_irqsave(&desc->lock, flags); | 259 | spin_lock_irqsave(&desc->lock, flags); |
250 | if (on) { | 260 | if (on) { |
251 | if (desc->wake_depth++ == 0) | 261 | if (desc->wake_depth++ == 0) { |
252 | desc->status |= IRQ_WAKEUP; | 262 | ret = set_irq_wake_real(irq, on); |
253 | else | 263 | if (ret) |
254 | set_wake = NULL; | 264 | desc->wake_depth = 0; |
265 | else | ||
266 | desc->status |= IRQ_WAKEUP; | ||
267 | } | ||
255 | } else { | 268 | } else { |
256 | if (desc->wake_depth == 0) { | 269 | if (desc->wake_depth == 0) { |
257 | printk(KERN_WARNING "Unbalanced IRQ %d " | 270 | printk(KERN_WARNING "Unbalanced IRQ %d " |
258 | "wake disable\n", irq); | 271 | "wake disable\n", irq); |
259 | WARN_ON(1); | 272 | WARN_ON(1); |
260 | } else if (--desc->wake_depth == 0) | 273 | } else if (--desc->wake_depth == 0) { |
261 | desc->status &= ~IRQ_WAKEUP; | 274 | ret = set_irq_wake_real(irq, on); |
262 | else | 275 | if (ret) |
263 | set_wake = NULL; | 276 | desc->wake_depth = 1; |
277 | else | ||
278 | desc->status &= ~IRQ_WAKEUP; | ||
279 | } | ||
264 | } | 280 | } |
265 | if (set_wake) | 281 | |
266 | ret = desc->chip->set_wake(irq, on); | ||
267 | spin_unlock_irqrestore(&desc->lock, flags); | 282 | spin_unlock_irqrestore(&desc->lock, flags); |
268 | return ret; | 283 | return ret; |
269 | } | 284 | } |
@@ -300,6 +315,30 @@ void compat_irq_chip_set_default_handler(struct irq_desc *desc) | |||
300 | desc->handle_irq = NULL; | 315 | desc->handle_irq = NULL; |
301 | } | 316 | } |
302 | 317 | ||
318 | static int __irq_set_trigger(struct irq_chip *chip, unsigned int irq, | ||
319 | unsigned long flags) | ||
320 | { | ||
321 | int ret; | ||
322 | |||
323 | if (!chip || !chip->set_type) { | ||
324 | /* | ||
325 | * IRQF_TRIGGER_* but the PIC does not support multiple | ||
326 | * flow-types? | ||
327 | */ | ||
328 | pr_warning("No set_type function for IRQ %d (%s)\n", irq, | ||
329 | chip ? (chip->name ? : "unknown") : "unknown"); | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | ret = chip->set_type(irq, flags & IRQF_TRIGGER_MASK); | ||
334 | |||
335 | if (ret) | ||
336 | pr_err("setting flow type for irq %u failed (%pF)\n", | ||
337 | irq, chip->set_type); | ||
338 | |||
339 | return ret; | ||
340 | } | ||
341 | |||
303 | /* | 342 | /* |
304 | * Internal function to register an irqaction - typically used to | 343 | * Internal function to register an irqaction - typically used to |
305 | * allocate special interrupts that are part of the architecture. | 344 | * allocate special interrupts that are part of the architecture. |
@@ -311,6 +350,7 @@ int setup_irq(unsigned int irq, struct irqaction *new) | |||
311 | const char *old_name = NULL; | 350 | const char *old_name = NULL; |
312 | unsigned long flags; | 351 | unsigned long flags; |
313 | int shared = 0; | 352 | int shared = 0; |
353 | int ret; | ||
314 | 354 | ||
315 | if (irq >= NR_IRQS) | 355 | if (irq >= NR_IRQS) |
316 | return -EINVAL; | 356 | return -EINVAL; |
@@ -368,35 +408,23 @@ int setup_irq(unsigned int irq, struct irqaction *new) | |||
368 | shared = 1; | 408 | shared = 1; |
369 | } | 409 | } |
370 | 410 | ||
371 | *p = new; | ||
372 | |||
373 | /* Exclude IRQ from balancing */ | ||
374 | if (new->flags & IRQF_NOBALANCING) | ||
375 | desc->status |= IRQ_NO_BALANCING; | ||
376 | |||
377 | if (!shared) { | 411 | if (!shared) { |
378 | irq_chip_set_defaults(desc->chip); | 412 | irq_chip_set_defaults(desc->chip); |
379 | 413 | ||
380 | #if defined(CONFIG_IRQ_PER_CPU) | ||
381 | if (new->flags & IRQF_PERCPU) | ||
382 | desc->status |= IRQ_PER_CPU; | ||
383 | #endif | ||
384 | |||
385 | /* Setup the type (level, edge polarity) if configured: */ | 414 | /* Setup the type (level, edge polarity) if configured: */ |
386 | if (new->flags & IRQF_TRIGGER_MASK) { | 415 | if (new->flags & IRQF_TRIGGER_MASK) { |
387 | if (desc->chip->set_type) | 416 | ret = __irq_set_trigger(desc->chip, irq, new->flags); |
388 | desc->chip->set_type(irq, | 417 | |
389 | new->flags & IRQF_TRIGGER_MASK); | 418 | if (ret) { |
390 | else | 419 | spin_unlock_irqrestore(&desc->lock, flags); |
391 | /* | 420 | return ret; |
392 | * IRQF_TRIGGER_* but the PIC does not support | 421 | } |
393 | * multiple flow-types? | ||
394 | */ | ||
395 | printk(KERN_WARNING "No IRQF_TRIGGER set_type " | ||
396 | "function for IRQ %d (%s)\n", irq, | ||
397 | desc->chip->name); | ||
398 | } else | 422 | } else |
399 | compat_irq_chip_set_default_handler(desc); | 423 | compat_irq_chip_set_default_handler(desc); |
424 | #if defined(CONFIG_IRQ_PER_CPU) | ||
425 | if (new->flags & IRQF_PERCPU) | ||
426 | desc->status |= IRQ_PER_CPU; | ||
427 | #endif | ||
400 | 428 | ||
401 | desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | | 429 | desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | |
402 | IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED); | 430 | IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED); |
@@ -415,6 +443,13 @@ int setup_irq(unsigned int irq, struct irqaction *new) | |||
415 | /* Set default affinity mask once everything is setup */ | 443 | /* Set default affinity mask once everything is setup */ |
416 | irq_select_affinity(irq); | 444 | irq_select_affinity(irq); |
417 | } | 445 | } |
446 | |||
447 | *p = new; | ||
448 | |||
449 | /* Exclude IRQ from balancing */ | ||
450 | if (new->flags & IRQF_NOBALANCING) | ||
451 | desc->status |= IRQ_NO_BALANCING; | ||
452 | |||
418 | /* Reset broken irq detection when installing new handler */ | 453 | /* Reset broken irq detection when installing new handler */ |
419 | desc->irq_count = 0; | 454 | desc->irq_count = 0; |
420 | desc->irqs_unhandled = 0; | 455 | desc->irqs_unhandled = 0; |