diff options
Diffstat (limited to 'kernel/irq/manage.c')
-rw-r--r-- | kernel/irq/manage.c | 202 |
1 files changed, 193 insertions, 9 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 7e1a3ed1e61a..7b4b156d065c 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; |
@@ -491,7 +491,7 @@ static int set_irq_wake_real(unsigned int irq, unsigned int on) | |||
491 | int irq_set_irq_wake(unsigned int irq, unsigned int on) | 491 | int irq_set_irq_wake(unsigned int irq, unsigned int on) |
492 | { | 492 | { |
493 | unsigned long flags; | 493 | unsigned long flags; |
494 | 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); |
495 | int ret = 0; | 495 | int ret = 0; |
496 | 496 | ||
497 | if (!desc) | 497 | if (!desc) |
@@ -532,7 +532,7 @@ EXPORT_SYMBOL(irq_set_irq_wake); | |||
532 | int can_request_irq(unsigned int irq, unsigned long irqflags) | 532 | int can_request_irq(unsigned int irq, unsigned long irqflags) |
533 | { | 533 | { |
534 | unsigned long flags; | 534 | unsigned long flags; |
535 | struct irq_desc *desc = irq_get_desc_lock(irq, &flags); | 535 | struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); |
536 | int canrequest = 0; | 536 | int canrequest = 0; |
537 | 537 | ||
538 | if (!desc) | 538 | if (!desc) |
@@ -1121,6 +1121,8 @@ int setup_irq(unsigned int irq, struct irqaction *act) | |||
1121 | int retval; | 1121 | int retval; |
1122 | struct irq_desc *desc = irq_to_desc(irq); | 1122 | struct irq_desc *desc = irq_to_desc(irq); |
1123 | 1123 | ||
1124 | if (WARN_ON(irq_settings_is_per_cpu_devid(desc))) | ||
1125 | return -EINVAL; | ||
1124 | chip_bus_lock(desc); | 1126 | chip_bus_lock(desc); |
1125 | retval = __setup_irq(irq, desc, act); | 1127 | retval = __setup_irq(irq, desc, act); |
1126 | chip_bus_sync_unlock(desc); | 1128 | chip_bus_sync_unlock(desc); |
@@ -1129,7 +1131,7 @@ int setup_irq(unsigned int irq, struct irqaction *act) | |||
1129 | } | 1131 | } |
1130 | EXPORT_SYMBOL_GPL(setup_irq); | 1132 | EXPORT_SYMBOL_GPL(setup_irq); |
1131 | 1133 | ||
1132 | /* | 1134 | /* |
1133 | * Internal function to unregister an irqaction - used to free | 1135 | * Internal function to unregister an irqaction - used to free |
1134 | * regular and special interrupts that are part of the architecture. | 1136 | * regular and special interrupts that are part of the architecture. |
1135 | */ | 1137 | */ |
@@ -1227,7 +1229,10 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) | |||
1227 | */ | 1229 | */ |
1228 | void remove_irq(unsigned int irq, struct irqaction *act) | 1230 | void remove_irq(unsigned int irq, struct irqaction *act) |
1229 | { | 1231 | { |
1230 | __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); | ||
1231 | } | 1236 | } |
1232 | EXPORT_SYMBOL_GPL(remove_irq); | 1237 | EXPORT_SYMBOL_GPL(remove_irq); |
1233 | 1238 | ||
@@ -1249,7 +1254,7 @@ void free_irq(unsigned int irq, void *dev_id) | |||
1249 | { | 1254 | { |
1250 | struct irq_desc *desc = irq_to_desc(irq); | 1255 | struct irq_desc *desc = irq_to_desc(irq); |
1251 | 1256 | ||
1252 | if (!desc) | 1257 | if (!desc || WARN_ON(irq_settings_is_per_cpu_devid(desc))) |
1253 | return; | 1258 | return; |
1254 | 1259 | ||
1255 | #ifdef CONFIG_SMP | 1260 | #ifdef CONFIG_SMP |
@@ -1327,7 +1332,8 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler, | |||
1327 | if (!desc) | 1332 | if (!desc) |
1328 | return -EINVAL; | 1333 | return -EINVAL; |
1329 | 1334 | ||
1330 | if (!irq_settings_can_request(desc)) | 1335 | if (!irq_settings_can_request(desc) || |
1336 | WARN_ON(irq_settings_is_per_cpu_devid(desc))) | ||
1331 | return -EINVAL; | 1337 | return -EINVAL; |
1332 | 1338 | ||
1333 | if (!handler) { | 1339 | if (!handler) { |
@@ -1412,3 +1418,181 @@ int request_any_context_irq(unsigned int irq, irq_handler_t handler, | |||
1412 | return !ret ? IRQC_IS_HARDIRQ : ret; | 1418 | return !ret ? IRQC_IS_HARDIRQ : ret; |
1413 | } | 1419 | } |
1414 | EXPORT_SYMBOL_GPL(request_any_context_irq); | 1420 | EXPORT_SYMBOL_GPL(request_any_context_irq); |
1421 | |||
1422 | void enable_percpu_irq(unsigned int irq) | ||
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 | irq_percpu_enable(desc, cpu); | ||
1432 | irq_put_desc_unlock(desc, flags); | ||
1433 | } | ||
1434 | |||
1435 | void disable_percpu_irq(unsigned int irq) | ||
1436 | { | ||
1437 | unsigned int cpu = smp_processor_id(); | ||
1438 | unsigned long flags; | ||
1439 | struct irq_desc *desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_PERCPU); | ||
1440 | |||
1441 | if (!desc) | ||
1442 | return; | ||
1443 | |||
1444 | irq_percpu_disable(desc, cpu); | ||
1445 | irq_put_desc_unlock(desc, flags); | ||
1446 | } | ||
1447 | |||
1448 | /* | ||
1449 | * Internal function to unregister a percpu irqaction. | ||
1450 | */ | ||
1451 | static struct irqaction *__free_percpu_irq(unsigned int irq, void __percpu *dev_id) | ||
1452 | { | ||
1453 | struct irq_desc *desc = irq_to_desc(irq); | ||
1454 | struct irqaction *action; | ||
1455 | unsigned long flags; | ||
1456 | |||
1457 | WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq); | ||
1458 | |||
1459 | if (!desc) | ||
1460 | return NULL; | ||
1461 | |||
1462 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
1463 | |||
1464 | action = desc->action; | ||
1465 | if (!action || action->percpu_dev_id != dev_id) { | ||
1466 | WARN(1, "Trying to free already-free IRQ %d\n", irq); | ||
1467 | goto bad; | ||
1468 | } | ||
1469 | |||
1470 | if (!cpumask_empty(desc->percpu_enabled)) { | ||
1471 | WARN(1, "percpu IRQ %d still enabled on CPU%d!\n", | ||
1472 | irq, cpumask_first(desc->percpu_enabled)); | ||
1473 | goto bad; | ||
1474 | } | ||
1475 | |||
1476 | /* Found it - now remove it from the list of entries: */ | ||
1477 | desc->action = NULL; | ||
1478 | |||
1479 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
1480 | |||
1481 | unregister_handler_proc(irq, action); | ||
1482 | |||
1483 | module_put(desc->owner); | ||
1484 | return action; | ||
1485 | |||
1486 | bad: | ||
1487 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
1488 | return NULL; | ||
1489 | } | ||
1490 | |||
1491 | /** | ||
1492 | * remove_percpu_irq - free a per-cpu interrupt | ||
1493 | * @irq: Interrupt line to free | ||
1494 | * @act: irqaction for the interrupt | ||
1495 | * | ||
1496 | * Used to remove interrupts statically setup by the early boot process. | ||
1497 | */ | ||
1498 | void remove_percpu_irq(unsigned int irq, struct irqaction *act) | ||
1499 | { | ||
1500 | struct irq_desc *desc = irq_to_desc(irq); | ||
1501 | |||
1502 | if (desc && irq_settings_is_per_cpu_devid(desc)) | ||
1503 | __free_percpu_irq(irq, act->percpu_dev_id); | ||
1504 | } | ||
1505 | |||
1506 | /** | ||
1507 | * free_percpu_irq - free an interrupt allocated with request_percpu_irq | ||
1508 | * @irq: Interrupt line to free | ||
1509 | * @dev_id: Device identity to free | ||
1510 | * | ||
1511 | * Remove a percpu interrupt handler. The handler is removed, but | ||
1512 | * the interrupt line is not disabled. This must be done on each | ||
1513 | * CPU before calling this function. The function does not return | ||
1514 | * until any executing interrupts for this IRQ have completed. | ||
1515 | * | ||
1516 | * This function must not be called from interrupt context. | ||
1517 | */ | ||
1518 | void free_percpu_irq(unsigned int irq, void __percpu *dev_id) | ||
1519 | { | ||
1520 | struct irq_desc *desc = irq_to_desc(irq); | ||
1521 | |||
1522 | if (!desc || !irq_settings_is_per_cpu_devid(desc)) | ||
1523 | return; | ||
1524 | |||
1525 | chip_bus_lock(desc); | ||
1526 | kfree(__free_percpu_irq(irq, dev_id)); | ||
1527 | chip_bus_sync_unlock(desc); | ||
1528 | } | ||
1529 | |||
1530 | /** | ||
1531 | * setup_percpu_irq - setup a per-cpu interrupt | ||
1532 | * @irq: Interrupt line to setup | ||
1533 | * @act: irqaction for the interrupt | ||
1534 | * | ||
1535 | * Used to statically setup per-cpu interrupts in the early boot process. | ||
1536 | */ | ||
1537 | int setup_percpu_irq(unsigned int irq, struct irqaction *act) | ||
1538 | { | ||
1539 | struct irq_desc *desc = irq_to_desc(irq); | ||
1540 | int retval; | ||
1541 | |||
1542 | if (!desc || !irq_settings_is_per_cpu_devid(desc)) | ||
1543 | return -EINVAL; | ||
1544 | chip_bus_lock(desc); | ||
1545 | retval = __setup_irq(irq, desc, act); | ||
1546 | chip_bus_sync_unlock(desc); | ||
1547 | |||
1548 | return retval; | ||
1549 | } | ||
1550 | |||
1551 | /** | ||
1552 | * request_percpu_irq - allocate a percpu interrupt line | ||
1553 | * @irq: Interrupt line to allocate | ||
1554 | * @handler: Function to be called when the IRQ occurs. | ||
1555 | * @devname: An ascii name for the claiming device | ||
1556 | * @dev_id: A percpu cookie passed back to the handler function | ||
1557 | * | ||
1558 | * This call allocates interrupt resources, but doesn't | ||
1559 | * automatically enable the interrupt. It has to be done on each | ||
1560 | * CPU using enable_percpu_irq(). | ||
1561 | * | ||
1562 | * Dev_id must be globally unique. It is a per-cpu variable, and | ||
1563 | * the handler gets called with the interrupted CPU's instance of | ||
1564 | * that variable. | ||
1565 | */ | ||
1566 | int request_percpu_irq(unsigned int irq, irq_handler_t handler, | ||
1567 | const char *devname, void __percpu *dev_id) | ||
1568 | { | ||
1569 | struct irqaction *action; | ||
1570 | struct irq_desc *desc; | ||
1571 | int retval; | ||
1572 | |||
1573 | if (!dev_id) | ||
1574 | return -EINVAL; | ||
1575 | |||
1576 | desc = irq_to_desc(irq); | ||
1577 | if (!desc || !irq_settings_can_request(desc) || | ||
1578 | !irq_settings_is_per_cpu_devid(desc)) | ||
1579 | return -EINVAL; | ||
1580 | |||
1581 | action = kzalloc(sizeof(struct irqaction), GFP_KERNEL); | ||
1582 | if (!action) | ||
1583 | return -ENOMEM; | ||
1584 | |||
1585 | action->handler = handler; | ||
1586 | action->flags = IRQF_PERCPU; | ||
1587 | action->name = devname; | ||
1588 | action->percpu_dev_id = dev_id; | ||
1589 | |||
1590 | chip_bus_lock(desc); | ||
1591 | retval = __setup_irq(irq, desc, action); | ||
1592 | chip_bus_sync_unlock(desc); | ||
1593 | |||
1594 | if (retval) | ||
1595 | kfree(action); | ||
1596 | |||
1597 | return retval; | ||
1598 | } | ||