While my Tecra S1 Pentium-M Centrino notebook is now able to enter S3
suspend-to-ram state, a power-on/resume has always resulted in a full
reboot, not the expected wakeup from S3-STR state.
There are apparently two problems in uts/i86pc/ml/cpr_wakecode.s:
1st Problem:
============
The 32-bit i386 code at label kernel_wc_code in
usr/src/uts/i86pc/ml/cpr_wakecode.s contains unconditional accesses to
amd specific MSRs - most likely this doesn't work on non-amd cpus:
movl $MSR_AMD_EFER, %ecx / re-enable NX bit
rdmsr
orl $AMD_EFER_NXE, %eax
wrmsr
This should be change to something like
diff -r 111aa1baa84a usr/src/uts/i86pc/ml/cpr_wakecode.s
--- a/usr/src/uts/i86pc/ml/cpr_wakecode.s Mon Oct 29 22:45:33 2007 -0700
+++ b/usr/src/uts/i86pc/ml/cpr_wakecode.s Thu Nov 01 20:37:40 2007 +0100
+
+ testl $X86_NX, x86_feature
+ jz 1f
movl $MSR_AMD_EFER, %ecx / re-enable NX bit
rdmsr
orl $AMD_EFER_NXE, %eax
wrmsr
+1:
2nd Problem:
============
The Tecra S1 is a uniprocessor PC and the BIOS doesn't
enable the APIC. On this system there is no function to enable the APIC:
# mdb -k
Loading modules: [ unix genunix specfssrn open OK
dtrace cpu.generic uppc scsi_vhci ufs ip hook neti sctp arp usba fctl nca zfs
random lofs audiosup cpc fcip nsctl ptm sppp ]
> ap_mlsetup::print
0
It seems cpr_wakecode.s just calls this NULL function pointer:
/*
* APIC initialization
*/
call *ap_mlsetup
Hmm, uppc.c defines psm_post_cpu_start as a NULL pointer in
struct psm_ops uppc_ops. This replaces the initialization
in usr/src/uts/i86pc/os/mp_machdep.c, which had set
int (*ap_mlsetup)() = (int (*)(void))return_instr;
Here we need something like the following fix:
@@ -1003,9 +1107,12 @@ kernel_wc_code:
movw WC_GS(%ebx), %gs
/*
- * APIC initialization
- */
+ * APIC initialization, skip this on UPPC machines without APIC
+ */
+ cmpl $0, ap_mlsetup
+ je 2f
call *ap_mlsetup
+2:
call *cpr_start_cpu_func
I'm currently using this set of cpr_wakecode.s changes; this includes
some changes to the SERIAL debug output code (where we need to
wait until the previous char is removed from the COM1 transmit register
before sending the next debug char, otherwise serial output is lost).
With these changes a resume from S3-STR starts to work on the Tecra S1,
but the resumed system stops with a "#df double fault" trap...
diff -r 111aa1baa84a usr/src/uts/i86pc/ml/cpr_wakecode.s
--- a/usr/src/uts/i86pc/ml/cpr_wakecode.s Mon Oct 29 22:45:33 2007 -0700
+++ b/usr/src/uts/i86pc/ml/cpr_wakecode.s Thu Nov 01 20:37:40 2007 +0100
@@ -844,15 +844,27 @@ wc_rm_end:
#define SERIAL 1
#if LED
- D16 movl $0x80, %edx
- D16 movb $0xd1, %al
- outb (%dx)
-#endif
-
-#if SERIAL
- D16 movl $0x3f8, %edx
- D16 movb $0x61, %al
- outb (%dx)
+ D16 movl $0x80, %edx
+ D16 movb $0xd1, %al
+ outb (%dx)
+#endif
+
+#if SERIAL
+ D16 movl $0x3fb, %edx / select com1 baud rate / ...
+ D16 movb $0x80, %al / ... divisor latch
+ outb (%dx)
+ D16 movl $0x3f8, %edx / baud rate = 115200 / divisor
+ D16 movb $0x0c, %al / set 9600 baud: divisor 0x0c
+ outb (%dx)
+ D16 movl $0x3f9, %edx
+ D16 movb $0x00, %al
+ outb (%dx)
+ D16 movl $0x3fb, %edx / select com1 transmit register
+ D16 movb $0x03, %al / ... and set com1 to "8n1"
+ outb (%dx)
+
+ D16 movb $0x61, %al / transmit 'a'
+ D16 call comout
#endif
@@ -867,9 +879,8 @@ wc_rm_end:
#endif
#if SERIAL
- D16 movl $0x3f8, %edx
D16 movb $0x62, %al
- outb (%dx)
+ D16 call comout
#endif
D16 A16 movl $WC_CPU, %ebx / base add of wc_cpu_t
@@ -880,48 +891,97 @@ wc_rm_end:
#endif
#if SERIAL
- D16 movl $0x3f8, %edx
D16 movb $0x63, %al
- outb (%dx)
+ D16 call comout
#endif
D16 A16 movl %cs:WC_DS(%ebx), %edx / %ds post prot/paging transit
+#if LED
D16 movb $0xd4, %al
outb $0x80
+#endif
+
+#if SERIAL
+ D16 movb $0x64, %al
+ D16 call comout
+#endif
D16 A16 lgdt %cs:WC_GDT(%ebx) / restore gdt and idtr
D16 A16 lidt %cs:WC_IDT(%ebx)
+#if LED
D16 movb $0xd5, %al
outb $0x80
+#endif
+
+#if SERIAL
+ D16 movb $0x65, %al
+ D16 call comout
+#endif
+
D16 A16 movl %cs:WC_CR4(%ebx), %eax / restore cr4
D16 andl $-1!CR4_PGE, %eax / don't set Global Enable yet
movl %eax, %cr4
+#if LED
D16 movb $0xd6, %al
outb $0x80
+#endif
+
+#if SERIAL
+ D16 movb $0x66, %al
+ D16 call comout
+#endif
D16 A16 movl %cs:WC_CR3(%ebx), %eax / set PDPT
movl %eax, %cr3
+#if LED
D16 movb $0xd7, %al
outb $0x80
+#endif
+
+#if SERIAL
+ D16 movb $0x67, %al
+ D16 call comout
+#endif
D16 A16 movl %cs:WC_CR0(%ebx), %eax / enable prot/paging, etc.
movl %eax, %cr0
+#if LED
D16 movb $0xd8, %al
outb $0x80
+#endif
+
+#if SERIAL
+ D16 movb $0x68, %al
+ D16 call comout
+#endif
D16 A16 movl %cs:WC_VIRTADDR(%ebx), %ebx / virtaddr of wc_cpu_t
+#if LED
D16 movb $0xd9, %al
outb $0x80
-
+#endif
+
+#if SERIAL
+ D16 movb $0x69, %al
+ D16 call comout
+#endif
+
+#if LED
D16 movb $0xda, %al
outb $0x80
+#endif
+
+#if SERIAL
+ D16 movb $0x6a, %al
+ D16 call comout
+#endif
jmp flush / flush prefetch queue
flush:
D16 pushl $KCS_SEL
@@ -954,6 +1014,19 @@ cominit:
int $0x14
D16 ret
+#if SERIAL
+comout:
+ pushl %edx
+ D16 movl $0x3f8, %edx
+ outb (%dx)
+ D16 movl $0x3f8+5, %edx
+1: inb (%dx)
+ testb $0x20, %al
+ jz 1b
+ popl %edx
+ D16 ret
+#endif
+
.globl wc_rm_end
wc_rm_end:
nop
@@ -967,19 +1040,50 @@ kernel_wc_code:
/ %ebx is wc_cpu
/ %dx is our ds
+#if LED
D16 movb $0xdb, %al
outb $0x80
+#endif
+
+#if SERIAL
+ movl %edx, %ecx
+ movw $0x3f8, %dx
+ movb $0x6b, %al
+ outb (%dx)
+ movw $0x3f8+5, %dx
+1: inb (%dx)
+ testb $0x20, %al
+ jz 1b
+ movl %ecx, %edx
+#endif
/ got here OK
movw %dx, %ds / $KDS_SEL
+#if LED
movb $0xdc, %al
outb $0x80
-
+#endif
+
+#if SERIAL
+ movl %edx, %ecx
+ movw $0x3f8, %dx
+ movb $0x6c, %al
+ outb (%dx)
+ movw $0x3f8+5, %dx
+1: inb (%dx)
+ testb $0x20, %al
+ jz 1b
+ movl %ecx, %edx
+#endif
+
+ testl $X86_NX, x86_feature
+ jz 1f
movl $MSR_AMD_EFER, %ecx / re-enable NX bit
rdmsr
orl $AMD_EFER_NXE, %eax
wrmsr
+1:
movl WC_CR4(%ebx), %eax / restore full cr4 (with Global Enable)
movl %eax, %cr4
@@ -1003,9 +1107,12 @@ kernel_wc_code:
movw WC_GS(%ebx), %gs
/*
- * APIC initialization
- */
+ * APIC initialization, skip this on UPPC machines without APIC
+ */
+ cmpl $0, ap_mlsetup
+ je 2f
call *ap_mlsetup
+2:
call *cpr_start_cpu_func
_______________________________________________
driver-discuss mailing list
[email protected]
http://mail.opensolaris.org/mailman/listinfo/driver-discuss