Re: patch: power off

Izumi Tsutsui <[email protected]> Mon, 24 Mar 2014 00:26:05 +0900
Newsgroups gmane.os.netbsd.ports.x68k
Message-ID <[email protected]>
> Current x68k kernel supports software power-off (by sysmon(4)),
> but in fact, the kernel does not turn off the power.  Power off
> is happened in IPLROM after software reset.
> 
> So, I wrote a patch that the kernel does power off itself.
> Any comments?

Basically looks good, but I have some dumb comments. (see below)

> I have tested only on XM6i because my X68030 has failed.  I'm
> happy if someone could test it on the real machine.

Powerdown after turning the power switch off just works on my X68030.

> +ENTRY_NOPROFILE(dopoweroff)
> +	movql	#1,%d1			| shutdown
> +	bra	Ldoboot_main
> +
>  ENTRY_NOPROFILE(doboot)
> +	movql	#0,%d1			| reboot
> +
> +Ldoboot_main:

It would be better to make doboot() take "howto" arg rather than
having different entry points. (patch attached)

> +#else /* without pxhtc patch, delay is local label */
> +	bsr	_delay

_ASM_LABEL(_delay) is more explicit for a function call.

> -	if (((howto & RB_POWERDOWN) == RB_POWERDOWN) && power_switch_is_off)
> -		doboot();
> -	else if (/*((howto & RB_POWERDOWN) == RB_POWERDOWN) ||*/
> -		 ((howto & RB_HALT) == RB_HALT)) {
> +	if (((howto & RB_POWERDOWN) == RB_POWERDOWN) && power_switch_is_off) {
> +		dopoweroff();
> +	} else if ((howto & RB_HALT) == RB_HALT) {
>  		printf("System halted.  Hit any key to reboot.\n\n");
>  		(void)cngetc();
>  	}

I wonder if the system port for powerdown can be accessed even before
the MMU is turned off.

If so, we can prepare a "poweroff" function and call it in cpu_reboot()
before calling doboot() like macppc does:
http://nxr.netbsd.org/xref/src/sys/arch/macppc/macppc/machdep.c?r=1.164#202

---
Index: x68k/locore.s
===================================================================
RCS file: /cvsroot/src/sys/arch/x68k/x68k/locore.s,v
retrieving revision 1.117
diff -u -p -d -r1.117 locore.s
--- x68k/locore.s	22 Mar 2014 21:49:18 -0000	1.117
+++ x68k/locore.s	23 Mar 2014 15:20:45 -0000
@@ -899,6 +899,7 @@ L_delay:
  * memory this way.
  */
 ENTRY_NOPROFILE(doboot)
+	movl	%sp@(4),%d1		| save "howto" arg
 	movw	#PSL_HIGHIPL,%sr	| cut off any interrupts
 	subal	%a1,%a1			| a1 = 0
 
@@ -915,18 +916,44 @@ Ldoboot0:
 	movc	%d0,%cacr		| disable on-chip cache(s)
 
 	| ok, turn off MMU..
-Ldoreboot:
 #if defined(M68040) || defined(M68060)
 	tstl	%d2			| 68040?
 	jne	LmotommuF		| no, skip
 	movc	%a1,%cacr		| caches off
 	.long	0x4e7b9003		| movc a1(=0),tc ; disable MMU
-	jra	Ldoreboot1
+	jra	Ldoboot1
 LmotommuF:
 #endif
 	clrl	%sp@
 	pmove	%sp@,%tc		| disable MMU
-Ldoreboot1:
+
+Ldoboot1:
+	/* Reset the stack pointer after MMU disabled */
+	subal	%a5,%a5			| XXX firstpa=0 because PA==VA
+	ASRELOC(tmpstk, %a0)
+	movl	%a0,%sp
+
+	andl	#0x800,%d1
+	tstl	%d1			| if ((howto & RB_POWERDOWN) == 0)
+	beq	Ldoreboot		|  then reboot
+
+	leal	0xe8e00f,%a0		| write a power-off sequence
+	movb	#0x00,%a0@		|  to system port
+	movb	#0x0f,%a0@
+	movb	#0x0f,%a0@
+
+	movl	#1000000,%sp@-		| wait a bit
+#define WITH_PXHTC 0
+#if WITH_PXHTC /* with pxhtc patch, delay is a pointer to function */
+	RELOC(delay, %a0)
+	moval	%a0@,%a0
+	jsr	%a0@
+#else /* without pxhtc patch, delay is local label */
+	bsr	_ASM_LABEL(_delay)
+#endif
+	/* PASSTHROUGH */		| passthrough even if came back
+
+Ldoreboot:
 	moveml	0x00ff0000,#0x0101	| get RESET vectors in ROM
 					|	(d0: ssp, a0: pc)
 	moveml	#0x0101,%a1@		| put them at 0x0000 (for Xellent30)
Index: x68k/machdep.c
===================================================================
RCS file: /cvsroot/src/sys/arch/x68k/x68k/machdep.c,v
retrieving revision 1.188
diff -u -p -d -r1.188 machdep.c
--- x68k/machdep.c	22 Mar 2014 21:49:18 -0000	1.188
+++ x68k/machdep.c	23 Mar 2014 15:20:45 -0000
@@ -107,7 +107,7 @@ __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 
 #include <machine/autoconf.h>
 #include <arch/x68k/dev/intiovar.h>
 
-extern void doboot(void) __attribute__((__noreturn__));
+extern void doboot(int) __attribute__((__noreturn__));
 
 /* the following is used externally (sysctl_hw) */
 char	machine[] = MACHINE;	/* from <machine/param.h> */
@@ -517,23 +517,22 @@ cpu_reboot(int howto, char *bootstr)
 	 *	Power cannot be removed; simply halt the system (b)
 	 *	Power switch state is checked in shutdown hook
 	 *  a2: the power switch is off
-	 *	Remove the power; the simplest way is go back to ROM eg. reboot
+	 *	Remove power by power-off sequence via system port in doboot()
 	 * b) RB_HALT
 	 *	call cngetc
 	 * c) otherwise
 	 *	Reboot
 	 */
-	if (((howto & RB_POWERDOWN) == RB_POWERDOWN) && power_switch_is_off)
-		doboot();
-	else if (/*((howto & RB_POWERDOWN) == RB_POWERDOWN) ||*/
-		 ((howto & RB_HALT) == RB_HALT)) {
+	if (((howto & RB_POWERDOWN) == RB_POWERDOWN) && power_switch_is_off) {
+		doboot(RB_POWERDOWN);
+	} else if ((howto & RB_HALT) == RB_HALT) {
 		printf("System halted.  Hit any key to reboot.\n\n");
 		(void)cngetc();
 	}
 
 	printf("rebooting...\n");
 	DELAY(1000000);
-	doboot();
+	doboot(RB_AUTOBOOT);
 	/* NOTREACHED */
 }
 

---
Izumi Tsutsui