* [PATCH] update generic irq for parisc
@ 2006-09-09 18:51 James Bottomley
2006-09-09 19:16 ` James Bottomley
2006-10-04 3:14 ` Benjamin Herrenschmidt
0 siblings, 2 replies; 3+ messages in thread
From: James Bottomley @ 2006-09-09 18:51 UTC (permalink / raw)
To: linux-arch
We have had a specific problem with the current generic linux IRQ code
for ages, in that indirection via function pointers is horribly
expensive for us (basically, the CPU pipes stall). We'd like to use the
new genirq infrastructure to mitigate some of the problem.
I didn't want simply to move the irq handlers back into our arch code
again, since that would remove all the benefits of common handling code.
What I did was template out the common code in a way that keeps it
common but allows an architecture to modify it (for us to put our acks
and eoi's in as functions instead of function pointers).
If everyone is OK with this, I'll introduce a new type of interrupt with
a specific handler (so for our heavily called interrupts like timer and
IPI we don't even need to indirect through action->handler()).
James
Index: parisc-2.6/include/linux/irq_helpers.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ parisc-2.6/include/linux/irq_helpers.h 2006-09-09 08:21:31.000000000 -0700
@@ -0,0 +1,64 @@
+#ifdef CONFIG_SMP
+#define HANDLE_PERCPU_IRQ(NAME, ACK, EOI) \
+void fastcall \
+handle_percpu_irq##NAME(unsigned int irq, struct irq_desc *desc, \
+ struct pt_regs *regs) \
+{ \
+ irqreturn_t action_ret; \
+ \
+ kstat_this_cpu.irqs[irq]++; \
+ \
+ ACK(desc, irq); \
+ \
+ action_ret = handle_IRQ_event(irq, regs, desc->action); \
+ if (!noirqdebug) \
+ note_interrupt(irq, desc, action_ret, regs); \
+ \
+ EOI(desc,irq); \
+}
+#else
+#define HANDLE_PERCPU_IRQ(NAME, ACK, END)
+#endif /* CONFIG_SMP */
+
+#define HANDLE_LEVEL_IRQ(NAME, MASK, UNMASK) \
+void fastcall \
+handle_level_irq##NAME(unsigned int irq, struct irq_desc *desc, \
+ struct pt_regs *regs) \
+{ \
+ unsigned int cpu = smp_processor_id(); \
+ struct irqaction *action; \
+ irqreturn_t action_ret; \
+ \
+ spin_lock(&desc->lock); \
+ MASK(desc, irq); \
+ \
+ if (unlikely(desc->status & IRQ_INPROGRESS)) \
+ goto out; \
+ desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); \
+ kstat_cpu(cpu).irqs[irq]++; \
+ \
+ /* \
+ * If its disabled or no action available \
+ * keep it masked and get out of here \
+ */ \
+ action = desc->action; \
+ if (unlikely(!action || (desc->status & IRQ_DISABLED))) { \
+ desc->status |= IRQ_PENDING; \
+ goto out; \
+ } \
+ \
+ desc->status |= IRQ_INPROGRESS; \
+ desc->status &= ~IRQ_PENDING; \
+ spin_unlock(&desc->lock); \
+ \
+ action_ret = handle_IRQ_event(irq, regs, action); \
+ if (!noirqdebug) \
+ note_interrupt(irq, desc, action_ret, regs); \
+ \
+ spin_lock(&desc->lock); \
+ desc->status &= ~IRQ_INPROGRESS; \
+out: \
+ UNMASK(desc,irq); \
+ spin_unlock(&desc->lock); \
+}
+
Index: parisc-2.6/kernel/irq/chip.c
===================================================================
--- parisc-2.6.orig/kernel/irq/chip.c 2006-09-09 07:32:35.000000000 -0700
+++ parisc-2.6/kernel/irq/chip.c 2006-09-09 07:58:45.000000000 -0700
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
+#include <linux/irq_helpers.h>
#include "internals.h"
@@ -186,6 +187,24 @@
}
}
+static inline void unmask_enabled_irq(struct irq_desc *desc, int irq)
+{
+ if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
+ desc->chip->unmask(irq);
+}
+
+static inline void ack_irq(struct irq_desc *desc, int irq)
+{
+ if (desc->chip->ack)
+ desc->chip->ack(irq);
+}
+
+static inline void eoi_irq(struct irq_desc *desc, int irq)
+{
+ if (desc->chip->eoi)
+ desc->chip->eoi(irq);
+}
+
/**
* handle_simple_irq - Simple and software-decoded IRQs.
* @irq: the interrupt number
@@ -241,46 +260,7 @@
* it after the associated handler has acknowledged the device, so the
* interrupt line is back to inactive.
*/
-void fastcall
-handle_level_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
-{
- unsigned int cpu = smp_processor_id();
- struct irqaction *action;
- irqreturn_t action_ret;
-
- spin_lock(&desc->lock);
- mask_ack_irq(desc, irq);
-
- if (unlikely(desc->status & IRQ_INPROGRESS))
- goto out;
- desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
- kstat_cpu(cpu).irqs[irq]++;
-
- /*
- * If its disabled or no action available
- * keep it masked and get out of here
- */
- action = desc->action;
- if (unlikely(!action || (desc->status & IRQ_DISABLED))) {
- desc->status |= IRQ_PENDING;
- goto out;
- }
-
- desc->status |= IRQ_INPROGRESS;
- desc->status &= ~IRQ_PENDING;
- spin_unlock(&desc->lock);
-
- action_ret = handle_IRQ_event(irq, regs, action);
- if (!noirqdebug)
- note_interrupt(irq, desc, action_ret, regs);
-
- spin_lock(&desc->lock);
- desc->status &= ~IRQ_INPROGRESS;
-out:
- if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
- desc->chip->unmask(irq);
- spin_unlock(&desc->lock);
-}
+HANDLE_LEVEL_IRQ(, mask_ack_irq, unmask_enabled_irq)
/**
* handle_fasteoi_irq - irq handler for transparent controllers
@@ -416,7 +396,6 @@
spin_unlock(&desc->lock);
}
-#ifdef CONFIG_SMP
/**
* handle_percpu_IRQ - Per CPU local irq handler
* @irq: the interrupt number
@@ -425,25 +404,19 @@
*
* Per CPU interrupts on SMP machines without locking requirements
*/
-void fastcall
-handle_percpu_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
-{
- irqreturn_t action_ret;
-
- kstat_this_cpu.irqs[irq]++;
+HANDLE_PERCPU_IRQ(, ack_irq, eoi_irq)
- if (desc->chip->ack)
- desc->chip->ack(irq);
-
- action_ret = handle_IRQ_event(irq, regs, desc->action);
- if (!noirqdebug)
- note_interrupt(irq, desc, action_ret, regs);
-
- if (desc->chip->eoi)
- desc->chip->eoi(irq);
+#ifdef ARCH_HAS_IRQ_HANDLERS
+#include <asm/irq-handlers.h>
+#else
+static inline char *arch_handle_irq_name(void fastcall (*handle)(unsigned int,
+ struct irq_desc *,
+ struct pt_regs *))
+{
+ return NULL;
}
+#endif
-#endif /* CONFIG_SMP */
void
__set_irq_handler(unsigned int irq,
@@ -533,5 +506,5 @@
if (handle == handle_bad_irq)
return "bad ";
- return NULL;
+ return arch_handle_irq_name(handle);
}
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH] update generic irq for parisc
2006-09-09 18:51 [PATCH] update generic irq for parisc James Bottomley
@ 2006-09-09 19:16 ` James Bottomley
2006-10-04 3:14 ` Benjamin Herrenschmidt
1 sibling, 0 replies; 3+ messages in thread
From: James Bottomley @ 2006-09-09 19:16 UTC (permalink / raw)
To: linux-arch
And for reference, this is how we plan to use the generic irq
enhancements on parisc.
James
Index: parisc-2.6/include/asm-parisc/irq-handlers.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ parisc-2.6/include/asm-parisc/irq-handlers.h 2006-09-09 10:57:28.000000000 -0700
@@ -0,0 +1,12 @@
+HANDLE_LEVEL_IRQ(_chip, cpu_ack_irq, cpu_end_irq)
+HANDLE_PERCPU_IRQ(_chip, cpu_ack_irq, cpu_end_irq)
+#ifdef CONFIG_IOSAPIC
+HANDLE_LEVEL_IRQ(_iosapic, cpu_ack_irq, iosapic_end_irq)
+#endif
+
+static inline char *arch_handle_irq_name(void fastcall (*handle)(unsigned int,
+ struct irq_desc *,
+ struct pt_regs *))
+{
+ return NULL;
+}
Index: parisc-2.6/include/asm-parisc/irq.h
===================================================================
--- parisc-2.6.orig/include/asm-parisc/irq.h 2006-09-09 08:30:10.000000000 -0700
+++ parisc-2.6/include/asm-parisc/irq.h 2006-09-09 11:24:25.000000000 -0700
@@ -26,6 +26,17 @@
#define NR_IRQS (CPU_IRQ_MAX + 1)
+#define ARCH_HAS_IRQ_HANDLERS
+
+struct irq_desc;
+
+void fastcall handle_level_irq_chip(unsigned int irq, struct irq_desc *desc,
+ struct pt_regs *regs);
+void fastcall handle_level_irq_iosapic(unsigned int irq, struct irq_desc *desc,
+ struct pt_regs *regs);
+void fastcall handle_percpu_irq_chip(unsigned int irq, struct irq_desc *desc,
+ struct pt_regs *regs);
+
static __inline__ int irq_canonicalize(int irq)
{
return (irq == 2) ? 9 : irq;
@@ -39,8 +50,9 @@
*/
void no_ack_irq(unsigned int irq);
void no_end_irq(unsigned int irq);
-void cpu_ack_irq(unsigned int irq);
-void cpu_end_irq(unsigned int irq);
+void cpu_ack_irq(struct irq_desc *, unsigned int irq);
+void cpu_end_irq(struct irq_desc *, unsigned int irq);
+void iosapic_end_irq(struct irq_desc *, unsigned int irq);
extern int txn_alloc_irq(unsigned int nbits);
extern int txn_claim_irq(int);
Index: parisc-2.6/arch/parisc/kernel/irq.c
===================================================================
--- parisc-2.6.orig/arch/parisc/kernel/irq.c 2006-09-09 10:01:02.000000000 -0700
+++ parisc-2.6/arch/parisc/kernel/irq.c 2006-09-09 11:17:49.000000000 -0700
@@ -88,7 +88,7 @@
void no_ack_irq(unsigned int irq) { }
void no_end_irq(unsigned int irq) { }
-void cpu_ack_irq(unsigned int irq)
+void cpu_ack_irq(struct irq_desc *dummy, unsigned int irq)
{
unsigned long mask = EIEM_MASK(irq);
int cpu = smp_processor_id();
@@ -105,7 +105,7 @@
mtctl(mask, 23);
}
-void cpu_end_irq(unsigned int irq)
+void cpu_end_irq(struct irq_desc *dummy, unsigned int irq)
{
unsigned long mask = EIEM_MASK(irq);
int cpu = smp_processor_id();
@@ -155,8 +155,6 @@
.shutdown = cpu_disable_irq,
.enable = cpu_enable_irq,
.disable = cpu_disable_irq,
- .ack = cpu_ack_irq,
- .end = cpu_end_irq,
#ifdef CONFIG_SMP
.set_affinity = cpu_set_affinity_irq,
#endif
@@ -253,8 +251,8 @@
return -EBUSY;
if (type) {
- irq_desc[irq].chip = type;
- irq_desc[irq].chip_data = data;
+ set_irq_chip(irq, type);
+ set_irq_chip_data(irq, data);
cpu_interrupt_type.enable(irq);
}
return 0;
@@ -375,7 +373,7 @@
goto set_out;
}
#endif
- __do_IRQ(irq, regs);
+ generic_handle_irq(irq, regs);
out:
irq_exit();
@@ -403,15 +401,17 @@
static void claim_cpu_irqs(void)
{
int i;
- for (i = CPU_IRQ_BASE; i <= CPU_IRQ_MAX; i++) {
- irq_desc[i].chip = &cpu_interrupt_type;
- }
+ for (i = CPU_IRQ_BASE; i <= CPU_IRQ_MAX; i++)
+ set_irq_chip_and_handler(i, &cpu_interrupt_type,
+ handle_level_irq_chip);
irq_desc[TIMER_IRQ].action = &timer_action;
irq_desc[TIMER_IRQ].status |= IRQ_PER_CPU;
#ifdef CONFIG_SMP
+ set_irq_handler(TIMER_IRQ, handle_percpu_irq_chip);
irq_desc[IPI_IRQ].action = &ipi_action;
irq_desc[IPI_IRQ].status = IRQ_PER_CPU;
+ set_irq_handler(IPI_IRQ, handle_percpu_irq_chip);
#endif
}
Index: parisc-2.6/drivers/parisc/iosapic.c
===================================================================
--- parisc-2.6.orig/drivers/parisc/iosapic.c 2006-09-09 10:26:14.000000000 -0700
+++ parisc-2.6/drivers/parisc/iosapic.c 2006-09-09 11:24:20.000000000 -0700
@@ -686,13 +686,13 @@
* i386/ia64 support ISA devices and have to deal with
* edge-triggered interrupts too.
*/
-static void iosapic_end_irq(unsigned int irq)
+void iosapic_end_irq(struct irq_desc *dummy, unsigned int irq)
{
struct vector_info *vi = iosapic_get_vector(irq);
DBG(KERN_DEBUG "end_irq(%d): eoi(%p, 0x%x)\n", irq,
vi->eoi_addr, vi->eoi_data);
iosapic_eoi(vi->eoi_addr, vi->eoi_data);
- cpu_end_irq(irq);
+ cpu_end_irq(NULL, irq);
}
static unsigned int iosapic_startup_irq(unsigned int irq)
@@ -729,8 +729,6 @@
.shutdown = iosapic_disable_irq,
.enable = iosapic_enable_irq,
.disable = iosapic_disable_irq,
- .ack = cpu_ack_irq,
- .end = iosapic_end_irq,
#ifdef CONFIG_SMP
.set_affinity = iosapic_set_affinity_irq,
#endif
@@ -819,6 +817,7 @@
vi->eoi_data = cpu_to_le32(vi->txn_data);
cpu_claim_irq(vi->txn_irq, &iosapic_interrupt_type, vi);
+ set_irq_handler(vi->txn_irq, handle_level_irq_iosapic);
out:
pcidev->irq = vi->txn_irq;
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH] update generic irq for parisc
2006-09-09 18:51 [PATCH] update generic irq for parisc James Bottomley
2006-09-09 19:16 ` James Bottomley
@ 2006-10-04 3:14 ` Benjamin Herrenschmidt
1 sibling, 0 replies; 3+ messages in thread
From: Benjamin Herrenschmidt @ 2006-10-04 3:14 UTC (permalink / raw)
To: James Bottomley; +Cc: linux-arch
On Sat, 2006-09-09 at 13:51 -0500, James Bottomley wrote:
> We have had a specific problem with the current generic linux IRQ code
> for ages, in that indirection via function pointers is horribly
> expensive for us (basically, the CPU pipes stall). We'd like to use the
> new genirq infrastructure to mitigate some of the problem.
>
> I didn't want simply to move the irq handlers back into our arch code
> again, since that would remove all the benefits of common handling code.
> What I did was template out the common code in a way that keeps it
> common but allows an architecture to modify it (for us to put our acks
> and eoi's in as functions instead of function pointers).
>
> If everyone is OK with this, I'll introduce a new type of interrupt with
> a specific handler (so for our heavily called interrupts like timer and
> IPI we don't even need to indirect through action->handler()).
I don't have any objection to this patch as long as the current
behaviour with function pointers still works fine (which seems to be the
case from a quick look through the patch). On PowerPC, we have a huge
variety of interrupt controllers and cascaded controllers and thus we
can't really apply your shortcut.
Ben.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2006-10-04 3:14 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-09-09 18:51 [PATCH] update generic irq for parisc James Bottomley
2006-09-09 19:16 ` James Bottomley
2006-10-04 3:14 ` Benjamin Herrenschmidt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox