diff options
author | Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com> | 2017-05-22 00:15:23 +0900 |
---|---|---|
committer | Jan-Simon Moeller <jsmoeller@linuxfoundation.org> | 2017-05-25 13:47:13 +0000 |
commit | a14e289caaae4c342c2bc686bd5d327ed612b0fc (patch) | |
tree | 87cc82526cadd31c77f72a208421e44ee97e7a3a /meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0001-Add-Hibernation-kernel-base-code.patch | |
parent | 5b5a54b60f45e67d647cf6cc0fe2b879b2bb8229 (diff) |
Add kernel Hibernation code for porter board.
This patch set is a support to Hibernation for a porter board.
I've commit with Hibernation Off patch, because it depends strongly on user land.
If you can use Hibernation, Please add local.conf agl-porter-hibernate.
OVERRIDES .= ":agl-porter-hibernate"
DISTRO_FEATURES_append = " agl-porter-hibernate"
Change-Id: Ic64c9494a4bbd2518ef1aa334325b96eb7a9479e
Signed-off-by: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
Reviewed-on: https://gerrit.automotivelinux.org/gerrit/9451
Tested-by: Jenkins Job builder account <agl-jobbuilder@automotivelinux.org>
ci-image-build: Jenkins Job builder account <agl-jobbuilder@automotivelinux.org>
Reviewed-by: Jan-Simon Moeller <jsmoeller@linuxfoundation.org>
Diffstat (limited to 'meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0001-Add-Hibernation-kernel-base-code.patch')
-rwxr-xr-x | meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0001-Add-Hibernation-kernel-base-code.patch | 853 |
1 files changed, 853 insertions, 0 deletions
diff --git a/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0001-Add-Hibernation-kernel-base-code.patch b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0001-Add-Hibernation-kernel-base-code.patch new file mode 100755 index 000000000..87cd2863a --- /dev/null +++ b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0001-Add-Hibernation-kernel-base-code.patch @@ -0,0 +1,853 @@ +From 60123966221b74199e4cf0c18d43396b4f00a94a Mon Sep 17 00:00:00 2001 +From: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com> +Date: Thu, 18 May 2017 16:44:34 +0900 +Subject: [PATCH 01/15] Add Hibernation kernel base code + +Signed-off-by: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com> +--- + include/linux/sched.h | 1 + + include/linux/suspend.h | 2 + + kernel/auditfilter.c | 2 +- + kernel/power/console.c | 2 + + kernel/power/hibernate.c | 146 +++++++++++++++++++++++++++++++---------------- + kernel/power/main.c | 4 -- + kernel/power/power.h | 8 ++- + kernel/power/process.c | 35 ++++++++---- + kernel/power/snapshot.c | 33 +++++++---- + kernel/power/suspend.c | 4 +- + kernel/power/swap.c | 50 ++++++++++++++-- + 11 files changed, 201 insertions(+), 86 deletions(-) + +diff --git a/include/linux/sched.h b/include/linux/sched.h +index f87e9a8..8e3270c 100644 +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -1644,6 +1644,7 @@ extern void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut, + #define PF_MEMPOLICY 0x10000000 /* Non-default NUMA mempolicy */ + #define PF_MUTEX_TESTER 0x20000000 /* Thread belongs to the rt mutex tester */ + #define PF_FREEZER_SKIP 0x40000000 /* Freezer should not count it as freezable */ ++#define PF_SUSPEND_TASK 0x80000000 /* this thread called freeze_processes and should not be frozen */ + + /* + * Only the _current_ task can read/write to tsk->flags, but other +diff --git a/include/linux/suspend.h b/include/linux/suspend.h +index d4e3f16..243ff56 100644 +--- a/include/linux/suspend.h ++++ b/include/linux/suspend.h +@@ -320,6 +320,8 @@ extern unsigned long get_safe_page(gfp_t gfp_mask); + extern void hibernation_set_ops(const struct platform_hibernation_ops *ops); + extern int hibernate(void); + extern bool system_entering_hibernation(void); ++asmlinkage int swsusp_save(void); ++extern struct pbe *restore_pblist; + #else /* CONFIG_HIBERNATION */ + static inline void register_nosave_region(unsigned long b, unsigned long e) {} + static inline void register_nosave_region_late(unsigned long b, unsigned long e) {} +diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c +index 6bd4a90..ac08a9a 100644 +--- a/kernel/auditfilter.c ++++ b/kernel/auditfilter.c +@@ -423,7 +423,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, + f->lsm_rule = NULL; + + /* Support legacy tests for a valid loginuid */ +- if ((f->type == AUDIT_LOGINUID) && (f->val == 4294967295)) { ++ if ((f->type == AUDIT_LOGINUID) && (f->val == 0xFFFFFFFF)) { + f->type = AUDIT_LOGINUID_SET; + f->val = 0; + } +diff --git a/kernel/power/console.c b/kernel/power/console.c +index 463aa67..aba9c54 100644 +--- a/kernel/power/console.c ++++ b/kernel/power/console.c +@@ -9,6 +9,7 @@ + #include <linux/kbd_kern.h> + #include <linux/vt.h> + #include <linux/module.h> ++#include <linux/slab.h> + #include "power.h" + + #define SUSPEND_CONSOLE (MAX_NR_CONSOLES-1) +@@ -81,6 +82,7 @@ void pm_vt_switch_unregister(struct device *dev) + list_for_each_entry(tmp, &pm_vt_switch_list, head) { + if (tmp->dev == dev) { + list_del(&tmp->head); ++ kfree(tmp); + break; + } + } +diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c +index b26f5f1..524dcf5 100644 +--- a/kernel/power/hibernate.c ++++ b/kernel/power/hibernate.c +@@ -34,12 +34,13 @@ + + static int nocompress; + static int noresume; ++static int nohibernate; + static int resume_wait; +-static int resume_delay; ++static unsigned int resume_delay; + static char resume_file[256] = CONFIG_PM_STD_PARTITION; + dev_t swsusp_resume_device; + sector_t swsusp_resume_block; +-int in_suspend __nosavedata; ++__visible int in_suspend __nosavedata; + + enum { + HIBERNATION_INVALID, +@@ -61,6 +62,11 @@ bool freezer_test_done; + + static const struct platform_hibernation_ops *hibernation_ops; + ++bool hibernation_available(void) ++{ ++ return (nohibernate == 0); ++} ++ + /** + * hibernation_set_ops - Set the global hibernate operations. + * @ops: Hibernation operations to use in subsequent hibernation transitions. +@@ -82,6 +88,7 @@ void hibernation_set_ops(const struct platform_hibernation_ops *ops) + + unlock_system_sleep(); + } ++EXPORT_SYMBOL_GPL(hibernation_set_ops); + + static bool entering_platform_hibernation; + +@@ -227,19 +234,23 @@ static void platform_recover(int platform_mode) + void swsusp_show_speed(struct timeval *start, struct timeval *stop, + unsigned nr_pages, char *msg) + { +- s64 elapsed_centisecs64; +- int centisecs; +- int k; +- int kps; ++ u64 elapsed_centisecs64; ++ unsigned int centisecs; ++ unsigned int k; ++ unsigned int kps; + + elapsed_centisecs64 = timeval_to_ns(stop) - timeval_to_ns(start); ++ /* ++ * If "(s64)elapsed_centisecs64 < 0", it will print long elapsed time, ++ * it is obvious enough for what went wrong. ++ */ + do_div(elapsed_centisecs64, NSEC_PER_SEC / 100); + centisecs = elapsed_centisecs64; + if (centisecs == 0) + centisecs = 1; /* avoid div-by-zero */ + k = nr_pages * (PAGE_SIZE / 1024); + kps = (k * 100) / centisecs; +- printk(KERN_INFO "PM: %s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n", ++ pr_info("PM: %s %u kbytes in %u.%02u seconds (%u.%02u MB/s)\n", + msg, k, + centisecs / 100, centisecs % 100, + kps / 1000, (kps % 1000) / 10); +@@ -293,10 +304,10 @@ static int create_image(int platform_mode) + error); + /* Restore control flow magically appears here */ + restore_processor_state(); +- if (!in_suspend) { ++ if (!in_suspend) + events_check_enabled = false; +- platform_leave(platform_mode); +- } ++ ++ platform_leave(platform_mode); + + Power_up: + syscore_resume(); +@@ -594,7 +605,8 @@ static void power_down(void) + case HIBERNATION_PLATFORM: + hibernation_platform_enter(); + case HIBERNATION_SHUTDOWN: +- kernel_power_off(); ++ if (pm_power_off) ++ kernel_power_off(); + break; + #ifdef CONFIG_SUSPEND + case HIBERNATION_SUSPEND: +@@ -622,7 +634,8 @@ static void power_down(void) + * corruption after resume. + */ + printk(KERN_CRIT "PM: Please power down manually\n"); +- while(1); ++ while (1) ++ cpu_relax(); + } + + /** +@@ -632,6 +645,11 @@ int hibernate(void) + { + int error; + ++ if (!hibernation_available()) { ++ pr_debug("PM: Hibernation not available.\n"); ++ return -EPERM; ++ } ++ + lock_system_sleep(); + /* The snapshot device should not be opened while we're running */ + if (!atomic_add_unless(&snapshot_device_available, -1, 0)) { +@@ -644,22 +662,22 @@ int hibernate(void) + if (error) + goto Exit; + +- /* Allocate memory management structures */ +- error = create_basic_memory_bitmaps(); +- if (error) +- goto Exit; +- + printk(KERN_INFO "PM: Syncing filesystems ... "); + sys_sync(); + printk("done.\n"); + + error = freeze_processes(); + if (error) +- goto Free_bitmaps; ++ goto Exit; ++ ++ /* Allocate memory management structures */ ++ error = create_basic_memory_bitmaps(); ++ if (error) ++ goto Thaw; + + error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM); + if (error || freezer_test_done) +- goto Thaw; ++ goto Free_bitmaps; + + if (in_suspend) { + unsigned int flags = 0; +@@ -682,14 +700,13 @@ int hibernate(void) + pr_debug("PM: Image restored successfully.\n"); + } + ++ Free_bitmaps: ++ free_basic_memory_bitmaps(); + Thaw: + thaw_processes(); + + /* Don't bother checking whether freezer_test_done is true */ + freezer_test_done = false; +- +- Free_bitmaps: +- free_basic_memory_bitmaps(); + Exit: + pm_notifier_call_chain(PM_POST_HIBERNATION); + pm_restore_console(); +@@ -723,7 +740,7 @@ static int software_resume(void) + /* + * If the user said "noresume".. bail out early. + */ +- if (noresume) ++ if (noresume || !hibernation_available()) + return 0; + + /* +@@ -806,21 +823,19 @@ static int software_resume(void) + pm_prepare_console(); + error = pm_notifier_call_chain(PM_RESTORE_PREPARE); + if (error) +- goto close_finish; +- +- error = create_basic_memory_bitmaps(); +- if (error) +- goto close_finish; ++ goto Close_Finish; + + pr_debug("PM: Preparing processes for restore.\n"); + error = freeze_processes(); +- if (error) { +- swsusp_close(FMODE_READ); +- goto Done; +- } ++ if (error) ++ goto Close_Finish; + + pr_debug("PM: Loading hibernation image.\n"); + ++ error = create_basic_memory_bitmaps(); ++ if (error) ++ goto Thaw; ++ + error = swsusp_read(&flags); + swsusp_close(FMODE_READ); + if (!error) +@@ -828,9 +843,9 @@ static int software_resume(void) + + printk(KERN_ERR "PM: Failed to load hibernation image, recovering.\n"); + swsusp_free(); +- thaw_processes(); +- Done: + free_basic_memory_bitmaps(); ++ Thaw: ++ thaw_processes(); + Finish: + pm_notifier_call_chain(PM_POST_RESTORE); + pm_restore_console(); +@@ -840,12 +855,12 @@ static int software_resume(void) + mutex_unlock(&pm_mutex); + pr_debug("PM: Hibernation image not present or could not be loaded.\n"); + return error; +-close_finish: ++ Close_Finish: + swsusp_close(FMODE_READ); + goto Finish; + } + +-late_initcall(software_resume); ++late_initcall_sync(software_resume); + + + static const char * const hibernation_modes[] = { +@@ -889,6 +904,9 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr, + int i; + char *start = buf; + ++ if (!hibernation_available()) ++ return sprintf(buf, "[disabled]\n"); ++ + for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) { + if (!hibernation_modes[i]) + continue; +@@ -923,6 +941,9 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, + char *p; + int mode = HIBERNATION_INVALID; + ++ if (!hibernation_available()) ++ return -EPERM; ++ + p = memchr(buf, '\n', n); + len = p ? p - buf : n; + +@@ -971,16 +992,20 @@ static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr, + static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n) + { +- unsigned int maj, min; + dev_t res; +- int ret = -EINVAL; ++ int len = n; ++ char *name; + +- if (sscanf(buf, "%u:%u", &maj, &min) != 2) +- goto out; ++ if (len && buf[len-1] == '\n') ++ len--; ++ name = kstrndup(buf, len, GFP_KERNEL); ++ if (!name) ++ return -ENOMEM; + +- res = MKDEV(maj,min); +- if (maj != MAJOR(res) || min != MINOR(res)) +- goto out; ++ res = name_to_dev_t(name); ++ kfree(name); ++ if (!res) ++ return -EINVAL; + + lock_system_sleep(); + swsusp_resume_device = res; +@@ -988,20 +1013,20 @@ static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr, + printk(KERN_INFO "PM: Starting manual resume from disk\n"); + noresume = 0; + software_resume(); +- ret = n; +- out: +- return ret; ++ return n; + } + + power_attr(resume); + +-static ssize_t image_size_show(struct kobject *kobj, struct kobj_attribute *attr, ++static ssize_t image_size_show(struct kobject *kobj, ++ struct kobj_attribute *attr, + char *buf) + { + return sprintf(buf, "%lu\n", image_size); + } + +-static ssize_t image_size_store(struct kobject *kobj, struct kobj_attribute *attr, ++static ssize_t image_size_store(struct kobject *kobj, ++ struct kobj_attribute *attr, + const char *buf, size_t n) + { + unsigned long size; +@@ -1065,7 +1090,7 @@ static int __init resume_setup(char *str) + if (noresume) + return 1; + +- strncpy( resume_file, str, 255 ); ++ strncpy(resume_file, str, 255); + return 1; + } + +@@ -1088,6 +1113,10 @@ static int __init hibernate_setup(char *str) + noresume = 1; + else if (!strncmp(str, "nocompress", 10)) + nocompress = 1; ++ else if (!strncmp(str, "no", 2)) { ++ noresume = 1; ++ nohibernate = 1; ++ } + return 1; + } + +@@ -1105,13 +1134,30 @@ static int __init resumewait_setup(char *str) + + static int __init resumedelay_setup(char *str) + { +- resume_delay = simple_strtoul(str, NULL, 0); ++ int rc = kstrtouint(str, 0, &resume_delay); ++ ++ if (rc) ++ return rc; ++ return 1; ++} ++ ++static int __init nohibernate_setup(char *str) ++{ ++ noresume = 1; ++ nohibernate = 1; + return 1; + } + ++static int __init kaslr_nohibernate_setup(char *str) ++{ ++ return nohibernate_setup(str); ++} ++ + __setup("noresume", noresume_setup); + __setup("resume_offset=", resume_offset_setup); + __setup("resume=", resume_setup); + __setup("hibernate=", hibernate_setup); + __setup("resumewait", resumewait_setup); + __setup("resumedelay=", resumedelay_setup); ++__setup("nohibernate", nohibernate_setup); ++__setup("kaslr", kaslr_nohibernate_setup); +diff --git a/kernel/power/main.c b/kernel/power/main.c +index d77663b..ac615e4 100644 +--- a/kernel/power/main.c ++++ b/kernel/power/main.c +@@ -610,7 +610,6 @@ static struct attribute_group attr_group = { + .attrs = g, + }; + +-#ifdef CONFIG_PM_RUNTIME + struct workqueue_struct *pm_wq; + EXPORT_SYMBOL_GPL(pm_wq); + +@@ -620,9 +619,6 @@ static int __init pm_start_workqueue(void) + + return pm_wq ? 0 : -ENOMEM; + } +-#else +-static inline int pm_start_workqueue(void) { return 0; } +-#endif + + static int __init pm_init(void) + { +diff --git a/kernel/power/power.h b/kernel/power/power.h +index 7d4b7ff..c5821ca 100644 +--- a/kernel/power/power.h ++++ b/kernel/power/power.h +@@ -2,6 +2,7 @@ + #include <linux/suspend_ioctls.h> + #include <linux/utsname.h> + #include <linux/freezer.h> ++#include <linux/compiler.h> + + struct swsusp_info { + struct new_utsname uts; +@@ -11,7 +12,8 @@ struct swsusp_info { + unsigned long image_pages; + unsigned long pages; + unsigned long size; +-} __attribute__((aligned(PAGE_SIZE))); ++ char archdata[1024]; ++} __aligned(PAGE_SIZE); + + #ifdef CONFIG_HIBERNATION + /* kernel/power/snapshot.c */ +@@ -37,6 +39,8 @@ static inline char *check_image_kernel(struct swsusp_info *info) + } + #endif /* CONFIG_ARCH_HIBERNATION_HEADER */ + ++extern void __weak swsusp_arch_add_info(char *archdata); ++ + /* + * Keep some memory free so that I/O operations can succeed without paging + * [Might this be more than 4 MB?] +@@ -49,6 +53,8 @@ static inline char *check_image_kernel(struct swsusp_info *info) + */ + #define SPARE_PAGES ((1024 * 1024) >> PAGE_SHIFT) + ++asmlinkage int swsusp_save(void); ++ + /* kernel/power/hibernate.c */ + extern bool freezer_test_done; + +diff --git a/kernel/power/process.c b/kernel/power/process.c +index 0695319..04559b4 100644 +--- a/kernel/power/process.c ++++ b/kernel/power/process.c +@@ -30,9 +30,10 @@ static int try_to_freeze_tasks(bool user_only) + unsigned int todo; + bool wq_busy = false; + struct timeval start, end; +- u64 elapsed_csecs64; +- unsigned int elapsed_csecs; ++ u64 elapsed_msecs64; ++ unsigned int elapsed_msecs; + bool wakeup = false; ++ int sleep_usecs = USEC_PER_MSEC; + + do_gettimeofday(&start); + +@@ -68,22 +69,25 @@ static int try_to_freeze_tasks(bool user_only) + + /* + * We need to retry, but first give the freezing tasks some +- * time to enter the refrigerator. ++ * time to enter the refrigerator. Start with an initial ++ * 1 ms sleep followed by exponential backoff until 8 ms. + */ +- msleep(10); ++ usleep_range(sleep_usecs / 2, sleep_usecs); ++ if (sleep_usecs < 8 * USEC_PER_MSEC) ++ sleep_usecs *= 2; + } + + do_gettimeofday(&end); +- elapsed_csecs64 = timeval_to_ns(&end) - timeval_to_ns(&start); +- do_div(elapsed_csecs64, NSEC_PER_SEC / 100); +- elapsed_csecs = elapsed_csecs64; ++ elapsed_msecs64 = timeval_to_ns(&end) - timeval_to_ns(&start); ++ do_div(elapsed_msecs64, NSEC_PER_MSEC); ++ elapsed_msecs = elapsed_msecs64; + + if (todo) { + printk("\n"); +- printk(KERN_ERR "Freezing of tasks %s after %d.%02d seconds " ++ printk(KERN_ERR "Freezing of tasks %s after %d.%03d seconds " + "(%d tasks refusing to freeze, wq_busy=%d):\n", + wakeup ? "aborted" : "failed", +- elapsed_csecs / 100, elapsed_csecs % 100, ++ elapsed_msecs / 1000, elapsed_msecs % 1000, + todo - wq_busy, wq_busy); + + if (!wakeup) { +@@ -96,8 +100,8 @@ static int try_to_freeze_tasks(bool user_only) + read_unlock(&tasklist_lock); + } + } else { +- printk("(elapsed %d.%02d seconds) ", elapsed_csecs / 100, +- elapsed_csecs % 100); ++ printk("(elapsed %d.%03d seconds) ", elapsed_msecs / 1000, ++ elapsed_msecs % 1000); + } + + return todo ? -EBUSY : 0; +@@ -139,6 +143,9 @@ int freeze_processes(void) + if (error) + return error; + ++ /* Make sure this task doesn't get frozen */ ++ current->flags |= PF_SUSPEND_TASK; ++ + if (!pm_freezing) + atomic_inc(&system_freezing_cnt); + +@@ -202,6 +209,7 @@ int freeze_kernel_threads(void) + void thaw_processes(void) + { + struct task_struct *g, *p; ++ struct task_struct *curr = current; + + if (pm_freezing) + atomic_dec(&system_freezing_cnt); +@@ -217,10 +225,15 @@ void thaw_processes(void) + + read_lock(&tasklist_lock); + do_each_thread(g, p) { ++ /* No other threads should have PF_SUSPEND_TASK set */ ++ WARN_ON((p != curr) && (p->flags & PF_SUSPEND_TASK)); + __thaw_task(p); + } while_each_thread(g, p); + read_unlock(&tasklist_lock); + ++ WARN_ON(!(curr->flags & PF_SUSPEND_TASK)); ++ curr->flags &= ~PF_SUSPEND_TASK; ++ + usermodehelper_enable(); + + schedule(); +diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c +index 91c04f1..a673f7b 100644 +--- a/kernel/power/snapshot.c ++++ b/kernel/power/snapshot.c +@@ -27,6 +27,7 @@ + #include <linux/highmem.h> + #include <linux/list.h> + #include <linux/slab.h> ++#include <linux/compiler.h> + + #include <asm/uaccess.h> + #include <asm/mmu_context.h> +@@ -155,7 +156,7 @@ static inline void free_image_page(void *addr, int clear_nosave_free) + struct linked_page { + struct linked_page *next; + char data[LINKED_PAGE_DATA_SIZE]; +-} __attribute__((packed)); ++} __packed; + + static inline void + free_list_of_pages(struct linked_page *list, int clear_page_nosave) +@@ -352,7 +353,7 @@ static int create_mem_extents(struct list_head *list, gfp_t gfp_mask) + struct mem_extent *ext, *cur, *aux; + + zone_start = zone->zone_start_pfn; +- zone_end = zone->zone_start_pfn + zone->spanned_pages; ++ zone_end = zone_end_pfn(zone); + + list_for_each_entry(ext, list, hook) + if (zone_start <= ext->end) +@@ -642,8 +643,9 @@ __register_nosave_region(unsigned long start_pfn, unsigned long end_pfn, + region->end_pfn = end_pfn; + list_add_tail(®ion->list, &nosave_regions); + Report: +- printk(KERN_INFO "PM: Registered nosave memory: %016lx - %016lx\n", +- start_pfn << PAGE_SHIFT, end_pfn << PAGE_SHIFT); ++ printk(KERN_INFO "PM: Registered nosave memory: [mem %#010llx-%#010llx]\n", ++ (unsigned long long) start_pfn << PAGE_SHIFT, ++ ((unsigned long long) end_pfn << PAGE_SHIFT) - 1); + } + + /* +@@ -742,7 +744,10 @@ int create_basic_memory_bitmaps(void) + struct memory_bitmap *bm1, *bm2; + int error = 0; + +- BUG_ON(forbidden_pages_map || free_pages_map); ++ if (forbidden_pages_map && free_pages_map) ++ return 0; ++ else ++ BUG_ON(forbidden_pages_map || free_pages_map); + + bm1 = kzalloc(sizeof(struct memory_bitmap), GFP_KERNEL); + if (!bm1) +@@ -788,7 +793,8 @@ void free_basic_memory_bitmaps(void) + { + struct memory_bitmap *bm1, *bm2; + +- BUG_ON(!(forbidden_pages_map && free_pages_map)); ++ if (WARN_ON(!(forbidden_pages_map && free_pages_map))) ++ return; + + bm1 = forbidden_pages_map; + bm2 = free_pages_map; +@@ -883,7 +889,7 @@ static unsigned int count_highmem_pages(void) + continue; + + mark_free_pages(zone); +- max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages; ++ max_zone_pfn = zone_end_pfn(zone); + for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) + if (saveable_highmem_page(zone, pfn)) + n++; +@@ -947,7 +953,7 @@ static unsigned int count_data_pages(void) + continue; + + mark_free_pages(zone); +- max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages; ++ max_zone_pfn = zone_end_pfn(zone); + for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) + if (saveable_page(zone, pfn)) + n++; +@@ -1040,7 +1046,7 @@ copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm) + unsigned long max_zone_pfn; + + mark_free_pages(zone); +- max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages; ++ max_zone_pfn = zone_end_pfn(zone); + for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) + if (page_is_saveable(zone, pfn)) + memory_bm_set_bit(orig_bm, pfn); +@@ -1092,7 +1098,7 @@ void swsusp_free(void) + unsigned long pfn, max_zone_pfn; + + for_each_populated_zone(zone) { +- max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages; ++ max_zone_pfn = zone_end_pfn(zone); + for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) + if (pfn_valid(pfn)) { + struct page *page = pfn_to_page(pfn); +@@ -1580,7 +1586,7 @@ swsusp_alloc(struct memory_bitmap *orig_bm, struct memory_bitmap *copy_bm, + return -ENOMEM; + } + +-asmlinkage int swsusp_save(void) ++asmlinkage __visible int swsusp_save(void) + { + unsigned int nr_pages, nr_highmem; + +@@ -1628,6 +1634,7 @@ static int init_header_complete(struct swsusp_info *info) + { + memcpy(&info->uts, init_utsname(), sizeof(struct new_utsname)); + info->version_code = LINUX_VERSION_CODE; ++ swsusp_arch_add_info(info->archdata); + return 0; + } + +@@ -1647,6 +1654,8 @@ static char *check_image_kernel(struct swsusp_info *info) + } + #endif /* CONFIG_ARCH_HIBERNATION_HEADER */ + ++void __weak swsusp_arch_add_info(char *archdata) {} ++ + unsigned long snapshot_get_image_size(void) + { + return nr_copy_pages + nr_meta_pages + 1; +@@ -1758,7 +1767,7 @@ static int mark_unsafe_pages(struct memory_bitmap *bm) + + /* Clear page flags */ + for_each_populated_zone(zone) { +- max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages; ++ max_zone_pfn = zone_end_pfn(zone); + for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) + if (pfn_valid(pfn)) + swsusp_unset_page_free(pfn_to_page(pfn)); +diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c +index bef86d1..deec937 100644 +--- a/kernel/power/suspend.c ++++ b/kernel/power/suspend.c +@@ -156,13 +156,13 @@ static int suspend_prepare(suspend_state_t state) + } + + /* default implementation */ +-void __attribute__ ((weak)) arch_suspend_disable_irqs(void) ++void __weak arch_suspend_disable_irqs(void) + { + local_irq_disable(); + } + + /* default implementation */ +-void __attribute__ ((weak)) arch_suspend_enable_irqs(void) ++void __weak arch_suspend_enable_irqs(void) + { + local_irq_enable(); + } +diff --git a/kernel/power/swap.c b/kernel/power/swap.c +index 7c33ed2..a6a1c55 100644 +--- a/kernel/power/swap.c ++++ b/kernel/power/swap.c +@@ -91,17 +91,28 @@ struct swap_map_handle { + unsigned int k; + unsigned long reqd_free_pages; + u32 crc32; ++#ifdef CONFIG_ARCH_SHMOBILE ++ unsigned int img_size; /* add */ ++#endif + }; + + struct swsusp_header { ++#ifdef CONFIG_ARCH_SHMOBILE ++ char reserved[PAGE_SIZE - 20 - sizeof(sector_t) - sizeof(int) - ++ sizeof(u32) - (sizeof(unsigned int)*4) - sizeof(u32)]; ++ unsigned int comp_crc32[4]; ++ u32 img_size; ++#else + char reserved[PAGE_SIZE - 20 - sizeof(sector_t) - sizeof(int) - +- sizeof(u32)]; ++ sizeof(u32) - sizeof(u32)]; ++ u32 comp_crc32; ++#endif + u32 crc32; + sector_t image; + unsigned int flags; /* Flags to pass to the "boot" kernel */ + char orig_sig[10]; + char sig[10]; +-} __attribute__((packed)); ++} __packed; + + static struct swsusp_header *swsusp_header; + +@@ -230,6 +241,11 @@ static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags) + swsusp_header->flags = flags; + if (flags & SF_CRC32_MODE) + swsusp_header->crc32 = handle->crc32; ++ ++#ifdef CONFIG_ARCH_SHMOBILE ++ swsusp_header->img_size = handle->img_size; ++#endif ++ + error = hib_bio_write_page(swsusp_resume_block, + swsusp_header, NULL); + } else { +@@ -587,7 +603,11 @@ static int save_image_lzo(struct swap_map_handle *handle, + unsigned char *page = NULL; + struct cmp_data *data = NULL; + struct crc_data *crc = NULL; ++ int compr = 0; + ++#ifdef CONFIG_ARCH_SHMOBILE ++ unsigned int comp_imgtotal = 0; ++#endif + /* + * We'll limit the number of threads for compression to limit memory + * footprint. +@@ -733,7 +753,12 @@ static int save_image_lzo(struct swap_map_handle *handle, + } + + *(size_t *)data[thr].cmp = data[thr].cmp_len; +- ++ compr += data[thr].cmp_len; ++#ifdef CONFIG_ARCH_SHMOBILE ++ comp_imgtotal += (data[thr].cmp_len ++ + LZO_HEADER + (PAGE_SIZE - 1)) ++ & ~(PAGE_SIZE - 1); ++#endif + /* + * Given we are writing one page at a time to disk, we + * copy that much from the buffer, although the last +@@ -746,7 +771,6 @@ static int save_image_lzo(struct swap_map_handle *handle, + off < LZO_HEADER + data[thr].cmp_len; + off += PAGE_SIZE) { + memcpy(page, data[thr].cmp + off, PAGE_SIZE); +- + ret = swap_write_page(handle, page, &bio); + if (ret) + goto out_finish; +@@ -762,8 +786,24 @@ out_finish: + do_gettimeofday(&stop); + if (!ret) + ret = err2; +- if (!ret) ++ if (!ret) { ++#ifdef CONFIG_ARCH_SHMOBILE ++ const unsigned int ds = comp_imgtotal + ++ ((comp_imgtotal ++ / ((2 * 1024 * 1024) ++ - PAGE_SIZE)) * PAGE_SIZE); ++ const unsigned int swaped = ++ (swp_offset(get_swap_page_of_type(root_swap)) ++ - 2) * PAGE_SIZE; ++ if (ds < swaped) ++ handle->img_size = swaped; ++ else ++ handle->img_size = ds; ++#endif + printk(KERN_INFO "PM: Image saving done.\n"); ++ printk(KERN_INFO "PM: Compressed output size: %d [%d] (imgsize=%d/swaped size=%d)\n", ++ compr, handle->img_size, ds, swaped); ++ } + swsusp_show_speed(&start, &stop, nr_to_write, "Wrote"); + out_clean: + if (crc) { +-- +1.8.3.1 + |