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 | 12 | ||||
-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 | 52 | ||||
-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/sysrq.c | 77 | ||||
-rw-r--r-- | arch/mips/kernel/traps.c | 12 | ||||
-rw-r--r-- | arch/mips/kernel/vmlinux.lds.S | 8 |
11 files changed, 156 insertions, 240 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 209e5b76c1bc..dbe0792fc9c1 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -945,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: @@ -960,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 */ @@ -1443,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: @@ -1478,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 3c8a18a00a65..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,20 +51,10 @@ 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 CONFIG_DEBUG_STACKOVERFLOW 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/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 |