aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq/chip.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2009-08-13 06:17:48 -0400
committerThomas Gleixner <tglx@linutronix.de>2009-08-17 04:54:05 -0400
commit70aedd24d20e75198f5a0b11750faabbb56924e2 (patch)
tree8492641c61aa3af6f4dea421b8f628efe6fc92bd /kernel/irq/chip.c
parentb25c340c195447afb1860da580fe2a85a6b652c5 (diff)
genirq: Add buslock support
Some interrupt chips are connected to a "slow" bus (i2c, spi ...). The bus access needs to sleep and therefor cannot be called in atomic contexts. Some of the generic interrupt management functions like disable_irq(), enable_irq() ... call interrupt chip functions with the irq_desc->lock held and interrupts disabled. This does not work for such devices. Provide a separate synchronization mechanism for such interrupt chips. The irq_chip structure is extended by two optional functions (bus_lock and bus_sync_and_unlock). The idea is to serialize the bus access for those operations in the core code so that drivers which are behind that bus operated interrupt controller do not have to worry about it and just can use the normal interfaces. To achieve this we add two function pointers to the irq_chip: bus_lock and bus_sync_unlock. bus_lock() is called to serialize access to the interrupt controller bus. Now the core code can issue chip->mask/unmask ... commands without changing the fast path code at all. The chip implementation merily stores that information in a chip private data structure and returns. No bus interaction as these functions are called from atomic context. After that bus_sync_unlock() is called outside the atomic context. Now the chip implementation issues the bus commands, waits for completion and unlocks the interrupt controller bus. The irq_chip implementation as pseudo code: struct irq_chip_data { struct mutex mutex; unsigned int irq_offset; unsigned long mask; unsigned long mask_status; } static void bus_lock(unsigned int irq) { struct irq_chip_data *data = get_irq_desc_chip_data(irq); mutex_lock(&data->mutex); } static void mask(unsigned int irq) { struct irq_chip_data *data = get_irq_desc_chip_data(irq); irq -= data->irq_offset; data->mask |= (1 << irq); } static void unmask(unsigned int irq) { struct irq_chip_data *data = get_irq_desc_chip_data(irq); irq -= data->irq_offset; data->mask &= ~(1 << irq); } static void bus_sync_unlock(unsigned int irq) { struct irq_chip_data *data = get_irq_desc_chip_data(irq); if (data->mask != data->mask_status) { do_bus_magic_to_set_mask(data->mask); data->mask_status = data->mask; } mutex_unlock(&data->mutex); } The device drivers can use request_threaded_irq, free_irq, disable_irq and enable_irq as usual with the only restriction that the calls need to come from non atomic context. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Mark Brown <broonie@opensource.wolfsonmicro.com> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com> Cc: Trilok Soni <soni.trilok@gmail.com> Cc: Pavel Machek <pavel@ucw.cz> Cc: Brian Swetland <swetland@google.com> Cc: Joonyoung Shim <jy0922.shim@samsung.com> Cc: m.szyprowski@samsung.com Cc: t.fujak@samsung.com Cc: kyungmin.park@samsung.com, Cc: David Brownell <david-b@pacbell.net> Cc: Daniel Ribeiro <drwyrm@gmail.com> Cc: arve@android.com Cc: Barry Song <21cnbao@gmail.com>
Diffstat (limited to 'kernel/irq/chip.c')
-rw-r--r--kernel/irq/chip.c2
1 files changed, 2 insertions, 0 deletions
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