Skip to content

Commit 9710cb6

Browse files
committed
Merge tag 'pm-4.8-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull power management fixes from Rafael Wysocki: "Two hibernation fixes allowing it to work with the recently added randomization of the kernel identity mapping base on x86-64 and one cpufreq driver regression fix. Specifics: - Fix the x86 identity mapping creation helpers to avoid the assumption that the base address of the mapping will always be aligned at the PGD level, as it may be aligned at the PUD level if address space randomization is enabled (Rafael Wysocki). - Fix the hibernation core to avoid executing tracing functions before restoring the processor state completely during resume (Thomas Garnier). - Fix a recently introduced regression in the powernv cpufreq driver that causes it to crash due to an out-of-bounds array access (Akshay Adiga)" * tag 'pm-4.8-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: PM / hibernate: Restore processor state before using per-CPU variables x86/power/64: Always create temporary identity mapping correctly cpufreq: powernv: Fix crash in gpstate_timer_handler()
2 parents 01ea443 + 0aeeb3e commit 9710cb6

File tree

5 files changed

+36
-14
lines changed

5 files changed

+36
-14
lines changed

arch/x86/include/asm/init.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ struct x86_mapping_info {
55
void *(*alloc_pgt_page)(void *); /* allocate buf for page table */
66
void *context; /* context for alloc_pgt_page */
77
unsigned long pmd_flag; /* page flag for PMD entry */
8-
bool kernel_mapping; /* kernel mapping or ident mapping */
8+
unsigned long offset; /* ident mapping offset */
99
};
1010

1111
int kernel_ident_mapping_init(struct x86_mapping_info *info, pgd_t *pgd_page,
12-
unsigned long addr, unsigned long end);
12+
unsigned long pstart, unsigned long pend);
1313

1414
#endif /* _ASM_X86_INIT_H */

arch/x86/mm/ident_map.c

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,17 @@
33
* included by both the compressed kernel and the regular kernel.
44
*/
55

6-
static void ident_pmd_init(unsigned long pmd_flag, pmd_t *pmd_page,
6+
static void ident_pmd_init(struct x86_mapping_info *info, pmd_t *pmd_page,
77
unsigned long addr, unsigned long end)
88
{
99
addr &= PMD_MASK;
1010
for (; addr < end; addr += PMD_SIZE) {
1111
pmd_t *pmd = pmd_page + pmd_index(addr);
1212

13-
if (!pmd_present(*pmd))
14-
set_pmd(pmd, __pmd(addr | pmd_flag));
13+
if (pmd_present(*pmd))
14+
continue;
15+
16+
set_pmd(pmd, __pmd((addr - info->offset) | info->pmd_flag));
1517
}
1618
}
1719

@@ -30,28 +32,29 @@ static int ident_pud_init(struct x86_mapping_info *info, pud_t *pud_page,
3032

3133
if (pud_present(*pud)) {
3234
pmd = pmd_offset(pud, 0);
33-
ident_pmd_init(info->pmd_flag, pmd, addr, next);
35+
ident_pmd_init(info, pmd, addr, next);
3436
continue;
3537
}
3638
pmd = (pmd_t *)info->alloc_pgt_page(info->context);
3739
if (!pmd)
3840
return -ENOMEM;
39-
ident_pmd_init(info->pmd_flag, pmd, addr, next);
41+
ident_pmd_init(info, pmd, addr, next);
4042
set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE));
4143
}
4244

4345
return 0;
4446
}
4547

4648
int kernel_ident_mapping_init(struct x86_mapping_info *info, pgd_t *pgd_page,
47-
unsigned long addr, unsigned long end)
49+
unsigned long pstart, unsigned long pend)
4850
{
51+
unsigned long addr = pstart + info->offset;
52+
unsigned long end = pend + info->offset;
4953
unsigned long next;
5054
int result;
51-
int off = info->kernel_mapping ? pgd_index(__PAGE_OFFSET) : 0;
5255

5356
for (; addr < end; addr = next) {
54-
pgd_t *pgd = pgd_page + pgd_index(addr) + off;
57+
pgd_t *pgd = pgd_page + pgd_index(addr);
5558
pud_t *pud;
5659

5760
next = (addr & PGDIR_MASK) + PGDIR_SIZE;

arch/x86/power/hibernate_64.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ static int set_up_temporary_mappings(void)
8787
struct x86_mapping_info info = {
8888
.alloc_pgt_page = alloc_pgt_page,
8989
.pmd_flag = __PAGE_KERNEL_LARGE_EXEC,
90-
.kernel_mapping = true,
90+
.offset = __PAGE_OFFSET,
9191
};
9292
unsigned long mstart, mend;
9393
pgd_t *pgd;

drivers/cpufreq/powernv-cpufreq.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,30 @@ static struct powernv_pstate_info {
145145
/* Use following macros for conversions between pstate_id and index */
146146
static inline int idx_to_pstate(unsigned int i)
147147
{
148+
if (unlikely(i >= powernv_pstate_info.nr_pstates)) {
149+
pr_warn_once("index %u is out of bound\n", i);
150+
return powernv_freqs[powernv_pstate_info.nominal].driver_data;
151+
}
152+
148153
return powernv_freqs[i].driver_data;
149154
}
150155

151156
static inline unsigned int pstate_to_idx(int pstate)
152157
{
158+
int min = powernv_freqs[powernv_pstate_info.min].driver_data;
159+
int max = powernv_freqs[powernv_pstate_info.max].driver_data;
160+
161+
if (min > 0) {
162+
if (unlikely((pstate < max) || (pstate > min))) {
163+
pr_warn_once("pstate %d is out of bound\n", pstate);
164+
return powernv_pstate_info.nominal;
165+
}
166+
} else {
167+
if (unlikely((pstate > max) || (pstate < min))) {
168+
pr_warn_once("pstate %d is out of bound\n", pstate);
169+
return powernv_pstate_info.nominal;
170+
}
171+
}
153172
/*
154173
* abs() is deliberately used so that is works with
155174
* both monotonically increasing and decreasing
@@ -593,7 +612,7 @@ void gpstate_timer_handler(unsigned long data)
593612
} else {
594613
gpstate_idx = calc_global_pstate(gpstates->elapsed_time,
595614
gpstates->highest_lpstate_idx,
596-
freq_data.pstate_id);
615+
gpstates->last_lpstate_idx);
597616
}
598617

599618
/*

kernel/power/hibernate.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,12 +300,12 @@ static int create_image(int platform_mode)
300300
save_processor_state();
301301
trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, true);
302302
error = swsusp_arch_suspend();
303+
/* Restore control flow magically appears here */
304+
restore_processor_state();
303305
trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, false);
304306
if (error)
305307
printk(KERN_ERR "PM: Error %d creating hibernation image\n",
306308
error);
307-
/* Restore control flow magically appears here */
308-
restore_processor_state();
309309
if (!in_suspend)
310310
events_check_enabled = false;
311311

0 commit comments

Comments
 (0)