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>