* [PATCH] OLPC: Add XO-1 suspend/resume support
@ 2010-10-19 22:01 Daniel Drake
2010-10-19 22:06 ` Randy Dunlap
2010-10-19 22:11 ` H. Peter Anvin
0 siblings, 2 replies; 8+ messages in thread
From: Daniel Drake @ 2010-10-19 22:01 UTC (permalink / raw)
To: tglx, mingo, hpa, x86; +Cc: dilinger, linux-kernel
Add code needed for basic suspend/resume of the XO-1 laptop.
swsusp_pg_dir needs to be exposed as it is used by the assembly
code run in the wakeup path.
Signed-off-by: Daniel Drake <dsd@laptop.org>
---
arch/x86/include/asm/olpc.h | 5 +-
arch/x86/kernel/Makefile | 2 +-
arch/x86/kernel/olpc-xo1-wakeup.S | 132 +++++++++++++++++++++++++++++++++++++
arch/x86/kernel/olpc-xo1.c | 79 ++++++++++++++++++++++
arch/x86/mm/init_32.c | 6 +-
5 files changed, 219 insertions(+), 5 deletions(-)
create mode 100644 arch/x86/kernel/olpc-xo1-wakeup.S
diff --git a/arch/x86/include/asm/olpc.h b/arch/x86/include/asm/olpc.h
index 101229b..54dfe92 100644
--- a/arch/x86/include/asm/olpc.h
+++ b/arch/x86/include/asm/olpc.h
@@ -88,7 +88,10 @@ extern int olpc_ec_mask_unset(uint8_t bits);
/* EC commands */
-#define EC_FIRMWARE_REV 0x08
+#define EC_FIRMWARE_REV 0x08
+#define EC_WAKE_UP_WLAN 0x24
+#define EC_SET_SCI_INHIBIT 0x32
+#define EC_SET_SCI_INHIBIT_RELEASE 0x34
/* SCI source values */
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 4983b61..1b23334 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -106,7 +106,7 @@ obj-$(CONFIG_SCx200) += scx200.o
scx200-y += scx200_32.o
obj-$(CONFIG_OLPC) += olpc.o
-obj-$(CONFIG_OLPC_XO1) += olpc-xo1.o
+obj-$(CONFIG_OLPC_XO1) += olpc-xo1.o olpc-xo1-wakeup.o
obj-$(CONFIG_OLPC_OPENFIRMWARE) += olpc_ofw.o
obj-$(CONFIG_X86_MRST) += mrst.o
diff --git a/arch/x86/kernel/olpc-xo1-wakeup.S b/arch/x86/kernel/olpc-xo1-wakeup.S
new file mode 100644
index 0000000..d335074
--- /dev/null
+++ b/arch/x86/kernel/olpc-xo1-wakeup.S
@@ -0,0 +1,132 @@
+.text
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+
+ .macro writepost,value
+ movb $0x34, %al
+ outb %al, $0x70
+ movb $\value, %al
+ outb %al, $0x71
+ .endm
+
+ALIGN
+ .align 4096
+
+wakeup_start:
+# jmp wakeup_start
+
+ cli
+ cld
+
+ # Clear any dangerous flags
+
+ pushl $0
+ popfl
+
+ writepost 0x31
+
+ # Set up %cr3
+ movl $swsusp_pg_dir - __PAGE_OFFSET, %eax
+ movl %eax, %cr3
+
+ movl saved_cr4, %eax
+ movl %eax, %cr4
+
+ movl saved_cr0, %eax
+ movl %eax, %cr0
+
+ jmp 1f
+1:
+ ljmpl $__KERNEL_CS,$wakeup_return
+
+
+.org 0x1000
+
+wakeup_return:
+ movw $__KERNEL_DS, %ax
+ movw %ax, %ss
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+
+ lgdt saved_gdt
+ lidt saved_idt
+ lldt saved_ldt
+ ljmp $(__KERNEL_CS),$1f
+1:
+ movl %cr3, %eax
+ movl %eax, %cr3
+ wbinvd
+
+ # Go back to the return point
+ jmp ret_point
+
+save_registers:
+ sgdt saved_gdt
+ sidt saved_idt
+ sldt saved_ldt
+
+ pushl %edx
+ movl %cr4, %edx
+ movl %edx, saved_cr4
+
+ movl %cr0, %edx
+ movl %edx, saved_cr0
+
+ popl %edx
+
+ movl %ebx, saved_context_ebx
+ movl %ebp, saved_context_ebp
+ movl %esi, saved_context_esi
+ movl %edi, saved_context_edi
+
+ pushfl
+ popl saved_context_eflags
+
+ ret
+
+
+restore_registers:
+ movl saved_context_ebp, %ebp
+ movl saved_context_ebx, %ebx
+ movl saved_context_esi, %esi
+ movl saved_context_edi, %edi
+
+ pushl saved_context_eflags
+ popfl
+
+ ret
+
+
+ENTRY(do_olpc_suspend_lowlevel)
+ call save_processor_state
+ call save_registers
+
+ # This is the stack context we want to remember
+ movl %esp, saved_context_esp
+
+ pushl $3
+ call olpc_xo1_do_sleep
+
+ jmp wakeup_start
+ .p2align 4,,7
+ret_point:
+ movl saved_context_esp, %esp
+
+ writepost 0x32
+
+ call restore_registers
+ call restore_processor_state
+ ret
+
+.data
+ALIGN
+
+saved_gdt: .long 0,0
+saved_idt: .long 0,0
+saved_ldt: .long 0
+saved_cr4: .long 0
+saved_cr0: .long 0
+
diff --git a/arch/x86/kernel/olpc-xo1.c b/arch/x86/kernel/olpc-xo1.c
index f5442c0..9a06081 100644
--- a/arch/x86/kernel/olpc-xo1.c
+++ b/arch/x86/kernel/olpc-xo1.c
@@ -16,6 +16,7 @@
#include <linux/pci_ids.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
+#include <linux/suspend.h>
#include <asm/io.h>
#include <asm/olpc.h>
@@ -33,12 +34,83 @@
#define PM_SSC 0x54
/* PM registers (ACPI block) */
+#define PM1_STS 0x00
#define PM1_CNT 0x08
#define PM_GPE0_STS 0x18
+#define CS5536_PM_PWRBTN (1 << 8)
+
+extern void do_olpc_suspend_lowlevel(void);
+
static unsigned long acpi_base;
static unsigned long pms_base;
+static struct {
+ unsigned long address;
+ unsigned short segment;
+} ofw_bios_entry = { 0xF0000 + PAGE_OFFSET, __KERNEL_CS };
+
+static int xo1_power_state_enter(suspend_state_t pm_state)
+{
+ int r;
+
+ /* Only STR is supported */
+ if (pm_state != PM_SUSPEND_MEM)
+ return -EINVAL;
+
+ r = olpc_ec_cmd(EC_SET_SCI_INHIBIT, NULL, 0, NULL, 0);
+ if (r)
+ return r;
+
+ /* Save CPU state */
+ do_olpc_suspend_lowlevel();
+
+ /* Resume path starts here */
+
+ /* Tell the EC to stop inhibiting SCIs */
+ olpc_ec_cmd(EC_SET_SCI_INHIBIT_RELEASE, NULL, 0, NULL, 0);
+
+ /*
+ * Tell the wireless module to restart USB communication.
+ * Must be done twice.
+ */
+ olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0);
+ olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0);
+
+ return 0;
+}
+
+asmlinkage int olpc_xo1_do_sleep(u8 sleep_state)
+{
+ void *pgd_addr = __va(read_cr3());
+ printk(KERN_ERR "xo1_do_sleep!\n"); /* this needs to remain here so
+ * that gcc doesn't optimize
+ * away our __va! */
+
+ /* Enable wakeup through power button */
+ outl((CS5536_PM_PWRBTN << 16) | 0xFFFF, acpi_base + PM1_STS);
+
+ __asm__ __volatile__("movl %0,%%eax" : : "r" (pgd_addr));
+ __asm__("call *(%%edi); cld"
+ : : "D" (&ofw_bios_entry));
+ __asm__ __volatile__("movb $0x34, %al\n\t"
+ "outb %al, $0x70\n\t"
+ "movb $0x30, %al\n\t"
+ "outb %al, $0x71\n\t");
+ return 0;
+}
+
+static int xo1_power_state_valid(suspend_state_t pm_state)
+{
+ /* suspend-to-RAM only */
+ return pm_state == PM_SUSPEND_MEM;
+}
+
+static struct platform_suspend_ops xo1_suspend_ops = {
+ .valid = xo1_power_state_valid,
+ .enter = xo1_power_state_enter,
+};
+
static void xo1_power_off(void)
{
printk(KERN_INFO "OLPC XO-1 power off sequence...\n");
@@ -101,6 +173,13 @@ static int __devinit olpc_xo1_probe(struct platform_device *pdev)
if (r)
return r;
+ /*
+ * Take a reference on ourself to prevent module unloading. We can't
+ * safely unload after changing the suspend handlers.
+ */
+ __module_get(THIS_MODULE);
+
+ suspend_set_ops(&xo1_suspend_ops);
pm_power_off = xo1_power_off;
printk(KERN_INFO "OLPC XO-1 support registered\n");
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index 43bbc29..dbdab67 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -549,7 +549,7 @@ static void __init pagetable_init(void)
permanent_kmaps_init(pgd_base);
}
-#ifdef CONFIG_ACPI_SLEEP
+#if defined(CONFIG_ACPI_SLEEP) || defined(CONFIG_OLPC_XO1)
/*
* ACPI suspend needs this for resume, because things like the intel-agp
* driver might have split up a kernel 4MB mapping.
@@ -561,11 +561,11 @@ static inline void save_pg_dir(void)
{
copy_page(swsusp_pg_dir, swapper_pg_dir);
}
-#else /* !CONFIG_ACPI_SLEEP */
+#else /* !CONFIG_ACPI_SLEEP && !CONFIG_OLPC_XO1 */
static inline void save_pg_dir(void)
{
}
-#endif /* !CONFIG_ACPI_SLEEP */
+#endif /* !CONFIG_ACPI_SLEEP && !CONFIG_OLPC_XO1 */
void zap_low_mappings(bool early)
{
--
1.7.2.3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH] OLPC: Add XO-1 suspend/resume support
2010-10-19 22:01 [PATCH] OLPC: Add XO-1 suspend/resume support Daniel Drake
@ 2010-10-19 22:06 ` Randy Dunlap
2010-10-19 22:11 ` H. Peter Anvin
1 sibling, 0 replies; 8+ messages in thread
From: Randy Dunlap @ 2010-10-19 22:06 UTC (permalink / raw)
To: Daniel Drake; +Cc: tglx, mingo, hpa, x86, dilinger, linux-kernel
On Tue, 19 Oct 2010 23:01:58 +0100 (BST) Daniel Drake wrote:
> Add code needed for basic suspend/resume of the XO-1 laptop.
>
> swsusp_pg_dir needs to be exposed as it is used by the assembly
> code run in the wakeup path.
>
> Signed-off-by: Daniel Drake <dsd@laptop.org>
> ---
> arch/x86/include/asm/olpc.h | 5 +-
> arch/x86/kernel/Makefile | 2 +-
> arch/x86/kernel/olpc-xo1-wakeup.S | 132 +++++++++++++++++++++++++++++++++++++
> arch/x86/kernel/olpc-xo1.c | 79 ++++++++++++++++++++++
> arch/x86/mm/init_32.c | 6 +-
> 5 files changed, 219 insertions(+), 5 deletions(-)
> create mode 100644 arch/x86/kernel/olpc-xo1-wakeup.S
>
> diff --git a/arch/x86/include/asm/olpc.h b/arch/x86/include/asm/olpc.h
> index 101229b..54dfe92 100644
> --- a/arch/x86/include/asm/olpc.h
> +++ b/arch/x86/include/asm/olpc.h
> @@ -88,7 +88,10 @@ extern int olpc_ec_mask_unset(uint8_t bits);
>
> /* EC commands */
>
> -#define EC_FIRMWARE_REV 0x08
> +#define EC_FIRMWARE_REV 0x08
> +#define EC_WAKE_UP_WLAN 0x24
> +#define EC_SET_SCI_INHIBIT 0x32
> +#define EC_SET_SCI_INHIBIT_RELEASE 0x34
>
> /* SCI source values */
>
> diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
> index 4983b61..1b23334 100644
> --- a/arch/x86/kernel/Makefile
> +++ b/arch/x86/kernel/Makefile
> @@ -106,7 +106,7 @@ obj-$(CONFIG_SCx200) += scx200.o
> scx200-y += scx200_32.o
>
> obj-$(CONFIG_OLPC) += olpc.o
> -obj-$(CONFIG_OLPC_XO1) += olpc-xo1.o
> +obj-$(CONFIG_OLPC_XO1) += olpc-xo1.o olpc-xo1-wakeup.o
> obj-$(CONFIG_OLPC_OPENFIRMWARE) += olpc_ofw.o
> obj-$(CONFIG_X86_MRST) += mrst.o
>
Hi,
Does this build OK when CONFIG_PM is not enabled?
or is that config not possible?
> diff --git a/arch/x86/kernel/olpc-xo1-wakeup.S b/arch/x86/kernel/olpc-xo1-wakeup.S
> new file mode 100644
> index 0000000..d335074
> --- /dev/null
> +++ b/arch/x86/kernel/olpc-xo1-wakeup.S
> @@ -0,0 +1,132 @@
> +.text
> +#include <linux/linkage.h>
> +#include <asm/segment.h>
> +#include <asm/page.h>
> +
> + .macro writepost,value
> + movb $0x34, %al
> + outb %al, $0x70
> + movb $\value, %al
> + outb %al, $0x71
> + .endm
> +
> +ALIGN
> + .align 4096
> +
> +wakeup_start:
> +# jmp wakeup_start
> +
> + cli
> + cld
> +
> + # Clear any dangerous flags
> +
> + pushl $0
> + popfl
> +
> + writepost 0x31
> +
> + # Set up %cr3
> + movl $swsusp_pg_dir - __PAGE_OFFSET, %eax
> + movl %eax, %cr3
> +
> + movl saved_cr4, %eax
> + movl %eax, %cr4
> +
> + movl saved_cr0, %eax
> + movl %eax, %cr0
> +
> + jmp 1f
> +1:
> + ljmpl $__KERNEL_CS,$wakeup_return
> +
> +
> +.org 0x1000
> +
> +wakeup_return:
> + movw $__KERNEL_DS, %ax
> + movw %ax, %ss
> + movw %ax, %ds
> + movw %ax, %es
> + movw %ax, %fs
> + movw %ax, %gs
> +
> + lgdt saved_gdt
> + lidt saved_idt
> + lldt saved_ldt
> + ljmp $(__KERNEL_CS),$1f
> +1:
> + movl %cr3, %eax
> + movl %eax, %cr3
> + wbinvd
> +
> + # Go back to the return point
> + jmp ret_point
> +
> +save_registers:
> + sgdt saved_gdt
> + sidt saved_idt
> + sldt saved_ldt
> +
> + pushl %edx
> + movl %cr4, %edx
> + movl %edx, saved_cr4
> +
> + movl %cr0, %edx
> + movl %edx, saved_cr0
> +
> + popl %edx
> +
> + movl %ebx, saved_context_ebx
> + movl %ebp, saved_context_ebp
> + movl %esi, saved_context_esi
> + movl %edi, saved_context_edi
> +
> + pushfl
> + popl saved_context_eflags
> +
> + ret
> +
> +
> +restore_registers:
> + movl saved_context_ebp, %ebp
> + movl saved_context_ebx, %ebx
> + movl saved_context_esi, %esi
> + movl saved_context_edi, %edi
> +
> + pushl saved_context_eflags
> + popfl
> +
> + ret
> +
> +
> +ENTRY(do_olpc_suspend_lowlevel)
> + call save_processor_state
> + call save_registers
> +
> + # This is the stack context we want to remember
> + movl %esp, saved_context_esp
> +
> + pushl $3
> + call olpc_xo1_do_sleep
> +
> + jmp wakeup_start
> + .p2align 4,,7
> +ret_point:
> + movl saved_context_esp, %esp
> +
> + writepost 0x32
> +
> + call restore_registers
> + call restore_processor_state
> + ret
> +
> +.data
> +ALIGN
> +
> +saved_gdt: .long 0,0
> +saved_idt: .long 0,0
> +saved_ldt: .long 0
> +saved_cr4: .long 0
> +saved_cr0: .long 0
> +
> diff --git a/arch/x86/kernel/olpc-xo1.c b/arch/x86/kernel/olpc-xo1.c
> index f5442c0..9a06081 100644
> --- a/arch/x86/kernel/olpc-xo1.c
> +++ b/arch/x86/kernel/olpc-xo1.c
> @@ -16,6 +16,7 @@
> #include <linux/pci_ids.h>
> #include <linux/platform_device.h>
> #include <linux/pm.h>
> +#include <linux/suspend.h>
>
> #include <asm/io.h>
> #include <asm/olpc.h>
> @@ -33,12 +34,83 @@
> #define PM_SSC 0x54
>
> /* PM registers (ACPI block) */
> +#define PM1_STS 0x00
> #define PM1_CNT 0x08
> #define PM_GPE0_STS 0x18
>
> +#define CS5536_PM_PWRBTN (1 << 8)
> +
> +extern void do_olpc_suspend_lowlevel(void);
> +
> static unsigned long acpi_base;
> static unsigned long pms_base;
>
> +static struct {
> + unsigned long address;
> + unsigned short segment;
> +} ofw_bios_entry = { 0xF0000 + PAGE_OFFSET, __KERNEL_CS };
> +
> +static int xo1_power_state_enter(suspend_state_t pm_state)
> +{
> + int r;
> +
> + /* Only STR is supported */
> + if (pm_state != PM_SUSPEND_MEM)
> + return -EINVAL;
> +
> + r = olpc_ec_cmd(EC_SET_SCI_INHIBIT, NULL, 0, NULL, 0);
> + if (r)
> + return r;
> +
> + /* Save CPU state */
> + do_olpc_suspend_lowlevel();
> +
> + /* Resume path starts here */
> +
> + /* Tell the EC to stop inhibiting SCIs */
> + olpc_ec_cmd(EC_SET_SCI_INHIBIT_RELEASE, NULL, 0, NULL, 0);
> +
> + /*
> + * Tell the wireless module to restart USB communication.
> + * Must be done twice.
> + */
> + olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0);
> + olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0);
> +
> + return 0;
> +}
> +
> +asmlinkage int olpc_xo1_do_sleep(u8 sleep_state)
> +{
> + void *pgd_addr = __va(read_cr3());
> + printk(KERN_ERR "xo1_do_sleep!\n"); /* this needs to remain here so
> + * that gcc doesn't optimize
> + * away our __va! */
> +
> + /* Enable wakeup through power button */
> + outl((CS5536_PM_PWRBTN << 16) | 0xFFFF, acpi_base + PM1_STS);
> +
> + __asm__ __volatile__("movl %0,%%eax" : : "r" (pgd_addr));
> + __asm__("call *(%%edi); cld"
> + : : "D" (&ofw_bios_entry));
> + __asm__ __volatile__("movb $0x34, %al\n\t"
> + "outb %al, $0x70\n\t"
> + "movb $0x30, %al\n\t"
> + "outb %al, $0x71\n\t");
> + return 0;
> +}
> +
> +static int xo1_power_state_valid(suspend_state_t pm_state)
> +{
> + /* suspend-to-RAM only */
> + return pm_state == PM_SUSPEND_MEM;
> +}
> +
> +static struct platform_suspend_ops xo1_suspend_ops = {
> + .valid = xo1_power_state_valid,
> + .enter = xo1_power_state_enter,
> +};
> +
> static void xo1_power_off(void)
> {
> printk(KERN_INFO "OLPC XO-1 power off sequence...\n");
> @@ -101,6 +173,13 @@ static int __devinit olpc_xo1_probe(struct platform_device *pdev)
> if (r)
> return r;
>
> + /*
> + * Take a reference on ourself to prevent module unloading. We can't
> + * safely unload after changing the suspend handlers.
> + */
> + __module_get(THIS_MODULE);
> +
> + suspend_set_ops(&xo1_suspend_ops);
> pm_power_off = xo1_power_off;
>
> printk(KERN_INFO "OLPC XO-1 support registered\n");
> diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
> index 43bbc29..dbdab67 100644
> --- a/arch/x86/mm/init_32.c
> +++ b/arch/x86/mm/init_32.c
> @@ -549,7 +549,7 @@ static void __init pagetable_init(void)
> permanent_kmaps_init(pgd_base);
> }
>
> -#ifdef CONFIG_ACPI_SLEEP
> +#if defined(CONFIG_ACPI_SLEEP) || defined(CONFIG_OLPC_XO1)
> /*
> * ACPI suspend needs this for resume, because things like the intel-agp
> * driver might have split up a kernel 4MB mapping.
> @@ -561,11 +561,11 @@ static inline void save_pg_dir(void)
> {
> copy_page(swsusp_pg_dir, swapper_pg_dir);
> }
> -#else /* !CONFIG_ACPI_SLEEP */
> +#else /* !CONFIG_ACPI_SLEEP && !CONFIG_OLPC_XO1 */
> static inline void save_pg_dir(void)
> {
> }
> -#endif /* !CONFIG_ACPI_SLEEP */
> +#endif /* !CONFIG_ACPI_SLEEP && !CONFIG_OLPC_XO1 */
>
> void zap_low_mappings(bool early)
> {
> --
---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] OLPC: Add XO-1 suspend/resume support
2010-10-19 22:01 [PATCH] OLPC: Add XO-1 suspend/resume support Daniel Drake
2010-10-19 22:06 ` Randy Dunlap
@ 2010-10-19 22:11 ` H. Peter Anvin
2010-10-20 5:47 ` Borislav Petkov
1 sibling, 1 reply; 8+ messages in thread
From: H. Peter Anvin @ 2010-10-19 22:11 UTC (permalink / raw)
To: Daniel Drake
Cc: tglx, mingo, x86, dilinger, linux-kernel, Borislav Petkov, Roedel, Joerg
On 10/19/2010 03:01 PM, Daniel Drake wrote:
> Add code needed for basic suspend/resume of the XO-1 laptop.
>
> swsusp_pg_dir needs to be exposed as it is used by the assembly
> code run in the wakeup path.
>
Okay... this is Yet Another Reason why we need to unify all the bloody
trampoline page tables.
What it comes down to is that there are several users which need a 1:1
mapped pagetable and a chunk of memory < 1 MiB, and they should all be
combined and linked together, and share a single pagetable set that
sticks around.
Borislav has already been doing some of this work:
[PATCH] x86-32, mm: Add an initial page table for core bootstrapping
I thought that patch was already in -tip, but it looks like it's not...
Borislav/Joerg... was there a newer patch or did we just miss the final
version? I remember we talked about this at some length, but it looks
like I dropped the ball (I was on vacation when the above message was
posted.)
-hpa
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] OLPC: Add XO-1 suspend/resume support
2010-10-19 22:11 ` H. Peter Anvin
@ 2010-10-20 5:47 ` Borislav Petkov
2010-10-20 5:58 ` H. Peter Anvin
0 siblings, 1 reply; 8+ messages in thread
From: Borislav Petkov @ 2010-10-20 5:47 UTC (permalink / raw)
To: H. Peter Anvin
Cc: Daniel Drake, tglx, mingo, x86, dilinger, linux-kernel,
Borislav Petkov, Roedel, Joerg
From: "H. Peter Anvin" <hpa@zytor.com>
Date: Tue, Oct 19, 2010 at 06:11:13PM -0400
> On 10/19/2010 03:01 PM, Daniel Drake wrote:
> > Add code needed for basic suspend/resume of the XO-1 laptop.
> >
> > swsusp_pg_dir needs to be exposed as it is used by the assembly
> > code run in the wakeup path.
> >
>
> Okay... this is Yet Another Reason why we need to unify all the bloody
> trampoline page tables.
>
> What it comes down to is that there are several users which need a 1:1
> mapped pagetable and a chunk of memory < 1 MiB, and they should all be
> combined and linked together, and share a single pagetable set that
> sticks around.
>
> Borislav has already been doing some of this work:
>
> [PATCH] x86-32, mm: Add an initial page table for core bootstrapping
>
> I thought that patch was already in -tip, but it looks like it's not...
> Borislav/Joerg... was there a newer patch or did we just miss the final
> version? I remember we talked about this at some length, but it looks
> like I dropped the ball (I was on vacation when the above message was
> posted.)
The final version with fixed ACPI sleep is this one:
http://www.gossamer-threads.com/lists/linux/kernel/1270589
I ran it for a couple of weeks and it didn't show any regressions. If
you want to get it into the merge window, I can get you an updated
version against a -tip branch of your liking ASAP.
--
Regards/Gruss,
Boris.
Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
General Managers: Alberto Bozzo, Andrew Bowd
Registration: Dornach, Gemeinde Aschheim, Landkreis Muenchen
Registergericht Muenchen, HRB Nr. 43632
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] OLPC: Add XO-1 suspend/resume support
2010-10-20 5:47 ` Borislav Petkov
@ 2010-10-20 5:58 ` H. Peter Anvin
2010-10-20 7:05 ` [PATCH -tip/master] x86-32, mm: Add an initial page table for core bootstrapping Borislav Petkov
0 siblings, 1 reply; 8+ messages in thread
From: H. Peter Anvin @ 2010-10-20 5:58 UTC (permalink / raw)
To: Borislav Petkov
Cc: Daniel Drake, tglx, mingo, x86, dilinger, linux-kernel, Roedel, Joerg
On 10/19/2010 10:47 PM, Borislav Petkov wrote:
>
> The final version with fixed ACPI sleep is this one:
> http://www.gossamer-threads.com/lists/linux/kernel/1270589
>
> I ran it for a couple of weeks and it didn't show any regressions. If
> you want to get it into the merge window, I can get you an updated
> version against a -tip branch of your liking ASAP.
>
If you could prep something against tip:master we *might* be able to get
it in... not sure yet (and it partly depends on when Linus decides to
push the button, of course.)
-hpa
--
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel. I don't speak on their behalf.
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH -tip/master] x86-32, mm: Add an initial page table for core bootstrapping
2010-10-20 5:58 ` H. Peter Anvin
@ 2010-10-20 7:05 ` Borislav Petkov
2010-10-20 21:28 ` [tip:x86/trampoline] " tip-bot for Borislav Petkov
0 siblings, 1 reply; 8+ messages in thread
From: Borislav Petkov @ 2010-10-20 7:05 UTC (permalink / raw)
To: H. Peter Anvin
Cc: Borislav Petkov, Daniel Drake, tglx, mingo, x86, dilinger,
linux-kernel, Roedel, Joerg
From: "H. Peter Anvin" <hpa@zytor.com>
Date: Tue, Oct 19, 2010 at 10:58:30PM -0700
> If you could prep something against tip:master we *might* be able to get
> it in... not sure yet (and it partly depends on when Linus decides to
> push the button, of course.)
Here you go, suspend-to-{ram,disk} works, will run it in the next couple
of days just in case.
--
From: Borislav Petkov <bp@alien8.de>
Date: Sat, 28 Aug 2010 15:58:33 +0200
Subject: [PATCH -tip/master] x86-32, mm: Add an initial page table for core bootstrapping
This patch adds an initial page table with low mappings used exclusively
for booting APs/resuming after ACPI suspend/machine restart. After this,
there's no need to add low mappings to swapper_pg_dir and zap them later
or create own swsusp PGD page solely for ACPI sleep needs - we have
initial_page_table for that.
[ v1.1 Fix suspend-to-ram ]
Signed-off-by: Borislav Petkov <bp@alien8.de>
---
arch/x86/include/asm/pgtable_32.h | 2 +-
arch/x86/include/asm/tlbflush.h | 2 -
arch/x86/include/asm/trampoline.h | 3 --
arch/x86/kernel/acpi/sleep.c | 7 ++++-
arch/x86/kernel/head32.c | 1 +
arch/x86/kernel/head_32.S | 55 +++++++++++++++++--------------------
arch/x86/kernel/reboot.c | 10 +-----
arch/x86/kernel/setup.c | 18 +++++++++++-
arch/x86/kernel/smpboot.c | 16 +++--------
arch/x86/kernel/trampoline.c | 16 -----------
arch/x86/mm/init_32.c | 45 ------------------------------
11 files changed, 56 insertions(+), 119 deletions(-)
diff --git a/arch/x86/include/asm/pgtable_32.h b/arch/x86/include/asm/pgtable_32.h
index f686f49..8abde9e 100644
--- a/arch/x86/include/asm/pgtable_32.h
+++ b/arch/x86/include/asm/pgtable_32.h
@@ -26,7 +26,7 @@ struct mm_struct;
struct vm_area_struct;
extern pgd_t swapper_pg_dir[1024];
-extern pgd_t trampoline_pg_dir[1024];
+extern pgd_t initial_page_table[1024];
static inline void pgtable_cache_init(void) { }
static inline void check_pgt_cache(void) { }
diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h
index 7f3eba0..169be89 100644
--- a/arch/x86/include/asm/tlbflush.h
+++ b/arch/x86/include/asm/tlbflush.h
@@ -172,6 +172,4 @@ static inline void flush_tlb_kernel_range(unsigned long start,
flush_tlb_all();
}
-extern void zap_low_mappings(bool early);
-
#endif /* _ASM_X86_TLBFLUSH_H */
diff --git a/arch/x86/include/asm/trampoline.h b/arch/x86/include/asm/trampoline.h
index 4dde797..f4500fb 100644
--- a/arch/x86/include/asm/trampoline.h
+++ b/arch/x86/include/asm/trampoline.h
@@ -13,16 +13,13 @@ extern unsigned char *trampoline_base;
extern unsigned long init_rsp;
extern unsigned long initial_code;
-extern unsigned long initial_page_table;
extern unsigned long initial_gs;
#define TRAMPOLINE_SIZE roundup(trampoline_end - trampoline_data, PAGE_SIZE)
extern unsigned long setup_trampoline(void);
-extern void __init setup_trampoline_page_table(void);
extern void __init reserve_trampoline_memory(void);
#else
-static inline void setup_trampoline_page_table(void) {}
static inline void reserve_trampoline_memory(void) {}
#endif /* CONFIG_X86_TRAMPOLINE */
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index e125207..74a8478 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -13,6 +13,11 @@
#include <asm/segment.h>
#include <asm/desc.h>
+#ifdef CONFIG_X86_32
+#include <asm/pgtable.h>
+#include <asm/pgtable_32.h>
+#endif
+
#include "realmode/wakeup.h"
#include "sleep.h"
@@ -91,7 +96,7 @@ int acpi_save_state_mem(void)
#ifndef CONFIG_64BIT
header->pmode_entry = (u32)&wakeup_pmode_return;
- header->pmode_cr3 = (u32)(swsusp_pg_dir - __PAGE_OFFSET);
+ header->pmode_cr3 = (u32)__pa(&initial_page_table);
saved_magic = 0x12345678;
#else /* CONFIG_64BIT */
header->trampoline_segment = setup_trampoline() >> 4;
diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c
index 9a6ca23..7633101 100644
--- a/arch/x86/kernel/head32.c
+++ b/arch/x86/kernel/head32.c
@@ -18,6 +18,7 @@
#include <asm/apic.h>
#include <asm/io_apic.h>
#include <asm/bios_ebda.h>
+#include <asm/tlbflush.h>
static void __init i386_default_early_setup(void)
{
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index fa8c1b8..bcece91 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -183,13 +183,12 @@ default_entry:
#ifdef CONFIG_X86_PAE
/*
- * In PAE mode swapper_pg_dir is statically defined to contain enough
- * entries to cover the VMSPLIT option (that is the top 1, 2 or 3
- * entries). The identity mapping is handled by pointing two PGD
- * entries to the first kernel PMD.
+ * In PAE mode initial_page_table is statically defined to contain
+ * enough entries to cover the VMSPLIT option (that is the top 1, 2 or 3
+ * entries). The identity mapping is handled by pointing two PGD entries
+ * to the first kernel PMD.
*
- * Note the upper half of each PMD or PTE are always zero at
- * this stage.
+ * Note the upper half of each PMD or PTE are always zero at this stage.
*/
#define KPMDS (((-__PAGE_OFFSET) >> 30) & 3) /* Number of kernel PMDs */
@@ -197,7 +196,7 @@ default_entry:
xorl %ebx,%ebx /* %ebx is kept at zero */
movl $pa(__brk_base), %edi
- movl $pa(swapper_pg_pmd), %edx
+ movl $pa(initial_pg_pmd), %edx
movl $PTE_IDENT_ATTR, %eax
10:
leal PDE_IDENT_ATTR(%edi),%ecx /* Create PMD entry */
@@ -226,14 +225,14 @@ default_entry:
movl %eax, pa(max_pfn_mapped)
/* Do early initialization of the fixmap area */
- movl $pa(swapper_pg_fixmap)+PDE_IDENT_ATTR,%eax
- movl %eax,pa(swapper_pg_pmd+0x1000*KPMDS-8)
+ movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,%eax
+ movl %eax,pa(initial_pg_pmd+0x1000*KPMDS-8)
#else /* Not PAE */
page_pde_offset = (__PAGE_OFFSET >> 20);
movl $pa(__brk_base), %edi
- movl $pa(swapper_pg_dir), %edx
+ movl $pa(initial_page_table), %edx
movl $PTE_IDENT_ATTR, %eax
10:
leal PDE_IDENT_ATTR(%edi),%ecx /* Create PDE entry */
@@ -257,8 +256,8 @@ page_pde_offset = (__PAGE_OFFSET >> 20);
movl %eax, pa(max_pfn_mapped)
/* Do early initialization of the fixmap area */
- movl $pa(swapper_pg_fixmap)+PDE_IDENT_ATTR,%eax
- movl %eax,pa(swapper_pg_dir+0xffc)
+ movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,%eax
+ movl %eax,pa(initial_page_table+0xffc)
#endif
jmp 3f
/*
@@ -334,7 +333,7 @@ ENTRY(startup_32_smp)
/*
* Enable paging
*/
- movl pa(initial_page_table), %eax
+ movl $pa(initial_page_table), %eax
movl %eax,%cr3 /* set the page table pointer.. */
movl %cr0,%eax
orl $X86_CR0_PG,%eax
@@ -614,8 +613,6 @@ ignore_int:
.align 4
ENTRY(initial_code)
.long i386_start_kernel
-ENTRY(initial_page_table)
- .long pa(swapper_pg_dir)
/*
* BSS section
@@ -623,20 +620,18 @@ ENTRY(initial_page_table)
__PAGE_ALIGNED_BSS
.align PAGE_SIZE_asm
#ifdef CONFIG_X86_PAE
-swapper_pg_pmd:
+initial_pg_pmd:
.fill 1024*KPMDS,4,0
#else
-ENTRY(swapper_pg_dir)
+ENTRY(initial_page_table)
.fill 1024,4,0
#endif
-swapper_pg_fixmap:
+initial_pg_fixmap:
.fill 1024,4,0
-#ifdef CONFIG_X86_TRAMPOLINE
-ENTRY(trampoline_pg_dir)
- .fill 1024,4,0
-#endif
ENTRY(empty_zero_page)
.fill 4096,1,0
+ENTRY(swapper_pg_dir)
+ .fill 1024,4,0
/*
* This starts the data section.
@@ -645,20 +640,20 @@ ENTRY(empty_zero_page)
__PAGE_ALIGNED_DATA
/* Page-aligned for the benefit of paravirt? */
.align PAGE_SIZE_asm
-ENTRY(swapper_pg_dir)
- .long pa(swapper_pg_pmd+PGD_IDENT_ATTR),0 /* low identity map */
+ENTRY(initial_page_table)
+ .long pa(initial_pg_pmd+PGD_IDENT_ATTR),0 /* low identity map */
# if KPMDS == 3
- .long pa(swapper_pg_pmd+PGD_IDENT_ATTR),0
- .long pa(swapper_pg_pmd+PGD_IDENT_ATTR+0x1000),0
- .long pa(swapper_pg_pmd+PGD_IDENT_ATTR+0x2000),0
+ .long pa(initial_pg_pmd+PGD_IDENT_ATTR),0
+ .long pa(initial_pg_pmd+PGD_IDENT_ATTR+0x1000),0
+ .long pa(initial_pg_pmd+PGD_IDENT_ATTR+0x2000),0
# elif KPMDS == 2
.long 0,0
- .long pa(swapper_pg_pmd+PGD_IDENT_ATTR),0
- .long pa(swapper_pg_pmd+PGD_IDENT_ATTR+0x1000),0
+ .long pa(initial_pg_pmd+PGD_IDENT_ATTR),0
+ .long pa(initial_pg_pmd+PGD_IDENT_ATTR+0x1000),0
# elif KPMDS == 1
.long 0,0
.long 0,0
- .long pa(swapper_pg_pmd+PGD_IDENT_ATTR),0
+ .long pa(initial_pg_pmd+PGD_IDENT_ATTR),0
# else
# error "Kernel PMDs should be 1, 2 or 3"
# endif
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 7a4cf14..f7f53dc 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -371,16 +371,10 @@ void machine_real_restart(const unsigned char *code, int length)
CMOS_WRITE(0x00, 0x8f);
spin_unlock(&rtc_lock);
- /* Remap the kernel at virtual address zero, as well as offset zero
- from the kernel segment. This assumes the kernel segment starts at
- virtual address PAGE_OFFSET. */
- memcpy(swapper_pg_dir, swapper_pg_dir + KERNEL_PGD_BOUNDARY,
- sizeof(swapper_pg_dir [0]) * KERNEL_PGD_PTRS);
-
/*
- * Use `swapper_pg_dir' as our page directory.
+ * Switch back to the initial page table.
*/
- load_cr3(swapper_pg_dir);
+ load_cr3(initial_page_table);
/* Write 0x1234 to absolute memory location 0x472. The BIOS reads
this on booting to tell it to "Bypass memory test (also warm
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 44e208e..3df995f 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -700,6 +700,17 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_X86_32
memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));
visws_early_detect();
+
+ /*
+ * copy kernel address range established so far and switch
+ * to the proper swapper page table
+ */
+ clone_pgd_range(swapper_pg_dir + KERNEL_PGD_BOUNDARY,
+ initial_page_table + KERNEL_PGD_BOUNDARY,
+ KERNEL_PGD_PTRS);
+
+ load_cr3(swapper_pg_dir);
+ __flush_tlb_all();
#else
printk(KERN_INFO "Command line: %s\n", boot_command_line);
#endif
@@ -985,7 +996,12 @@ void __init setup_arch(char **cmdline_p)
paging_init();
x86_init.paging.pagetable_setup_done(swapper_pg_dir);
- setup_trampoline_page_table();
+#ifdef CONFIG_X86_32
+ /* sync back kernel address range */
+ clone_pgd_range(initial_page_table + KERNEL_PGD_BOUNDARY,
+ swapper_pg_dir + KERNEL_PGD_BOUNDARY,
+ KERNEL_PGD_PTRS);
+#endif
tboot_probe();
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index dfb5089..6af1185 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -299,22 +299,16 @@ notrace static void __cpuinit start_secondary(void *unused)
* fragile that we want to limit the things done here to the
* most necessary things.
*/
+ cpu_init();
+ preempt_disable();
+ smp_callin();
#ifdef CONFIG_X86_32
- /*
- * Switch away from the trampoline page-table
- *
- * Do this before cpu_init() because it needs to access per-cpu
- * data which may not be mapped in the trampoline page-table.
- */
+ /* switch away from the initial page table */
load_cr3(swapper_pg_dir);
__flush_tlb_all();
#endif
- cpu_init();
- preempt_disable();
- smp_callin();
-
/* otherwise gcc will move up smp_processor_id before the cpu_init */
barrier();
/*
@@ -785,7 +779,6 @@ do_rest:
#ifdef CONFIG_X86_32
/* Stack for startup_32 can be just as for start_secondary onwards */
irq_ctx_init(cpu);
- initial_page_table = __pa(&trampoline_pg_dir);
#else
clear_tsk_thread_flag(c_idle.idle, TIF_FORK);
initial_gs = per_cpu_offset(cpu);
@@ -934,7 +927,6 @@ int __cpuinit native_cpu_up(unsigned int cpu)
per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
err = do_boot_cpu(apicid, cpu);
-
if (err) {
pr_debug("do_boot_cpu failed %d\n", err);
return -EIO;
diff --git a/arch/x86/kernel/trampoline.c b/arch/x86/kernel/trampoline.c
index 4c3da56..a375616 100644
--- a/arch/x86/kernel/trampoline.c
+++ b/arch/x86/kernel/trampoline.c
@@ -38,19 +38,3 @@ unsigned long __trampinit setup_trampoline(void)
memcpy(trampoline_base, trampoline_data, TRAMPOLINE_SIZE);
return virt_to_phys(trampoline_base);
}
-
-void __init setup_trampoline_page_table(void)
-{
-#ifdef CONFIG_X86_32
- /* Copy kernel address range */
- clone_pgd_range(trampoline_pg_dir + KERNEL_PGD_BOUNDARY,
- swapper_pg_dir + KERNEL_PGD_BOUNDARY,
- KERNEL_PGD_PTRS);
-
- /* Initialize low mappings */
- clone_pgd_range(trampoline_pg_dir,
- swapper_pg_dir + KERNEL_PGD_BOUNDARY,
- min_t(unsigned long, KERNEL_PGD_PTRS,
- KERNEL_PGD_BOUNDARY));
-#endif
-}
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index 5d0a671..0e969f9 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -528,48 +528,6 @@ static void __init pagetable_init(void)
permanent_kmaps_init(pgd_base);
}
-#ifdef CONFIG_ACPI_SLEEP
-/*
- * ACPI suspend needs this for resume, because things like the intel-agp
- * driver might have split up a kernel 4MB mapping.
- */
-char swsusp_pg_dir[PAGE_SIZE]
- __attribute__ ((aligned(PAGE_SIZE)));
-
-static inline void save_pg_dir(void)
-{
- copy_page(swsusp_pg_dir, swapper_pg_dir);
-}
-#else /* !CONFIG_ACPI_SLEEP */
-static inline void save_pg_dir(void)
-{
-}
-#endif /* !CONFIG_ACPI_SLEEP */
-
-void zap_low_mappings(bool early)
-{
- int i;
-
- /*
- * Zap initial low-memory mappings.
- *
- * Note that "pgd_clear()" doesn't do it for
- * us, because pgd_clear() is a no-op on i386.
- */
- for (i = 0; i < KERNEL_PGD_BOUNDARY; i++) {
-#ifdef CONFIG_X86_PAE
- set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page)));
-#else
- set_pgd(swapper_pg_dir+i, __pgd(0));
-#endif
- }
-
- if (early)
- __flush_tlb();
- else
- flush_tlb_all();
-}
-
pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL | _PAGE_IOMAP);
EXPORT_SYMBOL_GPL(__supported_pte_mask);
@@ -882,9 +840,6 @@ void __init mem_init(void)
if (boot_cpu_data.wp_works_ok < 0)
test_wp_bit();
-
- save_pg_dir();
- zap_low_mappings(true);
}
#ifdef CONFIG_MEMORY_HOTPLUG
--
1.7.2.3
--
Regards/Gruss,
Boris.
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [tip:x86/trampoline] x86-32, mm: Add an initial page table for core bootstrapping
2010-10-20 7:05 ` [PATCH -tip/master] x86-32, mm: Add an initial page table for core bootstrapping Borislav Petkov
@ 2010-10-20 21:28 ` tip-bot for Borislav Petkov
0 siblings, 0 replies; 8+ messages in thread
From: tip-bot for Borislav Petkov @ 2010-10-20 21:28 UTC (permalink / raw)
To: linux-tip-commits; +Cc: linux-kernel, hpa, mingo, tglx, hpa, bp
Commit-ID: b40827fa7268fda8a62490728a61c2856f33830b
Gitweb: http://git.kernel.org/tip/b40827fa7268fda8a62490728a61c2856f33830b
Author: Borislav Petkov <bp@alien8.de>
AuthorDate: Sat, 28 Aug 2010 15:58:33 +0200
Committer: H. Peter Anvin <hpa@linux.intel.com>
CommitDate: Wed, 20 Oct 2010 14:23:55 -0700
x86-32, mm: Add an initial page table for core bootstrapping
This patch adds an initial page table with low mappings used exclusively
for booting APs/resuming after ACPI suspend/machine restart. After this,
there's no need to add low mappings to swapper_pg_dir and zap them later
or create own swsusp PGD page solely for ACPI sleep needs - we have
initial_page_table for that.
Signed-off-by: Borislav Petkov <bp@alien8.de>
LKML-Reference: <20101020070526.GA9588@liondog.tnic>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
---
arch/x86/include/asm/pgtable_32.h | 2 +-
arch/x86/include/asm/tlbflush.h | 2 -
arch/x86/include/asm/trampoline.h | 3 --
arch/x86/kernel/acpi/sleep.c | 7 ++++-
arch/x86/kernel/head32.c | 1 +
arch/x86/kernel/head_32.S | 55 +++++++++++++++++--------------------
arch/x86/kernel/reboot.c | 10 +-----
arch/x86/kernel/setup.c | 18 +++++++++++-
arch/x86/kernel/smpboot.c | 16 +++--------
arch/x86/kernel/trampoline.c | 16 -----------
arch/x86/mm/init_32.c | 45 ------------------------------
11 files changed, 56 insertions(+), 119 deletions(-)
diff --git a/arch/x86/include/asm/pgtable_32.h b/arch/x86/include/asm/pgtable_32.h
index f686f49..8abde9e 100644
--- a/arch/x86/include/asm/pgtable_32.h
+++ b/arch/x86/include/asm/pgtable_32.h
@@ -26,7 +26,7 @@ struct mm_struct;
struct vm_area_struct;
extern pgd_t swapper_pg_dir[1024];
-extern pgd_t trampoline_pg_dir[1024];
+extern pgd_t initial_page_table[1024];
static inline void pgtable_cache_init(void) { }
static inline void check_pgt_cache(void) { }
diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h
index 7f3eba0..169be89 100644
--- a/arch/x86/include/asm/tlbflush.h
+++ b/arch/x86/include/asm/tlbflush.h
@@ -172,6 +172,4 @@ static inline void flush_tlb_kernel_range(unsigned long start,
flush_tlb_all();
}
-extern void zap_low_mappings(bool early);
-
#endif /* _ASM_X86_TLBFLUSH_H */
diff --git a/arch/x86/include/asm/trampoline.h b/arch/x86/include/asm/trampoline.h
index 4dde797..f4500fb 100644
--- a/arch/x86/include/asm/trampoline.h
+++ b/arch/x86/include/asm/trampoline.h
@@ -13,16 +13,13 @@ extern unsigned char *trampoline_base;
extern unsigned long init_rsp;
extern unsigned long initial_code;
-extern unsigned long initial_page_table;
extern unsigned long initial_gs;
#define TRAMPOLINE_SIZE roundup(trampoline_end - trampoline_data, PAGE_SIZE)
extern unsigned long setup_trampoline(void);
-extern void __init setup_trampoline_page_table(void);
extern void __init reserve_trampoline_memory(void);
#else
-static inline void setup_trampoline_page_table(void) {}
static inline void reserve_trampoline_memory(void) {}
#endif /* CONFIG_X86_TRAMPOLINE */
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index 33cec15..b35e1ab 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -12,6 +12,11 @@
#include <asm/segment.h>
#include <asm/desc.h>
+#ifdef CONFIG_X86_32
+#include <asm/pgtable.h>
+#include <asm/pgtable_32.h>
+#endif
+
#include "realmode/wakeup.h"
#include "sleep.h"
@@ -90,7 +95,7 @@ int acpi_save_state_mem(void)
#ifndef CONFIG_64BIT
header->pmode_entry = (u32)&wakeup_pmode_return;
- header->pmode_cr3 = (u32)(swsusp_pg_dir - __PAGE_OFFSET);
+ header->pmode_cr3 = (u32)__pa(&initial_page_table);
saved_magic = 0x12345678;
#else /* CONFIG_64BIT */
header->trampoline_segment = setup_trampoline() >> 4;
diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c
index 784360c..8b9c201 100644
--- a/arch/x86/kernel/head32.c
+++ b/arch/x86/kernel/head32.c
@@ -17,6 +17,7 @@
#include <asm/apic.h>
#include <asm/io_apic.h>
#include <asm/bios_ebda.h>
+#include <asm/tlbflush.h>
static void __init i386_default_early_setup(void)
{
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index fa8c1b8..bcece91 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -183,13 +183,12 @@ default_entry:
#ifdef CONFIG_X86_PAE
/*
- * In PAE mode swapper_pg_dir is statically defined to contain enough
- * entries to cover the VMSPLIT option (that is the top 1, 2 or 3
- * entries). The identity mapping is handled by pointing two PGD
- * entries to the first kernel PMD.
+ * In PAE mode initial_page_table is statically defined to contain
+ * enough entries to cover the VMSPLIT option (that is the top 1, 2 or 3
+ * entries). The identity mapping is handled by pointing two PGD entries
+ * to the first kernel PMD.
*
- * Note the upper half of each PMD or PTE are always zero at
- * this stage.
+ * Note the upper half of each PMD or PTE are always zero at this stage.
*/
#define KPMDS (((-__PAGE_OFFSET) >> 30) & 3) /* Number of kernel PMDs */
@@ -197,7 +196,7 @@ default_entry:
xorl %ebx,%ebx /* %ebx is kept at zero */
movl $pa(__brk_base), %edi
- movl $pa(swapper_pg_pmd), %edx
+ movl $pa(initial_pg_pmd), %edx
movl $PTE_IDENT_ATTR, %eax
10:
leal PDE_IDENT_ATTR(%edi),%ecx /* Create PMD entry */
@@ -226,14 +225,14 @@ default_entry:
movl %eax, pa(max_pfn_mapped)
/* Do early initialization of the fixmap area */
- movl $pa(swapper_pg_fixmap)+PDE_IDENT_ATTR,%eax
- movl %eax,pa(swapper_pg_pmd+0x1000*KPMDS-8)
+ movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,%eax
+ movl %eax,pa(initial_pg_pmd+0x1000*KPMDS-8)
#else /* Not PAE */
page_pde_offset = (__PAGE_OFFSET >> 20);
movl $pa(__brk_base), %edi
- movl $pa(swapper_pg_dir), %edx
+ movl $pa(initial_page_table), %edx
movl $PTE_IDENT_ATTR, %eax
10:
leal PDE_IDENT_ATTR(%edi),%ecx /* Create PDE entry */
@@ -257,8 +256,8 @@ page_pde_offset = (__PAGE_OFFSET >> 20);
movl %eax, pa(max_pfn_mapped)
/* Do early initialization of the fixmap area */
- movl $pa(swapper_pg_fixmap)+PDE_IDENT_ATTR,%eax
- movl %eax,pa(swapper_pg_dir+0xffc)
+ movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,%eax
+ movl %eax,pa(initial_page_table+0xffc)
#endif
jmp 3f
/*
@@ -334,7 +333,7 @@ ENTRY(startup_32_smp)
/*
* Enable paging
*/
- movl pa(initial_page_table), %eax
+ movl $pa(initial_page_table), %eax
movl %eax,%cr3 /* set the page table pointer.. */
movl %cr0,%eax
orl $X86_CR0_PG,%eax
@@ -614,8 +613,6 @@ ignore_int:
.align 4
ENTRY(initial_code)
.long i386_start_kernel
-ENTRY(initial_page_table)
- .long pa(swapper_pg_dir)
/*
* BSS section
@@ -623,20 +620,18 @@ ENTRY(initial_page_table)
__PAGE_ALIGNED_BSS
.align PAGE_SIZE_asm
#ifdef CONFIG_X86_PAE
-swapper_pg_pmd:
+initial_pg_pmd:
.fill 1024*KPMDS,4,0
#else
-ENTRY(swapper_pg_dir)
+ENTRY(initial_page_table)
.fill 1024,4,0
#endif
-swapper_pg_fixmap:
+initial_pg_fixmap:
.fill 1024,4,0
-#ifdef CONFIG_X86_TRAMPOLINE
-ENTRY(trampoline_pg_dir)
- .fill 1024,4,0
-#endif
ENTRY(empty_zero_page)
.fill 4096,1,0
+ENTRY(swapper_pg_dir)
+ .fill 1024,4,0
/*
* This starts the data section.
@@ -645,20 +640,20 @@ ENTRY(empty_zero_page)
__PAGE_ALIGNED_DATA
/* Page-aligned for the benefit of paravirt? */
.align PAGE_SIZE_asm
-ENTRY(swapper_pg_dir)
- .long pa(swapper_pg_pmd+PGD_IDENT_ATTR),0 /* low identity map */
+ENTRY(initial_page_table)
+ .long pa(initial_pg_pmd+PGD_IDENT_ATTR),0 /* low identity map */
# if KPMDS == 3
- .long pa(swapper_pg_pmd+PGD_IDENT_ATTR),0
- .long pa(swapper_pg_pmd+PGD_IDENT_ATTR+0x1000),0
- .long pa(swapper_pg_pmd+PGD_IDENT_ATTR+0x2000),0
+ .long pa(initial_pg_pmd+PGD_IDENT_ATTR),0
+ .long pa(initial_pg_pmd+PGD_IDENT_ATTR+0x1000),0
+ .long pa(initial_pg_pmd+PGD_IDENT_ATTR+0x2000),0
# elif KPMDS == 2
.long 0,0
- .long pa(swapper_pg_pmd+PGD_IDENT_ATTR),0
- .long pa(swapper_pg_pmd+PGD_IDENT_ATTR+0x1000),0
+ .long pa(initial_pg_pmd+PGD_IDENT_ATTR),0
+ .long pa(initial_pg_pmd+PGD_IDENT_ATTR+0x1000),0
# elif KPMDS == 1
.long 0,0
.long 0,0
- .long pa(swapper_pg_pmd+PGD_IDENT_ATTR),0
+ .long pa(initial_pg_pmd+PGD_IDENT_ATTR),0
# else
# error "Kernel PMDs should be 1, 2 or 3"
# endif
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 7a4cf14..f7f53dc 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -371,16 +371,10 @@ void machine_real_restart(const unsigned char *code, int length)
CMOS_WRITE(0x00, 0x8f);
spin_unlock(&rtc_lock);
- /* Remap the kernel at virtual address zero, as well as offset zero
- from the kernel segment. This assumes the kernel segment starts at
- virtual address PAGE_OFFSET. */
- memcpy(swapper_pg_dir, swapper_pg_dir + KERNEL_PGD_BOUNDARY,
- sizeof(swapper_pg_dir [0]) * KERNEL_PGD_PTRS);
-
/*
- * Use `swapper_pg_dir' as our page directory.
+ * Switch back to the initial page table.
*/
- load_cr3(swapper_pg_dir);
+ load_cr3(initial_page_table);
/* Write 0x1234 to absolute memory location 0x472. The BIOS reads
this on booting to tell it to "Bypass memory test (also warm
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 322b24f..af6cf2b 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -728,6 +728,17 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_X86_32
memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));
visws_early_detect();
+
+ /*
+ * copy kernel address range established so far and switch
+ * to the proper swapper page table
+ */
+ clone_pgd_range(swapper_pg_dir + KERNEL_PGD_BOUNDARY,
+ initial_page_table + KERNEL_PGD_BOUNDARY,
+ KERNEL_PGD_PTRS);
+
+ load_cr3(swapper_pg_dir);
+ __flush_tlb_all();
#else
printk(KERN_INFO "Command line: %s\n", boot_command_line);
#endif
@@ -1009,7 +1020,12 @@ void __init setup_arch(char **cmdline_p)
paging_init();
x86_init.paging.pagetable_setup_done(swapper_pg_dir);
- setup_trampoline_page_table();
+#ifdef CONFIG_X86_32
+ /* sync back kernel address range */
+ clone_pgd_range(initial_page_table + KERNEL_PGD_BOUNDARY,
+ swapper_pg_dir + KERNEL_PGD_BOUNDARY,
+ KERNEL_PGD_PTRS);
+#endif
tboot_probe();
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 63a1a55..e63bb51 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -298,22 +298,16 @@ notrace static void __cpuinit start_secondary(void *unused)
* fragile that we want to limit the things done here to the
* most necessary things.
*/
+ cpu_init();
+ preempt_disable();
+ smp_callin();
#ifdef CONFIG_X86_32
- /*
- * Switch away from the trampoline page-table
- *
- * Do this before cpu_init() because it needs to access per-cpu
- * data which may not be mapped in the trampoline page-table.
- */
+ /* switch away from the initial page table */
load_cr3(swapper_pg_dir);
__flush_tlb_all();
#endif
- cpu_init();
- preempt_disable();
- smp_callin();
-
/* otherwise gcc will move up smp_processor_id before the cpu_init */
barrier();
/*
@@ -772,7 +766,6 @@ do_rest:
#ifdef CONFIG_X86_32
/* Stack for startup_32 can be just as for start_secondary onwards */
irq_ctx_init(cpu);
- initial_page_table = __pa(&trampoline_pg_dir);
#else
clear_tsk_thread_flag(c_idle.idle, TIF_FORK);
initial_gs = per_cpu_offset(cpu);
@@ -921,7 +914,6 @@ int __cpuinit native_cpu_up(unsigned int cpu)
per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
err = do_boot_cpu(apicid, cpu);
-
if (err) {
pr_debug("do_boot_cpu failed %d\n", err);
return -EIO;
diff --git a/arch/x86/kernel/trampoline.c b/arch/x86/kernel/trampoline.c
index e2a5952..f1488a3 100644
--- a/arch/x86/kernel/trampoline.c
+++ b/arch/x86/kernel/trampoline.c
@@ -38,19 +38,3 @@ unsigned long __trampinit setup_trampoline(void)
memcpy(trampoline_base, trampoline_data, TRAMPOLINE_SIZE);
return virt_to_phys(trampoline_base);
}
-
-void __init setup_trampoline_page_table(void)
-{
-#ifdef CONFIG_X86_32
- /* Copy kernel address range */
- clone_pgd_range(trampoline_pg_dir + KERNEL_PGD_BOUNDARY,
- swapper_pg_dir + KERNEL_PGD_BOUNDARY,
- KERNEL_PGD_PTRS);
-
- /* Initialize low mappings */
- clone_pgd_range(trampoline_pg_dir,
- swapper_pg_dir + KERNEL_PGD_BOUNDARY,
- min_t(unsigned long, KERNEL_PGD_PTRS,
- KERNEL_PGD_BOUNDARY));
-#endif
-}
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index 558f2d3..1aeac2d 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -548,48 +548,6 @@ static void __init pagetable_init(void)
permanent_kmaps_init(pgd_base);
}
-#ifdef CONFIG_ACPI_SLEEP
-/*
- * ACPI suspend needs this for resume, because things like the intel-agp
- * driver might have split up a kernel 4MB mapping.
- */
-char swsusp_pg_dir[PAGE_SIZE]
- __attribute__ ((aligned(PAGE_SIZE)));
-
-static inline void save_pg_dir(void)
-{
- copy_page(swsusp_pg_dir, swapper_pg_dir);
-}
-#else /* !CONFIG_ACPI_SLEEP */
-static inline void save_pg_dir(void)
-{
-}
-#endif /* !CONFIG_ACPI_SLEEP */
-
-void zap_low_mappings(bool early)
-{
- int i;
-
- /*
- * Zap initial low-memory mappings.
- *
- * Note that "pgd_clear()" doesn't do it for
- * us, because pgd_clear() is a no-op on i386.
- */
- for (i = 0; i < KERNEL_PGD_BOUNDARY; i++) {
-#ifdef CONFIG_X86_PAE
- set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page)));
-#else
- set_pgd(swapper_pg_dir+i, __pgd(0));
-#endif
- }
-
- if (early)
- __flush_tlb();
- else
- flush_tlb_all();
-}
-
pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL | _PAGE_IOMAP);
EXPORT_SYMBOL_GPL(__supported_pte_mask);
@@ -958,9 +916,6 @@ void __init mem_init(void)
if (boot_cpu_data.wp_works_ok < 0)
test_wp_bit();
-
- save_pg_dir();
- zap_low_mappings(true);
}
#ifdef CONFIG_MEMORY_HOTPLUG
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH] OLPC: Add XO-1 suspend/resume support
@ 2010-11-11 15:02 Daniel Drake
0 siblings, 0 replies; 8+ messages in thread
From: Daniel Drake @ 2010-11-11 15:02 UTC (permalink / raw)
To: tglx, mingo, hpa, x86; +Cc: linux-kernel
Add code needed for basic suspend/resume of the XO-1 laptop.
Signed-off-by: Daniel Drake <dsd@laptop.org>
---
arch/x86/Kconfig | 2 +-
arch/x86/include/asm/olpc.h | 9 ++-
arch/x86/platform/olpc/Makefile | 2 +-
arch/x86/platform/olpc/olpc-xo1-wakeup.S | 132 ++++++++++++++++++++++++++++++
arch/x86/platform/olpc/olpc-xo1.c | 79 ++++++++++++++++++
5 files changed, 219 insertions(+), 5 deletions(-)
create mode 100644 arch/x86/platform/olpc/olpc-xo1-wakeup.S
v2: add dependency on CONFIG_PM_SLEEP (thanks Randy), avoid requirement
on hacking swsusp_pg_dir by switching to initial_page_table
v3: rebase to fix conflict in olpc.h with the now-merged XO-1 rfkill driver
Resending after 2 weeks of no feedback.
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index e832768..a27b0dc 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2041,7 +2041,7 @@ config OLPC
config OLPC_XO1
tristate "OLPC XO-1 support"
- depends on OLPC && PCI
+ depends on OLPC && PCI && PM_SLEEP
---help---
Add support for non-essential features of the OLPC XO-1 laptop.
diff --git a/arch/x86/include/asm/olpc.h b/arch/x86/include/asm/olpc.h
index 42a978c..5bf0805 100644
--- a/arch/x86/include/asm/olpc.h
+++ b/arch/x86/include/asm/olpc.h
@@ -88,9 +88,12 @@ extern int olpc_ec_mask_unset(uint8_t bits);
/* EC commands */
-#define EC_FIRMWARE_REV 0x08
-#define EC_WLAN_ENTER_RESET 0x35
-#define EC_WLAN_LEAVE_RESET 0x25
+#define EC_FIRMWARE_REV 0x08
+#define EC_WAKE_UP_WLAN 0x24
+#define EC_WLAN_LEAVE_RESET 0x25
+#define EC_SET_SCI_INHIBIT 0x32
+#define EC_SET_SCI_INHIBIT_RELEASE 0x34
+#define EC_WLAN_ENTER_RESET 0x35
/* SCI source values */
diff --git a/arch/x86/platform/olpc/Makefile b/arch/x86/platform/olpc/Makefile
index c31b8fc..a1e7f02 100644
--- a/arch/x86/platform/olpc/Makefile
+++ b/arch/x86/platform/olpc/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_OLPC) += olpc.o
-obj-$(CONFIG_OLPC_XO1) += olpc-xo1.o
+obj-$(CONFIG_OLPC_XO1) += olpc-xo1.o olpc-xo1-wakeup.o
obj-$(CONFIG_OLPC_OPENFIRMWARE) += olpc_ofw.o
diff --git a/arch/x86/platform/olpc/olpc-xo1-wakeup.S b/arch/x86/platform/olpc/olpc-xo1-wakeup.S
new file mode 100644
index 0000000..d36e5f4
--- /dev/null
+++ b/arch/x86/platform/olpc/olpc-xo1-wakeup.S
@@ -0,0 +1,132 @@
+.text
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable_32.h>
+
+ .macro writepost,value
+ movb $0x34, %al
+ outb %al, $0x70
+ movb $\value, %al
+ outb %al, $0x71
+ .endm
+
+ALIGN
+ .align 4096
+
+wakeup_start:
+# jmp wakeup_start
+
+ cli
+ cld
+
+ # Clear any dangerous flags
+
+ pushl $0
+ popfl
+
+ writepost 0x31
+
+ # Set up %cr3
+ movl $initial_page_table - __PAGE_OFFSET, %eax
+ movl %eax, %cr3
+
+ movl saved_cr4, %eax
+ movl %eax, %cr4
+
+ movl saved_cr0, %eax
+ movl %eax, %cr0
+
+ jmp 1f
+1:
+ ljmpl $__KERNEL_CS,$wakeup_return
+
+
+.org 0x1000
+
+wakeup_return:
+ movw $__KERNEL_DS, %ax
+ movw %ax, %ss
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+
+ lgdt saved_gdt
+ lidt saved_idt
+ lldt saved_ldt
+ ljmp $(__KERNEL_CS),$1f
+1:
+ movl %cr3, %eax
+ movl %eax, %cr3
+ wbinvd
+
+ # Go back to the return point
+ jmp ret_point
+
+save_registers:
+ sgdt saved_gdt
+ sidt saved_idt
+ sldt saved_ldt
+
+ pushl %edx
+ movl %cr4, %edx
+ movl %edx, saved_cr4
+
+ movl %cr0, %edx
+ movl %edx, saved_cr0
+
+ popl %edx
+
+ movl %ebx, saved_context_ebx
+ movl %ebp, saved_context_ebp
+ movl %esi, saved_context_esi
+ movl %edi, saved_context_edi
+
+ pushfl
+ popl saved_context_eflags
+
+ ret
+
+
+restore_registers:
+ movl saved_context_ebp, %ebp
+ movl saved_context_ebx, %ebx
+ movl saved_context_esi, %esi
+ movl saved_context_edi, %edi
+
+ pushl saved_context_eflags
+ popfl
+
+ ret
+
+
+ENTRY(do_olpc_suspend_lowlevel)
+ call save_processor_state
+ call save_registers
+
+ # This is the stack context we want to remember
+ movl %esp, saved_context_esp
+
+ pushl $3
+ call olpc_xo1_do_sleep
+
+ jmp wakeup_start
+ .p2align 4,,7
+ret_point:
+ movl saved_context_esp, %esp
+
+ writepost 0x32
+
+ call restore_registers
+ call restore_processor_state
+ ret
+
+.data
+ALIGN
+
+saved_gdt: .long 0,0
+saved_idt: .long 0,0
+saved_ldt: .long 0
+saved_cr4: .long 0
+saved_cr0: .long 0
diff --git a/arch/x86/platform/olpc/olpc-xo1.c b/arch/x86/platform/olpc/olpc-xo1.c
index f5442c0..9a06081 100644
--- a/arch/x86/platform/olpc/olpc-xo1.c
+++ b/arch/x86/platform/olpc/olpc-xo1.c
@@ -16,6 +16,7 @@
#include <linux/pci_ids.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
+#include <linux/suspend.h>
#include <asm/io.h>
#include <asm/olpc.h>
@@ -33,12 +34,83 @@
#define PM_SSC 0x54
/* PM registers (ACPI block) */
+#define PM1_STS 0x00
#define PM1_CNT 0x08
#define PM_GPE0_STS 0x18
+#define CS5536_PM_PWRBTN (1 << 8)
+
+extern void do_olpc_suspend_lowlevel(void);
+
static unsigned long acpi_base;
static unsigned long pms_base;
+static struct {
+ unsigned long address;
+ unsigned short segment;
+} ofw_bios_entry = { 0xF0000 + PAGE_OFFSET, __KERNEL_CS };
+
+static int xo1_power_state_enter(suspend_state_t pm_state)
+{
+ int r;
+
+ /* Only STR is supported */
+ if (pm_state != PM_SUSPEND_MEM)
+ return -EINVAL;
+
+ r = olpc_ec_cmd(EC_SET_SCI_INHIBIT, NULL, 0, NULL, 0);
+ if (r)
+ return r;
+
+ /* Save CPU state */
+ do_olpc_suspend_lowlevel();
+
+ /* Resume path starts here */
+
+ /* Tell the EC to stop inhibiting SCIs */
+ olpc_ec_cmd(EC_SET_SCI_INHIBIT_RELEASE, NULL, 0, NULL, 0);
+
+ /*
+ * Tell the wireless module to restart USB communication.
+ * Must be done twice.
+ */
+ olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0);
+ olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0);
+
+ return 0;
+}
+
+asmlinkage int olpc_xo1_do_sleep(u8 sleep_state)
+{
+ void *pgd_addr = __va(read_cr3());
+ printk(KERN_ERR "xo1_do_sleep!\n"); /* this needs to remain here so
+ * that gcc doesn't optimize
+ * away our __va! */
+
+ /* Enable wakeup through power button */
+ outl((CS5536_PM_PWRBTN << 16) | 0xFFFF, acpi_base + PM1_STS);
+
+ __asm__ __volatile__("movl %0,%%eax" : : "r" (pgd_addr));
+ __asm__("call *(%%edi); cld"
+ : : "D" (&ofw_bios_entry));
+ __asm__ __volatile__("movb $0x34, %al\n\t"
+ "outb %al, $0x70\n\t"
+ "movb $0x30, %al\n\t"
+ "outb %al, $0x71\n\t");
+ return 0;
+}
+
+static int xo1_power_state_valid(suspend_state_t pm_state)
+{
+ /* suspend-to-RAM only */
+ return pm_state == PM_SUSPEND_MEM;
+}
+
+static struct platform_suspend_ops xo1_suspend_ops = {
+ .valid = xo1_power_state_valid,
+ .enter = xo1_power_state_enter,
+};
+
static void xo1_power_off(void)
{
printk(KERN_INFO "OLPC XO-1 power off sequence...\n");
@@ -101,6 +173,13 @@ static int __devinit olpc_xo1_probe(struct platform_device *pdev)
if (r)
return r;
+ /*
+ * Take a reference on ourself to prevent module unloading. We can't
+ * safely unload after changing the suspend handlers.
+ */
+ __module_get(THIS_MODULE);
+
+ suspend_set_ops(&xo1_suspend_ops);
pm_power_off = xo1_power_off;
printk(KERN_INFO "OLPC XO-1 support registered\n");
--
1.7.3.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
end of thread, other threads:[~2010-11-11 15:02 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-10-19 22:01 [PATCH] OLPC: Add XO-1 suspend/resume support Daniel Drake
2010-10-19 22:06 ` Randy Dunlap
2010-10-19 22:11 ` H. Peter Anvin
2010-10-20 5:47 ` Borislav Petkov
2010-10-20 5:58 ` H. Peter Anvin
2010-10-20 7:05 ` [PATCH -tip/master] x86-32, mm: Add an initial page table for core bootstrapping Borislav Petkov
2010-10-20 21:28 ` [tip:x86/trampoline] " tip-bot for Borislav Petkov
2010-11-11 15:02 [PATCH] OLPC: Add XO-1 suspend/resume support Daniel Drake
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).