Re: Any success with Lenovo T60

"YAMAMOTO, Taku" <[email protected]>
Newsgroups gmane.os.freebsd.devel.mobile
Organization Trans New Technology, Inc.
Message-ID <[email protected]>
I'll attach the patch in a Triaez fashion :)
though I don't think this is the way to go.
# We need to implement suspend_cpus() for i386 and utilize it.


On Thu, 28 May 2009 19:22:39 +0900
Takanori Watanabe <[email protected]> wrote:

> In message <[email protected]>, "YAMAMOTO, Taku" 
> wrote:
> >On Thu, 28 May 2009 18:52:08 +0900
> >Takanori Watanabe <[email protected]> wrote:
> >
> >> In message <[email protected]>, "YAMAMOTO, Tak
> >u" 
> >> wrote:
> >> >Hi Vladimir,
> >> >
> >> >I have an X60 running 8.0-current/i386 as of Apr. 29, 2009
> >> >which can successfully suspend and resume, though things may be a bit
> >> >different from your case.
> >> >
> >> >There were a couple of pitfalls which I ran into:
> >> >
> >> > 0. Pristine kernels for i386 SMP don't support the resume yet.
> >> >    We can either use amd64 ones, stick on i386 UP kernels or apply
> >> >    unofficial patch floating around.
> >> >
> >> > 1. DO NOT DISABLE the built-in modem! (It took almost 2 weeks to identify!
> >)
> >> >    Disabling it ends up with hanging machine on resume.
> >> >
> >> > 2. Disable the USB while suspending; otherwise NMI parity error occurs
> >> >    on resume. (usb2 stack only; the old USB stack didn't have this problem
> >)
> >> >    In rc.suspend (the magic to turn the root hubs off):
> >> >	usbconfig -a 1 set_config 255
> >> >    In rc.resume (the magic to turn the root hubs on again):
> >> >	usbconfig -a 1 set_config 0
> >> >
> >> 
> >> Is the SMP/i386 patch applied cleanly? 
> >> Lazy author does not tried that since then.
> >
> >No, it requires slight modifications to apply, but that's it.
> >Would it be worth to have it available somewhere?
> 
> Yes, please. I want to review it.


-- 
-|-__   YAMAMOTO, Taku
 | __ <     <[email protected]>

      - A chicken is an egg's way of producing more eggs. -

_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-mobile
To unsubscribe, send any mail to "[email protected]"
takawata-mpresume-r189903.patch (text/x-diff, 8.7 KB)
Index: sys/i386/acpica/acpi_wakeup.c
===================================================================
RCS file: /home/ncvs/src/sys/i386/acpica/acpi_wakeup.c,v
retrieving revision 1.47
diff -u -r1.47 acpi_wakeup.c
--- sys/i386/acpica/acpi_wakeup.c	16 Mar 2008 10:58:03 -0000	1.47
+++ sys/i386/acpica/acpi_wakeup.c	13 May 2008 09:12:18 -0000
@@ -35,6 +35,8 @@ __FBSDID("$FreeBSD: src/sys/i386/acpica/
 #include <sys/lock.h>
 #include <sys/proc.h>
 #include <sys/sysctl.h>
+#include <sys/malloc.h> /* sys/memrange.h requires MALLOC_DECLARE XXX */
+#include <sys/memrange.h>
 
 #include <vm/vm.h>
 #include <vm/pmap.h>
@@ -49,6 +51,11 @@ __FBSDID("$FreeBSD: src/sys/i386/acpica/
 
 #include <contrib/dev/acpica/acpi.h>
 #include <dev/acpica/acpivar.h>
+#include <sys/smp.h>
+#include <machine/apicreg.h>
+#include <machine/apicvar.h>
+#include <machine/smp.h>
+#include <sys/sched.h>
 
 #include "acpi_wakecode.h"
 
@@ -71,6 +78,11 @@ static uint32_t __used	r_eax, r_ebx, r_ecx, r_
 static uint16_t __used	r_cs, r_ds, r_es, r_fs, r_gs, r_ss, r_tr;
 static uint32_t __used	r_esp;
 
+#ifdef SMP
+extern void *bootstacks[];
+static char *bootSTK;
+void restore_sub(void);
+#endif
 static void		acpi_printcpu(void);
 static void		acpi_realmodeinst(void *arg, bus_dma_segment_t *segs,
 					  int nsegs, int error);
@@ -80,6 +89,9 @@ static void		acpi_alloc_wakeup_handler(v
 /* XXX shut gcc up */
 extern int		acpi_savecpu(void);
 extern int		acpi_restorecpu(void);
+#ifdef SMP
+extern void		acpi_kicksub(void);
+#endif
 
 #ifdef __GNUCLIKE_ASM
 __asm__("				\n\
@@ -104,6 +114,18 @@ acpi_restorecpu:			\n\
 	movl	%eax,(%esp)		\n\
 	xorl	%eax,%eax		\n\
 	ret				\n\
+				\n"
+#ifdef SMP
+"	.text				\n\
+	.p2align 2, 0x90		\n\
+	.type acpi_kicksub, @function  \n\
+acpi_kicksub:			\n\
+	.align 4			\n\
+	movl	bootSTK,%esp		\n\
+	jmp     restore_sub		\n\
+	ret				\n"
+#endif	/* SMP */
+	"\
 					\n\
 	.text				\n\
 	.p2align 2, 0x90		\n\
@@ -150,6 +169,29 @@ acpi_savecpu:				\n\
 ");
 #endif /* __GNUCLIKE_ASM */
 
+#ifdef SMP
+int acpi_cpu_resumed[MAXCPU];
+int acpi_curcpu;
+extern int switch_debug;
+
+void restore_sub()
+{
+	ACPI_DISABLE_IRQS();
+	/*printf("RESTORE_SUB\n");*/
+	lapic_disable();	
+	pmap_init_pat();
+	/*printf("LAPIC_SETUP\n");*/
+	lapic_setup(0);	
+	if (bootverbose)
+		lapic_dump("RESTORE_SUB");
+	/*printf("RESTORE_SUB2\n");*/
+	ACPI_ENABLE_IRQS();
+
+	acpi_cpu_resumed[acpi_curcpu]= 1;
+	acpi_restorecpu();
+}
+#endif	/* SMP */
+
 static void
 acpi_printcpu(void)
 {
@@ -187,6 +234,120 @@ acpi_stop_beep(void *arg)
 	outb(0x61, inb(0x61) & ~0x3);
 }
 
+#ifdef SMP
+int resume_other_cpu(struct acpi_softc *sc, int cpu);
+int resume_other_cpu(struct acpi_softc *sc, int cpu)
+{
+	int ms;
+	int apic_id = cpu_apic_ids[cpu];
+	int gsel_tss;
+
+	gsel_tss = GSEL(GPROC0_SEL, SEL_KPL);
+	acpi_curcpu = cpu;
+	bootSTK= (char *)bootstacks[cpu] + KSTACK_PAGES * PAGE_SIZE - 4;
+	/*printf("%p\n", bootSTK);	*/
+	p_gdt = (struct region_descriptor *)
+		(sc->acpi_wakeaddr + physical_gdt);
+	saved_gdt.rd_limit = NGDT * sizeof(gdt[0]) -1;
+	saved_gdt.rd_base = (int )&gdt[cpu*NGDT];
+	p_gdt->rd_limit = saved_gdt.rd_limit;
+ 	p_gdt->rd_base = vtophys(saved_gdt.rd_base);
+	r_esp = stoppcbs[cpu].pcb_esp;
+	r_ebp = stoppcbs[cpu].pcb_ebp;
+	r_esi = stoppcbs[cpu].pcb_esi;
+	r_edi = stoppcbs[cpu].pcb_edi;
+	r_efl = stoppcbs[cpu].pcb_psl;
+	ret_addr = stoppcbs[cpu].pcb_eip;
+	WAKECODE_FIXUP(physical_esp, uint32_t, vtophys(bootSTK) );
+	WAKECODE_FIXUP(previous_cr0, uint32_t, r_cr0);
+	WAKECODE_FIXUP(previous_cr2, uint32_t, r_cr2);
+	WAKECODE_FIXUP(previous_cr3, uint32_t, r_cr3);
+	WAKECODE_FIXUP(previous_cr4, uint32_t, r_cr4);
+	
+	WAKECODE_FIXUP(resume_beep, uint32_t, 0);
+	WAKECODE_FIXUP(reset_video, uint32_t, 0);
+	
+	WAKECODE_FIXUP(previous_tr,  uint16_t, gsel_tss);
+	WAKECODE_BCOPY(previous_gdt, struct region_descriptor, saved_gdt);
+	WAKECODE_FIXUP(previous_ldt, uint16_t, saved_ldt);
+	WAKECODE_BCOPY(previous_idt, struct region_descriptor, saved_idt);
+	
+	WAKECODE_FIXUP(where_to_recover, void *, acpi_kicksub);
+	
+	WAKECODE_FIXUP(previous_ds,  uint16_t, r_ds);
+	WAKECODE_FIXUP(previous_es,  uint16_t, r_es);
+	WAKECODE_FIXUP(previous_fs,  uint16_t, r_fs);
+	WAKECODE_FIXUP(previous_gs,  uint16_t, 0);
+	WAKECODE_FIXUP(previous_ss,  uint16_t, r_ss);
+
+	/* do an INIT IPI: assert RESET */
+	lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
+	    APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_INIT, apic_id);
+
+	/* wait for pending status end */
+	lapic_ipi_wait(-1);
+
+	/* do an INIT IPI: deassert RESET */
+	lapic_ipi_raw(APIC_DEST_ALLESELF | APIC_TRIGMOD_LEVEL |
+	    APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_INIT, 0);
+
+	/* wait for pending status end */
+	DELAY(10000);		/* wait ~10mS */
+	lapic_ipi_wait(-1);
+	/*
+	 * next we do a STARTUP IPI: the previous INIT IPI might still be
+	 * latched, (P5 bug) this 1st STARTUP would then terminate
+	 * immediately, and the previously started INIT IPI would continue. OR
+	 * the previous INIT IPI has already run. and this STARTUP IPI will
+	 * run. OR the previous INIT IPI was ignored. and this STARTUP IPI
+	 * will run.
+	 */
+
+	/* do a STARTUP IPI */
+	lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
+	    APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
+		      ((sc->acpi_wakephys >>12)&0xff), apic_id);
+	lapic_ipi_wait(-1);
+	DELAY(200);		/* wait ~200uS */
+
+	/*
+	 * finally we do a 2nd STARTUP IPI: this 2nd STARTUP IPI should run IF
+	 * the previous STARTUP IPI was cancelled by a latched INIT IPI. OR
+	 * this STARTUP IPI will be ignored, as only ONE STARTUP IPI is
+	 * recognized after hardware RESET or INIT IPI.
+	 */
+
+	lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
+	    APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
+	    ((sc->acpi_wakephys >>12)&0xff), apic_id);
+	lapic_ipi_wait(-1);
+	DELAY(200);		/* wait ~200uS */
+
+	/* Wait up to 5 seconds for it to start. */
+	for (ms = 0; ms < 5000; ms++) {
+		if(acpi_cpu_resumed[cpu]){
+			acpi_cpu_resumed[cpu]= 0;
+			return 0;
+		}
+		DELAY(1000);
+	}
+	return -1;		/* return FAILURE */
+
+}
+int resume_other_cpus(struct acpi_softc *sc);
+int resume_other_cpus(struct acpi_softc *sc)
+{
+	int i;
+
+	*((volatile u_short *) 0x467) = 0;
+	*((volatile u_short *) 0x468) = (sc->acpi_wakephys&0xffff0)>>4;
+
+	for(i = 1; i < mp_ncpus; i++){
+		resume_other_cpu(sc, i);
+	}
+	return 0;
+}
+#endif	/* SMP */
 int
 acpi_sleep_machdep(struct acpi_softc *sc, int state)
 {
@@ -200,6 +360,9 @@ acpi_sleep_machdep(struct acpi_softc *sc
 	if (sc->acpi_wakeaddr == 0)
 		return (0);
 
+#ifdef SMP
+	stop_cpus(PCPU_GET(other_cpus));
+#endif
 	AcpiSetFirmwareWakingVector(sc->acpi_wakephys);
 
 	ef = read_eflags();
@@ -270,12 +436,22 @@ acpi_sleep_machdep(struct acpi_softc *sc
 		if (bootverbose) {
 			acpi_savecpu();
 			acpi_printcpu();
 		}
+		pmap_init_pat();
+#ifdef SMP
+		resume_other_cpus(sc);
+		if (bootverbose)
+			lapic_dump("MAIN");
+#endif
 	}
-
 out:
+#ifdef SMP
+	restart_cpus(stopped_cpus);
+#endif
 	load_cr3(cr3);
 	write_eflags(ef);
+	if (mem_range_softc.mr_op && mem_range_softc.mr_op->reinit)
+		mem_range_softc.mr_op->reinit(&mem_range_softc);
 
 	/* If we beeped, turn it off after a delay. */
 	if (acpi_resume_beep)
Index: sys/i386/i386/mp_machdep.c
===================================================================
RCS file: /home/ncvs/src/sys/i386/i386/mp_machdep.c,v
retrieving revision 1.286
diff -u -r1.286 mp_machdep.c
--- sys/i386/i386/mp_machdep.c	10 Apr 2008 18:38:31 -0000	1.286
+++ sys/i386/i386/mp_machdep.c	13 May 2008 07:08:29 -0000
@@ -1299,10 +1299,11 @@
 	int cpu = PCPU_GET(cpuid);
 	int cpumask = PCPU_GET(cpumask);
 
-	savectx(&stoppcbs[cpu]);
-
-	/* Indicate that we are stopped */
-	atomic_set_int(&stopped_cpus, cpumask);
+	if(savectx(&stoppcbs[cpu])){
+		/* Indicate that we are stopped */
+		wbinvd();
+		atomic_set_int(&stopped_cpus, cpumask);
+	}
 
 	/* Wait for restart */
 	while (!(started_cpus & cpumask))
Index: sys/i386/i386/swtch.s
===================================================================
RCS file: /home/ncvs/src/sys/i386/i386/swtch.s,v
retrieving revision 1.156
diff -u -r1.156 swtch.s
--- sys/i386/i386/swtch.s	22 Aug 2007 05:06:14 -0000	1.156
+++ sys/i386/i386/swtch.s	9 May 2008 15:16:03 -0000
@@ -413,6 +413,6 @@
 1:
 	popfl
 #endif	/* DEV_NPX */
-
+	movl  $1, %eax
 	ret
 END(savectx)
Index: sys/i386/include/pcb.h
===================================================================
RCS file: /home/ncvs/src/sys/i386/include/pcb.h,v
retrieving revision 1.56
diff -u -r1.56 pcb.h
--- sys/i386/include/pcb.h	29 Dec 2005 13:23:48 -0000	1.56
+++ sys/i386/include/pcb.h	24 Apr 2008 06:46:59 -0000
@@ -81,7 +81,7 @@
 struct trapframe;
 
 void	makectx(struct trapframe *, struct pcb *);
-void	savectx(struct pcb *);
+int	savectx(struct pcb *);
 #endif
 
 #endif /* _I386_PCB_H_ */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.