[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 = &region->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(&region->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)
 /*