[ARM] 5027/1: Fixed random memory corruption on pxa suspend cycle.
Each time a pxa type cpu went in suspend, a portion of
kmalloc memory was corrupted.
The issue was an incorrect length allocation introduced by
the commit 711be5ccfe
for
the save registers array (=> overflow).
Signed-off-by: Robert Jarzmik <rjarzmik@free.fr>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
c8df9a53e8
commit
649de51b88
|
@ -42,7 +42,7 @@ int pxa_pm_enter(suspend_state_t state)
|
||||||
if (state != PM_SUSPEND_STANDBY) {
|
if (state != PM_SUSPEND_STANDBY) {
|
||||||
pxa_cpu_pm_fns->save(sleep_save);
|
pxa_cpu_pm_fns->save(sleep_save);
|
||||||
/* before sleeping, calculate and save a checksum */
|
/* before sleeping, calculate and save a checksum */
|
||||||
for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++)
|
for (i = 0; i < pxa_cpu_pm_fns->save_count - 1; i++)
|
||||||
sleep_save_checksum += sleep_save[i];
|
sleep_save_checksum += sleep_save[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ int pxa_pm_enter(suspend_state_t state)
|
||||||
|
|
||||||
if (state != PM_SUSPEND_STANDBY) {
|
if (state != PM_SUSPEND_STANDBY) {
|
||||||
/* after sleeping, validate the checksum */
|
/* after sleeping, validate the checksum */
|
||||||
for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++)
|
for (i = 0; i < pxa_cpu_pm_fns->save_count - 1; i++)
|
||||||
checksum += sleep_save[i];
|
checksum += sleep_save[i];
|
||||||
|
|
||||||
/* if invalid, display message and wait for a hardware reset */
|
/* if invalid, display message and wait for a hardware reset */
|
||||||
|
@ -101,7 +101,8 @@ static int __init pxa_pm_init(void)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
sleep_save = kmalloc(pxa_cpu_pm_fns->save_size, GFP_KERNEL);
|
sleep_save = kmalloc(pxa_cpu_pm_fns->save_count * sizeof(unsigned long),
|
||||||
|
GFP_KERNEL);
|
||||||
if (!sleep_save) {
|
if (!sleep_save) {
|
||||||
printk(KERN_ERR "failed to alloc memory for pm save\n");
|
printk(KERN_ERR "failed to alloc memory for pm save\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
|
@ -150,9 +150,7 @@ static struct clk pxa25x_clks[] = {
|
||||||
* More ones like CP and general purpose register values are preserved
|
* More ones like CP and general purpose register values are preserved
|
||||||
* with the stack pointer in sleep.S.
|
* with the stack pointer in sleep.S.
|
||||||
*/
|
*/
|
||||||
enum { SLEEP_SAVE_START = 0,
|
enum { SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2,
|
||||||
|
|
||||||
SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2,
|
|
||||||
|
|
||||||
SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U,
|
SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U,
|
||||||
SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U,
|
SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U,
|
||||||
|
@ -162,7 +160,7 @@ enum { SLEEP_SAVE_START = 0,
|
||||||
|
|
||||||
SLEEP_SAVE_CKEN,
|
SLEEP_SAVE_CKEN,
|
||||||
|
|
||||||
SLEEP_SAVE_SIZE
|
SLEEP_SAVE_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -210,7 +208,7 @@ static void pxa25x_cpu_pm_enter(suspend_state_t state)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct pxa_cpu_pm_fns pxa25x_cpu_pm_fns = {
|
static struct pxa_cpu_pm_fns pxa25x_cpu_pm_fns = {
|
||||||
.save_size = SLEEP_SAVE_SIZE,
|
.save_count = SLEEP_SAVE_COUNT,
|
||||||
.valid = suspend_valid_only_mem,
|
.valid = suspend_valid_only_mem,
|
||||||
.save = pxa25x_cpu_pm_save,
|
.save = pxa25x_cpu_pm_save,
|
||||||
.restore = pxa25x_cpu_pm_restore,
|
.restore = pxa25x_cpu_pm_restore,
|
||||||
|
|
|
@ -181,9 +181,7 @@ static struct clk pxa27x_clks[] = {
|
||||||
* More ones like CP and general purpose register values are preserved
|
* More ones like CP and general purpose register values are preserved
|
||||||
* with the stack pointer in sleep.S.
|
* with the stack pointer in sleep.S.
|
||||||
*/
|
*/
|
||||||
enum { SLEEP_SAVE_START = 0,
|
enum { SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, SLEEP_SAVE_PGSR3,
|
||||||
|
|
||||||
SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, SLEEP_SAVE_PGSR3,
|
|
||||||
|
|
||||||
SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U,
|
SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U,
|
||||||
SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U,
|
SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U,
|
||||||
|
@ -198,7 +196,7 @@ enum { SLEEP_SAVE_START = 0,
|
||||||
SLEEP_SAVE_PWER, SLEEP_SAVE_PCFR, SLEEP_SAVE_PRER,
|
SLEEP_SAVE_PWER, SLEEP_SAVE_PCFR, SLEEP_SAVE_PRER,
|
||||||
SLEEP_SAVE_PFER, SLEEP_SAVE_PKWR,
|
SLEEP_SAVE_PFER, SLEEP_SAVE_PKWR,
|
||||||
|
|
||||||
SLEEP_SAVE_SIZE
|
SLEEP_SAVE_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
void pxa27x_cpu_pm_save(unsigned long *sleep_save)
|
void pxa27x_cpu_pm_save(unsigned long *sleep_save)
|
||||||
|
@ -269,7 +267,7 @@ static int pxa27x_cpu_pm_valid(suspend_state_t state)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct pxa_cpu_pm_fns pxa27x_cpu_pm_fns = {
|
static struct pxa_cpu_pm_fns pxa27x_cpu_pm_fns = {
|
||||||
.save_size = SLEEP_SAVE_SIZE,
|
.save_count = SLEEP_SAVE_COUNT,
|
||||||
.save = pxa27x_cpu_pm_save,
|
.save = pxa27x_cpu_pm_save,
|
||||||
.restore = pxa27x_cpu_pm_restore,
|
.restore = pxa27x_cpu_pm_restore,
|
||||||
.valid = pxa27x_cpu_pm_valid,
|
.valid = pxa27x_cpu_pm_valid,
|
||||||
|
|
|
@ -256,12 +256,11 @@ static unsigned long wakeup_src;
|
||||||
#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
|
#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
|
||||||
#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
|
#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
|
||||||
|
|
||||||
enum { SLEEP_SAVE_START = 0,
|
enum { SLEEP_SAVE_CKENA,
|
||||||
SLEEP_SAVE_CKENA,
|
|
||||||
SLEEP_SAVE_CKENB,
|
SLEEP_SAVE_CKENB,
|
||||||
SLEEP_SAVE_ACCR,
|
SLEEP_SAVE_ACCR,
|
||||||
|
|
||||||
SLEEP_SAVE_SIZE,
|
SLEEP_SAVE_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void pxa3xx_cpu_pm_save(unsigned long *sleep_save)
|
static void pxa3xx_cpu_pm_save(unsigned long *sleep_save)
|
||||||
|
@ -376,7 +375,7 @@ static int pxa3xx_cpu_pm_valid(suspend_state_t state)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct pxa_cpu_pm_fns pxa3xx_cpu_pm_fns = {
|
static struct pxa_cpu_pm_fns pxa3xx_cpu_pm_fns = {
|
||||||
.save_size = SLEEP_SAVE_SIZE,
|
.save_count = SLEEP_SAVE_COUNT,
|
||||||
.save = pxa3xx_cpu_pm_save,
|
.save = pxa3xx_cpu_pm_save,
|
||||||
.restore = pxa3xx_cpu_pm_restore,
|
.restore = pxa3xx_cpu_pm_restore,
|
||||||
.valid = pxa3xx_cpu_pm_valid,
|
.valid = pxa3xx_cpu_pm_valid,
|
||||||
|
|
|
@ -43,20 +43,18 @@ extern void sa1100_cpu_resume(void);
|
||||||
* More ones like CP and general purpose register values are preserved
|
* More ones like CP and general purpose register values are preserved
|
||||||
* on the stack and then the stack pointer is stored last in sleep.S.
|
* on the stack and then the stack pointer is stored last in sleep.S.
|
||||||
*/
|
*/
|
||||||
enum { SLEEP_SAVE_SP = 0,
|
enum { SLEEP_SAVE_GPDR, SLEEP_SAVE_GAFR,
|
||||||
|
|
||||||
SLEEP_SAVE_GPDR, SLEEP_SAVE_GAFR,
|
|
||||||
SLEEP_SAVE_PPDR, SLEEP_SAVE_PPSR, SLEEP_SAVE_PPAR, SLEEP_SAVE_PSDR,
|
SLEEP_SAVE_PPDR, SLEEP_SAVE_PPSR, SLEEP_SAVE_PPAR, SLEEP_SAVE_PSDR,
|
||||||
|
|
||||||
SLEEP_SAVE_Ser1SDCR0,
|
SLEEP_SAVE_Ser1SDCR0,
|
||||||
|
|
||||||
SLEEP_SAVE_SIZE
|
SLEEP_SAVE_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static int sa11x0_pm_enter(suspend_state_t state)
|
static int sa11x0_pm_enter(suspend_state_t state)
|
||||||
{
|
{
|
||||||
unsigned long gpio, sleep_save[SLEEP_SAVE_SIZE];
|
unsigned long gpio, sleep_save[SLEEP_SAVE_COUNT];
|
||||||
|
|
||||||
gpio = GPLR;
|
gpio = GPLR;
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#include <linux/suspend.h>
|
#include <linux/suspend.h>
|
||||||
|
|
||||||
struct pxa_cpu_pm_fns {
|
struct pxa_cpu_pm_fns {
|
||||||
int save_size;
|
int save_count;
|
||||||
void (*save)(unsigned long *);
|
void (*save)(unsigned long *);
|
||||||
void (*restore)(unsigned long *);
|
void (*restore)(unsigned long *);
|
||||||
int (*valid)(suspend_state_t state);
|
int (*valid)(suspend_state_t state);
|
||||||
|
|
Loading…
Reference in New Issue