From: Greg Kroah-Hartman Date: Mon, 20 Jun 2016 17:48:49 +0000 (-0700) Subject: 4.4-stable patches X-Git-Tag: v3.14.73~25 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=671a6b2ce6c6b675671ed67e561edca4581760f9;p=thirdparty%2Fkernel%2Fstable-queue.git 4.4-stable patches added patches: sparc-fix-system-call-tracing-register-handling.patch sparc-harden-signal-return-frame-checks.patch sparc-pci-fix-for-panic-while-enabling-sr-iov.patch sparc64-fix-bootup-regressions-on-some-kconfig-combinations.patch sparc64-fix-numa-node-distance-initialization.patch sparc64-fix-return-from-trap-window-fill-crashes.patch sparc64-fix-sparc64_set_context-stack-handling.patch sparc64-reduce-tlb-flushes-during-hugepte-changes.patch sparc64-take-ctx_alloc_lock-properly-in-hugetlb_setup.patch --- diff --git a/queue-4.4/series b/queue-4.4/series index 8858b271643..208639da779 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -48,3 +48,12 @@ x86-entry-traps-don-t-force-in_interrupt-to-return-true-in-ist-handlers.patch proc-prevent-stacking-filesystems-on-top.patch sched-panic-on-corrupted-stack-end.patch fix-d_walk-non-delayed-__d_free-race.patch +sparc-fix-system-call-tracing-register-handling.patch +sparc64-fix-bootup-regressions-on-some-kconfig-combinations.patch +sparc64-fix-numa-node-distance-initialization.patch +sparc64-fix-sparc64_set_context-stack-handling.patch +sparc-pci-fix-for-panic-while-enabling-sr-iov.patch +sparc64-reduce-tlb-flushes-during-hugepte-changes.patch +sparc64-take-ctx_alloc_lock-properly-in-hugetlb_setup.patch +sparc-harden-signal-return-frame-checks.patch +sparc64-fix-return-from-trap-window-fill-crashes.patch diff --git a/queue-4.4/sparc-fix-system-call-tracing-register-handling.patch b/queue-4.4/sparc-fix-system-call-tracing-register-handling.patch new file mode 100644 index 00000000000..10702b078d9 --- /dev/null +++ b/queue-4.4/sparc-fix-system-call-tracing-register-handling.patch @@ -0,0 +1,108 @@ +From foo@baz Mon Jun 20 10:48:29 PDT 2016 +From: Mike Frysinger +Date: Mon, 18 Jan 2016 06:32:30 -0500 +Subject: sparc: Fix system call tracing register handling. + +From: Mike Frysinger + +[ Upstream commit 1a40b95374f680625318ab61d81958e949e0afe3 ] + +A system call trace trigger on entry allows the tracing +process to inspect and potentially change the traced +process's registers. + +Account for that by reloading the %g1 (syscall number) +and %i0-%i5 (syscall argument) values. We need to be +careful to revalidate the range of %g1, and reload the +system call table entry it corresponds to into %l7. + +Reported-by: Mike Frysinger +Signed-off-by: David S. Miller +Tested-by: Mike Frysinger +Signed-off-by: Greg Kroah-Hartman +--- + arch/sparc/kernel/entry.S | 17 +++++++++++++++++ + arch/sparc/kernel/syscalls.S | 36 ++++++++++++++++++++++++++++++++++++ + 2 files changed, 53 insertions(+) + +--- a/arch/sparc/kernel/entry.S ++++ b/arch/sparc/kernel/entry.S +@@ -948,7 +948,24 @@ linux_syscall_trace: + cmp %o0, 0 + bne 3f + mov -ENOSYS, %o0 ++ ++ /* Syscall tracing can modify the registers. */ ++ ld [%sp + STACKFRAME_SZ + PT_G1], %g1 ++ sethi %hi(sys_call_table), %l7 ++ ld [%sp + STACKFRAME_SZ + PT_I0], %i0 ++ or %l7, %lo(sys_call_table), %l7 ++ ld [%sp + STACKFRAME_SZ + PT_I1], %i1 ++ ld [%sp + STACKFRAME_SZ + PT_I2], %i2 ++ ld [%sp + STACKFRAME_SZ + PT_I3], %i3 ++ ld [%sp + STACKFRAME_SZ + PT_I4], %i4 ++ ld [%sp + STACKFRAME_SZ + PT_I5], %i5 ++ cmp %g1, NR_syscalls ++ bgeu 3f ++ mov -ENOSYS, %o0 ++ ++ sll %g1, 2, %l4 + mov %i0, %o0 ++ ld [%l7 + %l4], %l7 + mov %i1, %o1 + mov %i2, %o2 + mov %i3, %o3 +--- a/arch/sparc/kernel/syscalls.S ++++ b/arch/sparc/kernel/syscalls.S +@@ -158,7 +158,25 @@ linux_syscall_trace32: + add %sp, PTREGS_OFF, %o0 + brnz,pn %o0, 3f + mov -ENOSYS, %o0 ++ ++ /* Syscall tracing can modify the registers. */ ++ ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1 ++ sethi %hi(sys_call_table32), %l7 ++ ldx [%sp + PTREGS_OFF + PT_V9_I0], %i0 ++ or %l7, %lo(sys_call_table32), %l7 ++ ldx [%sp + PTREGS_OFF + PT_V9_I1], %i1 ++ ldx [%sp + PTREGS_OFF + PT_V9_I2], %i2 ++ ldx [%sp + PTREGS_OFF + PT_V9_I3], %i3 ++ ldx [%sp + PTREGS_OFF + PT_V9_I4], %i4 ++ ldx [%sp + PTREGS_OFF + PT_V9_I5], %i5 ++ ++ cmp %g1, NR_syscalls ++ bgeu,pn %xcc, 3f ++ mov -ENOSYS, %o0 ++ ++ sll %g1, 2, %l4 + srl %i0, 0, %o0 ++ lduw [%l7 + %l4], %l7 + srl %i4, 0, %o4 + srl %i1, 0, %o1 + srl %i2, 0, %o2 +@@ -170,7 +188,25 @@ linux_syscall_trace: + add %sp, PTREGS_OFF, %o0 + brnz,pn %o0, 3f + mov -ENOSYS, %o0 ++ ++ /* Syscall tracing can modify the registers. */ ++ ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1 ++ sethi %hi(sys_call_table64), %l7 ++ ldx [%sp + PTREGS_OFF + PT_V9_I0], %i0 ++ or %l7, %lo(sys_call_table64), %l7 ++ ldx [%sp + PTREGS_OFF + PT_V9_I1], %i1 ++ ldx [%sp + PTREGS_OFF + PT_V9_I2], %i2 ++ ldx [%sp + PTREGS_OFF + PT_V9_I3], %i3 ++ ldx [%sp + PTREGS_OFF + PT_V9_I4], %i4 ++ ldx [%sp + PTREGS_OFF + PT_V9_I5], %i5 ++ ++ cmp %g1, NR_syscalls ++ bgeu,pn %xcc, 3f ++ mov -ENOSYS, %o0 ++ ++ sll %g1, 2, %l4 + mov %i0, %o0 ++ lduw [%l7 + %l4], %l7 + mov %i1, %o1 + mov %i2, %o2 + mov %i3, %o3 diff --git a/queue-4.4/sparc-harden-signal-return-frame-checks.patch b/queue-4.4/sparc-harden-signal-return-frame-checks.patch new file mode 100644 index 00000000000..497b09e53f9 --- /dev/null +++ b/queue-4.4/sparc-harden-signal-return-frame-checks.patch @@ -0,0 +1,315 @@ +From foo@baz Mon Jun 20 10:48:29 PDT 2016 +From: "David S. Miller" +Date: Sat, 28 May 2016 21:21:31 -0700 +Subject: sparc: Harden signal return frame checks. + +From: "David S. Miller" + +[ Upstream commit d11c2a0de2824395656cf8ed15811580c9dd38aa ] + +All signal frames must be at least 16-byte aligned, because that is +the alignment we explicitly create when we build signal return stack +frames. + +All stack pointers must be at least 8-byte aligned. + +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + arch/sparc/kernel/signal32.c | 46 ++++++++++++++++++++++++++--------------- + arch/sparc/kernel/signal_32.c | 41 +++++++++++++++++++++++------------- + arch/sparc/kernel/signal_64.c | 31 +++++++++++++++++---------- + arch/sparc/kernel/sigutil_32.c | 9 +++++++- + arch/sparc/kernel/sigutil_64.c | 10 +++++++- + 5 files changed, 92 insertions(+), 45 deletions(-) + +--- a/arch/sparc/kernel/signal32.c ++++ b/arch/sparc/kernel/signal32.c +@@ -138,12 +138,24 @@ int copy_siginfo_from_user32(siginfo_t * + return 0; + } + ++/* Checks if the fp is valid. We always build signal frames which are ++ * 16-byte aligned, therefore we can always enforce that the restore ++ * frame has that property as well. ++ */ ++static bool invalid_frame_pointer(void __user *fp, int fplen) ++{ ++ if ((((unsigned long) fp) & 15) || ++ ((unsigned long)fp) > 0x100000000ULL - fplen) ++ return true; ++ return false; ++} ++ + void do_sigreturn32(struct pt_regs *regs) + { + struct signal_frame32 __user *sf; + compat_uptr_t fpu_save; + compat_uptr_t rwin_save; +- unsigned int psr; ++ unsigned int psr, ufp; + unsigned pc, npc; + sigset_t set; + compat_sigset_t seta; +@@ -158,11 +170,16 @@ void do_sigreturn32(struct pt_regs *regs + sf = (struct signal_frame32 __user *) regs->u_regs[UREG_FP]; + + /* 1. Make sure we are not getting garbage from the user */ +- if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) || +- (((unsigned long) sf) & 3)) ++ if (invalid_frame_pointer(sf, sizeof(*sf))) ++ goto segv; ++ ++ if (get_user(ufp, &sf->info.si_regs.u_regs[UREG_FP])) ++ goto segv; ++ ++ if (ufp & 0x7) + goto segv; + +- if (get_user(pc, &sf->info.si_regs.pc) || ++ if (__get_user(pc, &sf->info.si_regs.pc) || + __get_user(npc, &sf->info.si_regs.npc)) + goto segv; + +@@ -227,7 +244,7 @@ segv: + asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) + { + struct rt_signal_frame32 __user *sf; +- unsigned int psr, pc, npc; ++ unsigned int psr, pc, npc, ufp; + compat_uptr_t fpu_save; + compat_uptr_t rwin_save; + sigset_t set; +@@ -242,11 +259,16 @@ asmlinkage void do_rt_sigreturn32(struct + sf = (struct rt_signal_frame32 __user *) regs->u_regs[UREG_FP]; + + /* 1. Make sure we are not getting garbage from the user */ +- if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) || +- (((unsigned long) sf) & 3)) ++ if (invalid_frame_pointer(sf, sizeof(*sf))) + goto segv; + +- if (get_user(pc, &sf->regs.pc) || ++ if (get_user(ufp, &sf->regs.u_regs[UREG_FP])) ++ goto segv; ++ ++ if (ufp & 0x7) ++ goto segv; ++ ++ if (__get_user(pc, &sf->regs.pc) || + __get_user(npc, &sf->regs.npc)) + goto segv; + +@@ -307,14 +329,6 @@ segv: + force_sig(SIGSEGV, current); + } + +-/* Checks if the fp is valid */ +-static int invalid_frame_pointer(void __user *fp, int fplen) +-{ +- if ((((unsigned long) fp) & 7) || ((unsigned long)fp) > 0x100000000ULL - fplen) +- return 1; +- return 0; +-} +- + static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize) + { + unsigned long sp; +--- a/arch/sparc/kernel/signal_32.c ++++ b/arch/sparc/kernel/signal_32.c +@@ -60,10 +60,22 @@ struct rt_signal_frame { + #define SF_ALIGNEDSZ (((sizeof(struct signal_frame) + 7) & (~7))) + #define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7))) + ++/* Checks if the fp is valid. We always build signal frames which are ++ * 16-byte aligned, therefore we can always enforce that the restore ++ * frame has that property as well. ++ */ ++static inline bool invalid_frame_pointer(void __user *fp, int fplen) ++{ ++ if ((((unsigned long) fp) & 15) || !__access_ok((unsigned long)fp, fplen)) ++ return true; ++ ++ return false; ++} ++ + asmlinkage void do_sigreturn(struct pt_regs *regs) + { ++ unsigned long up_psr, pc, npc, ufp; + struct signal_frame __user *sf; +- unsigned long up_psr, pc, npc; + sigset_t set; + __siginfo_fpu_t __user *fpu_save; + __siginfo_rwin_t __user *rwin_save; +@@ -77,10 +89,13 @@ asmlinkage void do_sigreturn(struct pt_r + sf = (struct signal_frame __user *) regs->u_regs[UREG_FP]; + + /* 1. Make sure we are not getting garbage from the user */ +- if (!access_ok(VERIFY_READ, sf, sizeof(*sf))) ++ if (!invalid_frame_pointer(sf, sizeof(*sf))) + goto segv_and_exit; + +- if (((unsigned long) sf) & 3) ++ if (get_user(ufp, &sf->info.si_regs.u_regs[UREG_FP])) ++ goto segv_and_exit; ++ ++ if (ufp & 0x7) + goto segv_and_exit; + + err = __get_user(pc, &sf->info.si_regs.pc); +@@ -127,7 +142,7 @@ segv_and_exit: + asmlinkage void do_rt_sigreturn(struct pt_regs *regs) + { + struct rt_signal_frame __user *sf; +- unsigned int psr, pc, npc; ++ unsigned int psr, pc, npc, ufp; + __siginfo_fpu_t __user *fpu_save; + __siginfo_rwin_t __user *rwin_save; + sigset_t set; +@@ -135,8 +150,13 @@ asmlinkage void do_rt_sigreturn(struct p + + synchronize_user_stack(); + sf = (struct rt_signal_frame __user *) regs->u_regs[UREG_FP]; +- if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) || +- (((unsigned long) sf) & 0x03)) ++ if (!invalid_frame_pointer(sf, sizeof(*sf))) ++ goto segv; ++ ++ if (get_user(ufp, &sf->regs.u_regs[UREG_FP])) ++ goto segv; ++ ++ if (ufp & 0x7) + goto segv; + + err = __get_user(pc, &sf->regs.pc); +@@ -178,15 +198,6 @@ segv: + force_sig(SIGSEGV, current); + } + +-/* Checks if the fp is valid */ +-static inline int invalid_frame_pointer(void __user *fp, int fplen) +-{ +- if ((((unsigned long) fp) & 7) || !__access_ok((unsigned long)fp, fplen)) +- return 1; +- +- return 0; +-} +- + static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize) + { + unsigned long sp = regs->u_regs[UREG_FP]; +--- a/arch/sparc/kernel/signal_64.c ++++ b/arch/sparc/kernel/signal_64.c +@@ -234,6 +234,17 @@ do_sigsegv: + goto out; + } + ++/* Checks if the fp is valid. We always build rt signal frames which ++ * are 16-byte aligned, therefore we can always enforce that the ++ * restore frame has that property as well. ++ */ ++static bool invalid_frame_pointer(void __user *fp) ++{ ++ if (((unsigned long) fp) & 15) ++ return true; ++ return false; ++} ++ + struct rt_signal_frame { + struct sparc_stackf ss; + siginfo_t info; +@@ -246,8 +257,8 @@ struct rt_signal_frame { + + void do_rt_sigreturn(struct pt_regs *regs) + { ++ unsigned long tpc, tnpc, tstate, ufp; + struct rt_signal_frame __user *sf; +- unsigned long tpc, tnpc, tstate; + __siginfo_fpu_t __user *fpu_save; + __siginfo_rwin_t __user *rwin_save; + sigset_t set; +@@ -261,10 +272,16 @@ void do_rt_sigreturn(struct pt_regs *reg + (regs->u_regs [UREG_FP] + STACK_BIAS); + + /* 1. Make sure we are not getting garbage from the user */ +- if (((unsigned long) sf) & 3) ++ if (invalid_frame_pointer(sf)) ++ goto segv; ++ ++ if (get_user(ufp, &sf->regs.u_regs[UREG_FP])) + goto segv; + +- err = get_user(tpc, &sf->regs.tpc); ++ if ((ufp + STACK_BIAS) & 0x7) ++ goto segv; ++ ++ err = __get_user(tpc, &sf->regs.tpc); + err |= __get_user(tnpc, &sf->regs.tnpc); + if (test_thread_flag(TIF_32BIT)) { + tpc &= 0xffffffff; +@@ -308,14 +325,6 @@ segv: + force_sig(SIGSEGV, current); + } + +-/* Checks if the fp is valid */ +-static int invalid_frame_pointer(void __user *fp) +-{ +- if (((unsigned long) fp) & 15) +- return 1; +- return 0; +-} +- + static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize) + { + unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS; +--- a/arch/sparc/kernel/sigutil_32.c ++++ b/arch/sparc/kernel/sigutil_32.c +@@ -48,6 +48,10 @@ int save_fpu_state(struct pt_regs *regs, + int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) + { + int err; ++ ++ if (((unsigned long) fpu) & 3) ++ return -EFAULT; ++ + #ifdef CONFIG_SMP + if (test_tsk_thread_flag(current, TIF_USEDFPU)) + regs->psr &= ~PSR_EF; +@@ -97,7 +101,10 @@ int restore_rwin_state(__siginfo_rwin_t + struct thread_info *t = current_thread_info(); + int i, wsaved, err; + +- __get_user(wsaved, &rp->wsaved); ++ if (((unsigned long) rp) & 3) ++ return -EFAULT; ++ ++ get_user(wsaved, &rp->wsaved); + if (wsaved > NSWINS) + return -EFAULT; + +--- a/arch/sparc/kernel/sigutil_64.c ++++ b/arch/sparc/kernel/sigutil_64.c +@@ -37,7 +37,10 @@ int restore_fpu_state(struct pt_regs *re + unsigned long fprs; + int err; + +- err = __get_user(fprs, &fpu->si_fprs); ++ if (((unsigned long) fpu) & 7) ++ return -EFAULT; ++ ++ err = get_user(fprs, &fpu->si_fprs); + fprs_write(0); + regs->tstate &= ~TSTATE_PEF; + if (fprs & FPRS_DL) +@@ -72,7 +75,10 @@ int restore_rwin_state(__siginfo_rwin_t + struct thread_info *t = current_thread_info(); + int i, wsaved, err; + +- __get_user(wsaved, &rp->wsaved); ++ if (((unsigned long) rp) & 7) ++ return -EFAULT; ++ ++ get_user(wsaved, &rp->wsaved); + if (wsaved > NSWINS) + return -EFAULT; + diff --git a/queue-4.4/sparc-pci-fix-for-panic-while-enabling-sr-iov.patch b/queue-4.4/sparc-pci-fix-for-panic-while-enabling-sr-iov.patch new file mode 100644 index 00000000000..efc6474a763 --- /dev/null +++ b/queue-4.4/sparc-pci-fix-for-panic-while-enabling-sr-iov.patch @@ -0,0 +1,148 @@ +From foo@baz Mon Jun 20 10:48:29 PDT 2016 +From: Babu Moger +Date: Thu, 24 Mar 2016 13:02:22 -0700 +Subject: sparc/PCI: Fix for panic while enabling SR-IOV + +From: Babu Moger + +[ Upstream commit d0c31e02005764dae0aab130a57e9794d06b824d ] + +We noticed this panic while enabling SR-IOV in sparc. + +mlx4_core: Mellanox ConnectX core driver v2.2-1 (Jan 1 2015) +mlx4_core: Initializing 0007:01:00.0 +mlx4_core 0007:01:00.0: Enabling SR-IOV with 5 VFs +mlx4_core: Initializing 0007:01:00.1 +Unable to handle kernel NULL pointer dereference +insmod(10010): Oops [#1] +CPU: 391 PID: 10010 Comm: insmod Not tainted + 4.1.12-32.el6uek.kdump2.sparc64 #1 +TPC: +I7: <__mlx4_init_one+0x324/0x500 [mlx4_core]> +Call Trace: + [00000000104c5ea4] __mlx4_init_one+0x324/0x500 [mlx4_core] + [00000000104c613c] mlx4_init_one+0xbc/0x120 [mlx4_core] + [0000000000725f14] local_pci_probe+0x34/0xa0 + [0000000000726028] pci_call_probe+0xa8/0xe0 + [0000000000726310] pci_device_probe+0x50/0x80 + [000000000079f700] really_probe+0x140/0x420 + [000000000079fa24] driver_probe_device+0x44/0xa0 + [000000000079fb5c] __device_attach+0x3c/0x60 + [000000000079d85c] bus_for_each_drv+0x5c/0xa0 + [000000000079f588] device_attach+0x88/0xc0 + [000000000071acd0] pci_bus_add_device+0x30/0x80 + [0000000000736090] virtfn_add.clone.1+0x210/0x360 + [00000000007364a4] sriov_enable+0x2c4/0x520 + [000000000073672c] pci_enable_sriov+0x2c/0x40 + [00000000104c2d58] mlx4_enable_sriov+0xf8/0x180 [mlx4_core] + [00000000104c49ac] mlx4_load_one+0x42c/0xd40 [mlx4_core] +Disabling lock debugging due to kernel taint +Caller[00000000104c5ea4]: __mlx4_init_one+0x324/0x500 [mlx4_core] +Caller[00000000104c613c]: mlx4_init_one+0xbc/0x120 [mlx4_core] +Caller[0000000000725f14]: local_pci_probe+0x34/0xa0 +Caller[0000000000726028]: pci_call_probe+0xa8/0xe0 +Caller[0000000000726310]: pci_device_probe+0x50/0x80 +Caller[000000000079f700]: really_probe+0x140/0x420 +Caller[000000000079fa24]: driver_probe_device+0x44/0xa0 +Caller[000000000079fb5c]: __device_attach+0x3c/0x60 +Caller[000000000079d85c]: bus_for_each_drv+0x5c/0xa0 +Caller[000000000079f588]: device_attach+0x88/0xc0 +Caller[000000000071acd0]: pci_bus_add_device+0x30/0x80 +Caller[0000000000736090]: virtfn_add.clone.1+0x210/0x360 +Caller[00000000007364a4]: sriov_enable+0x2c4/0x520 +Caller[000000000073672c]: pci_enable_sriov+0x2c/0x40 +Caller[00000000104c2d58]: mlx4_enable_sriov+0xf8/0x180 [mlx4_core] +Caller[00000000104c49ac]: mlx4_load_one+0x42c/0xd40 [mlx4_core] +Caller[00000000104c5f90]: __mlx4_init_one+0x410/0x500 [mlx4_core] +Caller[00000000104c613c]: mlx4_init_one+0xbc/0x120 [mlx4_core] +Caller[0000000000725f14]: local_pci_probe+0x34/0xa0 +Caller[0000000000726028]: pci_call_probe+0xa8/0xe0 +Caller[0000000000726310]: pci_device_probe+0x50/0x80 +Caller[000000000079f700]: really_probe+0x140/0x420 +Caller[000000000079fa24]: driver_probe_device+0x44/0xa0 +Caller[000000000079fb08]: __driver_attach+0x88/0xa0 +Caller[000000000079d90c]: bus_for_each_dev+0x6c/0xa0 +Caller[000000000079f29c]: driver_attach+0x1c/0x40 +Caller[000000000079e35c]: bus_add_driver+0x17c/0x220 +Caller[00000000007a02d4]: driver_register+0x74/0x120 +Caller[00000000007263fc]: __pci_register_driver+0x3c/0x60 +Caller[00000000104f62bc]: mlx4_init+0x60/0xcc [mlx4_core] +Kernel panic - not syncing: Fatal exception +Press Stop-A (L1-A) to return to the boot prom +---[ end Kernel panic - not syncing: Fatal exception + +Details: +Here is the call sequence +virtfn_add->__mlx4_init_one->dma_set_mask->dma_supported + +The panic happened at line 760(file arch/sparc/kernel/iommu.c) + +758 int dma_supported(struct device *dev, u64 device_mask) +759 { +760 struct iommu *iommu = dev->archdata.iommu; +761 u64 dma_addr_mask = iommu->dma_addr_mask; +762 +763 if (device_mask >= (1UL << 32UL)) +764 return 0; +765 +766 if ((device_mask & dma_addr_mask) == dma_addr_mask) +767 return 1; +768 +769 #ifdef CONFIG_PCI +770 if (dev_is_pci(dev)) +771 return pci64_dma_supported(to_pci_dev(dev), device_mask); +772 #endif +773 +774 return 0; +775 } +776 EXPORT_SYMBOL(dma_supported); + +Same panic happened with Intel ixgbe driver also. + +SR-IOV code looks for arch specific data while enabling +VFs. When VF device is added, driver probe function makes set +of calls to initialize the pci device. Because the VF device is +added different way than the normal PF device(which happens via +of_create_pci_dev for sparc), some of the arch specific initialization +does not happen for VF device. That causes panic when archdata is +accessed. + +To fix this, I have used already defined weak function +pcibios_setup_device to copy archdata from PF to VF. +Also verified the fix. + +Signed-off-by: Babu Moger +Signed-off-by: Sowmini Varadhan +Reviewed-by: Ethan Zhao +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + arch/sparc/kernel/pci.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +--- a/arch/sparc/kernel/pci.c ++++ b/arch/sparc/kernel/pci.c +@@ -994,6 +994,23 @@ void pcibios_set_master(struct pci_dev * + /* No special bus mastering setup handling */ + } + ++#ifdef CONFIG_PCI_IOV ++int pcibios_add_device(struct pci_dev *dev) ++{ ++ struct pci_dev *pdev; ++ ++ /* Add sriov arch specific initialization here. ++ * Copy dev_archdata from PF to VF ++ */ ++ if (dev->is_virtfn) { ++ pdev = dev->physfn; ++ memcpy(&dev->dev.archdata, &pdev->dev.archdata, ++ sizeof(struct dev_archdata)); ++ } ++ return 0; ++} ++#endif /* CONFIG_PCI_IOV */ ++ + static int __init pcibios_init(void) + { + pci_dfl_cache_line_size = 64 >> 2; diff --git a/queue-4.4/sparc64-fix-bootup-regressions-on-some-kconfig-combinations.patch b/queue-4.4/sparc64-fix-bootup-regressions-on-some-kconfig-combinations.patch new file mode 100644 index 00000000000..b083d425636 --- /dev/null +++ b/queue-4.4/sparc64-fix-bootup-regressions-on-some-kconfig-combinations.patch @@ -0,0 +1,349 @@ +From foo@baz Mon Jun 20 10:48:29 PDT 2016 +From: "David S. Miller" +Date: Wed, 27 Apr 2016 17:27:37 -0400 +Subject: sparc64: Fix bootup regressions on some Kconfig combinations. + +From: "David S. Miller" + +[ Upstream commit 49fa5230462f9f2c4e97c81356473a6bdf06c422 ] + +The system call tracing bug fix mentioned in the Fixes tag +below increased the amount of assembler code in the sequence +of assembler files included by head_64.S + +This caused to total set of code to exceed 0x4000 bytes in +size, which overflows the expression in head_64.S that works +to place swapper_tsb at address 0x408000. + +When this is violated, the TSB is not properly aligned, and +also the trap table is not aligned properly either. All of +this together results in failed boots. + +So, do two things: + +1) Simplify some code by using ba,a instead of ba/nop to get + those bytes back. + +2) Add a linker script assertion to make sure that if this + happens again the build will fail. + +Fixes: 1a40b95374f6 ("sparc: Fix system call tracing register handling.") +Reported-by: Meelis Roos +Reported-by: Joerg Abraham +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + arch/sparc/kernel/cherrs.S | 14 +++++--------- + arch/sparc/kernel/fpu_traps.S | 11 +++++------ + arch/sparc/kernel/head_64.S | 24 ++++++++---------------- + arch/sparc/kernel/misctrap.S | 12 ++++-------- + arch/sparc/kernel/spiterrs.S | 18 ++++++------------ + arch/sparc/kernel/utrap.S | 3 +-- + arch/sparc/kernel/vmlinux.lds.S | 4 ++++ + arch/sparc/kernel/winfixup.S | 3 +-- + 8 files changed, 34 insertions(+), 55 deletions(-) + +--- a/arch/sparc/kernel/cherrs.S ++++ b/arch/sparc/kernel/cherrs.S +@@ -214,8 +214,7 @@ do_dcpe_tl1_nonfatal: /* Ok we may use i + subcc %g1, %g2, %g1 ! Next cacheline + bge,pt %icc, 1b + nop +- ba,pt %xcc, dcpe_icpe_tl1_common +- nop ++ ba,a,pt %xcc, dcpe_icpe_tl1_common + + do_dcpe_tl1_fatal: + sethi %hi(1f), %g7 +@@ -224,8 +223,7 @@ do_dcpe_tl1_fatal: + mov 0x2, %o0 + call cheetah_plus_parity_error + add %sp, PTREGS_OFF, %o1 +- ba,pt %xcc, rtrap +- nop ++ ba,a,pt %xcc, rtrap + .size do_dcpe_tl1,.-do_dcpe_tl1 + + .globl do_icpe_tl1 +@@ -259,8 +257,7 @@ do_icpe_tl1_nonfatal: /* Ok we may use i + subcc %g1, %g2, %g1 + bge,pt %icc, 1b + nop +- ba,pt %xcc, dcpe_icpe_tl1_common +- nop ++ ba,a,pt %xcc, dcpe_icpe_tl1_common + + do_icpe_tl1_fatal: + sethi %hi(1f), %g7 +@@ -269,8 +266,7 @@ do_icpe_tl1_fatal: + mov 0x3, %o0 + call cheetah_plus_parity_error + add %sp, PTREGS_OFF, %o1 +- ba,pt %xcc, rtrap +- nop ++ ba,a,pt %xcc, rtrap + .size do_icpe_tl1,.-do_icpe_tl1 + + .type dcpe_icpe_tl1_common,#function +@@ -456,7 +452,7 @@ __cheetah_log_error: + cmp %g2, 0x63 + be c_cee + nop +- ba,pt %xcc, c_deferred ++ ba,a,pt %xcc, c_deferred + .size __cheetah_log_error,.-__cheetah_log_error + + /* Cheetah FECC trap handling, we get here from tl{0,1}_fecc +--- a/arch/sparc/kernel/fpu_traps.S ++++ b/arch/sparc/kernel/fpu_traps.S +@@ -100,8 +100,8 @@ do_fpdis: + fmuld %f0, %f2, %f26 + faddd %f0, %f2, %f28 + fmuld %f0, %f2, %f30 +- b,pt %xcc, fpdis_exit +- nop ++ ba,a,pt %xcc, fpdis_exit ++ + 2: andcc %g5, FPRS_DU, %g0 + bne,pt %icc, 3f + fzero %f32 +@@ -144,8 +144,8 @@ do_fpdis: + fmuld %f32, %f34, %f58 + faddd %f32, %f34, %f60 + fmuld %f32, %f34, %f62 +- ba,pt %xcc, fpdis_exit +- nop ++ ba,a,pt %xcc, fpdis_exit ++ + 3: mov SECONDARY_CONTEXT, %g3 + add %g6, TI_FPREGS, %g1 + +@@ -197,8 +197,7 @@ fpdis_exit2: + fp_other_bounce: + call do_fpother + add %sp, PTREGS_OFF, %o0 +- ba,pt %xcc, rtrap +- nop ++ ba,a,pt %xcc, rtrap + .size fp_other_bounce,.-fp_other_bounce + + .align 32 +--- a/arch/sparc/kernel/head_64.S ++++ b/arch/sparc/kernel/head_64.S +@@ -461,9 +461,8 @@ sun4v_chip_type: + subcc %g3, 1, %g3 + bne,pt %xcc, 41b + add %g1, 1, %g1 +- mov SUN4V_CHIP_SPARC64X, %g4 + ba,pt %xcc, 5f +- nop ++ mov SUN4V_CHIP_SPARC64X, %g4 + + 49: + mov SUN4V_CHIP_UNKNOWN, %g4 +@@ -548,8 +547,7 @@ sun4u_init: + stxa %g0, [%g7] ASI_DMMU + membar #Sync + +- ba,pt %xcc, sun4u_continue +- nop ++ ba,a,pt %xcc, sun4u_continue + + sun4v_init: + /* Set ctx 0 */ +@@ -560,14 +558,12 @@ sun4v_init: + mov SECONDARY_CONTEXT, %g7 + stxa %g0, [%g7] ASI_MMU + membar #Sync +- ba,pt %xcc, niagara_tlb_fixup +- nop ++ ba,a,pt %xcc, niagara_tlb_fixup + + sun4u_continue: + BRANCH_IF_ANY_CHEETAH(g1, g7, cheetah_tlb_fixup) + +- ba,pt %xcc, spitfire_tlb_fixup +- nop ++ ba,a,pt %xcc, spitfire_tlb_fixup + + niagara_tlb_fixup: + mov 3, %g2 /* Set TLB type to hypervisor. */ +@@ -639,8 +635,7 @@ niagara_patch: + call hypervisor_patch_cachetlbops + nop + +- ba,pt %xcc, tlb_fixup_done +- nop ++ ba,a,pt %xcc, tlb_fixup_done + + cheetah_tlb_fixup: + mov 2, %g2 /* Set TLB type to cheetah+. */ +@@ -659,8 +654,7 @@ cheetah_tlb_fixup: + call cheetah_patch_cachetlbops + nop + +- ba,pt %xcc, tlb_fixup_done +- nop ++ ba,a,pt %xcc, tlb_fixup_done + + spitfire_tlb_fixup: + /* Set TLB type to spitfire. */ +@@ -782,8 +776,7 @@ setup_trap_table: + call %o1 + add %sp, (2047 + 128), %o0 + +- ba,pt %xcc, 2f +- nop ++ ba,a,pt %xcc, 2f + + 1: sethi %hi(sparc64_ttable_tl0), %o0 + set prom_set_trap_table_name, %g2 +@@ -822,8 +815,7 @@ setup_trap_table: + + BRANCH_IF_ANY_CHEETAH(o2, o3, 1f) + +- ba,pt %xcc, 2f +- nop ++ ba,a,pt %xcc, 2f + + /* Disable STICK_INT interrupts. */ + 1: +--- a/arch/sparc/kernel/misctrap.S ++++ b/arch/sparc/kernel/misctrap.S +@@ -18,8 +18,7 @@ __do_privact: + 109: or %g7, %lo(109b), %g7 + call do_privact + add %sp, PTREGS_OFF, %o0 +- ba,pt %xcc, rtrap +- nop ++ ba,a,pt %xcc, rtrap + .size __do_privact,.-__do_privact + + .type do_mna,#function +@@ -46,8 +45,7 @@ do_mna: + mov %l5, %o2 + call mem_address_unaligned + add %sp, PTREGS_OFF, %o0 +- ba,pt %xcc, rtrap +- nop ++ ba,a,pt %xcc, rtrap + .size do_mna,.-do_mna + + .type do_lddfmna,#function +@@ -65,8 +63,7 @@ do_lddfmna: + mov %l5, %o2 + call handle_lddfmna + add %sp, PTREGS_OFF, %o0 +- ba,pt %xcc, rtrap +- nop ++ ba,a,pt %xcc, rtrap + .size do_lddfmna,.-do_lddfmna + + .type do_stdfmna,#function +@@ -84,8 +81,7 @@ do_stdfmna: + mov %l5, %o2 + call handle_stdfmna + add %sp, PTREGS_OFF, %o0 +- ba,pt %xcc, rtrap +- nop ++ ba,a,pt %xcc, rtrap + .size do_stdfmna,.-do_stdfmna + + .type breakpoint_trap,#function +--- a/arch/sparc/kernel/spiterrs.S ++++ b/arch/sparc/kernel/spiterrs.S +@@ -85,8 +85,7 @@ __spitfire_cee_trap_continue: + ba,pt %xcc, etraptl1 + rd %pc, %g7 + +- ba,pt %xcc, 2f +- nop ++ ba,a,pt %xcc, 2f + + 1: ba,pt %xcc, etrap_irq + rd %pc, %g7 +@@ -100,8 +99,7 @@ __spitfire_cee_trap_continue: + mov %l5, %o2 + call spitfire_access_error + add %sp, PTREGS_OFF, %o0 +- ba,pt %xcc, rtrap +- nop ++ ba,a,pt %xcc, rtrap + .size __spitfire_access_error,.-__spitfire_access_error + + /* This is the trap handler entry point for ECC correctable +@@ -179,8 +177,7 @@ __spitfire_data_access_exception_tl1: + mov %l5, %o2 + call spitfire_data_access_exception_tl1 + add %sp, PTREGS_OFF, %o0 +- ba,pt %xcc, rtrap +- nop ++ ba,a,pt %xcc, rtrap + .size __spitfire_data_access_exception_tl1,.-__spitfire_data_access_exception_tl1 + + .type __spitfire_data_access_exception,#function +@@ -200,8 +197,7 @@ __spitfire_data_access_exception: + mov %l5, %o2 + call spitfire_data_access_exception + add %sp, PTREGS_OFF, %o0 +- ba,pt %xcc, rtrap +- nop ++ ba,a,pt %xcc, rtrap + .size __spitfire_data_access_exception,.-__spitfire_data_access_exception + + .type __spitfire_insn_access_exception_tl1,#function +@@ -220,8 +216,7 @@ __spitfire_insn_access_exception_tl1: + mov %l5, %o2 + call spitfire_insn_access_exception_tl1 + add %sp, PTREGS_OFF, %o0 +- ba,pt %xcc, rtrap +- nop ++ ba,a,pt %xcc, rtrap + .size __spitfire_insn_access_exception_tl1,.-__spitfire_insn_access_exception_tl1 + + .type __spitfire_insn_access_exception,#function +@@ -240,6 +235,5 @@ __spitfire_insn_access_exception: + mov %l5, %o2 + call spitfire_insn_access_exception + add %sp, PTREGS_OFF, %o0 +- ba,pt %xcc, rtrap +- nop ++ ba,a,pt %xcc, rtrap + .size __spitfire_insn_access_exception,.-__spitfire_insn_access_exception +--- a/arch/sparc/kernel/utrap.S ++++ b/arch/sparc/kernel/utrap.S +@@ -11,8 +11,7 @@ utrap_trap: /* %g3=handler,%g4=level */ + mov %l4, %o1 + call bad_trap + add %sp, PTREGS_OFF, %o0 +- ba,pt %xcc, rtrap +- nop ++ ba,a,pt %xcc, rtrap + + invoke_utrap: + sllx %g3, 3, %g3 +--- a/arch/sparc/kernel/vmlinux.lds.S ++++ b/arch/sparc/kernel/vmlinux.lds.S +@@ -33,6 +33,10 @@ ENTRY(_start) + jiffies = jiffies_64; + #endif + ++#ifdef CONFIG_SPARC64 ++ASSERT((swapper_tsb == 0x0000000000408000), "Error: sparc64 early assembler too large") ++#endif ++ + SECTIONS + { + #ifdef CONFIG_SPARC64 +--- a/arch/sparc/kernel/winfixup.S ++++ b/arch/sparc/kernel/winfixup.S +@@ -32,8 +32,7 @@ fill_fixup: + rd %pc, %g7 + call do_sparc64_fault + add %sp, PTREGS_OFF, %o0 +- ba,pt %xcc, rtrap +- nop ++ ba,a,pt %xcc, rtrap + + /* Be very careful about usage of the trap globals here. + * You cannot touch %g5 as that has the fault information. diff --git a/queue-4.4/sparc64-fix-numa-node-distance-initialization.patch b/queue-4.4/sparc64-fix-numa-node-distance-initialization.patch new file mode 100644 index 00000000000..6c2b6caf502 --- /dev/null +++ b/queue-4.4/sparc64-fix-numa-node-distance-initialization.patch @@ -0,0 +1,60 @@ +From foo@baz Mon Jun 20 10:48:29 PDT 2016 +From: Nitin Gupta +Date: Tue, 5 Jan 2016 22:35:35 -0800 +Subject: sparc64: Fix numa node distance initialization + +From: Nitin Gupta + +[ Upstream commit 36beca6571c941b28b0798667608239731f9bc3a ] + +Orabug: 22495713 + +Currently, NUMA node distance matrix is initialized only +when a machine descriptor (MD) exists. However, sun4u +machines (e.g. Sun Blade 2500) do not have an MD and thus +distance values were left uninitialized. The initialization +is now moved such that it happens on both sun4u and sun4v. + +Signed-off-by: Nitin Gupta +Tested-by: Mikael Pettersson +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + arch/sparc/mm/init_64.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +--- a/arch/sparc/mm/init_64.c ++++ b/arch/sparc/mm/init_64.c +@@ -1267,13 +1267,6 @@ static int __init numa_parse_mdesc(void) + int i, j, err, count; + u64 node; + +- /* Some sane defaults for numa latency values */ +- for (i = 0; i < MAX_NUMNODES; i++) { +- for (j = 0; j < MAX_NUMNODES; j++) +- numa_latency[i][j] = (i == j) ? +- LOCAL_DISTANCE : REMOTE_DISTANCE; +- } +- + node = mdesc_node_by_name(md, MDESC_NODE_NULL, "latency-groups"); + if (node == MDESC_NODE_NULL) { + mdesc_release(md); +@@ -1369,10 +1362,18 @@ static int __init numa_parse_sun4u(void) + + static int __init bootmem_init_numa(void) + { ++ int i, j; + int err = -1; + + numadbg("bootmem_init_numa()\n"); + ++ /* Some sane defaults for numa latency values */ ++ for (i = 0; i < MAX_NUMNODES; i++) { ++ for (j = 0; j < MAX_NUMNODES; j++) ++ numa_latency[i][j] = (i == j) ? ++ LOCAL_DISTANCE : REMOTE_DISTANCE; ++ } ++ + if (numa_enabled) { + if (tlb_type == hypervisor) + err = numa_parse_mdesc(); diff --git a/queue-4.4/sparc64-fix-return-from-trap-window-fill-crashes.patch b/queue-4.4/sparc64-fix-return-from-trap-window-fill-crashes.patch new file mode 100644 index 00000000000..239c318d12b --- /dev/null +++ b/queue-4.4/sparc64-fix-return-from-trap-window-fill-crashes.patch @@ -0,0 +1,355 @@ +From foo@baz Mon Jun 20 10:48:29 PDT 2016 +From: "David S. Miller" +Date: Sat, 28 May 2016 20:41:12 -0700 +Subject: sparc64: Fix return from trap window fill crashes. + +From: "David S. Miller" + +[ Upstream commit 7cafc0b8bf130f038b0ec2dcdd6a9de6dc59b65a ] + +We must handle data access exception as well as memory address unaligned +exceptions from return from trap window fill faults, not just normal +TLB misses. + +Otherwise we can get an OOPS that looks like this: + +ld-linux.so.2(36808): Kernel bad sw trap 5 [#1] +CPU: 1 PID: 36808 Comm: ld-linux.so.2 Not tainted 4.6.0 #34 +task: fff8000303be5c60 ti: fff8000301344000 task.ti: fff8000301344000 +TSTATE: 0000004410001601 TPC: 0000000000a1a784 TNPC: 0000000000a1a788 Y: 00000002 Not tainted +TPC: +g0: fff8000024fc8248 g1: 0000000000db04dc g2: 0000000000000000 g3: 0000000000000001 +g4: fff8000303be5c60 g5: fff800030e672000 g6: fff8000301344000 g7: 0000000000000001 +o0: 0000000000b95ee8 o1: 000000000000012b o2: 0000000000000000 o3: 0000000200b9b358 +o4: 0000000000000000 o5: fff8000301344040 sp: fff80003013475c1 ret_pc: 0000000000a1a77c +RPC: +l0: 00000000000007ff l1: 0000000000000000 l2: 000000000000005f l3: 0000000000000000 +l4: fff8000301347e98 l5: fff8000024ff3060 l6: 0000000000000000 l7: 0000000000000000 +i0: fff8000301347f60 i1: 0000000000102400 i2: 0000000000000000 i3: 0000000000000000 +i4: 0000000000000000 i5: 0000000000000000 i6: fff80003013476a1 i7: 0000000000404d4c +I7: +Call Trace: + [0000000000404d4c] user_rtt_fill_fixup+0x6c/0x7c + +The window trap handlers are slightly clever, the trap table entries for them are +composed of two pieces of code. First comes the code that actually performs +the window fill or spill trap handling, and then there are three instructions at +the end which are for exception processing. + +The userland register window fill handler is: + + add %sp, STACK_BIAS + 0x00, %g1; \ + ldxa [%g1 + %g0] ASI, %l0; \ + mov 0x08, %g2; \ + mov 0x10, %g3; \ + ldxa [%g1 + %g2] ASI, %l1; \ + mov 0x18, %g5; \ + ldxa [%g1 + %g3] ASI, %l2; \ + ldxa [%g1 + %g5] ASI, %l3; \ + add %g1, 0x20, %g1; \ + ldxa [%g1 + %g0] ASI, %l4; \ + ldxa [%g1 + %g2] ASI, %l5; \ + ldxa [%g1 + %g3] ASI, %l6; \ + ldxa [%g1 + %g5] ASI, %l7; \ + add %g1, 0x20, %g1; \ + ldxa [%g1 + %g0] ASI, %i0; \ + ldxa [%g1 + %g2] ASI, %i1; \ + ldxa [%g1 + %g3] ASI, %i2; \ + ldxa [%g1 + %g5] ASI, %i3; \ + add %g1, 0x20, %g1; \ + ldxa [%g1 + %g0] ASI, %i4; \ + ldxa [%g1 + %g2] ASI, %i5; \ + ldxa [%g1 + %g3] ASI, %i6; \ + ldxa [%g1 + %g5] ASI, %i7; \ + restored; \ + retry; nop; nop; nop; nop; \ + b,a,pt %xcc, fill_fixup_dax; \ + b,a,pt %xcc, fill_fixup_mna; \ + b,a,pt %xcc, fill_fixup; + +And the way this works is that if any of those memory accesses +generate an exception, the exception handler can revector to one of +those final three branch instructions depending upon which kind of +exception the memory access took. In this way, the fault handler +doesn't have to know if it was a spill or a fill that it's handling +the fault for. It just always branches to the last instruction in +the parent trap's handler. + +For example, for a regular fault, the code goes: + +winfix_trampoline: + rdpr %tpc, %g3 + or %g3, 0x7c, %g3 + wrpr %g3, %tnpc + done + +All window trap handlers are 0x80 aligned, so if we "or" 0x7c into the +trap time program counter, we'll get that final instruction in the +trap handler. + +On return from trap, we have to pull the register window in but we do +this by hand instead of just executing a "restore" instruction for +several reasons. The largest being that from Niagara and onward we +simply don't have enough levels in the trap stack to fully resolve all +possible exception cases of a window fault when we are already at +trap level 1 (which we enter to get ready to return from the original +trap). + +This is executed inline via the FILL_*_RTRAP handlers. rtrap_64.S's +code branches directly to these to do the window fill by hand if +necessary. Now if you look at them, we'll see at the end: + + ba,a,pt %xcc, user_rtt_fill_fixup; + ba,a,pt %xcc, user_rtt_fill_fixup; + ba,a,pt %xcc, user_rtt_fill_fixup; + +And oops, all three cases are handled like a fault. + +This doesn't work because each of these trap types (data access +exception, memory address unaligned, and faults) store their auxiliary +info in different registers to pass on to the C handler which does the +real work. + +So in the case where the stack was unaligned, the unaligned trap +handler sets up the arg registers one way, and then we branched to +the fault handler which expects them setup another way. + +So the FAULT_TYPE_* value ends up basically being garbage, and +randomly would generate the backtrace seen above. + +Reported-by: Nick Alcock +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + arch/sparc/include/asm/head_64.h | 4 + + arch/sparc/include/asm/ttable.h | 8 +-- + arch/sparc/kernel/Makefile | 1 + arch/sparc/kernel/rtrap_64.S | 59 +++-------------------- + arch/sparc/kernel/urtt_fill.S | 98 +++++++++++++++++++++++++++++++++++++++ + 5 files changed, 117 insertions(+), 53 deletions(-) + create mode 100644 arch/sparc/kernel/urtt_fill.S + +--- a/arch/sparc/include/asm/head_64.h ++++ b/arch/sparc/include/asm/head_64.h +@@ -15,6 +15,10 @@ + + #define PTREGS_OFF (STACK_BIAS + STACKFRAME_SZ) + ++#define RTRAP_PSTATE (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV|PSTATE_IE) ++#define RTRAP_PSTATE_IRQOFF (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV) ++#define RTRAP_PSTATE_AG_IRQOFF (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV|PSTATE_AG) ++ + #define __CHEETAH_ID 0x003e0014 + #define __JALAPENO_ID 0x003e0016 + #define __SERRANO_ID 0x003e0022 +--- a/arch/sparc/include/asm/ttable.h ++++ b/arch/sparc/include/asm/ttable.h +@@ -589,8 +589,8 @@ user_rtt_fill_64bit: \ + restored; \ + nop; nop; nop; nop; nop; nop; \ + nop; nop; nop; nop; nop; \ +- ba,a,pt %xcc, user_rtt_fill_fixup; \ +- ba,a,pt %xcc, user_rtt_fill_fixup; \ ++ ba,a,pt %xcc, user_rtt_fill_fixup_dax; \ ++ ba,a,pt %xcc, user_rtt_fill_fixup_mna; \ + ba,a,pt %xcc, user_rtt_fill_fixup; + + +@@ -652,8 +652,8 @@ user_rtt_fill_32bit: \ + restored; \ + nop; nop; nop; nop; nop; \ + nop; nop; nop; \ +- ba,a,pt %xcc, user_rtt_fill_fixup; \ +- ba,a,pt %xcc, user_rtt_fill_fixup; \ ++ ba,a,pt %xcc, user_rtt_fill_fixup_dax; \ ++ ba,a,pt %xcc, user_rtt_fill_fixup_mna; \ + ba,a,pt %xcc, user_rtt_fill_fixup; + + +--- a/arch/sparc/kernel/Makefile ++++ b/arch/sparc/kernel/Makefile +@@ -21,6 +21,7 @@ CFLAGS_REMOVE_perf_event.o := -pg + CFLAGS_REMOVE_pcr.o := -pg + endif + ++obj-$(CONFIG_SPARC64) += urtt_fill.o + obj-$(CONFIG_SPARC32) += entry.o wof.o wuf.o + obj-$(CONFIG_SPARC32) += etrap_32.o + obj-$(CONFIG_SPARC32) += rtrap_32.o +--- a/arch/sparc/kernel/rtrap_64.S ++++ b/arch/sparc/kernel/rtrap_64.S +@@ -14,10 +14,6 @@ + #include + #include + +-#define RTRAP_PSTATE (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV|PSTATE_IE) +-#define RTRAP_PSTATE_IRQOFF (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV) +-#define RTRAP_PSTATE_AG_IRQOFF (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV|PSTATE_AG) +- + #ifdef CONFIG_CONTEXT_TRACKING + # define SCHEDULE_USER schedule_user + #else +@@ -242,52 +238,17 @@ rt_continue: ldx [%sp + PTREGS_OFF + P + wrpr %g1, %cwp + ba,a,pt %xcc, user_rtt_fill_64bit + +-user_rtt_fill_fixup: +- rdpr %cwp, %g1 +- add %g1, 1, %g1 +- wrpr %g1, 0x0, %cwp +- +- rdpr %wstate, %g2 +- sll %g2, 3, %g2 +- wrpr %g2, 0x0, %wstate +- +- /* We know %canrestore and %otherwin are both zero. */ +- +- sethi %hi(sparc64_kern_pri_context), %g2 +- ldx [%g2 + %lo(sparc64_kern_pri_context)], %g2 +- mov PRIMARY_CONTEXT, %g1 +- +-661: stxa %g2, [%g1] ASI_DMMU +- .section .sun4v_1insn_patch, "ax" +- .word 661b +- stxa %g2, [%g1] ASI_MMU +- .previous +- +- sethi %hi(KERNBASE), %g1 +- flush %g1 ++user_rtt_fill_fixup_dax: ++ ba,pt %xcc, user_rtt_fill_fixup_common ++ mov 1, %g3 ++ ++user_rtt_fill_fixup_mna: ++ ba,pt %xcc, user_rtt_fill_fixup_common ++ mov 2, %g3 + +- or %g4, FAULT_CODE_WINFIXUP, %g4 +- stb %g4, [%g6 + TI_FAULT_CODE] +- stx %g5, [%g6 + TI_FAULT_ADDR] +- +- mov %g6, %l1 +- wrpr %g0, 0x0, %tl +- +-661: nop +- .section .sun4v_1insn_patch, "ax" +- .word 661b +- SET_GL(0) +- .previous +- +- wrpr %g0, RTRAP_PSTATE, %pstate +- +- mov %l1, %g6 +- ldx [%g6 + TI_TASK], %g4 +- LOAD_PER_CPU_BASE(%g5, %g6, %g1, %g2, %g3) +- call do_sparc64_fault +- add %sp, PTREGS_OFF, %o0 +- ba,pt %xcc, rtrap +- nop ++user_rtt_fill_fixup: ++ ba,pt %xcc, user_rtt_fill_fixup_common ++ clr %g3 + + user_rtt_pre_restore: + add %g1, 1, %g1 +--- /dev/null ++++ b/arch/sparc/kernel/urtt_fill.S +@@ -0,0 +1,98 @@ ++#include ++#include ++#include ++#include ++#include ++ ++ .text ++ .align 8 ++ .globl user_rtt_fill_fixup_common ++user_rtt_fill_fixup_common: ++ rdpr %cwp, %g1 ++ add %g1, 1, %g1 ++ wrpr %g1, 0x0, %cwp ++ ++ rdpr %wstate, %g2 ++ sll %g2, 3, %g2 ++ wrpr %g2, 0x0, %wstate ++ ++ /* We know %canrestore and %otherwin are both zero. */ ++ ++ sethi %hi(sparc64_kern_pri_context), %g2 ++ ldx [%g2 + %lo(sparc64_kern_pri_context)], %g2 ++ mov PRIMARY_CONTEXT, %g1 ++ ++661: stxa %g2, [%g1] ASI_DMMU ++ .section .sun4v_1insn_patch, "ax" ++ .word 661b ++ stxa %g2, [%g1] ASI_MMU ++ .previous ++ ++ sethi %hi(KERNBASE), %g1 ++ flush %g1 ++ ++ mov %g4, %l4 ++ mov %g5, %l5 ++ brnz,pn %g3, 1f ++ mov %g3, %l3 ++ ++ or %g4, FAULT_CODE_WINFIXUP, %g4 ++ stb %g4, [%g6 + TI_FAULT_CODE] ++ stx %g5, [%g6 + TI_FAULT_ADDR] ++1: ++ mov %g6, %l1 ++ wrpr %g0, 0x0, %tl ++ ++661: nop ++ .section .sun4v_1insn_patch, "ax" ++ .word 661b ++ SET_GL(0) ++ .previous ++ ++ wrpr %g0, RTRAP_PSTATE, %pstate ++ ++ mov %l1, %g6 ++ ldx [%g6 + TI_TASK], %g4 ++ LOAD_PER_CPU_BASE(%g5, %g6, %g1, %g2, %g3) ++ ++ brnz,pn %l3, 1f ++ nop ++ ++ call do_sparc64_fault ++ add %sp, PTREGS_OFF, %o0 ++ ba,pt %xcc, rtrap ++ nop ++ ++1: cmp %g3, 2 ++ bne,pn %xcc, 2f ++ nop ++ ++ sethi %hi(tlb_type), %g1 ++ lduw [%g1 + %lo(tlb_type)], %g1 ++ cmp %g1, 3 ++ bne,pt %icc, 1f ++ add %sp, PTREGS_OFF, %o0 ++ mov %l4, %o2 ++ call sun4v_do_mna ++ mov %l5, %o1 ++ ba,a,pt %xcc, rtrap ++1: mov %l4, %o1 ++ mov %l5, %o2 ++ call mem_address_unaligned ++ nop ++ ba,a,pt %xcc, rtrap ++ ++2: sethi %hi(tlb_type), %g1 ++ mov %l4, %o1 ++ lduw [%g1 + %lo(tlb_type)], %g1 ++ mov %l5, %o2 ++ cmp %g1, 3 ++ bne,pt %icc, 1f ++ add %sp, PTREGS_OFF, %o0 ++ call sun4v_data_access_exception ++ nop ++ ba,a,pt %xcc, rtrap ++ ++1: call spitfire_data_access_exception ++ nop ++ ba,a,pt %xcc, rtrap diff --git a/queue-4.4/sparc64-fix-sparc64_set_context-stack-handling.patch b/queue-4.4/sparc64-fix-sparc64_set_context-stack-handling.patch new file mode 100644 index 00000000000..1f9ce6513f8 --- /dev/null +++ b/queue-4.4/sparc64-fix-sparc64_set_context-stack-handling.patch @@ -0,0 +1,30 @@ +From foo@baz Mon Jun 20 10:48:29 PDT 2016 +From: "David S. Miller" +Date: Tue, 1 Mar 2016 00:25:32 -0500 +Subject: sparc64: Fix sparc64_set_context stack handling. + +From: "David S. Miller" + +[ Upstream commit 397d1533b6cce0ccb5379542e2e6d079f6936c46 ] + +Like a signal return, we should use synchronize_user_stack() rather +than flush_user_windows(). + +Reported-by: Ilya Malakhov +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + arch/sparc/kernel/signal_64.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/sparc/kernel/signal_64.c ++++ b/arch/sparc/kernel/signal_64.c +@@ -52,7 +52,7 @@ asmlinkage void sparc64_set_context(stru + unsigned char fenab; + int err; + +- flush_user_windows(); ++ synchronize_user_stack(); + if (get_thread_wsaved() || + (((unsigned long)ucp) & (sizeof(unsigned long)-1)) || + (!__access_ok(ucp, sizeof(*ucp)))) diff --git a/queue-4.4/sparc64-reduce-tlb-flushes-during-hugepte-changes.patch b/queue-4.4/sparc64-reduce-tlb-flushes-during-hugepte-changes.patch new file mode 100644 index 00000000000..265751baae5 --- /dev/null +++ b/queue-4.4/sparc64-reduce-tlb-flushes-during-hugepte-changes.patch @@ -0,0 +1,349 @@ +From foo@baz Mon Jun 20 10:48:29 PDT 2016 +From: Nitin Gupta +Date: Wed, 30 Mar 2016 11:17:13 -0700 +Subject: sparc64: Reduce TLB flushes during hugepte changes + +From: Nitin Gupta + +[ Upstream commit 24e49ee3d76b70853a96520e46b8837e5eae65b2 ] + +During hugepage map/unmap, TSB and TLB flushes are currently +issued at every PAGE_SIZE'd boundary which is unnecessary. +We now issue the flush at REAL_HPAGE_SIZE boundaries only. + +Without this patch workloads which unmap a large hugepage +backed VMA region get CPU lockups due to excessive TLB +flush calls. + +Orabug: 22365539, 22643230, 22995196 + +Signed-off-by: Nitin Gupta +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + arch/sparc/include/asm/pgtable_64.h | 43 ++++++++++++++++++++++++++--------- + arch/sparc/include/asm/tlbflush_64.h | 3 +- + arch/sparc/mm/hugetlbpage.c | 33 ++++++++++++++++++++++---- + arch/sparc/mm/init_64.c | 12 --------- + arch/sparc/mm/tlb.c | 25 ++++++++++++++------ + arch/sparc/mm/tsb.c | 32 +++++++++++++------------- + 6 files changed, 97 insertions(+), 51 deletions(-) + +--- a/arch/sparc/include/asm/pgtable_64.h ++++ b/arch/sparc/include/asm/pgtable_64.h +@@ -375,7 +375,7 @@ static inline pgprot_t pgprot_noncached( + #define pgprot_noncached pgprot_noncached + + #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) +-static inline pte_t pte_mkhuge(pte_t pte) ++static inline unsigned long __pte_huge_mask(void) + { + unsigned long mask; + +@@ -390,8 +390,19 @@ static inline pte_t pte_mkhuge(pte_t pte + : "=r" (mask) + : "i" (_PAGE_SZHUGE_4U), "i" (_PAGE_SZHUGE_4V)); + +- return __pte(pte_val(pte) | mask); ++ return mask; ++} ++ ++static inline pte_t pte_mkhuge(pte_t pte) ++{ ++ return __pte(pte_val(pte) | __pte_huge_mask()); ++} ++ ++static inline bool is_hugetlb_pte(pte_t pte) ++{ ++ return !!(pte_val(pte) & __pte_huge_mask()); + } ++ + #ifdef CONFIG_TRANSPARENT_HUGEPAGE + static inline pmd_t pmd_mkhuge(pmd_t pmd) + { +@@ -403,6 +414,11 @@ static inline pmd_t pmd_mkhuge(pmd_t pmd + return __pmd(pte_val(pte)); + } + #endif ++#else ++static inline bool is_hugetlb_pte(pte_t pte) ++{ ++ return false; ++} + #endif + + static inline pte_t pte_mkdirty(pte_t pte) +@@ -865,6 +881,19 @@ static inline unsigned long pud_pfn(pud_ + void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, + pte_t *ptep, pte_t orig, int fullmm); + ++static void maybe_tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, ++ pte_t *ptep, pte_t orig, int fullmm) ++{ ++ /* It is more efficient to let flush_tlb_kernel_range() ++ * handle init_mm tlb flushes. ++ * ++ * SUN4V NOTE: _PAGE_VALID is the same value in both the SUN4U ++ * and SUN4V pte layout, so this inline test is fine. ++ */ ++ if (likely(mm != &init_mm) && pte_accessible(mm, orig)) ++ tlb_batch_add(mm, vaddr, ptep, orig, fullmm); ++} ++ + #define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR + static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm, + unsigned long addr, +@@ -881,15 +910,7 @@ static inline void __set_pte_at(struct m + pte_t orig = *ptep; + + *ptep = pte; +- +- /* It is more efficient to let flush_tlb_kernel_range() +- * handle init_mm tlb flushes. +- * +- * SUN4V NOTE: _PAGE_VALID is the same value in both the SUN4U +- * and SUN4V pte layout, so this inline test is fine. +- */ +- if (likely(mm != &init_mm) && pte_accessible(mm, orig)) +- tlb_batch_add(mm, addr, ptep, orig, fullmm); ++ maybe_tlb_batch_add(mm, addr, ptep, orig, fullmm); + } + + #define set_pte_at(mm,addr,ptep,pte) \ +--- a/arch/sparc/include/asm/tlbflush_64.h ++++ b/arch/sparc/include/asm/tlbflush_64.h +@@ -8,6 +8,7 @@ + #define TLB_BATCH_NR 192 + + struct tlb_batch { ++ bool huge; + struct mm_struct *mm; + unsigned long tlb_nr; + unsigned long active; +@@ -16,7 +17,7 @@ struct tlb_batch { + + void flush_tsb_kernel_range(unsigned long start, unsigned long end); + void flush_tsb_user(struct tlb_batch *tb); +-void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr); ++void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr, bool huge); + + /* TLB flush operations. */ + +--- a/arch/sparc/mm/hugetlbpage.c ++++ b/arch/sparc/mm/hugetlbpage.c +@@ -176,17 +176,31 @@ void set_huge_pte_at(struct mm_struct *m + pte_t *ptep, pte_t entry) + { + int i; ++ pte_t orig[2]; ++ unsigned long nptes; + + if (!pte_present(*ptep) && pte_present(entry)) + mm->context.huge_pte_count++; + + addr &= HPAGE_MASK; +- for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { +- set_pte_at(mm, addr, ptep, entry); ++ ++ nptes = 1 << HUGETLB_PAGE_ORDER; ++ orig[0] = *ptep; ++ orig[1] = *(ptep + nptes / 2); ++ for (i = 0; i < nptes; i++) { ++ *ptep = entry; + ptep++; + addr += PAGE_SIZE; + pte_val(entry) += PAGE_SIZE; + } ++ ++ /* Issue TLB flush at REAL_HPAGE_SIZE boundaries */ ++ addr -= REAL_HPAGE_SIZE; ++ ptep -= nptes / 2; ++ maybe_tlb_batch_add(mm, addr, ptep, orig[1], 0); ++ addr -= REAL_HPAGE_SIZE; ++ ptep -= nptes / 2; ++ maybe_tlb_batch_add(mm, addr, ptep, orig[0], 0); + } + + pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, +@@ -194,19 +208,28 @@ pte_t huge_ptep_get_and_clear(struct mm_ + { + pte_t entry; + int i; ++ unsigned long nptes; + + entry = *ptep; + if (pte_present(entry)) + mm->context.huge_pte_count--; + + addr &= HPAGE_MASK; +- +- for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { +- pte_clear(mm, addr, ptep); ++ nptes = 1 << HUGETLB_PAGE_ORDER; ++ for (i = 0; i < nptes; i++) { ++ *ptep = __pte(0UL); + addr += PAGE_SIZE; + ptep++; + } + ++ /* Issue TLB flush at REAL_HPAGE_SIZE boundaries */ ++ addr -= REAL_HPAGE_SIZE; ++ ptep -= nptes / 2; ++ maybe_tlb_batch_add(mm, addr, ptep, entry, 0); ++ addr -= REAL_HPAGE_SIZE; ++ ptep -= nptes / 2; ++ maybe_tlb_batch_add(mm, addr, ptep, entry, 0); ++ + return entry; + } + +--- a/arch/sparc/mm/init_64.c ++++ b/arch/sparc/mm/init_64.c +@@ -324,18 +324,6 @@ static void __update_mmu_tsb_insert(stru + tsb_insert(tsb, tag, tte); + } + +-#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) +-static inline bool is_hugetlb_pte(pte_t pte) +-{ +- if ((tlb_type == hypervisor && +- (pte_val(pte) & _PAGE_SZALL_4V) == _PAGE_SZHUGE_4V) || +- (tlb_type != hypervisor && +- (pte_val(pte) & _PAGE_SZALL_4U) == _PAGE_SZHUGE_4U)) +- return true; +- return false; +-} +-#endif +- + void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) + { + struct mm_struct *mm; +--- a/arch/sparc/mm/tlb.c ++++ b/arch/sparc/mm/tlb.c +@@ -67,7 +67,7 @@ void arch_leave_lazy_mmu_mode(void) + } + + static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr, +- bool exec) ++ bool exec, bool huge) + { + struct tlb_batch *tb = &get_cpu_var(tlb_batch); + unsigned long nr; +@@ -84,13 +84,21 @@ static void tlb_batch_add_one(struct mm_ + } + + if (!tb->active) { +- flush_tsb_user_page(mm, vaddr); ++ flush_tsb_user_page(mm, vaddr, huge); + global_flush_tlb_page(mm, vaddr); + goto out; + } + +- if (nr == 0) ++ if (nr == 0) { + tb->mm = mm; ++ tb->huge = huge; ++ } ++ ++ if (tb->huge != huge) { ++ flush_tlb_pending(); ++ tb->huge = huge; ++ nr = 0; ++ } + + tb->vaddrs[nr] = vaddr; + tb->tlb_nr = ++nr; +@@ -104,6 +112,8 @@ out: + void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, + pte_t *ptep, pte_t orig, int fullmm) + { ++ bool huge = is_hugetlb_pte(orig); ++ + if (tlb_type != hypervisor && + pte_dirty(orig)) { + unsigned long paddr, pfn = pte_pfn(orig); +@@ -129,7 +139,7 @@ void tlb_batch_add(struct mm_struct *mm, + + no_cache_flush: + if (!fullmm) +- tlb_batch_add_one(mm, vaddr, pte_exec(orig)); ++ tlb_batch_add_one(mm, vaddr, pte_exec(orig), huge); + } + + #ifdef CONFIG_TRANSPARENT_HUGEPAGE +@@ -145,7 +155,7 @@ static void tlb_batch_pmd_scan(struct mm + if (pte_val(*pte) & _PAGE_VALID) { + bool exec = pte_exec(*pte); + +- tlb_batch_add_one(mm, vaddr, exec); ++ tlb_batch_add_one(mm, vaddr, exec, false); + } + pte++; + vaddr += PAGE_SIZE; +@@ -185,8 +195,9 @@ void set_pmd_at(struct mm_struct *mm, un + pte_t orig_pte = __pte(pmd_val(orig)); + bool exec = pte_exec(orig_pte); + +- tlb_batch_add_one(mm, addr, exec); +- tlb_batch_add_one(mm, addr + REAL_HPAGE_SIZE, exec); ++ tlb_batch_add_one(mm, addr, exec, true); ++ tlb_batch_add_one(mm, addr + REAL_HPAGE_SIZE, exec, ++ true); + } else { + tlb_batch_pmd_scan(mm, addr, orig); + } +--- a/arch/sparc/mm/tsb.c ++++ b/arch/sparc/mm/tsb.c +@@ -76,14 +76,15 @@ void flush_tsb_user(struct tlb_batch *tb + + spin_lock_irqsave(&mm->context.lock, flags); + +- base = (unsigned long) mm->context.tsb_block[MM_TSB_BASE].tsb; +- nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries; +- if (tlb_type == cheetah_plus || tlb_type == hypervisor) +- base = __pa(base); +- __flush_tsb_one(tb, PAGE_SHIFT, base, nentries); +- ++ if (!tb->huge) { ++ base = (unsigned long) mm->context.tsb_block[MM_TSB_BASE].tsb; ++ nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries; ++ if (tlb_type == cheetah_plus || tlb_type == hypervisor) ++ base = __pa(base); ++ __flush_tsb_one(tb, PAGE_SHIFT, base, nentries); ++ } + #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) +- if (mm->context.tsb_block[MM_TSB_HUGE].tsb) { ++ if (tb->huge && mm->context.tsb_block[MM_TSB_HUGE].tsb) { + base = (unsigned long) mm->context.tsb_block[MM_TSB_HUGE].tsb; + nentries = mm->context.tsb_block[MM_TSB_HUGE].tsb_nentries; + if (tlb_type == cheetah_plus || tlb_type == hypervisor) +@@ -94,20 +95,21 @@ void flush_tsb_user(struct tlb_batch *tb + spin_unlock_irqrestore(&mm->context.lock, flags); + } + +-void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr) ++void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr, bool huge) + { + unsigned long nentries, base, flags; + + spin_lock_irqsave(&mm->context.lock, flags); + +- base = (unsigned long) mm->context.tsb_block[MM_TSB_BASE].tsb; +- nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries; +- if (tlb_type == cheetah_plus || tlb_type == hypervisor) +- base = __pa(base); +- __flush_tsb_one_entry(base, vaddr, PAGE_SHIFT, nentries); +- ++ if (!huge) { ++ base = (unsigned long) mm->context.tsb_block[MM_TSB_BASE].tsb; ++ nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries; ++ if (tlb_type == cheetah_plus || tlb_type == hypervisor) ++ base = __pa(base); ++ __flush_tsb_one_entry(base, vaddr, PAGE_SHIFT, nentries); ++ } + #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) +- if (mm->context.tsb_block[MM_TSB_HUGE].tsb) { ++ if (huge && mm->context.tsb_block[MM_TSB_HUGE].tsb) { + base = (unsigned long) mm->context.tsb_block[MM_TSB_HUGE].tsb; + nentries = mm->context.tsb_block[MM_TSB_HUGE].tsb_nentries; + if (tlb_type == cheetah_plus || tlb_type == hypervisor) diff --git a/queue-4.4/sparc64-take-ctx_alloc_lock-properly-in-hugetlb_setup.patch b/queue-4.4/sparc64-take-ctx_alloc_lock-properly-in-hugetlb_setup.patch new file mode 100644 index 00000000000..cf47ddb4ad3 --- /dev/null +++ b/queue-4.4/sparc64-take-ctx_alloc_lock-properly-in-hugetlb_setup.patch @@ -0,0 +1,54 @@ +From foo@baz Mon Jun 20 10:48:29 PDT 2016 +From: "David S. Miller" +Date: Wed, 25 May 2016 12:51:20 -0700 +Subject: sparc64: Take ctx_alloc_lock properly in hugetlb_setup(). + +From: "David S. Miller" + +[ Upstream commit 9ea46abe22550e3366ff7cee2f8391b35b12f730 ] + +On cheetahplus chips we take the ctx_alloc_lock in order to +modify the TLB lookup parameters for the indexed TLBs, which +are stored in the context register. + +This is called with interrupts disabled, however ctx_alloc_lock +is an IRQ safe lock, therefore we must take acquire/release it +properly with spin_{lock,unlock}_irq(). + +Reported-by: Meelis Roos +Tested-by: Meelis Roos +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + arch/sparc/mm/init_64.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +--- a/arch/sparc/mm/init_64.c ++++ b/arch/sparc/mm/init_64.c +@@ -2821,9 +2821,10 @@ void hugetlb_setup(struct pt_regs *regs) + * the Data-TLB for huge pages. + */ + if (tlb_type == cheetah_plus) { ++ bool need_context_reload = false; + unsigned long ctx; + +- spin_lock(&ctx_alloc_lock); ++ spin_lock_irq(&ctx_alloc_lock); + ctx = mm->context.sparc64_ctx_val; + ctx &= ~CTX_PGSZ_MASK; + ctx |= CTX_PGSZ_BASE << CTX_PGSZ0_SHIFT; +@@ -2842,9 +2843,12 @@ void hugetlb_setup(struct pt_regs *regs) + * also executing in this address space. + */ + mm->context.sparc64_ctx_val = ctx; +- on_each_cpu(context_reload, mm, 0); ++ need_context_reload = true; + } +- spin_unlock(&ctx_alloc_lock); ++ spin_unlock_irq(&ctx_alloc_lock); ++ ++ if (need_context_reload) ++ on_each_cpu(context_reload, mm, 0); + } + } + #endif