| .. | .. |
|---|
| 10 | 10 | |
|---|
| 11 | 11 | #include <linux/irq.h> |
|---|
| 12 | 12 | #include <linux/kthread.h> |
|---|
| 13 | +#include <linux/kconfig.h> |
|---|
| 13 | 14 | #include <linux/module.h> |
|---|
| 14 | 15 | #include <linux/random.h> |
|---|
| 15 | 16 | #include <linux/interrupt.h> |
|---|
| .. | .. |
|---|
| 829 | 830 | } |
|---|
| 830 | 831 | EXPORT_SYMBOL(irq_set_irq_wake); |
|---|
| 831 | 832 | |
|---|
| 833 | +#ifdef CONFIG_IRQ_PIPELINE |
|---|
| 834 | + |
|---|
| 835 | +/** |
|---|
| 836 | + * irq_switch_oob - Control out-of-band setting for a registered IRQ descriptor |
|---|
| 837 | + * @irq: interrupt to control |
|---|
| 838 | + * @on: enable/disable pipelining |
|---|
| 839 | + * |
|---|
| 840 | + * Enable/disable out-of-band handling for an IRQ. At least one |
|---|
| 841 | + * action must have been previously registered for such |
|---|
| 842 | + * interrupt. |
|---|
| 843 | + * |
|---|
| 844 | + * The previously registered action(s) need(s) not bearing the |
|---|
| 845 | + * IRQF_OOB flag for the IRQ to be switched to out-of-band |
|---|
| 846 | + * handling. This call enables switching pre-installed IRQs from |
|---|
| 847 | + * in-band to out-of-band handling. |
|---|
| 848 | + * |
|---|
| 849 | + * NOTE: This routine affects all action handlers sharing the |
|---|
| 850 | + * IRQ. |
|---|
| 851 | + */ |
|---|
| 852 | +int irq_switch_oob(unsigned int irq, bool on) |
|---|
| 853 | +{ |
|---|
| 854 | + struct irq_desc *desc; |
|---|
| 855 | + unsigned long flags; |
|---|
| 856 | + int ret = 0; |
|---|
| 857 | + |
|---|
| 858 | + desc = irq_get_desc_lock(irq, &flags, 0); |
|---|
| 859 | + if (!desc) |
|---|
| 860 | + return -EINVAL; |
|---|
| 861 | + |
|---|
| 862 | + if (!desc->action) |
|---|
| 863 | + ret = -EINVAL; |
|---|
| 864 | + else if (on) |
|---|
| 865 | + irq_settings_set_oob(desc); |
|---|
| 866 | + else |
|---|
| 867 | + irq_settings_clr_oob(desc); |
|---|
| 868 | + |
|---|
| 869 | + irq_put_desc_unlock(desc, flags); |
|---|
| 870 | + |
|---|
| 871 | + return ret; |
|---|
| 872 | +} |
|---|
| 873 | +EXPORT_SYMBOL_GPL(irq_switch_oob); |
|---|
| 874 | + |
|---|
| 875 | +#endif /* CONFIG_IRQ_PIPELINE */ |
|---|
| 876 | + |
|---|
| 832 | 877 | /* |
|---|
| 833 | 878 | * Internal function that tells the architecture code whether a |
|---|
| 834 | 879 | * particular irq has been exclusively allocated or is available |
|---|
| .. | .. |
|---|
| 845 | 890 | |
|---|
| 846 | 891 | if (irq_settings_can_request(desc)) { |
|---|
| 847 | 892 | if (!desc->action || |
|---|
| 848 | | - irqflags & desc->action->flags & IRQF_SHARED) |
|---|
| 893 | + ((irqflags & desc->action->flags & IRQF_SHARED) && |
|---|
| 894 | + !((irqflags ^ desc->action->flags) & IRQF_OOB))) |
|---|
| 849 | 895 | canrequest = 1; |
|---|
| 850 | 896 | } |
|---|
| 851 | 897 | irq_put_desc_unlock(desc, flags); |
|---|
| .. | .. |
|---|
| 1419 | 1465 | |
|---|
| 1420 | 1466 | new->irq = irq; |
|---|
| 1421 | 1467 | |
|---|
| 1468 | + ret = -EINVAL; |
|---|
| 1469 | + /* |
|---|
| 1470 | + * Out-of-band interrupts can be shared but not threaded. We |
|---|
| 1471 | + * silently ignore the OOB setting if interrupt pipelining is |
|---|
| 1472 | + * disabled. |
|---|
| 1473 | + */ |
|---|
| 1474 | + if (!irqs_pipelined()) |
|---|
| 1475 | + new->flags &= ~IRQF_OOB; |
|---|
| 1476 | + else if (new->flags & IRQF_OOB) { |
|---|
| 1477 | + if (new->thread_fn) |
|---|
| 1478 | + goto out_mput; |
|---|
| 1479 | + new->flags |= IRQF_NO_THREAD; |
|---|
| 1480 | + new->flags &= ~IRQF_ONESHOT; |
|---|
| 1481 | + } |
|---|
| 1482 | + |
|---|
| 1422 | 1483 | /* |
|---|
| 1423 | 1484 | * If the trigger type is not specified by the caller, |
|---|
| 1424 | 1485 | * then use the default for this interrupt. |
|---|
| .. | .. |
|---|
| 1432 | 1493 | */ |
|---|
| 1433 | 1494 | nested = irq_settings_is_nested_thread(desc); |
|---|
| 1434 | 1495 | if (nested) { |
|---|
| 1435 | | - if (!new->thread_fn) { |
|---|
| 1436 | | - ret = -EINVAL; |
|---|
| 1496 | + if (!new->thread_fn) |
|---|
| 1437 | 1497 | goto out_mput; |
|---|
| 1438 | | - } |
|---|
| 1439 | 1498 | /* |
|---|
| 1440 | 1499 | * Replace the primary handler which was provided from |
|---|
| 1441 | 1500 | * the driver for non nested interrupt handling by the |
|---|
| .. | .. |
|---|
| 1519 | 1578 | * the same type (level, edge, polarity). So both flag |
|---|
| 1520 | 1579 | * fields must have IRQF_SHARED set and the bits which |
|---|
| 1521 | 1580 | * set the trigger type must match. Also all must |
|---|
| 1522 | | - * agree on ONESHOT. |
|---|
| 1581 | + * agree on ONESHOT and OOB. |
|---|
| 1523 | 1582 | * Interrupt lines used for NMIs cannot be shared. |
|---|
| 1524 | 1583 | */ |
|---|
| 1525 | 1584 | unsigned int oldtype; |
|---|
| .. | .. |
|---|
| 1544 | 1603 | |
|---|
| 1545 | 1604 | if (!((old->flags & new->flags) & IRQF_SHARED) || |
|---|
| 1546 | 1605 | (oldtype != (new->flags & IRQF_TRIGGER_MASK)) || |
|---|
| 1547 | | - ((old->flags ^ new->flags) & IRQF_ONESHOT)) |
|---|
| 1606 | + ((old->flags ^ new->flags) & (IRQF_OOB|IRQF_ONESHOT))) |
|---|
| 1548 | 1607 | goto mismatch; |
|---|
| 1549 | 1608 | |
|---|
| 1550 | 1609 | /* All handlers must agree on per-cpuness */ |
|---|
| .. | .. |
|---|
| 1661 | 1720 | |
|---|
| 1662 | 1721 | if (new->flags & IRQF_ONESHOT) |
|---|
| 1663 | 1722 | desc->istate |= IRQS_ONESHOT; |
|---|
| 1723 | + |
|---|
| 1724 | + if (new->flags & IRQF_OOB) |
|---|
| 1725 | + irq_settings_set_oob(desc); |
|---|
| 1664 | 1726 | |
|---|
| 1665 | 1727 | /* Exclude IRQ from balancing if requested */ |
|---|
| 1666 | 1728 | if (new->flags & IRQF_NOBALANCING) { |
|---|
| .. | .. |
|---|
| 1809 | 1871 | irq_settings_clr_disable_unlazy(desc); |
|---|
| 1810 | 1872 | /* Only shutdown. Deactivate after synchronize_hardirq() */ |
|---|
| 1811 | 1873 | irq_shutdown(desc); |
|---|
| 1874 | + /* Turn off OOB handling (after shutdown). */ |
|---|
| 1875 | + irq_settings_clr_oob(desc); |
|---|
| 1812 | 1876 | } |
|---|
| 1813 | 1877 | |
|---|
| 1814 | 1878 | #ifdef CONFIG_SMP |
|---|
| .. | .. |
|---|
| 1845 | 1909 | |
|---|
| 1846 | 1910 | #ifdef CONFIG_DEBUG_SHIRQ |
|---|
| 1847 | 1911 | /* |
|---|
| 1848 | | - * It's a shared IRQ -- the driver ought to be prepared for an IRQ |
|---|
| 1849 | | - * event to happen even now it's being freed, so let's make sure that |
|---|
| 1850 | | - * is so by doing an extra call to the handler .... |
|---|
| 1912 | + * It's a shared IRQ (with in-band handler) -- the driver |
|---|
| 1913 | + * ought to be prepared for an IRQ event to happen even now |
|---|
| 1914 | + * it's being freed, so let's make sure that is so by doing an |
|---|
| 1915 | + * extra call to the handler .... |
|---|
| 1851 | 1916 | * |
|---|
| 1852 | 1917 | * ( We do this after actually deregistering it, to make sure that a |
|---|
| 1853 | 1918 | * 'real' IRQ doesn't run in parallel with our fake. ) |
|---|
| 1854 | 1919 | */ |
|---|
| 1855 | | - if (action->flags & IRQF_SHARED) { |
|---|
| 1920 | + if ((action->flags & (IRQF_SHARED|IRQF_OOB)) == IRQF_SHARED) { |
|---|
| 1856 | 1921 | local_irq_save(flags); |
|---|
| 1857 | 1922 | action->handler(irq, dev_id); |
|---|
| 1858 | 1923 | local_irq_restore(flags); |
|---|
| .. | .. |
|---|
| 2473 | 2538 | * __request_percpu_irq - allocate a percpu interrupt line |
|---|
| 2474 | 2539 | * @irq: Interrupt line to allocate |
|---|
| 2475 | 2540 | * @handler: Function to be called when the IRQ occurs. |
|---|
| 2476 | | - * @flags: Interrupt type flags (IRQF_TIMER only) |
|---|
| 2541 | + * @flags: Interrupt type flags (IRQF_TIMER and/or IRQF_OOB only) |
|---|
| 2477 | 2542 | * @devname: An ascii name for the claiming device |
|---|
| 2478 | 2543 | * @dev_id: A percpu cookie passed back to the handler function |
|---|
| 2479 | 2544 | * |
|---|
| .. | .. |
|---|
| 2502 | 2567 | !irq_settings_is_per_cpu_devid(desc)) |
|---|
| 2503 | 2568 | return -EINVAL; |
|---|
| 2504 | 2569 | |
|---|
| 2505 | | - if (flags && flags != IRQF_TIMER) |
|---|
| 2570 | + if (flags & ~(IRQF_TIMER|IRQF_OOB)) |
|---|
| 2506 | 2571 | return -EINVAL; |
|---|
| 2507 | 2572 | |
|---|
| 2508 | 2573 | action = kzalloc(sizeof(struct irqaction), GFP_KERNEL); |
|---|