Hello guys:
I'm try to porting Software Suspend to PowerPC. But I'm not family with
PowerPC assemble languae. So need someone to help me write the save
process state function in assemble language.
1: Download i386 suspend patch for 2.6.1 from swsusp.sf.net
you need two patch
software-suspend-core-2.0-rc4-whole.bz2
software-suspend-linux-2.6.1-rev1-whole.bz2
2: first you need apply linux-2.6.1 to 2.6.1 clean kernel
then apply core-2.0-rc4 to current patched kernel
3: then apply ppc-swsusp.patch to patched kernel
4: do make menuconfig
CONFIG_SOFTWARE_SUSPEND2=y
CONFIG_SOFTWARE_SUSPEND_DEBUG=y
CONFIG_SOFTWARE_SUSPEND_GZIP_COMPRESSION=y
CONFIG_SOFTWARE_SUSPEND_KEEP_IMAGE=y
CONFIG_SOFTWARE_SUSPEND_LZF_COMPRESSION=y
CONFIG_SOFTWARE_SUSPEND_SWAPWRITER=y
5: test with swsusp enable kernel.
in yaboot prompt:
/vmlinux.swsusp root=/dev/hda13 resume2=swap:/dev/hda10 init=/bin/sh
/dev/hda13 is the root device name
/dev/hda10 is swap device name
6: run suspend script to do software suspend, now the machine will power
off.
7: power on machin, in yaboot prompt:
/vmlinux.swsusp root=/dev/hda13 resume2=swap:/dev/hda10 init=/bin/sh
But for now the save and restore processor state is not finish, the
resume will oops.
--
Hu Gang / Steve
Linux Registered User 204016
GPG Public Key: http://soulinfo.com/~hugang/HuGang.asc
Hi.
I'd love to be able to help, but unfortunately the old assembly I know
is good old 6502 :> Hopefully someone else will pipe up and get you
going.
Once you do get it going, I'll be happy to help keep the other parts
updated, so far as I'm able.
Regards,
Nigel
On Mon, 2004-01-19 at 15:52, Hugang wrote:
> Hello guys:
>
> I'm try to porting Software Suspend to PowerPC. But I'm not family with
> PowerPC assemble languae. So need someone to help me write the save
> process state function in assemble language.
>
> 1: Download i386 suspend patch for 2.6.1 from swsusp.sf.net
> you need two patch
> software-suspend-core-2.0-rc4-whole.bz2
> software-suspend-linux-2.6.1-rev1-whole.bz2
> 2: first you need apply linux-2.6.1 to 2.6.1 clean kernel
> then apply core-2.0-rc4 to current patched kernel
> 3: then apply ppc-swsusp.patch to patched kernel
> 4: do make menuconfig
> CONFIG_SOFTWARE_SUSPEND2=y
> CONFIG_SOFTWARE_SUSPEND_DEBUG=y
> CONFIG_SOFTWARE_SUSPEND_GZIP_COMPRESSION=y
> CONFIG_SOFTWARE_SUSPEND_KEEP_IMAGE=y
> CONFIG_SOFTWARE_SUSPEND_LZF_COMPRESSION=y
> CONFIG_SOFTWARE_SUSPEND_SWAPWRITER=y
> 5: test with swsusp enable kernel.
> in yaboot prompt:
> /vmlinux.swsusp root=/dev/hda13 resume2=swap:/dev/hda10 init=/bin/sh
>
> /dev/hda13 is the root device name
> /dev/hda10 is swap device name
>
> 6: run suspend script to do software suspend, now the machine will power
> off.
>
> 7: power on machin, in yaboot prompt:
> /vmlinux.swsusp root=/dev/hda13 resume2=swap:/dev/hda10 init=/bin/sh
>
> But for now the save and restore processor state is not finish, the
> resume will oops.
--
My work on Software Suspend is graciously brought to you by
LinuxFund.org.
Hi !
Some comments...
>Index: arch/ppc/kernel/swsusp2-asm.S
>===================================================================
>--- arch/ppc/kernel/swsusp2-asm.S (revision 0)
>+++ arch/ppc/kernel/swsusp2-asm.S (revision 0)
What is this file ? It's absolutely horrible....
>Index: arch/ppc/kernel/Makefile
>===================================================================
>--- arch/ppc/kernel/Makefile (revision 192)
>+++ arch/ppc/kernel/Makefile (working copy)
>@@ -34,3 +34,5 @@
> obj-$(CONFIG_8xx) += softemu8xx.o
> endif
>
>+obj-$(CONFIG_SOFTWARE_SUSPEND2) += swsusp2-asm.o
>+obj-$(CONFIG_SOFTWARE_SUSPEND2) += ppc_reg.o
You could have put both of these on the same line.
>Index: arch/ppc/kernel/vmlinux.lds.S
>===================================================================
>--- arch/ppc/kernel/vmlinux.lds.S (revision 192)
>+++ arch/ppc/kernel/vmlinux.lds.S (working copy)
>@@ -72,6 +72,12 @@
> CONSTRUCTORS
> }
>
>+ . = ALIGN(4096);
>+ __nosave_begin = .;
>+ .data_nosave : { *(.data.nosave) }
>+ . = ALIGN(4096);
>+ __nosave_end = .;
>+
> . = ALIGN(32);
> .data.cacheline_aligned : { *(.data.cacheline_aligned) }
Why do you need the above for ?
Hi.
I can answer a couple of the questions:
On Mon, 2004-01-19 at 16:35, Benjamin Herrenschmidt wrote:
> What is this file ? It's absolutely horrible....
It should contain the .S equivalent to the swsusp2.c file. It would be
best if swsusp2.c could simply be compiled, but it appears that it can't
at the moment on x86 (I need to learn x86 assembly so I can understand
why).
> >Index: arch/ppc/kernel/vmlinux.lds.S
> >===================================================================
> >--- arch/ppc/kernel/vmlinux.lds.S (revision 192)
> >+++ arch/ppc/kernel/vmlinux.lds.S (working copy)
> >@@ -72,6 +72,12 @@
> > CONSTRUCTORS
> > }
> >
> >+ . = ALIGN(4096);
> >+ __nosave_begin = .;
> >+ .data_nosave : { *(.data.nosave) }
> >+ . = ALIGN(4096);
> >+ __nosave_end = .;
> >+
> > . = ALIGN(32);
> > .data.cacheline_aligned : { *(.data.cacheline_aligned) }
>
> Why do you need the above for ?
That idea is to have a section that doesn't get replaced when we copy
the original kernel back. Thus, small amounts of data that suspend uses
or stores can be given the __nosave attribute. An example is the cpu
frequency value, which should match the boot kernel, not the value at
suspend time.
Regards,
Nigel
--
My work on Software Suspend is graciously brought to you by
LinuxFund.org.
> It should contain the .S equivalent to the swsusp2.c file. It would be
> best if swsusp2.c could simply be compiled, but it appears that it can't
> at the moment on x86 (I need to learn x86 assembly so I can understand
> why).
I see no reason why this would be needed on ppc, only the last step,
that is the actual CPU state save, should matter.
> That idea is to have a section that doesn't get replaced when we copy
> the original kernel back. Thus, small amounts of data that suspend uses
> or stores can be given the __nosave attribute. An example is the cpu
> frequency value, which should match the boot kernel, not the value at
> suspend time.
That's very hairy... You basically assume the boot kernel and the
restore kernel are completely identical, which isn't something I would
do. I didn't have time to dive into it, but I do/did intend to implement
swsusp on ppc and I would eventually resume the whole environement
straight from the bootloader without kernel help.
If you want to pass some infos between the "loader" kernel and the "loaded"
one, I strongly suggest you define some well specified interface for doing
so that is immune to kernel versions.
Also, I haven't looked in details, but when switching to the "new" kernel
from the "loader" (boot) one, do you shut down all devices properly ?
This switch could actually be fairly similar to a kexec pass in this
regard.
Ben.
Hi.
On Tue, 2004-01-20 at 00:39, Benjamin Herrenschmidt wrote:
> I see no reason why this would be needed on ppc, only the last step,
> that is the actual CPU state save, should matter.
Besides saving the CPU state, the code copies the original kernel back.
It sort of defeats the purpose to remove that code :>
> That's very hairy... You basically assume the boot kernel and the
> restore kernel are completely identical, which isn't something I would
> do. I didn't have time to dive into it, but I do/did intend to implement
> swsusp on ppc and I would eventually resume the whole environement
> straight from the bootloader without kernel help.
Well, the whole things is pretty hairy :> But I don't think there's
anything wrong with assuming the boot and restored kernels are
identical. After all, we're calling it suspending and resuming, not
kexec. It does sound nice to do it all from the bootloader without
kernel help.
> If you want to pass some infos between the "loader" kernel and the "loaded"
> one, I strongly suggest you define some well specified interface for doing
> so that is immune to kernel versions.
It is a well defined interface: a section of memory marked nosave, with
variables given the matching attribute. Not my idea, by the way. If you
have a problem, you should be taking it up with Pavel or Linus. We
should also note that the interface can't be too well defined - there
has to be room for development over time.
> Also, I haven't looked in details, but when switching to the "new" kernel
> from the "loader" (boot) one, do you shut down all devices properly ?
> This switch could actually be fairly similar to a kexec pass in this
> regard.
Yes. we device_suspend. Regarding the similarities with kexec, I fully
agree. In fact, there is also LKCD to think off. There should be a
synergy here.
Regards,
Nigel
--
My work on Software Suspend is graciously brought to you by
LinuxFund.org.
On Tue, 2004-01-20 at 04:56, Nigel Cunningham wrote:
> Hi.
>
> On Tue, 2004-01-20 at 00:39, Benjamin Herrenschmidt wrote:
> > I see no reason why this would be needed on ppc, only the last step,
> > that is the actual CPU state save, should matter.
>
> Besides saving the CPU state, the code copies the original kernel back.
> It sort of defeats the purpose to remove that code :>
Ok, you mean copying the memory pages back down ? That should be done
with hand-made assembly or C code located specifically elsewhere then.
I do not want to see any kind of this ugly C-generated assembly in
arch/ppc.
> Well, the whole things is pretty hairy :> But I don't think there's
> anything wrong with assuming the boot and restored kernels are
> identical. After all, we're calling it suspending and resuming, not
> kexec. It does sound nice to do it all from the bootloader without
> kernel help.
I think that's a wrong assumption. I see personally _NO_ reason to
assume the boot and restored kernel are the same. They absolutely
don't need to do at all.
> It is a well defined interface: a section of memory marked nosave, with
> variables given the matching attribute. Not my idea, by the way. If you
> have a problem, you should be taking it up with Pavel or Linus. We
> should also note that the interface can't be too well defined - there
> has to be room for development over time.
Still... That makes assumptions about how it's located and organised
that plain wrong (c). Please get rid of that, at least I won't let a PPC
version do that. Depending on how much time I can spare, I'll try to
work on that PPC port later this week. If you need something like clock
calibration data down to the loaded kernel, then either re-calculate it
in the wakeup code path, or pass it via some _sane_ interface (at
_least_ a versioned data structure, better, a tagged list of values like
some bootloaders do).
> Yes. we device_suspend. Regarding the similarities with kexec, I fully
> agree. In fact, there is also LKCD to think off. There should be a
> synergy here.
device_suspend is, imho, hairy too. We have some semantics that need
cleanup here, I'll have to talk to Patrick about them. Putting devices
to an idle state is what you need and what kexec need, and doesn't mean
putting them to _sleep_. Or maybe we could pass a specific state to
device_suspend for that. For example, it makes little sense to spin down
the hard disk at this stage, or to power off the video chip...
Ben.
Hi!
> > That idea is to have a section that doesn't get replaced when we copy
> > the original kernel back. Thus, small amounts of data that suspend uses
> > or stores can be given the __nosave attribute. An example is the cpu
> > frequency value, which should match the boot kernel, not the value at
> > suspend time.
>
> That's very hairy... You basically assume the boot kernel and the
> restore kernel are completely identical, which isn't something I would
> do. I didn't have time to dive into it, but I do/did intend to implement
> swsusp on ppc and I would eventually resume the whole environement
> straight from the bootloader without kernel help.
Well, then what you do is not swsusp.
swsusp does assume same kernel during suspend and resume. Doing resume
within bootloader (and thus avoiding this) would be completely
different design.
> Also, I haven't looked in details, but when switching to the "new" kernel
> from the "loader" (boot) one, do you shut down all devices properly ?
> This switch could actually be fairly similar to a kexec pass in this
> regard.
I hope we do shut devices down. In my tree at least.
Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]
Hi!
> I can answer a couple of the questions:
>
> > What is this file ? It's absolutely horrible....
>
> It should contain the .S equivalent to the swsusp2.c file. It would be
> best if swsusp2.c could simply be compiled, but it appears that it can't
> at the moment on x86 (I need to learn x86 assembly so I can understand
> why).
You need to check resulting assembly for stack accesses. So yes, you
can compile it from .c file, _but you have to read it_.
Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]
> You need to check resulting assembly for stack accesses. So yes, you
> can compile it from .c file, _but you have to read it_.
Hrm... That's awful and terribly fragile. You should either write
it entirely in assembly (thus readable & commented) or write it in
C with a temporary stack or whatever that makes it safe. I'll certainly
not let something like that sneak into arch/ppc anyway.
Ben.
> Well, then what you do is not swsusp.
>
> swsusp does assume same kernel during suspend and resume. Doing resume
> within bootloader (and thus avoiding this) would be completely
> different design.
Wait... what the hell in swsusp requires this assumption ? It seems to
me like a completely unnecessary design limitation.
Ben.
Hi!
> > Well, then what you do is not swsusp.
> >
> > swsusp does assume same kernel during suspend and resume. Doing resume
> > within bootloader (and thus avoiding this) would be completely
> > different design.
>
> Wait... what the hell in swsusp requires this assumption ? It seems to
> me like a completely unnecessary design limitation.
(1) There's routine during resume that copies pages to their old
locations. If you (would want to) have different kernel during resume,
how do you guarantee that that "kernel being resumed" does not use
memory ocupied by copying routine?
(2) Plus number of problems with devices grows with number of versions
squared. To guarantee it works properly you'd have to test all
combinations of "suspend kernel" and "resume kernel".
[(1) Could be solved by reserving 4KB somewhere for copy routine, and
making sure copy routine is never bigger than 4KB etc. But I'd like to
keep it simple and really don't want to deal with (2).]
Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]
> (1) There's routine during resume that copies pages to their old
> locations. If you (would want to) have different kernel during resume,
> how do you guarantee that that "kernel being resumed" does not use
> memory ocupied by copying routine?
By having the copy routine sit elsewhere. You can have the copy routine
be in a known location of the kernel beeing resumed (that is it uses
its own copy routine) that is aligned on a page boundary and knows how
to copy itself. Fairly trivial.
> (2) Plus number of problems with devices grows with number of versions
> squared. To guarantee it works properly you'd have to test all
> combinations of "suspend kernel" and "resume kernel".
Why ? You aren't passing any device/driver information from the boot
kernel and the resumed one... do you ?
> [(1) Could be solved by reserving 4KB somewhere for copy routine, and
> making sure copy routine is never bigger than 4KB etc. But I'd like to
> keep it simple and really don't want to deal with (2).]
Then you don't wnat to do things properly...
Ben.
Hi!
> > You need to check resulting assembly for stack accesses. So yes, you
> > can compile it from .c file, _but you have to read it_.
>
> Hrm... That's awful and terribly fragile. You should either write
> it entirely in assembly (thus readable & commented) or write it in
Take a look before commenting.
Long time ago I took .c version, compiled it into assembly,
handcleaned (etc) and now its used.
But if someone wants to do ppc, taking .c version, compiling it into
assembly, then checking/fixing is probably easiest way...
Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]
On Tue, 20 Jan 2004, Benjamin Herrenschmidt wrote:
> > Well, then what you do is not swsusp.
> >
> > swsusp does assume same kernel during suspend and resume. Doing resume
> > within bootloader (and thus avoiding this) would be completely
> > different design.
>
> Wait... what the hell in swsusp requires this assumption ? It seems to
> me like a completely unnecessary design limitation.
Swsusp saves the data structures from the suspended kernel, so they have to
match the data structures of the resumed kernel, right?
I't s a bit like trying insmod -f on a module compiled for a completely
different kernel version... *bang*
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
Hi!
> > > Well, then what you do is not swsusp.
> > >
> > > swsusp does assume same kernel during suspend and resume. Doing resume
> > > within bootloader (and thus avoiding this) would be completely
> > > different design.
> >
> > Wait... what the hell in swsusp requires this assumption ? It seems to
> > me like a completely unnecessary design limitation.
>
> Swsusp saves the data structures from the suspended kernel, so they have to
> match the data structures of the resumed kernel, right?
Well, *all* the data pages are saved, so that would be okay (even if
they changed, as I'm replacing all the data pages, that should work),
but I'm not saving kernel text for example.
Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]
Hi!
> > (1) There's routine during resume that copies pages to their old
> > locations. If you (would want to) have different kernel during resume,
> > how do you guarantee that that "kernel being resumed" does not use
> > memory ocupied by copying routine?
>
> By having the copy routine sit elsewhere. You can have the copy routine
> be in a known location of the kernel beeing resumed (that is it uses
> its own copy routine) that is aligned on a page boundary and knows how
> to copy itself. Fairly trivial.
I said it is possible to solve. But "copy routine" becomes even more
nasty than it is already.
> > (2) Plus number of problems with devices grows with number of versions
> > squared. To guarantee it works properly you'd have to test all
> > combinations of "suspend kernel" and "resume kernel".
>
> Why ? You aren't passing any device/driver information from the boot
> kernel and the resumed one... do you ?
I'm not passing device information, but devices *do* have internal
state. I quiesce them before booting new kernel, but there's probably
more than one way to quiesce devices...
> > [(1) Could be solved by reserving 4KB somewhere for copy routine, and
> > making sure copy routine is never bigger than 4KB etc. But I'd like to
> > keep it simple and really don't want to deal with (2).]
>
> Then you don't wnat to do things properly...
No, I really do not want to make things more complicated in 2.6. And
you should not want to complicate it, too.
Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]
On Tue, 2004-01-20 at 21:04, Pavel Machek wrote:
> Well, *all* the data pages are saved, so that would be okay (even if
> they changed, as I'm replacing all the data pages, that should work),
> but I'm not saving kernel text for example.
Ahh... that's an interesting point. You aren't saving kernel text. I'm
not sure how that could be a problem for me. I think i'll just save it
along with the image though. I think there is much risk screwing up
because an uncompatible boot/load kernel pair here than because devices
aren't fully idle.
Ben.
Hi!
> > Well, *all* the data pages are saved, so that would be okay (even if
> > they changed, as I'm replacing all the data pages, that should work),
> > but I'm not saving kernel text for example.
>
> Ahh... that's an interesting point. You aren't saving kernel text. I'm
> not sure how that could be a problem for me. I think i'll just save it
> along with the image though.
Also pay attetion to page tables. I know that page tables "copy"
routine is running from are same between suspend and resume kernel.
Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]
> I'm not passing device information, but devices *do* have internal
> state. I quiesce them before booting new kernel, but there's probably
> more than one way to quiesce devices...
Not that many. You don't quite know in what state they are when
the BIOS calls you neither in most cases :) Nor when waking up
from BIOS-managed state.... It's usually safe if they just don't
bust master and are idle.
> No, I really do not want to make things more complicated in 2.6. And
> you should not want to complicate it, too.
I will not impose that limitation on a ppc implementation. I don't
even want to load the resume image from the boot kernel, it's much more
easier to load it from the bootloader for me anyway. And the copy routine
is just a tricky bit of asm, not even _that_ tricky I'd say (well, I don't
do x86 asm, but I've certainly had to deal with more tricky stuffs on
ppc so far).
Ben.
> Swsusp saves the data structures from the suspended kernel, so they have to
> match the data structures of the resumed kernel, right?
>
> I't s a bit like trying insmod -f on a module compiled for a completely
> different kernel version... *bang*
No, swsusp saves the whole memory image, including the old kernel. The
"boot" kernel is only used as a loader until all pages are put back in
place and control can be given back to the old kernel. Well, that might
not exactly be what x86 does but that's definitely waht I'll do on PPC :)
Ben.
Hi!
> > No, I really do not want to make things more complicated in 2.6. And
> > you should not want to complicate it, too.
>
> I will not impose that limitation on a ppc implementation. I don't
> even want to load the resume image from the boot kernel, it's much more
> easier to load it from the bootloader for me anyway. And the copy
> routine
Well, if you have just one common bootloader on ppc, no problem, go
ahead at load it from bootloader. You'll not have to worry about page
tables etc. I could not do that on i386 because there are many
bootloaders in use here.
You are going to have completely different resume phase, through. [And
if someone wants suspend-to-disk on ppc, *now*, it might still be
easiest to write those two screens of assembly to port swsusp to ppc.]
Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]
On Tue, 2004-01-20 at 22:36, Pavel Machek wrote:
> Hi!
>
> > > Well, *all* the data pages are saved, so that would be okay (even if
> > > they changed, as I'm replacing all the data pages, that should work),
> > > but I'm not saving kernel text for example.
> >
> > Ahh... that's an interesting point. You aren't saving kernel text. I'm
> > not sure how that could be a problem for me. I think i'll just save it
> > along with the image though.
>
> Also pay attetion to page tables. I know that page tables "copy"
> routine is running from are same between suspend and resume kernel.
I plan to run everything provided by the suspended kernel actually. My idea
is to keep a handle to a page of the suspended kernel that contains that
code and just kick into it. Copying pages to their final location without
overriding the source pages is a bit of a funky job, but I had to do it
already with BootX so ... I'll work on that during one of the upcoming few
weeks hopefully, I'm a bit swamped with 3 different things at the moment.
ben.
Hi!
> > > > Well, *all* the data pages are saved, so that would be okay (even if
> > > > they changed, as I'm replacing all the data pages, that should work),
> > > > but I'm not saving kernel text for example.
> > >
> > > Ahh... that's an interesting point. You aren't saving kernel text. I'm
> > > not sure how that could be a problem for me. I think i'll just save it
> > > along with the image though.
> >
> > Also pay attetion to page tables. I know that page tables "copy"
> > routine is running from are same between suspend and resume kernel.
>
> I plan to run everything provided by the suspended kernel actually. My idea
> is to keep a handle to a page of the suspended kernel that contains that
> code and just kick into it. Copying pages to their final location without
> overriding the source pages is a bit of a funky job, but I had to do it
> already with BootX so ... I'll work on that during one of the upcoming few
> weeks hopefully, I'm a bit swamped with 3 different things at the
> moment.
You actually *know* that half of memory is free during resume, so you
can load kernel-to-be-resumed data into that free memory. That's how
swsusp works. It makes it quite simple...
Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]
I'm really interested to see how you are going to initiate and execute
the suspend.
Perhaps I'm just ignorant, but I can't see how you can do it without
resorting to the same tricks we use now with regards to CPU context. I
think you're going to find yourself reinventing the wheel.
Regards,
Nigel
> I plan to run everything provided by the suspended kernel actually. My idea
> is to keep a handle to a page of the suspended kernel that contains that
> code and just kick into it. Copying pages to their final location without
> overriding the source pages is a bit of a funky job, but I had to do it
> already with BootX so ... I'll work on that during one of the upcoming few
> weeks hopefully, I'm a bit swamped with 3 different things at the moment.
>
> ben.
>
--
My work on Software Suspend is graciously brought to you by
LinuxFund.org.
Hi!
> > On Tue, 2004-01-20 at 00:39, Benjamin Herrenschmidt wrote:
> > > I see no reason why this would be needed on ppc, only the last step,
> > > that is the actual CPU state save, should matter.
> >
> > Besides saving the CPU state, the code copies the original kernel back.
> > It sort of defeats the purpose to remove that code :>
>
> Ok, you mean copying the memory pages back down ? That should be done
> with hand-made assembly or C code located specifically elsewhere then.
> I do not want to see any kind of this ugly C-generated assembly in
> arch/ppc.
FYI, this is that "ugly C-generated assembly" we are talking about. I
do not think it is so bad.
.text
/* Originally gcc generated, modified by hand */
#include <linux/linkage.h>
#include <asm/segment.h>
#include <asm/page.h>
.text
ENTRY(do_magic)
pushl %ebx
cmpl $0,8(%esp)
jne .L1450
call do_magic_suspend_1
call save_processor_state
movl %esp, saved_context_esp
movl %eax, saved_context_eax
movl %ebx, saved_context_ebx
movl %ecx, saved_context_ecx
movl %edx, saved_context_edx
movl %ebp, saved_context_ebp
movl %esi, saved_context_esi
movl %edi, saved_context_edi
pushfl ; popl saved_context_eflags
call do_magic_suspend_2
jmp .L1449
.p2align 4,,7
.L1450:
movl $swapper_pg_dir-__PAGE_OFFSET,%ecx
movl %ecx,%cr3
call do_magic_resume_1
movl $0,loop
cmpl $0,nr_copy_pages
je .L1453
.p2align 4,,7
.L1455:
movl $0,loop2
.p2align 4,,7
.L1459:
movl pagedir_nosave,%ecx
movl loop,%eax
movl loop2,%edx
sall $4,%eax
movl 4(%ecx,%eax),%ebx
movl (%ecx,%eax),%eax
movb (%edx,%eax),%al
movb %al,(%edx,%ebx)
movl %cr3, %eax;
movl %eax, %cr3; # flush TLB
movl loop2,%eax
leal 1(%eax),%edx
movl %edx,loop2
movl %edx,%eax
cmpl $4095,%eax
jbe .L1459
movl loop,%eax
leal 1(%eax),%edx
movl %edx,loop
movl %edx,%eax
cmpl nr_copy_pages,%eax
jb .L1455
.p2align 4,,7
.L1453:
movl $__USER_DS,%eax
movw %ax, %ds
movw %ax, %es
movl saved_context_esp, %esp
movl saved_context_ebp, %ebp
movl saved_context_eax, %eax
movl saved_context_ebx, %ebx
movl saved_context_ecx, %ecx
movl saved_context_edx, %edx
movl saved_context_esi, %esi
movl saved_context_edi, %edi
call restore_processor_state
pushl saved_context_eflags ; popfl
call do_magic_resume_2
.L1449:
popl %ebx
ret
.section .data.nosave
loop:
.quad 0
loop2:
.quad 0
.previous
> > It is a well defined interface: a section of memory marked nosave, with
> > variables given the matching attribute. Not my idea, by the way. If you
> > have a problem, you should be taking it up with Pavel or Linus. We
> > should also note that the interface can't be too well defined - there
> > has to be room for development over time.
>
> Still... That makes assumptions about how it's located and organised
> that plain wrong (c). Please get rid of that, at least I won't let a
> PPC
FYI, there are exactly 6 variables in "nosave" section. Two loop
variables you can see in above code, one spinlock, number of pages to
save, pointer to directory of pages to be copied, and its length.
I could probably move spinlock and length of pgdir out of there...
> > Yes. we device_suspend. Regarding the similarities with kexec, I fully
> > agree. In fact, there is also LKCD to think off. There should be a
> > synergy here.
>
> device_suspend is, imho, hairy too. We have some semantics that need
> cleanup here, I'll have to talk to Patrick about them. Putting devices
> to an idle state is what you need and what kexec need, and doesn't mean
> putting them to _sleep_. Or maybe we could pass a specific state to
Okay, I can agree that putting them into sleep is not ideal [it
puzzles users, at least]. But it is quite simple and should work
okay. I do not want another round of device_suspend changes in
2.6.X... [Well, perhaps if it was done in right&compatible way (tm),
it would be acceptable...]
Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]
On Wed, 2004-01-21 at 05:30, Nigel Cunningham wrote:
> I'm really interested to see how you are going to initiate and execute
> the suspend.
>
> Perhaps I'm just ignorant, but I can't see how you can do it without
> resorting to the same tricks we use now with regards to CPU context. I
> think you're going to find yourself reinventing the wheel.
CPU context ? I don't think swsusp needs anything different than
suspend-to-RAM in this regard (at least the pmac version of suspend-to
-RAM that wakes up on a CPU reset). The CPU setup will be saved as part
of the kernel data and will be restored after the pages are back in
place the same way it is restored when waking up from RAM. The code
is already there (and actually, that ppc port of swsusp borrowed it).
Ben.
> FYI, this is that "ugly C-generated assembly" we are talking about. I
> do not think it is so bad.
The x86 version has been cleaned up and isn't _that_ bad, though it
could definitely use some comments and I don't like the "Lxxx" labels,
I'd rather either use number with the "nb" or "nf" GAS constructs or
use real words labels. Looking at it though, I fail to see the need
to get it generated by gcc in the first place :)
The PPC version that was proposed is horrible.
> FYI, there are exactly 6 variables in "nosave" section. Two loop
> variables you can see in above code, one spinlock, number of pages to
> save, pointer to directory of pages to be copied, and its length.
>
> I could probably move spinlock and length of pgdir out of there...
That's not too much, you could probably afford having a one page header
to the suspend image with those informations and the page copy loop
(provided by the suspended kernel so you don't have _any_ compatibility
issue and can even do it from the bootloader one day...)
> > device_suspend is, imho, hairy too. We have some semantics that need
> > cleanup here, I'll have to talk to Patrick about them. Putting devices
> > to an idle state is what you need and what kexec need, and doesn't mean
> > putting them to _sleep_. Or maybe we could pass a specific state to
>
> Okay, I can agree that putting them into sleep is not ideal [it
> puzzles users, at least]. But it is quite simple and should work
> okay. I do not want another round of device_suspend changes in
> 2.6.X... [Well, perhaps if it was done in right&compatible way (tm),
> it would be acceptable...]
We already have the shutdown() callback or we can simply use device_suspend()
with a D1 parameter instead of D3 or D4. That's what I'd do...
Looking at swsusp code in current 2.6, when do you do that pass ? On the
shutdown pass, you call devices_suspend(4); which is fine. But I don't see
where you call devices_suspend(X) on the resume path. IMHO, that should be
done from the boot kernel after loading the suspend image and before
starting the resume process. Your mdelay(1000) for waiting for DMA to settle
down is PLAIN WRONG imho, even dangerous. (And typically, an USB controller
will still be hapilly be DMA'ing all over your memory). That's what I call
idling devices at this point, and that's where I'd call devices_suspend(1),
and we should do that for kexec too.
Ben.
Hi.
On Wed, 2004-01-21 at 10:54, Benjamin Herrenschmidt wrote:
> > FYI, this is that "ugly C-generated assembly" we are talking about. I
> > do not think it is so bad.
>
> The x86 version has been cleaned up and isn't _that_ bad, though it
> could definitely use some comments and I don't like the "Lxxx" labels,
> I'd rather either use number with the "nb" or "nf" GAS constructs or
> use real words labels. Looking at it though, I fail to see the need
> to get it generated by gcc in the first place :)
The 2.4 version works from C, even the SMP version I've prepared.
Something in 2.6 is different, and I don't understand what/why (Pavel
might be able to explain). If I understood that, I could get SMP support
for 2.6 going too.
> The PPC version that was proposed is horrible.
I think he wanted help with cleaning it up.
> > FYI, there are exactly 6 variables in "nosave" section. Two loop
> > variables you can see in above code, one spinlock, number of pages to
> > save, pointer to directory of pages to be copied, and its length.
> >
> > I could probably move spinlock and length of pgdir out of there...
>
> That's not too much, you could probably afford having a one page header
> to the suspend image with those informations and the page copy loop
> (provided by the suspended kernel so you don't have _any_ compatibility
> issue and can even do it from the bootloader one day...)
Well, we do have a header at the moment with that info, (but not
containing the page copy loop :>)
> Looking at swsusp code in current 2.6, when do you do that pass ? On the
> shutdown pass, you call devices_suspend(4); which is fine. But I don't see
> where you call devices_suspend(X) on the resume path. IMHO, that should be
Hmm. Perhaps it's just my version that does it? I couldn't find it
either.
Regards,
Nigel
--
My work on Software Suspend is graciously brought to you by
LinuxFund.org.
Hi!
> > FYI, this is that "ugly C-generated assembly" we are talking about. I
> > do not think it is so bad.
>
> The x86 version has been cleaned up and isn't _that_ bad, though it
> could definitely use some comments and I don't like the "Lxxx" labels,
> I'd rather either use number with the "nb" or "nf" GAS constructs or
> use real words labels. Looking at it though, I fail to see the need
> to get it generated by gcc in the first place :)
Well, I had C version that was working (and it was slightly easier to
code it in C), and really did not want to introduce errors at that
point.
> The PPC version that was proposed is horrible.
Sorry, I missed that one.
> > FYI, there are exactly 6 variables in "nosave" section. Two loop
> > variables you can see in above code, one spinlock, number of pages to
> > save, pointer to directory of pages to be copied, and its length.
> >
> > I could probably move spinlock and length of pgdir out of there...
>
> That's not too much, you could probably afford having a one page header
> to the suspend image with those informations and the page copy loop
> (provided by the suspended kernel so you don't have _any_ compatibility
> issue and can even do it from the bootloader one day...)
Unfortunately the copy loop has quite complicated interface. It
expects tables already loaded into memory, at non-conflicting
addresses etc.
> > > device_suspend is, imho, hairy too. We have some semantics that need
> > > cleanup here, I'll have to talk to Patrick about them. Putting devices
> > > to an idle state is what you need and what kexec need, and doesn't mean
> > > putting them to _sleep_. Or maybe we could pass a specific state to
> >
> > Okay, I can agree that putting them into sleep is not ideal [it
> > puzzles users, at least]. But it is quite simple and should work
> > okay. I do not want another round of device_suspend changes in
> > 2.6.X... [Well, perhaps if it was done in right&compatible way (tm),
> > it would be acceptable...]
>
> We already have the shutdown() callback or we can simply use device_suspend()
> with a D1 parameter instead of D3 or D4. That's what I'd do...
We need to do something with those 1,3s and 4s. IIRC there's no such
thing as D4 (or is it expected to be == D3cold?). This needs to be
documented somewhere.
> Looking at swsusp code in current 2.6, when do you do that pass ? On the
> shutdown pass, you call devices_suspend(4); which is fine. But I don't see
> where you call devices_suspend(X) on the resume path. IMHO, that
> should be
My fault, the patch is in my tree only. (Its here for quite a long
time. I synced it to Patrick and then he disappeared.).
> done from the boot kernel after loading the suspend image and before
> starting the resume process. Your mdelay(1000) for waiting for DMA to settle
> down is PLAIN WRONG imho, even dangerous. (And typically, an USB controller
> will still be hapilly be DMA'ing all over your memory). That's what I call
> idling devices at this point, and that's where I'd call devices_suspend(1),
> and we should do that for kexec too.
Yes, that's right solution. Here's the patch.
Index: linux/kernel/power/swsusp.c
===================================================================
--- linux.orig/kernel/power/swsusp.c 2004-01-13 22:52:40.000000000 +0100
+++ linux/kernel/power/swsusp.c 2004-01-09 20:33:05.000000000 +0100
@@ -488,33 +492,6 @@
printk("|\n");
}
-/* Make disk drivers accept operations, again */
-static void drivers_unsuspend(void)
-{
- device_resume();
-}
-
-/* Called from process context */
-static int drivers_suspend(void)
-{
- return device_suspend(4);
-}
-
-#define RESUME_PHASE1 1 /* Called from interrupts disabled */
-#define RESUME_PHASE2 2 /* Called with interrupts enabled */
-#define RESUME_ALL_PHASES (RESUME_PHASE1 | RESUME_PHASE2)
-static void drivers_resume(int flags)
-{
- if (flags & RESUME_PHASE1) {
- device_resume();
- }
- if (flags & RESUME_PHASE2) {
-#ifdef SUSPEND_CONSOLE
- update_screen(fg_console); /* Hmm, is this the problem? */
-#endif
- }
-}
-
static int suspend_prepare_image(void)
{
struct sysinfo i;
@@ -569,7 +546,7 @@
static void suspend_save_image(void)
{
- drivers_unsuspend();
+ device_resume();
lock_swapdevices();
write_suspend_image();
@@ -615,6 +592,7 @@
mb();
spin_lock_irq(&suspend_pagedir_lock); /* Done to disable interrupts */
+ device_power_down(4);
PRINTK( "Waiting for DMAs to settle down...\n");
mdelay(1000); /* We do not want some readahead with DMA to corrupt our memory, right?
Do it with disabled interrupts for best effect. That way, if some
@@ -630,8 +608,10 @@
PRINTK( "Freeing prev allocated pagedir\n" );
free_suspend_pagedir((unsigned long) pagedir_save);
+ device_power_up();
spin_unlock_irq(&suspend_pagedir_lock);
- drivers_resume(RESUME_ALL_PHASES);
+ device_resume();
+ update_screen(fg_console); /* Hmm, is this the problem? */
PRINTK( "Fixing swap signatures... " );
mark_swapfiles(((swp_entry_t) {0}), MARK_SWAP_RESUME);
@@ -672,7 +652,9 @@
{
int is_problem;
read_swapfiles();
+ device_power_down(4);
is_problem = suspend_prepare_image();
+ device_power_up();
spin_unlock_irq(&suspend_pagedir_lock);
if (!is_problem) {
kernel_fpu_end(); /* save_processor_state() does kernel_fpu_begin, and we need to revert it in order to pass in_atomic() checks */
@@ -716,7 +709,7 @@
blk_run_queues();
/* Save state of all device drivers, and stop them. */
- if(drivers_suspend()==0)
+ if ((res = device_suspend(4))==0)
/* If stopping device drivers worked, we proceed basically into
* suspend_save_image.
*
@@ -1091,6 +1072,7 @@
printk( "resuming from %s\n", resume_file);
if (read_suspend_image(resume_file, 0))
goto read_failure;
+ device_suspend(4);
do_magic(1);
panic("This never returns");
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]
I know nothing about the PPC. Is it a uniprocessor?
Regards,
Nigel
--
My work on Software Suspend is graciously brought to you by
LinuxFund.org.
On Tue, 20 Jan 2004 09:03:11 +1100
Benjamin Herrenschmidt <[email protected]> wrote:
> On Tue, 2004-01-20 at 04:56, Nigel Cunningham wrote:
> > Hi.
> >
> > On Tue, 2004-01-20 at 00:39, Benjamin Herrenschmidt wrote:
> > > I see no reason why this would be needed on ppc, only the last
> > > step, that is the actual CPU state save, should matter.
> >
> > Besides saving the CPU state, the code copies the original kernel
> > back. It sort of defeats the purpose to remove that code :>
>
Attached file is current version of port swsusp to ppc, STILL can not
works, Benjamin, gave me some comments.
I has add one files swsusp2-asm.S. The save/restore processor state base
on pmac_sleep.S. The copybackup is copy from gcc generate assmeble.
Now the suspend has no problem, resume can not works, strange.
--
Hu Gang / Steve
Linux Registered User 204016
GPG Public Key: http://soulinfo.com/~hugang/HuGang.asc
On Fri, 23 Jan 2004 06:53:26 +1300
Nigel Cunningham <[email protected]> wrote:
> I know nothing about the PPC. Is it a uniprocessor?
>
> Regards,
>
> Nigel
There is a document abourt ppc, that can download from Moto,
It help me to understand what is ppc, cool.
http://soulinfo.com/~hugang/tmp/MPCFPE_AD_R1.pdf
--
Hu Gang / Steve
Linux Registered User 204016
GPG Public Key: http://soulinfo.com/~hugang/HuGang.asc
> Attached file is current version of port swsusp to ppc, STILL can not
> works, Benjamin, gave me some comments.
>
> I has add one files swsusp2-asm.S. The save/restore processor state base
> on pmac_sleep.S. The copybackup is copy from gcc generate assmeble.
>
> Now the suspend has no problem, resume can not works, strange.
There is at least one reason I think your code cannot work: When
resuming, you are basically blowing up the MMU hash table and kernel
page tables when copying the pages. I'm hacking on an implementation
of pmdisk at the moment that switches the MMU off during the page
copy to avoid that problem. This isn't the best way though.
I'll keep you informed of my progress
Ben.
On Fri, 23 Jan 2004 18:12:53 +1100
Benjamin Herrenschmidt <[email protected]> wrote:
> There is at least one reason I think your code cannot work: When
> resuming, you are basically blowing up the MMU hash table and kernel
> page tables when copying the pages. I'm hacking on an implementation
> of pmdisk at the moment that switches the MMU off during the page
> copy to avoid that problem. This isn't the best way though.
I has hacking on swsusp2 to ppc for whole day. Here is the update
swsusp2-asm.S.
First I can true suspend is ok, the data and CPU context are full write
to disk. Then in resume, the copyback function works.
How I know it?
I'm adding printk before do_swsusp2_lowleve finished, I has printf
the r1, That is the pointer to cpu context, it must right on resume,
when resume it'll triger xmon, I d pm_sleep_storage, and check the
pointer, I see that same things, So I true the copyback is ok, at least
the cpu context memory has backed.
very tire day.
The current problem that is, In resume, It stop with all register
(r0-r32) is zero. I don't known where I am. :)
> I'll keep you informed of my progress
I'm too. :)
--
Hu Gang / Steve
Linux Registered User 204016
GPG Public Key: http://soulinfo.com/~hugang/HuGang.asc
Ok, I hammered that for a day and got pmdisk (patrick's version) suspending
and resuming on a pismo G3 (with XFree etc.. running). Lots of rough edges
still (via-pmu sleep need to be improved, ADB need porting to the new driver
model to be properly suspended/resumed, a sysdev for RTC is needed too for
time, the asm code should be fixed for G5, etc...)
I had to fix some issues in the core pmdisk code though. One big one is that
lots of drivers expect suspend to disk to be state 4 while the current code
used state 3 for that (and suspend to RAM to be state 3 btw). I hacked that
in include/linux/suspend.h, but we shall probably just get rid of those
stupid numbers and properly define each constant indstead.
We should also use a different state for the suspend calls done before saving
the image, and the ones done before resuming the image, some driver may be
optimized for these cases.
The patch is against my tree currently, and the arch/ppc/kernel/pmdisk.S file
is appended as-is (not in patch form). I don't plan to release that right now,
I may hack a bit on it in the "background" (I want to get HIGHMEM working
some day). Feel free to improve, but then keep me informed please.
Ah, also: The "Freeing memory" phase takes forever. That should really be fixed.
Ben.
First the patch:
===== arch/ppc/Kconfig 1.60 vs edited =====
--- 1.60/arch/ppc/Kconfig Wed Jan 21 11:29:19 2004
+++ edited/arch/ppc/Kconfig Fri Jan 23 17:03:20 2004
@@ -913,6 +913,8 @@
source "drivers/zorro/Kconfig"
+source kernel/power/Kconfig
+
endmenu
menu "Bus options"
===== arch/ppc/kernel/Makefile 1.61 vs edited =====
--- 1.61/arch/ppc/kernel/Makefile Wed Jan 21 11:29:20 2004
+++ edited/arch/ppc/kernel/Makefile Fri Jan 23 16:57:28 2004
@@ -15,6 +15,7 @@
extra-$(CONFIG_8xx) := head_8xx.o
extra-$(CONFIG_6xx) += idle_6xx.o
extra-$(CONFIG_POWER4) += idle_power4.o
+
extra-y += vmlinux.lds.s
obj-y := entry.o traps.o irq.o idle.o time.o misc.o \
@@ -22,6 +23,7 @@
semaphore.o syscalls.o setup.o \
cputable.o ppc_htab.o
obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o
+obj-$(CONFIG_PM_DISK) += pmdisk.o
obj-$(CONFIG_POWER4) += cpu_setup_power4.o
obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o
obj-$(CONFIG_PCI) += pci.o
===== arch/ppc/kernel/signal.c 1.37 vs edited =====
--- 1.37/arch/ppc/kernel/signal.c Fri Nov 28 12:13:45 2003
+++ edited/arch/ppc/kernel/signal.c Fri Jan 23 18:47:07 2004
@@ -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>
@@ -563,6 +564,11 @@
struct k_sigaction *ka;
unsigned long frame, newsp;
int signr, ret;
+
+ if (current->flags & PF_FREEZE) {
+ refrigerator(0);
+ return 0;
+ }
if (!oldset)
oldset = ¤t->blocked;
===== arch/ppc/kernel/vmlinux.lds.S 1.39 vs edited =====
--- 1.39/arch/ppc/kernel/vmlinux.lds.S Mon Nov 17 12:29:47 2003
+++ edited/arch/ppc/kernel/vmlinux.lds.S Fri Jan 23 18:26:26 2004
@@ -72,6 +72,12 @@
CONSTRUCTORS
}
+ . = ALIGN(4096);
+ __nosave_begin = .;
+ .data_nosave : { *(.data.nosave) }
+ . = ALIGN(4096);
+ __nosave_end = .;
+
. = ALIGN(32);
.data.cacheline_aligned : { *(.data.cacheline_aligned) }
===== arch/ppc/platforms/pmac_setup.c 1.48 vs edited =====
--- 1.48/arch/ppc/platforms/pmac_setup.c Sat Nov 1 12:36:52 2003
+++ edited/arch/ppc/platforms/pmac_setup.c Fri Jan 23 18:08:18 2004
@@ -51,6 +51,7 @@
#include <linux/irq.h>
#include <linux/seq_file.h>
#include <linux/root_dev.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"
@@ -425,11 +428,65 @@
#endif
}
+/* TODO: Merge the suspend-to-ram with the common code !!!
+ * currently, this is a stub implementation for suspend-to-disk
+ * only
+ */
+
+#ifdef CONFIG_PM_DISK
+
+static int pmac_pm_prepare(u32 state)
+{
+ printk(KERN_DEBUG "pmac_pm_prepare(%d)\n", state);
+
+ return 0;
+}
+
+static int pmac_pm_enter(u32 state)
+{
+ printk(KERN_DEBUG "pmac_pm_enter(%d)\n", 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(u32 state)
+{
+ printk(KERN_DEBUG "pmac_pm_finish(%d)\n", 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_PM_DISK */
+
static int initializing = 1;
static int pmac_late_init(void)
{
initializing = 0;
+
+#ifdef CONFIG_PM_DISK
+ pm_set_ops(&pmac_pm_ops);
+#endif /* CONFIG_PM_DISK */
return 0;
}
===== drivers/ide/ppc/pmac.c 1.47 vs edited =====
--- 1.47/drivers/ide/ppc/pmac.c Mon Nov 3 09:30:01 2003
+++ edited/drivers/ide/ppc/pmac.c Sat Jan 24 13:17:26 2004
@@ -1366,7 +1366,7 @@
ide_hwif_t *hwif = (ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev);
int rc = 0;
- if (state != mdev->ofdev.dev.power_state && state >= 2) {
+ if (state != mdev->ofdev.dev.power_state && state >= 2 && state != 4) {
rc = pmac_ide_do_suspend(hwif);
if (rc == 0)
mdev->ofdev.dev.power_state = state;
@@ -1469,7 +1469,7 @@
ide_hwif_t *hwif = (ide_hwif_t *)pci_get_drvdata(pdev);
int rc = 0;
- if (state != pdev->dev.power_state && state >= 2) {
+ if (state != pdev->dev.power_state && state >= 2 && state != 4) {
rc = pmac_ide_do_suspend(hwif);
if (rc == 0)
pdev->dev.power_state = state;
===== drivers/macintosh/Kconfig 1.1 vs edited =====
--- 1.1/drivers/macintosh/Kconfig Fri Jan 9 14:50:21 2004
+++ edited/drivers/macintosh/Kconfig Fri Jan 23 17:03:41 2004
@@ -29,7 +29,7 @@
config PMAC_PBOOK
bool "Power management support for PowerBooks"
- depends on ADB_PMU
+ depends on PM && ADB_PMU
---help---
This provides support for putting a PowerBook to sleep; it also
enables media bay support. Power management works on the
@@ -46,10 +46,10 @@
have it autoloaded. The act of removing the module shuts down the
sound hardware for more power savings.
-config PM
- bool
- depends on PPC_PMAC && ADB_PMU && PMAC_PBOOK
- default y
+#config PM
+# bool
+# depends on PPC_PMAC && ADB_PMU && PMAC_PBOOK
+# default y
config PMAC_APM_EMU
tristate "APM emulation"
===== drivers/macintosh/mediabay.c 1.23 vs edited =====
--- 1.23/drivers/macintosh/mediabay.c Sun Oct 5 09:22:51 2003
+++ edited/drivers/macintosh/mediabay.c Sat Jan 24 12:49:53 2004
@@ -703,7 +703,7 @@
{
struct media_bay_info *bay = macio_get_drvdata(mdev);
- if (state != mdev->ofdev.dev.power_state && state >= 2) {
+ if (state != mdev->ofdev.dev.power_state && state >= 2 && state != 4) {
down(&bay->lock);
bay->sleeping = 1;
set_mb_power(bay, 0);
===== drivers/macintosh/via-pmu.c 1.54 vs edited =====
--- 1.54/drivers/macintosh/via-pmu.c Wed Nov 5 18:01:27 2003
+++ edited/drivers/macintosh/via-pmu.c Fri Jan 23 18:17:17 2004
@@ -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 <asm/prom.h>
#include <asm/machdep.h>
@@ -3074,6 +3075,88 @@
return 0;
}
#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 = sys_device_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);
===== drivers/video/aty/aty128fb.c 1.34 vs edited =====
--- 1.34/drivers/video/aty/aty128fb.c Tue Oct 14 17:28:07 2003
+++ edited/drivers/video/aty/aty128fb.c Sat Jan 24 12:49:28 2004
@@ -2251,13 +2251,16 @@
* can properly take care of D3 ? Also, with swsusp, we
* know we'll be rebooted, ...
*/
+ if (state != 2 && state != 3)
+ return 0;
+
#ifdef CONFIG_PPC_PMAC
/* HACK ALERT ! Once I find a proper way to say to each driver
* individually what will happen with it's PCI slot, I'll change
* that. On laptops, the AGP slot is just unclocked, so D2 is
* expected, while on desktops, the card is powered off
*/
- if (state >= 3)
+ if (state == 3)
state = 2;
#endif /* CONFIG_PPC_PMAC */
===== drivers/video/aty/radeon_pm.c 1.4 vs edited =====
--- 1.4/drivers/video/aty/radeon_pm.c Wed Jan 21 17:00:06 2004
+++ edited/drivers/video/aty/radeon_pm.c Fri Jan 23 18:55:16 2004
@@ -845,6 +845,8 @@
*/
printk(KERN_DEBUG "radeonfb: suspending to state: %d...\n", state);
+ if (state != 2 && state != 3)
+ return 0;
acquire_console_sem();
===== include/linux/pm.h 1.9 vs edited =====
--- 1.9/include/linux/pm.h Tue Aug 26 06:03:37 2003
+++ edited/include/linux/pm.h Fri Jan 23 18:56:02 2004
@@ -195,10 +195,10 @@
extern void (*pm_power_off)(void);
enum {
- PM_SUSPEND_ON,
- PM_SUSPEND_STANDBY,
- PM_SUSPEND_MEM,
- PM_SUSPEND_DISK,
+ PM_SUSPEND_ON = 0,
+ PM_SUSPEND_STANDBY = 1,
+ PM_SUSPEND_MEM = 3,
+ PM_SUSPEND_DISK = 4,
PM_SUSPEND_MAX,
};
===== include/linux/reboot.h 1.5 vs edited =====
--- 1.5/include/linux/reboot.h Thu Aug 7 04:47:22 2003
+++ edited/include/linux/reboot.h Sat Jan 24 12:31:11 2004
@@ -40,6 +40,8 @@
extern int register_reboot_notifier(struct notifier_block *);
extern int unregister_reboot_notifier(struct notifier_block *);
+/* For use by swsusp only */
+extern struct notifier_block *reboot_notifier_list;
/*
* Architecture-specific implementations of sys_reboot commands.
===== include/linux/suspend.h 1.22 vs edited =====
--- 1.22/include/linux/suspend.h Tue Oct 14 17:28:08 2003
+++ edited/include/linux/suspend.h Fri Jan 23 18:06:56 2004
@@ -1,9 +1,9 @@
#ifndef _LINUX_SWSUSP_H
#define _LINUX_SWSUSP_H
-#ifdef CONFIG_X86
+//#ifdef CONFIG_X86
#include <asm/suspend.h>
-#endif
+//#endif
#include <linux/swap.h>
#include <linux/notifier.h>
#include <linux/config.h>
===== kernel/sys.c 1.68 vs edited =====
--- 1.68/kernel/sys.c Wed Jan 21 11:29:32 2004
+++ edited/kernel/sys.c Sat Jan 24 12:30:31 2004
@@ -84,7 +84,7 @@
* and the like.
*/
-static struct notifier_block *reboot_notifier_list;
+struct notifier_block *reboot_notifier_list;
rwlock_t notifier_lock = RW_LOCK_UNLOCKED;
/**
===== kernel/power/disk.c 1.6 vs edited =====
--- 1.6/kernel/power/disk.c Thu Oct 2 04:52:48 2003
+++ edited/kernel/power/disk.c Sat Jan 24 12:31:31 2004
@@ -16,6 +16,7 @@
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/fs.h>
+#include <linux/reboot.h>
#include "power.h"
@@ -46,23 +47,26 @@
unsigned long flags;
int error = 0;
- local_irq_save(flags);
- device_power_down(PM_SUSPEND_DISK);
switch(mode) {
case PM_DISK_PLATFORM:
+ local_irq_save(flags);
error = pm_ops->enter(PM_SUSPEND_DISK);
+ local_irq_restore(flags);
break;
case PM_DISK_SHUTDOWN:
printk("Powering off system\n");
+ notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL);
+ device_shutdown();
machine_power_off();
break;
case PM_DISK_REBOOT:
+ printk("Rebooting system\n");
+ notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
+ device_shutdown();
machine_restart(NULL);
break;
}
machine_halt();
- device_power_up();
- local_irq_restore(flags);
return 0;
}
@@ -163,8 +167,10 @@
pr_debug("PM: snapshotting memory.\n");
in_suspend = 1;
- if ((error = pmdisk_save()))
+ if ((error = pmdisk_save())) {
+ pr_debug("PM: snapshot memory failed !\n");
goto Done;
+ }
if (in_suspend) {
pr_debug("PM: writing image.\n");
@@ -225,9 +231,6 @@
* Do it with disabled interrupts for best effect. That way, if some
* driver scheduled DMA, we have good chance for DMA to finish ;-).
*/
- pr_debug("PM: Waiting for DMAs to settle down.\n");
- mdelay(1000);
-
pr_debug("PM: Restoring saved image.\n");
pmdisk_restore();
pr_debug("PM: Restore failed, recovering.n");
===== kernel/power/main.c 1.16 vs edited =====
--- 1.16/kernel/power/main.c Tue Sep 9 08:13:46 2003
+++ edited/kernel/power/main.c Fri Jan 23 19:27:16 2004
@@ -120,6 +120,7 @@
char * pm_states[] = {
[PM_SUSPEND_STANDBY] = "standby",
+ [2] = "",
[PM_SUSPEND_MEM] = "mem",
[PM_SUSPEND_DISK] = "disk",
NULL,
===== kernel/power/pmdisk.c 1.80 vs edited =====
--- 1.80/kernel/power/pmdisk.c Thu Oct 2 04:52:48 2003
+++ edited/kernel/power/pmdisk.c Sat Jan 24 13:52:30 2004
@@ -18,7 +18,7 @@
*
*/
-#undef DEBUG
+#define DEBUG
#include <linux/mm.h>
#include <linux/bio.h>
@@ -28,6 +28,7 @@
#include <linux/device.h>
#include <linux/swapops.h>
#include <linux/bootmem.h>
+#include <linux/utsname.h>
#include <asm/mmu_context.h>
@@ -624,8 +625,10 @@
{
int error = 0;
- if ((error = read_swapfiles()))
+ if ((error = read_swapfiles())) {
+ printk("Can't read swapfiles\n");
return error;
+ }
drain_local_pages();
@@ -702,6 +705,7 @@
* Magic happens here
*/
+#if 0
int pmdisk_resume(void)
{
BUG_ON (nr_copy_pages_check != pmdisk_pages);
@@ -711,6 +715,7 @@
__flush_tlb_global();
return 0;
}
+#endif
/* pmdisk_arch_suspend() is implemented in arch/?/power/pmdisk.S,
and basically does:
@@ -1082,9 +1087,11 @@
if ((error = arch_prepare_suspend()))
return error;
local_irq_disable();
+ device_power_down(PM_SUSPEND_DISK);
save_processor_state();
error = pmdisk_arch_suspend(0);
restore_processor_state();
+ device_power_up();
local_irq_enable();
return error;
}
@@ -1143,10 +1150,13 @@
int __init pmdisk_restore(void)
{
int error;
+
local_irq_disable();
+ device_power_down(PM_SUSPEND_DISK);
save_processor_state();
error = pmdisk_arch_suspend(1);
restore_processor_state();
+ device_power_up();
local_irq_enable();
return error;
}
Then the arch/ppc/kernel/pmdisk.S file:
#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(pmdisk_save_area)
.space SL_SIZE
.section .text
.align 5
_GLOBAL(pmdisk_arch_suspend)
cmpi 0,r3,0
bne do_resume
lis r11,pmdisk_save_area@h
ori r11,r11,pmdisk_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 pmdisk_suspend
/* Restore LR from the save area */
lis r11,pmdisk_save_area@h
ori r11,r11,pmdisk_save_area@l
lwz r0,SL_LR(r11)
mtlr r0
blr
/* Resume code */
do_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,(pm_pagedir_nosave - KERNELBASE)@h
ori r11,r11,pm_pagedir_nosave@l
lwz r10,0(r11)
tophys(r3,r10)
/* Load the count of pages to copy in r4 */
lis r11,(pmdisk_pages - KERNELBASE)@h
ori r11,r11,pmdisk_pages@l
lwz r4,0(r11)
/* Copy the pages. This is a very basic implementation, to
* be replaced by something more cache efficient */
1:
li r0,256
mtctr r0
lwz r11,0(r3) /* source */
tophys(r5,r11)
lwz r10,4(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
addi r3,r3,16
subi r4,r4,1
cmpwi 0,r4,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,pmdisk_save_area@h
ori r11,r11,pmdisk_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 pmdisk_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
(RESENT, sorry if you got it already, something apparently went wrong
on the SMTP here)
Ok, I hammered that for a day and got pmdisk (patrick's version) suspending
and resuming on a pismo G3 (with XFree etc.. running). Lots of rough edges
still (via-pmu sleep need to be improved, ADB need porting to the new driver
model to be properly suspended/resumed, a sysdev for RTC is needed too for
time, the asm code should be fixed for G5, etc...)
I had to fix some issues in the core pmdisk code though. One big one is that
lots of drivers expect suspend to disk to be state 4 while the current code
used state 3 for that (and suspend to RAM to be state 3 btw). I hacked that
in include/linux/suspend.h, but we shall probably just get rid of those
stupid numbers and properly define each constant indstead.
We should also use a different state for the suspend calls done before saving
the image, and the ones done before resuming the image, some driver may be
optimized for these cases.
The patch is against my tree currently, and the arch/ppc/kernel/pmdisk.S file
is appended as-is (not in patch form). I don't plan to release that right now,
I may hack a bit on it in the "background" (I want to get HIGHMEM working
some day). Feel free to improve, but then keep me informed please.
Ah, also: The "Freeing memory" phase takes forever. That should really be fixed.
Ben.
First the patch:
===== arch/ppc/Kconfig 1.60 vs edited =====
--- 1.60/arch/ppc/Kconfig Wed Jan 21 11:29:19 2004
+++ edited/arch/ppc/Kconfig Fri Jan 23 17:03:20 2004
@@ -913,6 +913,8 @@
source "drivers/zorro/Kconfig"
+source kernel/power/Kconfig
+
endmenu
menu "Bus options"
===== arch/ppc/kernel/Makefile 1.61 vs edited =====
--- 1.61/arch/ppc/kernel/Makefile Wed Jan 21 11:29:20 2004
+++ edited/arch/ppc/kernel/Makefile Fri Jan 23 16:57:28 2004
@@ -15,6 +15,7 @@
extra-$(CONFIG_8xx) := head_8xx.o
extra-$(CONFIG_6xx) += idle_6xx.o
extra-$(CONFIG_POWER4) += idle_power4.o
+
extra-y += vmlinux.lds.s
obj-y := entry.o traps.o irq.o idle.o time.o misc.o \
@@ -22,6 +23,7 @@
semaphore.o syscalls.o setup.o \
cputable.o ppc_htab.o
obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o
+obj-$(CONFIG_PM_DISK) += pmdisk.o
obj-$(CONFIG_POWER4) += cpu_setup_power4.o
obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o
obj-$(CONFIG_PCI) += pci.o
===== arch/ppc/kernel/signal.c 1.37 vs edited =====
--- 1.37/arch/ppc/kernel/signal.c Fri Nov 28 12:13:45 2003
+++ edited/arch/ppc/kernel/signal.c Fri Jan 23 18:47:07 2004
@@ -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>
@@ -563,6 +564,11 @@
struct k_sigaction *ka;
unsigned long frame, newsp;
int signr, ret;
+
+ if (current->flags & PF_FREEZE) {
+ refrigerator(0);
+ return 0;
+ }
if (!oldset)
oldset = ¤t->blocked;
===== arch/ppc/kernel/vmlinux.lds.S 1.39 vs edited =====
--- 1.39/arch/ppc/kernel/vmlinux.lds.S Mon Nov 17 12:29:47 2003
+++ edited/arch/ppc/kernel/vmlinux.lds.S Fri Jan 23 18:26:26 2004
@@ -72,6 +72,12 @@
CONSTRUCTORS
}
+ . = ALIGN(4096);
+ __nosave_begin = .;
+ .data_nosave : { *(.data.nosave) }
+ . = ALIGN(4096);
+ __nosave_end = .;
+
. = ALIGN(32);
.data.cacheline_aligned : { *(.data.cacheline_aligned) }
===== arch/ppc/platforms/pmac_setup.c 1.48 vs edited =====
--- 1.48/arch/ppc/platforms/pmac_setup.c Sat Nov 1 12:36:52 2003
+++ edited/arch/ppc/platforms/pmac_setup.c Fri Jan 23 18:08:18 2004
@@ -51,6 +51,7 @@
#include <linux/irq.h>
#include <linux/seq_file.h>
#include <linux/root_dev.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"
@@ -425,11 +428,65 @@
#endif
}
+/* TODO: Merge the suspend-to-ram with the common code !!!
+ * currently, this is a stub implementation for suspend-to-disk
+ * only
+ */
+
+#ifdef CONFIG_PM_DISK
+
+static int pmac_pm_prepare(u32 state)
+{
+ printk(KERN_DEBUG "pmac_pm_prepare(%d)\n", state);
+
+ return 0;
+}
+
+static int pmac_pm_enter(u32 state)
+{
+ printk(KERN_DEBUG "pmac_pm_enter(%d)\n", 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(u32 state)
+{
+ printk(KERN_DEBUG "pmac_pm_finish(%d)\n", 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_PM_DISK */
+
static int initializing = 1;
static int pmac_late_init(void)
{
initializing = 0;
+
+#ifdef CONFIG_PM_DISK
+ pm_set_ops(&pmac_pm_ops);
+#endif /* CONFIG_PM_DISK */
return 0;
}
===== drivers/ide/ppc/pmac.c 1.47 vs edited =====
--- 1.47/drivers/ide/ppc/pmac.c Mon Nov 3 09:30:01 2003
+++ edited/drivers/ide/ppc/pmac.c Sat Jan 24 13:17:26 2004
@@ -1366,7 +1366,7 @@
ide_hwif_t *hwif = (ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev);
int rc = 0;
- if (state != mdev->ofdev.dev.power_state && state >= 2) {
+ if (state != mdev->ofdev.dev.power_state && state >= 2 && state != 4) {
rc = pmac_ide_do_suspend(hwif);
if (rc == 0)
mdev->ofdev.dev.power_state = state;
@@ -1469,7 +1469,7 @@
ide_hwif_t *hwif = (ide_hwif_t *)pci_get_drvdata(pdev);
int rc = 0;
- if (state != pdev->dev.power_state && state >= 2) {
+ if (state != pdev->dev.power_state && state >= 2 && state != 4) {
rc = pmac_ide_do_suspend(hwif);
if (rc == 0)
pdev->dev.power_state = state;
===== drivers/macintosh/Kconfig 1.1 vs edited =====
--- 1.1/drivers/macintosh/Kconfig Fri Jan 9 14:50:21 2004
+++ edited/drivers/macintosh/Kconfig Fri Jan 23 17:03:41 2004
@@ -29,7 +29,7 @@
config PMAC_PBOOK
bool "Power management support for PowerBooks"
- depends on ADB_PMU
+ depends on PM && ADB_PMU
---help---
This provides support for putting a PowerBook to sleep; it also
enables media bay support. Power management works on the
@@ -46,10 +46,10 @@
have it autoloaded. The act of removing the module shuts down the
sound hardware for more power savings.
-config PM
- bool
- depends on PPC_PMAC && ADB_PMU && PMAC_PBOOK
- default y
+#config PM
+# bool
+# depends on PPC_PMAC && ADB_PMU && PMAC_PBOOK
+# default y
config PMAC_APM_EMU
tristate "APM emulation"
===== drivers/macintosh/mediabay.c 1.23 vs edited =====
--- 1.23/drivers/macintosh/mediabay.c Sun Oct 5 09:22:51 2003
+++ edited/drivers/macintosh/mediabay.c Sat Jan 24 12:49:53 2004
@@ -703,7 +703,7 @@
{
struct media_bay_info *bay = macio_get_drvdata(mdev);
- if (state != mdev->ofdev.dev.power_state && state >= 2) {
+ if (state != mdev->ofdev.dev.power_state && state >= 2 && state != 4) {
down(&bay->lock);
bay->sleeping = 1;
set_mb_power(bay, 0);
===== drivers/macintosh/via-pmu.c 1.54 vs edited =====
--- 1.54/drivers/macintosh/via-pmu.c Wed Nov 5 18:01:27 2003
+++ edited/drivers/macintosh/via-pmu.c Fri Jan 23 18:17:17 2004
@@ -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 <asm/prom.h>
#include <asm/machdep.h>
@@ -3074,6 +3075,88 @@
return 0;
}
#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 = sys_device_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);
===== drivers/video/aty/aty128fb.c 1.34 vs edited =====
--- 1.34/drivers/video/aty/aty128fb.c Tue Oct 14 17:28:07 2003
+++ edited/drivers/video/aty/aty128fb.c Sat Jan 24 12:49:28 2004
@@ -2251,13 +2251,16 @@
* can properly take care of D3 ? Also, with swsusp, we
* know we'll be rebooted, ...
*/
+ if (state != 2 && state != 3)
+ return 0;
+
#ifdef CONFIG_PPC_PMAC
/* HACK ALERT ! Once I find a proper way to say to each driver
* individually what will happen with it's PCI slot, I'll change
* that. On laptops, the AGP slot is just unclocked, so D2 is
* expected, while on desktops, the card is powered off
*/
- if (state >= 3)
+ if (state == 3)
state = 2;
#endif /* CONFIG_PPC_PMAC */
===== drivers/video/aty/radeon_pm.c 1.4 vs edited =====
--- 1.4/drivers/video/aty/radeon_pm.c Wed Jan 21 17:00:06 2004
+++ edited/drivers/video/aty/radeon_pm.c Fri Jan 23 18:55:16 2004
@@ -845,6 +845,8 @@
*/
printk(KERN_DEBUG "radeonfb: suspending to state: %d...\n", state);
+ if (state != 2 && state != 3)
+ return 0;
acquire_console_sem();
===== include/linux/pm.h 1.9 vs edited =====
--- 1.9/include/linux/pm.h Tue Aug 26 06:03:37 2003
+++ edited/include/linux/pm.h Fri Jan 23 18:56:02 2004
@@ -195,10 +195,10 @@
extern void (*pm_power_off)(void);
enum {
- PM_SUSPEND_ON,
- PM_SUSPEND_STANDBY,
- PM_SUSPEND_MEM,
- PM_SUSPEND_DISK,
+ PM_SUSPEND_ON = 0,
+ PM_SUSPEND_STANDBY = 1,
+ PM_SUSPEND_MEM = 3,
+ PM_SUSPEND_DISK = 4,
PM_SUSPEND_MAX,
};
===== include/linux/reboot.h 1.5 vs edited =====
--- 1.5/include/linux/reboot.h Thu Aug 7 04:47:22 2003
+++ edited/include/linux/reboot.h Sat Jan 24 12:31:11 2004
@@ -40,6 +40,8 @@
extern int register_reboot_notifier(struct notifier_block *);
extern int unregister_reboot_notifier(struct notifier_block *);
+/* For use by swsusp only */
+extern struct notifier_block *reboot_notifier_list;
/*
* Architecture-specific implementations of sys_reboot commands.
===== include/linux/suspend.h 1.22 vs edited =====
--- 1.22/include/linux/suspend.h Tue Oct 14 17:28:08 2003
+++ edited/include/linux/suspend.h Fri Jan 23 18:06:56 2004
@@ -1,9 +1,9 @@
#ifndef _LINUX_SWSUSP_H
#define _LINUX_SWSUSP_H
-#ifdef CONFIG_X86
+//#ifdef CONFIG_X86
#include <asm/suspend.h>
-#endif
+//#endif
#include <linux/swap.h>
#include <linux/notifier.h>
#include <linux/config.h>
===== kernel/sys.c 1.68 vs edited =====
--- 1.68/kernel/sys.c Wed Jan 21 11:29:32 2004
+++ edited/kernel/sys.c Sat Jan 24 12:30:31 2004
@@ -84,7 +84,7 @@
* and the like.
*/
-static struct notifier_block *reboot_notifier_list;
+struct notifier_block *reboot_notifier_list;
rwlock_t notifier_lock = RW_LOCK_UNLOCKED;
/**
===== kernel/power/disk.c 1.6 vs edited =====
--- 1.6/kernel/power/disk.c Thu Oct 2 04:52:48 2003
+++ edited/kernel/power/disk.c Sat Jan 24 12:31:31 2004
@@ -16,6 +16,7 @@
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/fs.h>
+#include <linux/reboot.h>
#include "power.h"
@@ -46,23 +47,26 @@
unsigned long flags;
int error = 0;
- local_irq_save(flags);
- device_power_down(PM_SUSPEND_DISK);
switch(mode) {
case PM_DISK_PLATFORM:
+ local_irq_save(flags);
error = pm_ops->enter(PM_SUSPEND_DISK);
+ local_irq_restore(flags);
break;
case PM_DISK_SHUTDOWN:
printk("Powering off system\n");
+ notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL);
+ device_shutdown();
machine_power_off();
break;
case PM_DISK_REBOOT:
+ printk("Rebooting system\n");
+ notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
+ device_shutdown();
machine_restart(NULL);
break;
}
machine_halt();
- device_power_up();
- local_irq_restore(flags);
return 0;
}
@@ -163,8 +167,10 @@
pr_debug("PM: snapshotting memory.\n");
in_suspend = 1;
- if ((error = pmdisk_save()))
+ if ((error = pmdisk_save())) {
+ pr_debug("PM: snapshot memory failed !\n");
goto Done;
+ }
if (in_suspend) {
pr_debug("PM: writing image.\n");
@@ -225,9 +231,6 @@
* Do it with disabled interrupts for best effect. That way, if some
* driver scheduled DMA, we have good chance for DMA to finish ;-).
*/
- pr_debug("PM: Waiting for DMAs to settle down.\n");
- mdelay(1000);
-
pr_debug("PM: Restoring saved image.\n");
pmdisk_restore();
pr_debug("PM: Restore failed, recovering.n");
===== kernel/power/main.c 1.16 vs edited =====
--- 1.16/kernel/power/main.c Tue Sep 9 08:13:46 2003
+++ edited/kernel/power/main.c Fri Jan 23 19:27:16 2004
@@ -120,6 +120,7 @@
char * pm_states[] = {
[PM_SUSPEND_STANDBY] = "standby",
+ [2] = "",
[PM_SUSPEND_MEM] = "mem",
[PM_SUSPEND_DISK] = "disk",
NULL,
===== kernel/power/pmdisk.c 1.80 vs edited =====
--- 1.80/kernel/power/pmdisk.c Thu Oct 2 04:52:48 2003
+++ edited/kernel/power/pmdisk.c Sat Jan 24 13:52:30 2004
@@ -18,7 +18,7 @@
*
*/
-#undef DEBUG
+#define DEBUG
#include <linux/mm.h>
#include <linux/bio.h>
@@ -28,6 +28,7 @@
#include <linux/device.h>
#include <linux/swapops.h>
#include <linux/bootmem.h>
+#include <linux/utsname.h>
#include <asm/mmu_context.h>
@@ -624,8 +625,10 @@
{
int error = 0;
- if ((error = read_swapfiles()))
+ if ((error = read_swapfiles())) {
+ printk("Can't read swapfiles\n");
return error;
+ }
drain_local_pages();
@@ -702,6 +705,7 @@
* Magic happens here
*/
+#if 0
int pmdisk_resume(void)
{
BUG_ON (nr_copy_pages_check != pmdisk_pages);
@@ -711,6 +715,7 @@
__flush_tlb_global();
return 0;
}
+#endif
/* pmdisk_arch_suspend() is implemented in arch/?/power/pmdisk.S,
and basically does:
@@ -1082,9 +1087,11 @@
if ((error = arch_prepare_suspend()))
return error;
local_irq_disable();
+ device_power_down(PM_SUSPEND_DISK);
save_processor_state();
error = pmdisk_arch_suspend(0);
restore_processor_state();
+ device_power_up();
local_irq_enable();
return error;
}
@@ -1143,10 +1150,13 @@
int __init pmdisk_restore(void)
{
int error;
+
local_irq_disable();
+ device_power_down(PM_SUSPEND_DISK);
save_processor_state();
error = pmdisk_arch_suspend(1);
restore_processor_state();
+ device_power_up();
local_irq_enable();
return error;
}
Then the arch/ppc/kernel/pmdisk.S file:
#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(pmdisk_save_area)
.space SL_SIZE
.section .text
.align 5
_GLOBAL(pmdisk_arch_suspend)
cmpi 0,r3,0
bne do_resume
lis r11,pmdisk_save_area@h
ori r11,r11,pmdisk_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 pmdisk_suspend
/* Restore LR from the save area */
lis r11,pmdisk_save_area@h
ori r11,r11,pmdisk_save_area@l
lwz r0,SL_LR(r11)
mtlr r0
blr
/* Resume code */
do_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,(pm_pagedir_nosave - KERNELBASE)@h
ori r11,r11,pm_pagedir_nosave@l
lwz r10,0(r11)
tophys(r3,r10)
/* Load the count of pages to copy in r4 */
lis r11,(pmdisk_pages - KERNELBASE)@h
ori r11,r11,pmdisk_pages@l
lwz r4,0(r11)
/* Copy the pages. This is a very basic implementation, to
* be replaced by something more cache efficient */
1:
li r0,256
mtctr r0
lwz r11,0(r3) /* source */
tophys(r5,r11)
lwz r10,4(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
addi r3,r3,16
subi r4,r4,1
cmpwi 0,r4,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,pmdisk_save_area@h
ori r11,r11,pmdisk_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 pmdisk_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
On Sat, 24 Jan 2004 13:54:15 +1100
Benjamin Herrenschmidt <[email protected]> wrote:
> Ok, I hammered that for a day and got pmdisk (patrick's version)
> suspending and resuming on a pismo G3 (with XFree etc.. running). Lots
> of rough edges still (via-pmu sleep need to be improved, ADB need
> porting to the new driver model to be properly suspended/resumed, a
> sysdev for RTC is needed too for time, the asm code should be fixed
> for G5, etc...)
Yes, It works in my laptop too. Cool.
thanks for greate work.
--
Hu Gang / Steve
Linux Registered User 204016
GPG Public Key: http://soulinfo.com/~hugang/HuGang.asc
Hi!
> (RESENT, sorry if you got it already, something apparently went wrong
> on the SMTP here)
>
> Ok, I hammered that for a day and got pmdisk (patrick's version) suspending
> and resuming on a pismo G3 (with XFree etc.. running). Lots of rough
> edges
Congratulations!
Pavel
[Now we'll have to do something with pmdisk vs. swsusp...]
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]
On 24 Jan 2004 at 13h01, Benjamin Herrenschmidt wrote:
Hi,
> The patch is against my tree currently, and the arch/ppc/kernel/pmdisk.S file
> is appended as-is (not in patch form).
Didn't you forget to include include/asm-ppc/suspend.h ? ;-)
--
Colin
On Sun, 2004-01-25 at 03:28, Colin Leroy wrote:
> On 24 Jan 2004 at 13h01, Benjamin Herrenschmidt wrote:
>
> Hi,
>
> > The patch is against my tree currently, and the arch/ppc/kernel/pmdisk.S file
> > is appended as-is (not in patch form).
>
> Didn't you forget to include include/asm-ppc/suspend.h ? ;-)
Yes, but you could have re-created it easily:
static inline int arch_prepare_suspend(void)
{
return 0;
}
static inline void save_processor_state(void)
{
}
static inline void restore_processor_state(void)
{
}
On 25 Jan 2004 at 10h01, Benjamin Herrenschmidt wrote:
Hi,
> > Didn't you forget to include include/asm-ppc/suspend.h ? ;-)
>
> Yes, but you could have re-created it easily:
Thanks - I wasn't sure about it.
The kernel now builds. However, after doing
echo disk > /sys/power/state
or "hda14" or "/dev/hda14" (which is my swap partition) instead of "disk",
nothing happens (and nothing gets logged).
The only things different from your patch is that I added PMAC_MB_CAN_SLEEP
to my iBook's entry in pmac_feature.c, and added
return -EBUSY;
after your
if (state != 2 && state != 3)
return 0;
in radeon_pm.c (to avoid pmud putting the iBook to sleep by mistake).
relevant .config part:
# CONFIG_SOFTWARE_SUSPEND is not set
CONFIG_PM_DISK=y
CONFIG_PM_DISK_PARTITION="/dev/hda14"
Any pointer ? (did I miss something obvious?)
Thanks,
--
Colin
> Thanks - I wasn't sure about it.
> The kernel now builds. However, after doing
> echo disk > /sys/power/state
> or "hda14" or "/dev/hda14" (which is my swap partition) instead of "disk",
> nothing happens (and nothing gets logged).
Hrm... It tends to do that when it's not happy with something,
but I did get it working... Ah yes, do
echo -n "disk" instead :) It doesn't like the trailing \n
Ben.
On Sat, Jan 24, 2004 at 01:54:15PM +1100, Benjamin Herrenschmidt wrote:
> Ok, I hammered that for a day and got pmdisk (patrick's version) suspending
> and resuming on a pismo G3 (with XFree etc.. running). Lots of rough edges
> still (via-pmu sleep need to be improved, ADB need porting to the new driver
> model to be properly suspended/resumed, a sysdev for RTC is needed too for
> time, the asm code should be fixed for G5, etc...)
Works fine on a
processor : 0
cpu : 7455, altivec supported
clock : 867MHz
revision : 3.3 (pvr 8001 0303)
bogomips : 863.00
machine : PowerBook6,1
motherboard : PowerBook6,1 MacRISC3 Power Macintosh
board revision : 00000001
detected as : 287 (PowerBook G4 12")
pmac flags : 0000000b
L2 cache : 256K unified
memory : 256MB
pmac-generation : NewWorld
Cheers,
-- Guido
On 26 Jan 2004 at 11h01, Benjamin Herrenschmidt wrote:
Hi,
> Hrm... It tends to do that when it's not happy with something,
> but I did get it working... Ah yes, do
>
> echo -n "disk" instead :) It doesn't like the trailing \n
Thanks, worked better. Got an oops with ohci-hcd or ehci-hcd, though.
shutdown worked after rmmoding these.
However resume did not - got:
dn: cn= pmdisk: CPUs: 544501616
pmdisk: Image: 168453230 Pages
pmdisk: Pagedir: 975201134 Pages
pmdisk: Resume mismatch: kernel version
pmdisk: Error -1 resuming
PM: Resume from disk failed.
of course, this was the same kernel. Don't really know what to try next,
but it doesn't matter that much to me, don't lose your time with it if
you lack time :)
--
Colin
On Tue, 2004-01-27 at 05:21, Colin Leroy wrote:
> On 26 Jan 2004 at 11h01, Benjamin Herrenschmidt wrote:
>
> Hi,
>
> > Hrm... It tends to do that when it's not happy with something,
> > but I did get it working... Ah yes, do
> >
> > echo -n "disk" instead :) It doesn't like the trailing \n
>
> Thanks, worked better. Got an oops with ohci-hcd or ehci-hcd, though.
> shutdown worked after rmmoding these.
> However resume did not - got:
pmdisk will save to the first (or the last, I'm not sure) installed
swap partition, not what your say on the command line. It will _resume_
from what you say on the command line.
ben.
On Tue, 2004-01-27 at 05:10, Pavel Machek wrote:
> Hi!
>
> > Ah, also: The "Freeing memory" phase takes forever. That should
> > really be fixed.
>
> Well, it does the trick for me, but it takes 50% or so of suspend
> time. Some memory managment guru making "freeing memory" faster would
> certainly be welcome.
> Pavel
> PS: But I'd like to keep it simple...
Haven't looked at it yet. Several crash reports so far, mostly
lockups right after printing the number of pages to save. I wonder
if we have something broken in there. It dies for me once too at
this point.
Also, at least on pmac laptops, the HD is usually so fast, that
I suspect spending 10 seconds freeing things is less efficient than
spending this 10 seconds writing 200Mb of data to disk :) Also, one
wakup, it's quite painful to see everything be swapped in again. It
may make sense to be less agressive on the memory freeing, though
finding a good balance isn't easy.
Hi.
On Tue, 2004-01-27 at 11:00, Benjamin Herrenschmidt wrote:
> Also, at least on pmac laptops, the HD is usually so fast, that
> I suspect spending 10 seconds freeing things is less efficient than
> spending this 10 seconds writing 200Mb of data to disk :) Also, one
> wakup, it's quite painful to see everything be swapped in again. It
> may make sense to be less agressive on the memory freeing, though
> finding a good balance isn't easy.
Yes. That's why suspend2 doesn't free any memory at all by default, but
gives the user the option of setting a maximum image size.
Regards,
Nigel
--
My work on Software Suspend is graciously brought to you by
LinuxFund.org.
Hi!
> > > Ah, also: The "Freeing memory" phase takes forever. That should
> > > really be fixed.
> >
> > Well, it does the trick for me, but it takes 50% or so of suspend
> > time. Some memory managment guru making "freeing memory" faster would
> > certainly be welcome.
> > Pavel
> > PS: But I'd like to keep it simple...
>
> Haven't looked at it yet. Several crash reports so far, mostly
> lockups right after printing the number of pages to save. I wonder
> if we have something broken in there. It dies for me once too at
> this point.
>
> Also, at least on pmac laptops, the HD is usually so fast, that
> I suspect spending 10 seconds freeing things is less efficient than
> spending this 10 seconds writing 200Mb of data to disk :) Also, one
> wakup, it's quite painful to see everything be swapped in again. It
> may make sense to be less agressive on the memory freeing, though
> finding a good balance isn't easy.
Notice that swsusp needs half of physical memory free by design. That
means that we need _some_ freeing. Nigel's swsusp2 works around that
at cost of more complicated implementation.
Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]
On Tue, 2004-01-27 at 12:21, Pavel Machek wrote:
> Notice that swsusp needs half of physical memory free by design. That
> means that we need _some_ freeing. Nigel's swsusp2 works around that
> at cost of more complicated implementation.
Yes, my method is a bit more complicated.
Yours doesn't always need some freeing though - you only need to free
memory until that 1/2 limitation is met. Last time I looked at it, it
freed memory until it could free no more. Is that still true?
Nigel
--
My work on Software Suspend is graciously brought to you by
LinuxFund.org.
Hi!
> > Notice that swsusp needs half of physical memory free by design. That
> > means that we need _some_ freeing. Nigel's swsusp2 works around that
> > at cost of more complicated implementation.
>
> Yes, my method is a bit more complicated.
>
> Yours doesn't always need some freeing though - you only need to free
> memory until that 1/2 limitation is met. Last time I looked at it, it
> freed memory until it could free no more. Is that still true?
Yes. [It could be changed, but at that point I'd have to figure out
how much memory I really do need for write buffers, bio allocation,
etc.]
Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]
On Tue, 27 Jan 2004 11:31:50 +1300
Nigel Cunningham <[email protected]> wrote:
> Yes. That's why suspend2 doesn't free any memory at all by default,
> but gives the user the option of setting a maximum image size.
HaHa, Here is swsusp2 patch for ppc. Now it WORKS fine.
The code base for testing, any comments and testing are welcome.
-: Howto let it work.
1: download clean 2.6.1 kernel.
2: apply swusp2 2.6.1 patch.
3: apply swsusp2 core patch.
4: apply ppc_swsusp2_1.diff
5: do make menuconfig
CONFIG_SOFTWARE_SUSPEND2=y
CONFIG_SOFTWARE_SUSPEND_DEBUG=y
CONFIG_SOFTWARE_SUSPEND_GZIP_COMPRESSION=y
CONFIG_SOFTWARE_SUSPEND_LZF_COMPRESSION=y
CONFIG_SOFTWARE_SUSPEND_SWAPWRITER=y
6:add "resume2=swap:/dev/hda10" into yaboot.conf.
"/dev/hda10" is your swap partition.
7:do suspend.
I using a sciprt to do it. or use suspend script from swsusp2.sf.net .
8:you system will backed.
-: Plans.
I has created arch/ppc/power directory like i386 arch, and put power
manger code in it.
1: clean code.
2: merge pmac sleep into.
thanks.
--
Hu Gang / Steve
Linux Registered User 204016
GPG Public Key: http://soulinfo.com/~hugang/HuGang.asc
On Wed, 28 Jan 2004 20:22:17 +0800
Hugang <[email protected]> wrote:
> HaHa, Here is swsusp2 patch for ppc. Now it WORKS fine.
>
> The code base for testing, any comments and testing are welcome.
previous patch, I has forgot a file, here is it.
Index: arch/ppc/Makefile
===================================================================
--- arch/ppc/Makefile (revision 192)
+++ arch/ppc/Makefile (working copy)
@@ -44,6 +44,7 @@
drivers-$(CONFIG_4xx) += arch/ppc/4xx_io/
drivers-$(CONFIG_8260) += arch/ppc/8260_io/
drivers-$(CONFIG_OCP) += arch/ppc/ocp/
+drivers-$(CONFIG_PM) += arch/ppc/power/
BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm
Attached file that is diff for the lastest swsusp2.
for clean 2.6.1 + 2.6.1-swsusp2-rc3 + swsusp2-core-rc5
swsusp2 for ppc like very stable, I has been do 5 times, has no
problems.
Nice day.
- SWSUSP core : 2.0-rc4
- Kernel Version : 2.6.1
- Version spec. : 2.0.0
- Compiler vers. : 2.95
ide_cd cdrom nfs lockd sunrpc af_packet ohci_hcd snd_pcm_oss
snd_mixer_oss i2c_keywest snd_powermac snd_pcm snd_page_alloc snd_timer
snd soundcore i2c_core ohci1394 ieee1394 hid sungem sungem_phy reiserfs
dm_mod uninorth_agp agpgart usbcore - Attempt number : 5
- Pageset sizes : 7201 and 56927 (56927 low).
- Parameters : 0 1 1 0 0 32
- Calculations : Image size: 2. Ram to suspend: 631.
- Limits : 65536 pages RAM. Initial boot: 63232.
- Overall expected compression percentage: 2.
- Swapwriter active.
Attempting to automatically swapon: .
Swap available for image: 110002.
- GZIP compressor enabled.
Compressed 129732608 bytes into 103573980.
Image compressed by 20 percent.
- LZF Compressor enabled.
Compressed 262668288 bytes into 129727869.
Image compressed by 50 percent.
- Debugging compiled in.
- Max ranges used: 11352
--
Hu Gang / Steve
Linux Registered User 204016
GPG Public Key: http://soulinfo.com/~hugang/HuGang.asc
On Wed, 2004-01-28 at 23:22, Hugang wrote:
> On Tue, 27 Jan 2004 11:31:50 +1300
> Nigel Cunningham <[email protected]> wrote:
>
> > Yes. That's why suspend2 doesn't free any memory at all by default,
> > but gives the user the option of setting a maximum image size.
>
> HaHa, Here is swsusp2 patch for ppc. Now it WORKS fine.
>
> The code base for testing, any comments and testing are welcome.
Ok, had a quick look. I _HATE_ those horrible macros you did. Why
not just call asm functions or just inline the code ?
Ben.
On Thu, 29 Jan 2004 11:34:53 +1100
Benjamin Herrenschmidt <[email protected]> wrote:
> Ok, had a quick look. I _HATE_ those horrible macros you did. Why
> not just call asm functions or just inline the code ?
Good idea, But will try inline first. I can't sure change to call asm
function can works. But I'll try.
Thanks for look.
--
Hu Gang / Steve
Linux Registered User 204016
GPG Public Key: http://soulinfo.com/~hugang/HuGang.asc
On Thu, 2004-01-29 at 13:05, Hugang wrote:
> On Thu, 29 Jan 2004 11:34:53 +1100
> Benjamin Herrenschmidt <[email protected]> wrote:
>
> > Ok, had a quick look. I _HATE_ those horrible macros you did. Why
> > not just call asm functions or just inline the code ?
>
> Good idea, But will try inline first. I can't sure change to call asm
> function can works. But I'll try.
As long as you make sure you save the LR in case you need it, you
can call asm functions. macros are _evil_ :)
Also, you can remove the code playing with BATs for now, they don't
really need to be saved. If the boot kernel sets them up any differently
than the saved kernel, we are in trouble anyway. And the G5 has no BATs.
Ben.
Hi!
> > As long as you make sure you save the LR in case you need it, you
> > can call asm functions. macros are _evil_ :)
> >
> > Also, you can remove the code playing with BATs for now, they don't
> > really need to be saved. If the boot kernel sets them up any
> > differently than the saved kernel, we are in trouble anyway. And the
> > G5 has no BATs.
>
> Thanks, I hate macros too, I'll change code to function as soon as
> possible.
>
> First I would tell you current swusp(2) signal ppc part has a problem.
> I has add follow code into do_signal to let process to FREEZE before
> suspend.
> ppc/
> int signr, ret;
>
> + if (current->flags & PF_FREEZE) {
> + refrigerator(PF_FREEZE);
> + return 0;
> + }
>
> if (!oldset)
> oldset = ¤t->blocked;
>
> i386/
> if (current->flags & PF_FREEZE) {
> refrigerator(PF_FREEZE);
> if (!signal_pending(current))
> goto no_signal;
> }
You may want to try this one.. Maybe it helps?
Pavel
Index: linux/kernel/power/process.c
===================================================================
--- linux.orig/kernel/power/process.c 2004-01-13 22:52:40.000000000 +0100
+++ linux/kernel/power/process.c 2004-01-09 20:33:05.000000000 +0100
@@ -49,10 +49,11 @@
pr_debug("%s entered refrigerator\n", current->comm);
printk("=");
current->flags &= ~PF_FREEZE;
- if (flag)
- flush_signals(current); /* We have signaled a kernel thread, which isn't normal behaviour
- and that may lead to 100%CPU sucking because those threads
- just don't manage signals. */
+
+ spin_lock_irq(¤t->sighand->siglock);
+ recalc_sigpending(); /* We sent fake signal, clean it up */
+ spin_unlock_irq(¤t->sighand->siglock);
+
current->flags |= PF_FROZEN;
while (current->flags & PF_FROZEN)
schedule();
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]
On Thu, 29 Jan 2004 11:29:48 +0100
Pavel Machek <[email protected]> wrote:
>
> You may want to try this one.. Maybe it helps?
>
I has check the kernel, I using swsusp2 patch, the process freeze like
this, but still need the patch I lastest send.
if (flag) {
swsusp_spin_lock_irqsave(PROCESS_SIG_MASK(current),
flags); RECALC_SIGPENDING;
swsusp_spin_unlock_irqrestore(PROCESS_SIG_MASK(current),
flags); }
--
Hu Gang / Steve
Linux Registered User 204016
GPG Public Key: http://soulinfo.com/~hugang/HuGang.asc
> The ppc part I has lost something, They are has a step to show bug.
> switch to vt console, login as normal use, run "screen", do suspend.
> after resume, screen will say unknown error 514.
>
> attached file should fix it. but look very very ulgy.
I'll have a look tomorrow, that code was a quick hack indeed.
Ben.