patch-2.2.10 linux/arch/alpha/kernel/smp.c

Next file: linux/arch/alpha/kernel/sys_dp264.c
Previous file: linux/arch/alpha/kernel/signal.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.9/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c
@@ -18,6 +18,7 @@
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
 
+#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/bitops.h>
 #include <asm/pgtable.h>
@@ -29,6 +30,8 @@
 #include <asm/unistd.h>
 
 #include "proto.h"
+#include "irq.h"
+
 
 #define DEBUG_SMP 0
 #if DEBUG_SMP
@@ -37,62 +40,44 @@
 #define DBGS(args)
 #endif
 
-struct ipi_msg_flush_tb_struct {
-	volatile unsigned int flush_tb_mask;
-	union {
-		struct mm_struct *	flush_mm;
-		struct vm_area_struct *	flush_vma;
-	} p;
-	unsigned long flush_addr;
-	unsigned long flush_end;
-};
-
-static struct ipi_msg_flush_tb_struct ipi_msg_flush_tb __cacheline_aligned;
-static spinlock_t flush_tb_lock = SPIN_LOCK_UNLOCKED;
-
+/* A collection of per-processor data.  */
 struct cpuinfo_alpha cpu_data[NR_CPUS];
 
-spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
-spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+/* A collection of single bit ipi messages.  */
+static struct {
+	unsigned long bits __cacheline_aligned;
+} ipi_data[NR_CPUS];
 
-unsigned int boot_cpu_id = 0;
-static int smp_activated = 0;
-
-int smp_found_config = 0; /* Have we found an SMP box */
-static int max_cpus = -1;
+enum ipi_message_type {
+        IPI_RESCHEDULE,
+        IPI_CALL_FUNC,
+        IPI_CPU_STOP,
+};
 
-unsigned int cpu_present_map = 0;
+spinlock_t kernel_flag __cacheline_aligned = SPIN_LOCK_UNLOCKED;
 
-int smp_num_cpus = 1;
-int smp_num_probed = 0; /* Internal processor count */
+/* Set to a secondary's cpuid when it comes online.  */
+static unsigned long smp_secondary_alive;
 
-int smp_threads_ready = 0;
-volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
-volatile unsigned long smp_spinning[NR_CPUS] = { 0, };
+unsigned long cpu_present_mask;	/* Which cpus ids came online.  */
 
+static int max_cpus = -1;	/* Command-line limitation.  */
+int smp_boot_cpuid;		/* Which processor we booted from.  */
+int smp_num_probed;		/* Internal processor count */
+int smp_num_cpus = 1;		/* Number that came online.  */
+int smp_threads_ready;		/* True once the per process idle is forked. */
 cycles_t cacheflush_time;
 
-unsigned int prof_multiplier[NR_CPUS];
-unsigned int prof_counter[NR_CPUS];
-
-volatile int ipi_bits[NR_CPUS] __cacheline_aligned;
-
-unsigned long boot_cpu_palrev;
-
-volatile int smp_commenced = 0;
-volatile int smp_processors_ready = 0;
-
-volatile int cpu_number_map[NR_CPUS];
-volatile int cpu_logical_map[NR_CPUS];
+int cpu_number_map[NR_CPUS];
+int __cpu_logical_map[NR_CPUS];
 
 extern void calibrate_delay(void);
-extern struct thread_struct * original_pcb_ptr;
-
-static void smp_setup_percpu_timer(void);
-static void secondary_cpu_start(int, struct task_struct *);
-static void send_cpu_msg(char *, int);
+extern asmlinkage void entInt(void);
 
-/* Process bootcommand SMP options, like "nosmp" and "maxcpus=" */
+
+/*
+ * Process bootcommand SMP options, like "nosmp" and "maxcpus=".
+ */
 void __init
 smp_setup(char *str, int *ints)
 {
@@ -102,100 +87,87 @@
 		max_cpus = 0;
 }
 
-static void __init
-smp_store_cpu_info(int id)
+/*
+ * Called by both boot and secondaries to move global data into
+ *  per-processor storage.
+ */
+static inline void __init
+smp_store_cpu_info(int cpuid)
 {
-	/* This is it on Alpha, so far. */
-	cpu_data[id].loops_per_sec = loops_per_sec;
+	cpu_data[cpuid].loops_per_sec = loops_per_sec;
 }
 
-void __init
-smp_commence(void)
+/*
+ * Ideally sets up per-cpu profiling hooks.  Doesn't do much now...
+ */
+static inline void __init
+smp_setup_percpu_timer(int cpuid)
 {
-	/* Lets the callin's below out of their loop. */
-	mb();
-	smp_commenced = 1;
+	cpu_data[cpuid].prof_counter = 1;
+	cpu_data[cpuid].prof_multiplier = 1;
+
+#ifdef NOT_YET_PROFILING
+	load_profile_irq(mid_xlate[cpu], lvl14_resolution);
+	if (cpu == smp_boot_cpuid)
+		enable_pil_irq(14);
+#endif
 }
 
+/*
+ * Where secondaries begin a life of C.
+ */
 void __init
 smp_callin(void)
 {
 	int cpuid = hard_smp_processor_id();
 
 	DBGS(("CALLIN %d state 0x%lx\n", cpuid, current->state));
-#ifdef HUH
-	local_flush_cache_all();
-	local_flush_tlb_all();
-#endif
-#if 0
-	set_irq_udt(mid_xlate[boot_cpu_id]);
-#endif
+
+	/* Turn on machine checks.  */
+	wrmces(7);
+
+	/* Set trap vectors.  */
+	trap_init();
+
+	/* Set interrupt vector.  */
+	wrent(entInt, 0);
+
+	/* Setup the scheduler for this processor.  */
+	init_idle();
 
 	/* Get our local ticker going. */
-	smp_setup_percpu_timer();
+	smp_setup_percpu_timer(cpuid);
 
-#if 0
+	/* Must have completely accurate bogos.  */
+	__sti();
 	calibrate_delay();
-#endif
 	smp_store_cpu_info(cpuid);
-#ifdef HUH
-	local_flush_cache_all();
-	local_flush_tlb_all();
-#endif
 
 	/* Allow master to continue. */
-	set_bit(cpuid, (unsigned long *)&cpu_callin_map[cpuid]);
-#ifdef HUH
-	local_flush_cache_all();
-	local_flush_tlb_all();
-#endif
-
-#ifdef NOT_YET
-	while(!task[cpuid] || current_set[cpuid] != task[cpuid])
-	        barrier();
-#endif
-
-#ifdef HUH
-	local_flush_cache_all();
-	local_flush_tlb_all();
-#endif
-#if 0
-	__sti();
-#endif
-}
+	wmb();
+	smp_secondary_alive = cpuid;
 
-asmlinkage int __init
-start_secondary(void *unused)
-{
-	extern asmlinkage void entInt(void);
-	extern void paging_init_secondary(void);
+	/* Wait for the go code.  */
+	while (!smp_threads_ready)
+		barrier();
 
-	wrmces(7);
-	paging_init_secondary();
-	trap_init();
-	wrent(entInt, 0);
+	DBGS(("smp_callin: commencing CPU %d current %p\n",
+	      cpuid, current));
 
-	smp_callin();
-	while (!smp_commenced)
-		barrier();
-#if 1
-	printk("start_secondary: commencing CPU %d current %p\n",
-	       hard_smp_processor_id(), current);
-#endif
+	/* Do nothing.  */
 	cpu_idle(NULL);
 }
 
+
+/*
+ * Rough estimation for SMP scheduling, this is the number of cycles it
+ * takes for a fully memory-limited process to flush the SMP-local cache.
+ *
+ * We are not told how much cache there is, so we have to guess.
+ */
 static void __init
 smp_tune_scheduling (void)
 {
-	/*
-	 * Rough estimation for SMP scheduling, this is the number of
-	 * cycles it takes for a fully memory-limited process to flush
-	 * the SMP-local cache.
-	 *
-	 * We are not told how much cache there is, so we have to guess.
-	 */
-
 	struct percpu_struct *cpu;
 	unsigned long on_chip_cache;
 	unsigned long freq;
@@ -231,298 +203,18 @@
 	cacheflush_time = freq / 1024 * on_chip_cache / 5000;
 }
 
-
 /*
- *      Cycle through the processors sending START msgs to boot each.
+ * Send a message to a secondary's console.  "START" is one such
+ * interesting message.  ;-)
  */
-void __init
-smp_boot_cpus(void)
-{
-	int cpucount = 0;
-	int i, first, prev;
-
-	printk("Entering SMP Mode.\n");
-
-#if 0
-	__sti();
-#endif
-
-	for(i=0; i < NR_CPUS; i++) {
-		cpu_number_map[i] = -1;
-		cpu_logical_map[i] = -1;
-	        prof_counter[i] = 1;
-	        prof_multiplier[i] = 1;
-		ipi_bits[i] = 0;
-	}
-
-	cpu_number_map[boot_cpu_id] = 0;
-	cpu_logical_map[0] = boot_cpu_id;
-	current->processor = boot_cpu_id; /* ??? */
-
-	smp_store_cpu_info(boot_cpu_id);
-	smp_tune_scheduling();
-#ifdef NOT_YET
-	printk("CPU%d: ", boot_cpu_id);
-	print_cpu_info(&cpu_data[boot_cpu_id]);
-	set_irq_udt(mid_xlate[boot_cpu_id]);
-#endif
-	smp_setup_percpu_timer();
-#ifdef HUH
-	local_flush_cache_all();
-#endif
-	if (smp_num_probed == 1)
-		return;  /* Not an MP box. */
-
-#if NOT_YET
-	/*
-	 * If SMP should be disabled, then really disable it!
-	 */
-	if (!max_cpus)
-	{
-		smp_found_config = 0;
-	        printk(KERN_INFO "SMP mode deactivated.\n");
-	}
-#endif
-
-	for (i = 0; i < NR_CPUS; i++) {
-
-		if (i == boot_cpu_id)
-			continue;
-
-	        if (cpu_present_map & (1 << i)) {
-	                struct task_struct *idle;
-	                int timeout;
-
-	                /* Cook up an idler for this guy. */
-	                kernel_thread(start_secondary, NULL, CLONE_PID);
-	                idle = task[++cpucount];
-			if (!idle)
-				panic("No idle process for CPU %d", i);
-	                idle->processor = i;
-
-			DBGS(("smp_boot_cpus: CPU %d state 0x%lx flags 0x%lx\n",
-			      i, idle->state, idle->flags));
-
-	                /* whirrr, whirrr, whirrrrrrrrr... */
-#ifdef HUH
-	                local_flush_cache_all();
-#endif
-	                secondary_cpu_start(i, idle);
-
-	                /* wheee... it's going... wait for 5 secs...*/
-	                for (timeout = 0; timeout < 50000; timeout++) {
-				if (cpu_callin_map[i])
-					break;
-	                        udelay(100);
-	                }
-	                if (cpu_callin_map[i]) {
-				/* Another "Red Snapper". */
-				cpu_number_map[i] = cpucount;
-	                        cpu_logical_map[cpucount] = i;
-	                } else {
-				cpucount--;
-	                        printk("smp_boot_cpus: Processor %d"
-				       " is stuck 0x%lx.\n", i, idle->flags);
-	                }
-	        }
-	        if (!(cpu_callin_map[i])) {
-			cpu_present_map &= ~(1 << i);
-	                cpu_number_map[i] = -1;
-	        }
-	}
-#ifdef HUH
-	local_flush_cache_all();
-#endif
-	if (cpucount == 0) {
-		printk("smp_boot_cpus: ERROR - only one Processor found.\n");
-	        cpu_present_map = (1 << smp_processor_id());
-	} else {
-		unsigned long bogosum = 0;
-	        for (i = 0; i < NR_CPUS; i++) {
-			if (cpu_present_map & (1 << i))
-				bogosum += cpu_data[i].loops_per_sec;
-	        }
-	        printk("smp_boot_cpus: Total of %d Processors activated"
-		       " (%lu.%02lu BogoMIPS).\n",
-	               cpucount + 1,
-	               (bogosum + 2500)/500000,
-	               ((bogosum + 2500)/5000)%100);
-	        smp_activated = 1;
-	        smp_num_cpus = cpucount + 1;
-	}
-
-	/* Setup CPU list for IRQ distribution scheme. */
-	first = prev = -1;
-	for (i = 0; i < NR_CPUS; i++) {
-		if (cpu_present_map & (1 << i)) {
-			if (first == -1)
-				first = i;
-			if (prev != -1)
-				cpu_data[i].next = i;
-	                prev = i;
-	        }
-	}
-	cpu_data[prev].next = first;
-
-	/* Ok, they are spinning and ready to go. */
-	smp_processors_ready = 1;
-}
-
-static void __init
-smp_setup_percpu_timer(void)
-{
-	int cpu = smp_processor_id();
-
-	prof_counter[cpu] = prof_multiplier[cpu] = 1;
-#ifdef NOT_YET
-	load_profile_irq(mid_xlate[cpu], lvl14_resolution);
-	if (cpu == boot_cpu_id)
-		enable_pil_irq(14);
-#endif
-}
-
-extern void update_one_process(struct task_struct *p, unsigned long ticks,
-	                       unsigned long user, unsigned long system,
-			       int cpu);
-
-void
-smp_percpu_timer_interrupt(struct pt_regs *regs)
-{
-	int cpu = smp_processor_id();
-
-#ifdef NOT_YET
-	clear_profile_irq(mid_xlate[cpu]);
-	if(!user_mode(regs))
-		alpha_do_profile(regs->pc);
-#endif
-
-	if (!--prof_counter[cpu]) {
-		int user = user_mode(regs);
-	        if (current->pid) {
-			update_one_process(current, 1, user, !user, cpu);
-
-	                if (--current->counter < 0) {
-				current->counter = 0;
-	                        current->need_resched = 1;
-	                }
-
-	                spin_lock(&ticker_lock);
-	                if (user) {
-				if (current->priority < DEF_PRIORITY) {
-					kstat.cpu_nice++;
-					kstat.per_cpu_nice[cpu]++;
-				} else {
-					kstat.cpu_user++;
-					kstat.per_cpu_user[cpu]++;
-				}
-	                } else {
-				kstat.cpu_system++;
-				kstat.per_cpu_system[cpu]++;
-	                }
-	                spin_unlock(&ticker_lock);
-	        }
-	        prof_counter[cpu] = prof_multiplier[cpu];
-	}
-}
-
-int __init
-setup_profiling_timer(unsigned int multiplier)
-{
-#ifdef NOT_YET
-	int i;
-	unsigned long flags;
-
-	/* Prevent level14 ticker IRQ flooding. */
-	if((!multiplier) || (lvl14_resolution / multiplier) < 500)
-	        return -EINVAL;
-
-	save_and_cli(flags);
-	for(i = 0; i < NR_CPUS; i++) {
-	        if(cpu_present_map & (1 << i)) {
-	                load_profile_irq(mid_xlate[i], lvl14_resolution / multip
-lier);
-	                prof_multiplier[i] = multiplier;
-	        }
-	}
-	restore_flags(flags);
-
-	return 0;
-
-#endif
-  return -EINVAL;
-}
-
-/* Only broken Intel needs this, thus it should not even be
-   referenced globally.  */
-
-void __init
-initialize_secondary(void)
-{
-}
-
-static void __init
-secondary_cpu_start(int cpuid, struct task_struct *idle)
-{
-	struct percpu_struct *cpu;
-	int timeout;
-	  
-	cpu = (struct percpu_struct *)
-		((char*)hwrpb
-		 + hwrpb->processor_offset
-		 + cpuid * hwrpb->processor_size);
-
-	/* Set context to idle thread this CPU will use when running
-	   assumption is that the idle thread is all set to go... ??? */
-	memcpy(&cpu->hwpcb[0], &idle->tss, sizeof(struct pcb_struct));
-	cpu->hwpcb[4] = cpu->hwpcb[0]; /* UNIQUE set to KSP ??? */
-
-	DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx\n",
-	      cpu->hwpcb[0], cpu->hwpcb[2], hwrpb->vptb));
-	DBGS(("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n",
-	      cpuid, idle->state, idle->tss.pal_flags));
-
-	/* Setup HWRPB fields that SRM uses to activate secondary CPU */
-	hwrpb->CPU_restart = __start_cpu;
-	hwrpb->CPU_restart_data = (unsigned long) idle;
-
-	/* Recalculate and update the HWRPB checksum */
-	hwrpb_update_checksum(hwrpb);
-
-	/*
-	 * Send a "start" command to the specified processor.
-	 */
-
-	/* SRM III 3.4.1.3 */
-	cpu->flags |= 0x22;	/* turn on Context Valid and Restart Capable */
-	cpu->flags &= ~1;	/* turn off Bootstrap In Progress */
-	mb();
-
-	send_cpu_msg("START\r\n", cpuid);
-
-	/* now, we wait... */
-	for (timeout = 10000; !(cpu->flags & 1); timeout--) {
-		if (timeout <= 0) {
-			printk("Processor %d failed to start\n", cpuid);
-	                        /* needed for pset_info to work */
-#if 0
-			ipc_processor_enable(cpu_to_processor(cpunum));
-#endif
-			return;
-		}
-		mdelay(1);
-		barrier();
-	}
-	DBGS(("secondary_cpu_start: SUCCESS for CPU %d!!!\n", cpuid));
-}
-
 static void
-send_cpu_msg(char *str, int cpuid)
+send_secondary_console_msg(char *str, int cpuid)
 {
 	struct percpu_struct *cpu;
 	register char *cp1, *cp2;
 	unsigned long cpumask;
 	size_t len;
-	int timeout;
+	long timeout;
 
 	cpu = (struct percpu_struct *)
 		((char*)hwrpb
@@ -541,6 +233,7 @@
 	memcpy(cp1, cp2, len);
 
 	/* atomic test and set */
+	wmb();
 	set_bit(cpuid, &hwrpb->rxrdy);
 
 	if (hwrpb->txrdy & cpumask)
@@ -549,19 +242,21 @@
 	return;
 
 delay1:
-	for (timeout = 10000; timeout > 0; --timeout) {
+	/* Wait one second.  Note that jiffies aren't ticking yet.  */
+	for (timeout = 100000; timeout > 0; --timeout) {
 		if (!(hwrpb->txrdy & cpumask))
 			goto ready1;
-		udelay(100);
+		udelay(10);
 		barrier();
 	}
 	goto timeout;
 
 delay2:
-	for (timeout = 10000; timeout > 0; --timeout) {
+	/* Wait one second.  */
+	for (timeout = 100000; timeout > 0; --timeout) {
 		if (!(hwrpb->txrdy & cpumask))
 			goto ready2;
-		udelay(100);
+		udelay(10);
 		barrier();
 	}
 	goto timeout;
@@ -572,64 +267,17 @@
 }
 
 /*
- * setup_smp()
- *
- * called from arch/alpha/kernel/setup.c:setup_arch() when __SMP__ defined
+ * A secondary console wants to send a message.  Receive it.
  */
-void __init
-setup_smp(void)
-{
-	struct percpu_struct *cpubase, *cpu;
-	int i;
-	  
-	boot_cpu_id = hard_smp_processor_id();
-	if (boot_cpu_id != 0) {
-		printk("setup_smp: boot_cpu_id != 0 (%d).\n", boot_cpu_id);
-	}
-
-	if (hwrpb->nr_processors > 1) {
-
-		DBGS(("setup_smp: nr_processors %ld\n",
-		      hwrpb->nr_processors));
-
-		cpubase = (struct percpu_struct *)
-			((char*)hwrpb + hwrpb->processor_offset);
-		boot_cpu_palrev = cpubase->pal_revision;
-
-		for (i = 0; i < hwrpb->nr_processors; i++ ) {
-			cpu = (struct percpu_struct *)
-				((char *)cpubase + i*hwrpb->processor_size);
-			if ((cpu->flags & 0x1cc) == 0x1cc) {
-				smp_num_probed++;
-				/* assume here that "whami" == index */
-				cpu_present_map |= (1 << i);
-				if (i != boot_cpu_id)
-				  cpu->pal_revision = boot_cpu_palrev;
-			}
-
-			DBGS(("setup_smp: CPU %d: flags 0x%lx type 0x%lx\n",
-			      i, cpu->flags, cpu->type));
-			DBGS(("setup_smp: CPU %d: PAL rev 0x%lx\n",
-			      i, cpu->pal_revision));
-		}
-	} else {
-		smp_num_probed = 1;
-		cpu_present_map = (1 << boot_cpu_id);
-	}
-	printk("setup_smp: %d CPUs probed, cpu_present_map 0x%x,"
-	       " boot_cpu_id %d\n",
-	       smp_num_probed, cpu_present_map, boot_cpu_id);
-}
-
 static void
-secondary_console_message(void)
+recv_secondary_console_msg(void)
 {
 	int mycpu, i, cnt;
 	unsigned long txrdy = hwrpb->txrdy;
 	char *cp1, *cp2, buf[80];
 	struct percpu_struct *cpu;
 
-	DBGS(("secondary_console_message: TXRDY 0x%lx.\n", txrdy));
+	DBGS(("recv_secondary_console_msg: TXRDY 0x%lx.\n", txrdy));
 
 	mycpu = hard_smp_processor_id();
 
@@ -637,7 +285,7 @@
 		if (!(txrdy & (1L << i)))
 			continue;
 
-		DBGS(("secondary_console_message: "
+		DBGS(("recv_secondary_console_msg: "
 		      "TXRDY contains CPU %d.\n", i));
 
 		cpu = (struct percpu_struct *)
@@ -645,9 +293,9 @@
 		   + hwrpb->processor_offset
 		   + i * hwrpb->processor_size);
 
- 		printk("secondary_console_message: on %d from %d"
-		       " HALT_REASON 0x%lx FLAGS 0x%lx\n",
-		       mycpu, i, cpu->halt_reason, cpu->flags);
+ 		DBGS(("recv_secondary_console_msg: on %d from %d"
+		      " HALT_REASON 0x%lx FLAGS 0x%lx\n",
+		      mycpu, i, cpu->halt_reason, cpu->flags));
 
 		cnt = cpu->ipc_buffer[0] >> 32;
 		if (cnt <= 0 || cnt >= 80)
@@ -664,85 +312,347 @@
 			}
 		}
 
-		printk("secondary_console_message: on %d message is '%s'\n",
-		       mycpu, buf);
+		printk(KERN_INFO "recv_secondary_console_msg: on %d "
+		       "message is '%s'\n", mycpu, buf);
 	}
 
 	hwrpb->txrdy = 0;
 }
 
-enum ipi_message_type {
-	IPI_TLB_ALL,
-	IPI_TLB_MM,
-	IPI_TLB_PAGE,
-	IPI_RESCHEDULE,
-	IPI_CPU_STOP
-};
-
-void
-handle_ipi(struct pt_regs *regs)
+/*
+ * Convince the console to have a secondary cpu begin execution.
+ */
+static int __init
+secondary_cpu_start(int cpuid, struct task_struct *idle)
 {
-	int this_cpu = smp_processor_id();
-	volatile int * pending_ipis = &ipi_bits[this_cpu];
-	unsigned long ops;
+	struct percpu_struct *cpu;
+	struct pcb_struct *hwpcb;
+	long timeout;
+	  
+	cpu = (struct percpu_struct *)
+		((char*)hwrpb
+		 + hwrpb->processor_offset
+		 + cpuid * hwrpb->processor_size);
+	hwpcb = (struct pcb_struct *) cpu->hwpcb;
 
-	DBGS(("handle_ipi: on CPU %d ops 0x%x PC 0x%lx\n",
-	      this_cpu, *pending_ipis, regs->pc));
+	/* Initialize the CPU's HWPCB to something just good enough for
+	   us to get started.  Immediately after starting, we'll swpctx
+	   to the target idle task's tss.  Reuse the stack in the mean
+	   time.  Precalculate the target PCBB.  */
+	hwpcb->ksp = (unsigned long) idle + sizeof(union task_union) - 16;
+	hwpcb->usp = 0;
+	hwpcb->ptbr = idle->tss.ptbr;
+	hwpcb->pcc = 0;
+	hwpcb->asn = 0;
+	hwpcb->unique = virt_to_phys(&idle->tss);
+	hwpcb->flags = idle->tss.pal_flags;
+	hwpcb->res1 = hwpcb->res2 = 0;
 
-	mb();	/* Order interrupt and bit testing. */
-	while ((ops = xchg(pending_ipis, 0)) != 0) {
-	  mb();	/* Order bit clearing and data access. */
-	  do {
-		unsigned long which;
+	DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx UNIQUE 0x%lx\n",
+	      hwpcb->ksp, hwpcb->ptbr, hwrpb->vptb, hwcpb->unique));
+	DBGS(("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n",
+	      cpuid, idle->state, idle->tss.pal_flags));
 
-		which = ops & -ops;
-		ops &= ~which;
-		which = ffz(~which);
+	/* Setup HWRPB fields that SRM uses to activate secondary CPU */
+	hwrpb->CPU_restart = __smp_callin;
+	hwrpb->CPU_restart_data = (unsigned long) __smp_callin;
 
-		if (which < IPI_RESCHEDULE) {
-			if (which == IPI_TLB_ALL)
-				tbia();
-			else if (which == IPI_TLB_MM) {
-				struct mm_struct * mm;
-				mm = ipi_msg_flush_tb.p.flush_mm;
-				if (mm == current->mm)
-					flush_tlb_current(mm);
-			}
-			else /* IPI_TLB_PAGE */ {
-				struct vm_area_struct * vma;
-				struct mm_struct * mm;
-				unsigned long addr;
-
-				vma = ipi_msg_flush_tb.p.flush_vma;
-				mm = vma->vm_mm;
-				addr = ipi_msg_flush_tb.flush_addr;
+	/* Recalculate and update the HWRPB checksum */
+	hwrpb_update_checksum(hwrpb);
+
+	/*
+	 * Send a "start" command to the specified processor.
+	 */
 
-				if (mm == current->mm)
-					flush_tlb_current_page(mm, vma, addr);
+	/* SRM III 3.4.1.3 */
+	cpu->flags |= 0x22;	/* turn on Context Valid and Restart Capable */
+	cpu->flags &= ~1;	/* turn off Bootstrap In Progress */
+	wmb();
+
+	send_secondary_console_msg("START\r\n", cpuid);
+
+	/* Wait 1 second for an ACK from the console.  Note that jiffies 
+	   aren't ticking yet.  */
+	for (timeout = 100000; timeout > 0; timeout--) {
+		if (cpu->flags & 1)
+			goto started;
+		udelay(10);
+		barrier();
+	}
+	printk(KERN_ERR "SMP: Processor %d failed to start.\n", cpuid);
+	return -1;
+
+started:
+	DBGS(("secondary_cpu_start: SUCCESS for CPU %d!!!\n", cpuid));
+	return 0;
+}
+
+/*
+ * Bring one cpu online.
+ */
+static int __init
+smp_boot_one_cpu(int cpuid, int cpunum)
+{
+	struct task_struct *idle;
+	long timeout;
+
+	/* Cook up an idler for this guy.  Note that the address we give
+	   to kernel_thread is irrelevant -- it's going to start where
+	   HWRPB.CPU_restart says to start.  But this gets all the other
+	   task-y sort of data structures set up like we wish.  */
+	kernel_thread((void *)__smp_callin, NULL, CLONE_PID|CLONE_VM);
+	idle = task[cpunum];
+	if (!idle)
+		panic("No idle process for CPU %d", cpuid);
+	idle->processor = cpuid;
+
+	/* Schedule the first task manually.  */
+	/* ??? Ingo, what is this?  */
+	idle->has_cpu = 1;
+
+	DBGS(("smp_boot_one_cpu: CPU %d state 0x%lx flags 0x%lx\n",
+	      cpuid, idle->state, idle->flags));
+
+	/* The secondary will change this once it is happy.  Note that
+	   secondary_cpu_start contains the necessary memory barrier.  */
+	smp_secondary_alive = -1;
+
+	/* Whirrr, whirrr, whirrrrrrrrr... */
+	if (secondary_cpu_start(cpuid, idle))
+		return -1;
+
+	/* We've been acked by the console; wait one second for the task
+	   to start up for real.  Note that jiffies aren't ticking yet.  */
+	for (timeout = 0; timeout < 100000; timeout++) {
+		if (smp_secondary_alive != -1)
+			goto alive;
+		udelay(10);
+		barrier();
+	}
+
+	printk(KERN_ERR "SMP: Processor %d is stuck.\n", cpuid);
+	return -1;
+
+alive:
+	/* Another "Red Snapper". */
+	cpu_number_map[cpuid] = cpunum;
+	__cpu_logical_map[cpunum] = cpuid;
+	return 0;
+}
+
+/*
+ * Called from setup_arch.  Detect an SMP system and which processors
+ * are present.
+ */
+void __init
+setup_smp(void)
+{
+	struct percpu_struct *cpubase, *cpu;
+	int i;
+
+	smp_boot_cpuid = hard_smp_processor_id();
+	if (smp_boot_cpuid != 0) {
+		printk(KERN_WARNING "SMP: Booting off cpu %d instead of 0?\n",
+		       smp_boot_cpuid);
+	}
+
+	if (hwrpb->nr_processors > 1) {
+		int boot_cpu_palrev;
+
+		DBGS(("setup_smp: nr_processors %ld\n",
+		      hwrpb->nr_processors));
+
+		cpubase = (struct percpu_struct *)
+			((char*)hwrpb + hwrpb->processor_offset);
+		boot_cpu_palrev = cpubase->pal_revision;
+
+		for (i = 0; i < hwrpb->nr_processors; i++ ) {
+			cpu = (struct percpu_struct *)
+				((char *)cpubase + i*hwrpb->processor_size);
+			if ((cpu->flags & 0x1cc) == 0x1cc) {
+				smp_num_probed++;
+				/* Assume here that "whami" == index */
+				cpu_present_mask |= (1L << i);
+				cpu->pal_revision = boot_cpu_palrev;
 			}
-			clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask);
-		}
-		else if (which == IPI_RESCHEDULE) {
-			/* Reschedule callback.  Everything to be done
-			   is done by the interrupt return path.  */
-		}
-		else if (which == IPI_CPU_STOP) {
-			halt();
-		}
-		else {
-			printk(KERN_CRIT "unknown_ipi() on CPU %d: %lu\n",
-			       this_cpu, which);
+
+			DBGS(("setup_smp: CPU %d: flags 0x%lx type 0x%lx\n",
+			      i, cpu->flags, cpu->type));
+			DBGS(("setup_smp: CPU %d: PAL rev 0x%lx\n",
+			      i, cpu->pal_revision));
 		}
-	  } while (ops);
-	  mb();	/* Order data access and bit testing. */
+	} else {
+		smp_num_probed = 1;
+		cpu_present_mask = (1L << smp_boot_cpuid);
 	}
 
-	cpu_data[this_cpu].ipi_count++;
+	printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_mask = %lx\n",
+	       smp_num_probed, cpu_present_mask);
+}
 
-	if (hwrpb->txrdy)
-		secondary_console_message();
+/*
+ * Called by smp_init bring all the secondaries online and hold them.
+ */
+void __init
+smp_boot_cpus(void)
+{
+	int cpu_count, i;
+	unsigned long bogosum;
+
+	/* Take care of some initial bookkeeping.  */
+	memset(cpu_number_map, -1, sizeof(cpu_number_map));
+	memset(__cpu_logical_map, -1, sizeof(__cpu_logical_map));
+	memset(ipi_data, 0, sizeof(ipi_data));
+
+	cpu_number_map[smp_boot_cpuid] = 0;
+	__cpu_logical_map[0] = smp_boot_cpuid;
+	current->processor = smp_boot_cpuid;
+
+	smp_store_cpu_info(smp_boot_cpuid);
+	smp_tune_scheduling();
+	smp_setup_percpu_timer(smp_boot_cpuid);
+
+	init_idle();
+
+	/* Nothing to do on a UP box, or when told not to.  */
+	if (smp_num_probed == 1 || max_cpus == 0) {
+	        printk(KERN_INFO "SMP mode deactivated.\n");
+		return;
+	}
+
+	printk(KERN_INFO "SMP starting up secondaries.\n");
+
+	cpu_count = 1;
+	for (i = 0; i < NR_CPUS; i++) {
+		if (i == smp_boot_cpuid)
+			continue;
+
+	        if (((cpu_present_mask >> i) & 1) == 0)
+			continue;
+
+		if (smp_boot_one_cpu(i, cpu_count))
+			continue;
+
+		cpu_count++;
+	}
+
+	if (cpu_count == 1) {
+		printk(KERN_ERR "SMP: Only one lonely processor alive.\n");
+		return;
+	}
+
+	bogosum = 0;
+        for (i = 0; i < NR_CPUS; i++) {
+		if (cpu_present_mask & (1L << i))
+			bogosum += cpu_data[i].loops_per_sec;
+        }
+	printk(KERN_INFO "SMP: Total of %d processors activated "
+	       "(%lu.%02lu BogoMIPS).\n",
+	       cpu_count, (bogosum + 2500) / 500000,
+	       ((bogosum + 2500) / 5000) % 100);
+
+	smp_num_cpus = cpu_count;
+}
+
+/*
+ * Called by smp_init to release the blocking online cpus once they 
+ * are all started.
+ */
+void __init
+smp_commence(void)
+{
+	/* smp_init sets smp_threads_ready -- that's enough.  */
+	mb();
+}
+
+/*
+ * Only broken Intel needs this, thus it should not even be
+ * referenced globally.
+ */
+
+void __init
+initialize_secondary(void)
+{
 }
 
+
+extern void update_one_process(struct task_struct *p, unsigned long ticks,
+	                       unsigned long user, unsigned long system,
+			       int cpu);
+
+void
+smp_percpu_timer_interrupt(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+	int user = user_mode(regs);
+	struct cpuinfo_alpha *data = &cpu_data[cpu];
+
+#ifdef NOT_YET_PROFILING
+	clear_profile_irq(mid_xlate[cpu]);
+	if (!user)
+		alpha_do_profile(regs->pc);
+#endif
+
+	if (!--data->prof_counter) {
+		/* We need to make like a normal interrupt -- otherwise
+		   timer interrupts ignore the global interrupt lock,
+		   which would be a Bad Thing.  */
+		irq_enter(cpu, TIMER_IRQ);
+
+		update_one_process(current, 1, user, !user, cpu);
+	        if (current->pid) {
+	                if (--current->counter < 0) {
+				current->counter = 0;
+	                        current->need_resched = 1;
+	                }
+
+	                if (user) {
+				if (current->priority < DEF_PRIORITY) {
+					kstat.cpu_nice++;
+					kstat.per_cpu_nice[cpu]++;
+				} else {
+					kstat.cpu_user++;
+					kstat.per_cpu_user[cpu]++;
+				}
+	                } else {
+				kstat.cpu_system++;
+				kstat.per_cpu_system[cpu]++;
+	                }
+	        }
+
+		data->prof_counter = data->prof_multiplier;
+		irq_exit(cpu, TIMER_IRQ);
+	}
+}
+
+int __init
+setup_profiling_timer(unsigned int multiplier)
+{
+#ifdef NOT_YET_PROFILING
+	int i;
+	unsigned long flags;
+
+	/* Prevent level14 ticker IRQ flooding. */
+	if((!multiplier) || (lvl14_resolution / multiplier) < 500)
+	        return -EINVAL;
+
+	save_and_cli(flags);
+	for (i = 0; i < NR_CPUS; i++) {
+	        if (cpu_present_mask & (1L << i)) {
+	                load_profile_irq(mid_xlate[i],
+					 lvl14_resolution / multiplier);
+	                prof_multiplier[i] = multiplier;
+	        }
+	}
+	restore_flags(flags);
+
+	return 0;
+#else
+	return -EINVAL;
+#endif
+}
+
+
 static void
 send_ipi_message(unsigned long to_whom, enum ipi_message_type operation)
 {
@@ -755,7 +665,7 @@
 
 	for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) {
 		if (to_whom & j)
-			set_bit(operation, &ipi_bits[i]);
+			set_bit(operation, &ipi_data[i].bits);
 	}
 
 	mb();	/* Order bit setting and interrupt. */
@@ -766,123 +676,263 @@
 	}
 }
 
-int
-smp_info(char *buffer)
+/* Structure and data for smp_call_function.  This is designed to 
+   minimize static memory requirements.  Plus it looks cleaner.  */
+
+struct smp_call_struct {
+	void (*func) (void *info);
+	void *info;
+	long wait;
+	atomic_t unstarted_count;
+	atomic_t unfinished_count;
+};
+
+static struct smp_call_struct *smp_call_function_data;
+
+/* Atomicly drop data into a shared pointer.  The pointer is free if
+   it is initially locked.  If retry, spin until free.  */
+
+static inline int
+pointer_lock (void *lock, void *data, int retry)
 {
-	long i;
-	unsigned long sum = 0;
-	for (i = 0; i < NR_CPUS; i++)
-		sum += cpu_data[i].ipi_count;
+	void *old, *tmp;
 
-	return sprintf(buffer, "CPUs probed %d active %d map 0x%x IPIs %ld\n",
-		       smp_num_probed, smp_num_cpus, cpu_present_map, sum);
+	mb();
+again:
+	/* Compare and swap with zero.  */
+	asm volatile (
+	"1:	ldq_l	%0,%1\n"
+	"	mov	%3,%2\n"
+	"	bne	%0,2f\n"
+	"	stq_c	%2,%1\n"
+	"	beq	%2,1b\n"
+	"2:"
+	: "=&r"(old), "=m"(*(void **)lock), "=&r"(tmp)
+	: "r"(data)
+	: "memory");
+
+	if (old == 0)
+		return 0;
+	if (! retry)
+		return -EBUSY;
+
+	while (*(void **)lock)
+		schedule();
+	goto again;
+}
+
+void
+handle_ipi(struct pt_regs *regs)
+{
+	int this_cpu = smp_processor_id();
+	unsigned long *pending_ipis = &ipi_data[this_cpu].bits;
+	unsigned long ops;
+
+	DBGS(("handle_ipi: on CPU %d ops 0x%x PC 0x%lx\n",
+	      this_cpu, *pending_ipis, regs->pc));
+
+	mb();	/* Order interrupt and bit testing. */
+	while ((ops = xchg(pending_ipis, 0)) != 0) {
+	  mb();	/* Order bit clearing and data access. */
+	  do {
+		unsigned long which;
+
+		which = ops & -ops;
+		ops &= ~which;
+		which = ffz(~which);
+
+		if (which == IPI_RESCHEDULE) {
+			/* Reschedule callback.  Everything to be done
+			   is done by the interrupt return path.  */
+		}
+		else if (which == IPI_CALL_FUNC) {
+			struct smp_call_struct *data;
+			void (*func)(void *info);
+			void *info;
+			int wait;
+
+			data = smp_call_function_data;
+			func = data->func;
+			info = data->info;
+			wait = data->wait;
+
+			/* Notify the sending CPU that the data has been
+			   received, and execution is about to begin.  */
+			mb();
+			atomic_dec (&data->unstarted_count);
+
+			/* At this point the structure may be gone unless
+			   wait is true.  */
+			(*func)(info);
+
+			/* Notify the sending CPU that the task is done.  */
+			mb();
+			if (wait) atomic_dec (&data->unfinished_count);
+		}
+		else if (which == IPI_CPU_STOP) {
+			halt();
+		}
+		else {
+			printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n",
+			       this_cpu, which);
+		}
+	  } while (ops);
+
+	  mb();	/* Order data access and bit testing. */
+	}
+
+	cpu_data[this_cpu].ipi_count++;
+
+	if (hwrpb->txrdy)
+		recv_secondary_console_msg();
 }
 
 void
 smp_send_reschedule(int cpu)
 {
-	send_ipi_message(1 << cpu, IPI_RESCHEDULE);
+#if DEBUG_IPI_MSG
+	if (cpu == hard_smp_processor_id())
+		printk(KERN_WARNING
+		       "smp_send_reschedule: Sending IPI to self.\n");
+#endif
+	send_ipi_message(1L << cpu, IPI_RESCHEDULE);
 }
 
 void
 smp_send_stop(void)
 {
-	unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id());
+	unsigned long to_whom = cpu_present_mask ^ (1L << smp_processor_id());
+#if DEBUG_IPI_MSG
+	if (hard_smp_processor_id() != boot_cpu_id)
+		printk(KERN_WARNING "smp_send_stop: Not on boot cpu.\n");
+#endif
 	send_ipi_message(to_whom, IPI_CPU_STOP);
 }
 
-void
-flush_tlb_all(void)
+/*
+ * Run a function on all other CPUs.
+ *  <func>	The function to run. This must be fast and non-blocking.
+ *  <info>	An arbitrary pointer to pass to the function.
+ *  <retry>	If true, keep retrying until ready.
+ *  <wait>	If true, wait until function has completed on other CPUs.
+ *  [RETURNS]   0 on success, else a negative status code.
+ *
+ * Does not return until remote CPUs are nearly ready to execute <func>
+ * or are or have executed.
+ */
+
+int
+smp_call_function (void (*func) (void *info), void *info, int retry, int wait)
 {
-	unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id());
-	long timeout = 1000000;
+	unsigned long to_whom = cpu_present_mask ^ (1L << smp_processor_id());
+	struct smp_call_struct data;
+	long timeout;
+	
+	data.func = func;
+	data.info = info;
+	data.wait = wait;
+	atomic_set(&data.unstarted_count, smp_num_cpus - 1);
+	atomic_set(&data.unfinished_count, smp_num_cpus - 1);
+
+	/* Aquire the smp_call_function_data mutex.  */
+	if (pointer_lock(&smp_call_function_data, &data, retry))
+		return -EBUSY;
+
+	/* Send a message to all other CPUs.  */
+	send_ipi_message(to_whom, IPI_CALL_FUNC);
+
+	/* Wait for a minimal response.  */
+	timeout = jiffies + HZ;
+	while (atomic_read (&data.unstarted_count) > 0
+	       && time_before (jiffies, timeout))
+		barrier();
+
+	/* We either got one or timed out -- clear the lock.  */
+	mb();
+	smp_call_function_data = 0;
+	if (atomic_read (&data.unstarted_count) > 0)
+		return -ETIMEDOUT;
+
+	/* Wait for a complete response, if needed.  */
+	if (wait) {
+		while (atomic_read (&data.unfinished_count) > 0)
+			barrier();
+	}
 
-	spin_lock(&flush_tb_lock);
+	return 0;
+}
 
-	ipi_msg_flush_tb.flush_tb_mask = to_whom;
-	send_ipi_message(to_whom, IPI_TLB_ALL);
+static void
+ipi_flush_tlb_all(void *ignored)
+{
 	tbia();
+}
 
-	while (ipi_msg_flush_tb.flush_tb_mask && --timeout) {
-		udelay(1);
-		barrier();
+void
+flush_tlb_all(void)
+{
+	/* Although we don't have any data to pass, we do want to
+	   synchronize with the other processors.  */
+	if (smp_call_function(ipi_flush_tlb_all, NULL, 1, 1)) {
+		printk(KERN_CRIT "flush_tlb_all: timed out\n");
 	}
 
-	if (timeout == 0) {
-		printk("flush_tlb_all: STUCK on CPU %d mask 0x%x\n",
-		       smp_processor_id(),
-		       ipi_msg_flush_tb.flush_tb_mask);
-		ipi_msg_flush_tb.flush_tb_mask = 0;
-	}
+	tbia();
+}
 
-	spin_unlock(&flush_tb_lock);
+static void
+ipi_flush_tlb_mm(void *x)
+{
+	struct mm_struct *mm = (struct mm_struct *) x;
+	if (mm == current->mm)
+		flush_tlb_current(mm);
 }
 
 void
 flush_tlb_mm(struct mm_struct *mm)
 {
-	unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id());
-	long timeout = 1000000;
-
-	spin_lock(&flush_tb_lock);
-
-	ipi_msg_flush_tb.flush_tb_mask = to_whom;
-	ipi_msg_flush_tb.p.flush_mm = mm;
-	send_ipi_message(to_whom, IPI_TLB_MM);
-
-	if (mm != current->mm)
-		flush_tlb_other(mm);
-	else
+	if (mm == current->mm)
 		flush_tlb_current(mm);
+	else
+		flush_tlb_other(mm);
 
-	while (ipi_msg_flush_tb.flush_tb_mask && --timeout) {
-		udelay(1);
-		barrier();
+	if (smp_call_function(ipi_flush_tlb_mm, mm, 1, 1)) {
+		printk(KERN_CRIT "flush_tlb_mm: timed out\n");
 	}
+}
 
-	if (timeout == 0) {
-		printk("flush_tlb_mm: STUCK on CPU %d mask 0x%x\n",
-		       smp_processor_id(),
-		       ipi_msg_flush_tb.flush_tb_mask);
-		ipi_msg_flush_tb.flush_tb_mask = 0;
-	}
+struct flush_tlb_page_struct {
+	struct vm_area_struct *vma;
+	struct mm_struct *mm;
+	unsigned long addr;
+};
 
-	spin_unlock(&flush_tb_lock);
+static void
+ipi_flush_tlb_page(void *x)
+{
+	struct flush_tlb_page_struct *data = (struct flush_tlb_page_struct *)x;
+	if (data->mm == current->mm)
+		flush_tlb_current_page(data->mm, data->vma, data->addr);
 }
 
 void
 flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
 {
-	int cpu = smp_processor_id();
-	unsigned long to_whom = cpu_present_map ^ (1 << cpu);
-	struct mm_struct * mm = vma->vm_mm;
-	int timeout = 1000000;
-
-	spin_lock(&flush_tb_lock);
-
-	ipi_msg_flush_tb.flush_tb_mask = to_whom;
-	ipi_msg_flush_tb.p.flush_vma = vma;
-	ipi_msg_flush_tb.flush_addr = addr;
-	send_ipi_message(to_whom, IPI_TLB_PAGE);
+	struct flush_tlb_page_struct data;
+	struct mm_struct *mm = vma->vm_mm;
 
-	if (mm != current->mm)
-		flush_tlb_other(mm);
-	else
-		flush_tlb_current_page(mm, vma, addr);
-
-	while (ipi_msg_flush_tb.flush_tb_mask && --timeout) {
-		udelay(1);
-		barrier();
-	}
+	data.vma = vma;
+	data.mm = mm;
+	data.addr = addr;
 
-	if (timeout == 0) {
-		printk("flush_tlb_page: STUCK on CPU %d mask 0x%x\n",
-		       smp_processor_id(),
-		       ipi_msg_flush_tb.flush_tb_mask);
-		ipi_msg_flush_tb.flush_tb_mask = 0;
+	if (mm == current->mm)
+		flush_tlb_current_page(mm, vma, addr);
+	else
+		flush_tlb_other(mm);
+	
+	if (smp_call_function(ipi_flush_tlb_page, &data, 1, 1)) {
+		printk(KERN_CRIT "flush_tlb_page: timed out\n");
 	}
-
-	spin_unlock(&flush_tb_lock);
 }
 
 void
@@ -892,57 +942,47 @@
 	flush_tlb_mm(mm);
 }
 
-#if DEBUG_SPINLOCK
-
-#ifdef MANAGE_SPINLOCK_IPL
-
-static inline long 
-spinlock_raise_ipl(spinlock_t * lock)
+
+int
+smp_info(char *buffer)
 {
- 	long min_ipl = lock->target_ipl;
-	long last_ipl = swpipl(7);
-	if (last_ipl < 7 && min_ipl < 7)
-		setipl(min_ipl < last_ipl ? last_ipl : min_ipl);
-	return last_ipl;
-}
+	long i;
+	unsigned long sum = 0;
+	for (i = 0; i < NR_CPUS; i++)
+		sum += cpu_data[i].ipi_count;
 
-static inline void
-spinlock_restore_ipl(long prev)
-{
-	setipl(prev);
+	return sprintf(buffer, "CPUs probed %d active %d map 0x%lx IPIs %ld\n",
+		       smp_num_probed, smp_num_cpus, cpu_present_mask, sum);
 }
 
-#else
-
-#define spinlock_raise_ipl(LOCK)	((void)(LOCK), 0)
-#define spinlock_restore_ipl(PREV)	((void)(PREV))
-
-#endif /* MANAGE_SPINLOCK_IPL */
-
+
+#if DEBUG_SPINLOCK
 void
 spin_unlock(spinlock_t * lock)
 {
-	long old_ipl = lock->saved_ipl;
 	mb();
 	lock->lock = 0;
-	spinlock_restore_ipl(old_ipl);
+
+	lock->on_cpu = -1;
+	lock->previous = NULL;
+	lock->task = NULL;
+	lock->base_file = "none";
+	lock->line_no = 0;
 }
 
 void
-spin_lock(spinlock_t * lock)
+debug_spin_lock(spinlock_t * lock, const char *base_file, int line_no)
 {
 	long tmp;
-	long stuck = 1<<27;
+	long stuck;
 	void *inline_pc = __builtin_return_address(0);
 	unsigned long started = jiffies;
 	int printed = 0;
 	int cpu = smp_processor_id();
-	long old_ipl = spinlock_raise_ipl(lock);
 
+	stuck = 1L << 28;
  try_again:
 
-	stuck = 0x10000000; /* was 4G, now 256M */
-
 	/* Use sub-sections to put the actual loop at the end
 	   of this object file's text section so as to perfect
 	   branch prediction.  */
@@ -961,52 +1001,53 @@
 	"	blbs	%0,2b\n"
 	"	br	1b\n"
 	".previous"
-	: "=r" (tmp),
-	  "=m" (__dummy_lock(lock)),
-	  "=r" (stuck)
-	: "2" (stuck));
+	: "=r" (tmp), "=m" (__dummy_lock(lock)), "=r" (stuck)
+	: "1" (__dummy_lock(lock)), "2" (stuck));
 
 	if (stuck < 0) {
-		if (!printed) {
-			printk("spinlock stuck at %p(%d) owner %s at %p\n",
-			       inline_pc, cpu, lock->task->comm,
-			       lock->previous);
-			printed = 1;
-		}
-		stuck = 1<<30;
+		printk(KERN_WARNING
+		       "%s:%d spinlock stuck in %s at %p(%d)"
+		       " owner %s at %p(%d) %s:%d\n",
+		       base_file, line_no,
+		       current->comm, inline_pc, cpu,
+		       lock->task->comm, lock->previous,
+		       lock->on_cpu, lock->base_file, lock->line_no);
+		stuck = 1L << 36;
+		printed = 1;
 		goto try_again;
 	}
 
 	/* Exiting.  Got the lock.  */
-	lock->saved_ipl = old_ipl;
 	lock->on_cpu = cpu;
 	lock->previous = inline_pc;
 	lock->task = current;
+	lock->base_file = base_file;
+	lock->line_no = line_no;
 
 	if (printed) {
-		printk("spinlock grabbed at %p(%d) %ld ticks\n",
-		       inline_pc, cpu, jiffies - started);
+		printk(KERN_WARNING
+		       "%s:%d spinlock grabbed in %s at %p(%d) %ld ticks\n",
+		       base_file, line_no, current->comm, inline_pc,
+		       cpu, jiffies - started);
 	}
 }
 
 int
-spin_trylock(spinlock_t * lock)
+debug_spin_trylock(spinlock_t * lock, const char *base_file, int line_no)
 {
-	long old_ipl = spinlock_raise_ipl(lock);
 	int ret;
 	if ((ret = !test_and_set_bit(0, lock))) {
-		mb();
-		lock->saved_ipl = old_ipl;
 		lock->on_cpu = smp_processor_id();
 		lock->previous = __builtin_return_address(0);
 		lock->task = current;
 	} else {
-		spinlock_restore_ipl(old_ipl);
+		lock->base_file = base_file;
+		lock->line_no = line_no;
 	}
 	return ret;
 }
 #endif /* DEBUG_SPINLOCK */
-
+
 #if DEBUG_RWLOCK
 void write_lock(rwlock_t * lock)
 {
@@ -1038,18 +1079,17 @@
 	"	blt	%1,8b\n"
 	"	br	1b\n"
 	".previous"
-	: "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (regy)
-	, "=&r" (stuck_lock), "=&r" (stuck_reader)
-	: "0" (__dummy_lock(lock))
-	, "3" (stuck_lock), "4" (stuck_reader)
-	);
+	: "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (regy),
+	  "=&r" (stuck_lock), "=&r" (stuck_reader)
+	: "0" (__dummy_lock(lock)), "3" (stuck_lock), "4" (stuck_reader));
 
 	if (stuck_lock < 0) {
-		printk("write_lock stuck at %p\n", inline_pc);
+		printk(KERN_WARNING "write_lock stuck at %p\n", inline_pc);
 		goto try_again;
 	}
 	if (stuck_reader < 0) {
-		printk("write_lock stuck on readers at %p\n", inline_pc);
+		printk(KERN_WARNING "write_lock stuck on readers at %p\n",
+		       inline_pc);
 		goto try_again;
 	}
 }
@@ -1079,11 +1119,10 @@
 	"	br	1b\n"
 	".previous"
 	: "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (stuck_lock)
-	: "0" (__dummy_lock(lock)), "2" (stuck_lock)
-	);
+	: "0" (__dummy_lock(lock)), "2" (stuck_lock));
 
 	if (stuck_lock < 0) {
-		printk("read_lock stuck at %p\n", inline_pc);
+		printk(KERN_WARNING "read_lock stuck at %p\n", inline_pc);
 		goto try_again;
 	}
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)