Messages in this thread | | | Subject | Re: [PATCH 1/3] swsusp add architecture special saveable pages support | From | Shaohua Li <> | Date | Wed, 12 Apr 2006 13:04:20 +0800 |
| |
On Wed, 2006-04-12 at 06:55 +0200, Pavel Machek wrote: > > > > 1. Add architecture specific pages save/restore support. Next two patches will > > use this to save/restore 'ACPI NVS' pages. > > 2. Allow reserved pages 'nosave'. This could avoid save/restore BIOS reserved > > pages. > > I'm not 100% convinced that it is needed, but if BIOS people say it > is, lets believe them. Code looks ok. ACPI spec 3.0 also says in P387, P405 reserved pages should not be saved/restored and ACPI NVS should be saved/restored in S4.
Thanks, Shaohua > > Pavel > > > > Signed-off-by: Shaohua Li <shaohua.li@intel.com> > > --- > > > > linux-2.6.17-rc1-root/include/linux/suspend.h | 1 > > linux-2.6.17-rc1-root/kernel/power/power.h | 4 + > > linux-2.6.17-rc1-root/kernel/power/snapshot.c | 100 +++++++++++++++++++++++++- > > linux-2.6.17-rc1-root/kernel/power/swsusp.c | 18 +--- > > 4 files changed, 108 insertions(+), 15 deletions(-) > > > > diff -puN kernel/power/snapshot.c~swsusp_save_pages kernel/power/snapshot.c > > --- linux-2.6.17-rc1/kernel/power/snapshot.c~swsusp_save_pages 2006-04-10 09:14:35.000000000 +0800 > > +++ linux-2.6.17-rc1-root/kernel/power/snapshot.c 2006-04-11 08:03:21.000000000 +0800 > > @@ -39,6 +39,78 @@ static unsigned int nr_copy_pages; > > static unsigned int nr_meta_pages; > > static unsigned long *buffer; > > > > +struct arch_saveable_page { > > + unsigned long pfn; > > + void *data; > > + struct arch_saveable_page *next; > > +}; > > +static struct arch_saveable_page *arch_pages; > > + > > +int swsusp_add_arch_pages(unsigned long start, unsigned long end) > > +{ > > + struct arch_saveable_page *tmp; > > + > > + while (start <= end) { > > + tmp = kzalloc(sizeof(struct arch_saveable_page), GFP_KERNEL); > > + if (!tmp) > > + return -ENOMEM; > > + tmp->pfn = start; > > + tmp->next = arch_pages; > > + start++; > > + arch_pages = tmp; > > + } > > + return 0; > > +} > > + > > +static unsigned int count_arch_pages(void) > > +{ > > + unsigned int count = 0; > > + struct arch_saveable_page *tmp = arch_pages; > > + while (tmp) { > > + count++; > > + tmp = tmp->next; > > + } > > + return count; > > +} > > + > > +static int save_arch_mem(void) > > +{ > > + void *kaddr; > > + struct arch_saveable_page *tmp = arch_pages; > > + > > + pr_debug("swsusp: Saving arch specific memory"); > > + while (tmp) { > > + tmp->data = (void *)get_zeroed_page(GFP_ATOMIC); > > + if (!tmp->data) > > + return -ENOMEM; > > + /* arch pages might haven't a 'struct page' */ > > + kaddr = kmap_atomic_pfn(tmp->pfn, KM_PTE0); > > + memcpy(tmp->data, kaddr, PAGE_SIZE); > > + kunmap_atomic(kaddr, KM_PTE0); > > + > > + tmp = tmp->next; > > + } > > + return 0; > > +} > > + > > +static int restore_arch_mem(void) > > +{ > > + void *kaddr; > > + struct arch_saveable_page *tmp = arch_pages; > > + > > + while (tmp) { > > + if (!tmp->data) > > + continue; > > + kaddr = kmap_atomic_pfn(tmp->pfn, KM_PTE0); > > + memcpy(kaddr, tmp->data, PAGE_SIZE); > > + kunmap_atomic(kaddr, KM_PTE0); > > + free_page((long)tmp->data); > > + tmp->data = NULL; > > + tmp = tmp->next; > > + } > > + return 0; > > +} > > + > > #ifdef CONFIG_HIGHMEM > > unsigned int count_highmem_pages(void) > > { > > @@ -150,8 +222,35 @@ int restore_highmem(void) > > } > > return 0; > > } > > +#else > > +static unsigned int count_highmem_pages(void) {return 0;} > > +static int save_highmem(void) {return 0;} > > +static int restore_highmem(void) {return 0;} > > #endif > > > > +unsigned int count_special_pages(void) > > +{ > > + return count_arch_pages() + count_highmem_pages(); > > +} > > + > > +int save_special_mem(void) > > +{ > > + int ret; > > + ret = save_arch_mem(); > > + if (!ret) > > + ret = save_highmem(); > > + return ret; > > +} > > + > > +int restore_special_mem(void) > > +{ > > + int ret; > > + ret = restore_arch_mem(); > > + if (!ret) > > + ret = restore_highmem(); > > + return ret; > > +} > > + > > static int pfn_is_nosave(unsigned long pfn) > > { > > unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT; > > @@ -177,7 +276,6 @@ static int saveable(struct zone *zone, u > > return 0; > > > > page = pfn_to_page(pfn); > > - BUG_ON(PageReserved(page) && PageNosave(page)); > > if (PageNosave(page)) > > return 0; > > if (PageReserved(page) && pfn_is_nosave(pfn)) > > diff -puN kernel/power/swsusp.c~swsusp_save_pages kernel/power/swsusp.c > > --- linux-2.6.17-rc1/kernel/power/swsusp.c~swsusp_save_pages 2006-04-10 09:14:35.000000000 +0800 > > +++ linux-2.6.17-rc1-root/kernel/power/swsusp.c 2006-04-11 08:02:02.000000000 +0800 > > @@ -62,16 +62,6 @@ unsigned long image_size = 500 * 1024 * > > > > int in_suspend __nosavedata = 0; > > > > -#ifdef CONFIG_HIGHMEM > > -unsigned int count_highmem_pages(void); > > -int save_highmem(void); > > -int restore_highmem(void); > > -#else > > -static int save_highmem(void) { return 0; } > > -static int restore_highmem(void) { return 0; } > > -static unsigned int count_highmem_pages(void) { return 0; } > > -#endif > > - > > /** > > * The following functions are used for tracing the allocated > > * swap pages, so that they can be freed in case of an error. > > @@ -186,7 +176,7 @@ int swsusp_shrink_memory(void) > > > > printk("Shrinking memory... "); > > do { > > - size = 2 * count_highmem_pages(); > > + size = 2 * count_special_pages(); > > size += size / 50 + count_data_pages(); > > size += (size + PBES_PER_PAGE - 1) / PBES_PER_PAGE + > > PAGES_FOR_IO; > > @@ -228,7 +218,7 @@ int swsusp_suspend(void) > > goto Enable_irqs; > > } > > > > - if ((error = save_highmem())) { > > + if ((error = save_special_mem())) { > > printk(KERN_ERR "swsusp: Not enough free pages for highmem\n"); > > goto Restore_highmem; > > } > > @@ -239,7 +229,7 @@ int swsusp_suspend(void) > > /* Restore control flow magically appears here */ > > restore_processor_state(); > > Restore_highmem: > > - restore_highmem(); > > + restore_special_mem(); > > device_power_up(); > > Enable_irqs: > > local_irq_enable(); > > @@ -265,7 +255,7 @@ int swsusp_resume(void) > > */ > > swsusp_free(); > > restore_processor_state(); > > - restore_highmem(); > > + restore_special_mem(); > > touch_softlockup_watchdog(); > > device_power_up(); > > local_irq_enable(); > > diff -puN include/linux/suspend.h~swsusp_save_pages include/linux/suspend.h > > --- linux-2.6.17-rc1/include/linux/suspend.h~swsusp_save_pages 2006-04-10 09:14:35.000000000 +0800 > > +++ linux-2.6.17-rc1-root/include/linux/suspend.h 2006-04-10 09:14:35.000000000 +0800 > > @@ -72,6 +72,7 @@ struct saved_context; > > void __save_processor_state(struct saved_context *ctxt); > > void __restore_processor_state(struct saved_context *ctxt); > > unsigned long get_safe_page(gfp_t gfp_mask); > > +int swsusp_add_arch_pages(unsigned long start, unsigned long end); > > > > /* > > * XXX: We try to keep some more pages free so that I/O operations succeed > > diff -puN kernel/power/power.h~swsusp_save_pages kernel/power/power.h > > --- linux-2.6.17-rc1/kernel/power/power.h~swsusp_save_pages 2006-04-11 08:00:30.000000000 +0800 > > +++ linux-2.6.17-rc1-root/kernel/power/power.h 2006-04-11 08:02:03.000000000 +0800 > > @@ -105,6 +105,10 @@ extern struct bitmap_page *alloc_bitmap( > > extern unsigned long alloc_swap_page(int swap, struct bitmap_page *bitmap); > > extern void free_all_swap_pages(int swap, struct bitmap_page *bitmap); > > > > +extern unsigned int count_special_pages(void); > > +extern int save_special_mem(void); > > +extern int restore_special_mem(void); > > + > > extern int swsusp_check(void); > > extern int swsusp_shrink_memory(void); > > extern void swsusp_free(void); > > _ > > > > > -- Shaohua Li <shaohua.li@intel.com>
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |