All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 resend] OLPC: Add XO-1 suspend/resume support
@ 2010-11-18 20:28 Daniel Drake
  2010-11-26  9:43 ` Thomas Gleixner
  2010-12-03  0:57 ` Andrew Morton
  0 siblings, 2 replies; 5+ messages in thread
From: Daniel Drake @ 2010-11-18 20:28 UTC (permalink / raw)
  To: akpm; +Cc: tglx, mingo, hpa, x86, 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


I've submitted this 5 times over the last few weeks, am I being too
impatient/persistant? Code is too horrible to even warrant review comments?

http://marc.info/?l=linux-kernel&m=128752574203087&w=2
http://marc.info/?l=linux-kernel&m=128758786712015&w=2
http://marc.info/?l=linux-kernel&m=128818888428639&w=2
http://marc.info/?l=linux-kernel&m=128836342103914&w=2
http://marc.info/?l=linux-kernel&m=128948775532145&w=2

Feedback after the first submission was quickly acted upon and I haven't been
able to get a peep since.




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

v4: update for arch/x86/platform/olpc code move

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] 5+ messages in thread

* Re: [PATCH v4 resend] OLPC: Add XO-1 suspend/resume support
  2010-11-18 20:28 [PATCH v4 resend] OLPC: Add XO-1 suspend/resume support Daniel Drake
@ 2010-11-26  9:43 ` Thomas Gleixner
       [not found]   ` <AANLkTikRoB2xmtwW=ddjJy-RdEpwrwT+5ngV3HC5t5k9@mail.gmail.com>
  2010-12-03  0:57 ` Andrew Morton
  1 sibling, 1 reply; 5+ messages in thread
From: Thomas Gleixner @ 2010-11-26  9:43 UTC (permalink / raw)
  To: Daniel Drake; +Cc: akpm, linux-kernel

On Thu, 18 Nov 2010, Daniel Drake wrote:
> Feedback after the first submission was quickly acted upon and I haven't been
> able to get a peep since.

Sorry, fell off the radar.

> +
> +wakeup_start:
> +#	jmp wakeup_start

  Debug leftover ?

> +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! */
> +

  This looks suspect along with the __volatile__ magic below. Care to
  explain, what you fear that gcc is optimizing away ?

> +	/* 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");

Looks good otherwise.

Thanks,

	tglx

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v4 resend] OLPC: Add XO-1 suspend/resume support
       [not found]   ` <AANLkTikRoB2xmtwW=ddjJy-RdEpwrwT+5ngV3HC5t5k9@mail.gmail.com>
@ 2010-11-26 19:29     ` Andres Salomon
  0 siblings, 0 replies; 5+ messages in thread
From: Andres Salomon @ 2010-11-26 19:29 UTC (permalink / raw)
  To: Daniel Drake, akpm, linux-kernel; +Cc: Thomas Gleixner

On Fri, 26 Nov 2010 16:28:51 +0000
Daniel Drake <dsd@laptop.org> wrote:

[...]
> Re. the printk thing, this was your doing:
> http://dev.laptop.org/git/olpc-2.6/commit/?h=stable&id=b4334e9e1444761f19806f9066c6b38ce23079bf
[...]
> ---------- Forwarded message ----------
> From: Thomas Gleixner <tglx@linutronix.de>
> Date: 26 November 2010 09:43
> Subject: Re: [PATCH v4 resend] OLPC: Add XO-1 suspend/resume support
> To: Daniel Drake <dsd@laptop.org>
> Cc: akpm@linux-foundation.org, linux-kernel@vger.kernel.org
> 
> 
> On Thu, 18 Nov 2010, Daniel Drake wrote:
> > Feedback after the first submission was quickly acted upon and I
> > haven't been able to get a peep since.
> 
> Sorry, fell off the radar.
> 
> > +
> > +wakeup_start:
> > +#    jmp wakeup_start
> 
>  Debug leftover ?


Leftovers from the original patch; certainly should be removed.


> 
> > +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! */
> > +
> 
>  This looks suspect along with the __volatile__ magic below. Care to
>  explain, what you fear that gcc is optimizing away ?
> 


I'm working from memory here; in the version of gcc we were using
at the time (stock FC5 or FC6), setting pgd_addr immediately followed
by the asm below resulted in gcc optimizing away the __va().  The asm
turned into simply:

movl %cr3, %eax

With no mention of PAGE_OFFSET.  Messing with 'volatile' didn't help.
Adding the printk did, as it causes %eax to get clobbered, forcing
temporary storage of %cr3 into a separate register.  A lot has changed
since then (compilers, this code, as well as the definition of
read_cr3()), so I highly suspect that it's no longer needed.
 

> > +     /* 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");
> 
> Looks good otherwise.
> 
> Thanks,
> 
>        tglx


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v4 resend] OLPC: Add XO-1 suspend/resume support
  2010-11-18 20:28 [PATCH v4 resend] OLPC: Add XO-1 suspend/resume support Daniel Drake
  2010-11-26  9:43 ` Thomas Gleixner
@ 2010-12-03  0:57 ` Andrew Morton
  2010-12-03  2:10   ` H. Peter Anvin
  1 sibling, 1 reply; 5+ messages in thread
From: Andrew Morton @ 2010-12-03  0:57 UTC (permalink / raw)
  To: Daniel Drake; +Cc: tglx, mingo, hpa, x86, linux-kernel

On Thu, 18 Nov 2010 20:28:37 +0000 (GMT)
Daniel Drake <dsd@laptop.org> wrote:

> 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 ++++++++++++++++++

i386 allmodconfig:

make[3]: *** No rule to make target `arch/x86/platform/olpc/olpc-xo1-wakeup.c', 

I "fixed" that locally by making olpc depend on x86_64.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v4 resend] OLPC: Add XO-1 suspend/resume support
  2010-12-03  0:57 ` Andrew Morton
@ 2010-12-03  2:10   ` H. Peter Anvin
  0 siblings, 0 replies; 5+ messages in thread
From: H. Peter Anvin @ 2010-12-03  2:10 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Daniel Drake, tglx, mingo, x86, linux-kernel

On 12/02/2010 04:57 PM, Andrew Morton wrote:
> On Thu, 18 Nov 2010 20:28:37 +0000 (GMT)
> Daniel Drake <dsd@laptop.org> wrote:
> 
>> 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 ++++++++++++++++++
> 
> i386 allmodconfig:
> 
> make[3]: *** No rule to make target `arch/x86/platform/olpc/olpc-xo1-wakeup.c', 
> 
> I "fixed" that locally by making olpc depend on x86_64.

... which is of course completely busted since olpc is 32 bit.

	-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] 5+ messages in thread

end of thread, other threads:[~2010-12-03  2:10 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-11-18 20:28 [PATCH v4 resend] OLPC: Add XO-1 suspend/resume support Daniel Drake
2010-11-26  9:43 ` Thomas Gleixner
     [not found]   ` <AANLkTikRoB2xmtwW=ddjJy-RdEpwrwT+5ngV3HC5t5k9@mail.gmail.com>
2010-11-26 19:29     ` Andres Salomon
2010-12-03  0:57 ` Andrew Morton
2010-12-03  2:10   ` H. Peter Anvin

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.