diff options
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r-- | arch/mips/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/mips/kernel/cpu-probe.c | 15 | ||||
-rw-r--r-- | arch/mips/kernel/elf.c | 32 | ||||
-rw-r--r-- | arch/mips/kernel/head.S | 16 | ||||
-rw-r--r-- | arch/mips/kernel/i8259.c | 43 | ||||
-rw-r--r-- | arch/mips/kernel/irq.c | 54 | ||||
-rw-r--r-- | arch/mips/kernel/irq_cpu.c | 169 | ||||
-rw-r--r-- | arch/mips/kernel/kgdb.c | 4 | ||||
-rw-r--r-- | arch/mips/kernel/prom.c | 1 | ||||
-rw-r--r-- | arch/mips/kernel/ptrace.c | 2 | ||||
-rw-r--r-- | arch/mips/kernel/signal-common.h | 9 | ||||
-rw-r--r-- | arch/mips/kernel/smp-bmips.c | 2 | ||||
-rw-r--r-- | arch/mips/kernel/smp-cps.c | 2 | ||||
-rw-r--r-- | arch/mips/kernel/smp.c | 6 | ||||
-rw-r--r-- | arch/mips/kernel/sysrq.c | 77 | ||||
-rw-r--r-- | arch/mips/kernel/traps.c | 13 | ||||
-rw-r--r-- | arch/mips/kernel/vmlinux.lds.S | 8 |
17 files changed, 184 insertions, 271 deletions
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index d3d2ff2d76dc..3f5cf8aff6f3 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -62,7 +62,6 @@ obj-$(CONFIG_MIPS_VPE_APSP_API_CMP) += rtlx-cmp.o obj-$(CONFIG_MIPS_VPE_APSP_API_MT) += rtlx-mt.o obj-$(CONFIG_I8259) += i8259.o -obj-$(CONFIG_IRQ_CPU) += irq_cpu.o obj-$(CONFIG_IRQ_CPU_RM7K) += irq-rm7000.o obj-$(CONFIG_MIPS_MSC) += irq-msc01.o obj-$(CONFIG_IRQ_TXX9) += irq_txx9.o @@ -77,6 +76,7 @@ obj-$(CONFIG_MIPS32_O32) += binfmt_elfo32.o scall64-o32.o obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_PROC_FS) += proc.o +obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o obj-$(CONFIG_64BIT) += cpu-bugs64.o diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index e36515dcd3b2..dbe0792fc9c1 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -74,13 +74,12 @@ static inline void cpu_set_fpu_fcsr_mask(struct cpuinfo_mips *c) { unsigned long sr, mask, fcsr, fcsr0, fcsr1; + fcsr = c->fpu_csr31; mask = FPU_CSR_ALL_X | FPU_CSR_ALL_E | FPU_CSR_ALL_S | FPU_CSR_RM; sr = read_c0_status(); __enable_fpu(FPU_AS_IS); - fcsr = read_32bit_cp1_register(CP1_STATUS); - fcsr0 = fcsr & mask; write_32bit_cp1_register(CP1_STATUS, fcsr0); fcsr0 = read_32bit_cp1_register(CP1_STATUS); @@ -946,7 +945,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) c->options = MIPS_CPU_TLB | MIPS_CPU_4K_CACHE | MIPS_CPU_4KEX | MIPS_CPU_FPU | MIPS_CPU_32FPR | MIPS_CPU_COUNTER | MIPS_CPU_WATCH | - MIPS_CPU_LLSC; + MIPS_CPU_LLSC | MIPS_CPU_BP_GHIST; c->tlbsize = 64; break; case PRID_IMP_R14000: @@ -961,7 +960,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) c->options = MIPS_CPU_TLB | MIPS_CPU_4K_CACHE | MIPS_CPU_4KEX | MIPS_CPU_FPU | MIPS_CPU_32FPR | MIPS_CPU_COUNTER | MIPS_CPU_WATCH | - MIPS_CPU_LLSC; + MIPS_CPU_LLSC | MIPS_CPU_BP_GHIST; c->tlbsize = 64; break; case PRID_IMP_LOONGSON_64: /* Loongson-2/3 */ @@ -1444,7 +1443,9 @@ void cpu_probe(void) case PRID_COMP_CAVIUM: cpu_probe_cavium(c, cpu); break; - case PRID_COMP_INGENIC: + case PRID_COMP_INGENIC_D0: + case PRID_COMP_INGENIC_D1: + case PRID_COMP_INGENIC_E1: cpu_probe_ingenic(c, cpu); break; case PRID_COMP_NETLOGIC: @@ -1479,6 +1480,10 @@ void cpu_probe(void) else cpu_set_nofpu_opts(c); + if (cpu_has_bp_ghist) + write_c0_r10k_diag(read_c0_r10k_diag() | + R10K_DIAG_E_GHIST); + if (cpu_has_mips_r2_r6) { c->srsets = ((read_c0_srsctl() >> 26) & 0x0f) + 1; /* R2 has Performance Counter Interrupt indicator */ diff --git a/arch/mips/kernel/elf.c b/arch/mips/kernel/elf.c index be4899f3c393..4a4d9e067c89 100644 --- a/arch/mips/kernel/elf.c +++ b/arch/mips/kernel/elf.c @@ -76,14 +76,6 @@ int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf, /* Lets see if this is an O32 ELF */ if (ehdr32->e_ident[EI_CLASS] == ELFCLASS32) { - /* FR = 1 for N32 */ - if (ehdr32->e_flags & EF_MIPS_ABI2) - state->overall_fp_mode = FP_FR1; - else - /* Set a good default FPU mode for O32 */ - state->overall_fp_mode = cpu_has_mips_r6 ? - FP_FRE : FP_FR0; - if (ehdr32->e_flags & EF_MIPS_FP64) { /* * Set MIPS_ABI_FP_OLD_64 for EF_MIPS_FP64. We will override it @@ -104,9 +96,6 @@ int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf, (char *)&abiflags, sizeof(abiflags)); } else { - /* FR=1 is really the only option for 64-bit */ - state->overall_fp_mode = FP_FR1; - if (phdr64->p_type != PT_MIPS_ABIFLAGS) return 0; if (phdr64->p_filesz < sizeof(abiflags)) @@ -137,6 +126,7 @@ int arch_check_elf(void *_ehdr, bool has_interpreter, struct elf32_hdr *ehdr = _ehdr; struct mode_req prog_req, interp_req; int fp_abi, interp_fp_abi, abi0, abi1, max_abi; + bool is_mips64; if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT)) return 0; @@ -152,10 +142,22 @@ int arch_check_elf(void *_ehdr, bool has_interpreter, abi0 = abi1 = fp_abi; } - /* ABI limits. O32 = FP_64A, N32/N64 = FP_SOFT */ - max_abi = ((ehdr->e_ident[EI_CLASS] == ELFCLASS32) && - (!(ehdr->e_flags & EF_MIPS_ABI2))) ? - MIPS_ABI_FP_64A : MIPS_ABI_FP_SOFT; + is_mips64 = (ehdr->e_ident[EI_CLASS] == ELFCLASS64) || + (ehdr->e_flags & EF_MIPS_ABI2); + + if (is_mips64) { + /* MIPS64 code always uses FR=1, thus the default is easy */ + state->overall_fp_mode = FP_FR1; + + /* Disallow access to the various FPXX & FP64 ABIs */ + max_abi = MIPS_ABI_FP_SOFT; + } else { + /* Default to a mode capable of running code expecting FR=0 */ + state->overall_fp_mode = cpu_has_mips_r6 ? FP_FRE : FP_FR0; + + /* Allow all ABIs we know about */ + max_abi = MIPS_ABI_FP_64A; + } if ((abi0 > max_abi && abi0 != MIPS_ABI_FP_UNKNOWN) || (abi1 > max_abi && abi1 != MIPS_ABI_FP_UNKNOWN)) diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index 95afd663cd45..4e4cc5b9a771 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -94,6 +94,22 @@ NESTED(kernel_entry, 16, sp) # kernel entry point jr t0 0: +#ifdef CONFIG_MIPS_RAW_APPENDED_DTB + PTR_LA t0, __appended_dtb + +#ifdef CONFIG_CPU_BIG_ENDIAN + li t1, 0xd00dfeed +#else + li t1, 0xedfe0dd0 +#endif + lw t2, (t0) + bne t1, t2, not_found + nop + + move a1, t0 + PTR_LI a0, -2 +not_found: +#endif PTR_LA t0, __bss_start # clear .bss LONG_S zero, (t0) PTR_LA t1, __bss_stop - LONGSIZE diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index a74ec3ae557c..74f6752814d3 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c @@ -14,6 +14,7 @@ #include <linux/interrupt.h> #include <linux/irqdomain.h> #include <linux/kernel.h> +#include <linux/of_irq.h> #include <linux/spinlock.h> #include <linux/syscore_ops.h> #include <linux/irq.h> @@ -21,6 +22,8 @@ #include <asm/i8259.h> #include <asm/io.h> +#include "../../drivers/irqchip/irqchip.h" + /* * This is the 'legacy' 8259A Programmable Interrupt Controller, * present in the majority of PC/AT boxes. @@ -327,7 +330,7 @@ static struct irq_domain_ops i8259A_ops = { * driver compatibility reasons interrupts 0 - 15 to be the i8259 * interrupts even if the hardware uses a different interrupt numbering. */ -void __init init_i8259_irqs(void) +struct irq_domain * __init __init_i8259_irqs(struct device_node *node) { struct irq_domain *domain; @@ -336,10 +339,46 @@ void __init init_i8259_irqs(void) init_8259A(0); - domain = irq_domain_add_legacy(NULL, 16, I8259A_IRQ_BASE, 0, + domain = irq_domain_add_legacy(node, 16, I8259A_IRQ_BASE, 0, &i8259A_ops, NULL); if (!domain) panic("Failed to add i8259 IRQ domain"); setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2); + return domain; +} + +void __init init_i8259_irqs(void) +{ + __init_i8259_irqs(NULL); +} + +static void i8259_irq_dispatch(unsigned int irq, struct irq_desc *desc) +{ + struct irq_domain *domain = irq_get_handler_data(irq); + int hwirq = i8259_irq(); + + if (hwirq < 0) + return; + + irq = irq_linear_revmap(domain, hwirq); + generic_handle_irq(irq); +} + +int __init i8259_of_init(struct device_node *node, struct device_node *parent) +{ + struct irq_domain *domain; + unsigned int parent_irq; + + parent_irq = irq_of_parse_and_map(node, 0); + if (!parent_irq) { + pr_err("Failed to map i8259 parent IRQ\n"); + return -ENODEV; + } + + domain = __init_i8259_irqs(node); + irq_set_handler_data(parent_irq, domain); + irq_set_chained_handler(parent_irq, i8259_irq_dispatch); + return 0; } +IRQCHIP_DECLARE(i8259, "intel,i8259", i8259_of_init); diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index d2bfbc2e8995..8eb5af805964 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c @@ -25,48 +25,6 @@ #include <linux/atomic.h> #include <asm/uaccess.h> -#ifdef CONFIG_KGDB -int kgdb_early_setup; -#endif - -static unsigned long irq_map[NR_IRQS / BITS_PER_LONG]; - -int allocate_irqno(void) -{ - int irq; - -again: - irq = find_first_zero_bit(irq_map, NR_IRQS); - - if (irq >= NR_IRQS) - return -ENOSPC; - - if (test_and_set_bit(irq, irq_map)) - goto again; - - return irq; -} - -/* - * Allocate the 16 legacy interrupts for i8259 devices. This happens early - * in the kernel initialization so treating allocation failure as BUG() is - * ok. - */ -void __init alloc_legacy_irqno(void) -{ - int i; - - for (i = 0; i <= 16; i++) - BUG_ON(test_and_set_bit(i, irq_map)); -} - -void free_irqno(unsigned int irq) -{ - smp_mb__before_atomic(); - clear_bit(irq, irq_map); - smp_mb__after_atomic(); -} - /* * 'what should we do if we get a hw irq event on an illegal vector'. * each architecture has to answer this themselves. @@ -93,23 +51,13 @@ void __init init_IRQ(void) { int i; -#ifdef CONFIG_KGDB - if (kgdb_early_setup) - return; -#endif - for (i = 0; i < NR_IRQS; i++) irq_set_noprobe(i); arch_init_irq(); - -#ifdef CONFIG_KGDB - if (!kgdb_early_setup) - kgdb_early_setup = 1; -#endif } -#ifdef DEBUG_STACKOVERFLOW +#ifdef CONFIG_DEBUG_STACKOVERFLOW static inline void check_stack_overflow(void) { unsigned long sp; diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c deleted file mode 100644 index 6eb7a3f515fc..000000000000 --- a/arch/mips/kernel/irq_cpu.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright 2001 MontaVista Software Inc. - * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net - * - * Copyright (C) 2001 Ralf Baechle - * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved. - * Author: Maciej W. Rozycki <macro@mips.com> - * - * This file define the irq handler for MIPS CPU interrupts. - * - * 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. - */ - -/* - * Almost all MIPS CPUs define 8 interrupt sources. They are typically - * level triggered (i.e., cannot be cleared from CPU; must be cleared from - * device). The first two are software interrupts which we don't really - * use or support. The last one is usually the CPU timer interrupt if - * counter register is present or, for CPUs with an external FPU, by - * convention it's the FPU exception interrupt. - * - * Don't even think about using this on SMP. You have been warned. - * - * This file exports one global function: - * void mips_cpu_irq_init(void); - */ -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/irq.h> -#include <linux/irqdomain.h> - -#include <asm/irq_cpu.h> -#include <asm/mipsregs.h> -#include <asm/mipsmtregs.h> -#include <asm/setup.h> - -static inline void unmask_mips_irq(struct irq_data *d) -{ - set_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); - irq_enable_hazard(); -} - -static inline void mask_mips_irq(struct irq_data *d) -{ - clear_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); - irq_disable_hazard(); -} - -static struct irq_chip mips_cpu_irq_controller = { - .name = "MIPS", - .irq_ack = mask_mips_irq, - .irq_mask = mask_mips_irq, - .irq_mask_ack = mask_mips_irq, - .irq_unmask = unmask_mips_irq, - .irq_eoi = unmask_mips_irq, - .irq_disable = mask_mips_irq, - .irq_enable = unmask_mips_irq, -}; - -/* - * Basically the same as above but taking care of all the MT stuff - */ - -static unsigned int mips_mt_cpu_irq_startup(struct irq_data *d) -{ - unsigned int vpflags = dvpe(); - - clear_c0_cause(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); - evpe(vpflags); - unmask_mips_irq(d); - return 0; -} - -/* - * While we ack the interrupt interrupts are disabled and thus we don't need - * to deal with concurrency issues. Same for mips_cpu_irq_end. - */ -static void mips_mt_cpu_irq_ack(struct irq_data *d) -{ - unsigned int vpflags = dvpe(); - clear_c0_cause(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); - evpe(vpflags); - mask_mips_irq(d); -} - -static struct irq_chip mips_mt_cpu_irq_controller = { - .name = "MIPS", - .irq_startup = mips_mt_cpu_irq_startup, - .irq_ack = mips_mt_cpu_irq_ack, - .irq_mask = mask_mips_irq, - .irq_mask_ack = mips_mt_cpu_irq_ack, - .irq_unmask = unmask_mips_irq, - .irq_eoi = unmask_mips_irq, - .irq_disable = mask_mips_irq, - .irq_enable = unmask_mips_irq, -}; - -asmlinkage void __weak plat_irq_dispatch(void) -{ - unsigned long pending = read_c0_cause() & read_c0_status() & ST0_IM; - int irq; - - if (!pending) { - spurious_interrupt(); - return; - } - - pending >>= CAUSEB_IP; - while (pending) { - irq = fls(pending) - 1; - do_IRQ(MIPS_CPU_IRQ_BASE + irq); - pending &= ~BIT(irq); - } -} - -static int mips_cpu_intc_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hw) -{ - static struct irq_chip *chip; - - if (hw < 2 && cpu_has_mipsmt) { - /* Software interrupts are used for MT/CMT IPI */ - chip = &mips_mt_cpu_irq_controller; - } else { - chip = &mips_cpu_irq_controller; - } - - if (cpu_has_vint) - set_vi_handler(hw, plat_irq_dispatch); - - irq_set_chip_and_handler(irq, chip, handle_percpu_irq); - - return 0; -} - -static const struct irq_domain_ops mips_cpu_intc_irq_domain_ops = { - .map = mips_cpu_intc_map, - .xlate = irq_domain_xlate_onecell, -}; - -static void __init __mips_cpu_irq_init(struct device_node *of_node) -{ - struct irq_domain *domain; - - /* Mask interrupts. */ - clear_c0_status(ST0_IM); - clear_c0_cause(CAUSEF_IP); - - domain = irq_domain_add_legacy(of_node, 8, MIPS_CPU_IRQ_BASE, 0, - &mips_cpu_intc_irq_domain_ops, NULL); - if (!domain) - panic("Failed to add irqdomain for MIPS CPU"); -} - -void __init mips_cpu_irq_init(void) -{ - __mips_cpu_irq_init(NULL); -} - -int __init mips_cpu_irq_of_init(struct device_node *of_node, - struct device_node *parent) -{ - __mips_cpu_irq_init(of_node); - return 0; -} diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c index 7afcc2f22c0d..de63d36af895 100644 --- a/arch/mips/kernel/kgdb.c +++ b/arch/mips/kernel/kgdb.c @@ -378,10 +378,6 @@ int kgdb_arch_handle_exception(int vector, int signo, int err_code, struct kgdb_arch arch_kgdb_ops; -/* - * We use kgdb_early_setup so that functions we need to call now don't - * cause trouble when called again later. - */ int kgdb_arch_init(void) { union mips_instruction insn = { diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c index e303cb1ef2f4..b130033838ba 100644 --- a/arch/mips/kernel/prom.c +++ b/arch/mips/kernel/prom.c @@ -18,6 +18,7 @@ #include <linux/of_fdt.h> #include <linux/of_platform.h> +#include <asm/bootinfo.h> #include <asm/page.h> #include <asm/prom.h> diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index d544e774eea6..e933a309f2ea 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -176,7 +176,7 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data) __get_user(value, data + 64); fcr31 = child->thread.fpu.fcr31; - mask = current_cpu_data.fpu_msk31; + mask = boot_cpu_data.fpu_msk31; child->thread.fpu.fcr31 = (value & ~mask) | (fcr31 & mask); /* FIR may not be written. */ diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index 06805e09bcd3..0b85f827cd18 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h @@ -28,12 +28,7 @@ extern void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, extern int fpcsr_pending(unsigned int __user *fpcsr); /* Make sure we will not lose FPU ownership */ -#ifdef CONFIG_PREEMPT -#define lock_fpu_owner() preempt_disable() -#define unlock_fpu_owner() preempt_enable() -#else -#define lock_fpu_owner() pagefault_disable() -#define unlock_fpu_owner() pagefault_enable() -#endif +#define lock_fpu_owner() ({ preempt_disable(); pagefault_disable(); }) +#define unlock_fpu_owner() ({ pagefault_enable(); preempt_enable(); }) #endif /* __SIGNAL_COMMON_H */ diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c index fd528d7ea278..336708ae5c5b 100644 --- a/arch/mips/kernel/smp-bmips.c +++ b/arch/mips/kernel/smp-bmips.c @@ -444,7 +444,7 @@ struct plat_smp_ops bmips5000_smp_ops = { static void bmips_wr_vec(unsigned long dst, char *start, char *end) { memcpy((void *)dst, start, end - start); - dma_cache_wback((unsigned long)start, end - start); + dma_cache_wback(dst, end - start); local_flush_icache_range(dst, dst + (end - start)); instruction_hazard(); } diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index 7e011f95bb8e..4251d390b5b6 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -92,7 +92,7 @@ static void __init cps_smp_setup(void) #ifdef CONFIG_MIPS_MT_FPAFF /* If we have an FPU, enroll ourselves in the FPU-full mask */ if (cpu_has_fpu) - cpu_set(0, mt_fpu_cpumask); + cpumask_set_cpu(0, &mt_fpu_cpumask); #endif /* CONFIG_MIPS_MT_FPAFF */ } diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 193ace7955fb..faa46ebd9dda 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -43,7 +43,7 @@ #include <asm/time.h> #include <asm/setup.h> -volatile cpumask_t cpu_callin_map; /* Bitmask of started secondaries */ +cpumask_t cpu_callin_map; /* Bitmask of started secondaries */ int __cpu_number_map[NR_CPUS]; /* Map physical to logical */ EXPORT_SYMBOL(__cpu_number_map); @@ -218,8 +218,10 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle) /* * Trust is futile. We should really have timeouts ... */ - while (!cpumask_test_cpu(cpu, &cpu_callin_map)) + while (!cpumask_test_cpu(cpu, &cpu_callin_map)) { udelay(100); + schedule(); + } synchronise_count_master(cpu); return 0; diff --git a/arch/mips/kernel/sysrq.c b/arch/mips/kernel/sysrq.c new file mode 100644 index 000000000000..5b539f5fc9d9 --- /dev/null +++ b/arch/mips/kernel/sysrq.c @@ -0,0 +1,77 @@ +/* + * MIPS specific sysrq operations. + * + * Copyright (C) 2015 Imagination Technologies Ltd. + */ +#include <linux/init.h> +#include <linux/smp.h> +#include <linux/spinlock.h> +#include <linux/sysrq.h> +#include <linux/workqueue.h> + +#include <asm/cpu-features.h> +#include <asm/mipsregs.h> +#include <asm/tlbdebug.h> + +/* + * Dump TLB entries on all CPUs. + */ + +static DEFINE_SPINLOCK(show_lock); + +static void sysrq_tlbdump_single(void *dummy) +{ + const int field = 2 * sizeof(unsigned long); + unsigned long flags; + + spin_lock_irqsave(&show_lock, flags); + + pr_info("CPU%d:\n", smp_processor_id()); + pr_info("Index : %0x\n", read_c0_index()); + pr_info("Pagemask: %0x\n", read_c0_pagemask()); + pr_info("EntryHi : %0*lx\n", field, read_c0_entryhi()); + pr_info("EntryLo0: %0*lx\n", field, read_c0_entrylo0()); + pr_info("EntryLo1: %0*lx\n", field, read_c0_entrylo1()); + pr_info("Wired : %0x\n", read_c0_wired()); + pr_info("Pagegrain: %0x\n", read_c0_pagegrain()); + if (cpu_has_htw) { + pr_info("PWField : %0*lx\n", field, read_c0_pwfield()); + pr_info("PWSize : %0*lx\n", field, read_c0_pwsize()); + pr_info("PWCtl : %0x\n", read_c0_pwctl()); + } + pr_info("\n"); + dump_tlb_all(); + pr_info("\n"); + + spin_unlock_irqrestore(&show_lock, flags); +} + +#ifdef CONFIG_SMP +static void sysrq_tlbdump_othercpus(struct work_struct *dummy) +{ + smp_call_function(sysrq_tlbdump_single, NULL, 0); +} + +static DECLARE_WORK(sysrq_tlbdump, sysrq_tlbdump_othercpus); +#endif + +static void sysrq_handle_tlbdump(int key) +{ + sysrq_tlbdump_single(NULL); +#ifdef CONFIG_SMP + schedule_work(&sysrq_tlbdump); +#endif +} + +static struct sysrq_key_op sysrq_tlbdump_op = { + .handler = sysrq_handle_tlbdump, + .help_msg = "show-tlbs(x)", + .action_msg = "Show TLB entries", + .enable_mask = SYSRQ_ENABLE_DUMP, +}; + +static int __init mips_sysrq_init(void) +{ + return register_sysrq_key('x', &sysrq_tlbdump_op); +} +arch_initcall(mips_sysrq_init); diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index ba32e48d4697..2a7b38ed23f0 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -236,6 +236,7 @@ static void __show_regs(const struct pt_regs *regs) { const int field = 2 * sizeof(unsigned long); unsigned int cause = regs->cp0_cause; + unsigned int exccode; int i; show_regs_print_info(KERN_DEFAULT); @@ -269,7 +270,6 @@ static void __show_regs(const struct pt_regs *regs) */ printk("epc : %0*lx %pS\n", field, regs->cp0_epc, (void *) regs->cp0_epc); - printk(" %s\n", print_tainted()); printk("ra : %0*lx %pS\n", field, regs->regs[31], (void *) regs->regs[31]); @@ -318,10 +318,10 @@ static void __show_regs(const struct pt_regs *regs) } printk("\n"); - printk("Cause : %08x\n", cause); + exccode = (cause & CAUSEF_EXCCODE) >> CAUSEB_EXCCODE; + printk("Cause : %08x (ExcCode %02x)\n", cause, exccode); - cause = (cause & CAUSEF_EXCCODE) >> CAUSEB_EXCCODE; - if (1 <= cause && cause <= 5) + if (1 <= exccode && exccode <= 5) printk("BadVA : %0*lx\n", field, regs->cp0_badvaddr); printk("PrId : %08x (%s)\n", read_c0_prid(), @@ -2185,11 +2185,6 @@ void __init trap_init(void) check_wait(); -#if defined(CONFIG_KGDB) - if (kgdb_early_setup) - return; /* Already done */ -#endif - if (cpu_has_veic || cpu_has_vint) { unsigned long size = 0x200 + VECTORSPACING*64; ebase = (unsigned long) diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index 3b46f7ce9ca7..07d32a4aea60 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -125,8 +125,14 @@ SECTIONS .exit.data : { EXIT_DATA } - +#ifdef CONFIG_SMP PERCPU_SECTION(1 << CONFIG_MIPS_L1_CACHE_SHIFT) +#endif +#ifdef CONFIG_MIPS_RAW_APPENDED_DTB + __appended_dtb = .; + /* leave space for appended DTB */ + . += 0x100000; +#endif /* * Align to 64K in attempt to eliminate holes before the * .bss..swapper_pg_dir section at the start of .bss. This |