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.c202
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)
195int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m) 195int 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)
356static int __disable_irq_nosync(unsigned int irq) 356static 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)
448void enable_irq(unsigned int irq) 448void 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)
491int irq_set_irq_wake(unsigned int irq, unsigned int on) 491int 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);
532int can_request_irq(unsigned int irq, unsigned long irqflags) 532int 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}
1130EXPORT_SYMBOL_GPL(setup_irq); 1132EXPORT_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 */
1228void remove_irq(unsigned int irq, struct irqaction *act) 1230void 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}
1232EXPORT_SYMBOL_GPL(remove_irq); 1237EXPORT_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}
1414EXPORT_SYMBOL_GPL(request_any_context_irq); 1420EXPORT_SYMBOL_GPL(request_any_context_irq);
1421
1422void 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
1435void 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 */
1451static 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
1486bad:
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 */
1498void 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 */
1518void 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 */
1537int 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 */
1566int 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}