[parisc-linux-cvs] Re: 2.4.19-pa15 enable IRQ distribution
Grant Grundler
grundler@dsl2.external.hp.com
Fri, 13 Sep 2002 00:56:50 -0600
Grant Grundler wrote:
> Log message:
> 2.4.19-pa15
> Enable interrupt distribution. Works on A500.
Alan,
Can you apply the following patch to your merged tree?
I would like to see parisc distribute "IRQs" in generic 2.4 kernels someday.
For 2.4.19-pa15, /proc/interrupts output now looks like:
a500:~# cat /proc/interrupts
CPU00 CPU01
64: 406478 405419 PARISC-CPU timer
65: 18231 23944 PARISC-CPU IPI
66: 22055 0 PARISC-CPU IO-SAPIC00-L0
67: 0 30 PARISC-CPU IO-SAPIC00-L1
68: 0 0 PARISC-CPU IO-SAPIC00-L2
69: 0 10281 PARISC-CPU IO-SAPIC00-L2
70: 10807 0 PARISC-CPU IO-SAPIC00-L3
71: 0 2709 PARISC-CPU IO-SAPIC00-L4
72: 0 0 PARISC-CPU IO-SAPIC00-L5
73: 0 0 PARISC-CPU IO-SAPIC02-L0
74: 0 0 PARISC-CPU IO-SAPIC03-L2
128: 22055 0 IO-SAPIC00 eth0
129: 0 30 IO-SAPIC00 sym53c8xx
130: 0 10281 IO-SAPIC00 sym53c8xx, sym53c8xx
131: 10807 0 IO-SAPIC00 sym53c8xx
132: 0 2709 IO-SAPIC00 serial
Able to rebuild (make -j2) kernels and apt-get update/upgrade.
Haven't done any other testing.
thanks,
grant
Index: arch/parisc/kernel/entry.S
===================================================================
RCS file: /var/cvs/linux/arch/parisc/kernel/entry.S,v
retrieving revision 1.93
diff -u -p -r1.93 entry.S
--- arch/parisc/kernel/entry.S 27 May 2002 22:15:53 -0000 1.93
+++ arch/parisc/kernel/entry.S 13 Sep 2002 06:44:18 -0000
@@ -498,7 +498,6 @@ fault_vector_11:
.import handle_real_interruption,code
.import do_cpu_irq_mask,code
.import parisc_stopkernel,code
- .import cpu_irq_region,data
/*
* r26 = function to be called
@@ -815,7 +814,7 @@ intr_do_signal:
*/
intr_extint:
- CMPIB=,n 0,%r16,1f
+ CMPIB=,n 0,%r16,1f /* on User or kernel stack? */
get_stack_use_cr30
b,n 3f
@@ -846,28 +845,16 @@ intr_extint:
loadgp
- copy %r29, %r25 /* arg1 is pt_regs */
+ copy %r29, %r26 /* arg0 is pt_regs */
copy %r29, %r16 /* save pt_regs */
-#ifdef CONFIG_KWDB
- copy %r29, %r3 /* KWDB - update frame pointer (gr3) */
-#endif
-
+ ldil L%intr_return, %r2
#ifdef __LP64__
ldo -16(%r30),%r29 /* Reference param save area */
-#else
- nop
#endif
-
- /*
- * We need to either load the CPU's ID or IRQ region.
- * Until we have "per CPU" IRQ regions, this is easy.
- */
- ldil L%cpu_irq_region, %r26
- ldil L%intr_return, %r2
- ldo R%cpu_irq_region(%r26), %r26
-
b do_cpu_irq_mask
ldo R%intr_return(%r2), %r2 /* return to intr_return, not here */
+
+
/* Generic interruptions (illegal insn, unaligned, page fault, etc) */
Index: arch/parisc/kernel/irq.c
===================================================================
RCS file: /var/cvs/linux/arch/parisc/kernel/irq.c,v
retrieving revision 1.57
diff -u -p -r1.57 irq.c
--- arch/parisc/kernel/irq.c 7 Jul 2002 06:23:38 -0000 1.57
+++ arch/parisc/kernel/irq.c 13 Sep 2002 06:44:18 -0000
@@ -104,24 +104,35 @@ static inline void unmask_cpu_irq(void *
set_eiem(cpu_eiem);
}
-static struct irqaction cpu_irq_actions[IRQ_PER_REGION] = {
+/*
+ * XXX cpu_irq_actions[] will become 2 dimensional for per CPU EIR support.
+ * correspond changes needed in:
+ * processor_probe() initialize additional action arrays
+ * request_irq() handle CPU IRQ region specially
+ * do_cpu_irq_mask() index into the matching irq_action array.
+ */
+struct irqaction cpu_irq_actions[IRQ_PER_REGION] = {
[IRQ_OFFSET(TIMER_IRQ)] { handler: timer_interrupt, name: "timer", },
#ifdef CONFIG_SMP
[IRQ_OFFSET(IPI_IRQ)] { handler: ipi_interrupt, name: "IPI", },
#endif
};
-struct irq_region cpu_irq_region = {
+struct irq_region_ops cpu_irq_ops = {
+ disable_cpu_irq, enable_cpu_irq, unmask_cpu_irq, unmask_cpu_irq
+};
+
+struct irq_region cpu0_irq_region = {
ops: { disable_cpu_irq, enable_cpu_irq, unmask_cpu_irq, unmask_cpu_irq },
data: { dev: &cpu_data[0],
- name: "PA-CPU-00",
+ name: "PARISC-CPU",
irqbase: IRQ_FROM_REGION(CPU_IRQ_REGION), },
action: cpu_irq_actions,
};
struct irq_region *irq_region[NR_IRQ_REGS] = {
[ 0 ] NULL, /* reserved for EISA, else causes data page fault (aka code 15) */
- [ CPU_IRQ_REGION ] &cpu_irq_region,
+ [ CPU_IRQ_REGION ] &cpu0_irq_region,
};
@@ -190,13 +201,14 @@ int get_irq_list(char *buf)
{
#ifdef CONFIG_PROC_FS
char *p = buf;
- unsigned int regnr = 0;
+ unsigned int regnr;
p += sprintf(p, " ");
#ifdef CONFIG_SMP
- for (; regnr < smp_num_cpus; regnr++)
+ for (regnr = 0; regnr < smp_num_cpus; regnr++)
#endif
- p += sprintf(p, " CPU%d ", regnr);
+ p += sprintf(p, " CPU%02d ", regnr);
+
#ifdef PARISC_IRQ_CR16_COUNTS
p += sprintf(p, "[min/avg/max] (CPU cycle counts)");
@@ -210,6 +222,9 @@ int get_irq_list(char *buf)
for (regnr = 0; regnr < NR_IRQ_REGS; regnr++) {
unsigned int i;
struct irq_region *region = irq_region[regnr];
+#ifdef CONFIG_SMP
+ unsigned int j;
+#endif
if (!region || !region->action)
continue;
@@ -217,9 +232,6 @@ int get_irq_list(char *buf)
for (i = 0; i <= MAX_CPU_IRQ; i++) {
struct irqaction *action = ®ion->action[i];
unsigned int irq_no = IRQ_FROM_REGION(regnr) + i;
-#ifdef CONFIG_SMP
- unsigned int j;
-#endif
if (!action->handler)
continue;
@@ -229,11 +241,12 @@ int get_irq_list(char *buf)
p += sprintf(p, "%10u ", kstat_irqs(irq_no));
#else
for (j = 0; j < smp_num_cpus; j++)
- p += sprintf(p, "%10u ",
- kstat.irqs[cpu_logical_map(j)][irq_no]);
+ p += sprintf(p, "%10u ",
+ kstat.irqs[j][regnr][i]);
#endif
p += sprintf(p, " %14s",
region->data.name ? region->data.name : "N/A");
+
#ifndef PARISC_IRQ_CR16_COUNTS
p += sprintf(p, " %s", action->name);
@@ -295,7 +308,7 @@ txn_alloc_irq(void)
/* never return irq 0 cause that's the interval timer */
for (irq = 1; irq <= MAX_CPU_IRQ; irq++) {
- if (cpu_irq_region.action[irq].handler == NULL) {
+ if (cpu_irq_actions[irq].handler == NULL) {
return (IRQ_FROM_REGION(CPU_IRQ_REGION) + irq);
}
}
@@ -317,14 +330,18 @@ txn_claim_irq(int irq)
unsigned long
txn_alloc_addr(int virt_irq)
{
- struct cpuinfo_parisc *dev = (struct cpuinfo_parisc *) (irq_region[IRQ_REGION(virt_irq)]->data.dev);
+ static int next_cpu = -1;
- if (!dev) {
- printk(KERN_ERR "txn_alloc_addr(0x%x): CPU IRQ region? dev %p\n",
- virt_irq,dev);
- return 0;
- }
- return (dev->txn_addr);
+ next_cpu++; /* assign to "next" CPU we want this bugger on */
+
+ /* validate entry */
+ while ((next_cpu < NR_CPUS) && !cpu_data[next_cpu].txn_addr)
+ next_cpu++;
+
+ if (next_cpu >= NR_CPUS)
+ next_cpu = 0; /* nothing else, assign monarch */
+
+ return cpu_data[next_cpu].txn_addr;
}
@@ -368,7 +385,7 @@ void do_irq(struct irqaction *action, in
int cpu = smp_processor_id();
irq_enter(cpu, irq);
- ++kstat.irqs[IRQ_REGION(irq)][IRQ_OFFSET(irq)];
+ ++kstat.irqs[cpu][IRQ_REGION(irq)][IRQ_OFFSET(irq)];
DBG_IRQ(irq, ("do_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq)));
@@ -410,7 +427,7 @@ void do_irq(struct irqaction *action, in
/* ONLY called from entry.S:intr_extint() */
-void do_cpu_irq_mask(struct irq_region *region, struct pt_regs *regs)
+void do_cpu_irq_mask(struct pt_regs *regs)
{
unsigned long eirr_val;
unsigned int i=3; /* limit time in interrupt context */
@@ -434,7 +451,7 @@ void do_cpu_irq_mask(struct irq_region *
*/
while ((eirr_val = (mfctl(23) & cpu_eiem)) && --i) {
unsigned long bit = (1UL<<MAX_CPU_IRQ);
- unsigned int irq = 0;
+ unsigned int irq;
mtctl(eirr_val, 23); /* reset bits we are going to process */
@@ -443,17 +460,15 @@ void do_cpu_irq_mask(struct irq_region *
printk(KERN_DEBUG "do_cpu_irq_mask %x\n", eirr_val);
#endif
- for (; eirr_val && bit; bit>>=1, irq++)
+ for (irq = 0; eirr_val && bit; bit>>=1, irq++)
{
- unsigned int irq_num;
if (!(bit&eirr_val))
continue;
/* clear bit in mask - can exit loop sooner */
eirr_val &= ~bit;
- irq_num = region->data.irqbase + irq;
- do_irq(®ion->action[irq], irq_num, regs);
+ do_irq(&cpu_irq_actions[irq], TIMER_IRQ+irq, regs);
}
}
set_eiem(cpu_eiem);
Index: arch/parisc/kernel/processor.c
===================================================================
RCS file: /var/cvs/linux/arch/parisc/kernel/processor.c,v
retrieving revision 1.13
diff -u -p -r1.13 processor.c
--- arch/parisc/kernel/processor.c 4 Jul 2002 19:33:01 -0000 1.13
+++ arch/parisc/kernel/processor.c 13 Sep 2002 06:44:18 -0000
@@ -77,6 +77,8 @@ static int __init processor_probe(struct
unsigned long txn_addr;
unsigned long cpuid;
struct cpuinfo_parisc *p;
+ extern struct irq_region_ops cpu_irq_ops; /* arch/parisc...irq.c */
+ extern struct irqaction cpu_irq_actions[]; /* arch/parisc...irq.c */
#ifndef CONFIG_SMP
if (boot_cpu_data.cpu_count > 0) {
@@ -167,12 +169,24 @@ static int __init processor_probe(struct
** p->state = STATE_RENDEZVOUS;
*/
- /*
- ** itimer and ipi IRQ handlers are statically initialized in
- ** arch/parisc/kernel/irq.c. ie Don't need to register them.
- */
- p->region = irq_region[IRQ_FROM_REGION(CPU_IRQ_REGION)];
+#if 0
+ /* CPU 0 IRQ table is statically allocated/initialized */
+ if (cpuid) {
+ struct irqaction actions[];
+
+ /*
+ ** itimer and ipi IRQ handlers are statically initialized in
+ ** arch/parisc/kernel/irq.c. ie Don't need to register them.
+ */
+ actions = kmalloc(sizeof(struct irqaction)*MAX_CPU_IRQ, GFP_ATOMIC);
+ if (!actions) {
+ /* not getting it's own table, share with monarch */
+ actions = cpu_irq_actions[0];
+ }
+ cpu_irq_actions[cpuid] = actions;
+ }
+#endif
return 0;
}
Index: include/asm-parisc/processor.h
===================================================================
RCS file: /var/cvs/linux/include/asm-parisc/processor.h,v
retrieving revision 1.53
diff -u -p -r1.53 processor.h
--- include/asm-parisc/processor.h 5 Apr 2002 08:02:02 -0000 1.53
+++ include/asm-parisc/processor.h 13 Sep 2002 06:44:18 -0000
@@ -9,6 +9,7 @@
#define __ASM_PARISC_PROCESSOR_H
#ifndef __ASSEMBLY__
+#include <linux/config.h>
#include <linux/threads.h>
#include <asm/hardware.h>
@@ -17,6 +18,9 @@
#include <asm/ptrace.h>
#include <asm/types.h>
#include <asm/system.h>
+#ifdef CONFIG_SMP
+#include <asm/spinlock_t.h>
+#endif
#endif /* __ASSEMBLY__ */
/*
@@ -71,7 +75,6 @@ struct system_cpuinfo_parisc {
*/
struct cpuinfo_parisc {
- struct irq_region *region;
unsigned long it_value; /* Interval Timer value at last timer Intr */
unsigned long it_delta; /* Interval Timer delta (tic_10ms / HZ * 100) */
unsigned long irq_count; /* number of IRQ's since boot */
Index: include/linux/kernel_stat.h
===================================================================
RCS file: /var/cvs/linux/include/linux/kernel_stat.h,v
retrieving revision 1.6
diff -u -p -r1.6 kernel_stat.h
--- include/linux/kernel_stat.h 4 Aug 2002 23:00:04 -0000 1.6
+++ include/linux/kernel_stat.h 13 Sep 2002 06:44:18 -0000
@@ -27,7 +27,7 @@ struct kernel_stat {
unsigned int pgpgin, pgpgout;
unsigned int pswpin, pswpout;
#if defined (__hppa__)
- unsigned int irqs[NR_IRQ_REGS][IRQ_PER_REGION];
+ unsigned int irqs[NR_CPUS][NR_IRQ_REGS][IRQ_PER_REGION];
#elif !defined(CONFIG_ARCH_S390)
unsigned int irqs[NR_CPUS][NR_IRQS];
#endif
@@ -42,7 +42,12 @@ extern struct kernel_stat kstat;
*/
static inline int kstat_irqs (int irq)
{
- return kstat.irqs[IRQ_REGION(irq)][IRQ_OFFSET(irq)];
+ int i, sum=0;
+
+ for (i = 0 ; i < smp_num_cpus ; i++)
+ sum += kstat.irqs[i][IRQ_REGION(irq)][IRQ_OFFSET(irq)];
+
+ return sum;
}
#elif !defined(CONFIG_ARCH_S390)
/*