lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:	Fri, 13 Feb 2009 04:38:57 +0100
From:	Frederic Weisbecker <fweisbec@...il.com>
To:	Steven Rostedt <rostedt@...dmis.org>
Cc:	linux-kernel@...r.kernel.org
Subject: [PATCH] rt/threadirqs: put the irq thread handler in a callback

Currently, when a hardirq is threaded, it is processed by do_hardirq()
which guess the best low-level handler for this irq.

This makes several branch conditions to check for each irq triggered,
adding some (very small) latencies since we are in a fastpath (irq disabled)
of the irq processing.

So it's better to put these checks only once when the handler of the irq is set
and then only dereference one pointer to find the appropriate callback.

This patch makes the irq thread handler a field in struct irq_desc.

[Note, I'm not sure the check if (!desc->handle_irq_thread) is really
useful. I've put it to ensure that even an irq_desc which never gone to
__set_irq_handler() can be handled. But I'm not sure it is possible.]

Signed-off-by: Frederic Weisbecker <fweisbec@...il.com>
---
 include/linux/irq.h |   11 ++++++++++-
 kernel/irq/chip.c   |    2 ++
 kernel/irq/manage.c |   27 ++++++++++++++++++---------
 3 files changed, 30 insertions(+), 10 deletions(-)

diff --git a/include/linux/irq.h b/include/linux/irq.h
index aa9d62e..ff83182 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -30,6 +30,7 @@
 struct irq_desc;
 typedef	void (*irq_flow_handler_t)(unsigned int irq,
 					    struct irq_desc *desc);
+typedef void (*irq_thread_handler_t)(struct irq_desc *desc);
 
 
 /*
@@ -136,6 +137,7 @@ struct irq_chip {
  * struct irq_desc - interrupt descriptor
  * @irq:		interrupt number for this descriptor
  * @handle_irq:		highlevel irq-events handler [if NULL, __do_IRQ()]
+ * @handle_irq_thread:	highlevel threaded irq-events handler
  * @chip:		low level interrupt hardware access
  * @msi_desc:		MSI descriptor
  * @handler_data:	per-IRQ data for the irq_chip methods
@@ -161,6 +163,9 @@ struct irq_chip {
 struct irq_desc {
 	unsigned int		irq;
 	irq_flow_handler_t	handle_irq;
+#ifdef CONFIG_PREEMPT_HARDIRQS
+	irq_thread_handler_t	handle_irq_thread;
+#endif
 	struct irq_chip		*chip;
 	struct msi_desc		*msi_desc;
 	void			*handler_data;
@@ -393,10 +398,14 @@ extern int set_irq_msi(unsigned int irq, struct msi_desc *entry);
 extern void early_init_hardirqs(void);
 extern cycles_t irq_timestamp(unsigned int irq);
 
-#if defined(CONFIG_PREEMPT_HARDIRQS)
+#ifdef CONFIG_PREEMPT_HARDIRQS
 extern void init_hardirqs(void);
+extern void
+__set_irq_thread_handler(struct irq_desc *desc, irq_flow_handler_t handle);
 #else
 static inline void init_hardirqs(void) { }
+static inline void
+__set_irq_thread_handler(struct irq_desc *desc, irq_flow_handler_t handle) { }
 #endif
 
 #else	/* end GENERIC HARDIRQS */
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index f25b747..e8aa31c 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -605,6 +605,8 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
 	desc->handle_irq = handle;
 	desc->name = name;
 
+	__set_irq_thread_handler(desc, handle);
+
 	if (handle != handle_bad_irq && is_chained) {
 		desc->status &= ~IRQ_DISABLED;
 		desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE;
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 8e963a9..776c715 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -901,6 +901,21 @@ static void thread_do_irq(irq_desc_t *desc)
 	desc->chip->end(irq);
 }
 
+void
+__set_irq_thread_handler(struct irq_desc *desc, irq_flow_handler_t handle)
+{
+	if (handle == handle_simple_irq)
+		desc->handle_irq_thread = thread_simple_irq;
+	else if (handle == handle_level_irq)
+		desc->handle_irq_thread = thread_level_irq;
+	else if (handle == handle_fasteoi_irq)
+		desc->handle_irq_thread = thread_fasteoi_irq;
+	else if (handle == handle_edge_irq)
+		desc->handle_irq_thread = thread_edge_irq;
+	else
+		desc->handle_irq_thread = thread_do_irq;
+}
+
 static void do_hardirq(struct irq_desc *desc)
 {
 	spin_lock(&desc->lock);
@@ -908,16 +923,10 @@ static void do_hardirq(struct irq_desc *desc)
 	if (!(desc->status & IRQ_INPROGRESS))
 		goto out;
 
-	if (desc->handle_irq == handle_simple_irq)
-		thread_simple_irq(desc);
-	else if (desc->handle_irq == handle_level_irq)
-		thread_level_irq(desc);
-	else if (desc->handle_irq == handle_fasteoi_irq)
-		thread_fasteoi_irq(desc);
-	else if (desc->handle_irq == handle_edge_irq)
-		thread_edge_irq(desc);
-	else
+	if (unlikely(!desc->handle_irq_thread))
 		thread_do_irq(desc);
+	else
+		desc->handle_irq_thread(desc);
  out:
 	spin_unlock(&desc->lock);
 
-- 
1.6.1


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ