aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-10-24 15:45:47 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-24 15:45:47 -0400
commit83da00fbc0c57ce6f84455156a2e3cc057fe7344 (patch)
treefac652b63aac0bfade55cd8113afe668f00c9cd8 /arch/sparc
parent96971e9aa9578322648b2de593fd4863f3d9fc39 (diff)
parent06090e8ed89ea2113a236befb41f71d51f100e60 (diff)
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.
Diffstat (limited to 'arch/sparc')
-rw-r--r--arch/sparc/include/asm/oplib_64.h3
-rw-r--r--arch/sparc/include/asm/setup.h2
-rw-r--r--arch/sparc/kernel/entry.h3
-rw-r--r--arch/sparc/kernel/head_64.S40
-rw-r--r--arch/sparc/kernel/hvtramp.S1
-rw-r--r--arch/sparc/kernel/setup_64.c28
-rw-r--r--arch/sparc/kernel/trampoline_64.S12
-rw-r--r--arch/sparc/mm/gup.c30
-rw-r--r--arch/sparc/prom/cif.S5
-rw-r--r--arch/sparc/prom/init_64.c6
-rw-r--r--arch/sparc/prom/p1275.c2
11 files changed, 70 insertions, 62 deletions
diff --git a/arch/sparc/include/asm/oplib_64.h b/arch/sparc/include/asm/oplib_64.h
index f34682430fcf..2e3a4add8591 100644
--- a/arch/sparc/include/asm/oplib_64.h
+++ b/arch/sparc/include/asm/oplib_64.h
@@ -62,7 +62,8 @@ struct linux_mem_p1275 {
62/* You must call prom_init() before using any of the library services, 62/* You must call prom_init() before using any of the library services,
63 * preferably as early as possible. Pass it the romvec pointer. 63 * preferably as early as possible. Pass it the romvec pointer.
64 */ 64 */
65void prom_init(void *cif_handler, void *cif_stack); 65void prom_init(void *cif_handler);
66void prom_init_report(void);
66 67
67/* Boot argument acquisition, returns the boot command line string. */ 68/* Boot argument acquisition, returns the boot command line string. */
68char *prom_getbootargs(void); 69char *prom_getbootargs(void);
diff --git a/arch/sparc/include/asm/setup.h b/arch/sparc/include/asm/setup.h
index f5fffd84d0dd..29d64b1758ed 100644
--- a/arch/sparc/include/asm/setup.h
+++ b/arch/sparc/include/asm/setup.h
@@ -48,6 +48,8 @@ unsigned long safe_compute_effective_address(struct pt_regs *, unsigned int);
48#endif 48#endif
49 49
50#ifdef CONFIG_SPARC64 50#ifdef CONFIG_SPARC64
51void __init start_early_boot(void);
52
51/* unaligned_64.c */ 53/* unaligned_64.c */
52int handle_ldf_stq(u32 insn, struct pt_regs *regs); 54int handle_ldf_stq(u32 insn, struct pt_regs *regs);
53void handle_ld_nf(u32 insn, struct pt_regs *regs); 55void handle_ld_nf(u32 insn, struct pt_regs *regs);
diff --git a/arch/sparc/kernel/entry.h b/arch/sparc/kernel/entry.h
index ebaba6167dd4..88d322b67fac 100644
--- a/arch/sparc/kernel/entry.h
+++ b/arch/sparc/kernel/entry.h
@@ -65,13 +65,10 @@ struct pause_patch_entry {
65extern struct pause_patch_entry __pause_3insn_patch, 65extern struct pause_patch_entry __pause_3insn_patch,
66 __pause_3insn_patch_end; 66 __pause_3insn_patch_end;
67 67
68void __init per_cpu_patch(void);
69void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *, 68void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *,
70 struct sun4v_1insn_patch_entry *); 69 struct sun4v_1insn_patch_entry *);
71void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *, 70void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *,
72 struct sun4v_2insn_patch_entry *); 71 struct sun4v_2insn_patch_entry *);
73void __init sun4v_patch(void);
74void __init boot_cpu_id_too_large(int cpu);
75extern unsigned int dcache_parity_tl1_occurred; 72extern unsigned int dcache_parity_tl1_occurred;
76extern unsigned int icache_parity_tl1_occurred; 73extern unsigned int icache_parity_tl1_occurred;
77 74
diff --git a/arch/sparc/kernel/head_64.S b/arch/sparc/kernel/head_64.S
index 4fdeb8040d4d..3d61fcae7ee3 100644
--- a/arch/sparc/kernel/head_64.S
+++ b/arch/sparc/kernel/head_64.S
@@ -672,14 +672,12 @@ tlb_fixup_done:
672 sethi %hi(init_thread_union), %g6 672 sethi %hi(init_thread_union), %g6
673 or %g6, %lo(init_thread_union), %g6 673 or %g6, %lo(init_thread_union), %g6
674 ldx [%g6 + TI_TASK], %g4 674 ldx [%g6 + TI_TASK], %g4
675 mov %sp, %l6
676 675
677 wr %g0, ASI_P, %asi 676 wr %g0, ASI_P, %asi
678 mov 1, %g1 677 mov 1, %g1
679 sllx %g1, THREAD_SHIFT, %g1 678 sllx %g1, THREAD_SHIFT, %g1
680 sub %g1, (STACKFRAME_SZ + STACK_BIAS), %g1 679 sub %g1, (STACKFRAME_SZ + STACK_BIAS), %g1
681 add %g6, %g1, %sp 680 add %g6, %g1, %sp
682 mov 0, %fp
683 681
684 /* Set per-cpu pointer initially to zero, this makes 682 /* Set per-cpu pointer initially to zero, this makes
685 * the boot-cpu use the in-kernel-image per-cpu areas 683 * the boot-cpu use the in-kernel-image per-cpu areas
@@ -706,44 +704,14 @@ tlb_fixup_done:
706 nop 704 nop
707#endif 705#endif
708 706
709 mov %l6, %o1 ! OpenPROM stack
710 call prom_init 707 call prom_init
711 mov %l7, %o0 ! OpenPROM cif handler 708 mov %l7, %o0 ! OpenPROM cif handler
712 709
713 /* Initialize current_thread_info()->cpu as early as possible. 710 /* To create a one-register-window buffer between the kernel's
714 * In order to do that accurately we have to patch up the get_cpuid() 711 * initial stack and the last stack frame we use from the firmware,
715 * assembler sequences. And that, in turn, requires that we know 712 * do the rest of the boot from a C helper function.
716 * if we are on a Starfire box or not. While we're here, patch up
717 * the sun4v sequences as well.
718 */ 713 */
719 call check_if_starfire 714 call start_early_boot
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
7361:
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
747 nop 715 nop
748 /* Not reached... */ 716 /* Not reached... */
749 717
diff --git a/arch/sparc/kernel/hvtramp.S b/arch/sparc/kernel/hvtramp.S
index b7ddcdd1dea9..cdbfec299f2f 100644
--- a/arch/sparc/kernel/hvtramp.S
+++ b/arch/sparc/kernel/hvtramp.S
@@ -109,7 +109,6 @@ hv_cpu_startup:
109 sllx %g5, THREAD_SHIFT, %g5 109 sllx %g5, THREAD_SHIFT, %g5
110 sub %g5, (STACKFRAME_SZ + STACK_BIAS), %g5 110 sub %g5, (STACKFRAME_SZ + STACK_BIAS), %g5
111 add %g6, %g5, %sp 111 add %g6, %g5, %sp
112 mov 0, %fp
113 112
114 call init_irqwork_curcpu 113 call init_irqwork_curcpu
115 nop 114 nop
diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c
index e629b8377587..c38d19fc27ba 100644
--- a/arch/sparc/kernel/setup_64.c
+++ b/arch/sparc/kernel/setup_64.c
@@ -30,6 +30,7 @@
30#include <linux/cpu.h> 30#include <linux/cpu.h>
31#include <linux/initrd.h> 31#include <linux/initrd.h>
32#include <linux/module.h> 32#include <linux/module.h>
33#include <linux/start_kernel.h>
33 34
34#include <asm/io.h> 35#include <asm/io.h>
35#include <asm/processor.h> 36#include <asm/processor.h>
@@ -162,7 +163,7 @@ char reboot_command[COMMAND_LINE_SIZE];
162 163
163static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 }; 164static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 };
164 165
165void __init per_cpu_patch(void) 166static void __init per_cpu_patch(void)
166{ 167{
167 struct cpuid_patch_entry *p; 168 struct cpuid_patch_entry *p;
168 unsigned long ver; 169 unsigned long ver;
@@ -254,7 +255,7 @@ void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *start,
254 } 255 }
255} 256}
256 257
257void __init sun4v_patch(void) 258static void __init sun4v_patch(void)
258{ 259{
259 extern void sun4v_hvapi_init(void); 260 extern void sun4v_hvapi_init(void);
260 261
@@ -323,14 +324,25 @@ static void __init pause_patch(void)
323 } 324 }
324} 325}
325 326
326#ifdef CONFIG_SMP 327void __init start_early_boot(void)
327void __init boot_cpu_id_too_large(int cpu)
328{ 328{
329 prom_printf("Serious problem, boot cpu id (%d) >= NR_CPUS (%d)\n", 329 int cpu;
330 cpu, NR_CPUS); 330
331 prom_halt(); 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/* On Ultra, we support all of the v8 capabilities. */ 347/* On Ultra, we support all of the v8 capabilities. */
336unsigned long sparc64_elf_hwcap = (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | 348unsigned long sparc64_elf_hwcap = (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR |
diff --git a/arch/sparc/kernel/trampoline_64.S b/arch/sparc/kernel/trampoline_64.S
index 737f8cbc7d56..88ede1d53b4c 100644
--- a/arch/sparc/kernel/trampoline_64.S
+++ b/arch/sparc/kernel/trampoline_64.S
@@ -109,10 +109,13 @@ startup_continue:
109 brnz,pn %g1, 1b 109 brnz,pn %g1, 1b
110 nop 110 nop
111 111
112 sethi %hi(p1275buf), %g2 112 /* Get onto temporary stack which will be in the locked
113 or %g2, %lo(p1275buf), %g2 113 * kernel image.
114 ldx [%g2 + 0x10], %l2 114 */
115 add %l2, -(192 + 128), %sp 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 flushw 119 flushw
117 120
118 /* Setup the loop variables: 121 /* Setup the loop variables:
@@ -394,7 +397,6 @@ after_lock_tlb:
394 sllx %g5, THREAD_SHIFT, %g5 397 sllx %g5, THREAD_SHIFT, %g5
395 sub %g5, (STACKFRAME_SZ + STACK_BIAS), %g5 398 sub %g5, (STACKFRAME_SZ + STACK_BIAS), %g5
396 add %g6, %g5, %sp 399 add %g6, %g5, %sp
397 mov 0, %fp
398 400
399 rdpr %pstate, %o1 401 rdpr %pstate, %o1
400 or %o1, PSTATE_IE, %o1 402 or %o1, PSTATE_IE, %o1
diff --git a/arch/sparc/mm/gup.c b/arch/sparc/mm/gup.c
index 1aed0432c64b..ae6ce383d4df 100644
--- a/arch/sparc/mm/gup.c
+++ b/arch/sparc/mm/gup.c
@@ -160,6 +160,36 @@ static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end,
160 return 1; 160 return 1;
161} 161}
162 162
163int __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
163int get_user_pages_fast(unsigned long start, int nr_pages, int write, 193int get_user_pages_fast(unsigned long start, int nr_pages, int write,
164 struct page **pages) 194 struct page **pages)
165{ 195{
diff --git a/arch/sparc/prom/cif.S b/arch/sparc/prom/cif.S
index 9c86b4b7d429..8050f381f518 100644
--- a/arch/sparc/prom/cif.S
+++ b/arch/sparc/prom/cif.S
@@ -11,11 +11,10 @@
11 .text 11 .text
12 .globl prom_cif_direct 12 .globl prom_cif_direct
13prom_cif_direct: 13prom_cif_direct:
14 save %sp, -192, %sp
14 sethi %hi(p1275buf), %o1 15 sethi %hi(p1275buf), %o1
15 or %o1, %lo(p1275buf), %o1 16 or %o1, %lo(p1275buf), %o1
16 ldx [%o1 + 0x0010], %o2 ! prom_cif_stack 17 ldx [%o1 + 0x0008], %l2 ! prom_cif_handler
17 save %o2, -192, %sp
18 ldx [%i1 + 0x0008], %l2 ! prom_cif_handler
19 mov %g4, %l0 18 mov %g4, %l0
20 mov %g5, %l1 19 mov %g5, %l1
21 mov %g6, %l3 20 mov %g6, %l3
diff --git a/arch/sparc/prom/init_64.c b/arch/sparc/prom/init_64.c
index d95db755828f..110b0d78b864 100644
--- a/arch/sparc/prom/init_64.c
+++ b/arch/sparc/prom/init_64.c
@@ -26,13 +26,13 @@ phandle prom_chosen_node;
26 * It gets passed the pointer to the PROM vector. 26 * It gets passed the pointer to the PROM vector.
27 */ 27 */
28 28
29extern void prom_cif_init(void *, void *); 29extern void prom_cif_init(void *);
30 30
31void __init prom_init(void *cif_handler, void *cif_stack) 31void __init prom_init(void *cif_handler)
32{ 32{
33 phandle node; 33 phandle node;
34 34
35 prom_cif_init(cif_handler, cif_stack); 35 prom_cif_init(cif_handler);
36 36
37 prom_chosen_node = prom_finddevice(prom_chosen_path); 37 prom_chosen_node = prom_finddevice(prom_chosen_path);
38 if (!prom_chosen_node || (s32)prom_chosen_node == -1) 38 if (!prom_chosen_node || (s32)prom_chosen_node == -1)
diff --git a/arch/sparc/prom/p1275.c b/arch/sparc/prom/p1275.c
index b2340f008ae0..545d8bb79b65 100644
--- a/arch/sparc/prom/p1275.c
+++ b/arch/sparc/prom/p1275.c
@@ -20,7 +20,6 @@
20struct { 20struct {
21 long prom_callback; /* 0x00 */ 21 long prom_callback; /* 0x00 */
22 void (*prom_cif_handler)(long *); /* 0x08 */ 22 void (*prom_cif_handler)(long *); /* 0x08 */
23 unsigned long prom_cif_stack; /* 0x10 */
24} p1275buf; 23} p1275buf;
25 24
26extern void prom_world(int); 25extern void prom_world(int);
@@ -52,5 +51,4 @@ void p1275_cmd_direct(unsigned long *args)
52void prom_cif_init(void *cif_handler, void *cif_stack) 51void prom_cif_init(void *cif_handler, void *cif_stack)
53{ 52{
54 p1275buf.prom_cif_handler = (void (*)(long *))cif_handler; 53 p1275buf.prom_cif_handler = (void (*)(long *))cif_handler;
55 p1275buf.prom_cif_stack = (unsigned long)cif_stack;
56} 54}