patch-2.1.36 linux/arch/sparc/kernel/irq.c

Next file: linux/arch/sparc/kernel/ptrace.c
Previous file: linux/arch/sparc/kernel/head.S
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.35/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c
@@ -1,4 +1,4 @@
-/*  $Id: irq.c,v 1.66 1997/04/14 05:38:21 davem Exp $
+/*  $Id: irq.c,v 1.72 1997/04/20 11:41:26 ecd Exp $
  *  arch/sparc/kernel/irq.c:  Interrupt request handling routines. On the
  *                            Sparc the IRQ's are basically 'cast in stone'
  *                            and you are supposed to probe the prom's device
@@ -41,6 +41,10 @@
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
 
+#ifdef __SMP_PROF__
+extern volatile unsigned long smp_local_timer_ticks[1+NR_CPUS];
+#endif
+
 /*
  * Dave Redman (djhr@tadpole.co.uk)
  *
@@ -71,11 +75,11 @@
 void (*disable_irq)(unsigned int) = (void (*)(unsigned int)) irq_panic;
 void (*enable_pil_irq)(unsigned int) = (void (*)(unsigned int)) irq_panic;
 void (*disable_pil_irq)(unsigned int) = (void (*)(unsigned int)) irq_panic;
-void (*clear_clock_irq)( void ) = irq_panic;
-void (*clear_profile_irq)( void ) = irq_panic;
-void (*load_profile_irq)( unsigned int ) =  (void (*)(unsigned int)) irq_panic;
-void (*init_timers)( void (*)(int, void *,struct pt_regs *)) =
-    (void (*)( void (*)(int, void *,struct pt_regs *))) irq_panic;
+void (*clear_clock_irq)(void) = irq_panic;
+void (*clear_profile_irq)(int) = (void (*)(int)) irq_panic;
+void (*load_profile_irq)(int, unsigned int) =  (void (*)(int, unsigned int)) irq_panic;
+void (*init_timers)(void (*)(int, void *,struct pt_regs *)) =
+    (void (*)(void (*)(int, void *,struct pt_regs *))) irq_panic;
 
 #ifdef __SMP__
 void (*set_cpu_int)(int, int);
@@ -128,6 +132,109 @@
 	return len;
 }
 
+#ifdef __SMP_PROF__
+
+static unsigned int int_count[NR_CPUS][NR_IRQS] = {{0},};
+
+extern unsigned int prof_multiplier[NR_CPUS];
+extern unsigned int prof_counter[NR_CPUS];
+
+int get_smp_prof_list(char *buf) {
+	int i,j, len = 0;
+	struct irqaction * action;
+	unsigned long sum_spins = 0;
+	unsigned long sum_spins_syscall = 0;
+	unsigned long sum_spins_sys_idle = 0;
+	unsigned long sum_smp_idle_count = 0;
+	unsigned long sum_local_timer_ticks = 0;
+
+	for (i=0;i<smp_num_cpus;i++) {
+		int cpunum = cpu_logical_map[i];
+		sum_spins+=smp_spins[cpunum];
+		sum_spins_syscall+=smp_spins_syscall[cpunum];
+		sum_spins_sys_idle+=smp_spins_sys_idle[cpunum];
+		sum_smp_idle_count+=smp_idle_count[cpunum];
+		sum_local_timer_ticks+=smp_local_timer_ticks[cpunum];
+	}
+
+	len += sprintf(buf+len,"CPUS: %10i \n", smp_num_cpus);
+	len += sprintf(buf+len,"            SUM ");
+	for (i=0;i<smp_num_cpus;i++)
+		len += sprintf(buf+len,"        P%1d ",cpu_logical_map[i]);
+	len += sprintf(buf+len,"\n");
+	for (i = 0 ; i < NR_IRQS ; i++) {
+		action = *(i + irq_action);
+		if (!action || !action->handler)
+			continue;
+		len += sprintf(buf+len, "%3d: %10d ",
+			i, kstat.interrupts[i]);
+		for (j=0;j<smp_num_cpus;j++)
+			len+=sprintf(buf+len, "%10d ",
+				int_count[cpu_logical_map[j]][i]);
+		len += sprintf(buf+len, "%c %s",
+			(action->flags & SA_INTERRUPT) ? '+' : ' ',
+			action->name);
+		for (action=action->next; action; action = action->next) {
+			len += sprintf(buf+len, ",%s %s",
+				(action->flags & SA_INTERRUPT) ? " +" : "",
+				action->name);
+		}
+		len += sprintf(buf+len, "\n");
+	}
+	len+=sprintf(buf+len, "LCK: %10lu",
+		sum_spins);
+
+	for (i=0;i<smp_num_cpus;i++)
+		len+=sprintf(buf+len," %10lu",smp_spins[cpu_logical_map[i]]);
+
+	len +=sprintf(buf+len,"   spins from int\n");
+
+	len+=sprintf(buf+len, "LCK: %10lu",
+		sum_spins_syscall);
+
+	for (i=0;i<smp_num_cpus;i++)
+		len+=sprintf(buf+len," %10lu",smp_spins_syscall[cpu_logical_map[i]]);
+
+	len +=sprintf(buf+len,"   spins from syscall\n");
+
+	len+=sprintf(buf+len, "LCK: %10lu",
+		sum_spins_sys_idle);
+
+	for (i=0;i<smp_num_cpus;i++)
+		len+=sprintf(buf+len," %10lu",smp_spins_sys_idle[cpu_logical_map[i]]);
+
+	len +=sprintf(buf+len,"   spins from sysidle\n");
+	len+=sprintf(buf+len,"IDLE %10lu",sum_smp_idle_count);
+
+	for (i=0;i<smp_num_cpus;i++)
+		len+=sprintf(buf+len," %10lu",smp_idle_count[cpu_logical_map[i]]);
+
+	len +=sprintf(buf+len,"   idle ticks\n");
+
+	len+=sprintf(buf+len,"TICK %10lu",sum_local_timer_ticks);
+	for (i=0;i<smp_num_cpus;i++)
+		len+=sprintf(buf+len," %10lu",smp_local_timer_ticks[cpu_logical_map[i]]);
+
+	len +=sprintf(buf+len,"   local APIC timer ticks\n");
+
+	len+=sprintf(buf+len,"MULT:          ");
+	for (i=0;i<smp_num_cpus;i++)
+		len+=sprintf(buf+len," %10u",prof_multiplier[cpu_logical_map[i]]);
+	len +=sprintf(buf+len,"   profiling multiplier\n");
+
+	len+=sprintf(buf+len,"COUNT:         ");
+	for (i=0;i<smp_num_cpus;i++)
+		len+=sprintf(buf+len," %10u",prof_counter[cpu_logical_map[i]]);
+
+	len +=sprintf(buf+len,"   profiling counter\n");
+
+	len+=sprintf(buf+len, "IPI: %10lu   received\n",
+		ipi_count);
+
+	return len;
+}
+#endif 
+
 void free_irq(unsigned int irq, void *dev_id)
 {
 	struct irqaction * action;
@@ -185,7 +292,11 @@
 
 /* Per-processor IRQ locking depth, both SMP and non-SMP code use this. */
 unsigned int local_irq_count[NR_CPUS];
-atomic_t __sparc_bh_counter;
+#ifdef __SMP__
+atomic_t __sparc_bh_counter = ATOMIC_INIT(0);
+#else
+int __sparc_bh_counter = 0;
+#endif
 
 #ifdef __SMP__
 /* SMP interrupt locking on Sparc. */
@@ -200,49 +311,10 @@
 spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED;
 
 /* Global IRQ locking depth. */
-atomic_t global_irq_count = ATOMIC_INIT;
-
-#define irq_active(cpu) \
-	(atomic_read(&global_irq_count) != local_irq_count[cpu])
-
-static unsigned long previous_irqholder;
-
-#define INIT_STUCK 10000000
-
-#define STUCK \
-if (!--stuck) { \
-	printk("wait_on_irq CPU#%d stuck at %08lx, waiting for [%08lx:%x] " \
-	       "(local=[%d(%x:%x:%x:%x)], global=[%d:%x]) ", \
-	       cpu, where, previous_irqholder, global_irq_holder, \
-	       local_count, local_irq_count[0], local_irq_count[1], \
-	       local_irq_count[2], local_irq_count[3], \
-	       atomic_read(&global_irq_count), global_irq_lock); \
-	printk("g[%d:%x]\n", atomic_read(&global_irq_count), global_irq_lock); \
-	stuck = INIT_STUCK; \
-}
-
-static inline void wait_on_irq(int cpu, unsigned long where)
-{
-	int stuck = INIT_STUCK;
-	int local_count = local_irq_count[cpu];
-
-	while(local_count != atomic_read(&global_irq_count)) {
-		atomic_sub(local_count, &global_irq_count);
-		spin_unlock(&global_irq_lock);
-		while(1) {
-			STUCK;
-			if(atomic_read(&global_irq_count))
-				continue;
-			if(global_irq_lock)
-				continue;
-			if(spin_trylock(&global_irq_lock))
-				break;
-		}
-		atomic_add(local_count, &global_irq_count);
-	}
-}
+atomic_t global_irq_count = ATOMIC_INIT(0);
 
 /* There has to be a better way. */
+/* XXX Must write faster version in irqlock.S -DaveM */
 void synchronize_irq(void)
 {
 	int cpu = smp_processor_id();
@@ -259,123 +331,6 @@
 	}
 }
 
-#undef INIT_STUCK
-#define INIT_STUCK 10000000
-
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;}
-
-static inline void get_irqlock(int cpu, unsigned long where)
-{
-	int stuck = INIT_STUCK;
-
-	if(!spin_trylock(&global_irq_lock)) {
-		if((unsigned char) cpu == global_irq_holder)
-			return;
-		do {
-			do {
-				STUCK;
-				barrier();
-			} while(global_irq_lock);
-		} while(!spin_trylock(&global_irq_lock));
-	}
-	wait_on_irq(cpu, where);
-	global_irq_holder = cpu;
-	previous_irqholder = where;
-}
-
-void __global_cli(void)
-{
-	int cpu = smp_processor_id();
-	unsigned long where;
-
-	__asm__ __volatile__("mov %%i7, %0\n\t" : "=r" (where));
-	__cli();
-	get_irqlock(cpu, where);
-}
-
-void __global_sti(void)
-{
-	release_irqlock(smp_processor_id());
-	__sti();
-}
-
-/* Yes, I know this is broken, but for the time being...
- *
- * On Sparc we must differentiate between real local processor
- * interrupts being disabled and global interrupt locking, this
- * is so that interrupt handlers which call this stuff don't get
- * interrupts turned back on when restore_flags() runs because
- * our current drivers will be very surprised about this, yes I
- * know they need to be fixed... -DaveM
- */
-unsigned long __global_save_flags(void)
-{
-	unsigned long flags, retval = 0;
-
-	__save_flags(flags);
-	if(global_irq_holder == (unsigned char) smp_processor_id())
-		retval |= 1;
-	if(flags & PSR_PIL)
-		retval |= 2;
-	return retval;
-}
-
-void __global_restore_flags(unsigned long flags)
-{
-	if(flags & 1) {
-		__global_cli();
-	} else {
-		release_irqlock(smp_processor_id());
-
-		if(flags & 2)
-			__cli();
-		else
-			__sti();
-	}
-}
-
-#undef INIT_STUCK
-#define INIT_STUCK 200000000
-
-#undef STUCK
-#define STUCK \
-if (!--stuck) { \
-	printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n", \
-	       irq, cpu, global_irq_holder); \
-	stuck = INIT_STUCK; \
-}
-
-static void irq_enter(int cpu, int irq)
-{
-	extern void smp_irq_rotate(int cpu);
-	int stuck = INIT_STUCK;
-
-	smp_irq_rotate(cpu);
-	hardirq_enter(cpu);
-	while(global_irq_lock) {
-		if((unsigned char) cpu == global_irq_holder) {
-			printk("YEEEE Local interrupts enabled, global disabled\n");
-			break;
-		}
-		STUCK;
-		barrier();
-	}
-}
-
-static void irq_exit(int cpu, int irq)
-{
-	__cli();
-	hardirq_exit(cpu);
-	release_irqlock(cpu);
-}
-
-#else /* !__SMP__ */
-
-#define irq_enter(cpu, irq)	(local_irq_count[cpu]++)
-#define irq_exit(cpu, irq)	(local_irq_count[cpu]--)
-
 #endif /* __SMP__ */
 
 void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
@@ -406,9 +361,17 @@
 	struct irqaction * action;
 	unsigned int cpu_irq = irq & NR_IRQS;
 	int cpu = smp_processor_id();
+#ifdef __SMP__
+	extern void smp_irq_rotate(int cpu);
+#endif
 	
 	disable_pil_irq(cpu_irq);
-	irq_enter(cpu, irq);
+#ifdef __SMP__
+	/* Only rotate on lower priority IRQ's (scsi, ethernet, etc.). */
+	if(irq < 10)
+		smp_irq_rotate(cpu);
+#endif
+	irq_enter(cpu, cpu_irq);
 	action = *(cpu_irq + irq_action);
 	kstat.interrupts[cpu_irq]++;
 	do {
@@ -417,7 +380,7 @@
 		action->handler(irq, action->dev_id, regs);
 		action = action->next;
 	} while (action);
-	irq_exit(cpu, irq);
+	irq_exit(cpu, cpu_irq);
 	enable_pil_irq(cpu_irq);
 }
 
@@ -432,7 +395,7 @@
 	irq_enter(cpu, irq);
 	floppy_interrupt(irq, dev_id, regs);
 	irq_exit(cpu, irq);
-	disable_pil_irq(irq);
+	enable_pil_irq(irq);
 }
 #endif
 
@@ -596,12 +559,12 @@
  */
 unsigned long probe_irq_on(void)
 {
-  return 0;
+	return 0;
 }
 
 int probe_irq_off(unsigned long mask)
 {
-  return 0;
+	return 0;
 }
 
 /* djhr

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov