Commit 83da00fbc0c57ce6f84455156a2e3cc057fe7344
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc
Pull two sparc fixes from David Miller: 1) Fix boots with gcc-4.9 compiled sparc64 kernels. 2) Add missing __get_user_pages_fast() on sparc64 to fix hangs on futexes used in transparent hugepage areas. It's really idiotic to have a weak symbolled fallback that just returns zero, and causes this kind of bug. There should be no backup implementation and the link should fail if the architecture fails to provide __get_user_pages_fast() and supports transparent hugepages. * git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc: sparc64: Implement __get_user_pages_fast(). sparc64: Fix register corruption in top-most kernel stack frame during boot.
Showing 11 changed files Side-by-side Diff
- arch/sparc/include/asm/oplib_64.h
- arch/sparc/include/asm/setup.h
- arch/sparc/kernel/entry.h
- arch/sparc/kernel/head_64.S
- arch/sparc/kernel/hvtramp.S
- arch/sparc/kernel/setup_64.c
- arch/sparc/kernel/trampoline_64.S
- arch/sparc/mm/gup.c
- arch/sparc/prom/cif.S
- arch/sparc/prom/init_64.c
- arch/sparc/prom/p1275.c
arch/sparc/include/asm/oplib_64.h
... | ... | @@ -62,7 +62,8 @@ |
62 | 62 | /* You must call prom_init() before using any of the library services, |
63 | 63 | * preferably as early as possible. Pass it the romvec pointer. |
64 | 64 | */ |
65 | -void prom_init(void *cif_handler, void *cif_stack); | |
65 | +void prom_init(void *cif_handler); | |
66 | +void prom_init_report(void); | |
66 | 67 | |
67 | 68 | /* Boot argument acquisition, returns the boot command line string. */ |
68 | 69 | char *prom_getbootargs(void); |
arch/sparc/include/asm/setup.h
arch/sparc/kernel/entry.h
... | ... | @@ -65,13 +65,10 @@ |
65 | 65 | extern struct pause_patch_entry __pause_3insn_patch, |
66 | 66 | __pause_3insn_patch_end; |
67 | 67 | |
68 | -void __init per_cpu_patch(void); | |
69 | 68 | void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *, |
70 | 69 | struct sun4v_1insn_patch_entry *); |
71 | 70 | void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *, |
72 | 71 | struct sun4v_2insn_patch_entry *); |
73 | -void __init sun4v_patch(void); | |
74 | -void __init boot_cpu_id_too_large(int cpu); | |
75 | 72 | extern unsigned int dcache_parity_tl1_occurred; |
76 | 73 | extern unsigned int icache_parity_tl1_occurred; |
77 | 74 |
arch/sparc/kernel/head_64.S
... | ... | @@ -672,14 +672,12 @@ |
672 | 672 | sethi %hi(init_thread_union), %g6 |
673 | 673 | or %g6, %lo(init_thread_union), %g6 |
674 | 674 | ldx [%g6 + TI_TASK], %g4 |
675 | - mov %sp, %l6 | |
676 | 675 | |
677 | 676 | wr %g0, ASI_P, %asi |
678 | 677 | mov 1, %g1 |
679 | 678 | sllx %g1, THREAD_SHIFT, %g1 |
680 | 679 | sub %g1, (STACKFRAME_SZ + STACK_BIAS), %g1 |
681 | 680 | add %g6, %g1, %sp |
682 | - mov 0, %fp | |
683 | 681 | |
684 | 682 | /* Set per-cpu pointer initially to zero, this makes |
685 | 683 | * the boot-cpu use the in-kernel-image per-cpu areas |
686 | 684 | |
687 | 685 | |
... | ... | @@ -706,44 +704,14 @@ |
706 | 704 | nop |
707 | 705 | #endif |
708 | 706 | |
709 | - mov %l6, %o1 ! OpenPROM stack | |
710 | 707 | call prom_init |
711 | 708 | mov %l7, %o0 ! OpenPROM cif handler |
712 | 709 | |
713 | - /* Initialize current_thread_info()->cpu as early as possible. | |
714 | - * In order to do that accurately we have to patch up the get_cpuid() | |
715 | - * assembler sequences. And that, in turn, requires that we know | |
716 | - * if we are on a Starfire box or not. While we're here, patch up | |
717 | - * the sun4v sequences as well. | |
710 | + /* To create a one-register-window buffer between the kernel's | |
711 | + * initial stack and the last stack frame we use from the firmware, | |
712 | + * do the rest of the boot from a C helper function. | |
718 | 713 | */ |
719 | - call check_if_starfire | |
720 | - nop | |
721 | - call per_cpu_patch | |
722 | - nop | |
723 | - call sun4v_patch | |
724 | - nop | |
725 | - | |
726 | -#ifdef CONFIG_SMP | |
727 | - call hard_smp_processor_id | |
728 | - nop | |
729 | - cmp %o0, NR_CPUS | |
730 | - blu,pt %xcc, 1f | |
731 | - nop | |
732 | - call boot_cpu_id_too_large | |
733 | - nop | |
734 | - /* Not reached... */ | |
735 | - | |
736 | -1: | |
737 | -#else | |
738 | - mov 0, %o0 | |
739 | -#endif | |
740 | - sth %o0, [%g6 + TI_CPU] | |
741 | - | |
742 | - call prom_init_report | |
743 | - nop | |
744 | - | |
745 | - /* Off we go.... */ | |
746 | - call start_kernel | |
714 | + call start_early_boot | |
747 | 715 | nop |
748 | 716 | /* Not reached... */ |
749 | 717 |
arch/sparc/kernel/hvtramp.S
arch/sparc/kernel/setup_64.c
... | ... | @@ -30,6 +30,7 @@ |
30 | 30 | #include <linux/cpu.h> |
31 | 31 | #include <linux/initrd.h> |
32 | 32 | #include <linux/module.h> |
33 | +#include <linux/start_kernel.h> | |
33 | 34 | |
34 | 35 | #include <asm/io.h> |
35 | 36 | #include <asm/processor.h> |
... | ... | @@ -162,7 +163,7 @@ |
162 | 163 | |
163 | 164 | static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 }; |
164 | 165 | |
165 | -void __init per_cpu_patch(void) | |
166 | +static void __init per_cpu_patch(void) | |
166 | 167 | { |
167 | 168 | struct cpuid_patch_entry *p; |
168 | 169 | unsigned long ver; |
... | ... | @@ -254,7 +255,7 @@ |
254 | 255 | } |
255 | 256 | } |
256 | 257 | |
257 | -void __init sun4v_patch(void) | |
258 | +static void __init sun4v_patch(void) | |
258 | 259 | { |
259 | 260 | extern void sun4v_hvapi_init(void); |
260 | 261 | |
261 | 262 | |
262 | 263 | |
... | ... | @@ -323,14 +324,25 @@ |
323 | 324 | } |
324 | 325 | } |
325 | 326 | |
326 | -#ifdef CONFIG_SMP | |
327 | -void __init boot_cpu_id_too_large(int cpu) | |
327 | +void __init start_early_boot(void) | |
328 | 328 | { |
329 | - prom_printf("Serious problem, boot cpu id (%d) >= NR_CPUS (%d)\n", | |
330 | - cpu, NR_CPUS); | |
331 | - prom_halt(); | |
329 | + int cpu; | |
330 | + | |
331 | + check_if_starfire(); | |
332 | + per_cpu_patch(); | |
333 | + sun4v_patch(); | |
334 | + | |
335 | + cpu = hard_smp_processor_id(); | |
336 | + if (cpu >= NR_CPUS) { | |
337 | + prom_printf("Serious problem, boot cpu id (%d) >= NR_CPUS (%d)\n", | |
338 | + cpu, NR_CPUS); | |
339 | + prom_halt(); | |
340 | + } | |
341 | + current_thread_info()->cpu = cpu; | |
342 | + | |
343 | + prom_init_report(); | |
344 | + start_kernel(); | |
332 | 345 | } |
333 | -#endif | |
334 | 346 | |
335 | 347 | /* On Ultra, we support all of the v8 capabilities. */ |
336 | 348 | unsigned long sparc64_elf_hwcap = (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | |
arch/sparc/kernel/trampoline_64.S
... | ... | @@ -109,10 +109,13 @@ |
109 | 109 | brnz,pn %g1, 1b |
110 | 110 | nop |
111 | 111 | |
112 | - sethi %hi(p1275buf), %g2 | |
113 | - or %g2, %lo(p1275buf), %g2 | |
114 | - ldx [%g2 + 0x10], %l2 | |
115 | - add %l2, -(192 + 128), %sp | |
112 | + /* Get onto temporary stack which will be in the locked | |
113 | + * kernel image. | |
114 | + */ | |
115 | + sethi %hi(tramp_stack), %g1 | |
116 | + or %g1, %lo(tramp_stack), %g1 | |
117 | + add %g1, TRAMP_STACK_SIZE, %g1 | |
118 | + sub %g1, STACKFRAME_SZ + STACK_BIAS + 256, %sp | |
116 | 119 | flushw |
117 | 120 | |
118 | 121 | /* Setup the loop variables: |
... | ... | @@ -394,7 +397,6 @@ |
394 | 397 | sllx %g5, THREAD_SHIFT, %g5 |
395 | 398 | sub %g5, (STACKFRAME_SZ + STACK_BIAS), %g5 |
396 | 399 | add %g6, %g5, %sp |
397 | - mov 0, %fp | |
398 | 400 | |
399 | 401 | rdpr %pstate, %o1 |
400 | 402 | or %o1, PSTATE_IE, %o1 |
arch/sparc/mm/gup.c
... | ... | @@ -160,6 +160,36 @@ |
160 | 160 | return 1; |
161 | 161 | } |
162 | 162 | |
163 | +int __get_user_pages_fast(unsigned long start, int nr_pages, int write, | |
164 | + struct page **pages) | |
165 | +{ | |
166 | + struct mm_struct *mm = current->mm; | |
167 | + unsigned long addr, len, end; | |
168 | + unsigned long next, flags; | |
169 | + pgd_t *pgdp; | |
170 | + int nr = 0; | |
171 | + | |
172 | + start &= PAGE_MASK; | |
173 | + addr = start; | |
174 | + len = (unsigned long) nr_pages << PAGE_SHIFT; | |
175 | + end = start + len; | |
176 | + | |
177 | + local_irq_save(flags); | |
178 | + pgdp = pgd_offset(mm, addr); | |
179 | + do { | |
180 | + pgd_t pgd = *pgdp; | |
181 | + | |
182 | + next = pgd_addr_end(addr, end); | |
183 | + if (pgd_none(pgd)) | |
184 | + break; | |
185 | + if (!gup_pud_range(pgd, addr, next, write, pages, &nr)) | |
186 | + break; | |
187 | + } while (pgdp++, addr = next, addr != end); | |
188 | + local_irq_restore(flags); | |
189 | + | |
190 | + return nr; | |
191 | +} | |
192 | + | |
163 | 193 | int get_user_pages_fast(unsigned long start, int nr_pages, int write, |
164 | 194 | struct page **pages) |
165 | 195 | { |
arch/sparc/prom/cif.S
... | ... | @@ -11,11 +11,10 @@ |
11 | 11 | .text |
12 | 12 | .globl prom_cif_direct |
13 | 13 | prom_cif_direct: |
14 | + save %sp, -192, %sp | |
14 | 15 | sethi %hi(p1275buf), %o1 |
15 | 16 | or %o1, %lo(p1275buf), %o1 |
16 | - ldx [%o1 + 0x0010], %o2 ! prom_cif_stack | |
17 | - save %o2, -192, %sp | |
18 | - ldx [%i1 + 0x0008], %l2 ! prom_cif_handler | |
17 | + ldx [%o1 + 0x0008], %l2 ! prom_cif_handler | |
19 | 18 | mov %g4, %l0 |
20 | 19 | mov %g5, %l1 |
21 | 20 | mov %g6, %l3 |
arch/sparc/prom/init_64.c
... | ... | @@ -26,13 +26,13 @@ |
26 | 26 | * It gets passed the pointer to the PROM vector. |
27 | 27 | */ |
28 | 28 | |
29 | -extern void prom_cif_init(void *, void *); | |
29 | +extern void prom_cif_init(void *); | |
30 | 30 | |
31 | -void __init prom_init(void *cif_handler, void *cif_stack) | |
31 | +void __init prom_init(void *cif_handler) | |
32 | 32 | { |
33 | 33 | phandle node; |
34 | 34 | |
35 | - prom_cif_init(cif_handler, cif_stack); | |
35 | + prom_cif_init(cif_handler); | |
36 | 36 | |
37 | 37 | prom_chosen_node = prom_finddevice(prom_chosen_path); |
38 | 38 | if (!prom_chosen_node || (s32)prom_chosen_node == -1) |
arch/sparc/prom/p1275.c
... | ... | @@ -20,7 +20,6 @@ |
20 | 20 | struct { |
21 | 21 | long prom_callback; /* 0x00 */ |
22 | 22 | void (*prom_cif_handler)(long *); /* 0x08 */ |
23 | - unsigned long prom_cif_stack; /* 0x10 */ | |
24 | 23 | } p1275buf; |
25 | 24 | |
26 | 25 | extern void prom_world(int); |
... | ... | @@ -52,6 +51,5 @@ |
52 | 51 | void prom_cif_init(void *cif_handler, void *cif_stack) |
53 | 52 | { |
54 | 53 | p1275buf.prom_cif_handler = (void (*)(long *))cif_handler; |
55 | - p1275buf.prom_cif_stack = (unsigned long)cif_stack; | |
56 | 54 | } |