aboutsummaryrefslogtreecommitdiffstats
path: root/include
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 /include
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 'include')
-rw-r--r--include/linux/irq.h6
1 files changed, 6 insertions, 0 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);