public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH][3/3] swsusp: use non-contiguous memory
       [not found] <200503042051.54176.rjw@sisk.pl>
@ 2005-03-07  6:41 ` hugang
  2005-03-07 11:32   ` Rafael J. Wysocki
  0 siblings, 1 reply; 8+ messages in thread
From: hugang @ 2005-03-07  6:41 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Andrew Morton, LKML, Pavel Machek

On Fri, Mar 04, 2005 at 08:51:53PM +0100, Rafael J. Wysocki wrote:
> From: Hu Gang <hugang@soulinfo.com>
> 
> Subject: swsusp: use non-contiguous memory on resume - ppc support
> 
> This patch contains the architecture-dependent changes for ppc
> required for using a linklist instead of an array of page backup entries
> during resume.
> 
> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
  Signed-off-by: Hu Gang <hugang@soulinfo.com>
...

-- 
Hu Gang       .-.
              /v\
             // \\ 
Linux User  /(   )\  [204016]
GPG Key ID   ^^-^^   http://soulinfo.com/~hugang/hugang.asc

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

* Re: [PATCH][3/3] swsusp: use non-contiguous memory
  2005-03-07  6:41 ` [PATCH][3/3] swsusp: use non-contiguous memory hugang
@ 2005-03-07 11:32   ` Rafael J. Wysocki
  2005-03-07 11:39     ` Andrew Morton
  0 siblings, 1 reply; 8+ messages in thread
From: Rafael J. Wysocki @ 2005-03-07 11:32 UTC (permalink / raw)
  To: hugang; +Cc: Andrew Morton, LKML, Pavel Machek

On Monday, 7 of March 2005 07:41, hugang@soulinfo.com wrote:
> On Fri, Mar 04, 2005 at 08:51:53PM +0100, Rafael J. Wysocki wrote:
> > From: Hu Gang <hugang@soulinfo.com>
> > 
> > Subject: swsusp: use non-contiguous memory on resume - ppc support
> > 
> > This patch contains the architecture-dependent changes for ppc
> > required for using a linklist instead of an array of page backup entries
> > during resume.
> > 
> > Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
>   Signed-off-by: Hu Gang <hugang@soulinfo.com>

Yes, the Signed-off-by line was missing from the original patch.  Andrew,
should I resubmit it?

Rafael


-- 
- Would you tell me, please, which way I ought to go from here?
- That depends a good deal on where you want to get to.
		-- Lewis Carroll "Alice's Adventures in Wonderland"

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

* Re: [PATCH][3/3] swsusp: use non-contiguous memory
  2005-03-07 11:32   ` Rafael J. Wysocki
@ 2005-03-07 11:39     ` Andrew Morton
  2005-03-07 12:13       ` Rafael J. Wysocki
  0 siblings, 1 reply; 8+ messages in thread
From: Andrew Morton @ 2005-03-07 11:39 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: hugang, linux-kernel, pavel

"Rafael J. Wysocki" <rjw@sisk.pl> wrote:
>
> On Monday, 7 of March 2005 07:41, hugang@soulinfo.com wrote:
> > On Fri, Mar 04, 2005 at 08:51:53PM +0100, Rafael J. Wysocki wrote:
> > > From: Hu Gang <hugang@soulinfo.com>
> > > 
> > > Subject: swsusp: use non-contiguous memory on resume - ppc support
> > > 
> > > This patch contains the architecture-dependent changes for ppc
> > > required for using a linklist instead of an array of page backup entries
> > > during resume.
> > > 
> > > Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
> >   Signed-off-by: Hu Gang <hugang@soulinfo.com>
> 
> Yes, the Signed-off-by line was missing from the original patch.  Andrew,
> should I resubmit it?
> 

I dropped lots of those swsusp patches due to various bit of breakage. 
Pavel will be redoing all of them sometime, hopefully.


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

* Re: [PATCH][3/3] swsusp: use non-contiguous memory
  2005-03-07 11:39     ` Andrew Morton
@ 2005-03-07 12:13       ` Rafael J. Wysocki
  2005-03-08 10:38         ` Pavel Machek
  0 siblings, 1 reply; 8+ messages in thread
From: Rafael J. Wysocki @ 2005-03-07 12:13 UTC (permalink / raw)
  To: Andrew Morton; +Cc: hugang, linux-kernel, pavel

On Monday, 7 of March 2005 12:39, Andrew Morton wrote:
> "Rafael J. Wysocki" <rjw@sisk.pl> wrote:
> >
> > On Monday, 7 of March 2005 07:41, hugang@soulinfo.com wrote:
> > > On Fri, Mar 04, 2005 at 08:51:53PM +0100, Rafael J. Wysocki wrote:
> > > > From: Hu Gang <hugang@soulinfo.com>
> > > > 
> > > > Subject: swsusp: use non-contiguous memory on resume - ppc support
> > > > 
> > > > This patch contains the architecture-dependent changes for ppc
> > > > required for using a linklist instead of an array of page backup entries
> > > > during resume.
> > > > 
> > > > Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
> > >   Signed-off-by: Hu Gang <hugang@soulinfo.com>
> > 
> > Yes, the Signed-off-by line was missing from the original patch.  Andrew,
> > should I resubmit it?
> > 
> 
> I dropped lots of those swsusp patches due to various bit of breakage. 
> Pavel will be redoing all of them sometime, hopefully.

These patches are a "redone version" of the patch that Pavel submitted
before and Pavel has acked them already.

I did my best not to break them, but if they are broken, could you please tell
me what's wrong with them so that I can fix it?

Rafael


-- 
- Would you tell me, please, which way I ought to go from here?
- That depends a good deal on where you want to get to.
		-- Lewis Carroll "Alice's Adventures in Wonderland"

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

* Re: [PATCH][3/3] swsusp: use non-contiguous memory
  2005-03-07 12:13       ` Rafael J. Wysocki
@ 2005-03-08 10:38         ` Pavel Machek
  2005-03-08 11:47           ` Rafael J. Wysocki
  0 siblings, 1 reply; 8+ messages in thread
From: Pavel Machek @ 2005-03-08 10:38 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: hugang, linux-kernel

On Po 07-03-05 13:13:07, Rafael J. Wysocki wrote:
> On Monday, 7 of March 2005 12:39, Andrew Morton wrote:
> > "Rafael J. Wysocki" <rjw@sisk.pl> wrote:
> > >
> > > Yes, the Signed-off-by line was missing from the original patch.  Andrew,
> > > should I resubmit it?
> > > 
> > 
> > I dropped lots of those swsusp patches due to various bit of breakage. 
> > Pavel will be redoing all of them sometime, hopefully.
> 
> These patches are a "redone version" of the patch that Pavel submitted
> before and Pavel has acked them already.
> 
> I did my best not to break them, but if they are broken, could you please tell
> me what's wrong with them so that I can fix it?

Just bad timing, I guess. I sent wrong patches, and andrew reacted by
simply waiting for me to catch up with right tree (which is okay, it
was big and not critical).

Now, akpm sent all (?) swsusp updates to Linus, so it should appear in
bk tree later today. If you could regenerate the patches (1/3 will no
longer be needed) and send them to me & l-k. I'll then forward them to
akpm. [He seems to prefer patches to come from my email address :-)]

								Pavel
-- 
People were complaining that M$ turns users into beta-testers...
...jr ghea gurz vagb qrirybcref, naq gurl frrz gb yvxr vg gung jnl!

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

* Re: [PATCH][3/3] swsusp: use non-contiguous memory
  2005-03-08 10:38         ` Pavel Machek
@ 2005-03-08 11:47           ` Rafael J. Wysocki
  2005-03-08 12:00             ` Rafael J. Wysocki
  0 siblings, 1 reply; 8+ messages in thread
From: Rafael J. Wysocki @ 2005-03-08 11:47 UTC (permalink / raw)
  To: Pavel Machek; +Cc: hugang, linux-kernel

Hi,

On Tuesday, 8 of March 2005 11:38, Pavel Machek wrote:
> On Po 07-03-05 13:13:07, Rafael J. Wysocki wrote:
> > On Monday, 7 of March 2005 12:39, Andrew Morton wrote:
> > > "Rafael J. Wysocki" <rjw@sisk.pl> wrote:
> > > >
> > > > Yes, the Signed-off-by line was missing from the original patch.  Andrew,
> > > > should I resubmit it?
> > > > 
> > > 
> > > I dropped lots of those swsusp patches due to various bit of breakage. 
> > > Pavel will be redoing all of them sometime, hopefully.
> > 
> > These patches are a "redone version" of the patch that Pavel submitted
> > before and Pavel has acked them already.
> > 
> > I did my best not to break them, but if they are broken, could you please tell
> > me what's wrong with them so that I can fix it?
> 
> Just bad timing, I guess. I sent wrong patches, and andrew reacted by
> simply waiting for me to catch up with right tree (which is okay, it
> was big and not critical).
> 
> Now, akpm sent all (?) swsusp updates to Linus, so it should appear in
> bk tree later today. If you could regenerate the patches (1/3 will no
> longer be needed) and send them to me & l-k. I'll then forward them to
> akpm. [He seems to prefer patches to come from my email address :-)]

OK

Here's the 2/3 one (ie the main resume part).  Do you need the summary?

Rafael


Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>

diff -Nru linux-2.6.11-a/arch/i386/kernel/asm-offsets.c linux-2.6.11-b/arch/i386/kernel/asm-offsets.c
--- linux-2.6.11-a/arch/i386/kernel/asm-offsets.c	2005-03-02 08:38:00.000000000 +0100
+++ linux-2.6.11-b/arch/i386/kernel/asm-offsets.c	2005-03-04 20:14:01.000000000 +0100
@@ -7,6 +7,7 @@
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <linux/personality.h>
+#include <linux/suspend.h>
 #include <asm/ucontext.h>
 #include "sigframe.h"
 #include <asm/fixmap.h>
@@ -56,6 +57,11 @@
 
 	OFFSET(EXEC_DOMAIN_handler, exec_domain, handler);
 	OFFSET(RT_SIGFRAME_sigcontext, rt_sigframe, uc.uc_mcontext);
+	BLANK();
+
+	OFFSET(pbe_address, pbe, address);
+	OFFSET(pbe_orig_address, pbe, orig_address);
+	OFFSET(pbe_next, pbe, next);
 
 	/* Offset from the sysenter stack to tss.esp0 */
 	DEFINE(TSS_sysenter_esp0, offsetof(struct tss_struct, esp0) -
diff -Nru linux-2.6.11-a/arch/i386/power/swsusp.S linux-2.6.11-b/arch/i386/power/swsusp.S
--- linux-2.6.11-a/arch/i386/power/swsusp.S	2005-03-02 08:38:37.000000000 +0100
+++ linux-2.6.11-b/arch/i386/power/swsusp.S	2005-03-04 20:14:01.000000000 +0100
@@ -12,6 +12,7 @@
 #include <linux/linkage.h>
 #include <asm/segment.h>
 #include <asm/page.h>
+#include <asm/asm_offsets.h>
 
 	.text
 
@@ -28,28 +29,28 @@
 	ret
 
 ENTRY(swsusp_arch_resume)
-	movl $swsusp_pg_dir-__PAGE_OFFSET,%ecx
-	movl %ecx,%cr3
+	movl	$swsusp_pg_dir-__PAGE_OFFSET, %ecx
+	movl	%ecx, %cr3
 
-	movl	pagedir_nosave, %ebx
-	xorl	%eax, %eax
-	xorl	%edx, %edx
+	movl	pagedir_nosave, %edx
 	.p2align 4,,7
 
 copy_loop:
-	movl	4(%ebx,%edx),%edi
-	movl	(%ebx,%edx),%esi
+	testl	%edx, %edx
+	jz	done
+
+	movl	pbe_address(%edx), %esi
+	movl	pbe_orig_address(%edx), %edi
 
 	movl	$1024, %ecx
 	rep
 	movsl
 
-	incl	%eax
-	addl	$16, %edx
-	cmpl	nr_copy_pages,%eax
-	jb copy_loop
+	movl	pbe_next(%edx), %edx
+	jmp	copy_loop
 	.p2align 4,,7
 
+done:
 	movl saved_context_esp, %esp
 	movl saved_context_ebp, %ebp
 	movl saved_context_ebx, %ebx
diff -Nru linux-2.6.11-a/arch/x86_64/kernel/asm-offsets.c linux-2.6.11-b/arch/x86_64/kernel/asm-offsets.c
--- linux-2.6.11-a/arch/x86_64/kernel/asm-offsets.c	2005-03-02 08:38:10.000000000 +0100
+++ linux-2.6.11-b/arch/x86_64/kernel/asm-offsets.c	2005-03-04 20:14:01.000000000 +0100
@@ -62,8 +62,8 @@
 	       offsetof (struct rt_sigframe32, uc.uc_mcontext));
 	BLANK();
 #endif
-	DEFINE(SIZEOF_PBE, sizeof(struct pbe));
 	DEFINE(pbe_address, offsetof(struct pbe, address));
 	DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address));
+	DEFINE(pbe_next, offsetof(struct pbe, next));
 	return 0;
 }
diff -Nru linux-2.6.11-a/arch/x86_64/kernel/suspend_asm.S linux-2.6.11-b/arch/x86_64/kernel/suspend_asm.S
--- linux-2.6.11-a/arch/x86_64/kernel/suspend_asm.S	2005-03-02 08:38:26.000000000 +0100
+++ linux-2.6.11-b/arch/x86_64/kernel/suspend_asm.S	2005-03-04 20:14:01.000000000 +0100
@@ -54,16 +54,10 @@
 	movq	%rax, %cr4;  # turn PGE back on
 
 	movq	pagedir_nosave(%rip), %rdx
-	/* compute the limit */
-	movl	nr_copy_pages(%rip), %eax
-	testl	%eax, %eax
-	jz	done
-	movq	%rdx,%r8
-	movl	$SIZEOF_PBE,%r9d
-	mul		%r9  # with rax, clobbers rdx
-	movq 	%r8, %rdx
-	addq	%r8, %rax
 loop:
+	testq	%rdx, %rdx
+	jz	done
+
 	/* get addresses from the pbe and copy the page */
 	movq	pbe_address(%rdx), %rsi
 	movq	pbe_orig_address(%rdx), %rdi
@@ -72,9 +66,8 @@
 	movsq
 
 	/* progress to the next pbe */
-	addq	$SIZEOF_PBE, %rdx
-	cmpq	%rax, %rdx
-	jb	loop
+	movq	pbe_next(%rdx), %rdx
+	jmp	loop
 done:
 	movl	$24, %eax
 	movl	%eax, %ds
diff -Nru linux-2.6.11-a/kernel/power/swsusp.c linux-2.6.11-b/kernel/power/swsusp.c
--- linux-2.6.11-a/kernel/power/swsusp.c	2005-03-04 20:05:49.000000000 +0100
+++ linux-2.6.11-b/kernel/power/swsusp.c	2005-03-04 20:14:01.000000000 +0100
@@ -621,6 +621,46 @@
 }
 
 /**
+ *	fill_pb_page - Create a list of PBEs on a given memory page
+ */
+
+static inline void fill_pb_page(struct pbe *pbpage)
+{
+	struct pbe *p;
+
+	p = pbpage;
+	pbpage += PB_PAGE_SKIP;
+	do
+		p->next = p + 1;
+	while (++p < pbpage);
+}
+
+/**
+ *	create_pbe_list - Create a list of PBEs on top of a given chain
+ *	of memory pages allocated with alloc_pagedir()
+ */
+ 
+static void create_pbe_list(struct pbe *pblist, unsigned nr_pages)
+{
+	struct pbe *pbpage, *p;
+	unsigned num = PBES_PER_PAGE;
+
+	for_each_pb_page (pbpage, pblist) {
+		if (num >= nr_pages)
+			break;
+
+		fill_pb_page(pbpage);
+		num += PBES_PER_PAGE;
+	}
+	if (pbpage) {
+		for (num -= PBES_PER_PAGE - 1, p = pbpage; num < nr_pages; p++, num++)
+			p->next = p + 1;
+		p->next = NULL;
+	}
+	pr_debug("create_pbe_list(): initialized %d PBEs\n", num);
+}
+
+/**
  *	alloc_pagedir - Allocate the page directory.
  *
  *	First, determine exactly how many pages we need and
@@ -636,7 +676,7 @@
 static struct pbe * alloc_pagedir(unsigned nr_pages)
 {
 	unsigned num;
-	struct pbe *pblist, *pbe, *p;
+	struct pbe *pblist, *pbe;
 
 	if (!nr_pages)
 		return NULL;
@@ -645,21 +685,13 @@
 	pblist = (struct pbe *)get_zeroed_page(GFP_ATOMIC | __GFP_COLD);
 	for (pbe = pblist, num = PBES_PER_PAGE; pbe && num < nr_pages;
         		pbe = pbe->next, num += PBES_PER_PAGE) {
-		p = pbe;
 		pbe += PB_PAGE_SKIP;
-		do
-			p->next = p + 1;
-		while (p++ < pbe);
 		pbe->next = (struct pbe *)get_zeroed_page(GFP_ATOMIC | __GFP_COLD);
 	}
-	if (pbe) {
-		for (num -= PBES_PER_PAGE - 1, p = pbe; num < nr_pages; p++, num++)
-			p->next = p + 1;
-	} else { /* get_zeroed_page() failed */
+	if (!pbe) { /* get_zeroed_page() failed */
 		free_pagedir(pblist);
 		pblist = NULL;
         }
-	pr_debug("alloc_pagedir(): allocated %d PBEs\n", num);
 	return pblist;
 }
 
@@ -766,6 +798,7 @@
 		printk(KERN_ERR "suspend: Allocating pagedir failed.\n");
 		return -ENOMEM;
 	}
+	create_pbe_list(pagedir_save, nr_copy_pages);
 	pagedir_nosave = pagedir_save;
 	if ((error = alloc_image_pages())) {
 		printk(KERN_ERR "suspend: Allocating image pages failed.\n");
@@ -917,44 +950,104 @@
 	return 0;
 }
 
-/*
- * We check here that pagedir & pages it points to won't collide with pages
- * where we're going to restore from the loaded pages later
+/**
+ *	On resume, for storing the PBE list and the image,
+ *	we can only use memory pages that do not conflict with the pages
+ *	which had been used before suspend.
+ *
+ *	We don't know which pages are usable until we allocate them.
+ *
+ *	Allocated but unusable (ie eaten) memory pages are linked together
+ *	to create a list, so that we can free them easily
+ *
+ *	We could have used a type other than (void *)
+ *	for this purpose, but ...
  */
-static int __init check_pagedir(void)
+static void **eaten_memory = NULL;
+
+static inline void eat_page(void *page)
 {
-	int i;
+	void **c;
 
-	for(i=0; i < nr_copy_pages; i++) {
-		unsigned long addr;
+	c = eaten_memory;
+	eaten_memory = page;
+	*eaten_memory = c;
+}
 
-		do {
-			addr = get_zeroed_page(GFP_ATOMIC);
-			if(!addr)
-				return -ENOMEM;
-		} while (does_collide_order(addr, 0));
+static unsigned long __init get_usable_page(unsigned gfp_mask)
+{
+	unsigned long m;
 
-		(pagedir_nosave+i)->address = addr;
+	m = get_zeroed_page(gfp_mask);
+	while (does_collide_order(m, 0)) {
+		eat_page((void *)m);
+		m = get_zeroed_page(gfp_mask);
+		if (!m)
+			break;
 	}
-	return 0;
+	return m;
 }
 
-static int __init swsusp_pagedir_relocate(void)
+static void __init free_eaten_memory(void)
 {
-	/*
-	 * We have to avoid recursion (not to overflow kernel stack),
-	 * and that's why code looks pretty cryptic 
+	unsigned long m;
+	void **c;
+	int i = 0;
+
+	c = eaten_memory;
+	while (c) {
+		m = (unsigned long)c;
+		c = *c;
+		free_page(m);
+		i++;
+	}
+	eaten_memory = NULL;
+	pr_debug("swsusp: %d unused pages freed\n", i);
+}
+
+/**
+ *	check_pagedir - We ensure here that pages that the PBEs point to
+ *	won't collide with pages where we're going to restore from the loaded
+ *	pages later
+ */
+
+static int __init check_pagedir(struct pbe *pblist)
+{
+	struct pbe *p;
+
+	/* This is necessary, so that we can free allocated pages
+	 * in case of failure
 	 */
-	suspend_pagedir_t *old_pagedir = pagedir_nosave;
-	void **eaten_memory = NULL;
-	void **c = eaten_memory, *m, *f;
-	int ret = 0;
+	for_each_pbe (p, pblist)
+		p->address = 0UL;
+
+	for_each_pbe (p, pblist) {
+		p->address = get_usable_page(GFP_ATOMIC);
+		if (!p->address)
+			return -ENOMEM;
+	}
+	return 0;
+}
+
+/**
+ *	swsusp_pagedir_relocate - It is possible, that some memory pages
+ *	occupied by the list of PBEs collide with pages where we're going to
+ *	restore from the loaded pages later.  We relocate them here.
+ */
+
+static struct pbe * __init swsusp_pagedir_relocate(struct pbe *pblist)
+{
 	struct zone *zone;
-	int i;
-	struct pbe *p;
 	unsigned long zone_pfn;
+	struct pbe *pbpage, *tail, *p;
+	void *m;
+	int rel = 0, error = 0;
+
+	if (!pblist) /* a sanity check */
+		return NULL;
 
-	printk("Relocating pagedir ");
+	pr_debug("swsusp: Relocating pagedir (%lu pages to check)\n",
+			swsusp_info.pagedir_pages);
 
 	/* Set page flags */
 
@@ -964,45 +1057,52 @@
 					zone->zone_start_pfn));
 	}
 
-	/* Clear orig address */
+	/* Clear orig addresses */
 
-	for(i = 0, p = pagedir_nosave; i < nr_copy_pages; i++, p++) {
+	for_each_pbe (p, pblist)
 		ClearPageNosaveFree(virt_to_page(p->orig_address));
-	}
 
-	if (!does_collide_order((unsigned long)old_pagedir, pagedir_order)) {
-		printk("not necessary\n");
-		return check_pagedir();
-	}
+	tail = pblist + PB_PAGE_SKIP;
 
-	while ((m = (void *) __get_free_pages(GFP_ATOMIC, pagedir_order)) != NULL) {
-		if (!does_collide_order((unsigned long)m, pagedir_order))
-			break;
-		eaten_memory = m;
-		printk( "." ); 
-		*eaten_memory = c;
-		c = eaten_memory;
-	}
+	/* Relocate colliding pages */
 
-	if (!m) {
-		printk("out of memory\n");
-		ret = -ENOMEM;
-	} else {
-		pagedir_nosave =
-			memcpy(m, old_pagedir, PAGE_SIZE << pagedir_order);
+	for_each_pb_page (pbpage, pblist) {
+		if (does_collide_order((unsigned long)pbpage, 0)) {
+			m = (void *)get_usable_page(GFP_ATOMIC | __GFP_COLD);
+			if (!m) {
+				error = -ENOMEM;
+				break;
+			}
+			memcpy(m, (void *)pbpage, PAGE_SIZE);
+			if (pbpage == pblist)
+				pblist = (struct pbe *)m;
+			else
+				tail->next = (struct pbe *)m;
+
+			eat_page((void *)pbpage);
+			pbpage = (struct pbe *)m;
+
+			/* We have to link the PBEs again */
+
+			for (p = pbpage; p < pbpage + PB_PAGE_SKIP; p++)
+				if (p->next) /* needed to save the end */
+					p->next = p + 1;
+
+			rel++;
+		}
+		tail = pbpage + PB_PAGE_SKIP;
 	}
 
-	c = eaten_memory;
-	while (c) {
-		printk(":");
-		f = c;
-		c = *c;
-		free_pages((unsigned long)f, pagedir_order);
+	if (error) {
+		printk("\nswsusp: Out of memory\n\n");
+		free_pagedir(pblist);
+		free_eaten_memory();
+		pblist = NULL;
 	}
-	if (ret)
-		return ret;
-	printk("|\n");
-	return check_pagedir();
+	else
+		printk("swsusp: Relocated %d pages\n", rel);
+
+	return pblist;
 }
 
 /**
@@ -1147,76 +1247,117 @@
 }
 
 /**
- *	swsusp_read_data - Read image pages from swap.
+ *	data_read - Read image pages from swap.
  *
  *	You do not need to check for overlaps, check_pagedir()
  *	already did that.
  */
 
-static int __init data_read(void)
+static int __init data_read(struct pbe *pblist)
 {
 	struct pbe * p;
-	int error;
-	int i;
-	int mod = nr_copy_pages / 100;
+	int error = 0;
+	int i = 0;
+	int mod = swsusp_info.image_pages / 100;
 
 	if (!mod)
 		mod = 1;
 
-	if ((error = swsusp_pagedir_relocate()))
-		return error;
+	printk("swsusp: Reading image data (%lu pages):     ",
+			swsusp_info.image_pages);
+
+	for_each_pbe (p, pblist) {
+		if (!(i % mod))
+			printk("\b\b\b\b%3d%%", i / mod);
 
-	printk( "Reading image data (%d pages):     ", nr_copy_pages );
-	for(i = 0, p = pagedir_nosave; i < nr_copy_pages && !error; i++, p++) {
-		if (!(i%mod))
-			printk( "\b\b\b\b%3d%%", i / mod );
 		error = bio_read_page(swp_offset(p->swap_address),
 				  (void *)p->address);
+		if (error)
+			return error;
+
+		i++;
 	}
-	printk(" %d done.\n",i);
+	printk("\b\b\b\bdone\n");
 	return error;
-
 }
 
 extern dev_t __init name_to_dev_t(const char *line);
 
-static int __init read_pagedir(void)
+/**
+ *	read_pagedir - Read page backup list pages from swap
+ */
+
+static int __init read_pagedir(struct pbe *pblist)
 {
-	unsigned long addr;
-	int i, n = swsusp_info.pagedir_pages;
-	int error = 0;
+	struct pbe *pbpage, *p;
+	unsigned i = 0;
+	int error;
 
-	addr = __get_free_pages(GFP_ATOMIC, pagedir_order);
-	if (!addr)
-		return -ENOMEM;
-	pagedir_nosave = (struct pbe *)addr;
+	if (!pblist)
+		return -EFAULT;
+
+	printk("swsusp: Reading pagedir (%lu pages)\n",
+			swsusp_info.pagedir_pages);
 
-	pr_debug("swsusp: Reading pagedir (%d Pages)\n",n);
+	for_each_pb_page (pbpage, pblist) {
+		unsigned long offset = swp_offset(swsusp_info.pagedir[i++]);
 
-	for (i = 0; i < n && !error; i++, addr += PAGE_SIZE) {
-		unsigned long offset = swp_offset(swsusp_info.pagedir[i]);
-		if (offset)
-			error = bio_read_page(offset, (void *)addr);
-		else
-			error = -EFAULT;
+		error = -EFAULT;
+		if (offset) {
+			p = (pbpage + PB_PAGE_SKIP)->next;
+			error = bio_read_page(offset, (void *)pbpage);
+			(pbpage + PB_PAGE_SKIP)->next = p;
+		}
+		if (error)
+			break;
 	}
+
 	if (error)
-		free_pages((unsigned long)pagedir_nosave, pagedir_order);
+		free_page((unsigned long)pblist);
+
+	BUG_ON(i != swsusp_info.pagedir_pages);
+
 	return error;
 }
 
+
 static int __init read_suspend_image(void)
 {
 	int error = 0;
+	struct pbe *p;
 
 	if ((error = check_sig()))
 		return error;
+
 	if ((error = check_header()))
 		return error;
-	if ((error = read_pagedir()))
+
+	if (!(p = alloc_pagedir(nr_copy_pages)))
+		return -ENOMEM;
+
+	if ((error = read_pagedir(p)))
 		return error;
-	if ((error = data_read()))
-		free_pages((unsigned long)pagedir_nosave, pagedir_order);
+
+	create_pbe_list(p, nr_copy_pages);
+
+	if (!(pagedir_nosave = swsusp_pagedir_relocate(p)))
+		return -ENOMEM;
+
+	/* Allocate memory for the image and read the data from swap */
+
+	error = check_pagedir(pagedir_nosave);
+	free_eaten_memory();
+	if (!error)
+		error = data_read(pagedir_nosave);
+
+	if (error) { /* We fail cleanly */
+		for_each_pbe (p, pagedir_nosave)
+			if (p->address) {
+				free_page(p->address);
+				p->address = 0UL;
+			}
+		free_pagedir(pagedir_nosave);
+	}
 	return error;
 }
 

-- 
- Would you tell me, please, which way I ought to go from here?
- That depends a good deal on where you want to get to.
		-- Lewis Carroll "Alice's Adventures in Wonderland"

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

* Re: [PATCH][3/3] swsusp: use non-contiguous memory
  2005-03-08 11:47           ` Rafael J. Wysocki
@ 2005-03-08 12:00             ` Rafael J. Wysocki
  2005-03-09 16:00               ` Rafael J. Wysocki
  0 siblings, 1 reply; 8+ messages in thread
From: Rafael J. Wysocki @ 2005-03-08 12:00 UTC (permalink / raw)
  To: Pavel Machek; +Cc: hugang, linux-kernel

Hi,

On Tuesday, 8 of March 2005 12:47, Rafael J. Wysocki wrote:
> Hi,
> 
[-- snip --] 
> > Just bad timing, I guess. I sent wrong patches, and andrew reacted by
> > simply waiting for me to catch up with right tree (which is okay, it
> > was big and not critical).
> > 
> > Now, akpm sent all (?) swsusp updates to Linus, so it should appear in
> > bk tree later today. If you could regenerate the patches (1/3 will no
> > longer be needed) and send them to me & l-k. I'll then forward them to
> > akpm. [He seems to prefer patches to come from my email address :-)]
> 
> OK
> 
> Here's the 2/3 one (ie the main resume part).  Do you need the summary?

Here's the 3/3 one (ie the ppc support from hugang).

The patches are against 2.6.11 + 1/3 (ie suspend part), but they should
apply cleanly to the -bk w/ the suspend part as well.

Rafael


Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Hu Gang <hugang@soulinfo.com>

diff -Nru linux-2.6.11-a/arch/ppc/Kconfig linux-2.6.11-b/arch/ppc/Kconfig
--- linux-2.6.11-a/arch/ppc/Kconfig	2005-03-02 08:38:33.000000000 +0100
+++ linux-2.6.11-b/arch/ppc/Kconfig	2005-03-04 18:42:16.000000000 +0100
@@ -1046,6 +1046,8 @@
 
 source "drivers/zorro/Kconfig"
 
+source kernel/power/Kconfig
+
 endmenu
 
 menu "Bus options"
diff -Nru linux-2.6.11-a/arch/ppc/kernel/asm-offsets.c linux-2.6.11-b/arch/ppc/kernel/asm-offsets.c
--- linux-2.6.11-a/arch/ppc/kernel/asm-offsets.c	2005-03-02 08:38:09.000000000 +0100
+++ linux-2.6.11-b/arch/ppc/kernel/asm-offsets.c	2005-03-04 18:42:16.000000000 +0100
@@ -16,6 +16,7 @@
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/ptrace.h>
+#include <linux/suspend.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <asm/io.h>
@@ -136,6 +137,10 @@
 	DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
 	DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
 
+	DEFINE(pbe_address, offsetof(struct pbe, address));
+	DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address));
+	DEFINE(pbe_next, offsetof(struct pbe, next));
+
 	DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28);
 	return 0;
 }
diff -Nru linux-2.6.11-a/arch/ppc/kernel/Makefile linux-2.6.11-b/arch/ppc/kernel/Makefile
--- linux-2.6.11-a/arch/ppc/kernel/Makefile	2005-03-02 08:38:25.000000000 +0100
+++ linux-2.6.11-b/arch/ppc/kernel/Makefile	2005-03-04 18:42:16.000000000 +0100
@@ -16,6 +16,7 @@
 					semaphore.o syscalls.o setup.o \
 					cputable.o ppc_htab.o perfmon.o
 obj-$(CONFIG_6xx)		+= l2cr.o cpu_setup_6xx.o
+obj-$(CONFIG_SOFTWARE_SUSPEND)	+= swsusp.o
 obj-$(CONFIG_POWER4)		+= cpu_setup_power4.o
 obj-$(CONFIG_MODULES)		+= module.o ppc_ksyms.o
 obj-$(CONFIG_NOT_COHERENT_CACHE)	+= dma-mapping.o
diff -Nru linux-2.6.11-a/arch/ppc/kernel/signal.c linux-2.6.11-b/arch/ppc/kernel/signal.c
--- linux-2.6.11-a/arch/ppc/kernel/signal.c	2005-03-02 08:38:33.000000000 +0100
+++ linux-2.6.11-b/arch/ppc/kernel/signal.c	2005-03-04 18:42:16.000000000 +0100
@@ -28,6 +28,7 @@
 #include <linux/elf.h>
 #include <linux/tty.h>
 #include <linux/binfmts.h>
+#include <linux/suspend.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -704,6 +705,14 @@
 	unsigned long frame, newsp;
 	int signr, ret;
 
+	if (current->flags & PF_FREEZE) {
+		refrigerator(PF_FREEZE);
+		signr = 0;
+		ret = regs->gpr[3];
+		if (!signal_pending(current))
+			goto no_signal;
+	}
+
 	if (!oldset)
 		oldset = &current->blocked;
 
@@ -726,6 +735,7 @@
 			regs->gpr[3] = EINTR;
 			/* note that the cr0.SO bit is already set */
 		} else {
+no_signal:
 			regs->nip -= 4;	/* Back up & retry system call */
 			regs->result = 0;
 			regs->trap = 0;
diff -Nru linux-2.6.11-a/arch/ppc/kernel/swsusp.S linux-2.6.11-b/arch/ppc/kernel/swsusp.S
--- linux-2.6.11-a/arch/ppc/kernel/swsusp.S	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.11-b/arch/ppc/kernel/swsusp.S	2005-03-04 18:42:16.000000000 +0100
@@ -0,0 +1,349 @@
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/cputable.h>
+#include <asm/thread_info.h>
+#include <asm/ppc_asm.h>
+#include <asm/offsets.h>
+
+
+/*
+ * Structure for storing CPU registers on the save area.
+ */
+#define SL_SP		0
+#define SL_PC		4
+#define SL_MSR		8
+#define SL_SDR1		0xc
+#define SL_SPRG0	0x10	/* 4 sprg's */
+#define SL_DBAT0	0x20
+#define SL_IBAT0	0x28
+#define SL_DBAT1	0x30
+#define SL_IBAT1	0x38
+#define SL_DBAT2	0x40
+#define SL_IBAT2	0x48
+#define SL_DBAT3	0x50
+#define SL_IBAT3	0x58
+#define SL_TB		0x60
+#define SL_R2		0x68
+#define SL_CR		0x6c
+#define SL_LR		0x70
+#define SL_R12		0x74	/* r12 to r31 */
+#define SL_SIZE		(SL_R12 + 80)
+
+	.section .data
+	.align	5
+
+_GLOBAL(swsusp_save_area)
+	.space	SL_SIZE
+
+
+	.section .text
+	.align	5
+
+_GLOBAL(swsusp_arch_suspend)
+
+	lis	r11,swsusp_save_area@h
+	ori	r11,r11,swsusp_save_area@l
+
+	mflr	r0
+	stw	r0,SL_LR(r11)
+	mfcr	r0
+	stw	r0,SL_CR(r11)
+	stw	r1,SL_SP(r11)
+	stw	r2,SL_R2(r11)
+	stmw	r12,SL_R12(r11)
+
+	/* Save MSR & SDR1 */
+	mfmsr	r4
+	stw	r4,SL_MSR(r11)
+	mfsdr1	r4
+	stw	r4,SL_SDR1(r11)
+
+	/* Get a stable timebase and save it */
+1:	mftbu	r4
+	stw	r4,SL_TB(r11)
+	mftb	r5
+	stw	r5,SL_TB+4(r11)
+	mftbu	r3
+	cmpw	r3,r4
+	bne	1b
+
+	/* Save SPRGs */
+	mfsprg	r4,0
+	stw	r4,SL_SPRG0(r11)
+	mfsprg	r4,1
+	stw	r4,SL_SPRG0+4(r11)
+	mfsprg	r4,2
+	stw	r4,SL_SPRG0+8(r11)
+	mfsprg	r4,3
+	stw	r4,SL_SPRG0+12(r11)
+
+	/* Save BATs */
+	mfdbatu	r4,0
+	stw	r4,SL_DBAT0(r11)
+	mfdbatl	r4,0
+	stw	r4,SL_DBAT0+4(r11)
+	mfdbatu	r4,1
+	stw	r4,SL_DBAT1(r11)
+	mfdbatl	r4,1
+	stw	r4,SL_DBAT1+4(r11)
+	mfdbatu	r4,2
+	stw	r4,SL_DBAT2(r11)
+	mfdbatl	r4,2
+	stw	r4,SL_DBAT2+4(r11)
+	mfdbatu	r4,3
+	stw	r4,SL_DBAT3(r11)
+	mfdbatl	r4,3
+	stw	r4,SL_DBAT3+4(r11)
+	mfibatu	r4,0
+	stw	r4,SL_IBAT0(r11)
+	mfibatl	r4,0
+	stw	r4,SL_IBAT0+4(r11)
+	mfibatu	r4,1
+	stw	r4,SL_IBAT1(r11)
+	mfibatl	r4,1
+	stw	r4,SL_IBAT1+4(r11)
+	mfibatu	r4,2
+	stw	r4,SL_IBAT2(r11)
+	mfibatl	r4,2
+	stw	r4,SL_IBAT2+4(r11)
+	mfibatu	r4,3
+	stw	r4,SL_IBAT3(r11)
+	mfibatl	r4,3
+	stw	r4,SL_IBAT3+4(r11)
+
+#if  0
+	/* Backup various CPU config stuffs */
+	bl	__save_cpu_setup
+#endif
+	/* Call the low level suspend stuff (we should probably have made
+	 * a stackframe...
+	 */
+	bl	swsusp_save
+
+	/* Restore LR from the save area */
+	lis	r11,swsusp_save_area@h
+	ori	r11,r11,swsusp_save_area@l
+	lwz	r0,SL_LR(r11)
+	mtlr	r0
+
+	blr
+
+
+/* Resume code */
+_GLOBAL(swsusp_arch_resume)
+
+	/* Stop pending alitvec streams and memory accesses */
+BEGIN_FTR_SECTION
+	DSSALL
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+ 	sync
+
+	/* Disable MSR:DR to make sure we don't take a TLB or
+	 * hash miss during the copy, as our hash table will
+	 * for a while be unuseable. For .text, we assume we are
+	 * covered by a BAT. This works only for non-G5 at this
+	 * point. G5 will need a better approach, possibly using
+	 * a small temporary hash table filled with large mappings,
+	 * disabling the MMU completely isn't a good option for
+	 * performance reasons.
+	 * (Note that 750's may have the same performance issue as
+	 * the G5 in this case, we should investigate using moving
+	 * BATs for these CPUs)
+	 */
+	mfmsr	r0
+	sync
+	rlwinm	r0,r0,0,28,26		/* clear MSR_DR */
+	mtmsr	r0
+	sync
+	isync
+
+	/* Load ptr the list of pages to copy in r3 */
+	lis	r11,(pagedir_nosave - KERNELBASE)@h
+	ori	r11,r11,pagedir_nosave@l
+	lwz	r10,0(r11)
+
+	/* Copy the pages. This is a very basic implementation, to
+	 * be replaced by something more cache efficient */
+1:
+	tophys(r3,r10)
+	li	r0,256
+	mtctr	r0
+	lwz	r11,pbe_address(r3)	/* source */
+	tophys(r5,r11)
+	lwz	r10,pbe_orig_address(r3)	/* destination */
+	tophys(r6,r10)
+2:
+	lwz	r8,0(r5)
+	lwz	r9,4(r5)
+	lwz	r10,8(r5)
+	lwz	r11,12(r5)
+	addi	r5,r5,16
+	stw	r8,0(r6)
+	stw	r9,4(r6)
+	stw	r10,8(r6)
+	stw	r11,12(r6)
+	addi	r6,r6,16
+	bdnz	2b
+	lwz		r10,pbe_next(r3)
+	cmpwi	0,r10,0
+	bne	1b
+
+	/* Do a very simple cache flush/inval of the L1 to ensure
+	 * coherency of the icache
+	 */
+	lis	r3,0x0002
+	mtctr	r3
+	li	r3, 0
+1:
+	lwz	r0,0(r3)
+	addi	r3,r3,0x0020
+	bdnz	1b
+	isync
+	sync
+
+	/* Now flush those cache lines */
+	lis	r3,0x0002
+	mtctr	r3
+	li	r3, 0
+1:
+	dcbf	0,r3
+	addi	r3,r3,0x0020
+	bdnz	1b
+	sync
+
+	/* Ok, we are now running with the kernel data of the old
+	 * kernel fully restored. We can get to the save area
+	 * easily now. As for the rest of the code, it assumes the
+	 * loader kernel and the booted one are exactly identical
+	 */
+	lis	r11,swsusp_save_area@h
+	ori	r11,r11,swsusp_save_area@l
+	tophys(r11,r11)
+
+#if 0
+	/* Restore various CPU config stuffs */
+	bl	__restore_cpu_setup
+#endif
+	/* Restore the BATs, and SDR1.  Then we can turn on the MMU.
+	 * This is a bit hairy as we are running out of those BATs,
+	 * but first, our code is probably in the icache, and we are
+	 * writing the same value to the BAT, so that should be fine,
+	 * though a better solution will have to be found long-term
+	 */
+	lwz	r4,SL_SDR1(r11)
+	mtsdr1	r4
+	lwz	r4,SL_SPRG0(r11)
+	mtsprg	0,r4
+	lwz	r4,SL_SPRG0+4(r11)
+	mtsprg	1,r4
+	lwz	r4,SL_SPRG0+8(r11)
+	mtsprg	2,r4
+	lwz	r4,SL_SPRG0+12(r11)
+	mtsprg	3,r4
+
+#if 0
+	lwz	r4,SL_DBAT0(r11)
+	mtdbatu	0,r4
+	lwz	r4,SL_DBAT0+4(r11)
+	mtdbatl	0,r4
+	lwz	r4,SL_DBAT1(r11)
+	mtdbatu	1,r4
+	lwz	r4,SL_DBAT1+4(r11)
+	mtdbatl	1,r4
+	lwz	r4,SL_DBAT2(r11)
+	mtdbatu	2,r4
+	lwz	r4,SL_DBAT2+4(r11)
+	mtdbatl	2,r4
+	lwz	r4,SL_DBAT3(r11)
+	mtdbatu	3,r4
+	lwz	r4,SL_DBAT3+4(r11)
+	mtdbatl	3,r4
+	lwz	r4,SL_IBAT0(r11)
+	mtibatu	0,r4
+	lwz	r4,SL_IBAT0+4(r11)
+	mtibatl	0,r4
+	lwz	r4,SL_IBAT1(r11)
+	mtibatu	1,r4
+	lwz	r4,SL_IBAT1+4(r11)
+	mtibatl	1,r4
+	lwz	r4,SL_IBAT2(r11)
+	mtibatu	2,r4
+	lwz	r4,SL_IBAT2+4(r11)
+	mtibatl	2,r4
+	lwz	r4,SL_IBAT3(r11)
+	mtibatu	3,r4
+	lwz	r4,SL_IBAT3+4(r11)
+	mtibatl	3,r4
+#endif
+
+BEGIN_FTR_SECTION
+	li	r4,0
+	mtspr	SPRN_DBAT4U,r4
+	mtspr	SPRN_DBAT4L,r4
+	mtspr	SPRN_DBAT5U,r4
+	mtspr	SPRN_DBAT5L,r4
+	mtspr	SPRN_DBAT6U,r4
+	mtspr	SPRN_DBAT6L,r4
+	mtspr	SPRN_DBAT7U,r4
+	mtspr	SPRN_DBAT7L,r4
+	mtspr	SPRN_IBAT4U,r4
+	mtspr	SPRN_IBAT4L,r4
+	mtspr	SPRN_IBAT5U,r4
+	mtspr	SPRN_IBAT5L,r4
+	mtspr	SPRN_IBAT6U,r4
+	mtspr	SPRN_IBAT6L,r4
+	mtspr	SPRN_IBAT7U,r4
+	mtspr	SPRN_IBAT7L,r4
+END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS)
+
+	/* Flush all TLBs */
+	lis	r4,0x1000
+1:	addic.	r4,r4,-0x1000
+	tlbie	r4
+	blt	1b
+	sync
+
+	/* restore the MSR and turn on the MMU */
+	lwz	r3,SL_MSR(r11)
+	bl	turn_on_mmu
+	tovirt(r11,r11)
+
+	/* Restore TB */
+	li	r3,0
+	mttbl	r3
+	lwz	r3,SL_TB(r11)
+	lwz	r4,SL_TB+4(r11)
+	mttbu	r3
+	mttbl	r4
+
+	/* Kick decrementer */
+	li	r0,1
+	mtdec	r0
+
+	/* Restore the callee-saved registers and return */
+	lwz	r0,SL_CR(r11)
+	mtcr	r0
+	lwz	r2,SL_R2(r11)
+	lmw	r12,SL_R12(r11)
+	lwz	r1,SL_SP(r11)
+	lwz	r0,SL_LR(r11)
+	mtlr	r0
+
+	// XXX Note: we don't really need to call swsusp_resume
+
+	li	r3,0
+	blr
+
+/* FIXME:This construct is actually not useful since we don't shut
+ * down the instruction MMU, we could just flip back MSR-DR on.
+ */
+turn_on_mmu:
+	mflr	r4
+	mtsrr0	r4
+	mtsrr1	r3
+	sync
+	isync
+	rfi
+
diff -Nru linux-2.6.11-a/arch/ppc/kernel/vmlinux.lds.S linux-2.6.11-b/arch/ppc/kernel/vmlinux.lds.S
--- linux-2.6.11-a/arch/ppc/kernel/vmlinux.lds.S	2005-03-02 08:38:34.000000000 +0100
+++ linux-2.6.11-b/arch/ppc/kernel/vmlinux.lds.S	2005-03-04 18:42:16.000000000 +0100
@@ -74,6 +74,12 @@
     CONSTRUCTORS
   }
 
+  . = ALIGN(4096);
+  __nosave_begin = .;
+  .data_nosave : { *(.data.nosave) }
+  . = ALIGN(4096);
+  __nosave_end = .;
+
   . = ALIGN(32);
   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
 
diff -Nru linux-2.6.11-a/arch/ppc/platforms/pmac_setup.c linux-2.6.11-b/arch/ppc/platforms/pmac_setup.c
--- linux-2.6.11-a/arch/ppc/platforms/pmac_setup.c	2005-03-02 08:38:13.000000000 +0100
+++ linux-2.6.11-b/arch/ppc/platforms/pmac_setup.c	2005-03-04 18:42:16.000000000 +0100
@@ -52,6 +52,7 @@
 #include <linux/seq_file.h>
 #include <linux/root_dev.h>
 #include <linux/bitops.h>
+#include <linux/suspend.h>
 
 #include <asm/reg.h>
 #include <asm/sections.h>
@@ -70,6 +71,8 @@
 #include <asm/pmac_feature.h>
 #include <asm/time.h>
 #include <asm/of_device.h>
+#include <asm/mmu_context.h>
+
 #include "pmac_pic.h"
 #include "mem_pieces.h"
 
@@ -421,10 +424,62 @@
 }
 
 static int initializing = 1;
+/* TODO: Merge the suspend-to-ram with the common code !!!
+ * currently, this is a stub implementation for suspend-to-disk
+ * only
+ */
+
+#ifdef CONFIG_SOFTWARE_SUSPEND
+
+static int pmac_pm_prepare(suspend_state_t state)
+{
+	printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
+
+	return 0;
+}
+
+static int pmac_pm_enter(suspend_state_t state)
+{
+	printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
+
+	/* Giveup the lazy FPU & vec so we don't have to back them
+	 * up from the low level code
+	 */
+	enable_kernel_fp();
+
+#ifdef CONFIG_ALTIVEC
+	if (cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC)
+		enable_kernel_altivec();
+#endif /* CONFIG_ALTIVEC */
+
+	return 0;
+}
+
+static int pmac_pm_finish(suspend_state_t state)
+{
+	printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
+
+	/* Restore userland MMU context */
+	set_context(current->active_mm->context, current->active_mm->pgd);
+
+	return 0;
+}
+
+static struct pm_ops pmac_pm_ops = {
+	.pm_disk_mode	= PM_DISK_SHUTDOWN,
+	.prepare	= pmac_pm_prepare,
+	.enter		= pmac_pm_enter,
+	.finish		= pmac_pm_finish,
+};
+
+#endif /* CONFIG_SOFTWARE_SUSPEND */
 
 static int pmac_late_init(void)
 {
 	initializing = 0;
+#ifdef CONFIG_SOFTWARE_SUSPEND
+	pm_set_ops(&pmac_pm_ops);
+#endif /* CONFIG_SOFTWARE_SUSPEND */
 	return 0;
 }
 
diff -Nru linux-2.6.11-a/drivers/macintosh/via-pmu.c linux-2.6.11-b/drivers/macintosh/via-pmu.c
--- linux-2.6.11-a/drivers/macintosh/via-pmu.c	2005-03-02 08:38:25.000000000 +0100
+++ linux-2.6.11-b/drivers/macintosh/via-pmu.c	2005-03-04 18:42:16.000000000 +0100
@@ -43,6 +43,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/device.h>
+#include <linux/sysdev.h>
 #include <linux/suspend.h>
 #include <linux/syscalls.h>
 #include <linux/cpu.h>
@@ -2326,7 +2327,7 @@
 	/* Sync the disks. */
 	/* XXX It would be nice to have some way to ensure that
 	 * nobody is dirtying any new buffers while we wait. That
-	 * could be acheived using the refrigerator for processes
+	 * could be achieved using the refrigerator for processes
 	 * that swsusp uses
 	 */
 	sys_sync();
@@ -2379,7 +2380,6 @@
 
 	/* Wait for completion of async backlight requests */
 	while (!bright_req_1.complete || !bright_req_2.complete ||
-
 			!batt_req.complete)
 		pmu_poll();
 
@@ -3040,6 +3040,88 @@
 }
 #endif /* DEBUG_SLEEP */
 
+
+/* FIXME: This is a temporary set of callbacks to enable us
+ * to do suspend-to-disk.
+ */
+
+#ifdef CONFIG_PM
+
+static int pmu_sys_suspended = 0;
+
+static int pmu_sys_suspend(struct sys_device *sysdev, u32 state)
+{
+	if (state != PM_SUSPEND_DISK || pmu_sys_suspended)
+		return 0;
+
+	/* Suspend PMU event interrupts */
+	pmu_suspend();
+
+	pmu_sys_suspended = 1;
+	return 0;
+}
+
+static int pmu_sys_resume(struct sys_device *sysdev)
+{
+	struct adb_request req;
+
+	if (!pmu_sys_suspended)
+		return 0;
+
+	/* Tell PMU we are ready */
+	pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);
+	pmu_wait_complete(&req);
+
+	/* Resume PMU event interrupts */
+	pmu_resume();
+
+	pmu_sys_suspended = 0;
+
+	return 0;
+}
+
+#endif /* CONFIG_PM */
+
+static struct sysdev_class pmu_sysclass = {
+	set_kset_name("pmu"),
+};
+
+static struct sys_device device_pmu = {
+	.id		= 0,
+	.cls		= &pmu_sysclass,
+};
+
+static struct sysdev_driver driver_pmu = {
+#ifdef CONFIG_PM
+	.suspend	= &pmu_sys_suspend,
+	.resume		= &pmu_sys_resume,
+#endif /* CONFIG_PM */
+};
+
+static int __init init_pmu_sysfs(void)
+{
+	int rc;
+
+	rc = sysdev_class_register(&pmu_sysclass);
+	if (rc) {
+		printk(KERN_ERR "Failed registering PMU sys class\n");
+		return -ENODEV;
+	}
+	rc = sysdev_register(&device_pmu);
+	if (rc) {
+		printk(KERN_ERR "Failed registering PMU sys device\n");
+		return -ENODEV;
+	}
+	rc = sysdev_driver_register(&pmu_sysclass, &driver_pmu);
+	if (rc) {
+		printk(KERN_ERR "Failed registering PMU sys driver\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+subsys_initcall(init_pmu_sysfs);
+
 EXPORT_SYMBOL(pmu_request);
 EXPORT_SYMBOL(pmu_poll);
 EXPORT_SYMBOL(pmu_poll_adb);
diff -Nru linux-2.6.11-a/include/asm-ppc/suspend.h linux-2.6.11-b/include/asm-ppc/suspend.h
--- linux-2.6.11-a/include/asm-ppc/suspend.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.11-b/include/asm-ppc/suspend.h	2005-03-04 18:42:16.000000000 +0100
@@ -0,0 +1,12 @@
+static inline int arch_prepare_suspend(void)
+{
+	return 0;
+}
+
+static inline void save_processor_state(void)
+{
+}
+
+static inline void restore_processor_state(void)
+{
+}
diff -Nru linux-2.6.11-a/include/linux/suspend.h linux-2.6.11-b/include/linux/suspend.h
--- linux-2.6.11-a/include/linux/suspend.h	2005-03-02 08:37:50.000000000 +0100
+++ linux-2.6.11-b/include/linux/suspend.h	2005-03-04 18:42:16.000000000 +0100
@@ -1,7 +1,7 @@
 #ifndef _LINUX_SWSUSP_H
 #define _LINUX_SWSUSP_H
 
-#if defined(CONFIG_X86) || defined(CONFIG_FRV)
+#if defined(CONFIG_X86) || defined(CONFIG_FRV) || defined(CONFIG_PPC32)
 #include <asm/suspend.h>
 #endif
 #include <linux/swap.h>

-- 
- Would you tell me, please, which way I ought to go from here?
- That depends a good deal on where you want to get to.
		-- Lewis Carroll "Alice's Adventures in Wonderland"

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

* Re: [PATCH][3/3] swsusp: use non-contiguous memory
  2005-03-08 12:00             ` Rafael J. Wysocki
@ 2005-03-09 16:00               ` Rafael J. Wysocki
  0 siblings, 0 replies; 8+ messages in thread
From: Rafael J. Wysocki @ 2005-03-09 16:00 UTC (permalink / raw)
  To: Pavel Machek; +Cc: hugang, linux-kernel

Hi,

On Tuesday, 8 of March 2005 13:00, Rafael J. Wysocki wrote:
]-- snip --[ 
> > > Now, akpm sent all (?) swsusp updates to Linus, so it should appear in
> > > bk tree later today. If you could regenerate the patches (1/3 will no
> > > longer be needed) and send them to me & l-k. I'll then forward them to
> > > akpm. [He seems to prefer patches to come from my email address :-)]
> > 
> > OK
> > 
> > Here's the 2/3 one (ie the main resume part).  Do you need the summary?
> 
> Here's the 3/3 one (ie the ppc support from hugang).
> 
> The patches are against 2.6.11 + 1/3 (ie suspend part), but they should
> apply cleanly to the -bk w/ the suspend part as well.

FYI, 2.6.11-kb5 is out and it contains the "suspend" patch.  The patches that
I have sent you apply to it cleanly.

Greets,
Rafael


-- 
- Would you tell me, please, which way I ought to go from here?
- That depends a good deal on where you want to get to.
		-- Lewis Carroll "Alice's Adventures in Wonderland"

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

end of thread, other threads:[~2005-03-09 16:00 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <200503042051.54176.rjw@sisk.pl>
2005-03-07  6:41 ` [PATCH][3/3] swsusp: use non-contiguous memory hugang
2005-03-07 11:32   ` Rafael J. Wysocki
2005-03-07 11:39     ` Andrew Morton
2005-03-07 12:13       ` Rafael J. Wysocki
2005-03-08 10:38         ` Pavel Machek
2005-03-08 11:47           ` Rafael J. Wysocki
2005-03-08 12:00             ` Rafael J. Wysocki
2005-03-09 16:00               ` Rafael J. Wysocki

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox