From 75dcfc1d678d76a82288c043bfd5bfc0fbd43b49 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 22 Sep 2015 10:10:55 -0700 Subject: MIPS: Declare mips_debugfs_dir in a header We have many extern declarations of mips_debugfs_dir through arch/mips/ in various C files. Unify them by declaring mips_debugfs_dir in a header, including it in each affected C file & removing the duplicate declarations. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Steven J. Hill Cc: Alexander Sverdlin Cc: Masahiro Yamada Cc: Leonid Yegoshin Cc: Maciej W. Rozycki Cc: linux-kernel@vger.kernel.org Cc: Joe Perches Cc: Jaedon Shin Cc: James Hogan Cc: David Daney Cc: Zubair Lutfullah Kakakhel Cc: Markos Chandras Cc: James Cowgill Patchwork: https://patchwork.linux-mips.org/patch/11181/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/mips-r2-to-r6-emul.c | 2 +- arch/mips/kernel/segment.c | 2 +- arch/mips/kernel/setup.c | 1 + arch/mips/kernel/spinlock_test.c | 4 +--- arch/mips/kernel/unaligned.c | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c index f2977f00911b..1f5aac7f9ec3 100644 --- a/arch/mips/kernel/mips-r2-to-r6-emul.c +++ b/arch/mips/kernel/mips-r2-to-r6-emul.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -2363,7 +2364,6 @@ static const struct file_operations mipsr2_clear_fops = { static int __init mipsr2_init_debugfs(void) { - extern struct dentry *mips_debugfs_dir; struct dentry *mipsr2_emul; if (!mips_debugfs_dir) diff --git a/arch/mips/kernel/segment.c b/arch/mips/kernel/segment.c index 076ead2a9859..87bc74a5a518 100644 --- a/arch/mips/kernel/segment.c +++ b/arch/mips/kernel/segment.c @@ -10,6 +10,7 @@ #include #include #include +#include #include static void build_segment_config(char *str, unsigned int cfg) @@ -91,7 +92,6 @@ static const struct file_operations segments_fops = { static int __init segments_info(void) { - extern struct dentry *mips_debugfs_dir; struct dentry *segments; if (cpu_has_segments) { diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 479515109e5b..5b46b672c939 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/mips/kernel/spinlock_test.c b/arch/mips/kernel/spinlock_test.c index 39f7ab7b0426..f7d86955d1b8 100644 --- a/arch/mips/kernel/spinlock_test.c +++ b/arch/mips/kernel/spinlock_test.c @@ -5,7 +5,7 @@ #include #include #include - +#include static int ss_get(void *data, u64 *val) { @@ -115,8 +115,6 @@ static int multi_get(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(fops_multi, multi_get, NULL, "%llu\n"); - -extern struct dentry *mips_debugfs_dir; static int __init spinlock_test(void) { struct dentry *d; diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 990354dd6bde..490cea569d57 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -85,6 +85,7 @@ #include #include #include +#include #include #include #include @@ -2295,7 +2296,6 @@ sigbus: } #ifdef CONFIG_DEBUG_FS -extern struct dentry *mips_debugfs_dir; static int __init debugfs_unaligned(void) { struct dentry *d; -- cgit v1.2.3 From a13c996249a5ca7635853a4e7e15033393575e46 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 22 Sep 2015 10:15:22 -0700 Subject: MIPS: traps: tidy up ebase calculation Rather than #ifdef on CONFIG_KVM_GUEST & redefine the guest kseg0 base locally, make use of the CAC_BASE macro which has the correct value in both cases. Signed-off-by: Paul Burton Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: Leonid Yegoshin Cc: Maciej W. Rozycki Cc: linux-kernel@vger.kernel.org Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/11183/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index fdb392b27e81..4e106d52f304 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -37,6 +37,7 @@ #include #include +#include #include #include #include @@ -2204,12 +2205,8 @@ void __init trap_init(void) ebase = (unsigned long) __alloc_bootmem(size, 1 << fls(size), 0); } else { -#ifdef CONFIG_KVM_GUEST -#define KVM_GUEST_KSEG0 0x40000000 - ebase = KVM_GUEST_KSEG0; -#else - ebase = CKSEG0; -#endif + ebase = CAC_BASE; + if (cpu_has_mips_r2_r6) ebase += (read_c0_ebase() & 0x3ffff000); } -- cgit v1.2.3 From 03b1b85d3d6c4f4153472afb7e015f1352e0c8f2 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 22 Sep 2015 10:26:38 -0700 Subject: MIPS: Don't read GCRs when a CM is not present Commit 3885c2b463f6 ("MIPS: CM: Add support for reporting CM cache errors") leads to Malta boards unconditionally reading CM GCRs upon bus errors, regardless of whether a CM is present. This is incorrect & will lead to further exceptions. Fix by moving the GCR reads to after the check for whether a CM is present. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Markos Chandras Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/11186/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/mips-cm.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index b8ceee576cdf..10524ce769ae 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -252,7 +252,6 @@ int mips_cm_probe(void) void mips_cm_error_report(void) { - unsigned long revision = mips_cm_revision(); /* * CM3 has a 64-bit Error cause register with 0:57 containing the error * info and 63:58 the error type. For old CMs, everything is contained @@ -260,17 +259,21 @@ void mips_cm_error_report(void) * though the cm_error is u64, we will simply ignore the upper word * for CM2. */ - u64 cm_error = read_gcr_error_cause(); - int cm_error_cause_sft = CM_GCR_ERROR_CAUSE_ERRTYPE_SHF + - ((revision >= CM_REV_CM3) ? 31 : 0); - unsigned long cm_addr = read_gcr_error_addr(); - unsigned long cm_other = read_gcr_error_mult(); - int ocause, cause; + u64 cm_error; + unsigned long revision, cm_addr, cm_other; + int ocause, cause, cm_error_cause_sft; char buf[256]; if (!mips_cm_present()) return; + revision = mips_cm_revision(); + cm_error = read_gcr_error_cause(); + cm_addr = read_gcr_error_addr(); + cm_other = read_gcr_error_mult(); + + cm_error_cause_sft = CM_GCR_ERROR_CAUSE_ERRTYPE_SHF + + ((revision >= CM_REV_CM3) ? 31 : 0); cause = cm_error >> cm_error_cause_sft; if (!cause) -- cgit v1.2.3 From f88e632480baf223cad67ac553a6729535db6d74 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 22 Sep 2015 10:26:39 -0700 Subject: MIPS: Avoid buffer overrun in mips_cm_error_report Commit 3885c2b463f6 ("MIPS: CM: Add support for reporting CM cache errors") added cases for decoding errors reported by CM3, but leaves the buf variable which is printed as a string uninitialised for cause values other than 1, 2 or 3. Fix by ensuring the buf variable is initialised to an empty string in such cases. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Markos Chandras Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/11187/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/mips-cm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index 10524ce769ae..88a8e21a51dd 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -366,6 +366,8 @@ void mips_cm_error_report(void) cm3_cmd_group[cmd_group_bits], cm3_cca_bits, 1 << mcp_bits, cm3_tr[cm3_tr_bits], sched_bit); + } else { + buf[0] = 0; } pr_err("CM_ERROR=%llx %s <%s>\n", cm_error, -- cgit v1.2.3 From 47b26a467dc7dacbeae9240af5a35fc2fec48650 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 22 Sep 2015 10:26:41 -0700 Subject: MIPS: Always read full 64 bit CM error GCRs for CM3 CM3 has 64 bit GCR_ERROR_* registers, but the code in mips_cm_error_report was previously only reading 32 bits of it in MIPS32 kernels. Fix by splitting the reads for CM2 & CM3, and making use of the read64_ variants of the accessor function for CM3. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: James Hogan Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/11189/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/mips-cm.c | 70 ++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 34 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index 88a8e21a51dd..02f7d7a41133 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -252,36 +252,26 @@ int mips_cm_probe(void) void mips_cm_error_report(void) { - /* - * CM3 has a 64-bit Error cause register with 0:57 containing the error - * info and 63:58 the error type. For old CMs, everything is contained - * in a single 32-bit register (0:26 and 31:27 respectively). Even - * though the cm_error is u64, we will simply ignore the upper word - * for CM2. - */ - u64 cm_error; - unsigned long revision, cm_addr, cm_other; - int ocause, cause, cm_error_cause_sft; + u64 cm_error, cm_addr, cm_other; + unsigned long revision; + int ocause, cause; char buf[256]; if (!mips_cm_present()) return; revision = mips_cm_revision(); - cm_error = read_gcr_error_cause(); - cm_addr = read_gcr_error_addr(); - cm_other = read_gcr_error_mult(); - cm_error_cause_sft = CM_GCR_ERROR_CAUSE_ERRTYPE_SHF + - ((revision >= CM_REV_CM3) ? 31 : 0); - cause = cm_error >> cm_error_cause_sft; + if (revision < CM_REV_CM3) { /* CM2 */ + cm_error = read_gcr_error_cause(); + cm_addr = read_gcr_error_addr(); + cm_other = read_gcr_error_mult(); + cause = cm_error >> CM_GCR_ERROR_CAUSE_ERRTYPE_SHF; + ocause = cm_other >> CM_GCR_ERROR_MULT_ERR2ND_SHF; - if (!cause) - /* All good */ - return; + if (!cause) + return; - ocause = cm_other >> CM_GCR_ERROR_MULT_ERR2ND_SHF; - if (revision < CM_REV_CM3) { /* CM2 */ if (cause < 16) { unsigned long cca_bits = (cm_error >> 15) & 7; unsigned long tr_bits = (cm_error >> 12) & 7; @@ -313,18 +303,30 @@ void mips_cm_error_report(void) } pr_err("CM_ERROR=%08llx %s <%s>\n", cm_error, cm2_causes[cause], buf); - pr_err("CM_ADDR =%08lx\n", cm_addr); - pr_err("CM_OTHER=%08lx %s\n", cm_other, cm2_causes[ocause]); + pr_err("CM_ADDR =%08llx\n", cm_addr); + pr_err("CM_OTHER=%08llx %s\n", cm_other, cm2_causes[ocause]); } else { /* CM3 */ - /* Used by cause == {1,2,3} */ - unsigned long core_id_bits = (cm_error >> 22) & 0xf; - unsigned long vp_id_bits = (cm_error >> 18) & 0xf; - unsigned long cmd_bits = (cm_error >> 14) & 0xf; - unsigned long cmd_group_bits = (cm_error >> 11) & 0xf; - unsigned long cm3_cca_bits = (cm_error >> 8) & 7; - unsigned long mcp_bits = (cm_error >> 5) & 0xf; - unsigned long cm3_tr_bits = (cm_error >> 1) & 0xf; - unsigned long sched_bit = cm_error & 0x1; + ulong core_id_bits, vp_id_bits, cmd_bits, cmd_group_bits; + ulong cm3_cca_bits, mcp_bits, cm3_tr_bits, sched_bit; + + cm_error = read64_gcr_error_cause(); + cm_addr = read64_gcr_error_addr(); + cm_other = read64_gcr_error_mult(); + cause = cm_error >> CM3_GCR_ERROR_CAUSE_ERRTYPE_SHF; + ocause = cm_other >> CM_GCR_ERROR_MULT_ERR2ND_SHF; + + if (!cause) + return; + + /* Used by cause == {1,2,3} */ + core_id_bits = (cm_error >> 22) & 0xf; + vp_id_bits = (cm_error >> 18) & 0xf; + cmd_bits = (cm_error >> 14) & 0xf; + cmd_group_bits = (cm_error >> 11) & 0xf; + cm3_cca_bits = (cm_error >> 8) & 7; + mcp_bits = (cm_error >> 5) & 0xf; + cm3_tr_bits = (cm_error >> 1) & 0xf; + sched_bit = cm_error & 0x1; if (cause == 1 || cause == 3) { /* Tag ECC */ unsigned long tag_ecc = (cm_error >> 57) & 0x1; @@ -372,8 +374,8 @@ void mips_cm_error_report(void) pr_err("CM_ERROR=%llx %s <%s>\n", cm_error, cm3_causes[cause], buf); - pr_err("CM_ADDR =%lx\n", cm_addr); - pr_err("CM_OTHER=%lx %s\n", cm_other, cm3_causes[ocause]); + pr_err("CM_ADDR =%llx\n", cm_addr); + pr_err("CM_OTHER=%llx %s\n", cm_other, cm3_causes[ocause]); } /* reprime cause register */ -- cgit v1.2.3 From b85ff244533fb4b88f34bcca55c194f142338c3f Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 22 Sep 2015 11:12:09 -0700 Subject: MIPS: CPS: Set Status.BEV bit during early boot Set the Status.BEV bit throughout the early startup of a secondary core such that if an exception occurs the core branches to one of the exception vector entries from cps-vec.S, rather than branching to whatever is set in EBase. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Markos Chandras Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/11200/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cps-vec.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index 209ded16806b..b3fdb2a6405e 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -71,7 +71,7 @@ not_nmi: mtc0 t0, CP0_CAUSE /* Setup Status */ - li t0, ST0_CU1 | ST0_CU0 + li t0, ST0_CU1 | ST0_CU0 | ST0_BEV mtc0 t0, CP0_STATUS /* -- cgit v1.2.3 From 8fe2c5478b11d407e3c19d96eb9c0bfe19ce5f8c Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 22 Sep 2015 11:12:10 -0700 Subject: MIPS: CPS: Set Status.KX on entry for MIPS64 kernels If the kernel may make use of 64 bit addresses outside of the compatibility address space then we need to set KX such that those accesses can succeed. Do so for MIPS64 kernels. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Markos Chandras Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/11201/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cps-vec.S | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index b3fdb2a6405e..f2663e460d37 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -25,6 +25,12 @@ .set noreorder +#ifdef CONFIG_64BIT +# define STATUS_BITDEPS ST0_KX +#else +# define STATUS_BITDEPS 0 +#endif + /* * Set dest to non-zero if the core supports the MT ASE, else zero. If * MT is not supported then branch to nomt. @@ -71,7 +77,7 @@ not_nmi: mtc0 t0, CP0_CAUSE /* Setup Status */ - li t0, ST0_CU1 | ST0_CU0 | ST0_BEV + li t0, ST0_CU1 | ST0_CU0 | ST0_BEV | STATUS_BITDEPS mtc0 t0, CP0_STATUS /* -- cgit v1.2.3 From 7963b3f127a7486815bc10639630c95c2792b811 Mon Sep 17 00:00:00 2001 From: Petri Gynther Date: Mon, 19 Oct 2015 11:49:52 -0700 Subject: MIPS: add nmi_enter() + nmi_exit() to nmi_exception_handler() We need to enter NMI context when NMI interrupt fires. Signed-off-by: Petri Gynther Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/11323/ 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 fdb392b27e81..efcedd43780f 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1856,12 +1856,14 @@ void __noreturn nmi_exception_handler(struct pt_regs *regs) { char str[100]; + nmi_enter(); raw_notifier_call_chain(&nmi_chain, 0, regs); bust_spinlocks(1); snprintf(str, 100, "CPU%d NMI taken, CP0_EPC=%lx\n", smp_processor_id(), regs->cp0_epc); regs->cp0_epc = read_c0_errorepc(); die(str, regs); + nmi_exit(); } #define VECTORSPACING 0x100 /* for EI/VI mode */ -- cgit v1.2.3 From adaa0b6c49795551b07576e952dfa94c3ccded51 Mon Sep 17 00:00:00 2001 From: Petri Gynther Date: Mon, 19 Oct 2015 11:44:24 -0700 Subject: MIPS: Switch BMIPS5000 to use r4k_wait_irqoff() BCM7425 CPU Interface Zephyr Processor, pages 5-309 and 5-310 BCM7428B0 CPU Interface Zephyr Processor, pages 5-337 and 5-338 WAIT instruction: Thread enters wait state. No instructions are executed until an interrupt occurs. The processor's clocks are stopped if both threads are in idle mode. Description: Execution of this instruction puts the thread into wait state, an idle mode in which no instructions are fetched or executed. The thread remains in wait state until an interrupt occurs that is not masked by the interrupt mask field in the Status register. Then, if interrupts are enabled by the IE bit in the Status register, the interrupt is serviced. The ERET instruction returns to the instruction following the WAIT instruction. If interrupts are disabled, the processor resumes executing instructions with the next sequential instruction. Programming notes: The WAIT instruction should be executed while interrupts are disabled by the IE bit in the Status register. This avoids a potential timing hazard, which occurs if an interrupt is taken between testing the counter and executing the WAIT instruction. In this hazard case, the interrupt will have been completed before the WAIT instruction is executed, so the processor will remain indefinitely in wait state until the next interrupt. Signed-off-by: Petri Gynther Reviewed-by: Florian Fainelli Cc: cernekee@gmail.com Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/11322/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/idle.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c index ab1478d5a4db..d636c70fef19 100644 --- a/arch/mips/kernel/idle.c +++ b/arch/mips/kernel/idle.c @@ -160,7 +160,6 @@ void __init check_wait(void) case CPU_BMIPS3300: case CPU_BMIPS4350: case CPU_BMIPS4380: - case CPU_BMIPS5000: case CPU_CAVIUM_OCTEON: case CPU_CAVIUM_OCTEON_PLUS: case CPU_CAVIUM_OCTEON2: @@ -171,7 +170,9 @@ void __init check_wait(void) case CPU_XLP: cpu_wait = r4k_wait; break; - + case CPU_BMIPS5000: + cpu_wait = r4k_wait_irqoff; + break; case CPU_RM7000: cpu_wait = rm7k_wait_irqoff; break; -- cgit v1.2.3 From 61379878320664ed44901b0537254e983fc7e4c4 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Fri, 30 Oct 2015 00:54:47 +0200 Subject: MIPS: vmlinux: discard .MIPS.abiflags Discard .MIPS.abiflags from vmlinux. It's not needed and will cause issues e.g. with old OCTEON bootloaders that cannot tolerate additional program headers. Before the patch: $ readelf --program-headers octeon-vmlinux Elf file type is EXEC (Executable file) Entry point 0xffffffff815d09d0 There are 3 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align ABIFLAGS 0x00000000005e77f0 0xffffffff816e67f0 0xffffffff816e67f0 0x0000000000000018 0x0000000000000018 R 8 LOAD 0x0000000000001000 0xffffffff81100000 0xffffffff81100000 0x0000000000b57f80 0x0000000001b86360 RWE 1000 NOTE 0x00000000004e02e0 0xffffffff815df2e0 0xffffffff815df2e0 0x0000000000000024 0x0000000000000024 R 4 After the patch: $ readelf --program-headers octeon-vmlinux Elf file type is EXEC (Executable file) Entry point 0xffffffff815d09d0 There are 2 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align LOAD 0x0000000000001000 0xffffffff81100000 0xffffffff81100000 0x0000000000b57f80 0x0000000001b86360 RWE 1000 NOTE 0x00000000004e02e0 0xffffffff815df2e0 0xffffffff815df2e0 0x0000000000000024 0x0000000000000024 R 4 Suggested-by: Matthew Fortune Suggested-by: Ralf Baechle Signed-off-by: Aaro Koskinen Cc: linux-mips@linux-mips.org Cc: David Daney Patchwork: https://patchwork.linux-mips.org/patch/11402/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/vmlinux.lds.S | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index 07d32a4aea60..06632d69ee5a 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -181,6 +181,7 @@ SECTIONS DISCARDS /DISCARD/ : { /* ABI crap starts here */ + *(.MIPS.abiflags) *(.MIPS.options) *(.options) *(.pdr) -- cgit v1.2.3 From 3bfb7224566593219dbd67474dacb23ef7c080e3 Mon Sep 17 00:00:00 2001 From: David Daney Date: Fri, 30 Oct 2015 00:54:48 +0200 Subject: MIPS: OCTEON: omit ELF NOTE segments OCTEON Pre-SDK-1.8.1 bootloaders can not handle PT_NOTE program headers, so do not emit them. Before the patch: $ readelf --program-headers octeon-vmlinux Elf file type is EXEC (Executable file) Entry point 0xffffffff815d09d0 There are 2 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align LOAD 0x0000000000001000 0xffffffff81100000 0xffffffff81100000 0x0000000000b57f80 0x0000000001b86360 RWE 1000 NOTE 0x00000000004e02e0 0xffffffff815df2e0 0xffffffff815df2e0 0x0000000000000024 0x0000000000000024 R 4 After the patch: $ readelf --program-headers octeon-vmlinux Elf file type is EXEC (Executable file) Entry point 0xffffffff815d09d0 There are 1 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align LOAD 0x0000000000001000 0xffffffff81100000 0xffffffff81100000 0x0000000000b57f80 0x0000000001b86360 RWE 1000 The patch was tested on DSR-1000N router. Signed-off-by: David Daney Signed-off-by: Aaro Koskinen Cc: Matthew Fortune Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/11403/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/vmlinux.lds.S | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index 06632d69ee5a..cce2fcb58881 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -17,7 +17,9 @@ OUTPUT_ARCH(mips) ENTRY(kernel_entry) PHDRS { text PT_LOAD FLAGS(7); /* RWX */ +#ifndef CONFIG_CAVIUM_OCTEON_SOC note PT_NOTE FLAGS(4); /* R__ */ +#endif /* CAVIUM_OCTEON_SOC */ } #ifdef CONFIG_32BIT @@ -71,7 +73,12 @@ SECTIONS __stop___dbe_table = .; } - NOTES :text :note +#ifdef CONFIG_CAVIUM_OCTEON_SOC +#define NOTES_HEADER +#else /* CONFIG_CAVIUM_OCTEON_SOC */ +#define NOTES_HEADER :note +#endif /* CONFIG_CAVIUM_OCTEON_SOC */ + NOTES :text NOTES_HEADER .dummy : { *(.dummy) } :text _sdata = .; /* Start of data section */ -- cgit v1.2.3 From 609cf6f2291a69d09aa5c02d74cd4488b19aa9a6 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 22 Sep 2015 11:12:11 -0700 Subject: MIPS: CPS: Early debug using an ns16550-compatible UART Provide support for outputting early debug information, in the form of various register values should an exception occur, during the early bringup of secondary cores. This code requires an ns16550-compatible UART accessible from the secondary core, and is written in assembly due to the environment in which such early exceptions occur where way may not have a stack, be coherent or even have initialised caches. [ralf@linux-mips.org: Fix merge conflict.] Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Steven J. Hill Cc: Andrew Bresticker Cc: Leonid Yegoshin Cc: Maciej W. Rozycki Cc: Jason Cooper Cc: linux-kernel@vger.kernel.org Cc: James Hogan Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/11202/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/Makefile | 1 + arch/mips/kernel/cps-vec-ns16550.S | 202 +++++++++++++++++++++++++++++++++++++ arch/mips/kernel/cps-vec.S | 20 ++++ 3 files changed, 223 insertions(+) create mode 100644 arch/mips/kernel/cps-vec-ns16550.S (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index d982be1ea1c3..68e2b7db9348 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o obj-$(CONFIG_MIPS_CMP) += smp-cmp.o obj-$(CONFIG_MIPS_CPS) += smp-cps.o cps-vec.o +obj-$(CONFIG_MIPS_CPS_NS16550) += cps-vec-ns16550.o obj-$(CONFIG_MIPS_GIC_IPI) += smp-gic.o obj-$(CONFIG_MIPS_SPRAM) += spram.o diff --git a/arch/mips/kernel/cps-vec-ns16550.S b/arch/mips/kernel/cps-vec-ns16550.S new file mode 100644 index 000000000000..6d246ad05638 --- /dev/null +++ b/arch/mips/kernel/cps-vec-ns16550.S @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2015 Imagination Technologies + * Author: Paul Burton + * + * 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 + +#define UART_TX_OFS (UART_TX << CONFIG_MIPS_CPS_NS16550_SHIFT) +#define UART_LSR_OFS (UART_LSR << CONFIG_MIPS_CPS_NS16550_SHIFT) + +/** + * _mips_cps_putc() - write a character to the UART + * @a0: ASCII character to write + * @t9: UART base address + */ +LEAF(_mips_cps_putc) +1: lw t0, UART_LSR_OFS(t9) + andi t0, t0, UART_LSR_TEMT + beqz t0, 1b + sb a0, UART_TX_OFS(t9) + jr ra + END(_mips_cps_putc) + +/** + * _mips_cps_puts() - write a string to the UART + * @a0: pointer to NULL-terminated ASCII string + * @t9: UART base address + * + * Write a null-terminated ASCII string to the UART. + */ +NESTED(_mips_cps_puts, 0, ra) + move s7, ra + move s6, a0 + +1: lb a0, 0(s6) + beqz a0, 2f + jal _mips_cps_putc + PTR_ADDIU s6, s6, 1 + b 1b + +2: jr s7 + END(_mips_cps_puts) + +/** + * _mips_cps_putx4 - write a 4b hex value to the UART + * @a0: the 4b value to write to the UART + * @t9: UART base address + * + * Write a single hexadecimal character to the UART. + */ +NESTED(_mips_cps_putx4, 0, ra) + andi a0, a0, 0xf + li t0, '0' + blt a0, 10, 1f + li t0, 'a' + addiu a0, a0, -10 +1: addu a0, a0, t0 + b _mips_cps_putc + END(_mips_cps_putx4) + +/** + * _mips_cps_putx8 - write an 8b hex value to the UART + * @a0: the 8b value to write to the UART + * @t9: UART base address + * + * Write an 8 bit value (ie. 2 hexadecimal characters) to the UART. + */ +NESTED(_mips_cps_putx8, 0, ra) + move s3, ra + move s2, a0 + srl a0, a0, 4 + jal _mips_cps_putx4 + move a0, s2 + move ra, s3 + b _mips_cps_putx4 + END(_mips_cps_putx8) + +/** + * _mips_cps_putx16 - write a 16b hex value to the UART + * @a0: the 16b value to write to the UART + * @t9: UART base address + * + * Write a 16 bit value (ie. 4 hexadecimal characters) to the UART. + */ +NESTED(_mips_cps_putx16, 0, ra) + move s5, ra + move s4, a0 + srl a0, a0, 8 + jal _mips_cps_putx8 + move a0, s4 + move ra, s5 + b _mips_cps_putx8 + END(_mips_cps_putx16) + +/** + * _mips_cps_putx32 - write a 32b hex value to the UART + * @a0: the 32b value to write to the UART + * @t9: UART base address + * + * Write a 32 bit value (ie. 8 hexadecimal characters) to the UART. + */ +NESTED(_mips_cps_putx32, 0, ra) + move s7, ra + move s6, a0 + srl a0, a0, 16 + jal _mips_cps_putx16 + move a0, s6 + move ra, s7 + b _mips_cps_putx16 + END(_mips_cps_putx32) + +#ifdef CONFIG_64BIT + +/** + * _mips_cps_putx64 - write a 64b hex value to the UART + * @a0: the 64b value to write to the UART + * @t9: UART base address + * + * Write a 64 bit value (ie. 16 hexadecimal characters) to the UART. + */ +NESTED(_mips_cps_putx64, 0, ra) + move sp, ra + move s8, a0 + dsrl32 a0, a0, 0 + jal _mips_cps_putx32 + move a0, s8 + move ra, sp + b _mips_cps_putx32 + END(_mips_cps_putx64) + +#define _mips_cps_putxlong _mips_cps_putx64 + +#else /* !CONFIG_64BIT */ + +#define _mips_cps_putxlong _mips_cps_putx32 + +#endif /* !CONFIG_64BIT */ + +/** + * mips_cps_bev_dump() - dump relevant exception state to UART + * @a0: pointer to NULL-terminated ASCII string naming the exception + * + * Write information that may be useful in debugging an exception to the + * UART configured by CONFIG_MIPS_CPS_NS16550_*. As this BEV exception + * will only be run if something goes horribly wrong very early during + * the bringup of a core and it is very likely to be unsafe to perform + * memory accesses at that point (cache state indeterminate, EVA may not + * be configured, coherence may be disabled) let alone have a stack, + * this is all written in assembly using only registers & unmapped + * uncached access to the UART registers. + */ +LEAF(mips_cps_bev_dump) + move s0, ra + move s1, a0 + + li t9, CKSEG1ADDR(CONFIG_MIPS_CPS_NS16550_BASE) + + PTR_LA a0, str_newline + jal _mips_cps_puts + PTR_LA a0, str_bev + jal _mips_cps_puts + move a0, s1 + jal _mips_cps_puts + PTR_LA a0, str_newline + jal _mips_cps_puts + PTR_LA a0, str_newline + jal _mips_cps_puts + +#define DUMP_COP0_REG(reg, name, sz, _mfc0) \ + PTR_LA a0, 8f; \ + jal _mips_cps_puts; \ + _mfc0 a0, reg; \ + jal _mips_cps_putx##sz; \ + PTR_LA a0, str_newline; \ + jal _mips_cps_puts; \ + TEXT(name) + + DUMP_COP0_REG(CP0_CAUSE, "Cause: 0x", 32, mfc0) + DUMP_COP0_REG(CP0_STATUS, "Status: 0x", 32, mfc0) + DUMP_COP0_REG(CP0_EBASE, "EBase: 0x", long, MFC0) + DUMP_COP0_REG(CP0_BADVADDR, "BadVAddr: 0x", long, MFC0) + DUMP_COP0_REG(CP0_BADINSTR, "BadInstr: 0x", 32, mfc0) + + PTR_LA a0, str_newline + jal _mips_cps_puts + jr s0 + END(mips_cps_bev_dump) + +.pushsection .data +str_bev: .asciiz "BEV Exception: " +str_newline: .asciiz "\r\n" +.popsection diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index f2663e460d37..b242ae3eb466 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -31,6 +31,20 @@ # define STATUS_BITDEPS 0 #endif +#ifdef CONFIG_MIPS_CPS_NS16550 + +#define DUMP_EXCEP(name) \ + PTR_LA a0, 8f; \ + jal mips_cps_bev_dump; \ + nop; \ + TEXT(name) + +#else /* !CONFIG_MIPS_CPS_NS16550 */ + +#define DUMP_EXCEP(name) + +#endif /* !CONFIG_MIPS_CPS_NS16550 */ + /* * Set dest to non-zero if the core supports the MT ASE, else zero. If * MT is not supported then branch to nomt. @@ -194,36 +208,42 @@ dcache_done: .org 0x200 LEAF(excep_tlbfill) + DUMP_EXCEP("TLB Fill") b . nop END(excep_tlbfill) .org 0x280 LEAF(excep_xtlbfill) + DUMP_EXCEP("XTLB Fill") b . nop END(excep_xtlbfill) .org 0x300 LEAF(excep_cache) + DUMP_EXCEP("Cache") b . nop END(excep_cache) .org 0x380 LEAF(excep_genex) + DUMP_EXCEP("General") b . nop END(excep_genex) .org 0x400 LEAF(excep_intex) + DUMP_EXCEP("Interrupt") b . nop END(excep_intex) .org 0x480 LEAF(excep_ejtag) + DUMP_EXCEP("EJTAG") PTR_LA k0, ejtag_debug_handler jr k0 nop -- cgit v1.2.3 From 946db17349f6922a9c8a959c34ad9fb3aa238952 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 22 Sep 2015 11:12:12 -0700 Subject: MIPS: CPS: Read CM GCR base from cop0 Rather than patching the start of mips_cps_core_entry to provide the base address of the CM GCRs, simply read that base address from the cop0 CMGCRBase register, converting from the physical address to an uncached virtual address. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Rusty Russell Cc: Andrew Bresticker Cc: linux-kernel@vger.kernel.org Cc: Niklas Cassel Cc: Ezequiel Garcia Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/11203/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cps-vec.S | 12 ++++++++---- arch/mips/kernel/smp-cps.c | 2 -- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index b242ae3eb466..2164dc4deace 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -67,11 +67,9 @@ LEAF(mips_cps_core_entry) /* - * These first 12 bytes will be patched by cps_smp_setup to load the - * base address of the CM GCRs into register v1 and the CCA to use into - * register s0. + * These first 4 bytes will be patched by cps_smp_setup to load the + * CCA to use into register s0. */ - .quad 0 .word 0 /* Check whether we're here due to an NMI */ @@ -171,6 +169,12 @@ dcache_done: mtc0 t0, CP0_CONFIG ehb + /* Calculate an uncached address for the CM GCRs */ + MFC0 v1, CP0_CMGCRBASE + PTR_SLL v1, v1, 4 + PTR_LI t0, UNCAC_BASE + PTR_ADDU v1, v1, t0 + /* Enter the coherent domain */ li t0, 0xff sw t0, GCR_CL_COHERENCE_OFS(v1) diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index c88937745b4e..8b967507e852 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -133,11 +133,9 @@ static void __init cps_prepare_cpus(unsigned int max_cpus) /* * Patch the start of mips_cps_core_entry to provide: * - * v1 = CM base address * s0 = kseg0 CCA */ 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); blast_dcache_range((unsigned long)&mips_cps_core_entry, (unsigned long)entry_code); -- cgit v1.2.3 From 192fbc20258c79e3f776a5ce6cea4654376f5af6 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 22 Sep 2015 11:12:13 -0700 Subject: MIPS: CPS: Skip Config1 presence check The Config1 register is architecturally defined as required, and is thus present in all systems which may make use of cps-vec.S. Skip the check for its presence via the Config.M bit. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Markos Chandras Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/11204/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cps-vec.S | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index 2164dc4deace..8fd5a276cad2 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -50,9 +50,7 @@ * MT is not supported then branch to nomt. */ .macro has_mt dest, nomt - mfc0 \dest, CP0_CONFIG - bgez \dest, \nomt - mfc0 \dest, CP0_CONFIG, 1 + mfc0 \dest, CP0_CONFIG, 1 bgez \dest, \nomt mfc0 \dest, CP0_CONFIG, 2 bgez \dest, \nomt -- cgit v1.2.3 From a8c20614b0163a71f2df3f9788bfe8b9ff07d742 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 22 Sep 2015 11:12:14 -0700 Subject: MIPS: CPS: Warn if a core doesn't start When debugging core bringup it is useful to see the state of the CPC sequencer, so output that value if the core hasn't started within a reasonable amount of time (1 second). This avoids simply appearing to the user to hang if a secondary core fails to start. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Rusty Russell Cc: Andrew Bresticker Cc: linux-kernel@vger.kernel.org Cc: Niklas Cassel Cc: Ezequiel Garcia Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/11205/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/smp-cps.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index 8b967507e852..48b1b7554f05 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -8,6 +8,7 @@ * option) any later version. */ +#include #include #include #include @@ -188,7 +189,8 @@ err_out: static void boot_core(unsigned core) { - u32 access; + u32 access, stat, seq_state; + unsigned timeout; /* Select the appropriate core */ write_gcr_cl_other(core << CM_GCR_Cx_OTHER_CORENUM_SHF); @@ -208,6 +210,28 @@ static void boot_core(unsigned core) /* Reset the core */ mips_cpc_lock_other(core); write_cpc_co_cmd(CPC_Cx_CMD_RESET); + + timeout = 100; + while (true) { + stat = read_cpc_co_stat_conf(); + seq_state = stat & CPC_Cx_STAT_CONF_SEQSTATE_MSK; + + /* U6 == coherent execution, ie. the core is up */ + if (seq_state == CPC_Cx_STAT_CONF_SEQSTATE_U6) + break; + + /* Delay a little while before we start warning */ + if (timeout) { + timeout--; + mdelay(10); + continue; + } + + pr_warn("Waiting for core %u to start... STAT_CONF=0x%x\n", + core, stat); + mdelay(1000); + } + mips_cpc_unlock_other(); } else { /* Take the core out of reset */ -- cgit v1.2.3 From 23d5de8efb9aed48074a72bf3d43841e1556ca42 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 22 Sep 2015 11:12:16 -0700 Subject: MIPS: CM: Introduce core-other locking functions Introduce mips_cm_lock_other & mips_cm_unlock_other, mirroring the existing CPC equivalents, in order to lock access from the current core to another via the core-other GCR region. This hasn't been required in the past but with CM3 the CPC starts using GCR_CL_OTHER rather than CPC_CL_OTHER and this will be required for safety. [ralf@linux-mips.org: Fix merge conflict.] Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: James Hogan Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/11207/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/mips-cm.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index 02f7d7a41133..01908dbdf677 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -9,6 +9,8 @@ */ #include +#include +#include #include #include @@ -136,6 +138,9 @@ static char *cm3_causes[32] = { "0x19", "0x1a", "0x1b", "0x1c", "0x1d", "0x1e", "0x1f" }; +static DEFINE_PER_CPU_ALIGNED(spinlock_t, cm_core_lock); +static DEFINE_PER_CPU_ALIGNED(unsigned long, cm_core_lock_flags); + phys_addr_t __mips_cm_phys_base(void) { u32 config3 = read_c0_config3(); @@ -200,6 +205,7 @@ int mips_cm_probe(void) { phys_addr_t addr; u32 base_reg; + unsigned cpu; /* * No need to probe again if we have already been @@ -247,9 +253,42 @@ int mips_cm_probe(void) /* determine register width for this CM */ mips_cm_is64 = config_enabled(CONFIG_64BIT) && (mips_cm_revision() >= CM_REV_CM3); + for_each_possible_cpu(cpu) + spin_lock_init(&per_cpu(cm_core_lock, cpu)); + return 0; } +void mips_cm_lock_other(unsigned int core, unsigned int vp) +{ + unsigned curr_core; + u32 val; + + preempt_disable(); + curr_core = current_cpu_data.core; + spin_lock_irqsave(&per_cpu(cm_core_lock, curr_core), + per_cpu(cm_core_lock_flags, curr_core)); + + if (mips_cm_revision() >= CM_REV_CM3) { + val = core << CM3_GCR_Cx_OTHER_CORE_SHF; + val |= vp << CM3_GCR_Cx_OTHER_VP_SHF; + } else { + BUG_ON(vp != 0); + val = core << CM_GCR_Cx_OTHER_CORENUM_SHF; + } + + write_gcr_cl_other(val); +} + +void mips_cm_unlock_other(void) +{ + unsigned curr_core = current_cpu_data.core; + + spin_unlock_irqrestore(&per_cpu(cm_core_lock, curr_core), + per_cpu(cm_core_lock_flags, curr_core)); + preempt_enable(); +} + void mips_cm_error_report(void) { u64 cm_error, cm_addr, cm_other; -- cgit v1.2.3 From 4ede31617056b7424eef28dce59dd6dbe81729c3 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 22 Sep 2015 11:12:17 -0700 Subject: MIPS: CM: make use of mips_cm_{lock,unlock}_other Document that CPC core-other accesses must take place within the bounds of the CM lock, and begin using the CM lock functions where we access the GCRs of other cores. This is required because with CM3 the CPC began using GCR_CL_OTHER instead of CPC_CL_OTHER. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Rusty Russell Cc: Andrew Bresticker Cc: Bjorn Helgaas Cc: linux-kernel@vger.kernel.org Cc: Niklas Cassel Cc: Ezequiel Garcia Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/11208/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/smp-cps.c | 7 +++++-- arch/mips/kernel/smp-gic.c | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index 48b1b7554f05..e04c8057b882 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -38,8 +38,9 @@ static unsigned core_vpe_count(unsigned core) if (!config_enabled(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt) return 1; - write_gcr_cl_other(core << CM_GCR_Cx_OTHER_CORENUM_SHF); + mips_cm_lock_other(core, 0); cfg = read_gcr_co_config() & CM_GCR_Cx_CONFIG_PVPE_MSK; + mips_cm_unlock_other(); return (cfg >> CM_GCR_Cx_CONFIG_PVPE_SHF) + 1; } @@ -193,7 +194,7 @@ static void boot_core(unsigned core) unsigned timeout; /* Select the appropriate core */ - write_gcr_cl_other(core << CM_GCR_Cx_OTHER_CORENUM_SHF); + mips_cm_lock_other(core, 0); /* Set its reset vector */ write_gcr_co_reset_base(CKSEG1ADDR((unsigned long)mips_cps_core_entry)); @@ -238,6 +239,8 @@ static void boot_core(unsigned core) write_gcr_co_reset_release(0); } + mips_cm_unlock_other(); + /* The core is now powered up */ bitmap_set(core_power, core, 1); } diff --git a/arch/mips/kernel/smp-gic.c b/arch/mips/kernel/smp-gic.c index 5f0ab5bcd01e..9b63829cf929 100644 --- a/arch/mips/kernel/smp-gic.c +++ b/arch/mips/kernel/smp-gic.c @@ -46,9 +46,11 @@ void gic_send_ipi_single(int cpu, unsigned int action) if (mips_cpc_present() && (core != current_cpu_data.core)) { while (!cpumask_test_cpu(cpu, &cpu_coherent_mask)) { + mips_cm_lock_other(core, 0); mips_cpc_lock_other(core); write_cpc_co_cmd(CPC_Cx_CMD_PWRUP); mips_cpc_unlock_other(); + mips_cm_unlock_other(); } } -- cgit v1.2.3 From 78a54c4d8e5a7915a4ec2ba0eb461fae50590683 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 22 Sep 2015 11:12:18 -0700 Subject: MIPS: CM, CPC: Ensure core-other GCRs reflect the correct core Ensure the update to which core the core-other GCR regions reflect has taken place before any core-other GCRs are accessed by placing a memory barrier (sync instruction) between the write to the core-other registers and any such GCR accesses. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Bjorn Helgaas Cc: linux-kernel@vger.kernel.org Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/11209/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/mips-cm.c | 6 ++++++ arch/mips/kernel/mips-cpc.c | 6 ++++++ 2 files changed, 12 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index 01908dbdf677..1448c1f43d4e 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -278,6 +278,12 @@ void mips_cm_lock_other(unsigned int core, unsigned int vp) } write_gcr_cl_other(val); + + /* + * Ensure the core-other region reflects the appropriate core & + * VP before any accesses to it occur. + */ + mb(); } void mips_cm_unlock_other(void) diff --git a/arch/mips/kernel/mips-cpc.c b/arch/mips/kernel/mips-cpc.c index 8af4d627b68b..566b8d2c092c 100644 --- a/arch/mips/kernel/mips-cpc.c +++ b/arch/mips/kernel/mips-cpc.c @@ -76,6 +76,12 @@ void mips_cpc_lock_other(unsigned int core) spin_lock_irqsave(&per_cpu(cpc_core_lock, curr_core), per_cpu(cpc_core_lock_flags, curr_core)); write_cpc_cl_other(core << CPC_Cx_OTHER_CORENUM_SHF); + + /* + * Ensure the core-other region reflects the appropriate core & + * VP before any accesses to it occur. + */ + mb(); } void mips_cpc_unlock_other(void) -- cgit v1.2.3 From 5b10a0e84b4ebe02a7018846e882caa112b4ffc6 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 22 Sep 2015 11:24:20 -0700 Subject: MIPS: Always use r4k_wait_irqoff for MIPSr6 Prior to release 6 of the MIPS architecture it has been implementation dependent whether masked interrupts cause a wait instruction to return, so the kernel has effectively had to maintain a whitelist of cores upon which it is safe to use the r4k_wait_irqoff cpu_wait implementation. With MIPSr6 this is no longer implementation dependent and r4k_wait_irqoff can always be used. Remove the existing I6400 case which will no longer ever be hit, and was incorrect anyway since I6400 & r6 in general doesn't have the WII bit. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Leonid Yegoshin Cc: linux-kernel@vger.kernel.org Cc: James Hogan Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/11210/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/idle.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c index ab1478d5a4db..3e2b0b6c3b08 100644 --- a/arch/mips/kernel/idle.c +++ b/arch/mips/kernel/idle.c @@ -134,6 +134,16 @@ void __init check_wait(void) return; } + /* + * MIPSr6 specifies that masked interrupts should unblock an executing + * wait instruction, and thus that it is safe for us to use + * r4k_wait_irqoff. Yippee! + */ + if (cpu_has_mips_r6) { + cpu_wait = r4k_wait_irqoff; + return; + } + switch (current_cpu_type()) { case CPU_R3081: case CPU_R3081E: @@ -196,7 +206,6 @@ void __init check_wait(void) case CPU_INTERAPTIV: case CPU_M5150: case CPU_QEMU_GENERIC: - case CPU_I6400: cpu_wait = r4k_wait; if (read_c0_config7() & MIPS_CONF7_WII) cpu_wait = r4k_wait_irqoff; -- cgit v1.2.3 From cab25bc7537badea41f635a049f45408c24dff26 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 22 Sep 2015 12:03:37 -0700 Subject: MIPS: Extend hardware table walking support to MIPS64 Extend the existing support for Hardware Table Walking (HTW) to MIPS64 systems by supporting PMDs & setting the pointer size bit in PWSize, then ceasing to blacklist HTW on MIPS64 systems. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Steven J. Hill Cc: Joshua Kinard Cc: Leonid Yegoshin Cc: Maciej W. Rozycki Cc: Paul Gortmaker Cc: linux-kernel@vger.kernel.org Cc: James Hogan Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/11224/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 09a51d091941..6b9064499bd3 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -536,8 +536,7 @@ 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)) { + if (config3 & MIPS_CONF3_PW) { c->htw_seq = 0; c->options |= MIPS_CPU_HTW; } -- cgit v1.2.3 From ebb5e78cc63417a35254a791de66e1cc84f963cc Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Wed, 21 Oct 2015 09:54:38 +0100 Subject: MIPS: Initial implementation of a VDSO Add an initial implementation of a proper (i.e. an ELF shared library) VDSO. With this commit it does not export any symbols, it only replaces the current signal return trampoline page. A later commit will add user implementations of gettimeofday()/clock_gettime(). To support both new toolchains and old ones which don't generate ABI flags section, we define its content manually and then use a tool (genvdso) to patch up the section to have the correct name and type. genvdso also extracts symbol offsets ({,rt_}sigreturn) needed by the kernel, and generates a C file containing a "struct mips_vdso_image" containing both the VDSO data and these offsets. This C file is compiled into the kernel. On 64-bit kernels we require a different VDSO for each supported ABI, so we may build up to 3 different VDSOs. The VDSO to use is selected by the mips_abi structure. A kernel/user shared data page is created and mapped below the VDSO image. This is currently empty, but will be used by the user time function implementations which are added later. [markos.chandras@imgtec.com: - Add more comments - Move abi detection in genvdso.h since it's the get_symbol function that needs it. - Add an R6 specific way to calculate the base address of VDSO in order to avoid the branch instruction which affects performance. - Do not patch .gnu.attributes since it's not needed for dynamic linking. - Simplify Makefile a little bit. - checkpatch fixes - Restrict VDSO support for binutils < 2.25 for pre-R6 - Include atomic64.h for O32 variant on MIPS64] Signed-off-by: Alex Smith Signed-off-by: Markos Chandras Cc: Matthew Fortune Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/11337/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/signal.c | 12 ++-- arch/mips/kernel/signal32.c | 7 +- arch/mips/kernel/signal_n32.c | 5 +- arch/mips/kernel/vdso.c | 160 ++++++++++++++++++++---------------------- 4 files changed, 86 insertions(+), 98 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 2fec67bfc457..bf792e2839a6 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -752,16 +751,15 @@ static int setup_rt_frame(void *sig_return, struct ksignal *ksig, struct mips_abi mips_abi = { #ifdef CONFIG_TRAD_SIGNALS .setup_frame = setup_frame, - .signal_return_offset = offsetof(struct mips_vdso, signal_trampoline), #endif .setup_rt_frame = setup_rt_frame, - .rt_signal_return_offset = - offsetof(struct mips_vdso, rt_signal_trampoline), .restart = __NR_restart_syscall, .off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs), .off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr), .off_sc_used_math = offsetof(struct sigcontext, sc_used_math), + + .vdso = &vdso_image, }; static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) @@ -801,11 +799,11 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) } if (sig_uses_siginfo(&ksig->ka)) - ret = abi->setup_rt_frame(vdso + abi->rt_signal_return_offset, + ret = abi->setup_rt_frame(vdso + abi->vdso->off_rt_sigreturn, ksig, regs, oldset); else - ret = abi->setup_frame(vdso + abi->signal_return_offset, ksig, - regs, oldset); + ret = abi->setup_frame(vdso + abi->vdso->off_sigreturn, + ksig, regs, oldset); signal_setup_done(ret, ksig, 0); } diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index f7e89524e316..4909639aa35b 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include "signal-common.h" @@ -406,14 +405,12 @@ static int setup_rt_frame_32(void *sig_return, struct ksignal *ksig, */ struct mips_abi mips_abi_32 = { .setup_frame = setup_frame_32, - .signal_return_offset = - offsetof(struct mips_vdso, o32_signal_trampoline), .setup_rt_frame = setup_rt_frame_32, - .rt_signal_return_offset = - offsetof(struct mips_vdso, o32_rt_signal_trampoline), .restart = __NR_O32_restart_syscall, .off_sc_fpregs = offsetof(struct sigcontext32, sc_fpregs), .off_sc_fpc_csr = offsetof(struct sigcontext32, sc_fpc_csr), .off_sc_used_math = offsetof(struct sigcontext32, sc_used_math), + + .vdso = &vdso_image_o32, }; diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index 0d017fdcaf07..a7bc38430500 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -38,7 +38,6 @@ #include #include #include -#include #include "signal-common.h" @@ -151,11 +150,11 @@ static int setup_rt_frame_n32(void *sig_return, struct ksignal *ksig, struct mips_abi mips_abi_n32 = { .setup_rt_frame = setup_rt_frame_n32, - .rt_signal_return_offset = - offsetof(struct mips_vdso, n32_rt_signal_trampoline), .restart = __NR_N32_restart_syscall, .off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs), .off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr), .off_sc_used_math = offsetof(struct sigcontext, sc_used_math), + + .vdso = &vdso_image_n32, }; diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c index ed2a278722a9..56cc3c4377fb 100644 --- a/arch/mips/kernel/vdso.c +++ b/arch/mips/kernel/vdso.c @@ -1,122 +1,116 @@ /* - * 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) 2015 Imagination Technologies + * Author: Alex Smith * - * Copyright (C) 2009, 2010 Cavium Networks, Inc. + * 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 + +/* Kernel-provided data used by the VDSO. */ +static union mips_vdso_data vdso_data __page_aligned_data; /* - * Including would give use the 64-bit syscall numbers ... + * Mapping for the VDSO data pages. The real pages are mapped manually, as + * what we map and where within the area they are mapped is determined at + * runtime. */ -#define __NR_O32_sigreturn 4119 -#define __NR_O32_rt_sigreturn 4193 -#define __NR_N32_rt_sigreturn 6211 +static struct page *no_pages[] = { NULL }; +static struct vm_special_mapping vdso_vvar_mapping = { + .name = "[vvar]", + .pages = no_pages, +}; -static struct page *vdso_page; - -static void __init install_trampoline(u32 *tramp, unsigned int sigreturn) +static void __init init_vdso_image(struct mips_vdso_image *image) { - uasm_i_addiu(&tramp, 2, 0, sigreturn); /* li v0, sigreturn */ - uasm_i_syscall(&tramp, 0); + unsigned long num_pages, i; + + BUG_ON(!PAGE_ALIGNED(image->data)); + BUG_ON(!PAGE_ALIGNED(image->size)); + + num_pages = image->size / PAGE_SIZE; + + for (i = 0; i < num_pages; i++) { + image->mapping.pages[i] = + virt_to_page(image->data + (i * PAGE_SIZE)); + } } static int __init init_vdso(void) { - struct mips_vdso *vdso; - - vdso_page = alloc_page(GFP_KERNEL); - if (!vdso_page) - panic("Cannot allocate vdso"); - - vdso = vmap(&vdso_page, 1, 0, PAGE_KERNEL); - if (!vdso) - panic("Cannot map vdso"); - clear_page(vdso); - - install_trampoline(vdso->rt_signal_trampoline, __NR_rt_sigreturn); -#ifdef CONFIG_32BIT - install_trampoline(vdso->signal_trampoline, __NR_sigreturn); -#else - install_trampoline(vdso->n32_rt_signal_trampoline, - __NR_N32_rt_sigreturn); - install_trampoline(vdso->o32_signal_trampoline, __NR_O32_sigreturn); - install_trampoline(vdso->o32_rt_signal_trampoline, - __NR_O32_rt_sigreturn); + init_vdso_image(&vdso_image); + +#ifdef CONFIG_MIPS32_O32 + init_vdso_image(&vdso_image_o32); #endif - vunmap(vdso); +#ifdef CONFIG_MIPS32_N32 + init_vdso_image(&vdso_image_n32); +#endif return 0; } subsys_initcall(init_vdso); -static unsigned long vdso_addr(unsigned long start) -{ - unsigned long offset = 0UL; - - if (current->flags & PF_RANDOMIZE) { - offset = get_random_int(); - offset <<= PAGE_SHIFT; - if (TASK_IS_32BIT_ADDR) - offset &= 0xfffffful; - else - offset &= 0xffffffful; - } - - return STACK_TOP + offset; -} - int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) { - int ret; - unsigned long addr; + struct mips_vdso_image *image = current->thread.abi->vdso; struct mm_struct *mm = current->mm; + unsigned long base, vdso_addr; + struct vm_area_struct *vma; + int ret; down_write(&mm->mmap_sem); - addr = vdso_addr(mm->start_stack); - - addr = get_unmapped_area(NULL, addr, PAGE_SIZE, 0, 0); - if (IS_ERR_VALUE(addr)) { - ret = addr; - goto up_fail; + base = get_unmapped_area(NULL, 0, PAGE_SIZE + image->size, 0, 0); + if (IS_ERR_VALUE(base)) { + ret = base; + goto out; } - ret = install_special_mapping(mm, addr, PAGE_SIZE, - VM_READ|VM_EXEC| - VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, - &vdso_page); + vdso_addr = base + PAGE_SIZE; + + vma = _install_special_mapping(mm, base, PAGE_SIZE, + VM_READ | VM_MAYREAD, + &vdso_vvar_mapping); + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); + goto out; + } + /* Map data page. */ + ret = remap_pfn_range(vma, base, + virt_to_phys(&vdso_data) >> PAGE_SHIFT, + PAGE_SIZE, PAGE_READONLY); if (ret) - goto up_fail; + goto out; + + /* Map VDSO image. */ + vma = _install_special_mapping(mm, vdso_addr, image->size, + VM_READ | VM_EXEC | + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC, + &image->mapping); + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); + goto out; + } - mm->context.vdso = (void *)addr; + mm->context.vdso = (void *)vdso_addr; + ret = 0; -up_fail: +out: up_write(&mm->mmap_sem); return ret; } - -const char *arch_vma_name(struct vm_area_struct *vma) -{ - if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso) - return "[vdso]"; - return NULL; -} -- cgit v1.2.3 From a7f4df4e21dd8a8dab96e88acd2c9c5017b83fc6 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Wed, 21 Oct 2015 09:57:44 +0100 Subject: MIPS: VDSO: Add implementations of gettimeofday() and clock_gettime() Add user-mode implementations of gettimeofday() and clock_gettime() to the VDSO. This is currently usable with 2 clocksources: the CP0 count register, which is accessible to user-mode via RDHWR on R2 and later cores, or the MIPS Global Interrupt Controller (GIC) timer, which provides a "user-mode visible" section containing a mirror of its counter registers. This section must be mapped into user memory, which is done below the VDSO data page. When a supported clocksource is not in use, the VDSO functions will return -ENOSYS, which causes libc to fall back on the standard syscall path. When support for neither of these clocksources is compiled into the kernel at all, the VDSO still provides clock_gettime(), as the coarse realtime/monotonic clocks can still be implemented. However, gettimeofday() is not provided in this case as nothing can be done without a suitable clocksource. This causes the symbol lookup to fail in libc and it will then always use the standard syscall path. This patch includes a workaround for a bug in QEMU which results in RDHWR on the CP0 count register always returning a constant (incorrect) value. A fix for this has been submitted, and the workaround can be removed after the fix has been in stable releases for a reasonable amount of time. A simple performance test which calls gettimeofday() 1000 times in a loop and calculates the average execution time gives the following results on a Malta + I6400 (running at 20MHz): - Syscall: ~31000 ns - VDSO (GIC): ~15000 ns - VDSO (CP0): ~9500 ns [markos.chandras@imgtec.com: - Minor code re-arrangements in order for mappings to be made in the order they appear to the process' address space. - Move do_{monotonic, realtime} outside of the MIPS_CLOCK_VSYSCALL ifdef - Use gic_get_usm_range so we can do the GIC mapping in the arch/mips/kernel/vdso instead of the GIC irqchip driver] Signed-off-by: Alex Smith Signed-off-by: Markos Chandras Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/11338/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/csrc-r4k.c | 44 ++++++++++++++++++++++++++++ arch/mips/kernel/vdso.c | 71 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 109 insertions(+), 6 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/csrc-r4k.c b/arch/mips/kernel/csrc-r4k.c index e5ed7ada1433..1f910563fdf6 100644 --- a/arch/mips/kernel/csrc-r4k.c +++ b/arch/mips/kernel/csrc-r4k.c @@ -28,6 +28,43 @@ static u64 notrace r4k_read_sched_clock(void) return read_c0_count(); } +static inline unsigned int rdhwr_count(void) +{ + unsigned int count; + + __asm__ __volatile__( + " .set push\n" + " .set mips32r2\n" + " rdhwr %0, $2\n" + " .set pop\n" + : "=r" (count)); + + return count; +} + +static bool rdhwr_count_usable(void) +{ + unsigned int prev, curr, i; + + /* + * Older QEMUs have a broken implementation of RDHWR for the CP0 count + * which always returns a constant value. Try to identify this and don't + * use it in the VDSO if it is broken. This workaround can be removed + * once the fix has been in QEMU stable for a reasonable amount of time. + */ + for (i = 0, prev = rdhwr_count(); i < 100; i++) { + curr = rdhwr_count(); + + if (curr != prev) + return true; + + prev = curr; + } + + pr_warn("Not using R4K clocksource in VDSO due to broken RDHWR\n"); + return false; +} + int __init init_r4k_clocksource(void) { if (!cpu_has_counter || !mips_hpt_frequency) @@ -36,6 +73,13 @@ int __init init_r4k_clocksource(void) /* Calculate a somewhat reasonable rating value */ clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000; + /* + * R2 onwards makes the count accessible to user mode so it can be used + * by the VDSO (HWREna is configured by configure_hwrena()). + */ + if (cpu_has_mips_r2_r6 && rdhwr_count_usable()) + clocksource_mips.archdata.vdso_clock_mode = VDSO_CLOCK_R4K; + clocksource_register_hz(&clocksource_mips, mips_hpt_frequency); sched_clock_register(r4k_read_sched_clock, 32, mips_hpt_frequency); diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c index 56cc3c4377fb..975e99759bab 100644 --- a/arch/mips/kernel/vdso.c +++ b/arch/mips/kernel/vdso.c @@ -12,9 +12,12 @@ #include #include #include +#include +#include #include #include #include +#include #include #include @@ -23,7 +26,7 @@ static union mips_vdso_data vdso_data __page_aligned_data; /* - * Mapping for the VDSO data pages. The real pages are mapped manually, as + * Mapping for the VDSO data/GIC pages. The real pages are mapped manually, as * what we map and where within the area they are mapped is determined at * runtime. */ @@ -64,25 +67,67 @@ static int __init init_vdso(void) } subsys_initcall(init_vdso); +void update_vsyscall(struct timekeeper *tk) +{ + vdso_data_write_begin(&vdso_data); + + vdso_data.xtime_sec = tk->xtime_sec; + vdso_data.xtime_nsec = tk->tkr_mono.xtime_nsec; + vdso_data.wall_to_mono_sec = tk->wall_to_monotonic.tv_sec; + vdso_data.wall_to_mono_nsec = tk->wall_to_monotonic.tv_nsec; + vdso_data.cs_shift = tk->tkr_mono.shift; + + vdso_data.clock_mode = tk->tkr_mono.clock->archdata.vdso_clock_mode; + if (vdso_data.clock_mode != VDSO_CLOCK_NONE) { + vdso_data.cs_mult = tk->tkr_mono.mult; + vdso_data.cs_cycle_last = tk->tkr_mono.cycle_last; + vdso_data.cs_mask = tk->tkr_mono.mask; + } + + vdso_data_write_end(&vdso_data); +} + +void update_vsyscall_tz(void) +{ + if (vdso_data.clock_mode != VDSO_CLOCK_NONE) { + vdso_data.tz_minuteswest = sys_tz.tz_minuteswest; + vdso_data.tz_dsttime = sys_tz.tz_dsttime; + } +} + int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) { struct mips_vdso_image *image = current->thread.abi->vdso; struct mm_struct *mm = current->mm; - unsigned long base, vdso_addr; + unsigned long gic_size, vvar_size, size, base, data_addr, vdso_addr; struct vm_area_struct *vma; + struct resource gic_res; int ret; down_write(&mm->mmap_sem); - base = get_unmapped_area(NULL, 0, PAGE_SIZE + image->size, 0, 0); + /* + * Determine total area size. This includes the VDSO data itself, the + * data page, and the GIC user page if present. Always create a mapping + * for the GIC user area if the GIC is present regardless of whether it + * is the current clocksource, in case it comes into use later on. We + * only map a page even though the total area is 64K, as we only need + * the counter registers at the start. + */ + gic_size = gic_present ? PAGE_SIZE : 0; + vvar_size = gic_size + PAGE_SIZE; + size = vvar_size + image->size; + + base = get_unmapped_area(NULL, 0, size, 0, 0); if (IS_ERR_VALUE(base)) { ret = base; goto out; } - vdso_addr = base + PAGE_SIZE; + data_addr = base + gic_size; + vdso_addr = data_addr + PAGE_SIZE; - vma = _install_special_mapping(mm, base, PAGE_SIZE, + vma = _install_special_mapping(mm, base, vvar_size, VM_READ | VM_MAYREAD, &vdso_vvar_mapping); if (IS_ERR(vma)) { @@ -90,8 +135,22 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) goto out; } + /* Map GIC user page. */ + if (gic_size) { + ret = gic_get_usm_range(&gic_res); + if (ret) + goto out; + + ret = io_remap_pfn_range(vma, base, + gic_res.start >> PAGE_SHIFT, + gic_size, + pgprot_noncached(PAGE_READONLY)); + if (ret) + goto out; + } + /* Map data page. */ - ret = remap_pfn_range(vma, base, + ret = remap_pfn_range(vma, data_addr, virt_to_phys(&vdso_data) >> PAGE_SHIFT, PAGE_SIZE, PAGE_READONLY); if (ret) -- cgit v1.2.3 From e1e1611598148e03c6d65e6c23338f4ff2cee71e Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Fri, 23 Oct 2015 15:39:02 +0300 Subject: MIPS: Add LATENCYTOP support Add LATENCYTOP support for MIPS. Tested on OCTEON. Signed-off-by: Aaro Koskinen Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/11353/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/stacktrace.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/stacktrace.c b/arch/mips/kernel/stacktrace.c index 1ba775d24d38..506021f62549 100644 --- a/arch/mips/kernel/stacktrace.c +++ b/arch/mips/kernel/stacktrace.c @@ -12,14 +12,15 @@ * Save stack-backtrace addresses into a stack_trace buffer: */ static void save_raw_context_stack(struct stack_trace *trace, - unsigned long reg29) + unsigned long reg29, int savesched) { unsigned long *sp = (unsigned long *)reg29; unsigned long addr; while (!kstack_end(sp)) { addr = *sp++; - if (__kernel_text_address(addr)) { + if (__kernel_text_address(addr) && + (savesched || !in_sched_functions(addr))) { if (trace->skip > 0) trace->skip--; else @@ -31,7 +32,7 @@ static void save_raw_context_stack(struct stack_trace *trace, } static void save_context_stack(struct stack_trace *trace, - struct task_struct *tsk, struct pt_regs *regs) + struct task_struct *tsk, struct pt_regs *regs, int savesched) { unsigned long sp = regs->regs[29]; #ifdef CONFIG_KALLSYMS @@ -43,20 +44,22 @@ static void save_context_stack(struct stack_trace *trace, (unsigned long)task_stack_page(tsk); if (stack_page && sp >= stack_page && sp <= stack_page + THREAD_SIZE - 32) - save_raw_context_stack(trace, sp); + save_raw_context_stack(trace, sp, savesched); return; } do { - if (trace->skip > 0) - trace->skip--; - else - trace->entries[trace->nr_entries++] = pc; - if (trace->nr_entries >= trace->max_entries) - break; + if (savesched || !in_sched_functions(pc)) { + if (trace->skip > 0) + trace->skip--; + else + trace->entries[trace->nr_entries++] = pc; + if (trace->nr_entries >= trace->max_entries) + break; + } pc = unwind_stack(tsk, &sp, pc, &ra); } while (pc); #else - save_raw_context_stack(trace, sp); + save_raw_context_stack(trace, sp, savesched); #endif } @@ -82,6 +85,6 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) regs->cp0_epc = tsk->thread.reg31; } else prepare_frametrace(regs); - save_context_stack(trace, tsk, regs); + save_context_stack(trace, tsk, regs, tsk == current); } EXPORT_SYMBOL_GPL(save_stack_trace_tsk); -- cgit v1.2.3 From 2024972ef5330dcae47f400c586764d8f4cb0b04 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Mon, 12 Oct 2015 13:13:02 +0200 Subject: MIPS: Make the kernel arguments from dtb available Similar to how arm allows using selecting between bootloader arguments, dtb arguments and both, allow to select them on mips. But since we have less control over the place of the dtb do not modify it but instead use the boot_command_line for merging them. The default is "use bootloader arguments" to keep the current behaviour as default. Signed-off-by: Jonas Gorski Cc: linux-mips@linux-mips.org Cc: Kevin Cernekee Cc: Florian Fainelli Cc: Zubair Lutfullah Kakakhel Cc: James Hogan Cc: John Crispin Cc: Ganesan Ramalingam Cc: Jayachandran C Cc: Andrew Bresticker Cc: James Hartley Patchwork: https://patchwork.linux-mips.org/patch/11284/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/setup.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 5b46b672c939..6f142ee4a086 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -617,6 +617,10 @@ static void __init request_crashkernel(struct resource *res) } #endif /* !defined(CONFIG_KEXEC) */ +#define USE_PROM_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER) +#define USE_DTB_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB) +#define EXTEND_WITH_PROM IS_ENABLED(CONFIG_MIPS_CMDLINE_EXTEND) + static void __init arch_mem_init(char **cmdline_p) { struct memblock_region *reg; @@ -641,18 +645,24 @@ static void __init arch_mem_init(char **cmdline_p) pr_info("Determined physical RAM map:\n"); print_memory_map(); -#ifdef CONFIG_CMDLINE_BOOL -#ifdef CONFIG_CMDLINE_OVERRIDE +#if defined(CONFIG_CMDLINE_BOOL) && defined(CONFIG_CMDLINE_OVERRIDE) strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); #else + if ((USE_PROM_CMDLINE && arcs_cmdline[0]) || + (USE_DTB_CMDLINE && !boot_command_line[0])) + strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE); + + if (EXTEND_WITH_PROM && arcs_cmdline[0]) { + strlcat(boot_command_line, " ", COMMAND_LINE_SIZE); + strlcat(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE); + } + +#if defined(CONFIG_CMDLINE_BOOL) if (builtin_cmdline[0]) { - strlcat(arcs_cmdline, " ", COMMAND_LINE_SIZE); - strlcat(arcs_cmdline, builtin_cmdline, COMMAND_LINE_SIZE); + strlcat(boot_command_line, " ", COMMAND_LINE_SIZE); + strlcat(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); } - strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE); #endif -#else - strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE); #endif strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE); -- cgit v1.2.3 From 87db537da4cd1bfad388511a3647bbb497d2fb61 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Fri, 11 Sep 2015 17:46:14 +0300 Subject: MIPS: vmlinux: create a section for appended DTB For bootloaders that support booting only ELF kernels and load only ELF segments to memory there is no easy way to supply DTB without kernel recompilation. For that purpose, create a section called .appended_dtb that can be later updated with board-specific DTB using binutils e.g. at kernel installation time. Signed-off-by: Aaro Koskinen Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/11114/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/setup.c | 4 ++++ arch/mips/kernel/vmlinux.lds.S | 5 +++++ 2 files changed, 9 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 6f142ee4a086..66aac55df349 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -39,6 +39,10 @@ #include #include +#ifdef CONFIG_MIPS_ELF_APPENDED_DTB +const char __section(.appended_dtb) __appended_dtb[0x100000]; +#endif /* CONFIG_MIPS_ELF_APPENDED_DTB */ + struct cpuinfo_mips cpu_data[NR_CPUS] __read_mostly; EXPORT_SYMBOL(cpu_data); diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index 07d32a4aea60..f4c23d9023be 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -132,6 +132,11 @@ SECTIONS __appended_dtb = .; /* leave space for appended DTB */ . += 0x100000; +#elif defined(CONFIG_MIPS_ELF_APPENDED_DTB) + .appended_dtb : AT(ADDR(.appended_dtb) - LOAD_OFFSET) { + *(.appended_dtb) + KEEP(*(.appended_dtb)) + } #endif /* * Align to 64K in attempt to eliminate holes before the -- cgit v1.2.3 From bf463f2f7510771db180908507005379850dade0 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 5 Sep 2015 18:47:31 +0200 Subject: MIPS: idle: add case for CPU_5KE While the 5KE processors have never been taped out, they exists though a CP0.PRId and experimental RTLs or QEMU implementations. Add a case entry in the idle code, as they can use the standard idle loop like the 5K processors. Signed-off-by: Aurelien Jarno Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/11099/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/idle.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c index 3e2b0b6c3b08..35af61530de1 100644 --- a/arch/mips/kernel/idle.c +++ b/arch/mips/kernel/idle.c @@ -165,6 +165,7 @@ void __init check_wait(void) case CPU_4KEC: case CPU_4KSC: case CPU_5KC: + case CPU_5KE: case CPU_25KF: case CPU_PR4450: case CPU_BMIPS3300: -- cgit v1.2.3