* pm-sleep: PM / hibernate: Restore processor state before using per-CPU variables x86/power/64: Always create temporary identity mapping correctly * pm-cpufreq: cpufreq: powernv: Fix crash in gpstate_timer_handler()
Unified · Split
| @@ -5,10 +5,10 @@ struct x86_mapping_info { · 4 unmodified lines | ||
| 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 */ |
| @@ -3,15 +3,17 @@ · 2 unmodified lines | ||
| 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 | |
| @@ -30,13 +32,13 @@ static int ident_pud_init(struct x86_mapping_info *info, pud_t *pud_page, · 12 unmodified lines | ||
| 30 | 32 | |
| 31 | 33 | if (pud_present(*pud)) { |
| 32 | 34 | pmd = pmd_offset(pud, 0); |
| 33 | − ident_pmd_init(info->pmd_flag, pmd, addr, next); | |
| 35 | + ident_pmd_init(info, pmd, addr, next); | |
| 34 | 36 | continue; |
| 35 | 37 | } |
| 36 | 38 | pmd = (pmd_t *)info->alloc_pgt_page(info->context); |
| 37 | 39 | if (!pmd) |
| 38 | 40 | return -ENOMEM; |
| 39 | − ident_pmd_init(info->pmd_flag, pmd, addr, next); | |
| 41 | + ident_pmd_init(info, pmd, addr, next); | |
| 40 | 42 | set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE)); |
| 41 | 43 | } |
| 42 | 44 | |
| @@ -44,14 +46,15 @@ static int ident_pud_init(struct x86_mapping_info *info, pud_t *pud_page, · 1 unmodified line | ||
| 44 | 46 | } |
| 45 | 47 | |
| 46 | 48 | 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) | |
| 48 | 50 | { |
| 51 | + unsigned long addr = pstart + info->offset; | |
| 52 | + unsigned long end = pend + info->offset; | |
| 49 | 53 | unsigned long next; |
| 50 | 54 | int result; |
| 51 | − int off = info->kernel_mapping ? pgd_index(__PAGE_OFFSET) : 0; | |
| 52 | 55 | |
| 53 | 56 | for (; addr < end; addr = next) { |
| 54 | − pgd_t *pgd = pgd_page + pgd_index(addr) + off; | |
| 57 | + pgd_t *pgd = pgd_page + pgd_index(addr); | |
| 55 | 58 | pud_t *pud; |
| 56 | 59 | |
| 57 | 60 | next = (addr & PGDIR_MASK) + PGDIR_SIZE; |
| @@ -87,7 +87,7 @@ static int set_up_temporary_mappings(void) · 86 unmodified lines | ||
| 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; |
| @@ -145,11 +145,30 @@ static struct powernv_pstate_info { · 144 unmodified lines | ||
| 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 |
| @@ -593,7 +612,7 @@ void gpstate_timer_handler(unsigned long data) · 437 unmodified lines | ||
| 593 | 612 | } else { |
| 594 | 613 | gpstate_idx = calc_global_pstate(gpstates->elapsed_time, |
| 595 | 614 | gpstates->highest_lpstate_idx, |
| 596 | − freq_data.pstate_id); | |
| 615 | + gpstates->last_lpstate_idx); | |
| 597 | 616 | } |
| 598 | 617 | |
| 599 | 618 | /* |
| @@ -300,12 +300,12 @@ static int create_image(int platform_mode) · 299 unmodified lines | ||
| 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 | |