[Suspend2-devel] [PATCH] Software Suspend 2 for ppc64 (1/2 - core)
Nigel Cunningham
ncunningham at cyclades.com
Thu Jul 21 03:24:59 EST 2005
Hi.
Thanks for working on ppc64 support. I'll wait for your reply to
Stephen's feedback (and an update) before incorporating them.
Regards,
Nigel
On Tue, 2005-07-19 at 06:05, Santiago Leon wrote:
> These patches add support for software-suspend-2 on the ppc64
> platform... I have tested and works nicely on a PAPR pSeries partition
> with virtual console, disk , and network (hvc_console, ibmvscsi, and
> ibmveth, respectively) hibernating to a file... It applies to the latest
> ssusp2 development version (2.1.9.9 which applies to the 2.6.12.2
> kernel)...
>
> Comments and suggestions are always welcome...
>
> Signed-off-by: Santiago Leon <santil at us.ibm.com>
>
>
>
>
> ______________________________________________________________________
> diff -urN corig/arch/ppc64/Kconfig c/arch/ppc64/Kconfig
> --- corig/arch/ppc64/Kconfig 2005-07-14 16:55:40.000000000 -0500
> +++ c/arch/ppc64/Kconfig 2005-07-14 15:55:52.000000000 -0500
> @@ -339,6 +339,12 @@
>
> source "drivers/pci/Kconfig"
>
> +menu "Power management options"
> +
> +source kernel/power/Kconfig
> +
> +endmenu
> +
> config HOTPLUG_CPU
> bool "Support for hot-pluggable CPUs"
> depends on SMP && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC)
> diff -urN corig/arch/ppc64/kernel/Makefile c/arch/ppc64/kernel/Makefile
> --- corig/arch/ppc64/kernel/Makefile 2005-07-14 16:55:40.000000000 -0500
> +++ c/arch/ppc64/kernel/Makefile 2005-07-14 15:55:52.000000000 -0500
> @@ -62,6 +62,7 @@
> obj-$(CONFIG_PPC_MAPLE) += smp-tbsync.o
> endif
>
> +obj-$(CONFIG_SUSPEND2) += suspend2.o
> obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o
> obj-$(CONFIG_KPROBES) += kprobes.o
>
> diff -urN corig/arch/ppc64/kernel/rtasd.c c/arch/ppc64/kernel/rtasd.c
> --- corig/arch/ppc64/kernel/rtasd.c 2005-07-14 16:55:41.000000000 -0500
> +++ c/arch/ppc64/kernel/rtasd.c 2005-07-14 16:11:46.000000000 -0500
> @@ -413,6 +413,8 @@
> /* Drop hotplug lock, and sleep for the specified delay */
> unlock_cpu_hotplug();
> set_current_state(TASK_INTERRUPTIBLE);
> + try_to_freeze();
> +
> schedule_timeout(delay);
> lock_cpu_hotplug();
>
> diff -urN corig/arch/ppc64/kernel/setup.c c/arch/ppc64/kernel/setup.c
> --- corig/arch/ppc64/kernel/setup.c 2005-07-14 16:55:41.000000000 -0500
> +++ c/arch/ppc64/kernel/setup.c 2005-07-14 15:55:52.000000000 -0500
> @@ -700,6 +700,8 @@
>
> EXPORT_SYMBOL(machine_halt);
>
> +void (*pm_power_off)(void) = machine_power_off;
> +
> unsigned long ppc_proc_freq;
> unsigned long ppc_tb_freq;
>
> diff -urN corig/arch/ppc64/kernel/signal.c c/arch/ppc64/kernel/signal.c
> --- corig/arch/ppc64/kernel/signal.c 2005-07-14 16:55:41.000000000 -0500
> +++ c/arch/ppc64/kernel/signal.c 2005-07-14 16:09:16.000000000 -0500
> @@ -534,6 +534,20 @@
> int signr;
> struct k_sigaction ka;
>
> + if (try_to_freeze()) {
> + signr = 0;
> + if (!signal_pending(current))
> + goto no_signal;
> + }
> +
> + if (freezing(current)) {
> + try_to_freeze();
> + signr = 0;
> + recalc_sigpending();
> + if (!signal_pending(current))
> + goto no_signal;
> + }
> +
> /*
> * If the current thread is 32 bit - invoke the
> * 32 bit signal handling code
> @@ -552,6 +566,7 @@
> return handle_signal(signr, &ka, &info, oldset, regs);
> }
>
> +no_signal:
> if (TRAP(regs) == 0x0C00) { /* System Call! */
> if ((int)regs->result == -ERESTARTNOHAND ||
> (int)regs->result == -ERESTARTSYS ||
> diff -urN corig/arch/ppc64/kernel/suspend2.c c/arch/ppc64/kernel/suspend2.c
> --- corig/arch/ppc64/kernel/suspend2.c 1969-12-31 18:00:00.000000000 -0600
> +++ c/arch/ppc64/kernel/suspend2.c 2005-07-14 20:01:33.000000000 -0500
> @@ -0,0 +1,164 @@
> +/*
> + * Written by Santiago Leon (santil at us.ibm.com) IBM Corp.
> + * based on ppc implementation by Hu Gang (hugang at soulinfo.com)
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version
> + * 2 of the License, or (at your option) any later version.
> + */
> +
> +#include <linux/suspend.h>
> +#include <linux/irq.h>
> +#include <asm/tlbflush.h>
> +#include <asm/suspend2.h>
> +
> +#ifdef CONFIG_SMP
> +struct saved_context suspend2_saved_contexts[NR_CPUS];
> +#endif
> +extern atomic_t suspend_cpu_counter __nosavedata;
> +
> +inline void __save_processor_state(struct saved_context *s)
> +{
> + asm volatile ("std 1,%0" : "=m" (s->sp));
> + asm volatile ("std 2,%0" : "=m" (s->r2));
> + asm volatile ("std 12,%0" : "=m" (s->r[0]));
> + asm volatile ("std 13,%0" : "=m" (s->r[1]));
> + asm volatile ("std 14,%0" : "=m" (s->r[2]));
> + asm volatile ("std 15,%0" : "=m" (s->r[3]));
> + asm volatile ("std 16,%0" : "=m" (s->r[4]));
> + asm volatile ("std 17,%0" : "=m" (s->r[5]));
> + asm volatile ("std 18,%0" : "=m" (s->r[6]));
> + asm volatile ("std 19,%0" : "=m" (s->r[7]));
> + asm volatile ("std 20,%0" : "=m" (s->r[8]));
> + asm volatile ("std 21,%0" : "=m" (s->r[9]));
> + asm volatile ("std 22,%0" : "=m" (s->r[10]));
> + asm volatile ("std 23,%0" : "=m" (s->r[11]));
> + asm volatile ("std 24,%0" : "=m" (s->r[12]));
> + asm volatile ("std 25,%0" : "=m" (s->r[13]));
> + asm volatile ("std 26,%0" : "=m" (s->r[14]));
> + asm volatile ("std 27,%0" : "=m" (s->r[15]));
> + asm volatile ("std 28,%0" : "=m" (s->r[16]));
> + asm volatile ("std 29,%0" : "=m" (s->r[17]));
> + asm volatile ("std 30,%0" : "=m" (s->r[18]));
> + asm volatile ("std 31,%0" : "=m" (s->r[19]));
> +
> + asm volatile ("mftb 4; std 4,%0": "=m" (s->tb));
> +
> + /* Save SPRGs */
> + asm volatile ("mfsprg 4,0; std 4,%0 " : "=m" (s->sprg[0]));
> + asm volatile ("mfsprg 4,1; std 4,%0 " : "=m" (s->sprg[1]));
> + asm volatile ("mfsprg 4,2; std 4,%0 " : "=m" (s->sprg[2]));
> + asm volatile ("mfsprg 4,3; std 4,%0 " : "=m" (s->sprg[3]));
> +
> + /* Save MSR & SDR1 */
> + asm volatile ("mfmsr 4; std 4,%0" : "=m" (s->msr));
> + asm volatile ("mfsdr1 4; std 4,%0": "=m" (s->sdr1));
> +}
> +
> +inline void __restore_processor_state(struct saved_context *s)
> +{
> + /* Restore MSR and SDR1 */
> + asm volatile ("ld 4,%0; mtsdr1 4" : "=m" (s->sdr1));
> + asm volatile ("ld 4,%0; mtmsr 4" : "=m" (s->msr));
> +
> + /* Restore SPRGs */
> + asm volatile ("ld 4,%0; mtsprg 0,4": "=m" (s->sprg[0]));
> + asm volatile ("ld 4,%0; mtsprg 1,4": "=m" (s->sprg[1]));
> + asm volatile ("ld 4,%0; mtsprg 2,4": "=m" (s->sprg[2]));
> + asm volatile ("ld 4,%0; mtsprg 3,4": "=m" (s->sprg[3]));
> +
> + /* Restore TB */
> + asm volatile ("li 3,0; mttbl 3; \n"
> + "lwz 3,%0\n; lwz 4,%1\n"
> + "mttbu 3; mttbl 4" :
> + "=m" (s->tb[0]),
> + "=m" (s->tb[1]) : : "r3");
> +
> + /* Restore the callee-saved registers and return */
> + asm volatile ("ld 12,%0" : "=m" (s->r[0]));
> + asm volatile ("ld 13,%0" : "=m" (s->r[1]));
> + asm volatile ("ld 14,%0" : "=m" (s->r[2]));
> + asm volatile ("ld 15,%0" : "=m" (s->r[3]));
> + asm volatile ("ld 16,%0" : "=m" (s->r[4]));
> + asm volatile ("ld 17,%0" : "=m" (s->r[5]));
> + asm volatile ("ld 18,%0" : "=m" (s->r[6]));
> + asm volatile ("ld 19,%0" : "=m" (s->r[7]));
> + asm volatile ("ld 20,%0" : "=m" (s->r[8]));
> + asm volatile ("ld 21,%0" : "=m" (s->r[9]));
> + asm volatile ("ld 22,%0" : "=m" (s->r[10]));
> + asm volatile ("ld 23,%0" : "=m" (s->r[11]));
> + asm volatile ("ld 24,%0" : "=m" (s->r[12]));
> + asm volatile ("ld 25,%0" : "=m" (s->r[13]));
> + asm volatile ("ld 26,%0" : "=m" (s->r[14]));
> + asm volatile ("ld 27,%0" : "=m" (s->r[15]));
> + asm volatile ("ld 28,%0" : "=m" (s->r[16]));
> + asm volatile ("ld 29,%0" : "=m" (s->r[17]));
> + asm volatile ("ld 30,%0" : "=m" (s->r[18]));
> + asm volatile ("ld 31,%0" : "=m" (s->r[19]));
> +
> + asm volatile ("ld 2,%0" : "=m" (s->r2));
> + asm volatile ("ld 1,%0" : "=m" (s->sp));
> +}
> +
> +
> +
> +#ifdef CONFIG_SMP
> +
> +/*
> + * Save and restore processor state for secondary processors.
> + * IRQs (and therefore preemption) are already disabled
> + * when we enter here (IPI).
> + */
> +void __smp_suspend_lowlevel(void * data)
> +{
> +
> + if (test_suspend_state(SUSPEND_NOW_RESUMING)) {
> + BUG_ON(!irqs_disabled());
> + atomic_inc(&suspend_cpu_counter);
> + /* Only image copied back while we spin in this loop. Our
> + * task info should not be looked at while this is happening
> + * (which smp_processor_id() will do( */
> + while (test_suspend_state(SUSPEND_FREEZE_SMP)) {
> + cpu_relax();
> + barrier();
> + }
> +
> + while (atomic_read(&suspend_cpu_counter)
> + != _smp_processor_id()) {
> + cpu_relax();
> + barrier();
> + }
> +
> + __restore_processor_state(suspend2_saved_contexts +
> + _smp_processor_id());
> + local_flush_tlb();
> + atomic_dec(&suspend_cpu_counter);
> + } else { /* suspending */
> + BUG_ON(!irqs_disabled());
> + /*
> + *Save context and go back to idling.
> + * Note that we cannot leave the processor
> + * here. It must be able to receive IPIs if
> + * the LZF compression driver (eg) does a
> + * vfree after compressing the kernel etc
> + */
> + while (test_suspend_state(SUSPEND_FREEZE_SMP) &&
> + (atomic_read(&suspend_cpu_counter)
> + != (_smp_processor_id() - 1))) {
> + cpu_relax();
> + barrier();
> + }
> + __save_processor_state(suspend2_saved_contexts +
> + _smp_processor_id());
> + atomic_inc(&suspend_cpu_counter);
> + /* Now spin until the atomic copy of the kernel is made. */
> + while (test_suspend_state(SUSPEND_FREEZE_SMP)) {
> + cpu_relax();
> + barrier();
> + }
> + atomic_dec(&suspend_cpu_counter);
> + }
> +}
> +
> +#endif
> diff -urN corig/arch/ppc64/kernel/vmlinux.lds.S c/arch/ppc64/kernel/vmlinux.lds.S
> --- corig/arch/ppc64/kernel/vmlinux.lds.S 2005-07-14 16:55:41.000000000 -0500
> +++ c/arch/ppc64/kernel/vmlinux.lds.S 2005-07-14 15:55:52.000000000 -0500
> @@ -101,6 +101,13 @@
>
>
> /* Read/write sections */
> +
> + . = ALIGN(4096);
> + __nosave_begin = .;
> + .data_nosave : { *(.data.nosave) }
> + . = ALIGN(4096);
> + __nosave_end = .;
> +
> . = ALIGN(16384);
> /* The initial task and kernel stack */
> .data.init_task : {
> diff -urN corig/arch/ppc64/mm/init.c c/arch/ppc64/mm/init.c
> --- corig/arch/ppc64/mm/init.c 2005-07-14 16:55:41.000000000 -0500
> +++ c/arch/ppc64/mm/init.c 2005-07-14 15:55:52.000000000 -0500
> @@ -39,6 +39,7 @@
> #include <linux/idr.h>
> #include <linux/nodemask.h>
> #include <linux/module.h>
> +#include <linux/suspend.h>
>
> #include <asm/pgalloc.h>
> #include <asm/page.h>
> @@ -461,6 +462,7 @@
> addr = (unsigned long)__init_begin;
> for (; addr < (unsigned long)__init_end; addr += PAGE_SIZE) {
> ClearPageReserved(virt_to_page(addr));
> + ClearPageNosave(virt_to_page(addr));
> set_page_count(virt_to_page(addr), 1);
> free_page(addr);
> totalram_pages++;
> @@ -476,6 +478,7 @@
> printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
> for (; start < end; start += PAGE_SIZE) {
> ClearPageReserved(virt_to_page(start));
> + ClearPageNosave(virt_to_page(start));
> set_page_count(virt_to_page(start), 1);
> free_page(start);
> totalram_pages++;
> @@ -730,8 +733,13 @@
> for_each_pgdat(pgdat) {
> for (i = 0; i < pgdat->node_spanned_pages; i++) {
> page = pgdat->node_mem_map + i;
> + void* addr = pfn_to_kaddr(page_to_pfn(page));
> if (PageReserved(page))
> reservedpages++;
> + if (addr >= (void *)&__nosave_begin
> + && addr < (void *)&__nosave_end)
> + SetPageNosave(virt_to_page(addr));
> +
> }
> }
>
> diff -urN corig/include/asm-ppc64/suspend2.h c/include/asm-ppc64/suspend2.h
> --- corig/include/asm-ppc64/suspend2.h 1969-12-31 18:00:00.000000000 -0600
> +++ c/include/asm-ppc64/suspend2.h 2005-07-14 20:01:54.000000000 -0500
> @@ -0,0 +1,91 @@
> +/*
> + * Written by Santiago Leon (santil at us.ibm.com) IBM Corp.
> + * based on ppc implementation by Hu Gang (hugang at soulinfo.com)
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version
> + * 2 of the License, or (at your option) any later version.
> + */
> +
> +/* image of the saved processor states */
> +struct saved_context {
> + u32 cr;
> + u64 lr, sp, r2;
> + u64 r[20]; /* r12 - r31 */
> + u64 sprg[4];
> + u64 msr, sdr1;
> + u32 tb[2];
> +};
> +
> +inline void __save_processor_state(struct saved_context *s);
> +inline void __restore_processor_state(struct saved_context *s);
> +
> +static struct saved_context suspend_saved_context;
> +static unsigned long new_stack_page;
> +extern atomic_t suspend_cpu_counter __nosavedata;
> +
> +static inline void suspend2_save_processor_context(void)
> +{
> + __save_processor_state(&suspend_saved_context);
> +}
> +
> +static inline void suspend2_restore_processor_context(void)
> +{
> + __restore_processor_state(&suspend_saved_context);
> +
> + enable_kernel_fp();
> +}
> +
> +static inline void suspend2_pre_copy(void)
> +{
> +}
> +
> +static inline void suspend2_post_copy(void)
> +{
> +}
> +
> +static inline void suspend2_pre_copyback(void)
> +{
> +}
> +
> +static inline void suspend2_post_copyback(void)
> +{
> + /* Get other CPUs to restore their contexts and flush their tlbs. */
> + clear_suspend_state(SUSPEND_FREEZE_SMP);
> +
> + do {
> + cpu_relax();
> + barrier();
> + } while (atomic_read(&suspend_cpu_counter));
> +
> +}
> +
> +static inline void suspend2_flush_caches(void)
> +{
> +}
> +
> +
> +static inline void move_stack_to_nonconflicing_area(void)
> +{
> + unsigned long old_stack, src;
> +
> + new_stack_page =
> + suspend2_get_nonconflicting_pages(get_order(THREAD_SIZE));
> +
> + BUG_ON(!new_stack_page);
> +
> + /* geting stack address */
> + asm volatile ("std %%r1, %0" : "=m" (old_stack));
> +
> + src = old_stack & (~(THREAD_SIZE - 1));
> +
> + /* Copy stack */
> + memcpy((void*)new_stack_page, (void*)src, THREAD_SIZE);
> +
> + new_stack_page += (old_stack - src);
> +
> + /* switch to new stack */
> + asm volatile ("ld %%r1, %0" : "=m" (new_stack_page));
> +
> +}
> diff -urN corig/include/asm-ppc64/tlbflush.h c/include/asm-ppc64/tlbflush.h
> --- corig/include/asm-ppc64/tlbflush.h 2005-07-14 16:55:59.000000000 -0500
> +++ c/include/asm-ppc64/tlbflush.h 2005-07-14 15:55:52.000000000 -0500
> @@ -39,6 +39,7 @@
> put_cpu_var(ppc64_tlb_batch);
> }
>
> +#define local_flush_tlb() flush_tlb_pending()
> #define flush_tlb_mm(mm) flush_tlb_pending()
> #define flush_tlb_page(vma, addr) flush_tlb_pending()
> #define flush_tlb_page_nohash(vma, addr) do { } while (0)
> diff -urN corig/kernel/power/driver_model.c c/kernel/power/driver_model.c
> --- corig/kernel/power/driver_model.c 2005-07-14 17:02:22.000000000 -0500
> +++ c/kernel/power/driver_model.c 2005-07-14 16:13:20.000000000 -0500
> @@ -9,6 +9,7 @@
> */
>
> #include <linux/pm.h>
> +#include <asm/bug.h>
> #include "driver_model.h"
> #include "power_off.h"
>
>
>
> ______________________________________________________________________
> _______________________________________________
> Suspend2-devel mailing list
> Suspend2-devel at lists.suspend2.net
> http://lists.suspend2.net/mailman/listinfo/suspend2-devel
--
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
More information about the Linuxppc64-dev
mailing list