Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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()

+36 -14
+2 -2
arch/x86/include/asm/init.h
··· 5 5 void *(*alloc_pgt_page)(void *); /* allocate buf for page table */ 6 6 void *context; /* context for alloc_pgt_page */ 7 7 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 */ 9 9 }; 10 10 11 11 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); 13 13 14 14 #endif /* _ASM_X86_INIT_H */
+11 -8
arch/x86/mm/ident_map.c
··· 3 3 * included by both the compressed kernel and the regular kernel. 4 4 */ 5 5 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, 7 7 unsigned long addr, unsigned long end) 8 8 { 9 9 addr &= PMD_MASK; 10 10 for (; addr < end; addr += PMD_SIZE) { 11 11 pmd_t *pmd = pmd_page + pmd_index(addr); 12 12 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)); 15 17 } 16 18 } 17 19 ··· 32 30 33 31 if (pud_present(*pud)) { 34 32 pmd = pmd_offset(pud, 0); 35 - ident_pmd_init(info->pmd_flag, pmd, addr, next); 33 + ident_pmd_init(info, pmd, addr, next); 36 34 continue; 37 35 } 38 36 pmd = (pmd_t *)info->alloc_pgt_page(info->context); 39 37 if (!pmd) 40 38 return -ENOMEM; 41 - ident_pmd_init(info->pmd_flag, pmd, addr, next); 39 + ident_pmd_init(info, pmd, addr, next); 42 40 set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE)); 43 41 } 44 42 ··· 46 44 } 47 45 48 46 int kernel_ident_mapping_init(struct x86_mapping_info *info, pgd_t *pgd_page, 49 - unsigned long addr, unsigned long end) 47 + unsigned long pstart, unsigned long pend) 50 48 { 49 + unsigned long addr = pstart + info->offset; 50 + unsigned long end = pend + info->offset; 51 51 unsigned long next; 52 52 int result; 53 - int off = info->kernel_mapping ? pgd_index(__PAGE_OFFSET) : 0; 54 53 55 54 for (; addr < end; addr = next) { 56 - pgd_t *pgd = pgd_page + pgd_index(addr) + off; 55 + pgd_t *pgd = pgd_page + pgd_index(addr); 57 56 pud_t *pud; 58 57 59 58 next = (addr & PGDIR_MASK) + PGDIR_SIZE;
+1 -1
arch/x86/power/hibernate_64.c
··· 87 87 struct x86_mapping_info info = { 88 88 .alloc_pgt_page = alloc_pgt_page, 89 89 .pmd_flag = __PAGE_KERNEL_LARGE_EXEC, 90 - .kernel_mapping = true, 90 + .offset = __PAGE_OFFSET, 91 91 }; 92 92 unsigned long mstart, mend; 93 93 pgd_t *pgd;
+20 -1
drivers/cpufreq/powernv-cpufreq.c
··· 145 145 /* Use following macros for conversions between pstate_id and index */ 146 146 static inline int idx_to_pstate(unsigned int i) 147 147 { 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 + 148 153 return powernv_freqs[i].driver_data; 149 154 } 150 155 151 156 static inline unsigned int pstate_to_idx(int pstate) 152 157 { 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 + } 153 172 /* 154 173 * abs() is deliberately used so that is works with 155 174 * both monotonically increasing and decreasing ··· 612 593 } else { 613 594 gpstate_idx = calc_global_pstate(gpstates->elapsed_time, 614 595 gpstates->highest_lpstate_idx, 615 - freq_data.pstate_id); 596 + gpstates->last_lpstate_idx); 616 597 } 617 598 618 599 /*
+2 -2
kernel/power/hibernate.c
··· 300 300 save_processor_state(); 301 301 trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, true); 302 302 error = swsusp_arch_suspend(); 303 + /* Restore control flow magically appears here */ 304 + restore_processor_state(); 303 305 trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, false); 304 306 if (error) 305 307 printk(KERN_ERR "PM: Error %d creating hibernation image\n", 306 308 error); 307 - /* Restore control flow magically appears here */ 308 - restore_processor_state(); 309 309 if (!in_suspend) 310 310 events_check_enabled = false; 311 311