From 6a8a5051130fd2e2b5f978a5a2e222fcc7d2dff4 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Wed, 25 Jun 2014 09:53:21 -0400 Subject: MIPS: ftrace: Add call to ftrace_graph_is_dead() in function graph code ftrace_stop() is going away as it disables parts of function tracing that affects users that should not be affected. But ftrace_graph_stop() is built on ftrace_stop(). Here's another example of killing all of function tracing because something went wrong with function graph tracing. Instead of disabling all users of function tracing on function graph error, disable only function graph tracing. To do this, the arch code must call ftrace_graph_is_dead() before it implements function graph. Cc: Ralf Baechle Tested-by: James Hogan Signed-off-by: Steven Rostedt --- arch/mips/kernel/ftrace.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c index 60e7e5e45af1..8b6538750fe1 100644 --- a/arch/mips/kernel/ftrace.c +++ b/arch/mips/kernel/ftrace.c @@ -302,6 +302,9 @@ void prepare_ftrace_return(unsigned long *parent_ra_addr, unsigned long self_ra, &return_to_handler; int faulted, insns; + if (unlikely(ftrace_graph_is_dead())) + return; + if (unlikely(atomic_read(¤t->tracing_graph_pause))) return; -- cgit v1.2.3 From 44304cfbcbb174057781e04a383180989d427ef8 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Wed, 25 Jun 2014 12:34:22 -0400 Subject: MIPS: ftrace: Remove check of obsolete variable function_trace_stop Nothing sets function_trace_stop to disable function tracing anymore. Remove the check for it in the arch code. Cc: Ralf Baechle Tested-by: James Hogan Signed-off-by: Steven Rostedt --- arch/mips/Kconfig | 1 - arch/mips/kernel/mcount.S | 7 ------- 2 files changed, 8 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 4e238e6e661c..10f270bd3e25 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -15,7 +15,6 @@ config MIPS select HAVE_BPF_JIT if !CPU_MICROMIPS select ARCH_HAVE_CUSTOM_GPIO_H select HAVE_FUNCTION_TRACER - select HAVE_FUNCTION_TRACE_MCOUNT_TEST select HAVE_DYNAMIC_FTRACE select HAVE_FTRACE_MCOUNT_RECORD select HAVE_C_RECORDMCOUNT diff --git a/arch/mips/kernel/mcount.S b/arch/mips/kernel/mcount.S index 539b6294b613..00940d1d5c4f 100644 --- a/arch/mips/kernel/mcount.S +++ b/arch/mips/kernel/mcount.S @@ -74,10 +74,6 @@ _mcount: #endif /* When tracing is activated, it calls ftrace_caller+8 (aka here) */ - lw t1, function_trace_stop - bnez t1, ftrace_stub - nop - MCOUNT_SAVE_REGS #ifdef KBUILD_MCOUNT_RA_ADDRESS PTR_S MCOUNT_RA_ADDRESS_REG, PT_R12(sp) @@ -105,9 +101,6 @@ ftrace_stub: #else /* ! CONFIG_DYNAMIC_FTRACE */ NESTED(_mcount, PT_SIZE, ra) - lw t1, function_trace_stop - bnez t1, ftrace_stub - nop PTR_LA t1, ftrace_stub PTR_L t2, ftrace_trace_function /* Prepare t2 for (1) */ bne t1, t2, static_trace -- cgit v1.2.3 From b1442d39fac2fcfbe6a4814979020e993ca59c9e Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 22 Jul 2014 14:21:21 +0100 Subject: MIPS: Prevent user from setting FCSR cause bits If one or more matching FCSR cause & enable bits are set in saved thread context then when that context is restored the kernel will take an FP exception. This is of course undesirable and considered an oops, leading to the kernel writing a backtrace to the console and potentially rebooting depending upon the configuration. Thus the kernel avoids this situation by clearing the cause bits of the FCSR register when handling FP exceptions and after emulating FP instructions. However the kernel does not prevent userland from setting arbitrary FCSR cause & enable bits via ptrace, using either the PTRACE_POKEUSR or PTRACE_SETFPREGS requests. This means userland can trivially cause the kernel to oops on any system with an FPU. Prevent this from happening by clearing the cause bits when writing to the saved FCSR context via ptrace. This problem appears to exist at least back to the beginning of the git era in the PTRACE_POKEUSR case. Signed-off-by: Paul Burton Cc: stable@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: Paul Burton Cc: stable@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/7438/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/ptrace.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index f639ccd5060c..3a7f7dd610fd 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -151,6 +151,7 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data) } __get_user(child->thread.fpu.fcr31, data + 64); + child->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X; /* FIR may not be written. */ @@ -565,7 +566,7 @@ long arch_ptrace(struct task_struct *child, long request, break; #endif case FPC_CSR: - child->thread.fpu.fcr31 = data; + child->thread.fpu.fcr31 = data & ~FPU_CSR_ALL_X; break; case DSP_BASE ... DSP_BASE + 5: { dspreg_t *dregs; -- cgit v1.2.3 From dce0e7d54a710400c0056d86d0f0ed972133b25d Mon Sep 17 00:00:00 2001 From: Petri Gynther Date: Wed, 23 Jul 2014 22:55:02 -0700 Subject: MIPS: ftrace: Fix dynamic tracing of kernel modules Dynamic tracing of kernel modules is broken on 32-bit MIPS. When modules are loaded, the kernel crashes when dynamic tracing is enabled with: cd /sys/kernel/debug/tracing echo > set_ftrace_filter echo function > current_tracer 1) arch/mips/kernel/ftrace.c When the kernel boots, or when a module is initialized, ftrace_make_nop() modifies every _mcount call site to eliminate the ftrace overhead. However, when ftrace is later enabled for a call site, ftrace_make_call() does not currently restore the _mcount call correctly for module call sites. Added ftrace_modify_code_2r() and modified ftrace_make_call() to fix this. 2) arch/mips/kernel/mcount.S _mcount assembly routine is supposed to have the caller's _mcount call site address in register a0. However, a0 is currently not calculated correctly for module call sites. a0 should be (ra - 20) or (ra - 24), depending on whether the kernel was built with KBUILD_MCOUNT_RA_ADDRESS or not. This fix has been tested on Broadcom BMIPS5000 processor. Dynamic tracing now works for both built-in functions and module functions. Signed-off-by: Petri Gynther Cc: linux-mips@linux-mips.org Cc: rostedt@goodmis.org Cc: alcooperx@gmail.com Cc: cminyard@mvista.com Patchwork: https://patchwork.linux-mips.org/patch/7476/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/ftrace.c | 56 +++++++++++++++++++++++++++++++++++++++-------- arch/mips/kernel/mcount.S | 13 +++++++++++ 2 files changed, 60 insertions(+), 9 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c index 60e7e5e45af1..2a72208e319c 100644 --- a/arch/mips/kernel/ftrace.c +++ b/arch/mips/kernel/ftrace.c @@ -63,7 +63,7 @@ static inline int in_kernel_space(unsigned long ip) ((unsigned int)(JAL | (((addr) >> 2) & ADDR_MASK))) static unsigned int insn_jal_ftrace_caller __read_mostly; -static unsigned int insn_lui_v1_hi16_mcount __read_mostly; +static unsigned int insn_la_mcount[2] __read_mostly; static unsigned int insn_j_ftrace_graph_caller __maybe_unused __read_mostly; static inline void ftrace_dyn_arch_init_insns(void) @@ -71,10 +71,10 @@ static inline void ftrace_dyn_arch_init_insns(void) u32 *buf; unsigned int v1; - /* lui v1, hi16_mcount */ + /* la v1, _mcount */ v1 = 3; - buf = (u32 *)&insn_lui_v1_hi16_mcount; - UASM_i_LA_mostly(&buf, v1, MCOUNT_ADDR); + buf = (u32 *)&insn_la_mcount[0]; + UASM_i_LA(&buf, v1, MCOUNT_ADDR); /* jal (ftrace_caller + 8), jump over the first two instruction */ buf = (u32 *)&insn_jal_ftrace_caller; @@ -111,14 +111,47 @@ static int ftrace_modify_code_2(unsigned long ip, unsigned int new_code1, unsigned int new_code2) { int faulted; + mm_segment_t old_fs; safe_store_code(new_code1, ip, faulted); if (unlikely(faulted)) return -EFAULT; - safe_store_code(new_code2, ip + 4, faulted); + + ip += 4; + safe_store_code(new_code2, ip, faulted); if (unlikely(faulted)) return -EFAULT; + + ip -= 4; + old_fs = get_fs(); + set_fs(get_ds()); flush_icache_range(ip, ip + 8); + set_fs(old_fs); + + return 0; +} + +static int ftrace_modify_code_2r(unsigned long ip, unsigned int new_code1, + unsigned int new_code2) +{ + int faulted; + mm_segment_t old_fs; + + ip += 4; + safe_store_code(new_code2, ip, faulted); + if (unlikely(faulted)) + return -EFAULT; + + ip -= 4; + safe_store_code(new_code1, ip, faulted); + if (unlikely(faulted)) + return -EFAULT; + + old_fs = get_fs(); + set_fs(get_ds()); + flush_icache_range(ip, ip + 8); + set_fs(old_fs); + return 0; } #endif @@ -130,13 +163,14 @@ static int ftrace_modify_code_2(unsigned long ip, unsigned int new_code1, * * move at, ra * jal _mcount --> nop + * sub sp, sp, 8 --> nop (CONFIG_32BIT) * * 2. For modules: * * 2.1 For KBUILD_MCOUNT_RA_ADDRESS and CONFIG_32BIT * * lui v1, hi_16bit_of_mcount --> b 1f (0x10000005) - * addiu v1, v1, low_16bit_of_mcount + * addiu v1, v1, low_16bit_of_mcount --> nop (CONFIG_32BIT) * move at, ra * move $12, ra_address * jalr v1 @@ -145,7 +179,7 @@ static int ftrace_modify_code_2(unsigned long ip, unsigned int new_code1, * 2.2 For the Other situations * * lui v1, hi_16bit_of_mcount --> b 1f (0x10000004) - * addiu v1, v1, low_16bit_of_mcount + * addiu v1, v1, low_16bit_of_mcount --> nop (CONFIG_32BIT) * move at, ra * jalr v1 * nop | move $12, ra_address | sub sp, sp, 8 @@ -184,10 +218,14 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) unsigned int new; unsigned long ip = rec->ip; - new = in_kernel_space(ip) ? insn_jal_ftrace_caller : - insn_lui_v1_hi16_mcount; + new = in_kernel_space(ip) ? insn_jal_ftrace_caller : insn_la_mcount[0]; +#ifdef CONFIG_64BIT return ftrace_modify_code(ip, new); +#else + return ftrace_modify_code_2r(ip, new, in_kernel_space(ip) ? + INSN_NOP : insn_la_mcount[1]); +#endif } #define FTRACE_CALL_IP ((unsigned long)(&ftrace_call)) diff --git a/arch/mips/kernel/mcount.S b/arch/mips/kernel/mcount.S index 539b6294b613..26ceb3c0eca9 100644 --- a/arch/mips/kernel/mcount.S +++ b/arch/mips/kernel/mcount.S @@ -84,6 +84,19 @@ _mcount: #endif PTR_SUBU a0, ra, 8 /* arg1: self address */ + PTR_LA t1, _stext + sltu t2, a0, t1 /* t2 = (a0 < _stext) */ + PTR_LA t1, _etext + sltu t3, t1, a0 /* t3 = (a0 > _etext) */ + or t1, t2, t3 + beqz t1, ftrace_call + nop +#if defined(KBUILD_MCOUNT_RA_ADDRESS) && defined(CONFIG_32BIT) + PTR_SUBU a0, a0, 16 /* arg1: adjust to module's recorded callsite */ +#else + PTR_SUBU a0, a0, 12 +#endif + .globl ftrace_call ftrace_call: nop /* a placeholder for the call to a real tracing function */ -- cgit v1.2.3 From 064231e548d0ef90453081f424ced7b3ffffffe9 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 9 Jul 2014 12:48:18 +0100 Subject: MIPS: pm-cps: Prevent use of mips_cps_* without CPS SMP These symbols will not be defined when CONFIG_MIPS_CPS=n, but although the CPS_PM_POWER_GATED state will never be used in that case the compiler doesn't have enough information to figure that out. Add checks which evaluate to a constant false for CONFIG_MIPS_CPS=n cases in order to help the compiler out & eliminate the symbol references. Signed-off-by: Paul Burton Reviewed-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7278/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/smp-cps.h | 12 ++++++++++-- arch/mips/kernel/pm-cps.c | 8 ++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/include/asm/smp-cps.h b/arch/mips/include/asm/smp-cps.h index a06a08a9afc6..326c16ebd589 100644 --- a/arch/mips/include/asm/smp-cps.h +++ b/arch/mips/include/asm/smp-cps.h @@ -31,11 +31,19 @@ extern void mips_cps_core_init(void); extern struct vpe_boot_config *mips_cps_boot_vpes(void); -extern bool mips_cps_smp_in_use(void); - extern void mips_cps_pm_save(void); extern void mips_cps_pm_restore(void); +#ifdef CONFIG_MIPS_CPS + +extern bool mips_cps_smp_in_use(void); + +#else /* !CONFIG_MIPS_CPS */ + +static inline bool mips_cps_smp_in_use(void) { return false; } + +#endif /* !CONFIG_MIPS_CPS */ + #else /* __ASSEMBLY__ */ .extern mips_cps_bootcfg; diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c index c4c2069d3a20..c409a5aef8ab 100644 --- a/arch/mips/kernel/pm-cps.c +++ b/arch/mips/kernel/pm-cps.c @@ -149,6 +149,10 @@ int cps_pm_enter_state(enum cps_pm_state state) /* Setup the VPE to run mips_cps_pm_restore when started again */ if (config_enabled(CONFIG_CPU_PM) && state == CPS_PM_POWER_GATED) { + /* Power gating relies upon CPS SMP */ + if (!mips_cps_smp_in_use()) + return -EINVAL; + core_cfg = &mips_cps_core_bootcfg[core]; vpe_cfg = &core_cfg->vpe_config[current_cpu_data.vpe_id]; vpe_cfg->pc = (unsigned long)mips_cps_pm_restore; @@ -376,6 +380,10 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) memset(relocs, 0, sizeof(relocs)); if (config_enabled(CONFIG_CPU_PM) && state == CPS_PM_POWER_GATED) { + /* Power gating relies upon CPS SMP */ + if (!mips_cps_smp_in_use()) + goto out_err; + /* * Save CPU state. Note the non-standard calling convention * with the return address placed in v0 to avoid clobbering -- cgit v1.2.3 From c90e49f26466d1733558b8385f4755a6ee3ddafc Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 9 Jul 2014 12:48:21 +0100 Subject: MIPS: {pm,smp}-cps: use cpu_vpe_id macro When determining the VPE ID of a CPU, make use of the cpu_vpe_id macro which will return 0 in a non-MT kernel build. Most code is already doing so but a couple of places weren't. Fixing this prevents a build failure for non-MT kernels where struct cpuinfo_mips does not contain the vpe_id field: arch/mips/kernel/pm-cps.c: In function 'cps_pm_enter_state': arch/mips/kernel/pm-cps.c:153:51: error: 'struct cpuinfo_mips' has no member named 'vpe_id' vpe_cfg = &core_cfg->vpe_config[current_cpu_data.vpe_id]; arch/mips/kernel/smp-cps.c: In function 'wait_for_sibling_halt': arch/mips/kernel/smp-cps.c:363:33: error: 'struct cpuinfo_mips' has no member named 'vpe_id' unsigned vpe_id = cpu_data[cpu].vpe_id; Signed-off-by: Paul Burton Reviewed-by: Markos Chandras Signed-off-by: Ralf Baechle --- arch/mips/kernel/pm-cps.c | 2 +- arch/mips/kernel/smp-cps.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c index c409a5aef8ab..06147179a175 100644 --- a/arch/mips/kernel/pm-cps.c +++ b/arch/mips/kernel/pm-cps.c @@ -154,7 +154,7 @@ int cps_pm_enter_state(enum cps_pm_state state) return -EINVAL; core_cfg = &mips_cps_core_bootcfg[core]; - vpe_cfg = &core_cfg->vpe_config[current_cpu_data.vpe_id]; + vpe_cfg = &core_cfg->vpe_config[cpu_vpe_id(¤t_cpu_data)]; vpe_cfg->pc = (unsigned long)mips_cps_pm_restore; vpe_cfg->gp = (unsigned long)current_thread_info(); vpe_cfg->sp = 0; diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index 949f2c6827a0..f9b53b4eaccb 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -360,7 +360,7 @@ void play_dead(void) static void wait_for_sibling_halt(void *ptr_cpu) { unsigned cpu = (unsigned)ptr_cpu; - unsigned vpe_id = cpu_data[cpu].vpe_id; + unsigned vpe_id = cpu_vpe_id(&cpu_data[cpu]); unsigned halted; unsigned long flags; -- cgit v1.2.3 From 0fc0708a8a2e6ff5e9ab633185903831fe478994 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 9 Jul 2014 12:51:05 +0100 Subject: MIPS: smp-cps: Fix entry code cache flush for systems with coherent I/O The dma_cache_wback_inv function performs exactly as is required here, unless the system has coherent I/O in which case it's a no-op. Call the underlying cache writeback functions directly, which is arguably clearer anyway given that the code doesn't actually have anything to do with DMA in a strict sense. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7282/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/smp-cps.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index f9b53b4eaccb..e6e16a1d4add 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -14,13 +14,14 @@ #include #include -#include +#include #include #include #include #include #include #include +#include #include #include #include @@ -132,8 +133,11 @@ static void __init cps_prepare_cpus(unsigned int max_cpus) entry_code = (u32 *)&mips_cps_core_entry; UASM_i_LA(&entry_code, 3, (long)mips_cm_base); uasm_i_addiu(&entry_code, 16, 0, cca); - dma_cache_wback_inv((unsigned long)&mips_cps_core_entry, - (void *)entry_code - (void *)&mips_cps_core_entry); + blast_dcache_range((unsigned long)&mips_cps_core_entry, + (unsigned long)entry_code); + bc_wback_inv((unsigned long)&mips_cps_core_entry, + (void *)entry_code - (void *)&mips_cps_core_entry); + __sync(); /* Allocate core boot configuration structs */ mips_cps_core_bootcfg = kcalloc(ncores, sizeof(*mips_cps_core_bootcfg), -- cgit v1.2.3 From 2e5767a27337812f6850b3fa362419e2f085e5c3 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Wed, 16 Jul 2014 09:19:16 +0800 Subject: MIPS: Remove BUG_ON(!is_fpu_owner()) in do_ade() In do_ade(), is_fpu_owner() isn't preempt-safe. For example, when an unaligned ldc1 is executed, do_cpu() is called and then FPU will be enabled (and TIF_USEDFPU will be set for the current process). Then, do_ade() is called because the access is unaligned. If the current process is preempted at this time, TIF_USEDFPU will be cleard. So when the process is scheduled again, BUG_ON(!is_fpu_owner()) is triggered. This small program can trigger this BUG in a preemptible kernel: int main (int argc, char *argv[]) { double u64[2]; while (1) { asm volatile ( ".set push \n\t" ".set noreorder \n\t" "ldc1 $f3, 4(%0) \n\t" ".set pop \n\t" ::"r"(u64): ); } return 0; } V2: Remove the BUG_ON() unconditionally due to Paul's suggestion. Signed-off-by: Huacai Chen Signed-off-by: Jie Chen Signed-off-by: Rui Wang Cc: Cc: John Crispin Cc: Steven J. Hill Cc: linux-mips@linux-mips.org Cc: Fuxin Zhang Cc: Zhangjin Wu Cc: stable@vger.kernel.org Signed-off-by: Ralf Baechle --- arch/mips/kernel/unaligned.c | 1 - 1 file changed, 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 2b3517214d6d..e11906dff885 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -690,7 +690,6 @@ static void emulate_load_store_insn(struct pt_regs *regs, case sdc1_op: die_if_kernel("Unaligned FP access in kernel code", regs); BUG_ON(!used_math()); - BUG_ON(!is_fpu_owner()); lose_fpu(1); /* Save FPU state for the emulator. */ res = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1, -- cgit v1.2.3 From 0f3f506b275517250ee0169ec075d5382967f5f6 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Thu, 26 Jun 2014 11:41:25 +0800 Subject: MIPS: Support hard limit of cpu count (nr_cpu_ids) On MIPS currently, only the soft limit of cpu count (maxcpus) has its effect, this patch enable the hard limit (nr_cpus) as well. Processor cores which greater than maxcpus and less than nr_cpus can be taken up via cpu hotplug. The code is borrowed from X86. Signed-off-by: Huacai Chen Reviewed-by: Andreas Herrmann Cc: John Crispin Cc: Steven J. Hill Cc: Aurelien Jarno Cc: linux-mips@linux-mips.org Cc: Fuxin Zhang Cc: Zhangjin Wu Patchwork: https://patchwork.linux-mips.org/patch/7183/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/setup.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index a842154d57dc..2f01201b158c 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -729,6 +729,25 @@ static void __init resource_init(void) } } +#ifdef CONFIG_SMP +static void __init prefill_possible_map(void) +{ + int i, possible = num_possible_cpus(); + + if (possible > nr_cpu_ids) + possible = nr_cpu_ids; + + for (i = 0; i < possible; i++) + set_cpu_possible(i, true); + for (; i < NR_CPUS; i++) + set_cpu_possible(i, false); + + nr_cpu_ids = possible; +} +#else +static inline void prefill_possible_map(void) {} +#endif + void __init setup_arch(char **cmdline_p) { cpu_probe(); @@ -752,6 +771,7 @@ void __init setup_arch(char **cmdline_p) resource_init(); plat_smp_setup(); + prefill_possible_map(); cpu_cache_init(); } -- cgit v1.2.3 From bda4584cd943d7bb6cf677a8d694700c1984cf3e Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Thu, 26 Jun 2014 11:41:26 +0800 Subject: MIPS: Support CPU topology files in sysfs This patch is prepared for Loongson's NUMA support, it offer meaningful sysfs files such as physical_package_id, core_id, core_siblings and thread_siblings in /sys/devices/system/cpu/cpu?/topology. Signed-off-by: Huacai Chen Reviewed-by: Andreas Herrmann Cc: John Crispin Cc: Steven J. Hill Cc: Aurelien Jarno Cc: linux-mips@linux-mips.org Cc: Fuxin Zhang Cc: Zhangjin Wu Patchwork: https://patchwork.linux-mips.org/patch/7184/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/cpu-info.h | 1 + arch/mips/include/asm/smp.h | 6 ++++++ arch/mips/kernel/proc.c | 1 + arch/mips/kernel/smp.c | 26 +++++++++++++++++++++++++- 4 files changed, 33 insertions(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/include/asm/cpu-info.h b/arch/mips/include/asm/cpu-info.h index a28e3de473d2..6690d7af0a03 100644 --- a/arch/mips/include/asm/cpu-info.h +++ b/arch/mips/include/asm/cpu-info.h @@ -61,6 +61,7 @@ struct cpuinfo_mips { struct cache_desc scache; /* Secondary cache */ struct cache_desc tcache; /* Tertiary/split secondary cache */ int srsets; /* Shadow register sets */ + int package;/* physical package number */ int core; /* physical core number */ #ifdef CONFIG_64BIT int vmbits; /* Virtual memory size in bits */ diff --git a/arch/mips/include/asm/smp.h b/arch/mips/include/asm/smp.h index b037334fca22..1e0f20a9cdda 100644 --- a/arch/mips/include/asm/smp.h +++ b/arch/mips/include/asm/smp.h @@ -22,6 +22,7 @@ extern int smp_num_siblings; extern cpumask_t cpu_sibling_map[]; +extern cpumask_t cpu_core_map[]; #define raw_smp_processor_id() (current_thread_info()->cpu) @@ -36,6 +37,11 @@ extern int __cpu_logical_map[NR_CPUS]; #define NO_PROC_ID (-1) +#define topology_physical_package_id(cpu) (cpu_data[cpu].package) +#define topology_core_id(cpu) (cpu_data[cpu].core) +#define topology_core_cpumask(cpu) (&cpu_core_map[cpu]) +#define topology_thread_cpumask(cpu) (&cpu_sibling_map[cpu]) + #define SMP_RESCHEDULE_YOURSELF 0x1 /* XXX braindead */ #define SMP_CALL_FUNCTION 0x2 /* Octeon - Tell another core to flush its icache */ diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 037a44d962f3..62c4439a147b 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -123,6 +123,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) cpu_data[n].srsets); seq_printf(m, "kscratch registers\t: %d\n", hweight8(cpu_data[n].kscratch_mask)); + seq_printf(m, "package\t\t\t: %d\n", cpu_data[n].package); seq_printf(m, "core\t\t\t: %d\n", cpu_data[n].core); sprintf(fmt, "VCE%%c exceptions\t\t: %s\n", diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 9bad52ede903..c94c4e92e17d 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -59,9 +59,16 @@ EXPORT_SYMBOL(smp_num_siblings); cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly; EXPORT_SYMBOL(cpu_sibling_map); +/* representing the core map of multi-core chips of each logical CPU */ +cpumask_t cpu_core_map[NR_CPUS] __read_mostly; +EXPORT_SYMBOL(cpu_core_map); + /* representing cpus for which sibling maps can be computed */ static cpumask_t cpu_sibling_setup_map; +/* representing cpus for which core maps can be computed */ +static cpumask_t cpu_core_setup_map; + cpumask_t cpu_coherent_mask; static inline void set_cpu_sibling_map(int cpu) @@ -72,7 +79,8 @@ static inline void set_cpu_sibling_map(int cpu) if (smp_num_siblings > 1) { for_each_cpu_mask(i, cpu_sibling_setup_map) { - if (cpu_data[cpu].core == cpu_data[i].core) { + if (cpu_data[cpu].package == cpu_data[i].package && + cpu_data[cpu].core == cpu_data[i].core) { cpu_set(i, cpu_sibling_map[cpu]); cpu_set(cpu, cpu_sibling_map[i]); } @@ -81,6 +89,20 @@ static inline void set_cpu_sibling_map(int cpu) cpu_set(cpu, cpu_sibling_map[cpu]); } +static inline void set_cpu_core_map(int cpu) +{ + int i; + + cpu_set(cpu, cpu_core_setup_map); + + for_each_cpu_mask(i, cpu_core_setup_map) { + if (cpu_data[cpu].package == cpu_data[i].package) { + cpu_set(i, cpu_core_map[cpu]); + cpu_set(cpu, cpu_core_map[i]); + } + } +} + struct plat_smp_ops *mp_ops; EXPORT_SYMBOL(mp_ops); @@ -122,6 +144,7 @@ asmlinkage void start_secondary(void) set_cpu_online(cpu, true); set_cpu_sibling_map(cpu); + set_cpu_core_map(cpu); cpu_set(cpu, cpu_callin_map); @@ -175,6 +198,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) current_thread_info()->cpu = 0; mp_ops->prepare_cpus(max_cpus); set_cpu_sibling_map(0); + set_cpu_core_map(0); #ifndef CONFIG_HOTPLUG_CPU init_cpu_present(cpu_possible_mask); #endif -- cgit v1.2.3 From c46173183657bbdbe0d54a981c28807581648422 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Thu, 26 Jun 2014 11:41:28 +0800 Subject: MIPS: Add NUMA support for Loongson-3 Multiple Loongson-3A chips can be interconnected with HT0-bus. This is a CC-NUMA system that every chip (node) has its own local memory and cache coherency is maintained by hardware. The 64-bit physical memory address format is as follows: 0x-0000-YZZZ-ZZZZ-ZZZZ The high 16 bits should be 0, which means the real physical address supported by Loongson-3 is 48-bit. The "Y" bits is the base address of each node, which can be also considered as the node-id. The "Z" bits is the address offset within a node, which means every node has a 44 bits address space. Macros XPHYSADDR and MAX_PHYSMEM_BITS are modified unconditionally, because many other MIPS CPUs have also extended their address spaces. Signed-off-by: Huacai Chen Cc: John Crispin Cc: Steven J. Hill Cc: Aurelien Jarno Cc: linux-mips@linux-mips.org Cc: Fuxin Zhang Cc: Zhangjin Wu Patchwork: https://patchwork.linux-mips.org/patch/7187/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/addrspace.h | 2 +- arch/mips/include/asm/mach-loongson/boot_param.h | 3 + .../include/asm/mach-loongson/kernel-entry-init.h | 52 ++++ arch/mips/include/asm/mach-loongson/mmzone.h | 53 ++++ arch/mips/include/asm/mach-loongson/topology.h | 23 ++ arch/mips/include/asm/sparsemem.h | 2 +- arch/mips/kernel/setup.c | 2 +- arch/mips/loongson/Kconfig | 1 + arch/mips/loongson/common/env.c | 7 + arch/mips/loongson/common/init.c | 4 + arch/mips/loongson/loongson-3/Makefile | 2 + arch/mips/loongson/loongson-3/numa.c | 291 +++++++++++++++++++++ arch/mips/loongson/loongson-3/smp.c | 8 +- 13 files changed, 445 insertions(+), 5 deletions(-) create mode 100644 arch/mips/include/asm/mach-loongson/kernel-entry-init.h create mode 100644 arch/mips/include/asm/mach-loongson/mmzone.h create mode 100644 arch/mips/include/asm/mach-loongson/topology.h create mode 100644 arch/mips/loongson/loongson-3/numa.c (limited to 'arch/mips/kernel') diff --git a/arch/mips/include/asm/addrspace.h b/arch/mips/include/asm/addrspace.h index 3f745459fdb5..3b0e51d5a613 100644 --- a/arch/mips/include/asm/addrspace.h +++ b/arch/mips/include/asm/addrspace.h @@ -52,7 +52,7 @@ */ #define CPHYSADDR(a) ((_ACAST32_(a)) & 0x1fffffff) #define XPHYSADDR(a) ((_ACAST64_(a)) & \ - _CONST64_(0x000000ffffffffff)) + _CONST64_(0x0000ffffffffffff)) #ifdef CONFIG_64BIT diff --git a/arch/mips/include/asm/mach-loongson/boot_param.h b/arch/mips/include/asm/mach-loongson/boot_param.h index 829a7ec185fb..8b06c96cce1f 100644 --- a/arch/mips/include/asm/mach-loongson/boot_param.h +++ b/arch/mips/include/asm/mach-loongson/boot_param.h @@ -146,6 +146,9 @@ struct boot_params { struct loongson_system_configuration { u32 nr_cpus; + u32 nr_nodes; + int cores_per_node; + int cores_per_package; enum loongson_cpu_type cputype; u64 ht_control_base; u64 pci_mem_start_addr; diff --git a/arch/mips/include/asm/mach-loongson/kernel-entry-init.h b/arch/mips/include/asm/mach-loongson/kernel-entry-init.h new file mode 100644 index 000000000000..df5fca8eeb80 --- /dev/null +++ b/arch/mips/include/asm/mach-loongson/kernel-entry-init.h @@ -0,0 +1,52 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2005 Embedded Alley Solutions, Inc + * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2009 Jiajie Chen (chenjiajie@cse.buaa.edu.cn) + * Copyright (C) 2012 Huacai Chen (chenhc@lemote.com) + */ +#ifndef __ASM_MACH_LOONGSON_KERNEL_ENTRY_H +#define __ASM_MACH_LOONGSON_KERNEL_ENTRY_H + +/* + * Override macros used in arch/mips/kernel/head.S. + */ + .macro kernel_entry_setup +#ifdef CONFIG_CPU_LOONGSON3 + .set push + .set mips64 + /* Set LPA on LOONGSON3 config3 */ + mfc0 t0, $16, 3 + or t0, (0x1 << 7) + mtc0 t0, $16, 3 + /* Set ELPA on LOONGSON3 pagegrain */ + li t0, (0x1 << 29) + mtc0 t0, $5, 1 + _ehb + .set pop +#endif + .endm + +/* + * Do SMP slave processor setup. + */ + .macro smp_slave_setup +#ifdef CONFIG_CPU_LOONGSON3 + .set push + .set mips64 + /* Set LPA on LOONGSON3 config3 */ + mfc0 t0, $16, 3 + or t0, (0x1 << 7) + mtc0 t0, $16, 3 + /* Set ELPA on LOONGSON3 pagegrain */ + li t0, (0x1 << 29) + mtc0 t0, $5, 1 + _ehb + .set pop +#endif + .endm + +#endif /* __ASM_MACH_LOONGSON_KERNEL_ENTRY_H */ diff --git a/arch/mips/include/asm/mach-loongson/mmzone.h b/arch/mips/include/asm/mach-loongson/mmzone.h new file mode 100644 index 000000000000..37c08a27b4f0 --- /dev/null +++ b/arch/mips/include/asm/mach-loongson/mmzone.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 Loongson Inc. & Lemote Inc. & + * Insititute of Computing Technology + * Author: Xiang Gao, gaoxiang@ict.ac.cn + * Huacai Chen, chenhc@lemote.com + * Xiaofu Meng, Shuangshuang Zhang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#ifndef _ASM_MACH_MMZONE_H +#define _ASM_MACH_MMZONE_H + +#include +#define NODE_ADDRSPACE_SHIFT 44 +#define NODE0_ADDRSPACE_OFFSET 0x000000000000UL +#define NODE1_ADDRSPACE_OFFSET 0x100000000000UL +#define NODE2_ADDRSPACE_OFFSET 0x200000000000UL +#define NODE3_ADDRSPACE_OFFSET 0x300000000000UL + +#define pa_to_nid(addr) (((addr) & 0xf00000000000) >> NODE_ADDRSPACE_SHIFT) + +#define LEVELS_PER_SLICE 128 + +struct slice_data { + unsigned long irq_enable_mask[2]; + int level_to_irq[LEVELS_PER_SLICE]; +}; + +struct hub_data { + cpumask_t h_cpus; + unsigned long slice_map; + unsigned long irq_alloc_mask[2]; + struct slice_data slice[2]; +}; + +struct node_data { + struct pglist_data pglist; + struct hub_data hub; + cpumask_t cpumask; +}; + +extern struct node_data *__node_data[]; + +#define NODE_DATA(n) (&__node_data[(n)]->pglist) +#define hub_data(n) (&__node_data[(n)]->hub) + +extern void setup_zero_pages(void); +extern void __init prom_init_numa_memory(void); + +#endif /* _ASM_MACH_MMZONE_H */ diff --git a/arch/mips/include/asm/mach-loongson/topology.h b/arch/mips/include/asm/mach-loongson/topology.h new file mode 100644 index 000000000000..5598ba77d2ef --- /dev/null +++ b/arch/mips/include/asm/mach-loongson/topology.h @@ -0,0 +1,23 @@ +#ifndef _ASM_MACH_TOPOLOGY_H +#define _ASM_MACH_TOPOLOGY_H + +#ifdef CONFIG_NUMA + +#define cpu_to_node(cpu) ((cpu) >> 2) +#define parent_node(node) (node) +#define cpumask_of_node(node) (&__node_data[(node)]->cpumask) + +struct pci_bus; +extern int pcibus_to_node(struct pci_bus *); + +#define cpumask_of_pcibus(bus) (cpu_online_mask) + +extern unsigned char __node_distances[MAX_NUMNODES][MAX_NUMNODES]; + +#define node_distance(from, to) (__node_distances[(from)][(to)]) + +#endif + +#include + +#endif /* _ASM_MACH_TOPOLOGY_H */ diff --git a/arch/mips/include/asm/sparsemem.h b/arch/mips/include/asm/sparsemem.h index d2da53c2c2f8..b1071c1e54f5 100644 --- a/arch/mips/include/asm/sparsemem.h +++ b/arch/mips/include/asm/sparsemem.h @@ -11,7 +11,7 @@ #else # define SECTION_SIZE_BITS 28 #endif -#define MAX_PHYSMEM_BITS 35 +#define MAX_PHYSMEM_BITS 48 #endif /* CONFIG_SPARSEMEM */ #endif /* _MIPS_SPARSEMEM_H */ diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 2f01201b158c..7c1fe2b42d40 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -282,7 +282,7 @@ static unsigned long __init init_initrd(void) * Initialize the bootmem allocator. It also setup initrd related data * if needed. */ -#ifdef CONFIG_SGI_IP27 +#if defined(CONFIG_SGI_IP27) || (defined(CONFIG_CPU_LOONGSON3) && defined(CONFIG_NUMA)) static void __init bootmem_init(void) { diff --git a/arch/mips/loongson/Kconfig b/arch/mips/loongson/Kconfig index e6a86ccc4421..a14a50d009d4 100644 --- a/arch/mips/loongson/Kconfig +++ b/arch/mips/loongson/Kconfig @@ -79,6 +79,7 @@ config LEMOTE_MACH3A select SYS_HAS_EARLY_PRINTK select SYS_SUPPORTS_SMP select SYS_SUPPORTS_HOTPLUG_CPU + select SYS_SUPPORTS_NUMA select SYS_SUPPORTS_64BIT_KERNEL select SYS_SUPPORTS_HIGHMEM select SYS_SUPPORTS_LITTLE_ENDIAN diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c index dc592412f764..33a13b9e436c 100644 --- a/arch/mips/loongson/common/env.c +++ b/arch/mips/loongson/common/env.c @@ -80,17 +80,24 @@ void __init prom_init_env(void) cpu_clock_freq = ecpu->cpu_clock_freq; loongson_sysconf.cputype = ecpu->cputype; if (ecpu->cputype == Loongson_3A) { + loongson_sysconf.cores_per_node = 4; + loongson_sysconf.cores_per_package = 4; loongson_chipcfg[0] = 0x900000001fe00180; loongson_chipcfg[1] = 0x900010001fe00180; loongson_chipcfg[2] = 0x900020001fe00180; loongson_chipcfg[3] = 0x900030001fe00180; } else { + loongson_sysconf.cores_per_node = 1; + loongson_sysconf.cores_per_package = 1; loongson_chipcfg[0] = 0x900000001fe00180; } loongson_sysconf.nr_cpus = ecpu->nr_cpus; if (ecpu->nr_cpus > NR_CPUS || ecpu->nr_cpus == 0) loongson_sysconf.nr_cpus = NR_CPUS; + loongson_sysconf.nr_nodes = (loongson_sysconf.nr_cpus + + loongson_sysconf.cores_per_node - 1) / + loongson_sysconf.cores_per_node; loongson_sysconf.pci_mem_start_addr = eirq_source->pci_mem_start_addr; loongson_sysconf.pci_mem_end_addr = eirq_source->pci_mem_end_addr; diff --git a/arch/mips/loongson/common/init.c b/arch/mips/loongson/common/init.c index f37fe5413b73..f6af3aba4c86 100644 --- a/arch/mips/loongson/common/init.c +++ b/arch/mips/loongson/common/init.c @@ -30,7 +30,11 @@ void __init prom_init(void) set_io_port_base((unsigned long) ioremap(LOONGSON_PCIIO_BASE, LOONGSON_PCIIO_SIZE)); +#ifdef CONFIG_NUMA + prom_init_numa_memory(); +#else prom_init_memory(); +#endif /*init the uart base address */ prom_init_uart_base(); diff --git a/arch/mips/loongson/loongson-3/Makefile b/arch/mips/loongson/loongson-3/Makefile index 70152b252ddc..471b0f2af079 100644 --- a/arch/mips/loongson/loongson-3/Makefile +++ b/arch/mips/loongson/loongson-3/Makefile @@ -4,3 +4,5 @@ obj-y += irq.o obj-$(CONFIG_SMP) += smp.o + +obj-$(CONFIG_NUMA) += numa.o diff --git a/arch/mips/loongson/loongson-3/numa.c b/arch/mips/loongson/loongson-3/numa.c new file mode 100644 index 000000000000..ca025a6ba559 --- /dev/null +++ b/arch/mips/loongson/loongson-3/numa.c @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2010 Loongson Inc. & Lemote Inc. & + * Insititute of Computing Technology + * Author: Xiang Gao, gaoxiang@ict.ac.cn + * Huacai Chen, chenhc@lemote.com + * Xiaofu Meng, Shuangshuang Zhang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct node_data prealloc__node_data[MAX_NUMNODES]; +unsigned char __node_distances[MAX_NUMNODES][MAX_NUMNODES]; +struct node_data *__node_data[MAX_NUMNODES]; +EXPORT_SYMBOL(__node_data); + +static void enable_lpa(void) +{ + unsigned long value; + + value = __read_32bit_c0_register($16, 3); + value |= 0x00000080; + __write_32bit_c0_register($16, 3, value); + value = __read_32bit_c0_register($16, 3); + pr_info("CP0_Config3: CP0 16.3 (0x%lx)\n", value); + + value = __read_32bit_c0_register($5, 1); + value |= 0x20000000; + __write_32bit_c0_register($5, 1, value); + value = __read_32bit_c0_register($5, 1); + pr_info("CP0_PageGrain: CP0 5.1 (0x%lx)\n", value); +} + +static void cpu_node_probe(void) +{ + int i; + + nodes_clear(node_possible_map); + nodes_clear(node_online_map); + for (i = 0; i < loongson_sysconf.nr_nodes; i++) { + node_set_state(num_online_nodes(), N_POSSIBLE); + node_set_online(num_online_nodes()); + } + + pr_info("NUMA: Discovered %d cpus on %d nodes\n", + loongson_sysconf.nr_cpus, num_online_nodes()); +} + +static int __init compute_node_distance(int row, int col) +{ + int package_row = row * loongson_sysconf.cores_per_node / + loongson_sysconf.cores_per_package; + int package_col = col * loongson_sysconf.cores_per_node / + loongson_sysconf.cores_per_package; + + if (col == row) + return 0; + else if (package_row == package_col) + return 40; + else + return 100; +} + +static void __init init_topology_matrix(void) +{ + int row, col; + + for (row = 0; row < MAX_NUMNODES; row++) + for (col = 0; col < MAX_NUMNODES; col++) + __node_distances[row][col] = -1; + + for_each_online_node(row) { + for_each_online_node(col) { + __node_distances[row][col] = + compute_node_distance(row, col); + } + } +} + +static unsigned long nid_to_addroffset(unsigned int nid) +{ + unsigned long result; + switch (nid) { + case 0: + default: + result = NODE0_ADDRSPACE_OFFSET; + break; + case 1: + result = NODE1_ADDRSPACE_OFFSET; + break; + case 2: + result = NODE2_ADDRSPACE_OFFSET; + break; + case 3: + result = NODE3_ADDRSPACE_OFFSET; + break; + } + return result; +} + +static void __init szmem(unsigned int node) +{ + u32 i, mem_type; + static unsigned long num_physpages = 0; + u64 node_id, node_psize, start_pfn, end_pfn, mem_start, mem_size; + + /* Parse memory information and activate */ + for (i = 0; i < loongson_memmap->nr_map; i++) { + node_id = loongson_memmap->map[i].node_id; + if (node_id != node) + continue; + + mem_type = loongson_memmap->map[i].mem_type; + mem_size = loongson_memmap->map[i].mem_size; + mem_start = loongson_memmap->map[i].mem_start; + + switch (mem_type) { + case SYSTEM_RAM_LOW: + start_pfn = ((node_id << 44) + mem_start) >> PAGE_SHIFT; + node_psize = (mem_size << 20) >> PAGE_SHIFT; + end_pfn = start_pfn + node_psize; + num_physpages += node_psize; + pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n", + (u32)node_id, mem_type, mem_start, mem_size); + pr_info(" start_pfn:0x%llx, end_pfn:0x%llx, num_physpages:0x%lx\n", + start_pfn, end_pfn, num_physpages); + add_memory_region((node_id << 44) + mem_start, + (u64)mem_size << 20, BOOT_MEM_RAM); + memblock_add_node(PFN_PHYS(start_pfn), + PFN_PHYS(end_pfn - start_pfn), node); + break; + case SYSTEM_RAM_HIGH: + start_pfn = ((node_id << 44) + mem_start) >> PAGE_SHIFT; + node_psize = (mem_size << 20) >> PAGE_SHIFT; + end_pfn = start_pfn + node_psize; + num_physpages += node_psize; + pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n", + (u32)node_id, mem_type, mem_start, mem_size); + pr_info(" start_pfn:0x%llx, end_pfn:0x%llx, num_physpages:0x%lx\n", + start_pfn, end_pfn, num_physpages); + add_memory_region((node_id << 44) + mem_start, + (u64)mem_size << 20, BOOT_MEM_RAM); + memblock_add_node(PFN_PHYS(start_pfn), + PFN_PHYS(end_pfn - start_pfn), node); + break; + case MEM_RESERVED: + pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n", + (u32)node_id, mem_type, mem_start, mem_size); + add_memory_region((node_id << 44) + mem_start, + (u64)mem_size << 20, BOOT_MEM_RESERVED); + memblock_reserve(((node_id << 44) + mem_start), + mem_size << 20); + break; + } + } +} + +static void __init node_mem_init(unsigned int node) +{ + unsigned long bootmap_size; + unsigned long node_addrspace_offset; + unsigned long start_pfn, end_pfn, freepfn; + + node_addrspace_offset = nid_to_addroffset(node); + pr_info("Node%d's addrspace_offset is 0x%lx\n", + node, node_addrspace_offset); + + get_pfn_range_for_nid(node, &start_pfn, &end_pfn); + freepfn = start_pfn; + if (node == 0) + freepfn = PFN_UP(__pa_symbol(&_end)); /* kernel end address */ + pr_info("Node%d: start_pfn=0x%lx, end_pfn=0x%lx, freepfn=0x%lx\n", + node, start_pfn, end_pfn, freepfn); + + __node_data[node] = prealloc__node_data + node; + + NODE_DATA(node)->bdata = &bootmem_node_data[node]; + NODE_DATA(node)->node_start_pfn = start_pfn; + NODE_DATA(node)->node_spanned_pages = end_pfn - start_pfn; + + bootmap_size = init_bootmem_node(NODE_DATA(node), freepfn, + start_pfn, end_pfn); + free_bootmem_with_active_regions(node, end_pfn); + if (node == 0) /* used by finalize_initrd() */ + max_low_pfn = end_pfn; + + /* This is reserved for the kernel and bdata->node_bootmem_map */ + reserve_bootmem_node(NODE_DATA(node), start_pfn << PAGE_SHIFT, + ((freepfn - start_pfn) << PAGE_SHIFT) + bootmap_size, + BOOTMEM_DEFAULT); + + if (node == 0 && node_end_pfn(0) >= (0xffffffff >> PAGE_SHIFT)) { + /* Reserve 0xff800000~0xffffffff for RS780E integrated GPU */ + reserve_bootmem_node(NODE_DATA(node), + (node_addrspace_offset | 0xff800000), + 8 << 20, BOOTMEM_DEFAULT); + } + + sparse_memory_present_with_active_regions(node); +} + +static __init void prom_meminit(void) +{ + unsigned int node, cpu; + + cpu_node_probe(); + init_topology_matrix(); + + for (node = 0; node < loongson_sysconf.nr_nodes; node++) { + if (node_online(node)) { + szmem(node); + node_mem_init(node); + cpus_clear(__node_data[(node)]->cpumask); + } + } + for (cpu = 0; cpu < loongson_sysconf.nr_cpus; cpu++) { + node = cpu / loongson_sysconf.cores_per_node; + if (node >= num_online_nodes()) + node = 0; + pr_info("NUMA: set cpumask cpu %d on node %d\n", cpu, node); + cpu_set(cpu, __node_data[(node)]->cpumask); + } +} + +void __init paging_init(void) +{ + unsigned node; + unsigned long zones_size[MAX_NR_ZONES] = {0, }; + + pagetable_init(); + + for_each_online_node(node) { + unsigned long start_pfn, end_pfn; + + get_pfn_range_for_nid(node, &start_pfn, &end_pfn); + + if (end_pfn > max_low_pfn) + max_low_pfn = end_pfn; + } +#ifdef CONFIG_ZONE_DMA32 + zones_size[ZONE_DMA32] = MAX_DMA32_PFN; +#endif + zones_size[ZONE_NORMAL] = max_low_pfn; + free_area_init_nodes(zones_size); +} + +void __init mem_init(void) +{ + high_memory = (void *) __va(get_num_physpages() << PAGE_SHIFT); + free_all_bootmem(); + setup_zero_pages(); /* This comes from node 0 */ + mem_init_print_info(NULL); +} + +/* All PCI device belongs to logical Node-0 */ +int pcibus_to_node(struct pci_bus *bus) +{ + return 0; +} +EXPORT_SYMBOL(pcibus_to_node); + +void __init prom_init_numa_memory(void) +{ + enable_lpa(); + prom_meminit(); +} +EXPORT_SYMBOL(prom_init_numa_memory); diff --git a/arch/mips/loongson/loongson-3/smp.c b/arch/mips/loongson/loongson-3/smp.c index 3c320e709e91..ed0e2d0f87ab 100644 --- a/arch/mips/loongson/loongson-3/smp.c +++ b/arch/mips/loongson/loongson-3/smp.c @@ -203,6 +203,8 @@ static void loongson3_init_secondary(void) for (i = 0; i < loongson_sysconf.nr_cpus; i++) loongson3_ipi_write32(0xffffffff, ipi_en0_regs[i]); + cpu_data[cpu].package = cpu / loongson_sysconf.cores_per_package; + cpu_data[cpu].core = cpu % loongson_sysconf.cores_per_package; per_cpu(cpu_state, cpu) = CPU_ONLINE; i = 0; @@ -394,17 +396,19 @@ static int loongson3_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { unsigned int cpu = (unsigned long)hcpu; + uint64_t core_id = cpu_data[cpu].core; + uint64_t package_id = cpu_data[cpu].package; switch (action) { case CPU_POST_DEAD: case CPU_POST_DEAD_FROZEN: pr_info("Disable clock for CPU#%d\n", cpu); - LOONGSON_CHIPCFG(0) &= ~(1 << (12 + cpu)); + LOONGSON_CHIPCFG(package_id) &= ~(1 << (12 + core_id)); break; case CPU_UP_PREPARE: case CPU_UP_PREPARE_FROZEN: pr_info("Enable clock for CPU#%d\n", cpu); - LOONGSON_CHIPCFG(0) |= 1 << (12 + cpu); + LOONGSON_CHIPCFG(package_id) |= 1 << (12 + core_id); break; } -- cgit v1.2.3 From 1ff1ad6bc2c63f219cbc00dcdd35dcf36a7d6fe4 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Thu, 26 Jun 2014 11:41:29 +0800 Subject: MIPS: Add numa api support Enable sys_mbind()/sys_get_mempolicy()/sys_set_mempolicy() for O32, N32, and N64 ABIs. By the way, O32/N32 should use the compat version of sys_migrate_pages()/sys_move_pages(), so fix that. Signed-off-by: Huacai Chen Cc: John Crispin Cc: Steven J. Hill Cc: Aurelien Jarno Cc: linux-mips@linux-mips.org Cc: Fuxin Zhang Cc: Zhangjin Wu Patchwork: https://patchwork.linux-mips.org/patch/7186/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/scall32-o32.S | 4 ++-- arch/mips/kernel/scall64-64.S | 4 ++-- arch/mips/kernel/scall64-n32.S | 10 +++++----- arch/mips/kernel/scall64-o32.S | 8 ++++---- 4 files changed, 13 insertions(+), 13 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index 3245474f19d5..6bfdc820ccc3 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -495,8 +495,8 @@ EXPORT(sys_call_table) PTR sys_tgkill PTR sys_utimes PTR sys_mbind - PTR sys_ni_syscall /* sys_get_mempolicy */ - PTR sys_ni_syscall /* 4270 sys_set_mempolicy */ + PTR sys_get_mempolicy + PTR sys_set_mempolicy /* 4270 */ PTR sys_mq_open PTR sys_mq_unlink PTR sys_mq_timedsend diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index be2fedd4ae33..0952139cde62 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -347,8 +347,8 @@ EXPORT(sys_call_table) PTR sys_tgkill /* 5225 */ PTR sys_utimes PTR sys_mbind - PTR sys_ni_syscall /* sys_get_mempolicy */ - PTR sys_ni_syscall /* sys_set_mempolicy */ + PTR sys_get_mempolicy + PTR sys_set_mempolicy PTR sys_mq_open /* 5230 */ PTR sys_mq_unlink PTR sys_mq_timedsend diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index c1dbcda4b816..7641c87be99a 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -339,9 +339,9 @@ EXPORT(sysn32_call_table) PTR compat_sys_clock_nanosleep PTR sys_tgkill PTR compat_sys_utimes /* 6230 */ - PTR sys_ni_syscall /* sys_mbind */ - PTR sys_ni_syscall /* sys_get_mempolicy */ - PTR sys_ni_syscall /* sys_set_mempolicy */ + PTR compat_sys_mbind + PTR compat_sys_get_mempolicy + PTR compat_sys_set_mempolicy PTR compat_sys_mq_open PTR sys_mq_unlink /* 6235 */ PTR compat_sys_mq_timedsend @@ -358,7 +358,7 @@ EXPORT(sysn32_call_table) PTR sys_inotify_init PTR sys_inotify_add_watch PTR sys_inotify_rm_watch - PTR sys_migrate_pages /* 6250 */ + PTR compat_sys_migrate_pages /* 6250 */ PTR sys_openat PTR sys_mkdirat PTR sys_mknodat @@ -379,7 +379,7 @@ EXPORT(sysn32_call_table) PTR sys_sync_file_range PTR sys_tee PTR compat_sys_vmsplice /* 6270 */ - PTR sys_move_pages + PTR compat_sys_move_pages PTR compat_sys_set_robust_list PTR compat_sys_get_robust_list PTR compat_sys_kexec_load diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index f1343ccd7ed7..18cfa115d07e 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -473,9 +473,9 @@ EXPORT(sys32_call_table) PTR compat_sys_clock_nanosleep /* 4265 */ PTR sys_tgkill PTR compat_sys_utimes - PTR sys_ni_syscall /* sys_mbind */ - PTR sys_ni_syscall /* sys_get_mempolicy */ - PTR sys_ni_syscall /* 4270 sys_set_mempolicy */ + PTR compat_sys_mbind + PTR compat_sys_get_mempolicy + PTR compat_sys_set_mempolicy /* 4270 */ PTR compat_sys_mq_open PTR sys_mq_unlink PTR compat_sys_mq_timedsend @@ -492,7 +492,7 @@ EXPORT(sys32_call_table) PTR sys_inotify_init PTR sys_inotify_add_watch /* 4285 */ PTR sys_inotify_rm_watch - PTR sys_migrate_pages + PTR compat_sys_migrate_pages PTR compat_sys_openat PTR sys_mkdirat PTR sys_mknodat /* 4290 */ -- cgit v1.2.3 From e7841be50fe2b8751a51a068b8cdcdcb6611e354 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Thu, 26 Jun 2014 11:41:30 +0800 Subject: MIPS: Add Loongson-3B support Loongson-3B is a 8-cores processor. In general it looks like there are two Loongson-3A integrated in one chip: 8 cores are separated into two groups (two NUMA node), each node has its own local memory. Of course there are some differences between one Loongson-3B and two Loongson-3A. E.g., the base addresses of IPI registers of each node are not the same; Loongson-3A use ChipConfig register to enable/disable clock, but Loongson-3B use FreqControl register instead. There are two revision of Loongson-3B, the first revision is called as Loongson-3B1000, whose frequency is 1GHz and has a PRid 0x6306, the second revision is called as Loongson-3B1500, whose frequency is 1.5GHz and has a PRid 0x6307. Both revisions has a bug that clock cannot be disabled at runtime, but this will be fixed in future. Signed-off-by: Huacai Chen Cc: John Crispin Cc: Steven J. Hill Cc: Aurelien Jarno Cc: linux-mips@linux-mips.org Cc: Fuxin Zhang Cc: Zhangjin Wu Patchwork: https://patchwork.linux-mips.org/patch/7188/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/cpu.h | 2 + arch/mips/include/asm/mach-loongson/boot_param.h | 1 + arch/mips/include/asm/mach-loongson/loongson.h | 4 + arch/mips/kernel/cpu-probe.c | 6 + arch/mips/loongson/common/env.c | 31 +- arch/mips/loongson/loongson-3/irq.c | 26 +- arch/mips/loongson/loongson-3/smp.c | 387 +++++++++++++++++------ arch/mips/loongson/loongson-3/smp.h | 37 +-- 8 files changed, 372 insertions(+), 122 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index 129d08701e91..abf7e005b98f 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -233,6 +233,8 @@ #define PRID_REV_LOONGSON2E 0x0002 #define PRID_REV_LOONGSON2F 0x0003 #define PRID_REV_LOONGSON3A 0x0005 +#define PRID_REV_LOONGSON3B_R1 0x0006 +#define PRID_REV_LOONGSON3B_R2 0x0007 /* * Older processors used to encode processor version and revision in two diff --git a/arch/mips/include/asm/mach-loongson/boot_param.h b/arch/mips/include/asm/mach-loongson/boot_param.h index 8b06c96cce1f..3388fc53599e 100644 --- a/arch/mips/include/asm/mach-loongson/boot_param.h +++ b/arch/mips/include/asm/mach-loongson/boot_param.h @@ -163,4 +163,5 @@ struct loongson_system_configuration { extern struct efi_memory_map_loongson *loongson_memmap; extern struct loongson_system_configuration loongson_sysconf; +extern int cpuhotplug_workaround; #endif diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h index a1c76caa7436..92bf76c21441 100644 --- a/arch/mips/include/asm/mach-loongson/loongson.h +++ b/arch/mips/include/asm/mach-loongson/loongson.h @@ -255,6 +255,10 @@ static inline void do_perfcnt_IRQ(void) extern u64 loongson_chipcfg[MAX_PACKAGES]; #define LOONGSON_CHIPCFG(id) (*(volatile u32 *)(loongson_chipcfg[id])) +/* Freq Control register of each physical cpu package, PRid >= Loongson-3B */ +extern u64 loongson_freqctrl[MAX_PACKAGES]; +#define LOONGSON_FREQCTRL(id) (*(volatile u32 *)(loongson_freqctrl[id])) + /* pcimap */ #define LOONGSON_PCIMAP_PCIMAP_LO0 0x0000003f diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index d74f957c561e..2d2e2877b1ea 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -740,6 +740,12 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) __cpu_name[cpu] = "ICT Loongson-3"; set_elf_platform(cpu, "loongson3a"); break; + case PRID_REV_LOONGSON3B_R1: + case PRID_REV_LOONGSON3B_R2: + c->cputype = CPU_LOONGSON3; + __cpu_name[cpu] = "ICT Loongson-3"; + set_elf_platform(cpu, "loongson3b"); + break; } set_isa(c, MIPS_CPU_ISA_III); diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c index 33a13b9e436c..f15228550a22 100644 --- a/arch/mips/loongson/common/env.c +++ b/arch/mips/loongson/common/env.c @@ -28,6 +28,10 @@ struct efi_memory_map_loongson *loongson_memmap; struct loongson_system_configuration loongson_sysconf; u64 loongson_chipcfg[MAX_PACKAGES] = {0xffffffffbfc00180}; +u64 loongson_freqctrl[MAX_PACKAGES]; + +unsigned long long smp_group[4]; +int cpuhotplug_workaround = 0; #define parse_even_earlier(res, option, p) \ do { \ @@ -82,10 +86,32 @@ void __init prom_init_env(void) if (ecpu->cputype == Loongson_3A) { loongson_sysconf.cores_per_node = 4; loongson_sysconf.cores_per_package = 4; + smp_group[0] = 0x900000003ff01000; + smp_group[1] = 0x900010003ff01000; + smp_group[2] = 0x900020003ff01000; + smp_group[3] = 0x900030003ff01000; loongson_chipcfg[0] = 0x900000001fe00180; loongson_chipcfg[1] = 0x900010001fe00180; loongson_chipcfg[2] = 0x900020001fe00180; loongson_chipcfg[3] = 0x900030001fe00180; + loongson_sysconf.ht_control_base = 0x90000EFDFB000000; + } else if (ecpu->cputype == Loongson_3B) { + loongson_sysconf.cores_per_node = 4; /* One chip has 2 nodes */ + loongson_sysconf.cores_per_package = 8; + smp_group[0] = 0x900000003ff01000; + smp_group[1] = 0x900010003ff05000; + smp_group[2] = 0x900020003ff09000; + smp_group[3] = 0x900030003ff0d000; + loongson_chipcfg[0] = 0x900000001fe00180; + loongson_chipcfg[1] = 0x900020001fe00180; + loongson_chipcfg[2] = 0x900040001fe00180; + loongson_chipcfg[3] = 0x900060001fe00180; + loongson_freqctrl[0] = 0x900000001fe001d0; + loongson_freqctrl[1] = 0x900020001fe001d0; + loongson_freqctrl[2] = 0x900040001fe001d0; + loongson_freqctrl[3] = 0x900060001fe001d0; + loongson_sysconf.ht_control_base = 0x90001EFDFB000000; + cpuhotplug_workaround = 1; } else { loongson_sysconf.cores_per_node = 1; loongson_sysconf.cores_per_package = 1; @@ -111,7 +137,6 @@ void __init prom_init_env(void) loongson_sysconf.poweroff_addr = boot_p->reset_system.Shutdown; loongson_sysconf.suspend_addr = boot_p->reset_system.DoSuspend; - loongson_sysconf.ht_control_base = 0x90000EFDFB000000; loongson_sysconf.vgabios_addr = boot_p->efi.smbios.vga_bios; pr_debug("Shutdown Addr: %llx, Restart Addr: %llx, VBIOS Addr: %llx\n", loongson_sysconf.poweroff_addr, loongson_sysconf.restart_addr, @@ -129,6 +154,10 @@ void __init prom_init_env(void) case PRID_REV_LOONGSON3A: cpu_clock_freq = 900000000; break; + case PRID_REV_LOONGSON3B_R1: + case PRID_REV_LOONGSON3B_R2: + cpu_clock_freq = 1000000000; + break; default: cpu_clock_freq = 100000000; break; diff --git a/arch/mips/loongson/loongson-3/irq.c b/arch/mips/loongson/loongson-3/irq.c index f240828181ff..ca1c62af5188 100644 --- a/arch/mips/loongson/loongson-3/irq.c +++ b/arch/mips/loongson/loongson-3/irq.c @@ -7,6 +7,8 @@ #include #include +#include "smp.h" + unsigned int ht_irq[] = {1, 3, 4, 5, 6, 7, 8, 12, 14, 15}; static void ht_irqdispatch(void) @@ -53,9 +55,15 @@ static inline void mask_loongson_irq(struct irq_data *d) /* Workaround: UART IRQ may deliver to any core */ if (d->irq == LOONGSON_UART_IRQ) { int cpu = smp_processor_id(); - - LOONGSON_INT_ROUTER_INTENCLR = 1 << 10; - LOONGSON_INT_ROUTER_LPC = 0x10 + (1<irq == LOONGSON_UART_IRQ) { int cpu = smp_processor_id(); - - LOONGSON_INT_ROUTER_INTENSET = 1 << 10; - LOONGSON_INT_ROUTER_LPC = 0x10 + (1<irq - MIPS_CPU_IRQ_BASE)); diff --git a/arch/mips/loongson/loongson-3/smp.c b/arch/mips/loongson/loongson-3/smp.c index ed0e2d0f87ab..74e827b4ec8f 100644 --- a/arch/mips/loongson/loongson-3/smp.c +++ b/arch/mips/loongson/loongson-3/smp.c @@ -31,6 +31,12 @@ DEFINE_PER_CPU(int, cpu_state); DEFINE_PER_CPU(uint32_t, core0_c0count); +static void *ipi_set0_regs[16]; +static void *ipi_clear0_regs[16]; +static void *ipi_status0_regs[16]; +static void *ipi_en0_regs[16]; +static void *ipi_mailbox_buf[16]; + /* read a 32bit value from ipi register */ #define loongson3_ipi_read32(addr) readl(addr) /* read a 64bit value from ipi register */ @@ -48,100 +54,185 @@ DEFINE_PER_CPU(uint32_t, core0_c0count); __wbflush(); \ } while (0) -static void *ipi_set0_regs[] = { - (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + SET0), - (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + SET0), - (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + SET0), - (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + SET0), - (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + SET0), - (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + SET0), - (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + SET0), - (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + SET0), - (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + SET0), - (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + SET0), - (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + SET0), - (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + SET0), - (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + SET0), - (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + SET0), - (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + SET0), - (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + SET0), -}; +static void ipi_set0_regs_init(void) +{ + ipi_set0_regs[0] = (void *) + (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + SET0); + ipi_set0_regs[1] = (void *) + (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + SET0); + ipi_set0_regs[2] = (void *) + (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + SET0); + ipi_set0_regs[3] = (void *) + (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + SET0); + ipi_set0_regs[4] = (void *) + (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + SET0); + ipi_set0_regs[5] = (void *) + (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + SET0); + ipi_set0_regs[6] = (void *) + (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + SET0); + ipi_set0_regs[7] = (void *) + (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + SET0); + ipi_set0_regs[8] = (void *) + (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + SET0); + ipi_set0_regs[9] = (void *) + (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + SET0); + ipi_set0_regs[10] = (void *) + (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + SET0); + ipi_set0_regs[11] = (void *) + (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + SET0); + ipi_set0_regs[12] = (void *) + (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + SET0); + ipi_set0_regs[13] = (void *) + (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + SET0); + ipi_set0_regs[14] = (void *) + (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + SET0); + ipi_set0_regs[15] = (void *) + (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + SET0); +} -static void *ipi_clear0_regs[] = { - (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + CLEAR0), - (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + CLEAR0), - (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + CLEAR0), - (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + CLEAR0), - (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + CLEAR0), - (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + CLEAR0), - (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + CLEAR0), - (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + CLEAR0), - (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + CLEAR0), - (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + CLEAR0), - (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + CLEAR0), - (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + CLEAR0), - (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + CLEAR0), - (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + CLEAR0), - (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + CLEAR0), - (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + CLEAR0), -}; +static void ipi_clear0_regs_init(void) +{ + ipi_clear0_regs[0] = (void *) + (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + CLEAR0); + ipi_clear0_regs[1] = (void *) + (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + CLEAR0); + ipi_clear0_regs[2] = (void *) + (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + CLEAR0); + ipi_clear0_regs[3] = (void *) + (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + CLEAR0); + ipi_clear0_regs[4] = (void *) + (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + CLEAR0); + ipi_clear0_regs[5] = (void *) + (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + CLEAR0); + ipi_clear0_regs[6] = (void *) + (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + CLEAR0); + ipi_clear0_regs[7] = (void *) + (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + CLEAR0); + ipi_clear0_regs[8] = (void *) + (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + CLEAR0); + ipi_clear0_regs[9] = (void *) + (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + CLEAR0); + ipi_clear0_regs[10] = (void *) + (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + CLEAR0); + ipi_clear0_regs[11] = (void *) + (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + CLEAR0); + ipi_clear0_regs[12] = (void *) + (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + CLEAR0); + ipi_clear0_regs[13] = (void *) + (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + CLEAR0); + ipi_clear0_regs[14] = (void *) + (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + CLEAR0); + ipi_clear0_regs[15] = (void *) + (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + CLEAR0); +} -static void *ipi_status0_regs[] = { - (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + STATUS0), - (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + STATUS0), - (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + STATUS0), - (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + STATUS0), - (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + STATUS0), - (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + STATUS0), - (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + STATUS0), - (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + STATUS0), - (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + STATUS0), - (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + STATUS0), - (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + STATUS0), - (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + STATUS0), - (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + STATUS0), - (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + STATUS0), - (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + STATUS0), - (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + STATUS0), -}; +static void ipi_status0_regs_init(void) +{ + ipi_status0_regs[0] = (void *) + (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + STATUS0); + ipi_status0_regs[1] = (void *) + (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + STATUS0); + ipi_status0_regs[2] = (void *) + (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + STATUS0); + ipi_status0_regs[3] = (void *) + (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + STATUS0); + ipi_status0_regs[4] = (void *) + (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + STATUS0); + ipi_status0_regs[5] = (void *) + (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + STATUS0); + ipi_status0_regs[6] = (void *) + (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + STATUS0); + ipi_status0_regs[7] = (void *) + (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + STATUS0); + ipi_status0_regs[8] = (void *) + (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + STATUS0); + ipi_status0_regs[9] = (void *) + (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + STATUS0); + ipi_status0_regs[10] = (void *) + (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + STATUS0); + ipi_status0_regs[11] = (void *) + (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + STATUS0); + ipi_status0_regs[12] = (void *) + (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + STATUS0); + ipi_status0_regs[13] = (void *) + (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + STATUS0); + ipi_status0_regs[14] = (void *) + (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + STATUS0); + ipi_status0_regs[15] = (void *) + (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + STATUS0); +} -static void *ipi_en0_regs[] = { - (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + EN0), - (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + EN0), - (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + EN0), - (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + EN0), - (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + EN0), - (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + EN0), - (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + EN0), - (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + EN0), - (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + EN0), - (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + EN0), - (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + EN0), - (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + EN0), - (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + EN0), - (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + EN0), - (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + EN0), - (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + EN0), -}; +static void ipi_en0_regs_init(void) +{ + ipi_en0_regs[0] = (void *) + (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + EN0); + ipi_en0_regs[1] = (void *) + (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + EN0); + ipi_en0_regs[2] = (void *) + (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + EN0); + ipi_en0_regs[3] = (void *) + (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + EN0); + ipi_en0_regs[4] = (void *) + (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + EN0); + ipi_en0_regs[5] = (void *) + (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + EN0); + ipi_en0_regs[6] = (void *) + (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + EN0); + ipi_en0_regs[7] = (void *) + (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + EN0); + ipi_en0_regs[8] = (void *) + (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + EN0); + ipi_en0_regs[9] = (void *) + (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + EN0); + ipi_en0_regs[10] = (void *) + (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + EN0); + ipi_en0_regs[11] = (void *) + (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + EN0); + ipi_en0_regs[12] = (void *) + (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + EN0); + ipi_en0_regs[13] = (void *) + (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + EN0); + ipi_en0_regs[14] = (void *) + (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + EN0); + ipi_en0_regs[15] = (void *) + (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + EN0); +} -static void *ipi_mailbox_buf[] = { - (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + BUF), - (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + BUF), - (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + BUF), - (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + BUF), - (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + BUF), - (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + BUF), - (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + BUF), - (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + BUF), - (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + BUF), - (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + BUF), - (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + BUF), - (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + BUF), - (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + BUF), - (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + BUF), - (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + BUF), - (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + BUF), -}; +static void ipi_mailbox_buf_init(void) +{ + ipi_mailbox_buf[0] = (void *) + (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + BUF); + ipi_mailbox_buf[1] = (void *) + (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + BUF); + ipi_mailbox_buf[2] = (void *) + (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + BUF); + ipi_mailbox_buf[3] = (void *) + (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + BUF); + ipi_mailbox_buf[4] = (void *) + (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + BUF); + ipi_mailbox_buf[5] = (void *) + (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + BUF); + ipi_mailbox_buf[6] = (void *) + (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + BUF); + ipi_mailbox_buf[7] = (void *) + (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + BUF); + ipi_mailbox_buf[8] = (void *) + (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + BUF); + ipi_mailbox_buf[9] = (void *) + (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + BUF); + ipi_mailbox_buf[10] = (void *) + (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + BUF); + ipi_mailbox_buf[11] = (void *) + (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + BUF); + ipi_mailbox_buf[12] = (void *) + (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + BUF); + ipi_mailbox_buf[13] = (void *) + (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + BUF); + ipi_mailbox_buf[14] = (void *) + (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + BUF); + ipi_mailbox_buf[15] = (void *) + (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + BUF); +} /* * Simple enough, just poke the appropriate ipi register @@ -248,6 +339,11 @@ static void __init loongson3_smp_setup(void) __cpu_number_map[i] = ++num; __cpu_logical_map[num] = i; } + ipi_set0_regs_init(); + ipi_clear0_regs_init(); + ipi_status0_regs_init(); + ipi_en0_regs_init(); + ipi_mailbox_buf_init(); pr_info("Detected %i available secondary CPU(s)\n", num); } @@ -315,7 +411,7 @@ static void loongson3_cpu_die(unsigned int cpu) * flush all L1 entries at first. Then, another core (usually Core 0) can * safely disable the clock of the target core. loongson3_play_dead() is * called via CKSEG1 (uncached and unmmaped) */ -static void loongson3_play_dead(int *state_addr) +static void loongson3a_play_dead(int *state_addr) { register int val; register long cpuid, core, node, count; @@ -377,6 +473,70 @@ static void loongson3_play_dead(int *state_addr) : "a1"); } +static void loongson3b_play_dead(int *state_addr) +{ + register int val; + register long cpuid, core, node, count; + register void *addr, *base, *initfunc; + + __asm__ __volatile__( + " .set push \n" + " .set noreorder \n" + " li %[addr], 0x80000000 \n" /* KSEG0 */ + "1: cache 0, 0(%[addr]) \n" /* flush L1 ICache */ + " cache 0, 1(%[addr]) \n" + " cache 0, 2(%[addr]) \n" + " cache 0, 3(%[addr]) \n" + " cache 1, 0(%[addr]) \n" /* flush L1 DCache */ + " cache 1, 1(%[addr]) \n" + " cache 1, 2(%[addr]) \n" + " cache 1, 3(%[addr]) \n" + " addiu %[sets], %[sets], -1 \n" + " bnez %[sets], 1b \n" + " addiu %[addr], %[addr], 0x20 \n" + " li %[val], 0x7 \n" /* *state_addr = CPU_DEAD; */ + " sw %[val], (%[state_addr]) \n" + " sync \n" + " cache 21, (%[state_addr]) \n" /* flush entry of *state_addr */ + " .set pop \n" + : [addr] "=&r" (addr), [val] "=&r" (val) + : [state_addr] "r" (state_addr), + [sets] "r" (cpu_data[smp_processor_id()].dcache.sets)); + + __asm__ __volatile__( + " .set push \n" + " .set noreorder \n" + " .set mips64 \n" + " mfc0 %[cpuid], $15, 1 \n" + " andi %[cpuid], 0x3ff \n" + " dli %[base], 0x900000003ff01000 \n" + " andi %[core], %[cpuid], 0x3 \n" + " sll %[core], 8 \n" /* get core id */ + " or %[base], %[base], %[core] \n" + " andi %[node], %[cpuid], 0xc \n" + " dsll %[node], 42 \n" /* get node id */ + " or %[base], %[base], %[node] \n" + " dsrl %[node], 30 \n" /* 15:14 */ + " or %[base], %[base], %[node] \n" + "1: li %[count], 0x100 \n" /* wait for init loop */ + "2: bnez %[count], 2b \n" /* limit mailbox access */ + " addiu %[count], -1 \n" + " ld %[initfunc], 0x20(%[base]) \n" /* get PC via mailbox */ + " beqz %[initfunc], 1b \n" + " nop \n" + " ld $sp, 0x28(%[base]) \n" /* get SP via mailbox */ + " ld $gp, 0x30(%[base]) \n" /* get GP via mailbox */ + " ld $a1, 0x38(%[base]) \n" + " jr %[initfunc] \n" /* jump to initial PC */ + " nop \n" + " .set pop \n" + : [core] "=&r" (core), [node] "=&r" (node), + [base] "=&r" (base), [cpuid] "=&r" (cpuid), + [count] "=&r" (count), [initfunc] "=&r" (initfunc) + : /* No Input */ + : "a1"); +} + void play_dead(void) { int *state_addr; @@ -384,31 +544,64 @@ void play_dead(void) void (*play_dead_at_ckseg1)(int *); idle_task_exit(); - play_dead_at_ckseg1 = - (void *)CKSEG1ADDR((unsigned long)loongson3_play_dead); + switch (loongson_sysconf.cputype) { + case Loongson_3A: + default: + play_dead_at_ckseg1 = + (void *)CKSEG1ADDR((unsigned long)loongson3a_play_dead); + break; + case Loongson_3B: + play_dead_at_ckseg1 = + (void *)CKSEG1ADDR((unsigned long)loongson3b_play_dead); + break; + } state_addr = &per_cpu(cpu_state, cpu); mb(); play_dead_at_ckseg1(state_addr); } +void loongson3_disable_clock(int cpu) +{ + uint64_t core_id = cpu_data[cpu].core; + uint64_t package_id = cpu_data[cpu].package; + + if (loongson_sysconf.cputype == Loongson_3A) { + LOONGSON_CHIPCFG(package_id) &= ~(1 << (12 + core_id)); + } else if (loongson_sysconf.cputype == Loongson_3B) { + if (!cpuhotplug_workaround) + LOONGSON_FREQCTRL(package_id) &= ~(1 << (core_id * 4 + 3)); + } +} + +void loongson3_enable_clock(int cpu) +{ + uint64_t core_id = cpu_data[cpu].core; + uint64_t package_id = cpu_data[cpu].package; + + if (loongson_sysconf.cputype == Loongson_3A) { + LOONGSON_CHIPCFG(package_id) |= 1 << (12 + core_id); + } else if (loongson_sysconf.cputype == Loongson_3B) { + if (!cpuhotplug_workaround) + LOONGSON_FREQCTRL(package_id) |= 1 << (core_id * 4 + 3); + } +} + #define CPU_POST_DEAD_FROZEN (CPU_POST_DEAD | CPU_TASKS_FROZEN) static int loongson3_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { unsigned int cpu = (unsigned long)hcpu; - uint64_t core_id = cpu_data[cpu].core; - uint64_t package_id = cpu_data[cpu].package; switch (action) { case CPU_POST_DEAD: case CPU_POST_DEAD_FROZEN: pr_info("Disable clock for CPU#%d\n", cpu); - LOONGSON_CHIPCFG(package_id) &= ~(1 << (12 + core_id)); + loongson3_disable_clock(cpu); break; case CPU_UP_PREPARE: case CPU_UP_PREPARE_FROZEN: pr_info("Enable clock for CPU#%d\n", cpu); - LOONGSON_CHIPCFG(package_id) |= 1 << (12 + core_id); + loongson3_enable_clock(cpu); break; } diff --git a/arch/mips/loongson/loongson-3/smp.h b/arch/mips/loongson/loongson-3/smp.h index 3453e8c4f2f0..d98ff654b7d7 100644 --- a/arch/mips/loongson/loongson-3/smp.h +++ b/arch/mips/loongson/loongson-3/smp.h @@ -1,29 +1,30 @@ #ifndef __LOONGSON_SMP_H_ #define __LOONGSON_SMP_H_ -/* for Loongson-3A smp support */ +/* for Loongson-3 smp support */ +extern unsigned long long smp_group[4]; /* 4 groups(nodes) in maximum in numa case */ -#define SMP_CORE_GROUP0_BASE 0x900000003ff01000 -#define SMP_CORE_GROUP1_BASE 0x900010003ff01000 -#define SMP_CORE_GROUP2_BASE 0x900020003ff01000 -#define SMP_CORE_GROUP3_BASE 0x900030003ff01000 +#define SMP_CORE_GROUP0_BASE (smp_group[0]) +#define SMP_CORE_GROUP1_BASE (smp_group[1]) +#define SMP_CORE_GROUP2_BASE (smp_group[2]) +#define SMP_CORE_GROUP3_BASE (smp_group[3]) /* 4 cores in each group(node) */ -#define SMP_CORE0_OFFSET 0x000 -#define SMP_CORE1_OFFSET 0x100 -#define SMP_CORE2_OFFSET 0x200 -#define SMP_CORE3_OFFSET 0x300 +#define SMP_CORE0_OFFSET 0x000 +#define SMP_CORE1_OFFSET 0x100 +#define SMP_CORE2_OFFSET 0x200 +#define SMP_CORE3_OFFSET 0x300 /* ipi registers offsets */ -#define STATUS0 0x00 -#define EN0 0x04 -#define SET0 0x08 -#define CLEAR0 0x0c -#define STATUS1 0x10 -#define MASK1 0x14 -#define SET1 0x18 -#define CLEAR1 0x1c -#define BUF 0x20 +#define STATUS0 0x00 +#define EN0 0x04 +#define SET0 0x08 +#define CLEAR0 0x0c +#define STATUS1 0x10 +#define MASK1 0x14 +#define SET1 0x18 +#define CLEAR1 0x1c +#define BUF 0x20 #endif -- cgit v1.2.3 From 656ff9bef08c19a6471b49528dacb4cbbeb1e537 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Wed, 23 Jul 2014 14:40:06 +0100 Subject: MIPS: ptrace: Avoid smp_processor_id() when retrieving FPU IR Whenever ptrace attempts to retrieve the FPU implementation register it accesses it through current_cpu_data, which calls smp_processor_id(). Since the code may execute with preemption enabled, this can trigger a warning. Fix this by using boot_cpu_data to get the IR instead. Signed-off-by: Alex Smith Cc: # v3.15+ Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7449/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/ptrace.c | 4 ++-- arch/mips/kernel/ptrace32.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index f639ccd5060c..6063b112a6aa 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -129,7 +129,7 @@ int ptrace_getfpregs(struct task_struct *child, __u32 __user *data) } __put_user(child->thread.fpu.fcr31, data + 64); - __put_user(current_cpu_data.fpu_id, data + 65); + __put_user(boot_cpu_data.fpu_id, data + 65); return 0; } @@ -480,7 +480,7 @@ long arch_ptrace(struct task_struct *child, long request, break; case FPC_EIR: /* implementation / version register */ - tmp = current_cpu_data.fpu_id; + tmp = boot_cpu_data.fpu_id; break; case DSP_BASE ... DSP_BASE + 5: { dspreg_t *dregs; diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index b40c3ca60ee5..a83fb730b387 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -129,7 +129,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, break; case FPC_EIR: /* implementation / version register */ - tmp = current_cpu_data.fpu_id; + tmp = boot_cpu_data.fpu_id; break; case DSP_BASE ... DSP_BASE + 5: { dspreg_t *dregs; -- cgit v1.2.3 From 65768a1a92cb12cbba87588927cf597a65d560aa Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Wed, 23 Jul 2014 14:40:07 +0100 Subject: MIPS: ptrace: Test correct task's flags in task_user_regset_view() task_user_regset_view() should test for TIF_32BIT_REGS in the flags of the specified task, not of the current task. Signed-off-by: Alex Smith Cc: # v3.13+ Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7450/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/ptrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 6063b112a6aa..8f2130a2bbd3 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -398,7 +398,7 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) #endif #ifdef CONFIG_MIPS32_O32 - if (test_thread_flag(TIF_32BIT_REGS)) + if (test_tsk_thread_flag(task, TIF_32BIT_REGS)) return &user_mips_view; #endif -- cgit v1.2.3 From bcec7c8da6b092b1ff3327fd83c2193adb12f684 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Wed, 23 Jul 2014 14:40:08 +0100 Subject: MIPS: asm/reg.h: Make 32- and 64-bit definitions available at the same time Get rid of the WANT_COMPAT_REG_H test and instead define both the 32- and 64-bit register offset definitions at the same time with MIPS{32,64}_ prefixes, then define the existing EF_* names to the correct definitions for the kernel's bitness. This patch is a prerequisite of the following bug fix patch. Signed-off-by: Alex Smith Cc: # v3.13+ Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7451/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/reg.h | 260 +++++++++++++++++++++++++-------------- arch/mips/kernel/binfmt_elfo32.c | 32 ++--- 2 files changed, 182 insertions(+), 110 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/include/asm/reg.h b/arch/mips/include/asm/reg.h index 910e71a12466..b8343ccbc989 100644 --- a/arch/mips/include/asm/reg.h +++ b/arch/mips/include/asm/reg.h @@ -12,116 +12,194 @@ #ifndef __ASM_MIPS_REG_H #define __ASM_MIPS_REG_H - -#if defined(CONFIG_32BIT) || defined(WANT_COMPAT_REG_H) - -#define EF_R0 6 -#define EF_R1 7 -#define EF_R2 8 -#define EF_R3 9 -#define EF_R4 10 -#define EF_R5 11 -#define EF_R6 12 -#define EF_R7 13 -#define EF_R8 14 -#define EF_R9 15 -#define EF_R10 16 -#define EF_R11 17 -#define EF_R12 18 -#define EF_R13 19 -#define EF_R14 20 -#define EF_R15 21 -#define EF_R16 22 -#define EF_R17 23 -#define EF_R18 24 -#define EF_R19 25 -#define EF_R20 26 -#define EF_R21 27 -#define EF_R22 28 -#define EF_R23 29 -#define EF_R24 30 -#define EF_R25 31 +#define MIPS32_EF_R0 6 +#define MIPS32_EF_R1 7 +#define MIPS32_EF_R2 8 +#define MIPS32_EF_R3 9 +#define MIPS32_EF_R4 10 +#define MIPS32_EF_R5 11 +#define MIPS32_EF_R6 12 +#define MIPS32_EF_R7 13 +#define MIPS32_EF_R8 14 +#define MIPS32_EF_R9 15 +#define MIPS32_EF_R10 16 +#define MIPS32_EF_R11 17 +#define MIPS32_EF_R12 18 +#define MIPS32_EF_R13 19 +#define MIPS32_EF_R14 20 +#define MIPS32_EF_R15 21 +#define MIPS32_EF_R16 22 +#define MIPS32_EF_R17 23 +#define MIPS32_EF_R18 24 +#define MIPS32_EF_R19 25 +#define MIPS32_EF_R20 26 +#define MIPS32_EF_R21 27 +#define MIPS32_EF_R22 28 +#define MIPS32_EF_R23 29 +#define MIPS32_EF_R24 30 +#define MIPS32_EF_R25 31 /* * k0/k1 unsaved */ -#define EF_R26 32 -#define EF_R27 33 +#define MIPS32_EF_R26 32 +#define MIPS32_EF_R27 33 -#define EF_R28 34 -#define EF_R29 35 -#define EF_R30 36 -#define EF_R31 37 +#define MIPS32_EF_R28 34 +#define MIPS32_EF_R29 35 +#define MIPS32_EF_R30 36 +#define MIPS32_EF_R31 37 /* * Saved special registers */ -#define EF_LO 38 -#define EF_HI 39 - -#define EF_CP0_EPC 40 -#define EF_CP0_BADVADDR 41 -#define EF_CP0_STATUS 42 -#define EF_CP0_CAUSE 43 -#define EF_UNUSED0 44 - -#define EF_SIZE 180 - -#endif - -#if defined(CONFIG_64BIT) && !defined(WANT_COMPAT_REG_H) - -#define EF_R0 0 -#define EF_R1 1 -#define EF_R2 2 -#define EF_R3 3 -#define EF_R4 4 -#define EF_R5 5 -#define EF_R6 6 -#define EF_R7 7 -#define EF_R8 8 -#define EF_R9 9 -#define EF_R10 10 -#define EF_R11 11 -#define EF_R12 12 -#define EF_R13 13 -#define EF_R14 14 -#define EF_R15 15 -#define EF_R16 16 -#define EF_R17 17 -#define EF_R18 18 -#define EF_R19 19 -#define EF_R20 20 -#define EF_R21 21 -#define EF_R22 22 -#define EF_R23 23 -#define EF_R24 24 -#define EF_R25 25 +#define MIPS32_EF_LO 38 +#define MIPS32_EF_HI 39 + +#define MIPS32_EF_CP0_EPC 40 +#define MIPS32_EF_CP0_BADVADDR 41 +#define MIPS32_EF_CP0_STATUS 42 +#define MIPS32_EF_CP0_CAUSE 43 +#define MIPS32_EF_UNUSED0 44 + +#define MIPS32_EF_SIZE 180 + +#define MIPS64_EF_R0 0 +#define MIPS64_EF_R1 1 +#define MIPS64_EF_R2 2 +#define MIPS64_EF_R3 3 +#define MIPS64_EF_R4 4 +#define MIPS64_EF_R5 5 +#define MIPS64_EF_R6 6 +#define MIPS64_EF_R7 7 +#define MIPS64_EF_R8 8 +#define MIPS64_EF_R9 9 +#define MIPS64_EF_R10 10 +#define MIPS64_EF_R11 11 +#define MIPS64_EF_R12 12 +#define MIPS64_EF_R13 13 +#define MIPS64_EF_R14 14 +#define MIPS64_EF_R15 15 +#define MIPS64_EF_R16 16 +#define MIPS64_EF_R17 17 +#define MIPS64_EF_R18 18 +#define MIPS64_EF_R19 19 +#define MIPS64_EF_R20 20 +#define MIPS64_EF_R21 21 +#define MIPS64_EF_R22 22 +#define MIPS64_EF_R23 23 +#define MIPS64_EF_R24 24 +#define MIPS64_EF_R25 25 /* * k0/k1 unsaved */ -#define EF_R26 26 -#define EF_R27 27 +#define MIPS64_EF_R26 26 +#define MIPS64_EF_R27 27 -#define EF_R28 28 -#define EF_R29 29 -#define EF_R30 30 -#define EF_R31 31 +#define MIPS64_EF_R28 28 +#define MIPS64_EF_R29 29 +#define MIPS64_EF_R30 30 +#define MIPS64_EF_R31 31 /* * Saved special registers */ -#define EF_LO 32 -#define EF_HI 33 - -#define EF_CP0_EPC 34 -#define EF_CP0_BADVADDR 35 -#define EF_CP0_STATUS 36 -#define EF_CP0_CAUSE 37 - -#define EF_SIZE 304 /* size in bytes */ +#define MIPS64_EF_LO 32 +#define MIPS64_EF_HI 33 + +#define MIPS64_EF_CP0_EPC 34 +#define MIPS64_EF_CP0_BADVADDR 35 +#define MIPS64_EF_CP0_STATUS 36 +#define MIPS64_EF_CP0_CAUSE 37 + +#define MIPS64_EF_SIZE 304 /* size in bytes */ + +#if defined(CONFIG_32BIT) + +#define EF_R0 MIPS32_EF_R0 +#define EF_R1 MIPS32_EF_R1 +#define EF_R2 MIPS32_EF_R2 +#define EF_R3 MIPS32_EF_R3 +#define EF_R4 MIPS32_EF_R4 +#define EF_R5 MIPS32_EF_R5 +#define EF_R6 MIPS32_EF_R6 +#define EF_R7 MIPS32_EF_R7 +#define EF_R8 MIPS32_EF_R8 +#define EF_R9 MIPS32_EF_R9 +#define EF_R10 MIPS32_EF_R10 +#define EF_R11 MIPS32_EF_R11 +#define EF_R12 MIPS32_EF_R12 +#define EF_R13 MIPS32_EF_R13 +#define EF_R14 MIPS32_EF_R14 +#define EF_R15 MIPS32_EF_R15 +#define EF_R16 MIPS32_EF_R16 +#define EF_R17 MIPS32_EF_R17 +#define EF_R18 MIPS32_EF_R18 +#define EF_R19 MIPS32_EF_R19 +#define EF_R20 MIPS32_EF_R20 +#define EF_R21 MIPS32_EF_R21 +#define EF_R22 MIPS32_EF_R22 +#define EF_R23 MIPS32_EF_R23 +#define EF_R24 MIPS32_EF_R24 +#define EF_R25 MIPS32_EF_R25 +#define EF_R26 MIPS32_EF_R26 +#define EF_R27 MIPS32_EF_R27 +#define EF_R28 MIPS32_EF_R28 +#define EF_R29 MIPS32_EF_R29 +#define EF_R30 MIPS32_EF_R30 +#define EF_R31 MIPS32_EF_R31 +#define EF_LO MIPS32_EF_LO +#define EF_HI MIPS32_EF_HI +#define EF_CP0_EPC MIPS32_EF_CP0_EPC +#define EF_CP0_BADVADDR MIPS32_EF_CP0_BADVADDR +#define EF_CP0_STATUS MIPS32_EF_CP0_STATUS +#define EF_CP0_CAUSE MIPS32_EF_CP0_CAUSE +#define EF_UNUSED0 MIPS32_EF_UNUSED0 +#define EF_SIZE MIPS32_EF_SIZE + +#elif defined(CONFIG_64BIT) + +#define EF_R0 MIPS64_EF_R0 +#define EF_R1 MIPS64_EF_R1 +#define EF_R2 MIPS64_EF_R2 +#define EF_R3 MIPS64_EF_R3 +#define EF_R4 MIPS64_EF_R4 +#define EF_R5 MIPS64_EF_R5 +#define EF_R6 MIPS64_EF_R6 +#define EF_R7 MIPS64_EF_R7 +#define EF_R8 MIPS64_EF_R8 +#define EF_R9 MIPS64_EF_R9 +#define EF_R10 MIPS64_EF_R10 +#define EF_R11 MIPS64_EF_R11 +#define EF_R12 MIPS64_EF_R12 +#define EF_R13 MIPS64_EF_R13 +#define EF_R14 MIPS64_EF_R14 +#define EF_R15 MIPS64_EF_R15 +#define EF_R16 MIPS64_EF_R16 +#define EF_R17 MIPS64_EF_R17 +#define EF_R18 MIPS64_EF_R18 +#define EF_R19 MIPS64_EF_R19 +#define EF_R20 MIPS64_EF_R20 +#define EF_R21 MIPS64_EF_R21 +#define EF_R22 MIPS64_EF_R22 +#define EF_R23 MIPS64_EF_R23 +#define EF_R24 MIPS64_EF_R24 +#define EF_R25 MIPS64_EF_R25 +#define EF_R26 MIPS64_EF_R26 +#define EF_R27 MIPS64_EF_R27 +#define EF_R28 MIPS64_EF_R28 +#define EF_R29 MIPS64_EF_R29 +#define EF_R30 MIPS64_EF_R30 +#define EF_R31 MIPS64_EF_R31 +#define EF_LO MIPS64_EF_LO +#define EF_HI MIPS64_EF_HI +#define EF_CP0_EPC MIPS64_EF_CP0_EPC +#define EF_CP0_BADVADDR MIPS64_EF_CP0_BADVADDR +#define EF_CP0_STATUS MIPS64_EF_CP0_STATUS +#define EF_CP0_CAUSE MIPS64_EF_CP0_CAUSE +#define EF_SIZE MIPS64_EF_SIZE #endif /* CONFIG_64BIT */ diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c index 7faf5f2bee25..71df942fb77c 100644 --- a/arch/mips/kernel/binfmt_elfo32.c +++ b/arch/mips/kernel/binfmt_elfo32.c @@ -72,12 +72,6 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; #include -/* - * When this file is selected, we are definitely running a 64bit kernel. - * So using the right regs define in asm/reg.h - */ -#define WANT_COMPAT_REG_H - /* These MUST be defined before elf.h gets included */ extern void elf32_core_copy_regs(elf_gregset_t grp, struct pt_regs *regs); #define ELF_CORE_COPY_REGS(_dest, _regs) elf32_core_copy_regs(_dest, _regs); @@ -149,21 +143,21 @@ void elf32_core_copy_regs(elf_gregset_t grp, struct pt_regs *regs) { int i; - for (i = 0; i < EF_R0; i++) + for (i = 0; i < MIPS32_EF_R0; i++) grp[i] = 0; - grp[EF_R0] = 0; + grp[MIPS32_EF_R0] = 0; for (i = 1; i <= 31; i++) - grp[EF_R0 + i] = (elf_greg_t) regs->regs[i]; - grp[EF_R26] = 0; - grp[EF_R27] = 0; - grp[EF_LO] = (elf_greg_t) regs->lo; - grp[EF_HI] = (elf_greg_t) regs->hi; - grp[EF_CP0_EPC] = (elf_greg_t) regs->cp0_epc; - grp[EF_CP0_BADVADDR] = (elf_greg_t) regs->cp0_badvaddr; - grp[EF_CP0_STATUS] = (elf_greg_t) regs->cp0_status; - grp[EF_CP0_CAUSE] = (elf_greg_t) regs->cp0_cause; -#ifdef EF_UNUSED0 - grp[EF_UNUSED0] = 0; + grp[MIPS32_EF_R0 + i] = (elf_greg_t) regs->regs[i]; + grp[MIPS32_EF_R26] = 0; + grp[MIPS32_EF_R27] = 0; + grp[MIPS32_EF_LO] = (elf_greg_t) regs->lo; + grp[MIPS32_EF_HI] = (elf_greg_t) regs->hi; + grp[MIPS32_EF_CP0_EPC] = (elf_greg_t) regs->cp0_epc; + grp[MIPS32_EF_CP0_BADVADDR] = (elf_greg_t) regs->cp0_badvaddr; + grp[MIPS32_EF_CP0_STATUS] = (elf_greg_t) regs->cp0_status; + grp[MIPS32_EF_CP0_CAUSE] = (elf_greg_t) regs->cp0_cause; +#ifdef MIPS32_EF_UNUSED0 + grp[MIPS32_EF_UNUSED0] = 0; #endif } -- cgit v1.2.3 From c23b3d1a53119849dc3c23c417124deb067aa33d Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Wed, 23 Jul 2014 14:40:09 +0100 Subject: MIPS: ptrace: Change GP regset to use correct core dump register layout Commit 6a9c001b7ec3 ("MIPS: Switch ELF core dumper to use regsets.") switched the core dumper to use regsets, however the GP regset code simply makes a direct copy of the kernel's pt_regs, which does not match the original core dump register layout as defined in asm/reg.h. Furthermore, the definition of pt_regs can vary with certain Kconfig variables, therefore the GP regset can never be relied upon to return registers in the same layout. Therefore, this patch changes the GP regset to match the original core dump layout. The layout differs for 32- and 64-bit processes, so separate implementations of the get/set functions are added for the 32- and 64-bit regsets. Signed-off-by: Alex Smith Cc: # v3.13+ Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7452/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/ptrace.c | 189 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 160 insertions(+), 29 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 8f2130a2bbd3..8bd13ed084d2 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -246,36 +246,160 @@ int ptrace_set_watch_regs(struct task_struct *child, /* regset get/set implementations */ -static int gpr_get(struct task_struct *target, - const struct user_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) +#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32) + +static int gpr32_get(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) { struct pt_regs *regs = task_pt_regs(target); + u32 uregs[ELF_NGREG] = {}; + unsigned i; + + for (i = MIPS32_EF_R1; i <= MIPS32_EF_R31; i++) { + /* k0/k1 are copied as zero. */ + if (i == MIPS32_EF_R26 || i == MIPS32_EF_R27) + continue; + + uregs[i] = regs->regs[i - MIPS32_EF_R0]; + } - return user_regset_copyout(&pos, &count, &kbuf, &ubuf, - regs, 0, sizeof(*regs)); + uregs[MIPS32_EF_LO] = regs->lo; + uregs[MIPS32_EF_HI] = regs->hi; + uregs[MIPS32_EF_CP0_EPC] = regs->cp0_epc; + uregs[MIPS32_EF_CP0_BADVADDR] = regs->cp0_badvaddr; + uregs[MIPS32_EF_CP0_STATUS] = regs->cp0_status; + uregs[MIPS32_EF_CP0_CAUSE] = regs->cp0_cause; + + return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, + sizeof(uregs)); } -static int gpr_set(struct task_struct *target, - const struct user_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) +static int gpr32_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) { - struct pt_regs newregs; - int ret; + struct pt_regs *regs = task_pt_regs(target); + u32 uregs[ELF_NGREG]; + unsigned start, num_regs, i; + int err; + + start = pos / sizeof(u32); + num_regs = count / sizeof(u32); + + if (start + num_regs > ELF_NGREG) + return -EIO; + + err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0, + sizeof(uregs)); + if (err) + return err; + + for (i = start; i < num_regs; i++) { + /* + * Cast all values to signed here so that if this is a 64-bit + * kernel, the supplied 32-bit values will be sign extended. + */ + switch (i) { + case MIPS32_EF_R1 ... MIPS32_EF_R25: + /* k0/k1 are ignored. */ + case MIPS32_EF_R28 ... MIPS32_EF_R31: + regs->regs[i - MIPS32_EF_R0] = (s32)uregs[i]; + break; + case MIPS32_EF_LO: + regs->lo = (s32)uregs[i]; + break; + case MIPS32_EF_HI: + regs->hi = (s32)uregs[i]; + break; + case MIPS32_EF_CP0_EPC: + regs->cp0_epc = (s32)uregs[i]; + break; + } + } + + return 0; +} + +#endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */ + +#ifdef CONFIG_64BIT + +static int gpr64_get(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + struct pt_regs *regs = task_pt_regs(target); + u64 uregs[ELF_NGREG] = {}; + unsigned i; + + for (i = MIPS64_EF_R1; i <= MIPS64_EF_R31; i++) { + /* k0/k1 are copied as zero. */ + if (i == MIPS64_EF_R26 || i == MIPS64_EF_R27) + continue; + + uregs[i] = regs->regs[i - MIPS64_EF_R0]; + } + + uregs[MIPS64_EF_LO] = regs->lo; + uregs[MIPS64_EF_HI] = regs->hi; + uregs[MIPS64_EF_CP0_EPC] = regs->cp0_epc; + uregs[MIPS64_EF_CP0_BADVADDR] = regs->cp0_badvaddr; + uregs[MIPS64_EF_CP0_STATUS] = regs->cp0_status; + uregs[MIPS64_EF_CP0_CAUSE] = regs->cp0_cause; + + return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, + sizeof(uregs)); +} - ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, - &newregs, - 0, sizeof(newregs)); - if (ret) - return ret; +static int gpr64_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + struct pt_regs *regs = task_pt_regs(target); + u64 uregs[ELF_NGREG]; + unsigned start, num_regs, i; + int err; + + start = pos / sizeof(u64); + num_regs = count / sizeof(u64); - *task_pt_regs(target) = newregs; + if (start + num_regs > ELF_NGREG) + return -EIO; + + err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0, + sizeof(uregs)); + if (err) + return err; + + for (i = start; i < num_regs; i++) { + switch (i) { + case MIPS64_EF_R1 ... MIPS64_EF_R25: + /* k0/k1 are ignored. */ + case MIPS64_EF_R28 ... MIPS64_EF_R31: + regs->regs[i - MIPS64_EF_R0] = uregs[i]; + break; + case MIPS64_EF_LO: + regs->lo = uregs[i]; + break; + case MIPS64_EF_HI: + regs->hi = uregs[i]; + break; + case MIPS64_EF_CP0_EPC: + regs->cp0_epc = uregs[i]; + break; + } + } return 0; } +#endif /* CONFIG_64BIT */ + static int fpr_get(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, @@ -337,14 +461,16 @@ enum mips_regset { REGSET_FPR, }; +#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32) + static const struct user_regset mips_regsets[] = { [REGSET_GPR] = { .core_note_type = NT_PRSTATUS, .n = ELF_NGREG, .size = sizeof(unsigned int), .align = sizeof(unsigned int), - .get = gpr_get, - .set = gpr_set, + .get = gpr32_get, + .set = gpr32_set, }, [REGSET_FPR] = { .core_note_type = NT_PRFPREG, @@ -364,14 +490,18 @@ static const struct user_regset_view user_mips_view = { .n = ARRAY_SIZE(mips_regsets), }; +#endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */ + +#ifdef CONFIG_64BIT + static const struct user_regset mips64_regsets[] = { [REGSET_GPR] = { .core_note_type = NT_PRSTATUS, .n = ELF_NGREG, .size = sizeof(unsigned long), .align = sizeof(unsigned long), - .get = gpr_get, - .set = gpr_set, + .get = gpr64_get, + .set = gpr64_set, }, [REGSET_FPR] = { .core_note_type = NT_PRFPREG, @@ -384,25 +514,26 @@ static const struct user_regset mips64_regsets[] = { }; static const struct user_regset_view user_mips64_view = { - .name = "mips", + .name = "mips64", .e_machine = ELF_ARCH, .ei_osabi = ELF_OSABI, .regsets = mips64_regsets, - .n = ARRAY_SIZE(mips_regsets), + .n = ARRAY_SIZE(mips64_regsets), }; +#endif /* CONFIG_64BIT */ + const struct user_regset_view *task_user_regset_view(struct task_struct *task) { #ifdef CONFIG_32BIT return &user_mips_view; -#endif - +#else #ifdef CONFIG_MIPS32_O32 - if (test_tsk_thread_flag(task, TIF_32BIT_REGS)) - return &user_mips_view; + if (test_tsk_thread_flag(task, TIF_32BIT_REGS)) + return &user_mips_view; #endif - return &user_mips64_view; +#endif } long arch_ptrace(struct task_struct *child, long request, -- cgit v1.2.3 From ffc8415afab20bd97754efae6aad1f67b531132b Mon Sep 17 00:00:00 2001 From: Jeffrey Deans Date: Thu, 17 Jul 2014 09:20:56 +0100 Subject: MIPS: GIC: Prevent array overrun A GIC interrupt which is declared as having a GIC_MAP_TO_NMI_MSK mapping causes the cpu parameter to gic_setup_intr() to be increased to 32, causing memory corruption when pcpu_masks[] is written to again later in the function. Signed-off-by: Jeffrey Deans Signed-off-by: Markos Chandras Cc: stable@vger.kernel.org Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7375/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/irq-gic.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/irq-gic.c b/arch/mips/kernel/irq-gic.c index 88e4c323382c..d5e59b8f4863 100644 --- a/arch/mips/kernel/irq-gic.c +++ b/arch/mips/kernel/irq-gic.c @@ -269,11 +269,13 @@ static void __init gic_setup_intr(unsigned int intr, unsigned int cpu, /* Setup Intr to Pin mapping */ if (pin & GIC_MAP_TO_NMI_MSK) { + int i; + GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), pin); /* FIXME: hack to route NMI to all cpu's */ - for (cpu = 0; cpu < NR_CPUS; cpu += 32) { + for (i = 0; i < NR_CPUS; i += 32) { GICWRITE(GIC_REG_ADDR(SHARED, - GIC_SH_MAP_TO_VPE_REG_OFF(intr, cpu)), + GIC_SH_MAP_TO_VPE_REG_OFF(intr, i)), 0xffffffff); } } else { -- cgit v1.2.3 From 0435b13ee3732c1dda5312025f49073d01d8d15d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdelin Date: Thu, 19 Jun 2014 16:30:23 -0400 Subject: MIPS: APRP: Fix an issue when device_create() fails. If a call to device_create() fails for a channel during the initialize loop, we need to clean the devices entries already created before leaving. Signed-off-by: Sebastien Bourdelin Cc: linux-mips@linux-mips.org Cc: Steven J. Hill Cc: Deng-Cheng Zhu Cc: John Crispin Cc: Qais Yousef Cc: linux-kernel@vger.kernel.org Cc: Jerome Oufella Patchwork: https://patchwork.linux-mips.org/patch/7111/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/rtlx-cmp.c | 3 +++ arch/mips/kernel/rtlx-mt.c | 3 +++ 2 files changed, 6 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/rtlx-cmp.c b/arch/mips/kernel/rtlx-cmp.c index 758fb3cd2326..d26dcc4b46e7 100644 --- a/arch/mips/kernel/rtlx-cmp.c +++ b/arch/mips/kernel/rtlx-cmp.c @@ -77,6 +77,9 @@ int __init rtlx_module_init(void) dev = device_create(mt_class, NULL, MKDEV(major, i), NULL, "%s%d", RTLX_MODULE_NAME, i); if (IS_ERR(dev)) { + while (i--) + device_destroy(mt_class, MKDEV(major, i)); + err = PTR_ERR(dev); goto out_chrdev; } diff --git a/arch/mips/kernel/rtlx-mt.c b/arch/mips/kernel/rtlx-mt.c index 5a66b975989e..cb95470e2e69 100644 --- a/arch/mips/kernel/rtlx-mt.c +++ b/arch/mips/kernel/rtlx-mt.c @@ -103,6 +103,9 @@ int __init rtlx_module_init(void) dev = device_create(mt_class, NULL, MKDEV(major, i), NULL, "%s%d", RTLX_MODULE_NAME, i); if (IS_ERR(dev)) { + while (i--) + device_destroy(mt_class, MKDEV(major, i)); + err = PTR_ERR(dev); goto out_chrdev; } -- cgit v1.2.3 From 077d0e65618f27b2199d622e12ada6d8f3dbd862 Mon Sep 17 00:00:00 2001 From: Sorin Dumitru Date: Fri, 20 Jun 2014 14:23:35 +0300 Subject: MIPS: N32: Use compat getsockopt syscall The IP_PKTOPTIONS sockopt puts control messages in option_values, these need to be handled differently in the compat case. This is already done through the MSG_CMSG_COMPAT flag, we just need to use compat_sys_getsockopt which sets that flag. Signed-off-by: Sorin Dumitru Reviewed-by: James Hogan Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7115/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/scall64-n32.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index c1dbcda4b816..e543861ef00a 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -162,7 +162,7 @@ EXPORT(sysn32_call_table) PTR sys_getpeername PTR sys_socketpair PTR compat_sys_setsockopt - PTR sys_getsockopt + PTR compat_sys_getsockopt PTR __sys_clone /* 6055 */ PTR __sys_fork PTR compat_sys_execve -- cgit v1.2.3 From 7d907fa1c6ccb64c7f64cc7d3dcc7f6fe30a67b4 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 4 Jul 2014 11:59:46 +0100 Subject: MIPS: smp-mt: Fix link error when PROC_FS=n Commit d6d3c9afaab4 (MIPS: MT: proc: Add support for printing VPE and TC ids) causes a link error when CONFIG_PROC_FS=n: arch/mips/built-in.o: In function `proc_cpuinfo_notifier_init': smp-mt.c: undefined reference to `register_proc_cpuinfo_notifier' This is fixed by adding an ifdef around the procfs handling code in smp-mt.c. Signed-off-by: James Hogan Reported-by: Markos Chandras Reviewed-by: Markos Chandras Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: # >= 3.15 Patchwork: https://patchwork.linux-mips.org/patch/7244/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/smp-mt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c index 3babf6e4f894..21f23add04f4 100644 --- a/arch/mips/kernel/smp-mt.c +++ b/arch/mips/kernel/smp-mt.c @@ -288,6 +288,7 @@ struct plat_smp_ops vsmp_smp_ops = { .prepare_cpus = vsmp_prepare_cpus, }; +#ifdef CONFIG_PROC_FS static int proc_cpuinfo_chain_call(struct notifier_block *nfb, unsigned long action_unused, void *data) { @@ -309,3 +310,4 @@ static int __init proc_cpuinfo_notifier_init(void) } subsys_initcall(proc_cpuinfo_notifier_init); +#endif -- cgit v1.2.3 From 457ed7702dcc8ba13e3eea7f2d44d0e18dc76b3f Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Wed, 23 Jul 2014 14:40:12 +0100 Subject: MIPS: O32/32-bit: Remove outdated comment A comment in the O32/32-bit system call code is incorrect since commit 46e12c07b3b9 ("MIPS: O32 / 32-bit: Always copy 4 stack arguments."). Remove it. Signed-off-by: Alex Smith Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7455/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/scall32-o32.S | 2 -- 1 file changed, 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index 6bfdc820ccc3..94a490d6cdc1 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -67,8 +67,6 @@ NESTED(handle_sys, PT_SIZE, sp) /* * Ok, copy the args from the luser stack to the kernel stack. - * t3 is the precomputed number of instruction bytes needed to - * load or store arguments 6-8. */ .set push -- cgit v1.2.3 From a79ebea620109cf5e58711077177b34d60960898 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Wed, 23 Jul 2014 14:40:13 +0100 Subject: MIPS: ptrace: Fix user pt_regs definition, use in ptrace_{get, set}regs() In uapi/asm/ptrace.h, a user version of pt_regs is defined wrapped in ifndef __KERNEL__. This structure definition does not match anything used by any kernel API, in particular it does not match the format used by PTRACE_{GET,SET}REGS. Therefore, replace the structure definition with one matching what is used by PTRACE_{GET,SET}REGS. The format used by these is the same for both 32-bit and 64-bit. Also, change the implementation of PTRACE_{GET,SET}REGS to use this new structure definition. The structure is renamed to user_pt_regs when __KERNEL__ is defined to avoid conflicts with the kernel's own pt_regs. Signed-off-by: Alex Smith Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7457/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/ptrace.h | 6 ++++-- arch/mips/include/uapi/asm/ptrace.h | 25 ++++++++++++++----------- arch/mips/kernel/ptrace.c | 26 +++++++++++++------------- arch/mips/kernel/ptrace32.c | 6 ++++-- 4 files changed, 35 insertions(+), 28 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h index c301fa9b139f..fc783f843bdc 100644 --- a/arch/mips/include/asm/ptrace.h +++ b/arch/mips/include/asm/ptrace.h @@ -47,8 +47,10 @@ struct pt_regs { struct task_struct; -extern int ptrace_getregs(struct task_struct *child, __s64 __user *data); -extern int ptrace_setregs(struct task_struct *child, __s64 __user *data); +extern int ptrace_getregs(struct task_struct *child, + struct user_pt_regs __user *data); +extern int ptrace_setregs(struct task_struct *child, + struct user_pt_regs __user *data); extern int ptrace_getfpregs(struct task_struct *child, __u32 __user *data); extern int ptrace_setfpregs(struct task_struct *child, __u32 __user *data); diff --git a/arch/mips/include/uapi/asm/ptrace.h b/arch/mips/include/uapi/asm/ptrace.h index b26f7e317279..bbcfb8ba8106 100644 --- a/arch/mips/include/uapi/asm/ptrace.h +++ b/arch/mips/include/uapi/asm/ptrace.h @@ -22,24 +22,27 @@ #define DSP_CONTROL 77 #define ACX 78 -#ifndef __KERNEL__ /* - * This struct defines the way the registers are stored on the stack during a - * system call/exception. As usual the registers k0/k1 aren't being saved. + * This struct defines the registers as used by PTRACE_{GET,SET}REGS. The + * format is the same for both 32- and 64-bit processes. Registers for 32-bit + * processes are sign extended. */ +#ifdef __KERNEL__ +struct user_pt_regs { +#else struct pt_regs { +#endif /* Saved main processor registers. */ - unsigned long regs[32]; + __u64 regs[32]; /* Saved special registers. */ - unsigned long cp0_status; - unsigned long hi; - unsigned long lo; - unsigned long cp0_badvaddr; - unsigned long cp0_cause; - unsigned long cp0_epc; + __u64 lo; + __u64 hi; + __u64 cp0_epc; + __u64 cp0_badvaddr; + __u64 cp0_status; + __u64 cp0_cause; } __attribute__ ((aligned (8))); -#endif /* __KERNEL__ */ /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ #define PTRACE_GETREGS 12 diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 8bd13ed084d2..0fdb91e36137 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -63,7 +63,7 @@ void ptrace_disable(struct task_struct *child) * for 32-bit kernels and for 32-bit processes on a 64-bit kernel. * Registers are sign extended to fill the available space. */ -int ptrace_getregs(struct task_struct *child, __s64 __user *data) +int ptrace_getregs(struct task_struct *child, struct user_pt_regs __user *data) { struct pt_regs *regs; int i; @@ -74,13 +74,13 @@ int ptrace_getregs(struct task_struct *child, __s64 __user *data) regs = task_pt_regs(child); for (i = 0; i < 32; i++) - __put_user((long)regs->regs[i], data + i); - __put_user((long)regs->lo, data + EF_LO - EF_R0); - __put_user((long)regs->hi, data + EF_HI - EF_R0); - __put_user((long)regs->cp0_epc, data + EF_CP0_EPC - EF_R0); - __put_user((long)regs->cp0_badvaddr, data + EF_CP0_BADVADDR - EF_R0); - __put_user((long)regs->cp0_status, data + EF_CP0_STATUS - EF_R0); - __put_user((long)regs->cp0_cause, data + EF_CP0_CAUSE - EF_R0); + __put_user((long)regs->regs[i], (__s64 __user *)&data->regs[i]); + __put_user((long)regs->lo, (__s64 __user *)&data->lo); + __put_user((long)regs->hi, (__s64 __user *)&data->hi); + __put_user((long)regs->cp0_epc, (__s64 __user *)&data->cp0_epc); + __put_user((long)regs->cp0_badvaddr, (__s64 __user *)&data->cp0_badvaddr); + __put_user((long)regs->cp0_status, (__s64 __user *)&data->cp0_status); + __put_user((long)regs->cp0_cause, (__s64 __user *)&data->cp0_cause); return 0; } @@ -90,7 +90,7 @@ int ptrace_getregs(struct task_struct *child, __s64 __user *data) * the 64-bit format. On a 32-bit kernel only the lower order half * (according to endianness) will be used. */ -int ptrace_setregs(struct task_struct *child, __s64 __user *data) +int ptrace_setregs(struct task_struct *child, struct user_pt_regs __user *data) { struct pt_regs *regs; int i; @@ -101,10 +101,10 @@ int ptrace_setregs(struct task_struct *child, __s64 __user *data) regs = task_pt_regs(child); for (i = 0; i < 32; i++) - __get_user(regs->regs[i], data + i); - __get_user(regs->lo, data + EF_LO - EF_R0); - __get_user(regs->hi, data + EF_HI - EF_R0); - __get_user(regs->cp0_epc, data + EF_CP0_EPC - EF_R0); + __get_user(regs->regs[i], (__s64 __user *)&data->regs[i]); + __get_user(regs->lo, (__s64 __user *)&data->lo); + __get_user(regs->hi, (__s64 __user *)&data->hi); + __get_user(regs->cp0_epc, (__s64 __user *)&data->cp0_epc); /* badvaddr, status, and cause may not be written. */ diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index a83fb730b387..dee8729995a7 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -256,11 +256,13 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, } case PTRACE_GETREGS: - ret = ptrace_getregs(child, (__s64 __user *) (__u64) data); + ret = ptrace_getregs(child, + (struct user_pt_regs __user *) (__u64) data); break; case PTRACE_SETREGS: - ret = ptrace_setregs(child, (__s64 __user *) (__u64) data); + ret = ptrace_setregs(child, + (struct user_pt_regs __user *) (__u64) data); break; case PTRACE_GETFPREGS: -- cgit v1.2.3 From 30852ad0039b4a54b5062efd66877125e519dc30 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Wed, 23 Jul 2014 14:40:14 +0100 Subject: MIPS: Remove old core dump functions Since the core dumper now uses regsets, the old core dump functions are now unused. Remove them. Signed-off-by: Alex Smith Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7456/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/elf.h | 17 ------------- arch/mips/kernel/binfmt_elfo32.c | 32 ----------------------- arch/mips/kernel/process.c | 55 ---------------------------------------- 3 files changed, 104 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index d4144056e928..1d38fe0edd2d 100644 --- a/arch/mips/include/asm/elf.h +++ b/arch/mips/include/asm/elf.h @@ -339,23 +339,6 @@ do { \ #endif /* CONFIG_64BIT */ -struct pt_regs; -struct task_struct; - -extern void elf_dump_regs(elf_greg_t *, struct pt_regs *regs); -extern int dump_task_regs(struct task_struct *, elf_gregset_t *); -extern int dump_task_fpu(struct task_struct *, elf_fpregset_t *); - -#ifndef ELF_CORE_COPY_REGS -#define ELF_CORE_COPY_REGS(elf_regs, regs) \ - elf_dump_regs((elf_greg_t *)&(elf_regs), regs); -#endif -#ifndef ELF_CORE_COPY_TASK_REGS -#define ELF_CORE_COPY_TASK_REGS(tsk, elf_regs) dump_task_regs(tsk, elf_regs) -#endif -#define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) \ - dump_task_fpu(tsk, elf_fpregs) - #define CORE_DUMP_USE_REGSET #define ELF_EXEC_PAGESIZE PAGE_SIZE diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c index 71df942fb77c..928767858b86 100644 --- a/arch/mips/kernel/binfmt_elfo32.c +++ b/arch/mips/kernel/binfmt_elfo32.c @@ -72,16 +72,6 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; #include -/* These MUST be defined before elf.h gets included */ -extern void elf32_core_copy_regs(elf_gregset_t grp, struct pt_regs *regs); -#define ELF_CORE_COPY_REGS(_dest, _regs) elf32_core_copy_regs(_dest, _regs); -#define ELF_CORE_COPY_TASK_REGS(_tsk, _dest) \ -({ \ - int __res = 1; \ - elf32_core_copy_regs(*(_dest), task_pt_regs(_tsk)); \ - __res; \ -}) - #include #include #include @@ -139,28 +129,6 @@ jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value) value->tv_usec = rem / NSEC_PER_USEC; } -void elf32_core_copy_regs(elf_gregset_t grp, struct pt_regs *regs) -{ - int i; - - for (i = 0; i < MIPS32_EF_R0; i++) - grp[i] = 0; - grp[MIPS32_EF_R0] = 0; - for (i = 1; i <= 31; i++) - grp[MIPS32_EF_R0 + i] = (elf_greg_t) regs->regs[i]; - grp[MIPS32_EF_R26] = 0; - grp[MIPS32_EF_R27] = 0; - grp[MIPS32_EF_LO] = (elf_greg_t) regs->lo; - grp[MIPS32_EF_HI] = (elf_greg_t) regs->hi; - grp[MIPS32_EF_CP0_EPC] = (elf_greg_t) regs->cp0_epc; - grp[MIPS32_EF_CP0_BADVADDR] = (elf_greg_t) regs->cp0_badvaddr; - grp[MIPS32_EF_CP0_STATUS] = (elf_greg_t) regs->cp0_status; - grp[MIPS32_EF_CP0_CAUSE] = (elf_greg_t) regs->cp0_cause; -#ifdef MIPS32_EF_UNUSED0 - grp[MIPS32_EF_UNUSED0] = 0; -#endif -} - MODULE_DESCRIPTION("Binary format loader for compatibility with o32 Linux/MIPS binaries"); MODULE_AUTHOR("Ralf Baechle (ralf@linux-mips.org)"); diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 0a1ec0f3beff..7564c371c660 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -152,61 +152,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, return 0; } -/* Fill in the fpu structure for a core dump.. */ -int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r) -{ - int i; - - for (i = 0; i < NUM_FPU_REGS; i++) - memcpy(&r[i], ¤t->thread.fpu.fpr[i], sizeof(*r)); - - memcpy(&r[NUM_FPU_REGS], ¤t->thread.fpu.fcr31, - sizeof(current->thread.fpu.fcr31)); - - return 1; -} - -void elf_dump_regs(elf_greg_t *gp, struct pt_regs *regs) -{ - int i; - - for (i = 0; i < EF_R0; i++) - gp[i] = 0; - gp[EF_R0] = 0; - for (i = 1; i <= 31; i++) - gp[EF_R0 + i] = regs->regs[i]; - gp[EF_R26] = 0; - gp[EF_R27] = 0; - gp[EF_LO] = regs->lo; - gp[EF_HI] = regs->hi; - gp[EF_CP0_EPC] = regs->cp0_epc; - gp[EF_CP0_BADVADDR] = regs->cp0_badvaddr; - gp[EF_CP0_STATUS] = regs->cp0_status; - gp[EF_CP0_CAUSE] = regs->cp0_cause; -#ifdef EF_UNUSED0 - gp[EF_UNUSED0] = 0; -#endif -} - -int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) -{ - elf_dump_regs(*regs, task_pt_regs(tsk)); - return 1; -} - -int dump_task_fpu(struct task_struct *t, elf_fpregset_t *fpr) -{ - int i; - - for (i = 0; i < NUM_FPU_REGS; i++) - memcpy(&fpr[i], &t->thread.fpu.fpr[i], sizeof(*fpr)); - - memcpy(&fpr[NUM_FPU_REGS], &t->thread.fpu.fcr31, - sizeof(t->thread.fpu.fcr31)); - - return 1; -} - #ifdef CONFIG_CC_STACKPROTECTOR #include unsigned long __stack_chk_guard __read_mostly; -- cgit v1.2.3 From 60be939c5a7956cd93714b0737bf289269a52c17 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Wed, 23 Jul 2014 14:40:15 +0100 Subject: MIPS: Remove asm/user.h The struct user definition in this file is not used anywhere (the ELF core dumper does not use that format). Therefore, remove the header and instead enable the asm-generic user.h which is an empty header to satisfy a few generic headers which still try to include user.h. Signed-off-by: Alex Smith Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7459/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/Kbuild | 1 + arch/mips/include/asm/user.h | 58 -------------------------------------------- arch/mips/kernel/process.c | 2 +- arch/mips/kernel/ptrace.c | 1 - arch/mips/kernel/ptrace32.c | 2 +- 5 files changed, 3 insertions(+), 61 deletions(-) delete mode 100644 arch/mips/include/asm/user.h (limited to 'arch/mips/kernel') diff --git a/arch/mips/include/asm/Kbuild b/arch/mips/include/asm/Kbuild index 05439187891d..335e5290ec75 100644 --- a/arch/mips/include/asm/Kbuild +++ b/arch/mips/include/asm/Kbuild @@ -15,4 +15,5 @@ generic-y += segment.h generic-y += serial.h generic-y += trace_clock.h generic-y += ucontext.h +generic-y += user.h generic-y += xor.h diff --git a/arch/mips/include/asm/user.h b/arch/mips/include/asm/user.h deleted file mode 100644 index 6bad61b0a53a..000000000000 --- a/arch/mips/include/asm/user.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1994, 1995, 1996, 1999 by Ralf Baechle - */ -#ifndef _ASM_USER_H -#define _ASM_USER_H - -#include -#include - -/* - * Core file format: The core file is written in such a way that gdb - * can understand it and provide useful information to the user (under - * linux we use the `trad-core' bfd, NOT the irix-core). The file - * contents are as follows: - * - * upage: 1 page consisting of a user struct that tells gdb - * what is present in the file. Directly after this is a - * copy of the task_struct, which is currently not used by gdb, - * but it may come in handy at some point. All of the registers - * are stored as part of the upage. The upage should always be - * only one page long. - * data: The data segment follows next. We use current->end_text to - * current->brk to pick up all of the user variables, plus any memory - * that may have been sbrk'ed. No attempt is made to determine if a - * page is demand-zero or if a page is totally unused, we just cover - * the entire range. All of the addresses are rounded in such a way - * that an integral number of pages is written. - * stack: We need the stack information in order to get a meaningful - * backtrace. We need to write the data from usp to - * current->start_stack, so we round each of these in order to be able - * to write an integer number of pages. - */ -struct user { - unsigned long regs[EF_SIZE / /* integer and fp regs */ - sizeof(unsigned long) + 64]; - size_t u_tsize; /* text size (pages) */ - size_t u_dsize; /* data size (pages) */ - size_t u_ssize; /* stack size (pages) */ - unsigned long start_code; /* text starting address */ - unsigned long start_data; /* data starting address */ - unsigned long start_stack; /* stack starting address */ - long int signal; /* signal causing core dump */ - unsigned long u_ar0; /* help gdb find registers */ - unsigned long magic; /* identifies a core file */ - char u_comm[32]; /* user command name */ -}; - -#define NBPG PAGE_SIZE -#define UPAGES 1 -#define HOST_TEXT_START_ADDR (u.start_code) -#define HOST_DATA_START_ADDR (u.start_data) -#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG) - -#endif /* _ASM_USER_H */ diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 7564c371c660..2dafceb0d0c6 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -36,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 0fdb91e36137..8c78f01dbe73 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index dee8729995a7..283b5a1967d1 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -32,6 +31,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From 67dca667516529b24f98dd9d1d4e832ff705054b Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 4 Jul 2014 11:08:56 +0100 Subject: MIPS: perf: Allow for more perf events In mipsxx_pmu_map_raw_event(), set event_id to base_id after the cpu type conditional code to allow that code to override the base_id to use more bits from the config and a higher bit for parity. This will allow cores with up to 512 events between all even/odd counters (an 8-bit event id) such as P5600 to use bit 8 for parity. Signed-off-by: James Hogan Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7243/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/perf_event_mipsxx.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c index 4f2d9dece7ab..ef8b3d994c5a 100644 --- a/arch/mips/kernel/perf_event_mipsxx.c +++ b/arch/mips/kernel/perf_event_mipsxx.c @@ -1420,20 +1420,23 @@ static irqreturn_t mipsxx_pmu_handle_irq(int irq, void *dev) /* - * User can use 0-255 raw events, where 0-127 for the events of even - * counters, and 128-255 for odd counters. Note that bit 7 is used to - * indicate the parity. So, for example, when user wants to take the - * Event Num of 15 for odd counters (by referring to the user manual), - * then 128 needs to be added to 15 as the input for the event config, - * i.e., 143 (0x8F) to be used. + * For most cores the user can use 0-255 raw events, where 0-127 for the events + * of even counters, and 128-255 for odd counters. Note that bit 7 is used to + * indicate the even/odd bank selector. So, for example, when user wants to take + * the Event Num of 15 for odd counters (by referring to the user manual), then + * 128 needs to be added to 15 as the input for the event config, i.e., 143 (0x8F) + * to be used. + * + * Some newer cores have even more events, in which case the user can use raw + * events 0-511, where 0-255 are for the events of even counters, and 256-511 + * are for odd counters, so bit 8 is used to indicate the even/odd bank selector. */ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config) { + /* currently most cores have 7-bit event numbers */ unsigned int raw_id = config & 0xff; unsigned int base_id = raw_id & 0x7f; - raw_event.event_id = base_id; - switch (current_cpu_type()) { case CPU_24K: if (IS_BOTH_COUNTERS_24K_EVENT(base_id)) @@ -1523,6 +1526,8 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config) raw_id > 127 ? CNTR_ODD : CNTR_EVEN; } + raw_event.event_id = base_id; + return &raw_event; } -- cgit v1.2.3 From 560b461be17039046ae241426f4adf9bd997abb4 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 4 Jul 2014 11:08:57 +0100 Subject: MIPS: perf: Add hardware events for P5600 Add cases in perf_event_mipsxx.c for CPU_P5600. All the event numbers listed for proAptiv also apply to P5600, so we use mipsxxcore_event_map2 and mipsxxcore_cache_map2 too, but the P5600 has 8-bit event numbers so bit 8 (256) of the user ABI config is used for the parity bit (to specify odd/even counter events). Signed-off-by: James Hogan Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7242/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/perf_event_mipsxx.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c index ef8b3d994c5a..14bf74b0f51c 100644 --- a/arch/mips/kernel/perf_event_mipsxx.c +++ b/arch/mips/kernel/perf_event_mipsxx.c @@ -1386,6 +1386,9 @@ static irqreturn_t mipsxx_pmu_handle_irq(int irq, void *dev) /* proAptiv */ #define IS_BOTH_COUNTERS_PROAPTIV_EVENT(b) \ ((b) == 0 || (b) == 1) +/* P5600 */ +#define IS_BOTH_COUNTERS_P5600_EVENT(b) \ + ((b) == 0 || (b) == 1) /* 1004K */ #define IS_BOTH_COUNTERS_1004K_EVENT(b) \ @@ -1486,6 +1489,19 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config) raw_id > 127 ? CNTR_ODD : CNTR_EVEN; #ifdef CONFIG_MIPS_MT_SMP raw_event.range = P; +#endif + break; + case CPU_P5600: + /* 8-bit event numbers */ + raw_id = config & 0x1ff; + base_id = raw_id & 0xff; + if (IS_BOTH_COUNTERS_P5600_EVENT(base_id)) + raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD; + else + raw_event.cntr_mask = + raw_id > 255 ? CNTR_ODD : CNTR_EVEN; +#ifdef CONFIG_MIPS_MT_SMP + raw_event.range = P; #endif break; case CPU_1004K: @@ -1638,6 +1654,11 @@ init_hw_perf_events(void) mipspmu.general_event_map = &mipsxxcore_event_map2; mipspmu.cache_event_map = &mipsxxcore_cache_map2; break; + case CPU_P5600: + mipspmu.name = "mips/P5600"; + mipspmu.general_event_map = &mipsxxcore_event_map2; + mipspmu.cache_event_map = &mipsxxcore_cache_map2; + break; case CPU_1004K: mipspmu.name = "mips/1004K"; mipspmu.general_event_map = &mipsxxcore_event_map; -- cgit v1.2.3 From e647e6b5b355bbf58d5c20c181e69474e5aee5fe Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Mon, 14 Jul 2014 12:43:28 +0100 Subject: MIPS: cpu: Add new cpu option for Hardware Table Walker. Moreover, report hardware page table walker support as 'htw' in the ASE list of /proc/cpuinfo, if the core implements this feature. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7334/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/cpu-features.h | 3 +++ arch/mips/include/asm/cpu.h | 1 + arch/mips/kernel/proc.c | 1 + 3 files changed, 5 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h index c7d8c997d93e..3b9768e92e9e 100644 --- a/arch/mips/include/asm/cpu-features.h +++ b/arch/mips/include/asm/cpu-features.h @@ -29,6 +29,9 @@ #ifndef cpu_has_eva #define cpu_has_eva (cpu_data[0].options & MIPS_CPU_EVA) #endif +#ifndef cpu_has_htw +#define cpu_has_htw (cpu_data[0].options & MIPS_CPU_HTW) +#endif /* * For the moment we don't consider R6000 and R8000 so we can assume that diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index abacaa1f7293..ec6a0f964d6a 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -365,6 +365,7 @@ enum cpu_type_enum { #define MIPS_CPU_TLBINV 0x02000000ull /* CPU supports TLBINV/F */ #define MIPS_CPU_SEGMENTS 0x04000000ull /* CPU supports Segmentation Control registers */ #define MIPS_CPU_EVA 0x80000000ull /* CPU supports Enhanced Virtual Addressing */ +#define MIPS_CPU_HTW 0x100000000ull /* CPU support Hardware Page Table Walker */ /* * CPU ASE encodings diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 62c4439a147b..097fc8d14e42 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -113,6 +113,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) if (cpu_has_vz) seq_printf(m, "%s", " vz"); if (cpu_has_msa) seq_printf(m, "%s", " msa"); if (cpu_has_eva) seq_printf(m, "%s", " eva"); + if (cpu_has_htw) seq_printf(m, "%s", " htw"); seq_printf(m, "\n"); if (cpu_has_mmips) { -- cgit v1.2.3 From 3d528b326d7da8e28ec62c2ff1a92e85d93af098 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Mon, 14 Jul 2014 12:46:13 +0100 Subject: MIPS: kernel: cpu-probe: Add support for the HardWare Table Walker Detect if the core implements the HTW and set the option accordingly. Also, add a new kernel parameter called 'nohtw' allowing the user to disable the htw support and fallback to the software refill handler. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7335/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 2d2e2877b1ea..0d30433db54b 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -54,6 +54,20 @@ static int __init dsp_disable(char *s) __setup("nodsp", dsp_disable); +static int mips_htw_disabled; + +static int __init htw_disable(char *s) +{ + mips_htw_disabled = 1; + cpu_data[0].options &= ~MIPS_CPU_HTW; + write_c0_pwctl(read_c0_pwctl() & + ~(1 << MIPS_PWCTL_PWEN_SHIFT)); + + return 1; +} + +__setup("nohtw", htw_disable); + static inline void check_errata(void) { struct cpuinfo_mips *c = ¤t_cpu_data; @@ -321,6 +335,9 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c) c->options |= MIPS_CPU_SEGMENTS; if (config3 & MIPS_CONF3_MSA) c->ases |= MIPS_ASE_MSA; + /* Only tested on 32-bit cores */ + if ((config3 & MIPS_CONF3_PW) && config_enabled(CONFIG_32BIT)) + c->options |= MIPS_CPU_HTW; return config3 & MIPS_CONF_M; } @@ -1193,6 +1210,12 @@ void cpu_probe(void) if (mips_dsp_disabled) c->ases &= ~(MIPS_ASE_DSP | MIPS_ASE_DSP2P); + if (mips_htw_disabled) { + c->options &= ~MIPS_CPU_HTW; + write_c0_pwctl(read_c0_pwctl() & + ~(1 << MIPS_PWCTL_PWEN_SHIFT)); + } + if (c->options & MIPS_CPU_FPU) { c->fpu_id = cpu_get_fpu_id(); -- cgit v1.2.3 From 5890f70f15c52d0204a578422f8da828a0ba1096 Mon Sep 17 00:00:00 2001 From: Leonid Yegoshin Date: Tue, 15 Jul 2014 14:09:56 +0100 Subject: MIPS: Use dedicated exception handler if CPU supports RI/XI exceptions Use the regular tlb_do_page_fault_0 (no write) handler to handle the RI and XI exceptions. Also skip the RI/XI validation check on TLB load handler since it's redundant when the CPU has unique RI/XI exceptions. Singed-off-by: Leonid Yegoshin Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7339/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 7 +++++++ arch/mips/mm/tlbex.c | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 51706d6dd5b0..1a328b1e288b 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -90,6 +90,7 @@ extern asmlinkage void handle_mt(void); extern asmlinkage void handle_dsp(void); extern asmlinkage void handle_mcheck(void); extern asmlinkage void handle_reserved(void); +extern void tlb_do_page_fault_0(void); void (*board_be_init)(void); int (*board_be_handler)(struct pt_regs *regs, int is_fixup); @@ -2114,6 +2115,12 @@ void __init trap_init(void) set_except_vector(15, handle_fpe); set_except_vector(16, handle_ftlb); + + if (cpu_has_rixiex) { + set_except_vector(19, tlb_do_page_fault_0); + set_except_vector(20, tlb_do_page_fault_0); + } + set_except_vector(21, handle_msa); set_except_vector(22, handle_mdmx); diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 0d9d0f06dbb2..ccf8298e7ab2 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -1919,7 +1919,7 @@ static void build_r4000_tlb_load_handler(void) if (m4kc_tlbp_war()) build_tlb_probe_entry(&p); - if (cpu_has_rixi) { + if (cpu_has_rixi && !cpu_has_rixiex) { /* * If the page is not _PAGE_VALID, RI or XI could not * have triggered it. Skip the expensive test.. @@ -1986,7 +1986,7 @@ static void build_r4000_tlb_load_handler(void) build_pte_present(&p, &r, wr.r1, wr.r2, wr.r3, label_nopage_tlbl); build_tlb_probe_entry(&p); - if (cpu_has_rixi) { + if (cpu_has_rixi && !cpu_has_rixiex) { /* * If the page is not _PAGE_VALID, RI or XI could not * have triggered it. Skip the expensive test.. -- cgit v1.2.3 From 6575b1d4173eaeff6742a2c6dcbd835bb052952b Mon Sep 17 00:00:00 2001 From: Leonid Yegoshin Date: Tue, 15 Jul 2014 14:09:57 +0100 Subject: MIPS: kernel: cpu-probe: Detect unique RI/XI exceptions Detect if the core supports unique exception codes for the Read-Inhibit and Execute-Inhibit exceptions and set the option accordingly. The RI/XI exception support is detected by setting the 27th bit (IEC) of the PageGrain C0 register and reading back the value of that register to verify the bit is enabled. Signed-off-by: Leonid Yegoshin Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7340/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mipsregs.h | 1 + arch/mips/kernel/cpu-probe.c | 9 +++++++++ 2 files changed, 10 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 417125548bde..9775c1aba4d3 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -265,6 +265,7 @@ #define PG_XIE (_ULCAST_(1) << 30) #define PG_ELPA (_ULCAST_(1) << 29) #define PG_ESP (_ULCAST_(1) << 28) +#define PG_IEC (_ULCAST_(1) << 27) /* * R4x00 interrupt enable / cause bits diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 0d30433db54b..cd252fd684b7 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -438,6 +438,15 @@ static void decode_configs(struct cpuinfo_mips *c) mips_probe_watch_registers(c); + if (cpu_has_rixi) { + /* Enable the RIXI exceptions */ + write_c0_pagegrain(read_c0_pagegrain() | PG_IEC); + back_to_back_c0_hazard(); + /* Verify the IEC bit is set */ + if (read_c0_pagegrain() & PG_IEC) + c->options |= MIPS_CPU_RIXIEX; + } + #ifndef CONFIG_MIPS_CPS if (cpu_has_mips_r2) { c->core = get_ebase_cpunum(); -- cgit v1.2.3 From 822350bc90c5069e9ab39f8720e2ef06af736124 Mon Sep 17 00:00:00 2001 From: Jeffrey Deans Date: Thu, 17 Jul 2014 09:20:53 +0100 Subject: MIPS: GIC: move GIC interrupt bitmap declarations Several bitmaps are declared in arch/mips/include/asm/gic.h, but the scope of their use is limited to arch/mips/kernel/irq-gic.c. Move the declarations from the header file to the C file. Signed-off-by: Jeffrey Deans Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7372/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/gic.h | 12 ------------ arch/mips/kernel/irq-gic.c | 12 ++++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h index 10f6a99f92c2..5b0e6a4b2c30 100644 --- a/arch/mips/include/asm/gic.h +++ b/arch/mips/include/asm/gic.h @@ -306,18 +306,6 @@ GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_VPE_REG_OFF(intr, vpe)), \ GIC_SH_MAP_TO_VPE_REG_BIT(vpe)) -struct gic_pcpu_mask { - DECLARE_BITMAP(pcpu_mask, GIC_NUM_INTRS); -}; - -struct gic_pending_regs { - DECLARE_BITMAP(pending, GIC_NUM_INTRS); -}; - -struct gic_intrmask_regs { - DECLARE_BITMAP(intrmask, GIC_NUM_INTRS); -}; - /* * Interrupt Meta-data specification. The ipiflag helps * in building ipi_map. diff --git a/arch/mips/kernel/irq-gic.c b/arch/mips/kernel/irq-gic.c index 88e4c323382c..a1dea3ea59a0 100644 --- a/arch/mips/kernel/irq-gic.c +++ b/arch/mips/kernel/irq-gic.c @@ -28,6 +28,18 @@ unsigned int gic_irq_flags[GIC_NUM_INTRS]; /* The index into this array is the vector # of the interrupt. */ struct gic_shared_intr_map gic_shared_intr_map[GIC_NUM_INTRS]; +struct gic_pcpu_mask { + DECLARE_BITMAP(pcpu_mask, GIC_NUM_INTRS); +}; + +struct gic_pending_regs { + DECLARE_BITMAP(pending, GIC_NUM_INTRS); +}; + +struct gic_intrmask_regs { + DECLARE_BITMAP(intrmask, GIC_NUM_INTRS); +}; + static struct gic_pcpu_mask pcpu_masks[NR_CPUS]; static struct gic_pending_regs pending_regs[NR_CPUS]; static struct gic_intrmask_regs intrmask_regs[NR_CPUS]; -- cgit v1.2.3 From b0a88ae50220b60d6e9686fc5f5a200151217037 Mon Sep 17 00:00:00 2001 From: Jeffrey Deans Date: Thu, 17 Jul 2014 09:20:55 +0100 Subject: MIPS: GIC: Remove GIC_FLAG_IPI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit irq-gic.c:gic_get_int() masks out interrupts from the pending set which aren’t in the pcpu_mask. Only interrupts marked with GIC_FLAG_IPI were set in pcpu_mask, meaning that peripheral interrupts also had to be marked as IPIs. Remove the use of GIC_FLAG_IPI and allow the flags member of struct gic_intr_map to be zero. Signed-off-by: Jeffrey Deans Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7374/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/gic.h | 3 +-- arch/mips/kernel/irq-gic.c | 7 +++---- arch/mips/mti-malta/malta-int.c | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h index 80804c16bb9d..394d366b8fc1 100644 --- a/arch/mips/include/asm/gic.h +++ b/arch/mips/include/asm/gic.h @@ -317,8 +317,7 @@ struct gic_intr_map { unsigned int polarity; /* Polarity : +/- */ unsigned int trigtype; /* Trigger : Edge/Levl */ unsigned int flags; /* Misc flags */ -#define GIC_FLAG_IPI 0x01 -#define GIC_FLAG_TRANSPARENT 0x02 +#define GIC_FLAG_TRANSPARENT 0x01 }; /* diff --git a/arch/mips/kernel/irq-gic.c b/arch/mips/kernel/irq-gic.c index a1dea3ea59a0..71cf45a335b6 100644 --- a/arch/mips/kernel/irq-gic.c +++ b/arch/mips/kernel/irq-gic.c @@ -311,9 +311,10 @@ static void __init gic_setup_intr(unsigned int intr, unsigned int cpu, /* Init Intr Masks */ GIC_CLR_INTR_MASK(intr); + /* Initialise per-cpu Interrupt software masks */ - if (flags & GIC_FLAG_IPI) - set_bit(intr, pcpu_masks[cpu].pcpu_mask); + set_bit(intr, pcpu_masks[cpu].pcpu_mask); + if ((flags & GIC_FLAG_TRANSPARENT) && (cpu_has_veic == 0)) GIC_SET_INTR_MASK(intr); if (trigtype == GIC_TRIG_EDGE) @@ -352,8 +353,6 @@ static void __init gic_basic_init(int numintrs, int numvpes, cpu = intrmap[i].cpunum; if (cpu == GIC_UNUSED) continue; - if (cpu == 0 && i != 0 && intrmap[i].flags == 0) - continue; gic_setup_intr(i, intrmap[i].cpunum, intrmap[i].pin + pin_offset, diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c index ecc2785f7858..4ab919141737 100644 --- a/arch/mips/mti-malta/malta-int.c +++ b/arch/mips/mti-malta/malta-int.c @@ -427,7 +427,7 @@ static void __init fill_ipi_map1(int baseintr, int cpu, int cpupin) gic_intr_map[intr].pin = cpupin; gic_intr_map[intr].polarity = GIC_POL_POS; gic_intr_map[intr].trigtype = GIC_TRIG_EDGE; - gic_intr_map[intr].flags = GIC_FLAG_IPI; + gic_intr_map[intr].flags = 0; ipi_map[cpu] |= (1 << (cpupin + 2)); } -- cgit v1.2.3 From 6096e114f5f70d29d9e01e031f69d529b2193ab7 Mon Sep 17 00:00:00 2001 From: Jeffrey Deans Date: Thu, 17 Jul 2014 09:20:56 +0100 Subject: MIPS: GIC: Prevent array overrun A GIC interrupt which is declared as having a GIC_MAP_TO_NMI_MSK mapping causes the cpu parameter to gic_setup_intr() to be increased to 32, causing memory corruption when pcpu_masks[] is written to again later in the function. Signed-off-by: Jeffrey Deans Signed-off-by: Markos Chandras Cc: stable@vger.kernel.org Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7375/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/irq-gic.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/irq-gic.c b/arch/mips/kernel/irq-gic.c index 71cf45a335b6..9932aef91abb 100644 --- a/arch/mips/kernel/irq-gic.c +++ b/arch/mips/kernel/irq-gic.c @@ -281,11 +281,13 @@ static void __init gic_setup_intr(unsigned int intr, unsigned int cpu, /* Setup Intr to Pin mapping */ if (pin & GIC_MAP_TO_NMI_MSK) { + int i; + GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), pin); /* FIXME: hack to route NMI to all cpu's */ - for (cpu = 0; cpu < NR_CPUS; cpu += 32) { + for (i = 0; i < NR_CPUS; i += 32) { GICWRITE(GIC_REG_ADDR(SHARED, - GIC_SH_MAP_TO_VPE_REG_OFF(intr, cpu)), + GIC_SH_MAP_TO_VPE_REG_OFF(intr, i)), 0xffffffff); } } else { -- cgit v1.2.3 From 31521a7a64bc5df5202e479ee7ba8133993ab32a Mon Sep 17 00:00:00 2001 From: Jeffrey Deans Date: Thu, 17 Jul 2014 09:20:57 +0100 Subject: MIPS: GIC: Generalise check for pending interrupts Move most of the functionality of gic_get_int() into a new function gic_get_int_mask() which takes a bitmask of interrupts in which the caller is interested, and returns the subset which are pending for the current CPU. This allows CP0 IRQ dispatch routines to check only the GIC interrupts which are routed to a particular CPU interrupt input. gic_get_int() is reimplemented using gic_get_int_mask() and is retained for use by any platforms for which gic_get_int() is sufficient. Signed-off-by: Jeffrey Deans Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7376/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/gic.h | 1 + arch/mips/kernel/irq-gic.c | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h index 394d366b8fc1..8b30befd99d6 100644 --- a/arch/mips/include/asm/gic.h +++ b/arch/mips/include/asm/gic.h @@ -373,6 +373,7 @@ extern unsigned int plat_ipi_call_int_xlate(unsigned int); extern unsigned int plat_ipi_resched_int_xlate(unsigned int); extern void gic_bind_eic_interrupt(int irq, int set); extern unsigned int gic_get_timer_pending(void); +extern void gic_get_int_mask(unsigned long *dst, const unsigned long *src); extern unsigned int gic_get_int(void); extern void gic_enable_interrupt(int irq_vec); extern void gic_disable_interrupt(int irq_vec); diff --git a/arch/mips/kernel/irq-gic.c b/arch/mips/kernel/irq-gic.c index 9932aef91abb..9e9d8b9a5b97 100644 --- a/arch/mips/kernel/irq-gic.c +++ b/arch/mips/kernel/irq-gic.c @@ -189,7 +189,7 @@ unsigned int gic_compare_int(void) return 0; } -unsigned int gic_get_int(void) +void gic_get_int_mask(unsigned long *dst, const unsigned long *src) { unsigned int i; unsigned long *pending, *intrmask, *pcpu_mask; @@ -214,8 +214,17 @@ unsigned int gic_get_int(void) bitmap_and(pending, pending, intrmask, GIC_NUM_INTRS); bitmap_and(pending, pending, pcpu_mask, GIC_NUM_INTRS); + bitmap_and(dst, src, pending, GIC_NUM_INTRS); +} + +unsigned int gic_get_int(void) +{ + DECLARE_BITMAP(interrupts, GIC_NUM_INTRS); + + bitmap_fill(interrupts, GIC_NUM_INTRS); + gic_get_int_mask(interrupts, interrupts); - return find_first_bit(pending, GIC_NUM_INTRS); + return find_first_bit(interrupts, GIC_NUM_INTRS); } static void gic_mask_irq(struct irq_data *d) -- cgit v1.2.3 From f7a46fa7bb0047d3e226702a0c4b786862fe6843 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 11 Jul 2014 16:44:28 +0100 Subject: MIPS: save/restore MSACSR register on context switch I added a field for the MSACSR register in struct mips_fpu_struct, but never actually made use of it... This is a clear bug. Save and restore the MSACSR register along with the vector registers. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7300/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/asmmacro.h | 11 +++++++++++ arch/mips/kernel/asm-offsets.c | 1 + 2 files changed, 12 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/include/asm/asmmacro.h b/arch/mips/include/asm/asmmacro.h index 935543f14538..4986bf5ffd29 100644 --- a/arch/mips/include/asm/asmmacro.h +++ b/arch/mips/include/asm/asmmacro.h @@ -10,6 +10,7 @@ #include #include +#include #ifdef CONFIG_32BIT #include @@ -378,9 +379,19 @@ st_d 29, THREAD_FPR29, \thread st_d 30, THREAD_FPR30, \thread st_d 31, THREAD_FPR31, \thread + .set push + .set noat + cfcmsa $1, MSA_CSR + sw $1, THREAD_MSA_CSR(\thread) + .set pop .endm .macro msa_restore_all thread + .set push + .set noat + lw $1, THREAD_MSA_CSR(\thread) + ctcmsa MSA_CSR, $1 + .set pop ld_d 0, THREAD_FPR0, \thread ld_d 1, THREAD_FPR1, \thread ld_d 2, THREAD_FPR2, \thread diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index 4bb5107511e2..b1d84bd4efb3 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -234,6 +234,7 @@ void output_thread_fpu_defines(void) thread.fpu.fpr[31].val64[FPR_IDX(64, 0)]); OFFSET(THREAD_FCR31, task_struct, thread.fpu.fcr31); + OFFSET(THREAD_MSA_CSR, task_struct, thread.fpu.msacsr); BLANK(); } -- cgit v1.2.3 From b83406735a4ae0aff4b614664d6a64a0fd6b9917 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 11 Jul 2014 16:44:29 +0100 Subject: MIPS: preserve scalar FP CSR when switching vector context Switching the vector context implicitly saves & restores the state of the aliased scalar FP data registers, however the scalar FP control & status register is distinct from the MSA control & status register. In order to allow scalar FP to function correctly in programs using MSA, the scalar CSR needs to be saved & restored along with the MSA vector context. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7301/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/r4k_switch.S | 4 +++- arch/mips/kernel/traps.c | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index 81ca3f70fe29..1a1aef04312d 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S @@ -64,8 +64,10 @@ /* Check whether we're saving scalar or vector context. */ bgtz a3, 1f - /* Save 128b MSA vector context. */ + /* Save 128b MSA vector context + scalar FP control & status. */ + cfc1 t1, fcr31 msa_save_all a0 + sw t1, THREAD_FCR31(a0) b 2f 1: /* Save 32b/64b scalar FP context. */ diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 1a328b1e288b..649c151fe1db 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1154,6 +1154,11 @@ static int enable_restore_fp_context(int msa) /* We need to restore the vector context. */ restore_msa(current); + + /* Restore the scalar FP control & status register */ + if (!was_fpu_owner) + asm volatile("ctc1 %0, $31" : : "r"(current->thread.fpu.fcr31)); + return 0; } -- cgit v1.2.3 From c9017757c532d48bf43d6e7d3b7282443ad4207b Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 30 Jul 2014 08:53:20 +0100 Subject: MIPS: init upper 64b of vector registers when MSA is first used When a task first makes use of MSA we need to ensure that the upper 64b of the vector registers are set to some value such that no information can be leaked to it from the previous task to use MSA context on the CPU. The architecture formerly specified that these bits would be cleared to 0 when a scalar FP instructions wrote to the aliased FP registers, which would have implicitly handled this as the kernel restored scalar FP context. However more recent versions of the specification now state that the value of the bits in such cases is unpredictable. Initialise them explictly to be sure, and set all the bits to 1 rather than 0 for consistency with the least significant 64b. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7497/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/asmmacro.h | 20 ++++++++++++++++++++ arch/mips/include/asm/msa.h | 1 + arch/mips/kernel/r4k_switch.S | 5 +++++ arch/mips/kernel/traps.c | 39 ++++++++++++++++++++++++++++++--------- 4 files changed, 56 insertions(+), 9 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/include/asm/asmmacro.h b/arch/mips/include/asm/asmmacro.h index 4986bf5ffd29..cd9a98bc8f60 100644 --- a/arch/mips/include/asm/asmmacro.h +++ b/arch/mips/include/asm/asmmacro.h @@ -426,4 +426,24 @@ ld_d 31, THREAD_FPR31, \thread .endm + .macro msa_init_upper wd +#ifdef CONFIG_64BIT + insert_d \wd, 1 +#else + insert_w \wd, 2 + insert_w \wd, 3 +#endif + .if 31-\wd + msa_init_upper (\wd+1) + .endif + .endm + + .macro msa_init_all_upper + .set push + .set noat + not $1, zero + msa_init_upper 0 + .set pop + .endm + #endif /* _ASM_ASMMACRO_H */ diff --git a/arch/mips/include/asm/msa.h b/arch/mips/include/asm/msa.h index e80e85c1334f..fe25a17bc783 100644 --- a/arch/mips/include/asm/msa.h +++ b/arch/mips/include/asm/msa.h @@ -16,6 +16,7 @@ extern void _save_msa(struct task_struct *); extern void _restore_msa(struct task_struct *); +extern void _init_msa_upper(void); static inline void enable_msa(void) { diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index 1a1aef04312d..4c4ec1812420 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S @@ -144,6 +144,11 @@ LEAF(_restore_msa) jr ra END(_restore_msa) +LEAF(_init_msa_upper) + msa_init_all_upper + jr ra + END(_init_msa_upper) + #endif /* diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 649c151fe1db..1ed84577d3e3 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1089,13 +1089,15 @@ static int default_cu2_call(struct notifier_block *nfb, unsigned long action, static int enable_restore_fp_context(int msa) { - int err, was_fpu_owner; + int err, was_fpu_owner, prior_msa; if (!used_math()) { /* First time FP context user. */ err = init_fpu(); - if (msa && !err) + if (msa && !err) { enable_msa(); + _init_msa_upper(); + } if (!err) set_used_math(); return err; @@ -1147,18 +1149,37 @@ static int enable_restore_fp_context(int msa) /* * If this is the first time that the task is using MSA and it has * previously used scalar FP in this time slice then we already nave - * FP context which we shouldn't clobber. + * FP context which we shouldn't clobber. We do however need to clear + * the upper 64b of each vector register so that this task has no + * opportunity to see data left behind by another. */ - if (!test_and_set_thread_flag(TIF_MSA_CTX_LIVE) && was_fpu_owner) + prior_msa = test_and_set_thread_flag(TIF_MSA_CTX_LIVE); + if (!prior_msa && was_fpu_owner) { + _init_msa_upper(); return 0; + } - /* We need to restore the vector context. */ - restore_msa(current); + if (!prior_msa) { + /* + * Restore the least significant 64b of each vector register + * from the existing scalar FP context. + */ + _restore_fp(current); - /* Restore the scalar FP control & status register */ - if (!was_fpu_owner) - asm volatile("ctc1 %0, $31" : : "r"(current->thread.fpu.fcr31)); + /* + * The task has not formerly used MSA, so clear the upper 64b + * of each vector register such that it cannot see data left + * behind by another task. + */ + _init_msa_upper(); + } else { + /* We need to restore the vector context. */ + restore_msa(current); + /* Restore the scalar FP control & status register */ + if (!was_fpu_owner) + asm volatile("ctc1 %0, $31" : : "r"(current->thread.fpu.fcr31)); + } return 0; } -- cgit v1.2.3 From 732c0c3c70869af53654db2b56dffdd8d4df5211 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Thu, 31 Jul 2014 14:53:16 +0100 Subject: MIPS: fix MSA context for tasks which don't use FP first If a task does not execute scalar FP instructions prior to using MSA then the flags indicating that the task has live MSA context were not being set. The upper 64b of each vector register would then be lost upon the tasks first context switch after using MSA. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7500/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 1ed84577d3e3..4716b89543a9 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1097,6 +1097,8 @@ static int enable_restore_fp_context(int msa) if (msa && !err) { enable_msa(); _init_msa_upper(); + set_thread_flag(TIF_USEDMSA); + set_thread_flag(TIF_MSA_CTX_LIVE); } if (!err) set_used_math(); -- cgit v1.2.3 From 3587ea888b8ed0a3d7e792738b4db687d9e7f73b Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 11 Jul 2014 16:44:34 +0100 Subject: MIPS: ensure MSA gets disabled during boot The kernel relies upon MSA being disabled when a task begins running, so that it can initialise or restore context in response to the resulting MSA disabled exception. Previously the state of MSA following boot was left as it was before the kernel ran, where MSA could potentially have been enabled. Explicitly disable it during boot to prevent any problems. As a nice side effect the code reads a little better too. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7306/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index cd252fd684b7..66b8fe97f739 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -144,14 +144,13 @@ static inline int __cpu_has_fpu(void) static inline unsigned long cpu_get_msa_id(void) { - unsigned long status, conf5, msa_id; + unsigned long status, msa_id; status = read_c0_status(); __enable_fpu(FPU_64BIT); - conf5 = read_c0_config5(); enable_msa(); msa_id = read_msa_ir(); - write_c0_config5(conf5); + disable_msa(); write_c0_status(status); return msa_id; } -- cgit v1.2.3 From 762a1f4388a22690cd4f848ba858e5f02d4bfc22 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 11 Jul 2014 16:44:35 +0100 Subject: MIPS: disable preemption whilst initialising MSA Preemption must be disabled throughout the process of enabling the FPU, enabling MSA & initialising the vector registers. Without doing so it is possible to lose the FPU or MSA whilst initialising them causing that initialisation to fail. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7307/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/fpu.h | 4 ---- arch/mips/kernel/traps.c | 14 +++++++++++--- 2 files changed, 11 insertions(+), 7 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/include/asm/fpu.h b/arch/mips/include/asm/fpu.h index 71d97ebd9090..4d0aeda68397 100644 --- a/arch/mips/include/asm/fpu.h +++ b/arch/mips/include/asm/fpu.h @@ -164,8 +164,6 @@ static inline int init_fpu(void) { int ret = 0; - preempt_disable(); - if (cpu_has_fpu) { ret = __own_fpu(); if (!ret) @@ -173,8 +171,6 @@ static inline int init_fpu(void) } else fpu_emulator_init_fpu(); - preempt_enable(); - return ret; } diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 4716b89543a9..22b19c275044 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1093,6 +1093,7 @@ static int enable_restore_fp_context(int msa) if (!used_math()) { /* First time FP context user. */ + preempt_disable(); err = init_fpu(); if (msa && !err) { enable_msa(); @@ -1100,6 +1101,7 @@ static int enable_restore_fp_context(int msa) set_thread_flag(TIF_USEDMSA); set_thread_flag(TIF_MSA_CTX_LIVE); } + preempt_enable(); if (!err) set_used_math(); return err; @@ -1139,10 +1141,11 @@ static int enable_restore_fp_context(int msa) * This task is using or has previously used MSA. Thus we require * that Status.FR == 1. */ + preempt_disable(); was_fpu_owner = is_fpu_owner(); - err = own_fpu(0); + err = own_fpu_inatomic(0); if (err) - return err; + goto out; enable_msa(); write_msa_csr(current->thread.fpu.msacsr); @@ -1158,7 +1161,8 @@ static int enable_restore_fp_context(int msa) prior_msa = test_and_set_thread_flag(TIF_MSA_CTX_LIVE); if (!prior_msa && was_fpu_owner) { _init_msa_upper(); - return 0; + + goto out; } if (!prior_msa) { @@ -1182,6 +1186,10 @@ static int enable_restore_fp_context(int msa) if (!was_fpu_owner) asm volatile("ctc1 %0, $31" : : "r"(current->thread.fpu.fcr31)); } + +out: + preempt_enable(); + return 0; } -- cgit v1.2.3 From 7daef8f261e509bea79ea3b0076e624135259bc1 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 11 Jul 2014 16:47:05 +0100 Subject: MIPS: consistently clear MSA flags when starting & copying threads The TIF_MSA_CTX_LIVE flag (indicating that a task has MSA context which needs to be preserved) was being cleared in start_thread, but the TIF_USEDMSA flag (indicating that a task has used MSA in this timeslice) was not. In copy_thread neither flag was cleared, but both need to be. Without clearing these flags the kernel will proceed to attempt to save MSA context when the task is context switched out, and if the task had not used MSA in the meantime then it will fail because MSA or the FPU are disabled. The end result is typically: do_cpu invoked from kernel context![#1]: CPU: 0 PID: 99 Comm: sh Not tainted 3.16.0-rc4-00025-g6dc9476-dirty #88 task: 8f23dc60 ti: 8f1d8000 task.ti: 8f1d8000 ... Call Trace: [<8010edbc>] resume+0x5c/0x280 [<80481e0c>] __schedule+0x370/0x800 [<80104838>] work_resched+0x8/0x2c Fix by consistently clearing both flags in both functions. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7309/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/process.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 2dafceb0d0c6..636b0745d7c7 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -66,6 +66,7 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) clear_used_math(); clear_fpu_owner(); init_dsp(); + clear_thread_flag(TIF_USEDMSA); clear_thread_flag(TIF_MSA_CTX_LIVE); disable_msa(); regs->cp0_epc = pc; @@ -141,6 +142,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, childregs->cp0_status &= ~(ST0_CU2|ST0_CU1); clear_tsk_thread_flag(p, TIF_USEDFPU); + clear_tsk_thread_flag(p, TIF_USEDMSA); + clear_tsk_thread_flag(p, TIF_MSA_CTX_LIVE); #ifdef CONFIG_MIPS_MT_FPAFF clear_tsk_thread_flag(p, TIF_FPUBOUND); -- cgit v1.2.3 From 1f6c52ff7225789d20c1d69883f263d502b7eda7 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 14 Jul 2014 10:32:14 +0100 Subject: MIPS: detect presence of MAARs Detect the presence of MAAR using the MRP bit in Config5, and record that presence using a CPU option bit. A cpu_has_maar macro will then allow code to conditionalise upon the presence of MAARs. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7330/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/cpu-features.h | 3 +++ arch/mips/include/asm/cpu.h | 1 + arch/mips/kernel/cpu-probe.c | 2 ++ 3 files changed, 6 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h index eeb5400ed4ee..e079598ae051 100644 --- a/arch/mips/include/asm/cpu-features.h +++ b/arch/mips/include/asm/cpu-features.h @@ -35,6 +35,9 @@ #ifndef cpu_has_rixiex #define cpu_has_rixiex (cpu_data[0].options & MIPS_CPU_RIXIEX) #endif +#ifndef cpu_has_maar +#define cpu_has_maar (cpu_data[0].options & MIPS_CPU_MAAR) +#endif /* * For the moment we don't consider R6000 and R8000 so we can assume that diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index 7ba2a035ad86..dfdc77ed1839 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -367,6 +367,7 @@ enum cpu_type_enum { #define MIPS_CPU_EVA 0x80000000ull /* CPU supports Enhanced Virtual Addressing */ #define MIPS_CPU_HTW 0x100000000ull /* CPU support Hardware Page Table Walker */ #define MIPS_CPU_RIXIEX 0x200000000ull /* CPU has unique exception codes for {Read, Execute}-Inhibit exceptions */ +#define MIPS_CPU_MAAR 0x400000000ull /* MAAR(I) registers are present */ /* * CPU ASE encodings diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 66b8fe97f739..e34b10be782e 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -405,6 +405,8 @@ static inline unsigned int decode_config5(struct cpuinfo_mips *c) if (config5 & MIPS_CONF5_EVA) c->options |= MIPS_CPU_EVA; + if (config5 & MIPS_CONF5_MRP) + c->options |= MIPS_CPU_MAAR; return config5 & MIPS_CONF_M; } -- cgit v1.2.3 From 81d103bf80678669c56658185e758fc3f9845d71 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Sun, 6 Oct 2013 22:25:42 +0200 Subject: mips: Use get_signal() signal_setup_done() Use the more generic functions get_signal() signal_setup_done() for signal delivery. Signed-off-by: Richard Weinberger --- arch/mips/include/asm/abi.h | 10 +++--- arch/mips/kernel/signal-common.h | 2 +- arch/mips/kernel/signal.c | 66 +++++++++++++++------------------------- arch/mips/kernel/signal32.c | 39 +++++++++--------------- arch/mips/kernel/signal_n32.c | 20 +++++------- 5 files changed, 53 insertions(+), 84 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/include/asm/abi.h b/arch/mips/include/asm/abi.h index 909bb6984866..7186bb51b89b 100644 --- a/arch/mips/include/asm/abi.h +++ b/arch/mips/include/asm/abi.h @@ -13,13 +13,11 @@ #include struct mips_abi { - int (* const setup_frame)(void *sig_return, struct k_sigaction *ka, - struct pt_regs *regs, int signr, - sigset_t *set); + int (* const setup_frame)(void *sig_return, struct ksignal *ksig, + struct pt_regs *regs, sigset_t *set); const unsigned long signal_return_offset; - int (* const setup_rt_frame)(void *sig_return, struct k_sigaction *ka, - struct pt_regs *regs, int signr, - sigset_t *set, siginfo_t *info); + int (* const setup_rt_frame)(void *sig_return, struct ksignal *ksig, + struct pt_regs *regs, sigset_t *set); const unsigned long rt_signal_return_offset; const unsigned long restart; }; diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index 9c60d09e62a7..06805e09bcd3 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h @@ -22,7 +22,7 @@ /* * Determine which stack to use.. */ -extern void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, +extern void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size); /* Check and clear pending FPU exceptions in saved CSR */ extern int fpcsr_pending(unsigned int __user *fpcsr); diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 9e60d117e41e..da4baac8652c 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -428,20 +428,20 @@ badframe: } #ifdef CONFIG_TRAD_SIGNALS -static int setup_frame(void *sig_return, struct k_sigaction *ka, - struct pt_regs *regs, int signr, sigset_t *set) +static int setup_frame(void *sig_return, struct ksignal *ksig, + struct pt_regs *regs, sigset_t *set) { struct sigframe __user *frame; int err = 0; - frame = get_sigframe(ka, regs, sizeof(*frame)); + frame = get_sigframe(&ksig->ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) - goto give_sigsegv; + return -EFAULT; err |= setup_sigcontext(regs, &frame->sf_sc); err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); if (err) - goto give_sigsegv; + return -EFAULT; /* * Arguments to signal handler: @@ -453,37 +453,32 @@ static int setup_frame(void *sig_return, struct k_sigaction *ka, * $25 and c0_epc point to the signal handler, $29 points to the * struct sigframe. */ - regs->regs[ 4] = signr; + regs->regs[ 4] = ksig->sig; regs->regs[ 5] = 0; regs->regs[ 6] = (unsigned long) &frame->sf_sc; regs->regs[29] = (unsigned long) frame; regs->regs[31] = (unsigned long) sig_return; - regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; + regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler; DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", current->comm, current->pid, frame, regs->cp0_epc, regs->regs[31]); return 0; - -give_sigsegv: - force_sigsegv(signr, current); - return -EFAULT; } #endif -static int setup_rt_frame(void *sig_return, struct k_sigaction *ka, - struct pt_regs *regs, int signr, sigset_t *set, - siginfo_t *info) +static int setup_rt_frame(void *sig_return, struct ksignal *ksig, + struct pt_regs *regs, sigset_t *set) { struct rt_sigframe __user *frame; int err = 0; - frame = get_sigframe(ka, regs, sizeof(*frame)); + frame = get_sigframe(&ksig->ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) - goto give_sigsegv; + return -EFAULT; /* Create siginfo. */ - err |= copy_siginfo_to_user(&frame->rs_info, info); + err |= copy_siginfo_to_user(&frame->rs_info, &ksig->info); /* Create the ucontext. */ err |= __put_user(0, &frame->rs_uc.uc_flags); @@ -493,7 +488,7 @@ static int setup_rt_frame(void *sig_return, struct k_sigaction *ka, err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set)); if (err) - goto give_sigsegv; + return -EFAULT; /* * Arguments to signal handler: @@ -505,22 +500,18 @@ static int setup_rt_frame(void *sig_return, struct k_sigaction *ka, * $25 and c0_epc point to the signal handler, $29 points to * the struct rt_sigframe. */ - regs->regs[ 4] = signr; + regs->regs[ 4] = ksig->sig; regs->regs[ 5] = (unsigned long) &frame->rs_info; regs->regs[ 6] = (unsigned long) &frame->rs_uc; regs->regs[29] = (unsigned long) frame; regs->regs[31] = (unsigned long) sig_return; - regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; + regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler; DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", current->comm, current->pid, frame, regs->cp0_epc, regs->regs[31]); return 0; - -give_sigsegv: - force_sigsegv(signr, current); - return -EFAULT; } struct mips_abi mips_abi = { @@ -534,8 +525,7 @@ struct mips_abi mips_abi = { .restart = __NR_restart_syscall }; -static void handle_signal(unsigned long sig, siginfo_t *info, - struct k_sigaction *ka, struct pt_regs *regs) +static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) { sigset_t *oldset = sigmask_to_save(); int ret; @@ -557,7 +547,7 @@ static void handle_signal(unsigned long sig, siginfo_t *info, regs->regs[2] = EINTR; break; case ERESTARTSYS: - if (!(ka->sa.sa_flags & SA_RESTART)) { + if (!(ksig->ka.sa.sa_flags & SA_RESTART)) { regs->regs[2] = EINTR; break; } @@ -571,29 +561,23 @@ static void handle_signal(unsigned long sig, siginfo_t *info, regs->regs[0] = 0; /* Don't deal with this again. */ } - if (sig_uses_siginfo(ka)) + if (sig_uses_siginfo(&ksig->ka)) ret = abi->setup_rt_frame(vdso + abi->rt_signal_return_offset, - ka, regs, sig, oldset, info); + ksig, regs, oldset); else - ret = abi->setup_frame(vdso + abi->signal_return_offset, - ka, regs, sig, oldset); - - if (ret) - return; + ret = abi->setup_frame(vdso + abi->signal_return_offset, ksig, + regs, oldset); - signal_delivered(sig, info, ka, regs, 0); + signal_setup_done(ret, ksig, 0); } static void do_signal(struct pt_regs *regs) { - struct k_sigaction ka; - siginfo_t info; - int signr; + struct ksignal ksig; - signr = get_signal_to_deliver(&info, &ka, regs, NULL); - if (signr > 0) { + if (get_signal(&ksig)) { /* Whee! Actually deliver the signal. */ - handle_signal(signr, &info, &ka, regs); + handle_signal(&ksig, regs); return; } diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index bae2e6ee2109..eb8d0e26404d 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -490,21 +490,21 @@ badframe: force_sig(SIGSEGV, current); } -static int setup_frame_32(void *sig_return, struct k_sigaction *ka, - struct pt_regs *regs, int signr, sigset_t *set) +static int setup_frame_32(void *sig_return, struct ksignal *ksig, + struct pt_regs *regs, sigset_t *set) { struct sigframe32 __user *frame; int err = 0; - frame = get_sigframe(ka, regs, sizeof(*frame)); + frame = get_sigframe(&ksig->ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) - goto give_sigsegv; + return -EFAULT; err |= setup_sigcontext32(regs, &frame->sf_sc); err |= __copy_conv_sigset_to_user(&frame->sf_mask, set); if (err) - goto give_sigsegv; + return -EFAULT; /* * Arguments to signal handler: @@ -516,37 +516,32 @@ static int setup_frame_32(void *sig_return, struct k_sigaction *ka, * $25 and c0_epc point to the signal handler, $29 points to the * struct sigframe. */ - regs->regs[ 4] = signr; + regs->regs[ 4] = ksig->sig; regs->regs[ 5] = 0; regs->regs[ 6] = (unsigned long) &frame->sf_sc; regs->regs[29] = (unsigned long) frame; regs->regs[31] = (unsigned long) sig_return; - regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; + regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler; DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", current->comm, current->pid, frame, regs->cp0_epc, regs->regs[31]); return 0; - -give_sigsegv: - force_sigsegv(signr, current); - return -EFAULT; } -static int setup_rt_frame_32(void *sig_return, struct k_sigaction *ka, - struct pt_regs *regs, int signr, sigset_t *set, - siginfo_t *info) +static int setup_rt_frame_32(void *sig_return, struct ksignal *ksig, + struct pt_regs *regs, sigset_t *set) { struct rt_sigframe32 __user *frame; int err = 0; - frame = get_sigframe(ka, regs, sizeof(*frame)); + frame = get_sigframe(&ksig->ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) - goto give_sigsegv; + return -EFAULT; /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */ - err |= copy_siginfo_to_user32(&frame->rs_info, info); + err |= copy_siginfo_to_user32(&frame->rs_info, &ksig->info); /* Create the ucontext. */ err |= __put_user(0, &frame->rs_uc.uc_flags); @@ -556,7 +551,7 @@ static int setup_rt_frame_32(void *sig_return, struct k_sigaction *ka, err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set); if (err) - goto give_sigsegv; + return -EFAULT; /* * Arguments to signal handler: @@ -568,22 +563,18 @@ static int setup_rt_frame_32(void *sig_return, struct k_sigaction *ka, * $25 and c0_epc point to the signal handler, $29 points to * the struct rt_sigframe32. */ - regs->regs[ 4] = signr; + regs->regs[ 4] = ksig->sig; regs->regs[ 5] = (unsigned long) &frame->rs_info; regs->regs[ 6] = (unsigned long) &frame->rs_uc; regs->regs[29] = (unsigned long) frame; regs->regs[31] = (unsigned long) sig_return; - regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; + regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler; DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", current->comm, current->pid, frame, regs->cp0_epc, regs->regs[31]); return 0; - -give_sigsegv: - force_sigsegv(signr, current); - return -EFAULT; } /* diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index b2241bb9cac1..7d04f2868ba6 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -102,18 +102,18 @@ badframe: force_sig(SIGSEGV, current); } -static int setup_rt_frame_n32(void *sig_return, struct k_sigaction *ka, - struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info) +static int setup_rt_frame_n32(void *sig_return, struct ksignal *ksig, + struct pt_regs *regs, sigset_t *set) { struct rt_sigframe_n32 __user *frame; int err = 0; - frame = get_sigframe(ka, regs, sizeof(*frame)); + frame = get_sigframe(&ksig->ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) - goto give_sigsegv; + return -EFAULT; /* Create siginfo. */ - err |= copy_siginfo_to_user32(&frame->rs_info, info); + err |= copy_siginfo_to_user32(&frame->rs_info, &ksig->info); /* Create the ucontext. */ err |= __put_user(0, &frame->rs_uc.uc_flags); @@ -123,7 +123,7 @@ static int setup_rt_frame_n32(void *sig_return, struct k_sigaction *ka, err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set); if (err) - goto give_sigsegv; + return -EFAULT; /* * Arguments to signal handler: @@ -135,22 +135,18 @@ static int setup_rt_frame_n32(void *sig_return, struct k_sigaction *ka, * $25 and c0_epc point to the signal handler, $29 points to * the struct rt_sigframe. */ - regs->regs[ 4] = signr; + regs->regs[ 4] = ksig->sig; regs->regs[ 5] = (unsigned long) &frame->rs_info; regs->regs[ 6] = (unsigned long) &frame->rs_uc; regs->regs[29] = (unsigned long) frame; regs->regs[31] = (unsigned long) sig_return; - regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; + regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler; DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", current->comm, current->pid, frame, regs->cp0_epc, regs->regs[31]); return 0; - -give_sigsegv: - force_sigsegv(signr, current); - return -EFAULT; } struct mips_abi mips_abi_n32 = { -- cgit v1.2.3 From 7c4f563507c33ca97dcfbd62dba1e9232575d499 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Wed, 5 Mar 2014 15:35:41 +0100 Subject: mips: Use sigsp() Use sigsp() instead of the open coded variant. Signed-off-by: Richard Weinberger --- arch/mips/kernel/signal.c | 10 ++++------ arch/mips/kernel/signal32.c | 4 ++-- arch/mips/kernel/signal_n32.c | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index da4baac8652c..1d57605e4615 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -280,7 +280,7 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) return err; } -void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, +void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size) { unsigned long sp; @@ -295,9 +295,7 @@ void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, */ sp -= 32; - /* This is the X/Open sanctioned signal stack switching. */ - if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) - sp = current->sas_ss_sp + current->sas_ss_size; + sp = sigsp(sp, ksig); return (void __user *)((sp - frame_size) & (ICACHE_REFILLS_WORKAROUND_WAR ? ~(cpu_icache_line_size()-1) : ALMASK)); } @@ -434,7 +432,7 @@ static int setup_frame(void *sig_return, struct ksignal *ksig, struct sigframe __user *frame; int err = 0; - frame = get_sigframe(&ksig->ka, regs, sizeof(*frame)); + frame = get_sigframe(ksig, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) return -EFAULT; @@ -473,7 +471,7 @@ static int setup_rt_frame(void *sig_return, struct ksignal *ksig, struct rt_sigframe __user *frame; int err = 0; - frame = get_sigframe(&ksig->ka, regs, sizeof(*frame)); + frame = get_sigframe(ksig, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) return -EFAULT; diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index eb8d0e26404d..d69179c0d49d 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -496,7 +496,7 @@ static int setup_frame_32(void *sig_return, struct ksignal *ksig, struct sigframe32 __user *frame; int err = 0; - frame = get_sigframe(&ksig->ka, regs, sizeof(*frame)); + frame = get_sigframe(ksig, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) return -EFAULT; @@ -536,7 +536,7 @@ static int setup_rt_frame_32(void *sig_return, struct ksignal *ksig, struct rt_sigframe32 __user *frame; int err = 0; - frame = get_sigframe(&ksig->ka, regs, sizeof(*frame)); + frame = get_sigframe(ksig, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) return -EFAULT; diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index 7d04f2868ba6..f1d4751eead0 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -108,7 +108,7 @@ static int setup_rt_frame_n32(void *sig_return, struct ksignal *ksig, struct rt_sigframe_n32 __user *frame; int err = 0; - frame = get_sigframe(&ksig->ka, regs, sizeof(*frame)); + frame = get_sigframe(ksig, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) return -EFAULT; -- cgit v1.2.3 From 91ffaa27834b69dc23dfe14a0358f1c70d2938e2 Mon Sep 17 00:00:00 2001 From: Yang Wei Date: Thu, 31 Jul 2014 19:42:29 +0800 Subject: MIPS: kdump: Set correct value to kexec_indirection_page variable Since there is not indirection page in crash type, so the vaule of the head field of kimage structure is not equal to the address of indirection page but IND_DONE. so we have to set kexec_indirection_page variable to the address of the head field of image structure. [ralf@linux-mips.org: Don't add pointless empty line, fix trailing whitespace damage.] Signed-off-by: Yang Wei Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/7499/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/machine_kexec.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/machine_kexec.c b/arch/mips/kernel/machine_kexec.c index 992e18474da5..50980bf3983e 100644 --- a/arch/mips/kernel/machine_kexec.c +++ b/arch/mips/kernel/machine_kexec.c @@ -71,8 +71,12 @@ machine_kexec(struct kimage *image) kexec_start_address = (unsigned long) phys_to_virt(image->start); - kexec_indirection_page = - (unsigned long) phys_to_virt(image->head & PAGE_MASK); + if (image->type == KEXEC_TYPE_DEFAULT) { + kexec_indirection_page = + (unsigned long) phys_to_virt(image->head & PAGE_MASK); + } else { + kexec_indirection_page = (unsigned long)&image->head; + } memcpy((void*)reboot_code_buffer, relocate_new_kernel, relocate_new_kernel_size); -- cgit v1.2.3 From 014365f5831dc993ac02b8871a165c9a7bde56cc Mon Sep 17 00:00:00 2001 From: Yang Wei Date: Tue, 5 Aug 2014 13:37:47 +0800 Subject: MIPS: perf: Mark pmu interupt IRQF_NO_THREAD In RT kernel, I ran into the following calltrace, so PMU interrupts cannot be threaded in_atomic(): 1, irqs_disabled(): 1, pid: 0, name: swapper/0 INFO: lockdep is turned off. Call Trace: [] dump_stack+0x1c/0x50 [] __might_sleep+0x13c/0x148 [] rt_spin_lock+0x3c/0xb0 [] __wake_up+0x3c/0x80 [] perf_event_wakeup+0x8c/0xf8 [] perf_pending_event+0x40/0x78 [] irq_work_run+0x74/0xc0 [] mipsxx_pmu_handle_shared_irq+0x110/0x228 [] mipsxx_pmu_handle_irq+0x14/0x30 [] handle_irq_event_percpu+0xbc/0x470 [] handle_percpu_irq+0x98/0xc8 [] generic_handle_irq+0x4c/0x68 [] do_IRQ+0x2c/0x48 [] plat_irq_dispatch+0x64/0xd0 [ralf@linux-mips.org: I don't see why based on this register dump the handler should be marked IRQF_NO_THREAD - but the handler is manipulating per-CPU resources so we don't want it to be rescheduled to another CPU.] Signed-off-by: Yang Wei Cc: a.p.zijlstra@chello.nl Cc: paulus@samba.org Cc: mingo@redhat.com Cc: acme@kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7506/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/perf_event_mipsxx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c index 14bf74b0f51c..b63f2482f288 100644 --- a/arch/mips/kernel/perf_event_mipsxx.c +++ b/arch/mips/kernel/perf_event_mipsxx.c @@ -558,7 +558,7 @@ static int mipspmu_get_irq(void) if (mipspmu.irq >= 0) { /* Request my own irq handler. */ err = request_irq(mipspmu.irq, mipsxx_pmu_handle_irq, - IRQF_PERCPU | IRQF_NOBALANCING, + IRQF_PERCPU | IRQF_NOBALANCING | IRQF_NO_THREAD, "mips_perf_pmu", NULL); if (err) { pr_warning("Unable to request IRQ%d for MIPS " -- cgit v1.2.3 From ad61ba23f192f6d87a4e1f665f2d92ba2bae0950 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 24 Jul 2014 12:10:02 +0100 Subject: MIPS: scall64-o32: Fix indirect syscall detection Commit 4c21b8fd8f14 (MIPS: seccomp: Handle indirect system calls (o32)) added indirect syscall detection for O32 processes running on MIPS64 but it did not work as expected. The reason is the the scall64-o32 implementation differs compared to scall32-o32. In the former, the v0 (syscall number) register contains the absolute syscall number (4000 + X) whereas in the latter it contains the relative syscall number (X). Fix the code to avoid doing an extra addition, and load the v0 register directly to the first argument for syscall_trace_enter. Moreover, set the .reorder assembler option in order to have better control on this part of the assembly code. Signed-off-by: Markos Chandras Patchwork: http://patchwork.linux-mips.org/patch/7481/ Cc: # v3.15+ Signed-off-by: James Hogan --- arch/mips/kernel/scall64-o32.S | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 13b964fddc4a..25bb8400156d 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -113,15 +113,19 @@ trace_a_syscall: move s0, t2 # Save syscall pointer move a0, sp /* - * syscall number is in v0 unless we called syscall(__NR_###) + * absolute syscall number is in v0 unless we called syscall(__NR_###) * where the real syscall number is in a0 * note: NR_syscall is the first O32 syscall but the macro is * only defined when compiling with -mabi=32 (CONFIG_32BIT) * therefore __NR_O32_Linux is used (4000) */ - addiu a1, v0, __NR_O32_Linux - bnez v0, 1f /* __NR_syscall at offset 0 */ - lw a1, PT_R4(sp) + .set push + .set reorder + subu t1, v0, __NR_O32_Linux + move a1, v0 + bnez t1, 1f /* __NR_syscall at offset 0 */ + lw a1, PT_R4(sp) /* Arg1 for __NR_syscall case */ + .set pop 1: jal syscall_trace_enter -- cgit v1.2.3 From 56d2960958f81db9cfd488e530d2206edede5f8f Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Mon, 21 Jul 2014 14:35:56 +0100 Subject: MIPS: CPS: Initialize EVA before bringing up VPEs from secondary cores The CPS code is doing several memory loads when configuring the VPEs from secondary cores, so the segmentation control registers must be initialized in time otherwise the kernel will crash with strange TLB exceptions. Reviewed-by: Paul Burton Signed-off-by: Markos Chandras Patchwork: http://patchwork.linux-mips.org/patch/7424/ Signed-off-by: James Hogan --- arch/mips/kernel/cps-vec.S | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index 6f4f739dad96..e6e97d2a5c9e 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -166,6 +167,9 @@ dcache_done: 1: jal mips_cps_core_init nop + /* Do any EVA initialization if necessary */ + eva_init + /* * Boot any other VPEs within this core that should be online, and * deactivate this VPE if it should be offline. -- cgit v1.2.3 From 42944521af97a3b25516f15f3149aec3779656dc Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 26 Aug 2014 03:03:40 +0200 Subject: MIPS: Wire up new syscalls getrandom and memfd_create. Signed-off-by: Ralf Baechle --- arch/mips/include/uapi/asm/unistd.h | 18 ++++++++++++------ arch/mips/kernel/scall32-o32.S | 2 ++ arch/mips/kernel/scall64-64.S | 2 ++ arch/mips/kernel/scall64-n32.S | 2 ++ arch/mips/kernel/scall64-o32.S | 2 ++ 5 files changed, 20 insertions(+), 6 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/include/uapi/asm/unistd.h b/arch/mips/include/uapi/asm/unistd.h index 9bc13eaf9d67..fdb4923777d1 100644 --- a/arch/mips/include/uapi/asm/unistd.h +++ b/arch/mips/include/uapi/asm/unistd.h @@ -373,16 +373,18 @@ #define __NR_sched_getattr (__NR_Linux + 350) #define __NR_renameat2 (__NR_Linux + 351) #define __NR_seccomp (__NR_Linux + 352) +#define __NR_getrandom (__NR_Linux + 353) +#define __NR_memfd_create (__NR_Linux + 354) /* * Offset of the last Linux o32 flavoured syscall */ -#define __NR_Linux_syscalls 352 +#define __NR_Linux_syscalls 354 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ #define __NR_O32_Linux 4000 -#define __NR_O32_Linux_syscalls 352 +#define __NR_O32_Linux_syscalls 354 #if _MIPS_SIM == _MIPS_SIM_ABI64 @@ -703,16 +705,18 @@ #define __NR_sched_getattr (__NR_Linux + 310) #define __NR_renameat2 (__NR_Linux + 311) #define __NR_seccomp (__NR_Linux + 312) +#define __NR_getrandom (__NR_Linux + 313) +#define __NR_memfd_create (__NR_Linux + 314) /* * Offset of the last Linux 64-bit flavoured syscall */ -#define __NR_Linux_syscalls 312 +#define __NR_Linux_syscalls 314 #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */ #define __NR_64_Linux 5000 -#define __NR_64_Linux_syscalls 312 +#define __NR_64_Linux_syscalls 314 #if _MIPS_SIM == _MIPS_SIM_NABI32 @@ -1037,15 +1041,17 @@ #define __NR_sched_getattr (__NR_Linux + 314) #define __NR_renameat2 (__NR_Linux + 315) #define __NR_seccomp (__NR_Linux + 316) +#define __NR_getrandom (__NR_Linux + 317) +#define __NR_memfd_create (__NR_Linux + 318) /* * Offset of the last N32 flavoured syscall */ -#define __NR_Linux_syscalls 316 +#define __NR_Linux_syscalls 318 #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */ #define __NR_N32_Linux 6000 -#define __NR_N32_Linux_syscalls 316 +#define __NR_N32_Linux_syscalls 318 #endif /* _UAPI_ASM_UNISTD_H */ diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index f93b4cbec739..744cd10ba599 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -577,3 +577,5 @@ EXPORT(sys_call_table) PTR sys_sched_getattr /* 4350 */ PTR sys_renameat2 PTR sys_seccomp + PTR sys_getrandom + PTR sys_memfd_create diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index 03ebd9979ad2..002b1bc09c38 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -432,4 +432,6 @@ EXPORT(sys_call_table) PTR sys_sched_getattr /* 5310 */ PTR sys_renameat2 PTR sys_seccomp + PTR sys_getrandom + PTR sys_memfd_create .size sys_call_table,.-sys_call_table diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index ebc9228e2e15..ca6cbbe9805b 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -425,4 +425,6 @@ EXPORT(sysn32_call_table) PTR sys_sched_getattr PTR sys_renameat2 /* 6315 */ PTR sys_seccomp + PTR sys_getrandom + PTR sys_memfd_create .size sysn32_call_table,.-sysn32_call_table diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 25bb8400156d..9e10d11fbb84 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -562,4 +562,6 @@ EXPORT(sys32_call_table) PTR sys_sched_getattr /* 4350 */ PTR sys_renameat2 PTR sys_seccomp + PTR sys_getrandom + PTR sys_memfd_create .size sys32_call_table,.-sys32_call_table -- cgit v1.2.3 From 8a574cfa2652545eb95595d38ac2a0bb501af0ae Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Tue, 16 Sep 2014 15:55:12 +0100 Subject: MIPS: mcount: Adjust stack pointer for static trace in MIPS32 Every mcount() call in the MIPS 32-bit kernel is done as follows: [...] move at, ra jal _mcount addiu sp, sp, -8 [...] but upon returning from the mcount() function, the stack pointer is not adjusted properly. This is explained in details in 58b69401c797 (MIPS: Function tracer: Fix broken function tracing). Commit ad8c396936e3 ("MIPS: Unbreak function tracer for 64-bit kernel.) fixed the stack manipulation for 64-bit but it didn't fix it completely for MIPS32. Signed-off-by: Markos Chandras Cc: Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7792/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/mcount.S | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/mcount.S b/arch/mips/kernel/mcount.S index 5d25462de8a6..2f7c734771f4 100644 --- a/arch/mips/kernel/mcount.S +++ b/arch/mips/kernel/mcount.S @@ -129,7 +129,11 @@ NESTED(_mcount, PT_SIZE, ra) nop #endif b ftrace_stub +#ifdef CONFIG_32BIT + addiu sp, sp, 8 +#else nop +#endif static_trace: MCOUNT_SAVE_REGS @@ -139,6 +143,9 @@ static_trace: move a1, AT /* arg2: parent's return address */ MCOUNT_RESTORE_REGS +#ifdef CONFIG_32BIT + addiu sp, sp, 8 +#endif .globl ftrace_stub ftrace_stub: RETURN_BACK @@ -183,6 +190,11 @@ NESTED(ftrace_graph_caller, PT_SIZE, ra) jal prepare_ftrace_return nop MCOUNT_RESTORE_REGS +#ifndef CONFIG_DYNAMIC_FTRACE +#ifdef CONFIG_32BIT + addiu sp, sp, 8 +#endif +#endif RETURN_BACK END(ftrace_graph_caller) -- cgit v1.2.3