diff options
| -rw-r--r-- | include/linux/irq.h | 6 | ||||
| -rw-r--r-- | kernel/irq/chip.c | 2 | ||||
| -rw-r--r-- | kernel/irq/internals.h | 13 | ||||
| -rw-r--r-- | kernel/irq/manage.c | 19 |
4 files changed, 39 insertions, 1 deletions
diff --git a/include/linux/irq.h b/include/linux/irq.h index 5e7c6ee8c35c..ce8171bc6fac 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h | |||
| @@ -101,6 +101,9 @@ struct msi_desc; | |||
| 101 | * @set_type: set the flow type (IRQ_TYPE_LEVEL/etc.) of an IRQ | 101 | * @set_type: set the flow type (IRQ_TYPE_LEVEL/etc.) of an IRQ |
| 102 | * @set_wake: enable/disable power-management wake-on of an IRQ | 102 | * @set_wake: enable/disable power-management wake-on of an IRQ |
| 103 | * | 103 | * |
| 104 | * @bus_lock: function to lock access to slow bus (i2c) chips | ||
| 105 | * @bus_sync_unlock: function to sync and unlock slow bus (i2c) chips | ||
| 106 | * | ||
| 104 | * @release: release function solely used by UML | 107 | * @release: release function solely used by UML |
| 105 | * @typename: obsoleted by name, kept as migration helper | 108 | * @typename: obsoleted by name, kept as migration helper |
| 106 | */ | 109 | */ |
| @@ -124,6 +127,9 @@ struct irq_chip { | |||
| 124 | int (*set_type)(unsigned int irq, unsigned int flow_type); | 127 | int (*set_type)(unsigned int irq, unsigned int flow_type); |
| 125 | int (*set_wake)(unsigned int irq, unsigned int on); | 128 | int (*set_wake)(unsigned int irq, unsigned int on); |
| 126 | 129 | ||
| 130 | void (*bus_lock)(unsigned int irq); | ||
| 131 | void (*bus_sync_unlock)(unsigned int irq); | ||
| 132 | |||
| 127 | /* Currently used only by UML, might disappear one day.*/ | 133 | /* Currently used only by UML, might disappear one day.*/ |
| 128 | #ifdef CONFIG_IRQ_RELEASE_METHOD | 134 | #ifdef CONFIG_IRQ_RELEASE_METHOD |
| 129 | void (*release)(unsigned int irq, void *dev_id); | 135 | void (*release)(unsigned int irq, void *dev_id); |
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index b08c0d24f202..f856330e684a 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c | |||
| @@ -580,6 +580,7 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, | |||
| 580 | desc->chip = &dummy_irq_chip; | 580 | desc->chip = &dummy_irq_chip; |
| 581 | } | 581 | } |
| 582 | 582 | ||
| 583 | chip_bus_lock(irq, desc); | ||
| 583 | spin_lock_irqsave(&desc->lock, flags); | 584 | spin_lock_irqsave(&desc->lock, flags); |
| 584 | 585 | ||
| 585 | /* Uninstall? */ | 586 | /* Uninstall? */ |
| @@ -599,6 +600,7 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, | |||
| 599 | desc->chip->startup(irq); | 600 | desc->chip->startup(irq); |
| 600 | } | 601 | } |
| 601 | spin_unlock_irqrestore(&desc->lock, flags); | 602 | spin_unlock_irqrestore(&desc->lock, flags); |
| 603 | chip_bus_sync_unlock(irq, desc); | ||
| 602 | } | 604 | } |
| 603 | EXPORT_SYMBOL_GPL(__set_irq_handler); | 605 | EXPORT_SYMBOL_GPL(__set_irq_handler); |
| 604 | 606 | ||
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index e70ed5592eb9..1b5d742c6a77 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h | |||
| @@ -44,6 +44,19 @@ extern int irq_select_affinity_usr(unsigned int irq); | |||
| 44 | 44 | ||
| 45 | extern void irq_set_thread_affinity(struct irq_desc *desc); | 45 | extern void irq_set_thread_affinity(struct irq_desc *desc); |
| 46 | 46 | ||
| 47 | /* Inline functions for support of irq chips on slow busses */ | ||
| 48 | static inline void chip_bus_lock(unsigned int irq, struct irq_desc *desc) | ||
| 49 | { | ||
| 50 | if (unlikely(desc->chip->bus_lock)) | ||
| 51 | desc->chip->bus_lock(irq); | ||
| 52 | } | ||
| 53 | |||
| 54 | static inline void chip_bus_sync_unlock(unsigned int irq, struct irq_desc *desc) | ||
| 55 | { | ||
| 56 | if (unlikely(desc->chip->bus_sync_unlock)) | ||
| 57 | desc->chip->bus_sync_unlock(irq); | ||
| 58 | } | ||
| 59 | |||
| 47 | /* | 60 | /* |
| 48 | * Debugging printout: | 61 | * Debugging printout: |
| 49 | */ | 62 | */ |
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index d7f7b5fd2476..0a3fd5b524c9 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
| @@ -230,9 +230,11 @@ void disable_irq_nosync(unsigned int irq) | |||
| 230 | if (!desc) | 230 | if (!desc) |
| 231 | return; | 231 | return; |
| 232 | 232 | ||
| 233 | chip_bus_lock(irq, desc); | ||
| 233 | spin_lock_irqsave(&desc->lock, flags); | 234 | spin_lock_irqsave(&desc->lock, flags); |
| 234 | __disable_irq(desc, irq, false); | 235 | __disable_irq(desc, irq, false); |
| 235 | spin_unlock_irqrestore(&desc->lock, flags); | 236 | spin_unlock_irqrestore(&desc->lock, flags); |
| 237 | chip_bus_sync_unlock(irq, desc); | ||
| 236 | } | 238 | } |
| 237 | EXPORT_SYMBOL(disable_irq_nosync); | 239 | EXPORT_SYMBOL(disable_irq_nosync); |
| 238 | 240 | ||
| @@ -294,7 +296,8 @@ void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume) | |||
| 294 | * matches the last disable, processing of interrupts on this | 296 | * matches the last disable, processing of interrupts on this |
| 295 | * IRQ line is re-enabled. | 297 | * IRQ line is re-enabled. |
| 296 | * | 298 | * |
| 297 | * This function may be called from IRQ context. | 299 | * This function may be called from IRQ context only when |
| 300 | * desc->chip->bus_lock and desc->chip->bus_sync_unlock are NULL ! | ||
| 298 | */ | 301 | */ |
| 299 | void enable_irq(unsigned int irq) | 302 | void enable_irq(unsigned int irq) |
| 300 | { | 303 | { |
| @@ -304,9 +307,11 @@ void enable_irq(unsigned int irq) | |||
| 304 | if (!desc) | 307 | if (!desc) |
| 305 | return; | 308 | return; |
| 306 | 309 | ||
| 310 | chip_bus_lock(irq, desc); | ||
| 307 | spin_lock_irqsave(&desc->lock, flags); | 311 | spin_lock_irqsave(&desc->lock, flags); |
| 308 | __enable_irq(desc, irq, false); | 312 | __enable_irq(desc, irq, false); |
| 309 | spin_unlock_irqrestore(&desc->lock, flags); | 313 | spin_unlock_irqrestore(&desc->lock, flags); |
| 314 | chip_bus_sync_unlock(irq, desc); | ||
| 310 | } | 315 | } |
| 311 | EXPORT_SYMBOL(enable_irq); | 316 | EXPORT_SYMBOL(enable_irq); |
| 312 | 317 | ||
| @@ -468,12 +473,14 @@ static int irq_wait_for_interrupt(struct irqaction *action) | |||
| 468 | */ | 473 | */ |
| 469 | static void irq_finalize_oneshot(unsigned int irq, struct irq_desc *desc) | 474 | static void irq_finalize_oneshot(unsigned int irq, struct irq_desc *desc) |
| 470 | { | 475 | { |
| 476 | chip_bus_lock(irq, desc); | ||
| 471 | spin_lock_irq(&desc->lock); | 477 | spin_lock_irq(&desc->lock); |
| 472 | if (!(desc->status & IRQ_DISABLED) && (desc->status & IRQ_MASKED)) { | 478 | if (!(desc->status & IRQ_DISABLED) && (desc->status & IRQ_MASKED)) { |
| 473 | desc->status &= ~IRQ_MASKED; | 479 | desc->status &= ~IRQ_MASKED; |
| 474 | desc->chip->unmask(irq); | 480 | desc->chip->unmask(irq); |
| 475 | } | 481 | } |
| 476 | spin_unlock_irq(&desc->lock); | 482 | spin_unlock_irq(&desc->lock); |
| 483 | chip_bus_sync_unlock(irq, desc); | ||
| 477 | } | 484 | } |
| 478 | 485 | ||
| 479 | #ifdef CONFIG_SMP | 486 | #ifdef CONFIG_SMP |
| @@ -904,7 +911,14 @@ EXPORT_SYMBOL_GPL(remove_irq); | |||
| 904 | */ | 911 | */ |
| 905 | void free_irq(unsigned int irq, void *dev_id) | 912 | void free_irq(unsigned int irq, void *dev_id) |
| 906 | { | 913 | { |
| 914 | struct irq_desc *desc = irq_to_desc(irq); | ||
| 915 | |||
| 916 | if (!desc) | ||
| 917 | return; | ||
| 918 | |||
| 919 | chip_bus_lock(irq, desc); | ||
| 907 | kfree(__free_irq(irq, dev_id)); | 920 | kfree(__free_irq(irq, dev_id)); |
| 921 | chip_bus_sync_unlock(irq, desc); | ||
| 908 | } | 922 | } |
| 909 | EXPORT_SYMBOL(free_irq); | 923 | EXPORT_SYMBOL(free_irq); |
| 910 | 924 | ||
| @@ -1011,7 +1025,10 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler, | |||
| 1011 | action->name = devname; | 1025 | action->name = devname; |
| 1012 | action->dev_id = dev_id; | 1026 | action->dev_id = dev_id; |
| 1013 | 1027 | ||
| 1028 | chip_bus_lock(irq, desc); | ||
| 1014 | retval = __setup_irq(irq, desc, action); | 1029 | retval = __setup_irq(irq, desc, action); |
| 1030 | chip_bus_sync_unlock(irq, desc); | ||
| 1031 | |||
| 1015 | if (retval) | 1032 | if (retval) |
| 1016 | kfree(action); | 1033 | kfree(action); |
| 1017 | 1034 | ||
