diff options
Diffstat (limited to 'kernel/irq/manage.c')
| -rw-r--r-- | kernel/irq/manage.c | 235 | 
1 files changed, 222 insertions, 13 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 0a7840aeb0fb..67ce837ae52c 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c  | |||
| @@ -195,7 +195,7 @@ int irq_set_affinity(unsigned int irq, const struct cpumask *mask) | |||
| 195 | int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m) | 195 | int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m) | 
| 196 | { | 196 | { | 
| 197 | unsigned long flags; | 197 | unsigned long flags; | 
| 198 | struct irq_desc *desc = irq_get_desc_lock(irq, &flags); | 198 | struct irq_desc *desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL); | 
| 199 | 199 | ||
| 200 | if (!desc) | 200 | if (!desc) | 
| 201 | return -EINVAL; | 201 | return -EINVAL; | 
| @@ -356,7 +356,7 @@ void __disable_irq(struct irq_desc *desc, unsigned int irq, bool suspend) | |||
| 356 | static int __disable_irq_nosync(unsigned int irq) | 356 | static int __disable_irq_nosync(unsigned int irq) | 
| 357 | { | 357 | { | 
| 358 | unsigned long flags; | 358 | unsigned long flags; | 
| 359 | struct irq_desc *desc = irq_get_desc_buslock(irq, &flags); | 359 | struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL); | 
| 360 | 360 | ||
| 361 | if (!desc) | 361 | if (!desc) | 
| 362 | return -EINVAL; | 362 | return -EINVAL; | 
| @@ -448,7 +448,7 @@ void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume) | |||
| 448 | void enable_irq(unsigned int irq) | 448 | void enable_irq(unsigned int irq) | 
| 449 | { | 449 | { | 
| 450 | unsigned long flags; | 450 | unsigned long flags; | 
| 451 | struct irq_desc *desc = irq_get_desc_buslock(irq, &flags); | 451 | struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL); | 
| 452 | 452 | ||
| 453 | if (!desc) | 453 | if (!desc) | 
| 454 | return; | 454 | return; | 
| @@ -467,6 +467,9 @@ static int set_irq_wake_real(unsigned int irq, unsigned int on) | |||
| 467 | struct irq_desc *desc = irq_to_desc(irq); | 467 | struct irq_desc *desc = irq_to_desc(irq); | 
| 468 | int ret = -ENXIO; | 468 | int ret = -ENXIO; | 
| 469 | 469 | ||
| 470 | if (irq_desc_get_chip(desc)->flags & IRQCHIP_SKIP_SET_WAKE) | ||
| 471 | return 0; | ||
| 472 | |||
| 470 | if (desc->irq_data.chip->irq_set_wake) | 473 | if (desc->irq_data.chip->irq_set_wake) | 
| 471 | ret = desc->irq_data.chip->irq_set_wake(&desc->irq_data, on); | 474 | ret = desc->irq_data.chip->irq_set_wake(&desc->irq_data, on); | 
| 472 | 475 | ||
| @@ -488,7 +491,7 @@ static int set_irq_wake_real(unsigned int irq, unsigned int on) | |||
| 488 | int irq_set_irq_wake(unsigned int irq, unsigned int on) | 491 | int irq_set_irq_wake(unsigned int irq, unsigned int on) | 
| 489 | { | 492 | { | 
| 490 | unsigned long flags; | 493 | unsigned long flags; | 
| 491 | struct irq_desc *desc = irq_get_desc_buslock(irq, &flags); | 494 | struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL); | 
| 492 | int ret = 0; | 495 | int ret = 0; | 
| 493 | 496 | ||
| 494 | if (!desc) | 497 | if (!desc) | 
| @@ -529,7 +532,7 @@ EXPORT_SYMBOL(irq_set_irq_wake); | |||
| 529 | int can_request_irq(unsigned int irq, unsigned long irqflags) | 532 | int can_request_irq(unsigned int irq, unsigned long irqflags) | 
| 530 | { | 533 | { | 
| 531 | unsigned long flags; | 534 | unsigned long flags; | 
| 532 | struct irq_desc *desc = irq_get_desc_lock(irq, &flags); | 535 | struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); | 
| 533 | int canrequest = 0; | 536 | int canrequest = 0; | 
| 534 | 537 | ||
| 535 | if (!desc) | 538 | if (!desc) | 
| @@ -883,6 +886,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
| 883 | 886 | ||
| 884 | if (desc->irq_data.chip == &no_irq_chip) | 887 | if (desc->irq_data.chip == &no_irq_chip) | 
| 885 | return -ENOSYS; | 888 | return -ENOSYS; | 
| 889 | if (!try_module_get(desc->owner)) | ||
| 890 | return -ENODEV; | ||
| 886 | /* | 891 | /* | 
| 887 | * Some drivers like serial.c use request_irq() heavily, | 892 | * Some drivers like serial.c use request_irq() heavily, | 
| 888 | * so we have to be careful not to interfere with a | 893 | * so we have to be careful not to interfere with a | 
| @@ -906,8 +911,10 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
| 906 | */ | 911 | */ | 
| 907 | nested = irq_settings_is_nested_thread(desc); | 912 | nested = irq_settings_is_nested_thread(desc); | 
| 908 | if (nested) { | 913 | if (nested) { | 
| 909 | if (!new->thread_fn) | 914 | if (!new->thread_fn) { | 
| 910 | return -EINVAL; | 915 | ret = -EINVAL; | 
| 916 | goto out_mput; | ||
| 917 | } | ||
| 911 | /* | 918 | /* | 
| 912 | * Replace the primary handler which was provided from | 919 | * Replace the primary handler which was provided from | 
| 913 | * the driver for non nested interrupt handling by the | 920 | * the driver for non nested interrupt handling by the | 
| @@ -929,8 +936,10 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
| 929 | 936 | ||
| 930 | t = kthread_create(irq_thread, new, "irq/%d-%s", irq, | 937 | t = kthread_create(irq_thread, new, "irq/%d-%s", irq, | 
| 931 | new->name); | 938 | new->name); | 
| 932 | if (IS_ERR(t)) | 939 | if (IS_ERR(t)) { | 
| 933 | return PTR_ERR(t); | 940 | ret = PTR_ERR(t); | 
| 941 | goto out_mput; | ||
| 942 | } | ||
| 934 | /* | 943 | /* | 
| 935 | * We keep the reference to the task struct even if | 944 | * We keep the reference to the task struct even if | 
| 936 | * the thread dies to avoid that the interrupt code | 945 | * the thread dies to avoid that the interrupt code | 
| @@ -1095,6 +1104,8 @@ out_thread: | |||
| 1095 | kthread_stop(t); | 1104 | kthread_stop(t); | 
| 1096 | put_task_struct(t); | 1105 | put_task_struct(t); | 
| 1097 | } | 1106 | } | 
| 1107 | out_mput: | ||
| 1108 | module_put(desc->owner); | ||
| 1098 | return ret; | 1109 | return ret; | 
| 1099 | } | 1110 | } | 
| 1100 | 1111 | ||
| @@ -1110,6 +1121,8 @@ int setup_irq(unsigned int irq, struct irqaction *act) | |||
| 1110 | int retval; | 1121 | int retval; | 
| 1111 | struct irq_desc *desc = irq_to_desc(irq); | 1122 | struct irq_desc *desc = irq_to_desc(irq); | 
| 1112 | 1123 | ||
| 1124 | if (WARN_ON(irq_settings_is_per_cpu_devid(desc))) | ||
| 1125 | return -EINVAL; | ||
| 1113 | chip_bus_lock(desc); | 1126 | chip_bus_lock(desc); | 
| 1114 | retval = __setup_irq(irq, desc, act); | 1127 | retval = __setup_irq(irq, desc, act); | 
| 1115 | chip_bus_sync_unlock(desc); | 1128 | chip_bus_sync_unlock(desc); | 
| @@ -1118,7 +1131,7 @@ int setup_irq(unsigned int irq, struct irqaction *act) | |||
| 1118 | } | 1131 | } | 
| 1119 | EXPORT_SYMBOL_GPL(setup_irq); | 1132 | EXPORT_SYMBOL_GPL(setup_irq); | 
| 1120 | 1133 | ||
| 1121 | /* | 1134 | /* | 
| 1122 | * Internal function to unregister an irqaction - used to free | 1135 | * Internal function to unregister an irqaction - used to free | 
| 1123 | * regular and special interrupts that are part of the architecture. | 1136 | * regular and special interrupts that are part of the architecture. | 
| 1124 | */ | 1137 | */ | 
| @@ -1203,6 +1216,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) | |||
| 1203 | put_task_struct(action->thread); | 1216 | put_task_struct(action->thread); | 
| 1204 | } | 1217 | } | 
| 1205 | 1218 | ||
| 1219 | module_put(desc->owner); | ||
| 1206 | return action; | 1220 | return action; | 
| 1207 | } | 1221 | } | 
| 1208 | 1222 | ||
| @@ -1215,7 +1229,10 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) | |||
| 1215 | */ | 1229 | */ | 
| 1216 | void remove_irq(unsigned int irq, struct irqaction *act) | 1230 | void remove_irq(unsigned int irq, struct irqaction *act) | 
| 1217 | { | 1231 | { | 
| 1218 | __free_irq(irq, act->dev_id); | 1232 | struct irq_desc *desc = irq_to_desc(irq); | 
| 1233 | |||
| 1234 | if (desc && !WARN_ON(irq_settings_is_per_cpu_devid(desc))) | ||
| 1235 | __free_irq(irq, act->dev_id); | ||
| 1219 | } | 1236 | } | 
| 1220 | EXPORT_SYMBOL_GPL(remove_irq); | 1237 | EXPORT_SYMBOL_GPL(remove_irq); | 
| 1221 | 1238 | ||
| @@ -1237,7 +1254,7 @@ void free_irq(unsigned int irq, void *dev_id) | |||
| 1237 | { | 1254 | { | 
| 1238 | struct irq_desc *desc = irq_to_desc(irq); | 1255 | struct irq_desc *desc = irq_to_desc(irq); | 
| 1239 | 1256 | ||
| 1240 | if (!desc) | 1257 | if (!desc || WARN_ON(irq_settings_is_per_cpu_devid(desc))) | 
| 1241 | return; | 1258 | return; | 
| 1242 | 1259 | ||
| 1243 | #ifdef CONFIG_SMP | 1260 | #ifdef CONFIG_SMP | 
| @@ -1315,7 +1332,8 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler, | |||
| 1315 | if (!desc) | 1332 | if (!desc) | 
| 1316 | return -EINVAL; | 1333 | return -EINVAL; | 
| 1317 | 1334 | ||
| 1318 | if (!irq_settings_can_request(desc)) | 1335 | if (!irq_settings_can_request(desc) || | 
| 1336 | WARN_ON(irq_settings_is_per_cpu_devid(desc))) | ||
| 1319 | return -EINVAL; | 1337 | return -EINVAL; | 
| 1320 | 1338 | ||
| 1321 | if (!handler) { | 1339 | if (!handler) { | 
| @@ -1400,3 +1418,194 @@ int request_any_context_irq(unsigned int irq, irq_handler_t handler, | |||
| 1400 | return !ret ? IRQC_IS_HARDIRQ : ret; | 1418 | return !ret ? IRQC_IS_HARDIRQ : ret; | 
| 1401 | } | 1419 | } | 
| 1402 | EXPORT_SYMBOL_GPL(request_any_context_irq); | 1420 | EXPORT_SYMBOL_GPL(request_any_context_irq); | 
| 1421 | |||
| 1422 | void enable_percpu_irq(unsigned int irq, unsigned int type) | ||
| 1423 | { | ||
| 1424 | unsigned int cpu = smp_processor_id(); | ||
| 1425 | unsigned long flags; | ||
| 1426 | struct irq_desc *desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_PERCPU); | ||
| 1427 | |||
| 1428 | if (!desc) | ||
| 1429 | return; | ||
| 1430 | |||
| 1431 | type &= IRQ_TYPE_SENSE_MASK; | ||
| 1432 | if (type != IRQ_TYPE_NONE) { | ||
| 1433 | int ret; | ||
| 1434 | |||
| 1435 | ret = __irq_set_trigger(desc, irq, type); | ||
| 1436 | |||
| 1437 | if (ret) { | ||
| 1438 | WARN(1, "failed to set type for IRQ%d\n", irq); | ||
| 1439 | goto out; | ||
| 1440 | } | ||
| 1441 | } | ||
| 1442 | |||
| 1443 | irq_percpu_enable(desc, cpu); | ||
| 1444 | out: | ||
| 1445 | irq_put_desc_unlock(desc, flags); | ||
| 1446 | } | ||
| 1447 | |||
| 1448 | void disable_percpu_irq(unsigned int irq) | ||
| 1449 | { | ||
| 1450 | unsigned int cpu = smp_processor_id(); | ||
| 1451 | unsigned long flags; | ||
| 1452 | struct irq_desc *desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_PERCPU); | ||
| 1453 | |||
| 1454 | if (!desc) | ||
| 1455 | return; | ||
| 1456 | |||
| 1457 | irq_percpu_disable(desc, cpu); | ||
| 1458 | irq_put_desc_unlock(desc, flags); | ||
| 1459 | } | ||
| 1460 | |||
| 1461 | /* | ||
| 1462 | * Internal function to unregister a percpu irqaction. | ||
| 1463 | */ | ||
| 1464 | static struct irqaction *__free_percpu_irq(unsigned int irq, void __percpu *dev_id) | ||
| 1465 | { | ||
| 1466 | struct irq_desc *desc = irq_to_desc(irq); | ||
| 1467 | struct irqaction *action; | ||
| 1468 | unsigned long flags; | ||
| 1469 | |||
| 1470 | WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq); | ||
| 1471 | |||
| 1472 | if (!desc) | ||
| 1473 | return NULL; | ||
| 1474 | |||
| 1475 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
| 1476 | |||
| 1477 | action = desc->action; | ||
| 1478 | if (!action || action->percpu_dev_id != dev_id) { | ||
| 1479 | WARN(1, "Trying to free already-free IRQ %d\n", irq); | ||
| 1480 | goto bad; | ||
| 1481 | } | ||
| 1482 | |||
| 1483 | if (!cpumask_empty(desc->percpu_enabled)) { | ||
| 1484 | WARN(1, "percpu IRQ %d still enabled on CPU%d!\n", | ||
| 1485 | irq, cpumask_first(desc->percpu_enabled)); | ||
| 1486 | goto bad; | ||
| 1487 | } | ||
| 1488 | |||
| 1489 | /* Found it - now remove it from the list of entries: */ | ||
| 1490 | desc->action = NULL; | ||
| 1491 | |||
| 1492 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
| 1493 | |||
| 1494 | unregister_handler_proc(irq, action); | ||
| 1495 | |||
| 1496 | module_put(desc->owner); | ||
| 1497 | return action; | ||
| 1498 | |||
| 1499 | bad: | ||
| 1500 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
| 1501 | return NULL; | ||
| 1502 | } | ||
| 1503 | |||
| 1504 | /** | ||
| 1505 | * remove_percpu_irq - free a per-cpu interrupt | ||
| 1506 | * @irq: Interrupt line to free | ||
| 1507 | * @act: irqaction for the interrupt | ||
| 1508 | * | ||
| 1509 | * Used to remove interrupts statically setup by the early boot process. | ||
| 1510 | */ | ||
| 1511 | void remove_percpu_irq(unsigned int irq, struct irqaction *act) | ||
| 1512 | { | ||
| 1513 | struct irq_desc *desc = irq_to_desc(irq); | ||
| 1514 | |||
| 1515 | if (desc && irq_settings_is_per_cpu_devid(desc)) | ||
| 1516 | __free_percpu_irq(irq, act->percpu_dev_id); | ||
| 1517 | } | ||
| 1518 | |||
| 1519 | /** | ||
| 1520 | * free_percpu_irq - free an interrupt allocated with request_percpu_irq | ||
| 1521 | * @irq: Interrupt line to free | ||
| 1522 | * @dev_id: Device identity to free | ||
| 1523 | * | ||
| 1524 | * Remove a percpu interrupt handler. The handler is removed, but | ||
| 1525 | * the interrupt line is not disabled. This must be done on each | ||
| 1526 | * CPU before calling this function. The function does not return | ||
| 1527 | * until any executing interrupts for this IRQ have completed. | ||
| 1528 | * | ||
| 1529 | * This function must not be called from interrupt context. | ||
| 1530 | */ | ||
| 1531 | void free_percpu_irq(unsigned int irq, void __percpu *dev_id) | ||
| 1532 | { | ||
| 1533 | struct irq_desc *desc = irq_to_desc(irq); | ||
| 1534 | |||
| 1535 | if (!desc || !irq_settings_is_per_cpu_devid(desc)) | ||
| 1536 | return; | ||
| 1537 | |||
| 1538 | chip_bus_lock(desc); | ||
| 1539 | kfree(__free_percpu_irq(irq, dev_id)); | ||
| 1540 | chip_bus_sync_unlock(desc); | ||
| 1541 | } | ||
| 1542 | |||
| 1543 | /** | ||
| 1544 | * setup_percpu_irq - setup a per-cpu interrupt | ||
| 1545 | * @irq: Interrupt line to setup | ||
| 1546 | * @act: irqaction for the interrupt | ||
| 1547 | * | ||
| 1548 | * Used to statically setup per-cpu interrupts in the early boot process. | ||
| 1549 | */ | ||
| 1550 | int setup_percpu_irq(unsigned int irq, struct irqaction *act) | ||
| 1551 | { | ||
| 1552 | struct irq_desc *desc = irq_to_desc(irq); | ||
| 1553 | int retval; | ||
| 1554 | |||
| 1555 | if (!desc || !irq_settings_is_per_cpu_devid(desc)) | ||
| 1556 | return -EINVAL; | ||
| 1557 | chip_bus_lock(desc); | ||
| 1558 | retval = __setup_irq(irq, desc, act); | ||
| 1559 | chip_bus_sync_unlock(desc); | ||
| 1560 | |||
| 1561 | return retval; | ||
| 1562 | } | ||
| 1563 | |||
| 1564 | /** | ||
| 1565 | * request_percpu_irq - allocate a percpu interrupt line | ||
| 1566 | * @irq: Interrupt line to allocate | ||
| 1567 | * @handler: Function to be called when the IRQ occurs. | ||
| 1568 | * @devname: An ascii name for the claiming device | ||
| 1569 | * @dev_id: A percpu cookie passed back to the handler function | ||
| 1570 | * | ||
| 1571 | * This call allocates interrupt resources, but doesn't | ||
| 1572 | * automatically enable the interrupt. It has to be done on each | ||
| 1573 | * CPU using enable_percpu_irq(). | ||
| 1574 | * | ||
| 1575 | * Dev_id must be globally unique. It is a per-cpu variable, and | ||
| 1576 | * the handler gets called with the interrupted CPU's instance of | ||
| 1577 | * that variable. | ||
| 1578 | */ | ||
| 1579 | int request_percpu_irq(unsigned int irq, irq_handler_t handler, | ||
| 1580 | const char *devname, void __percpu *dev_id) | ||
| 1581 | { | ||
| 1582 | struct irqaction *action; | ||
| 1583 | struct irq_desc *desc; | ||
| 1584 | int retval; | ||
| 1585 | |||
| 1586 | if (!dev_id) | ||
| 1587 | return -EINVAL; | ||
| 1588 | |||
| 1589 | desc = irq_to_desc(irq); | ||
| 1590 | if (!desc || !irq_settings_can_request(desc) || | ||
| 1591 | !irq_settings_is_per_cpu_devid(desc)) | ||
| 1592 | return -EINVAL; | ||
| 1593 | |||
| 1594 | action = kzalloc(sizeof(struct irqaction), GFP_KERNEL); | ||
| 1595 | if (!action) | ||
| 1596 | return -ENOMEM; | ||
| 1597 | |||
| 1598 | action->handler = handler; | ||
| 1599 | action->flags = IRQF_PERCPU; | ||
| 1600 | action->name = devname; | ||
| 1601 | action->percpu_dev_id = dev_id; | ||
| 1602 | |||
| 1603 | chip_bus_lock(desc); | ||
| 1604 | retval = __setup_irq(irq, desc, action); | ||
| 1605 | chip_bus_sync_unlock(desc); | ||
| 1606 | |||
| 1607 | if (retval) | ||
| 1608 | kfree(action); | ||
| 1609 | |||
| 1610 | return retval; | ||
| 1611 | } | ||
