Free setup_irq() interrupt V3
These patches improve the early interrupt functions to support
both registering and unregistering. While at it the functions
are exported so they can be used both early from compiled-in
driver and as a regular module.
[PATCH 01/03] Add remove_irq() for freeing of setup_irq() irqs
[PATCH 02/03] Match remove_irq() args with setup_irq()
[PATCH 03/03] Export remove_irq() and setup_irq() symbols
The first patch does exactly what Ingo and Thomas suggests as
feedback to V2. The second and third are my more or less useful
improvements. =) Feel free to just pick up the first one.
Signed-off-by: Magnus Damm <[email protected]>
---
Applies to tip.git.
include/linux/irq.h | 3 +-
kernel/irq/manage.c | 67 ++++++++++++++++++++++++++++++++++-----------------
2 files changed, 47 insertions(+), 23 deletions(-)
From: Magnus Damm <[email protected]>
This patch adds a remove_irq() function for releasing
interrupts requested with setup_irq().
Without this patch we have no way of releasing such
interrupts since free_irq() today tries to kfree()
the irqaction passed with setup_irq().
Signed-off-by: Magnus Damm <[email protected]>
---
Changes since V2:
- name the function remove_irq() instead of __free_irq(), thanks Thomas!
Changes since V1:
- break out a __free_irq() function, thanks Ingo!
include/linux/irq.h | 1 +
kernel/irq/manage.c | 39 ++++++++++++++++++++++++++-------------
2 files changed, 27 insertions(+), 13 deletions(-)
--- 0001/include/linux/irq.h
+++ work/include/linux/irq.h 2009-03-12 18:36:20.000000000 +0900
@@ -228,6 +228,7 @@ typedef struct irq_desc irq_desc_t;
#include <asm/hw_irq.h>
extern int setup_irq(unsigned int irq, struct irqaction *new);
+extern struct irqaction *remove_irq(unsigned int irq, void *dev_id);
#ifdef CONFIG_GENERIC_HARDIRQS
--- 0001/kernel/irq/manage.c
+++ work/kernel/irq/manage.c 2009-03-12 20:29:17.000000000 +0900
@@ -551,20 +551,14 @@ int setup_irq(unsigned int irq, struct i
}
/**
- * free_irq - free an interrupt
+ * remove_irq - free an interrupt
* @irq: Interrupt line to free
* @dev_id: Device identity to free
*
- * Remove an interrupt handler. The handler is removed and if the
- * interrupt line is no longer in use by any driver it is disabled.
- * On a shared IRQ the caller must ensure the interrupt is disabled
- * on the card it drives before calling this function. The function
- * does not return until any executing interrupts for this IRQ
- * have completed.
- *
- * This function must not be called from interrupt context.
+ * Used to remove interrupts statically setup by the early boot process.
*/
-void free_irq(unsigned int irq, void *dev_id)
+
+struct irqaction *remove_irq(unsigned int irq, void *dev_id)
{
struct irq_desc *desc = irq_to_desc(irq);
struct irqaction *action, **action_ptr;
@@ -573,7 +567,7 @@ void free_irq(unsigned int irq, void *de
WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq);
if (!desc)
- return;
+ return NULL;
spin_lock_irqsave(&desc->lock, flags);
@@ -589,7 +583,7 @@ void free_irq(unsigned int irq, void *de
WARN(1, "Trying to free already-free IRQ %d\n", irq);
spin_unlock_irqrestore(&desc->lock, flags);
- return;
+ return NULL;
}
if (action->dev_id == dev_id)
@@ -636,7 +630,26 @@ void free_irq(unsigned int irq, void *de
local_irq_restore(flags);
}
#endif
- kfree(action);
+ return action;
+}
+
+/**
+ * free_irq - free an interrupt allocated with request_irq
+ * @irq: Interrupt line to free
+ * @dev_id: Device identity to free
+ *
+ * Remove an interrupt handler. The handler is removed and if the
+ * interrupt line is no longer in use by any driver it is disabled.
+ * On a shared IRQ the caller must ensure the interrupt is disabled
+ * on the card it drives before calling this function. The function
+ * does not return until any executing interrupts for this IRQ
+ * have completed.
+ *
+ * This function must not be called from interrupt context.
+ */
+void free_irq(unsigned int irq, void *dev_id)
+{
+ kfree(remove_irq(irq, dev_id));
}
EXPORT_SYMBOL(free_irq);
From: Magnus Damm <[email protected]>
Export the setup_irq() and remove_irq() symbols.
I'd like to export these functions since I have timer
code that needs to use setup_irq() early on (too early
for request_irq()), and the same code can also be
compiled as a module.
Signed-off-by: Magnus Damm <[email protected]>
---
kernel/irq/manage.c | 2 ++
1 file changed, 2 insertions(+)
--- 0003/kernel/irq/manage.c
+++ work/kernel/irq/manage.c 2009-03-12 18:49:09.000000000 +0900
@@ -549,6 +549,7 @@ int setup_irq(unsigned int irq, struct i
return __setup_irq(irq, desc, act);
}
+EXPORT_SYMBOL(setup_irq);
/*
* Internal function to unregister an irqaction - used to free
@@ -640,6 +641,7 @@ void remove_irq(unsigned int irq, struct
{
__free_irq(irq, act->dev_id);
}
+EXPORT_SYMBOL(remove_irq);
/**
* free_irq - free an interrupt allocated with request_irq
From: Magnus Damm <[email protected]>
Modify remove_irq() to match setup_irq().
Signed-off-by: Magnus Damm <[email protected]>
---
include/linux/irq.h | 2 +-
kernel/irq/manage.c | 26 +++++++++++++++++---------
2 files changed, 18 insertions(+), 10 deletions(-)
--- 0002/include/linux/irq.h
+++ work/include/linux/irq.h 2009-03-12 20:30:10.000000000 +0900
@@ -228,7 +228,7 @@ typedef struct irq_desc irq_desc_t;
#include <asm/hw_irq.h>
extern int setup_irq(unsigned int irq, struct irqaction *new);
-extern struct irqaction *remove_irq(unsigned int irq, void *dev_id);
+extern void remove_irq(unsigned int irq, struct irqaction *act);
#ifdef CONFIG_GENERIC_HARDIRQS
--- 0002/kernel/irq/manage.c
+++ work/kernel/irq/manage.c 2009-03-12 20:31:05.000000000 +0900
@@ -550,15 +550,11 @@ int setup_irq(unsigned int irq, struct i
return __setup_irq(irq, desc, act);
}
-/**
- * remove_irq - free an interrupt
- * @irq: Interrupt line to free
- * @dev_id: Device identity to free
- *
- * Used to remove interrupts statically setup by the early boot process.
+ /*
+ * Internal function to unregister an irqaction - used to free
+ * regular and special interrupts that are part of the architecture.
*/
-
-struct irqaction *remove_irq(unsigned int irq, void *dev_id)
+static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
{
struct irq_desc *desc = irq_to_desc(irq);
struct irqaction *action, **action_ptr;
@@ -634,6 +630,18 @@ struct irqaction *remove_irq(unsigned in
}
/**
+ * remove_irq - free an interrupt
+ * @irq: Interrupt line to free
+ * @act: irqaction for the interrupt
+ *
+ * Used to remove interrupts statically setup by the early boot process.
+ */
+void remove_irq(unsigned int irq, struct irqaction *act)
+{
+ __free_irq(irq, act->dev_id);
+}
+
+/**
* free_irq - free an interrupt allocated with request_irq
* @irq: Interrupt line to free
* @dev_id: Device identity to free
@@ -649,7 +657,7 @@ struct irqaction *remove_irq(unsigned in
*/
void free_irq(unsigned int irq, void *dev_id)
{
- kfree(remove_irq(irq, dev_id));
+ kfree(__free_irq(irq, dev_id));
}
EXPORT_SYMBOL(free_irq);
Commit-ID: f21cfb258df6dd3ea0b3e56d75c7e994edb81b35
Gitweb: http://git.kernel.org/tip/f21cfb258df6dd3ea0b3e56d75c7e994edb81b35
Author: Magnus Damm <[email protected]>
AuthorDate: Thu, 12 Mar 2009 21:05:42 +0900
Commit: Ingo Molnar <[email protected]>
CommitDate: Thu, 12 Mar 2009 13:16:32 +0100
irq: add remove_irq() for freeing of setup_irq() irqs
Impact: add new API
This patch adds a remove_irq() function for releasing
interrupts requested with setup_irq().
Without this patch we have no way of releasing such
interrupts since free_irq() today tries to kfree()
the irqaction passed with setup_irq().
Signed-off-by: Magnus Damm <[email protected]>
LKML-Reference: <[email protected]>
Signed-off-by: Ingo Molnar <[email protected]>
---
include/linux/irq.h | 1 +
kernel/irq/manage.c | 39 ++++++++++++++++++++++++++-------------
2 files changed, 27 insertions(+), 13 deletions(-)
diff --git a/include/linux/irq.h b/include/linux/irq.h
index f899b50..56f9988 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -236,6 +236,7 @@ typedef struct irq_desc irq_desc_t;
#include <asm/hw_irq.h>
extern int setup_irq(unsigned int irq, struct irqaction *new);
+extern struct irqaction *remove_irq(unsigned int irq, void *dev_id);
#ifdef CONFIG_GENERIC_HARDIRQS
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 52ee171..8b069a7 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -551,20 +551,14 @@ int setup_irq(unsigned int irq, struct irqaction *act)
}
/**
- * free_irq - free an interrupt
+ * remove_irq - free an interrupt
* @irq: Interrupt line to free
* @dev_id: Device identity to free
*
- * Remove an interrupt handler. The handler is removed and if the
- * interrupt line is no longer in use by any driver it is disabled.
- * On a shared IRQ the caller must ensure the interrupt is disabled
- * on the card it drives before calling this function. The function
- * does not return until any executing interrupts for this IRQ
- * have completed.
- *
- * This function must not be called from interrupt context.
+ * Used to remove interrupts statically setup by the early boot process.
*/
-void free_irq(unsigned int irq, void *dev_id)
+
+struct irqaction *remove_irq(unsigned int irq, void *dev_id)
{
struct irq_desc *desc = irq_to_desc(irq);
struct irqaction *action, **action_ptr;
@@ -573,7 +567,7 @@ void free_irq(unsigned int irq, void *dev_id)
WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq);
if (!desc)
- return;
+ return NULL;
spin_lock_irqsave(&desc->lock, flags);
@@ -589,7 +583,7 @@ void free_irq(unsigned int irq, void *dev_id)
WARN(1, "Trying to free already-free IRQ %d\n", irq);
spin_unlock_irqrestore(&desc->lock, flags);
- return;
+ return NULL;
}
if (action->dev_id == dev_id)
@@ -636,7 +630,26 @@ void free_irq(unsigned int irq, void *dev_id)
local_irq_restore(flags);
}
#endif
- kfree(action);
+ return action;
+}
+
+/**
+ * free_irq - free an interrupt allocated with request_irq
+ * @irq: Interrupt line to free
+ * @dev_id: Device identity to free
+ *
+ * Remove an interrupt handler. The handler is removed and if the
+ * interrupt line is no longer in use by any driver it is disabled.
+ * On a shared IRQ the caller must ensure the interrupt is disabled
+ * on the card it drives before calling this function. The function
+ * does not return until any executing interrupts for this IRQ
+ * have completed.
+ *
+ * This function must not be called from interrupt context.
+ */
+void free_irq(unsigned int irq, void *dev_id)
+{
+ kfree(remove_irq(irq, dev_id));
}
EXPORT_SYMBOL(free_irq);
Commit-ID: cbf94f06824780183e4bba165c7c29d5c7bd9a51
Gitweb: http://git.kernel.org/tip/cbf94f06824780183e4bba165c7c29d5c7bd9a51
Author: Magnus Damm <[email protected]>
AuthorDate: Thu, 12 Mar 2009 21:05:51 +0900
Commit: Ingo Molnar <[email protected]>
CommitDate: Thu, 12 Mar 2009 13:16:33 +0100
irq: match remove_irq() args with setup_irq()
Modify remove_irq() to match setup_irq().
Signed-off-by: Magnus Damm <[email protected]>
LKML-Reference: <[email protected]>
Signed-off-by: Ingo Molnar <[email protected]>
---
include/linux/irq.h | 2 +-
kernel/irq/manage.c | 26 +++++++++++++++++---------
2 files changed, 18 insertions(+), 10 deletions(-)
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 56f9988..737eafb 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -236,7 +236,7 @@ typedef struct irq_desc irq_desc_t;
#include <asm/hw_irq.h>
extern int setup_irq(unsigned int irq, struct irqaction *new);
-extern struct irqaction *remove_irq(unsigned int irq, void *dev_id);
+extern void remove_irq(unsigned int irq, struct irqaction *act);
#ifdef CONFIG_GENERIC_HARDIRQS
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 8b069a7..fc16570 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -550,15 +550,11 @@ int setup_irq(unsigned int irq, struct irqaction *act)
return __setup_irq(irq, desc, act);
}
-/**
- * remove_irq - free an interrupt
- * @irq: Interrupt line to free
- * @dev_id: Device identity to free
- *
- * Used to remove interrupts statically setup by the early boot process.
+ /*
+ * Internal function to unregister an irqaction - used to free
+ * regular and special interrupts that are part of the architecture.
*/
-
-struct irqaction *remove_irq(unsigned int irq, void *dev_id)
+static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
{
struct irq_desc *desc = irq_to_desc(irq);
struct irqaction *action, **action_ptr;
@@ -634,6 +630,18 @@ struct irqaction *remove_irq(unsigned int irq, void *dev_id)
}
/**
+ * remove_irq - free an interrupt
+ * @irq: Interrupt line to free
+ * @act: irqaction for the interrupt
+ *
+ * Used to remove interrupts statically setup by the early boot process.
+ */
+void remove_irq(unsigned int irq, struct irqaction *act)
+{
+ __free_irq(irq, act->dev_id);
+}
+
+/**
* free_irq - free an interrupt allocated with request_irq
* @irq: Interrupt line to free
* @dev_id: Device identity to free
@@ -649,7 +657,7 @@ struct irqaction *remove_irq(unsigned int irq, void *dev_id)
*/
void free_irq(unsigned int irq, void *dev_id)
{
- kfree(remove_irq(irq, dev_id));
+ kfree(__free_irq(irq, dev_id));
}
EXPORT_SYMBOL(free_irq);
Commit-ID: eb53b4e8fef10ccccb49a6dbb5e19ca84ba5a305
Gitweb: http://git.kernel.org/tip/eb53b4e8fef10ccccb49a6dbb5e19ca84ba5a305
Author: Magnus Damm <[email protected]>
AuthorDate: Thu, 12 Mar 2009 21:05:59 +0900
Commit: Ingo Molnar <[email protected]>
CommitDate: Thu, 12 Mar 2009 13:16:33 +0100
irq: export remove_irq() and setup_irq() symbols
Export the setup_irq() and remove_irq() symbols.
I'd like to export these functions since I have timer
code that needs to use setup_irq() early on (too early
for request_irq()), and the same code can also be
compiled as a module.
Signed-off-by: Magnus Damm <[email protected]>
LKML-Reference: <[email protected]>
[ changed to _GPL as these are special APIs deep inside the irq layer. ]
Signed-off-by: Ingo Molnar <[email protected]>
---
kernel/irq/manage.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index fc16570..e28db0f 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -549,6 +549,7 @@ int setup_irq(unsigned int irq, struct irqaction *act)
return __setup_irq(irq, desc, act);
}
+EXPORT_SYMBOL_GPL(setup_irq);
/*
* Internal function to unregister an irqaction - used to free
@@ -640,6 +641,7 @@ void remove_irq(unsigned int irq, struct irqaction *act)
{
__free_irq(irq, act->dev_id);
}
+EXPORT_SYMBOL_GPL(remove_irq);
/**
* free_irq - free an interrupt allocated with request_irq