Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 28 May 2009 20:18:44 +0900
From:      "YAMAMOTO, Taku" <taku@tackymt.homeip.net>
To:        Takanori Watanabe <takawata@init-main.com>
Cc:        acpi@freebsd.org, mobile@freebsd.org
Subject:   Re: Any success with Lenovo T60
Message-ID:  <20090528201844.7df2e164.taku@tackymt.homeip.net>
In-Reply-To: <200905281022.n4SAMdxr065296@sana.init-main.com>
References:  <20090528191311.b68ab3b7.taku@tackymt.homeip.net> <200905281022.n4SAMdxr065296@sana.init-main.com>

next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.

--Multipart=_Thu__28_May_2009_20_18_44_+0900_2JXH5XYx0UfrcBzn
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit

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 <takawata@init-main.com> wrote:

> In message <20090528191311.b68ab3b7.taku@tackymt.homeip.net>, "YAMAMOTO, Taku" 
> wrote:
> >On Thu, 28 May 2009 18:52:08 +0900
> >Takanori Watanabe <takawata@init-main.com> wrote:
> >
> >> In message <20090528184537.b2ac4798.taku@tackymt.homeip.net>, "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
 | __ <     <taku@tackymt.homeip.net>

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

--Multipart=_Thu__28_May_2009_20_18_44_+0900_2JXH5XYx0UfrcBzn
Content-Type: text/x-diff;
 name="takawata-mpresume-r189903.patch"
Content-Disposition: attachment;
 filename="takawata-mpresume-r189903.patch"
Content-Transfer-Encoding: 7bit

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_ */

--Multipart=_Thu__28_May_2009_20_18_44_+0900_2JXH5XYx0UfrcBzn--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20090528201844.7df2e164.taku>