aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/irq.h6
-rw-r--r--kernel/irq/chip.c2
-rw-r--r--kernel/irq/internals.h13
-rw-r--r--kernel/irq/manage.c19
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}
603EXPORT_SYMBOL_GPL(__set_irq_handler); 605EXPORT_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
45extern void irq_set_thread_affinity(struct irq_desc *desc); 45extern void irq_set_thread_affinity(struct irq_desc *desc);
46 46
47/* Inline functions for support of irq chips on slow busses */
48static 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
54static 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}
237EXPORT_SYMBOL(disable_irq_nosync); 239EXPORT_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 */
299void enable_irq(unsigned int irq) 302void 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}
311EXPORT_SYMBOL(enable_irq); 316EXPORT_SYMBOL(enable_irq);
312 317
@@ -468,12 +473,14 @@ static int irq_wait_for_interrupt(struct irqaction *action)
468 */ 473 */
469static void irq_finalize_oneshot(unsigned int irq, struct irq_desc *desc) 474static 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 */
905void free_irq(unsigned int irq, void *dev_id) 912void 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}
909EXPORT_SYMBOL(free_irq); 923EXPORT_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