patch-2.2.15 linux/arch/sparc64/kernel/smp.c

Next file: linux/arch/sparc64/kernel/sparc64_ksyms.c
Previous file: linux/arch/sparc64/kernel/signal32.c
Back to the patch index
Back to the overall index

diff -u --new-file --recursive --exclude-from ../../exclude v2.2.14/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
@@ -119,6 +119,7 @@
 __initfunc(void smp_callin(void))
 {
 	int cpuid = hard_smp_processor_id();
+	unsigned long pstate;
 
 	inherit_locked_prom_mappings(0);
 
@@ -127,18 +128,37 @@
 
 	cpu_probe();
 
-	/* Master did this already, now is the time for us to do it. */
+	/* Guarentee that the following sequences execute
+	 * uninterrupted.
+	 */
+	__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
+			     "wrpr	%0, %1, %%pstate"
+			     : "=r" (pstate)
+			     : "i" (PSTATE_IE));
+
+	/* Set things up so user can access tick register for profiling
+	 * purposes.  Also workaround BB_ERRATA_1 by doing a dummy
+	 * read back of %tick after writing it.
+	 */
 	__asm__ __volatile__("
 	sethi	%%hi(0x80000000), %%g1
-	sllx	%%g1, 32, %%g1
-	rd	%%tick, %%g2
+	ba,pt	%%xcc, 1f
+	 sllx	%%g1, 32, %%g1
+	.align	64
+1:	rd	%%tick, %%g2
 	add	%%g2, 6, %%g2
 	andn	%%g2, %%g1, %%g2
 	wrpr	%%g2, 0, %%tick
-"	: /* no outputs */
+	rdpr	%%tick, %%g0"
+	: /* no outputs */
 	: /* no inputs */
 	: "g1", "g2");
 
+	/* Restore PSTATE_IE. */
+	__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
+			     : /* no outputs */
+			     : "r" (pstate));
+
 	smp_setup_percpu_timer();
 
 	__sti();
@@ -159,7 +179,7 @@
 }
 
 extern int cpu_idle(void *unused);
-extern void init_IRQ(void);
+extern unsigned long init_IRQ(unsigned long);
 
 void initialize_secondary(void)
 {
@@ -168,7 +188,8 @@
 int start_secondary(void *unused)
 {
 	trap_init();
-	init_IRQ();
+	/* No memory allocation allowed on slave IRQ init */
+	init_IRQ(0UL);
 	smp_callin();
 	return cpu_idle(NULL);
 }
@@ -280,6 +301,13 @@
 	       smp_processor_id(), data0, data1, data2, target);
 #endif
 again:
+	/* Ok, this is the real Spitfire Errata #54.
+	 * One must read back from a UDB internal register
+	 * after writes to the UDB interrupt dispatch, but
+	 * before the membar Sync for that write.
+	 * So we use the high UDB control register (ASI 0x7f,
+	 * ADDR 0x20) for the dummy read. -DaveM
+	 */
 	__asm__ __volatile__("
 	wrpr	%0, %1, %%pstate
 	wr	%%g0, %2, %%asi
@@ -288,10 +316,14 @@
 	stxa	%5, [0x60] %%asi
 	membar	#Sync
 	stxa	%%g0, [%6] %%asi
+	membar	#Sync
+	mov	0x20, %%g1
+	ldxa	[%%g1] 0x7f, %%g0
 	membar	#Sync"
 	: /* No outputs */
 	: "r" (pstate), "i" (PSTATE_IE), "i" (ASI_UDB_INTR_W),
-	  "r" (data0), "r" (data1), "r" (data2), "r" (target));
+	  "r" (data0), "r" (data1), "r" (data2), "r" (target)
+	: "g1");
 
 	/* NOTE: PSTATE_IE is still clear. */
 	stuck = 100000;
@@ -589,7 +621,7 @@
 
 void smp_percpu_timer_interrupt(struct pt_regs *regs)
 {
-	unsigned long compare, tick;
+	unsigned long compare, tick, pstate;
 	int cpu = smp_processor_id();
 	int user = user_mode(regs);
 
@@ -655,27 +687,87 @@
 			prof_counter(cpu) = prof_multiplier(cpu);
 		}
 
+		/* Guarentee that the following sequences execute
+		 * uninterrupted.
+		 */
+		__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
+				     "wrpr	%0, %1, %%pstate"
+				     : "=r" (pstate)
+				     : "i" (PSTATE_IE));
+
+		/* Workaround for Spitfire Errata (#54 I think??), I discovered
+		 * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch
+		 * number 103640.
+		 *
+		 * On Blackbird writes to %tick_cmpr can fail, the
+		 * workaround seems to be to execute the wr instruction
+		 * at the start of an I-cache line, and perform a dummy
+		 * read back from %tick_cmpr right after writing to it. -DaveM
+		 *
+		 * Just to be anal we add a workaround for Spitfire
+		 * Errata 50 by preventing pipeline bypasses on the
+		 * final read of the %tick register into a compare
+		 * instruction.  The Errata 50 description states
+		 * that %tick is not prone to this bug, but I am not
+		 * taking any chances.
+		 */
 		__asm__ __volatile__("rd	%%tick_cmpr, %0\n\t"
-				     "add	%0, %2, %0\n\t"
-				     "wr	%0, 0x0, %%tick_cmpr\n\t"
-				     "rd	%%tick, %1"
+				     "ba,pt	%%xcc, 1f\n\t"
+				     " add	%0, %2, %0\n\t"
+				     ".align	64\n"
+				  "1: wr	%0, 0x0, %%tick_cmpr\n\t"
+				     "rd	%%tick_cmpr, %%g0\n\t"
+				     "rd	%%tick, %1\n\t"
+				     "mov	%1, %1"
 				     : "=&r" (compare), "=r" (tick)
 				     : "r" (current_tick_offset));
+
+		/* Restore PSTATE_IE. */
+		__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
+				     : /* no outputs */
+				     : "r" (pstate));
 	} while (tick >= compare);
 }
 
 __initfunc(static void smp_setup_percpu_timer(void))
 {
 	int cpu = smp_processor_id();
+	unsigned long pstate;
 
 	prof_counter(cpu) = prof_multiplier(cpu) = 1;
 
-	__asm__ __volatile__("rd	%%tick, %%g1\n\t"
-			     "add	%%g1, %0, %%g1\n\t"
-			     "wr	%%g1, 0x0, %%tick_cmpr"
+	/* Guarentee that the following sequences execute
+	 * uninterrupted.
+	 */
+	__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
+			     "wrpr	%0, %1, %%pstate"
+			     : "=r" (pstate)
+			     : "i" (PSTATE_IE));
+
+	/* Workaround for Spitfire Errata (#54 I think??), I discovered
+	 * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch
+	 * number 103640.
+	 *
+	 * On Blackbird writes to %tick_cmpr can fail, the
+	 * workaround seems to be to execute the wr instruction
+	 * at the start of an I-cache line, and perform a dummy
+	 * read back from %tick_cmpr right after writing to it. -DaveM
+	 */
+	__asm__ __volatile__("
+		rd	%%tick, %%g1
+		ba,pt	%%xcc, 1f
+		 add	%%g1, %0, %%g1
+		.align	64
+	1:	wr	%%g1, 0x0, %%tick_cmpr
+		rd	%%tick_cmpr, %%g0"
+	: /* no outputs */
+	: "r" (current_tick_offset)
+	: "g1");
+
+	/* Restore PSTATE_IE. */
+	__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
 			     : /* no outputs */
-			     : "r" (current_tick_offset)
-			     : "g1");
+			     : "r" (pstate));
 }
 
 __initfunc(void smp_tick_init(void))

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