Power management fixes for v4.8-rc2
- 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). -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABCAAGBQJXrjxTAAoJEILEb/54YlRxhsAP/RHGfc0DtkvZyJPfW5eAT73t LihmOFtOeGF6Bo0pyM1YnGW4DdIgfnfBYbFSrKlorfveVikK1QkgcEb69XxJwhjW i/75Gwy5sLhdjzmGVV7kpmozhwSo4gbfW6q4rJ3x3FEWxMcLbMPAA4AlJq0kVdRm CfwTS7YIx/zCWWJTTL8CW0WuVoVOYKuJThCd/HwuwBF1Y8pqg5XAmeyDH2HzQDbH OdR4dLjS2xki0f2z1TdAUeSVn8FcuRoH6e/sF5v8T/3I2LdbME3QiCf9uYkeyWJ3 vhUM40x6O+lB84HdsZjXQqbX/7lZmDj5bgcyPFf2WA/WOf12Y7OquQSc/yKasOrK mNFPDUyl+hbUiD5BvDQES/HOxNLFkekARFEb2Ud4HUrN2nIbEghDRcQ5zP6/Nf9o Cht8kS/OYe7PeMWXPXDX+zb8Fi8O5jz/9GJ97h6gYKBcaLPbuxUNkhxu5ikIGK+f CgefgdpNWS1EdooYmmSFHRyY8RxQjuw7l0CJh7TpTJJFgthr7iCN2A7UQqKlt/zU ARqnsUSRQcvjQs23tw8fPwRzUEuynW4udqVNM5XnvNu46KGWqkRgCVMmO6lNrIl6 v/+S8hLVFJH0t00Y+ZGvh0YcGHR65S1CMdNAuMxd1Gylr/Y3neRun0hHI6qDA19N ErPNMydb6BSY+vqcO/i1 =DWxX -----END PGP SIGNATURE----- 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()
This commit is contained in:
commit
9710cb6624
|
@ -5,10 +5,10 @@ struct x86_mapping_info {
|
|||
void *(*alloc_pgt_page)(void *); /* allocate buf for page table */
|
||||
void *context; /* context for alloc_pgt_page */
|
||||
unsigned long pmd_flag; /* page flag for PMD entry */
|
||||
bool kernel_mapping; /* kernel mapping or ident mapping */
|
||||
unsigned long offset; /* ident mapping offset */
|
||||
};
|
||||
|
||||
int kernel_ident_mapping_init(struct x86_mapping_info *info, pgd_t *pgd_page,
|
||||
unsigned long addr, unsigned long end);
|
||||
unsigned long pstart, unsigned long pend);
|
||||
|
||||
#endif /* _ASM_X86_INIT_H */
|
||||
|
|
|
@ -3,15 +3,17 @@
|
|||
* included by both the compressed kernel and the regular kernel.
|
||||
*/
|
||||
|
||||
static void ident_pmd_init(unsigned long pmd_flag, pmd_t *pmd_page,
|
||||
static void ident_pmd_init(struct x86_mapping_info *info, pmd_t *pmd_page,
|
||||
unsigned long addr, unsigned long end)
|
||||
{
|
||||
addr &= PMD_MASK;
|
||||
for (; addr < end; addr += PMD_SIZE) {
|
||||
pmd_t *pmd = pmd_page + pmd_index(addr);
|
||||
|
||||
if (!pmd_present(*pmd))
|
||||
set_pmd(pmd, __pmd(addr | pmd_flag));
|
||||
if (pmd_present(*pmd))
|
||||
continue;
|
||||
|
||||
set_pmd(pmd, __pmd((addr - info->offset) | info->pmd_flag));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,13 +32,13 @@ static int ident_pud_init(struct x86_mapping_info *info, pud_t *pud_page,
|
|||
|
||||
if (pud_present(*pud)) {
|
||||
pmd = pmd_offset(pud, 0);
|
||||
ident_pmd_init(info->pmd_flag, pmd, addr, next);
|
||||
ident_pmd_init(info, pmd, addr, next);
|
||||
continue;
|
||||
}
|
||||
pmd = (pmd_t *)info->alloc_pgt_page(info->context);
|
||||
if (!pmd)
|
||||
return -ENOMEM;
|
||||
ident_pmd_init(info->pmd_flag, pmd, addr, next);
|
||||
ident_pmd_init(info, pmd, addr, next);
|
||||
set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE));
|
||||
}
|
||||
|
||||
|
@ -44,14 +46,15 @@ static int ident_pud_init(struct x86_mapping_info *info, pud_t *pud_page,
|
|||
}
|
||||
|
||||
int kernel_ident_mapping_init(struct x86_mapping_info *info, pgd_t *pgd_page,
|
||||
unsigned long addr, unsigned long end)
|
||||
unsigned long pstart, unsigned long pend)
|
||||
{
|
||||
unsigned long addr = pstart + info->offset;
|
||||
unsigned long end = pend + info->offset;
|
||||
unsigned long next;
|
||||
int result;
|
||||
int off = info->kernel_mapping ? pgd_index(__PAGE_OFFSET) : 0;
|
||||
|
||||
for (; addr < end; addr = next) {
|
||||
pgd_t *pgd = pgd_page + pgd_index(addr) + off;
|
||||
pgd_t *pgd = pgd_page + pgd_index(addr);
|
||||
pud_t *pud;
|
||||
|
||||
next = (addr & PGDIR_MASK) + PGDIR_SIZE;
|
||||
|
|
|
@ -87,7 +87,7 @@ static int set_up_temporary_mappings(void)
|
|||
struct x86_mapping_info info = {
|
||||
.alloc_pgt_page = alloc_pgt_page,
|
||||
.pmd_flag = __PAGE_KERNEL_LARGE_EXEC,
|
||||
.kernel_mapping = true,
|
||||
.offset = __PAGE_OFFSET,
|
||||
};
|
||||
unsigned long mstart, mend;
|
||||
pgd_t *pgd;
|
||||
|
|
|
@ -145,11 +145,30 @@ static struct powernv_pstate_info {
|
|||
/* Use following macros for conversions between pstate_id and index */
|
||||
static inline int idx_to_pstate(unsigned int i)
|
||||
{
|
||||
if (unlikely(i >= powernv_pstate_info.nr_pstates)) {
|
||||
pr_warn_once("index %u is out of bound\n", i);
|
||||
return powernv_freqs[powernv_pstate_info.nominal].driver_data;
|
||||
}
|
||||
|
||||
return powernv_freqs[i].driver_data;
|
||||
}
|
||||
|
||||
static inline unsigned int pstate_to_idx(int pstate)
|
||||
{
|
||||
int min = powernv_freqs[powernv_pstate_info.min].driver_data;
|
||||
int max = powernv_freqs[powernv_pstate_info.max].driver_data;
|
||||
|
||||
if (min > 0) {
|
||||
if (unlikely((pstate < max) || (pstate > min))) {
|
||||
pr_warn_once("pstate %d is out of bound\n", pstate);
|
||||
return powernv_pstate_info.nominal;
|
||||
}
|
||||
} else {
|
||||
if (unlikely((pstate > max) || (pstate < min))) {
|
||||
pr_warn_once("pstate %d is out of bound\n", pstate);
|
||||
return powernv_pstate_info.nominal;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* abs() is deliberately used so that is works with
|
||||
* both monotonically increasing and decreasing
|
||||
|
@ -593,7 +612,7 @@ void gpstate_timer_handler(unsigned long data)
|
|||
} else {
|
||||
gpstate_idx = calc_global_pstate(gpstates->elapsed_time,
|
||||
gpstates->highest_lpstate_idx,
|
||||
freq_data.pstate_id);
|
||||
gpstates->last_lpstate_idx);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -300,12 +300,12 @@ static int create_image(int platform_mode)
|
|||
save_processor_state();
|
||||
trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, true);
|
||||
error = swsusp_arch_suspend();
|
||||
/* Restore control flow magically appears here */
|
||||
restore_processor_state();
|
||||
trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, false);
|
||||
if (error)
|
||||
printk(KERN_ERR "PM: Error %d creating hibernation image\n",
|
||||
error);
|
||||
/* Restore control flow magically appears here */
|
||||
restore_processor_state();
|
||||
if (!in_suspend)
|
||||
events_check_enabled = false;
|
||||
|
||||
|
|
Loading…
Reference in New Issue