-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[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 <ben-linux@fluff.org>
- Loading branch information
Ben Dooks
committed
Mar 8, 2009
1 parent
6419711
commit 549c7e3
Showing
4 changed files
with
240 additions
and
203 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <ben@simtec.co.uk> | ||
* | ||
* 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 <linux/kernel.h> | ||
#include <linux/suspend.h> | ||
#include <linux/init.h> | ||
#include <linux/crc32.h> | ||
#include <linux/ioport.h> | ||
|
||
#include <plat/pm.h> | ||
|
||
#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; | ||
} | ||
} |
Oops, something went wrong.