diff options
Diffstat (limited to 'kernel/irq/manage.c')
| -rw-r--r-- | kernel/irq/manage.c | 127 |
1 files changed, 125 insertions, 2 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 886d09e691d5..e68932bb308e 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
| @@ -68,14 +68,20 @@ static void __synchronize_hardirq(struct irq_desc *desc) | |||
| 68 | * Do not use this for shutdown scenarios where you must be sure | 68 | * Do not use this for shutdown scenarios where you must be sure |
| 69 | * that all parts (hardirq and threaded handler) have completed. | 69 | * that all parts (hardirq and threaded handler) have completed. |
| 70 | * | 70 | * |
| 71 | * Returns: false if a threaded handler is active. | ||
| 72 | * | ||
| 71 | * This function may be called - with care - from IRQ context. | 73 | * This function may be called - with care - from IRQ context. |
| 72 | */ | 74 | */ |
| 73 | void synchronize_hardirq(unsigned int irq) | 75 | bool synchronize_hardirq(unsigned int irq) |
| 74 | { | 76 | { |
| 75 | struct irq_desc *desc = irq_to_desc(irq); | 77 | struct irq_desc *desc = irq_to_desc(irq); |
| 76 | 78 | ||
| 77 | if (desc) | 79 | if (desc) { |
| 78 | __synchronize_hardirq(desc); | 80 | __synchronize_hardirq(desc); |
| 81 | return !atomic_read(&desc->threads_active); | ||
| 82 | } | ||
| 83 | |||
| 84 | return true; | ||
| 79 | } | 85 | } |
| 80 | EXPORT_SYMBOL(synchronize_hardirq); | 86 | EXPORT_SYMBOL(synchronize_hardirq); |
| 81 | 87 | ||
| @@ -440,6 +446,32 @@ void disable_irq(unsigned int irq) | |||
| 440 | } | 446 | } |
| 441 | EXPORT_SYMBOL(disable_irq); | 447 | EXPORT_SYMBOL(disable_irq); |
| 442 | 448 | ||
| 449 | /** | ||
| 450 | * disable_hardirq - disables an irq and waits for hardirq completion | ||
| 451 | * @irq: Interrupt to disable | ||
| 452 | * | ||
| 453 | * Disable the selected interrupt line. Enables and Disables are | ||
| 454 | * nested. | ||
| 455 | * This function waits for any pending hard IRQ handlers for this | ||
| 456 | * interrupt to complete before returning. If you use this function while | ||
| 457 | * holding a resource the hard IRQ handler may need you will deadlock. | ||
| 458 | * | ||
| 459 | * When used to optimistically disable an interrupt from atomic context | ||
| 460 | * the return value must be checked. | ||
| 461 | * | ||
| 462 | * Returns: false if a threaded handler is active. | ||
| 463 | * | ||
| 464 | * This function may be called - with care - from IRQ context. | ||
| 465 | */ | ||
| 466 | bool disable_hardirq(unsigned int irq) | ||
| 467 | { | ||
| 468 | if (!__disable_irq_nosync(irq)) | ||
| 469 | return synchronize_hardirq(irq); | ||
| 470 | |||
| 471 | return false; | ||
| 472 | } | ||
| 473 | EXPORT_SYMBOL_GPL(disable_hardirq); | ||
| 474 | |||
| 443 | void __enable_irq(struct irq_desc *desc, unsigned int irq) | 475 | void __enable_irq(struct irq_desc *desc, unsigned int irq) |
| 444 | { | 476 | { |
| 445 | switch (desc->depth) { | 477 | switch (desc->depth) { |
| @@ -1766,3 +1798,94 @@ int request_percpu_irq(unsigned int irq, irq_handler_t handler, | |||
| 1766 | 1798 | ||
| 1767 | return retval; | 1799 | return retval; |
| 1768 | } | 1800 | } |
| 1801 | |||
| 1802 | /** | ||
| 1803 | * irq_get_irqchip_state - returns the irqchip state of a interrupt. | ||
| 1804 | * @irq: Interrupt line that is forwarded to a VM | ||
| 1805 | * @which: One of IRQCHIP_STATE_* the caller wants to know about | ||
| 1806 | * @state: a pointer to a boolean where the state is to be storeed | ||
| 1807 | * | ||
| 1808 | * This call snapshots the internal irqchip state of an | ||
| 1809 | * interrupt, returning into @state the bit corresponding to | ||
| 1810 | * stage @which | ||
| 1811 | * | ||
| 1812 | * This function should be called with preemption disabled if the | ||
| 1813 | * interrupt controller has per-cpu registers. | ||
| 1814 | */ | ||
| 1815 | int irq_get_irqchip_state(unsigned int irq, enum irqchip_irq_state which, | ||
| 1816 | bool *state) | ||
| 1817 | { | ||
| 1818 | struct irq_desc *desc; | ||
| 1819 | struct irq_data *data; | ||
| 1820 | struct irq_chip *chip; | ||
| 1821 | unsigned long flags; | ||
| 1822 | int err = -EINVAL; | ||
| 1823 | |||
| 1824 | desc = irq_get_desc_buslock(irq, &flags, 0); | ||
| 1825 | if (!desc) | ||
| 1826 | return err; | ||
| 1827 | |||
| 1828 | data = irq_desc_get_irq_data(desc); | ||
| 1829 | |||
| 1830 | do { | ||
| 1831 | chip = irq_data_get_irq_chip(data); | ||
| 1832 | if (chip->irq_get_irqchip_state) | ||
| 1833 | break; | ||
| 1834 | #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY | ||
| 1835 | data = data->parent_data; | ||
| 1836 | #else | ||
| 1837 | data = NULL; | ||
| 1838 | #endif | ||
| 1839 | } while (data); | ||
| 1840 | |||
| 1841 | if (data) | ||
| 1842 | err = chip->irq_get_irqchip_state(data, which, state); | ||
| 1843 | |||
| 1844 | irq_put_desc_busunlock(desc, flags); | ||
| 1845 | return err; | ||
| 1846 | } | ||
| 1847 | |||
| 1848 | /** | ||
| 1849 | * irq_set_irqchip_state - set the state of a forwarded interrupt. | ||
| 1850 | * @irq: Interrupt line that is forwarded to a VM | ||
| 1851 | * @which: State to be restored (one of IRQCHIP_STATE_*) | ||
| 1852 | * @val: Value corresponding to @which | ||
| 1853 | * | ||
| 1854 | * This call sets the internal irqchip state of an interrupt, | ||
| 1855 | * depending on the value of @which. | ||
| 1856 | * | ||
| 1857 | * This function should be called with preemption disabled if the | ||
| 1858 | * interrupt controller has per-cpu registers. | ||
| 1859 | */ | ||
| 1860 | int irq_set_irqchip_state(unsigned int irq, enum irqchip_irq_state which, | ||
| 1861 | bool val) | ||
| 1862 | { | ||
| 1863 | struct irq_desc *desc; | ||
| 1864 | struct irq_data *data; | ||
| 1865 | struct irq_chip *chip; | ||
| 1866 | unsigned long flags; | ||
| 1867 | int err = -EINVAL; | ||
| 1868 | |||
| 1869 | desc = irq_get_desc_buslock(irq, &flags, 0); | ||
| 1870 | if (!desc) | ||
| 1871 | return err; | ||
| 1872 | |||
| 1873 | data = irq_desc_get_irq_data(desc); | ||
| 1874 | |||
| 1875 | do { | ||
| 1876 | chip = irq_data_get_irq_chip(data); | ||
| 1877 | if (chip->irq_set_irqchip_state) | ||
| 1878 | break; | ||
| 1879 | #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY | ||
| 1880 | data = data->parent_data; | ||
| 1881 | #else | ||
| 1882 | data = NULL; | ||
| 1883 | #endif | ||
| 1884 | } while (data); | ||
| 1885 | |||
| 1886 | if (data) | ||
| 1887 | err = chip->irq_set_irqchip_state(data, which, val); | ||
| 1888 | |||
| 1889 | irq_put_desc_busunlock(desc, flags); | ||
| 1890 | return err; | ||
| 1891 | } | ||
