aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq/manage.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/irq/manage.c')
-rw-r--r--kernel/irq/manage.c103
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}
225EXPORT_SYMBOL(enable_irq); 225EXPORT_SYMBOL(enable_irq);
226 226
227int 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
318static 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;