From 549c7e33aeb9bfe441ecf68639d2227bb90978e7 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 12 Dec 2008 00:24:07 +0000 Subject: [ARM] S3C: Split the resume memory check code from pm.c Split the optional memory check code out of the pm.c file as it is quite a big #ifdef block and as-such can be moved out and simply compiled when the configuration is set. Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/pm-check.c | 220 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 arch/arm/plat-s3c/pm-check.c (limited to 'arch/arm/plat-s3c/pm-check.c') diff --git a/arch/arm/plat-s3c/pm-check.c b/arch/arm/plat-s3c/pm-check.c new file mode 100644 index 000000000000..95ba7693b5af --- /dev/null +++ b/arch/arm/plat-s3c/pm-check.c @@ -0,0 +1,220 @@ +/* linux/arch/arm/plat-s3c/pm-check.c + * originally in linux/arch/arm/plat-s3c24xx/pm.c + * + * Copyright (c) 2004,2006,2008 Simtec Electronics + * http://armlinux.simtec.co.uk + * Ben Dooks + * + * S3C Power Mangament - suspend/resume memory corruptiuon check. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include +#include +#include +#include +#include + +#include + +#if CONFIG_S3C2410_PM_CHECK_CHUNKSIZE < 1 +#error CONFIG_S3C2410_PM_CHECK_CHUNKSIZE must be a positive non-zero value +#endif + +/* suspend checking code... + * + * this next area does a set of crc checks over all the installed + * memory, so the system can verify if the resume was ok. + * + * CONFIG_S3C2410_PM_CHECK_CHUNKSIZE defines the block-size for the CRC, + * increasing it will mean that the area corrupted will be less easy to spot, + * and reducing the size will cause the CRC save area to grow +*/ + +#define CHECK_CHUNKSIZE (CONFIG_S3C2410_PM_CHECK_CHUNKSIZE * 1024) + +static u32 crc_size; /* size needed for the crc block */ +static u32 *crcs; /* allocated over suspend/resume */ + +typedef u32 *(run_fn_t)(struct resource *ptr, u32 *arg); + +/* s3c_pm_run_res + * + * go through the given resource list, and look for system ram +*/ + +static void s3c_pm_run_res(struct resource *ptr, run_fn_t fn, u32 *arg) +{ + while (ptr != NULL) { + if (ptr->child != NULL) + s3c_pm_run_res(ptr->child, fn, arg); + + if ((ptr->flags & IORESOURCE_MEM) && + strcmp(ptr->name, "System RAM") == 0) { + S3C_PMDBG("Found system RAM at %08lx..%08lx\n", + ptr->start, ptr->end); + arg = (fn)(ptr, arg); + } + + ptr = ptr->sibling; + } +} + +static void s3c_pm_run_sysram(run_fn_t fn, u32 *arg) +{ + s3c_pm_run_res(&iomem_resource, fn, arg); +} + +static u32 *s3c_pm_countram(struct resource *res, u32 *val) +{ + u32 size = (u32)(res->end - res->start)+1; + + size += CHECK_CHUNKSIZE-1; + size /= CHECK_CHUNKSIZE; + + S3C_PMDBG("Area %08lx..%08lx, %d blocks\n", res->start, res->end, size); + + *val += size * sizeof(u32); + return val; +} + +/* s3c_pm_prepare_check + * + * prepare the necessary information for creating the CRCs. This + * must be done before the final save, as it will require memory + * allocating, and thus touching bits of the kernel we do not + * know about. +*/ + +void s3c_pm_check_prepare(void) +{ + crc_size = 0; + + s3c_pm_run_sysram(s3c_pm_countram, &crc_size); + + S3C_PMDBG("s3c_pm_prepare_check: %u checks needed\n", crc_size); + + crcs = kmalloc(crc_size+4, GFP_KERNEL); + if (crcs == NULL) + printk(KERN_ERR "Cannot allocated CRC save area\n"); +} + +static u32 *s3c_pm_makecheck(struct resource *res, u32 *val) +{ + unsigned long addr, left; + + for (addr = res->start; addr < res->end; + addr += CHECK_CHUNKSIZE) { + left = res->end - addr; + + if (left > CHECK_CHUNKSIZE) + left = CHECK_CHUNKSIZE; + + *val = crc32_le(~0, phys_to_virt(addr), left); + val++; + } + + return val; +} + +/* s3c_pm_check_store + * + * compute the CRC values for the memory blocks before the final + * sleep. +*/ + +void s3c_pm_check_store(void) +{ + if (crcs != NULL) + s3c_pm_run_sysram(s3c_pm_makecheck, crcs); +} + +/* in_region + * + * return TRUE if the area defined by ptr..ptr+size contains the + * what..what+whatsz +*/ + +static inline int in_region(void *ptr, int size, void *what, size_t whatsz) +{ + if ((what+whatsz) < ptr) + return 0; + + if (what > (ptr+size)) + return 0; + + return 1; +} + +/** + * s3c_pm_runcheck*() - helper to check a resource on restore. + * @res: The resource to check + * @vak: Pointer to list of CRC32 values to check. + * + * Called from the s3c_pm_check_restore() via s3c_pm_run_sysram(), this + * function runs the given memory resource checking it against the stored + * CRC to ensure that memory is restored. The function tries to skip as + * many of the areas used during the suspend process. + */ +static u32 *s3c_pm_runcheck(struct resource *res, u32 *val) +{ + void *save_at = phys_to_virt(s3c_sleep_save_phys); + unsigned long addr; + unsigned long left; + void *ptr; + u32 calc; + + for (addr = res->start; addr < res->end; + addr += CHECK_CHUNKSIZE) { + left = res->end - addr; + + if (left > CHECK_CHUNKSIZE) + left = CHECK_CHUNKSIZE; + + ptr = phys_to_virt(addr); + + if (in_region(ptr, left, crcs, crc_size)) { + S3C_PMDBG("skipping %08lx, has crc block in\n", addr); + goto skip_check; + } + + if (in_region(ptr, left, save_at, 32*4 )) { + S3C_PMDBG("skipping %08lx, has save block in\n", addr); + goto skip_check; + } + + /* calculate and check the checksum */ + + calc = crc32_le(~0, ptr, left); + if (calc != *val) { + printk(KERN_ERR "Restore CRC error at " + "%08lx (%08x vs %08x)\n", addr, calc, *val); + + S3C_PMDBG("Restore CRC error at %08lx (%08x vs %08x)\n", + addr, calc, *val); + } + + skip_check: + val++; + } + + return val; +} + +/** + * s3c_pm_check_restore() - memory check called on resume + * + * check the CRCs after the restore event and free the memory used + * to hold them +*/ +void s3c_pm_check_restore(void) +{ + if (crcs != NULL) { + s3c_pm_run_sysram(s3c_pm_runcheck, crcs); + kfree(crcs); + crcs = NULL; + } +} -- cgit v1.2.3 From 840eeeb880e03927588e0e971cb426441795ff14 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 12 Dec 2008 00:24:09 +0000 Subject: [ARM] S3C: Fix warnings in the PM memory CRC code Fix warnings from struct resource being bigger than unsigned long by forcing the type. We are only a 32bit platform so no physical memory addresses will be too big to fit in this. Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/pm-check.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'arch/arm/plat-s3c/pm-check.c') diff --git a/arch/arm/plat-s3c/pm-check.c b/arch/arm/plat-s3c/pm-check.c index 95ba7693b5af..b221470e3bfc 100644 --- a/arch/arm/plat-s3c/pm-check.c +++ b/arch/arm/plat-s3c/pm-check.c @@ -55,7 +55,8 @@ static void s3c_pm_run_res(struct resource *ptr, run_fn_t fn, u32 *arg) if ((ptr->flags & IORESOURCE_MEM) && strcmp(ptr->name, "System RAM") == 0) { S3C_PMDBG("Found system RAM at %08lx..%08lx\n", - ptr->start, ptr->end); + (unsigned long)ptr->start, + (unsigned long)ptr->end); arg = (fn)(ptr, arg); } @@ -75,7 +76,8 @@ static u32 *s3c_pm_countram(struct resource *res, u32 *val) size += CHECK_CHUNKSIZE-1; size /= CHECK_CHUNKSIZE; - S3C_PMDBG("Area %08lx..%08lx, %d blocks\n", res->start, res->end, size); + S3C_PMDBG("Area %08lx..%08lx, %d blocks\n", + (unsigned long)res->start, (unsigned long)res->end, size); *val += size * sizeof(u32); return val; -- cgit v1.2.3 From 663a83048c602d5176c23489b4e29598d753e42b Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 12 Dec 2008 00:24:36 +0000 Subject: [ARM] S3C: Avoid checking the task stackpage in pm-check When doing the CRC check of the memory, avoid checking the page that our stack is residing in as this changes during the execution of the suspend and resume. Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/pm-check.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'arch/arm/plat-s3c/pm-check.c') diff --git a/arch/arm/plat-s3c/pm-check.c b/arch/arm/plat-s3c/pm-check.c index b221470e3bfc..183f1304bf58 100644 --- a/arch/arm/plat-s3c/pm-check.c +++ b/arch/arm/plat-s3c/pm-check.c @@ -152,7 +152,7 @@ static inline int in_region(void *ptr, int size, void *what, size_t whatsz) } /** - * s3c_pm_runcheck*() - helper to check a resource on restore. + * s3c_pm_runcheck() - helper to check a resource on restore. * @res: The resource to check * @vak: Pointer to list of CRC32 values to check. * @@ -166,9 +166,12 @@ static u32 *s3c_pm_runcheck(struct resource *res, u32 *val) void *save_at = phys_to_virt(s3c_sleep_save_phys); unsigned long addr; unsigned long left; + void *stkpage; void *ptr; u32 calc; + stkpage = (void *)((u32)&calc & ~PAGE_MASK); + for (addr = res->start; addr < res->end; addr += CHECK_CHUNKSIZE) { left = res->end - addr; @@ -178,6 +181,11 @@ static u32 *s3c_pm_runcheck(struct resource *res, u32 *val) ptr = phys_to_virt(addr); + if (in_region(ptr, left, stkpage, 4096)) { + S3C_PMDBG("skipping %08lx, has stack in\n", addr); + goto skip_check; + } + if (in_region(ptr, left, crcs, crc_size)) { S3C_PMDBG("skipping %08lx, has crc block in\n", addr); goto skip_check; -- cgit v1.2.3 From aa8aba6944203a17a7e941b42d8415153c649660 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 12 Dec 2008 00:24:34 +0000 Subject: [ARM] S3C: Do not kmalloc/kfree during inner suspend code. The PM CRC checking code kmallocs an area to save a set of CRC values during suspend. This triggers a warning due to the call of a function that might sleep whilst the system is not in a valid state to do so. Move the allocation and free to points in the suspend and resume process where they can call a function that might-sleep. Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/pm-check.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'arch/arm/plat-s3c/pm-check.c') diff --git a/arch/arm/plat-s3c/pm-check.c b/arch/arm/plat-s3c/pm-check.c index 183f1304bf58..39f2555564da 100644 --- a/arch/arm/plat-s3c/pm-check.c +++ b/arch/arm/plat-s3c/pm-check.c @@ -222,9 +222,21 @@ static u32 *s3c_pm_runcheck(struct resource *res, u32 *val) */ void s3c_pm_check_restore(void) { - if (crcs != NULL) { + if (crcs != NULL) s3c_pm_run_sysram(s3c_pm_runcheck, crcs); - kfree(crcs); - crcs = NULL; - } } + +/** + * s3c_pm_check_cleanup() - free memory resources + * + * Free the resources that where allocated by the suspend + * memory check code. We do this separately from the + * s3c_pm_check_restore() function as we cannot call any + * functions that might sleep during that resume. + */ +void s3c_pm_check_cleanup(void) +{ + kfree(crcs); + crcs = NULL; +} + -- cgit v1.2.3