[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