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
[-- Attachment #1 --]
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. -
[-- Attachment #2 --]
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_ */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20090528201844.7df2e164.taku>
