parisc: Fix SMP reboot

Most important is the flushing of the TLB entries

Signed-off-by: Helge Deller <deller@gmx.de>
diff --git a/src/parisc/head.S b/src/parisc/head.S
index 891ec9a..900ec48 100644
--- a/src/parisc/head.S
+++ b/src/parisc/head.S
@@ -67,6 +67,15 @@
 #define INT_LEN 4
 #endif
 
+/* various control register and irq bits */
+#define PSW_I		1
+#define PSW_Q		8
+#define CR_EIRR		23
+#define CR_IVA		14
+#define CR_EIEM		15
+#define PSW_W_SM	0x200
+#define PSW_W_BIT       36
+
 	.import	$global$
 	.section ".head.text","ax"
 	 .level 1.1
@@ -91,6 +100,8 @@
 
         .align 0x80
 ENTRY(startup)
+	rsm	PSW_I, %r0	/* disable local irqs */
+
 	/* Make sure space registers are set to zero */
 	mtsp    %r0,%sr0
 	mtsp    %r0,%sr1
@@ -101,14 +112,34 @@
 	mtsp    %r0,%sr6
 	mtsp    %r0,%sr7
 
-#define PSW_W_SM	0x200
-#define PSW_W_BIT       36
-
 	;! nuke the W bit
 	.level 2.0
 	rsm	PSW_W_SM, %r0
 	.level 1.1
 
+	/* If CPU HPA is already set in CPU_HPA_CR_REG then the
+	 * CPU is already initialized and the machine was only reset */
+	mfctl   CPU_HPA_CR_REG, %r1
+	comib,= 0,%r1,$startup_fresh_booted
+	nop
+
+$startup_just_rebooted:
+	/* Get current CPU HPA. It was stored there at initial bootup. */
+	mfctl   CPU_HPA_CR_REG, %r5
+
+	/* branch if this is the monarch cpu */
+	load32 CPU_HPA, %r1
+	comb,= %r5,%r1,$is_monarch_cpu_reboot
+	nop
+
+	/* we assume the monarch CPU is in idle loop. wake it up. */
+	ldi	-1, %r3		/* trigger IRQ0 (Timer) */
+	stw	%r3, 0(%r1)
+	b,n	enter_smp_idle_loop
+
+$startup_fresh_booted:
+	/* Here the machine was booted from scratch: */
+
 	/* Save CPU HPA in cr7, hopefully HP-UX will not use that register. */
 	mtctl   %r5, CPU_HPA_CR_REG /* store CPU HPA */
 
@@ -121,38 +152,32 @@
 	/* IDLE LOOP for SMP CPUs - wait for rendenzvous. */
 	mfctl   CPU_HPA_CR_REG, %r25 /* get CPU HPA from cr7 */
 
-#define PSW_I 1
-	rsm	PSW_I, %r0	/* disable local irqs */
+	rsm	PSW_I | PSW_Q, %r0	/* disable local irqs */
+	mtctl	%r0, CR_EIEM	/* disable all external irqs */
 
 	/* EIRR : clear all pending external intr */
-#define CR_EIRR 23
 	load32	-1,%r1
 	mtctl	%r1, CR_EIRR
 	mfctl	CR_EIRR, %r0
 	mtctl	%r0, CR_EIRR
 
 	/* Load IVT for SMT tiny loop exit */
-#define CR_IVA 14
 	load32	BOOTADDR(smp_ivt),%r1
 	mtctl	%r1, CR_IVA
 
 	/* enable CPU local interrupts */
-#define CR_EIEM 15
 	load32	1<<31, %r1	/* allow IRQ0 (Timer) */
 	mtctl	%r1, CR_EIEM
 	ssm	PSW_I, %r0	/* enable local irqs */
 
-	/* endless idle loop, exits to $smp_exit_loop by IRQ only */
+	/* endless idle loop for secondary CPUs. Exits to $smp_exit_loop by IRQ only */
 $smp_idle_loop:
 	b $smp_idle_loop
-	or %r10,%r10,%r10
+	or %r10,%r10,%r10	/* qemu sleep instruction */
 
 $smp_exit_loop:
-	mtctl	%r0, CR_EIEM
 	rsm	PSW_I, %r0	/* disable local irqs */
-
-	/* tell QEMU to drop all local TLB entries. */
-	pdtlbe	%r0(%sr1,%r0)
+	mtctl	%r0, CR_EIEM
 
 	/* on 64bit: Address of PDCE_PROC for each non-monarch processor in GR26. */
 	load32	BOOTADDR(pdc_entry), %r26
@@ -160,11 +185,23 @@
 	/* jump to rendevouz */
 	ldw	0x10(%r0),%r3	/* MEM_RENDEZ */
 	/* ldw	0x28(%r0),%r0	MEM_RENDEZ_HI - assume addr < 4GB */
-	load32	enter_smp_idle_loop, %rp
+	cmpb,=,n  %r0,%r3,startup	/* branch to startup if not yet initialized */
+	load32	startup, %rp
 	bv,n	0(%r3)
 
-
 $is_monarch_cpu:
+	/* Save boot_args. Only monarch CPU does this once. */
+        load32          BOOTADDR(0x040 + 10*4),%r1
+        stw,ma          %r26,4(%r1)
+        stw,ma          %r25,4(%r1)
+        stw,ma          %r24,4(%r1)
+        stw,ma          %r23,4(%r1)
+        stw,ma          %r22,4(%r1)
+        stw,ma          %r21,4(%r1)
+        stw,ma          %r20,4(%r1)
+        stw,ma          %r19,4(%r1)
+
+$is_monarch_cpu_reboot:
 	/* Initialize stack pointer */
 	load32	BOOTADDR(parisc_stack),%r1
 	ldo	FRAME_SIZE(%r1),%sp
@@ -182,23 +219,11 @@
 	cmpb,<<,n %r3,%r4,$bss_loop
 	stw,ma	%r0,4(%r3)
 
-	/* Save boot args */
-        load32          BOOTADDR(boot_args),%r1
-        stw,ma          %r26,4(%r1)
-        stw,ma          %r25,4(%r1)
-        stw,ma          %r24,4(%r1)
-        stw,ma          %r23,4(%r1)
-        stw,ma          %r22,4(%r1)
-        stw,ma          %r21,4(%r1)
-        stw,ma          %r20,4(%r1)
-        stw,ma          %r19,4(%r1)
-
 	load32	BOOTADDR(start_parisc_firmware),%r3
 	bv	0(%r3)
 	copy	%r0,%r2
 END(startup)
 
-
 /*******************************************************
   TOC handler
   Write all GRs, CRs, SRs and the iaoq_back and iasq_back registers (in
@@ -381,18 +406,6 @@
 	ldw -32(%sp),%dp
 END(iodc_entry)
 
-	.data
-ENTRY(boot_args)
-        .word 0 /* r26: ramsize */
-        .word 0 /* r25: kernel entry point */
-        .word 0 /* r24: cmdline */
-        .word 0 /* r23: initrd_start */
-        .word 0 /* r22: initrd_end */
-        .word 0 /* r21: num CPUs */
-        .word 0 /* r20: pdc_debug */
-        .word 0 /* r19: fw_cfg port */
-END(boot_args)
-
 /****************************************************************
  * Rom Header for VGA / STI
  ****************************************************************/
diff --git a/src/parisc/parisc.c b/src/parisc/parisc.c
index 65ed177..5cae7b5 100644
--- a/src/parisc/parisc.c
+++ b/src/parisc/parisc.c
@@ -92,24 +92,21 @@
  * PA-RISC specific constants and functions.
  ********************************************************/
 
-/* Pointer to zero-page of PA-RISC */
-#define PAGE0 ((volatile struct zeropage *) 0UL)
-
-/* variables provided by qemu */
-extern unsigned long boot_args[];
-#define ram_size		(boot_args[0])
-#define linux_kernel_entry	(boot_args[1])
-#define cmdline			(boot_args[2])
-#define initrd_start		(boot_args[3])
-#define initrd_end		(boot_args[4])
-#define smp_cpus		(boot_args[5])
-#define pdc_debug               (boot_args[6])
-#define fw_cfg_port		(boot_args[7])
+/* variables provided by qemu - boot_args starting at pad0[10] */
+#define ram_size		PAGE0->pad0[10]
+#define linux_kernel_entry	PAGE0->pad0[11]
+#define cmdline			PAGE0->pad0[12]
+#define initrd_start		PAGE0->pad0[13]
+#define initrd_end		PAGE0->pad0[14]
+#define smp_cpus		PAGE0->pad0[15]
+#define pdc_debug		PAGE0->pad0[16]
+#define fw_cfg_port		PAGE0->pad0[17]
 
 /* flags for pdc_debug */
-#define DEBUG_PDC       0x0001
-#define DEBUG_IODC      0x0002
-#define DEBUG_BOOT_IO   0x0004
+#define DEBUG_PDC       0x01
+#define DEBUG_IODC      0x02
+#define DEBUG_BOOT_IO   0x04
+#define DEBUG_CHASSIS   0x08
 
 int pdc_console;
 /* flags for pdc_console */
@@ -1720,13 +1717,14 @@
                 p = (unsigned long *)&pim11->sr[0];
         printf("SR0: %lx %lx %lx %lx %lx %lx %lx %lx\n", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
         if (is_64bit()) {
-                printf("IAQ: %lx.%lx %lx.%lx\n",
+                printf("IAQ: %lx.%lx %lx.%lx   PSW: %lx\n",
                         (unsigned long)pim20->cr[17], (unsigned long)pim20->cr[18],
-                        (unsigned long)pim20->iasq_back, (unsigned long)pim20->iaoq_back);
+                        (unsigned long)pim20->iasq_back, (unsigned long)pim20->iaoq_back,
+			(unsigned long)pim20->cr[22]);
                 printf("RP(r2): %lx\n", (unsigned long)pim20->gr[2]);
         } else {
-                printf("IAQ: %x.%x %x.%x\n", pim11->cr[17], pim11->cr[18],
-                        pim11->iasq_back, pim11->iaoq_back);
+                printf("IAQ: %x.%x %x.%x   PSW: %x\n", pim11->cr[17], pim11->cr[18],
+                        pim11->iasq_back, pim11->iaoq_back, pim11->cr[22]);
                 printf("RP(r2): %x\n", pim11->gr[2]);
         }
 
@@ -2178,8 +2176,8 @@
     model.sw_id = romfile_loadstring_to_int("opt/hostid", model.sw_id);
     dprintf(0, "fw_cfg: machine hostid %lu\n", model.sw_id);
 
-    /* Initialize PAGE0 */
-    memset((void*)PAGE0, 0, sizeof(*PAGE0));
+    /* Do not initialize PAGE0. We have the boot args stored there. */
+    /* memset((void*)PAGE0, 0, sizeof(*PAGE0)); */
 
     /* copy pdc_entry entry into low memory. */
     memcpy((void*)MEM_PDC_ENTRY, &pdc_entry_table, 3*4);
@@ -2254,13 +2252,13 @@
     // PlatformRunningOn = PF_QEMU;  // emulate runningOnQEMU()
 
     cpu_hz = 100 * PAGE0->mem_10msec; /* Hz of this PARISC */
-    dprintf(1, "\nPARISC SeaBIOS Firmware, %ld x PA7300LC (PCX-L2) at %d.%06d MHz, %lu MB RAM.\n",
+    dprintf(1, "\nPARISC SeaBIOS Firmware, %d x PA7300LC (PCX-L2) at %d.%06d MHz, %d MB RAM.\n",
             smp_cpus, cpu_hz / 1000000, cpu_hz % 1000000,
             ram_size/1024/1024);
 
     if (ram_size < MIN_RAM_SIZE) {
         printf("\nSeaBIOS: Machine configured with too little "
-                "memory (%ld MB), minimum is %d MB.\n\n",
+                "memory (%d MB), minimum is %d MB.\n\n",
                 ram_size/1024/1024, MIN_RAM_SIZE/1024/1024);
         hlt();
     }
@@ -2278,6 +2276,16 @@
     serial_setup();
     block_setup();
 
+    PAGE0->vec_rendz = 0; /* No rendezvous yet. Add MEM_RENDEZ_HI later */
+    /* if this is a reboot, force secondary CPUs to enter smp_idle loop */
+    if (PAGE0->imm_soft_boot) {
+	for (i = 1; i < smp_cpus; i++) {
+		unsigned long hpa;
+		hpa = CPU_HPA_IDX(i);
+		*(int*)hpa = -1; /* send Wakeup IRQ to trigger QEMU to load boot address */
+	}
+    }
+
     printf("\n");
     printf("SeaBIOS PA-RISC Firmware Version %d\n"
             "\n"
@@ -2293,9 +2301,9 @@
                 " MHz    %s                 Functional            0 KB\n",
                 i < 10 ? " ":"", i, i?"Idle  ":"Active");
     printf("\n\n");
-    printf("  Available memory:     %llu MB\n"
+    printf("  Available memory:     %u MB\n"
             "  Good memory required: %d MB\n\n",
-            (unsigned long long)ram_size/1024/1024, MIN_RAM_SIZE/1024/1024);
+            ram_size/1024/1024, MIN_RAM_SIZE/1024/1024);
 
     // search boot devices
     find_initial_parisc_boot_drives(&parisc_boot_harddisc, &parisc_boot_cdrom);
@@ -2338,6 +2346,10 @@
         PAGE0->mem_boot.dp.layers[1] = boot_drive->lun;
     }
 
+    /* Qemu-specific: Drop *all* TLB entries for all CPUs before start. */
+    /* Necessary if machine was rebooted. */
+    asm("pdtlbe %%r0(%%sr1,%%r0)" : : : "memory");
+
     /* directly start Linux kernel if it was given on qemu command line. */
     if (linux_kernel_entry > 1) {
         void (*start_kernel)(unsigned long mem_free, unsigned long cline,
@@ -2345,6 +2357,8 @@
 
         printf("Autobooting Linux kernel which was loaded by qemu...\n\n");
         start_kernel = (void *) linux_kernel_entry;
+	/* zero out kernel entry point in case we reset the machine: */
+        linux_kernel_entry = 0;
         start_kernel(PAGE0->mem_free, cmdline, initrd_start, initrd_end);
         hlt(); /* this ends the emulator */
     }