samsung: pm-check: Cleanup chunk exclude code to use suspend_volatile
authorDoug Anderson <dianders@chromium.org>
Mon, 5 Nov 2012 22:50:18 +0000 (14:50 -0800)
committerGerrit <chrome-bot@google.com>
Wed, 7 Nov 2012 23:32:05 +0000 (15:32 -0800)
Recent changes mark memory that may change across suspend/resume
as suspend_volatile.  We can now use this in pm-check, so do so.
That means we can remove some extra globals from printk.c.

This change also cleans up handling of sleep_save_sp:
* Don't exclude *sleep_save_sp.  That was a physical address and is
  also already handled by current_thread_info().
* Don't exclude sleep_save_sp.  Instead: we zero it out before out
  code runs.  This is a transitory value and zeroing it is fine.  Now
  we won't exclude chunks of memory stored near sleep_save_sp.

...and a few other minor fixes:
* Skips regions in s3c_pm_makecheck() too.
* Avoids goto in s3c_pm_runcheck() loop.

BUG=chrome-os-partner:15914
TEST=suspend_stress_test

Change-Id: I5eadc7631c3f31f91138170c5e37430da7e3520b
Signed-off-by: Doug Anderson <dianders@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/37359
Reviewed-by: Jon Kliegman <kliegs@chromium.org>
arch/arm/plat-samsung/pm-check.c
kernel/printk.c

index 634808d..7f2ae6a 100644 (file)
@@ -13,6 +13,8 @@
 */
 
 #include <linux/kernel.h>
+
+#include <linux/addr_overlap.h>
 #include <linux/suspend.h>
 #include <linux/init.h>
 #include <linux/crc32.h>
@@ -48,7 +50,9 @@ static int pm_check_chunksize = CONFIG_SAMSUNG_PM_CHECK_CHUNKSIZE * 1024;
 
 static u32 crc_size;   /* size needed for the crc block */
 static u32 *crcs;      /* allocated over suspend/resume */
-static u32 crc_err_cnt;        /* number of errors found this resume */
+
+/* number of errors found this resume */
+static __suspend_volatile_bss u32 crc_err_cnt;
 
 
 typedef u32 *(run_fn_t)(struct resource *ptr, u32 *arg);
@@ -205,18 +209,65 @@ void s3c_pm_check_prepare(void)
                printk(KERN_ERR "Cannot allocated CRC save area\n");
 }
 
+static inline void s3c_pm_printskip(char *desc, unsigned long addr)
+{
+       if (!pm_check_print_skips)
+               return;
+       S3C_PMDBG("s3c_pm_check: skipping %08lx, has %s in\n", addr, desc);
+}
+
+/* externs from sleep.S */
+extern u32 *sleep_save_sp;
+
+/**
+ * Zero memory that the sleep code may have used but doesn't care about.
+ *
+ * The sleep code uses some temporary memory that it doesn't need anymore
+ * after resume.  We zero it out here so we don't have to skip a whole chunk.
+ * This keeps CRCs consistent.
+ *
+ * Alternatively we could change sleep code to zero this memory, but we run
+ * into some issues if we ever get a failed suspend (the normal resume code
+ * doesn't run).
+ */
+static void zero_temp_memory(void)
+{
+       sleep_save_sp = 0;
+}
+
+static bool s3c_pm_should_skip(phys_addr_t addr, u32 size)
+{
+       void *stkbase = current_thread_info();
+
+       if (phys_addrs_overlap(addr, size,
+                              virt_to_phys(stkbase), THREAD_SIZE)) {
+               s3c_pm_printskip("stack", addr);
+               return true;
+       }
+       if (phys_addrs_overlap(addr, size, virt_to_phys(crcs), crc_size)) {
+               s3c_pm_printskip("crc block", addr);
+               return true;
+       }
+       if (pm_does_overlap_suspend_volatile(addr, size)) {
+               s3c_pm_printskip("volatile suspend data", addr);
+               return true;
+       }
+
+       return false;
+}
+
 static u32 *s3c_pm_makecheck(struct resource *res, u32 *val)
 {
        unsigned long addr, left;
 
        for (addr = res->start; addr <= res->end;
-            addr += pm_check_chunksize) {
+            addr += pm_check_chunksize, val++) {
                left = res->end - addr + 1;
                if (left > pm_check_chunksize)
                        left = pm_check_chunksize;
 
-               *val = s3c_pm_process_mem(~0, addr, left);
-               val++;
+               if (!s3c_pm_should_skip(addr, left))
+                       *val = s3c_pm_process_mem(~0, addr, left);
        }
 
        return val;
@@ -237,6 +288,8 @@ void s3c_pm_check_store(void)
 
        if (pm_check_print_timings)
                start = ktime_get();
+
+       zero_temp_memory();
        s3c_pm_run_sysram(s3c_pm_makecheck, crcs);
        if (pm_check_print_timings) {
                stop = ktime_get();
@@ -246,36 +299,6 @@ void s3c_pm_check_store(void)
        }
 }
 
-/* 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;
-}
-
-static inline void s3c_pm_printskip(char *desc, unsigned long addr)
-{
-       if (!pm_check_print_skips)
-               return;
-       S3C_PMDBG("s3c_pm_check: skipping %08lx, has %s in\n", addr, desc);
-}
-
-/* externs from printk.c and sleep.S */
-extern u32 *sleep_save_sp;
-extern char *pm_check_log_buf;
-extern int *pm_check_log_buf_len;
-extern unsigned *pm_check_logged_chars;
-
 /**
  * s3c_pm_runcheck() - helper to check a resource on restore.
  * @res: The resource to check
@@ -290,52 +313,17 @@ static u32 *s3c_pm_runcheck(struct resource *res, u32 *val)
 {
        unsigned long addr;
        unsigned long left;
-       void *stkbase;
-       void *virt;
        u32 calc;
 
-       stkbase = current_thread_info();
        for (addr = res->start; addr <= res->end;
-            addr += pm_check_chunksize) {
-               virt = phys_to_virt(addr);
+            addr += pm_check_chunksize, val++) {
                left = res->end - addr + 1;
 
                if (left > pm_check_chunksize)
                        left = pm_check_chunksize;
 
-               if (in_region(virt, left, stkbase, THREAD_SIZE)) {
-                       s3c_pm_printskip("stack", addr);
-                       goto skip_check;
-               }
-               if (in_region(virt, left, crcs, crc_size)) {
-                       s3c_pm_printskip("crc block", addr);
-                       goto skip_check;
-               }
-               if (in_region(virt, left, &crc_err_cnt, sizeof(crc_err_cnt))) {
-                       s3c_pm_printskip("crc_err_cnt", addr);
-                       goto skip_check;
-               }
-               if (in_region(virt, left, pm_check_logged_chars,
-                               sizeof(unsigned))) {
-                       s3c_pm_printskip("logged_chars", addr);
-                       goto skip_check;
-               }
-               if (in_region(virt, left, pm_check_log_buf,
-                               *pm_check_log_buf_len)) {
-                       s3c_pm_printskip("log_buf", addr);
-                       goto skip_check;
-               }
-               if (in_region(virt, left, &sleep_save_sp,
-                               sizeof(u32 *))) {
-                       s3c_pm_printskip("sleep_save_sp", addr);
-                       goto skip_check;
-               }
-               if (in_region(virt, left,
-                             sleep_save_sp - (PAGE_SIZE / sizeof(u32)),
-                             PAGE_SIZE * 2)) {
-                       s3c_pm_printskip("*sleep_save_sp", addr);
-                       goto skip_check;
-               }
+               if (s3c_pm_should_skip(addr, left))
+                       continue;
 
                /* calculate and check the checksum */
 
@@ -346,9 +334,6 @@ static u32 *s3c_pm_runcheck(struct resource *res, u32 *val)
                                "(%08x vs %08x)\n",
                                addr, calc, *val);
                }
-
-       skip_check:
-               val++;
        }
 
        return val;
@@ -370,6 +355,7 @@ void s3c_pm_check_restore(void)
        crc_err_cnt = 0;
        if (pm_check_print_timings)
                start = ktime_get();
+       zero_temp_memory();
        s3c_pm_run_sysram(s3c_pm_runcheck, crcs);
        if (pm_check_print_timings) {
                stop = ktime_get();
index 639a55a..363718d 100644 (file)
@@ -158,14 +158,9 @@ static int console_may_schedule;
 static __suspend_volatile_bss char __log_buf[__LOG_BUF_LEN];
 static char *log_buf = __log_buf;
 static int log_buf_len = __LOG_BUF_LEN;
-/* Added pm_check_* versions just in case these names are reused elsewhere */
-char *pm_check_log_buf = __log_buf;
-int *pm_check_log_buf_len = &log_buf_len;
 
 /* Number of chars produced since last read+clear operation */
 static __suspend_volatile_bss unsigned logged_chars;
-/* Added pm_check_* versions just in case these names are reused elsewhere */
-unsigned *pm_check_logged_chars = &logged_chars;
 static int saved_console_loglevel = -1;
 
 #ifdef CONFIG_KEXEC