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

Reply via email to