aboutsummaryrefslogtreecommitdiff
path: root/arch/mips/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r--arch/mips/kernel/Makefile2
-rw-r--r--arch/mips/kernel/cpu-probe.c15
-rw-r--r--arch/mips/kernel/head.S16
-rw-r--r--arch/mips/kernel/i8259.c43
-rw-r--r--arch/mips/kernel/irq.c54
-rw-r--r--arch/mips/kernel/irq_cpu.c169
-rw-r--r--arch/mips/kernel/kgdb.c4
-rw-r--r--arch/mips/kernel/prom.c1
-rw-r--r--arch/mips/kernel/signal-common.h9
-rw-r--r--arch/mips/kernel/sysrq.c77
-rw-r--r--arch/mips/kernel/traps.c12
-rw-r--r--arch/mips/kernel/vmlinux.lds.S8
12 files changed, 160 insertions, 250 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/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 51f57d841662..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 DECLARE_BITMAP(irq_map, NR_IRQS);
-
-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/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/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 d2d1c1933bc9..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);
@@ -317,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(),
@@ -2184,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