mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-07-23 07:12:09 +00:00
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
Pull MIPS updates from Ralf Baechle: "These are the highlists of the main MIPS pull request for 4.4: - Add latencytop support - Support appended DTBs - VDSO support and initially use it for gettimeofday. - Drop the .MIPS.abiflags and ELF NOTE sections from vmlinux - Support for the 5KE, an internal test core. - Switch all MIPS platfroms to libata drivers. - Improved support, cleanups for ralink and Lantiq platforms. - Support for the new xilfpga platform. - A number of DTB improvments for BMIPS. - Improved support for CM and CPS. - Minor JZ4740 and BCM47xx enhancements" * 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (120 commits) MIPS: idle: add case for CPU_5KE MIPS: Octeon: Support APPENDED_DTB MIPS: vmlinux: create a section for appended DTB MIPS: Clean up compat_siginfo_t MIPS: Fix PAGE_MASK definition MIPS: BMIPS: Enable GZIP ramdisk and timed printks MIPS: Add xilfpga defconfig MIPS: xilfpga: Add mipsfpga platform code MIPS: xilfpga: Add xilfpga device tree files. dt-bindings: MIPS: Document xilfpga bindings and boot style MIPS: Make MIPS_CMDLINE_DTB default MIPS: Make the kernel arguments from dtb available MIPS: Use USE_OF as the guard for appended dtb MIPS: BCM63XX: Use pr_* instead of printk MIPS: Loongson: Cleanup CONFIG_LOONGSON_SUSPEND. MIPS: lantiq: Disable xbar fpi burst mode MIPS: lantiq: Force the crossbar to big endian MIPS: lantiq: Initialize the USB core on boot MIPS: lantiq: Return correct value for fpi clock on ar9 MIPS: ralink: Add missing clock on rt305x ...
This commit is contained in:
commit
b84da9fa47
151 changed files with 4596 additions and 755 deletions
|
@ -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
|
||||
|
||||
|
|
202
arch/mips/kernel/cps-vec-ns16550.S
Normal file
202
arch/mips/kernel/cps-vec-ns16550.S
Normal file
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Imagination Technologies
|
||||
* Author: Paul Burton <paul.burton@imgtec.com>
|
||||
*
|
||||
* 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 <asm/addrspace.h>
|
||||
#include <asm/asm.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/regdef.h>
|
||||
#include <linux/serial_reg.h>
|
||||
|
||||
#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
|
|
@ -25,14 +25,32 @@
|
|||
|
||||
.set noreorder
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
# define STATUS_BITDEPS ST0_KX
|
||||
#else
|
||||
# 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.
|
||||
*/
|
||||
.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
|
||||
|
@ -47,11 +65,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 */
|
||||
|
@ -71,7 +87,7 @@ not_nmi:
|
|||
mtc0 t0, CP0_CAUSE
|
||||
|
||||
/* Setup Status */
|
||||
li t0, ST0_CU1 | ST0_CU0
|
||||
li t0, ST0_CU1 | ST0_CU0 | ST0_BEV | STATUS_BITDEPS
|
||||
mtc0 t0, CP0_STATUS
|
||||
|
||||
/*
|
||||
|
@ -151,6 +167,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)
|
||||
|
@ -188,36 +210,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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
@ -155,12 +165,12 @@ 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:
|
||||
case CPU_BMIPS4350:
|
||||
case CPU_BMIPS4380:
|
||||
case CPU_BMIPS5000:
|
||||
case CPU_CAVIUM_OCTEON:
|
||||
case CPU_CAVIUM_OCTEON_PLUS:
|
||||
case CPU_CAVIUM_OCTEON2:
|
||||
|
@ -171,7 +181,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;
|
||||
|
@ -196,7 +208,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;
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <asm/mips-cm.h>
|
||||
#include <asm/mipsregs.h>
|
||||
|
@ -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,38 +253,70 @@ 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);
|
||||
|
||||
/*
|
||||
* Ensure the core-other region reflects the appropriate core &
|
||||
* VP before any accesses to it occur.
|
||||
*/
|
||||
mb();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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
|
||||
* 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 = 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();
|
||||
u64 cm_error, cm_addr, cm_other;
|
||||
unsigned long revision;
|
||||
int ocause, cause;
|
||||
char buf[256];
|
||||
|
||||
if (!mips_cm_present())
|
||||
return;
|
||||
|
||||
cause = cm_error >> cm_error_cause_sft;
|
||||
revision = mips_cm_revision();
|
||||
|
||||
if (!cause)
|
||||
/* All good */
|
||||
return;
|
||||
|
||||
ocause = cm_other >> CM_GCR_ERROR_MULT_ERR2ND_SHF;
|
||||
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)
|
||||
return;
|
||||
|
||||
if (cause < 16) {
|
||||
unsigned long cca_bits = (cm_error >> 15) & 7;
|
||||
unsigned long tr_bits = (cm_error >> 12) & 7;
|
||||
|
@ -310,18 +348,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;
|
||||
|
@ -363,12 +413,14 @@ 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,
|
||||
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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <asm/asm.h>
|
||||
#include <asm/branch.h>
|
||||
#include <asm/break.h>
|
||||
#include <asm/debug.h>
|
||||
#include <asm/fpu.h>
|
||||
#include <asm/fpu_emulator.h>
|
||||
#include <asm/inst.h>
|
||||
|
@ -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)
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/debug.h>
|
||||
#include <asm/mipsregs.h>
|
||||
|
||||
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) {
|
||||
|
|
|
@ -33,11 +33,16 @@
|
|||
#include <asm/cache.h>
|
||||
#include <asm/cdmm.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/debug.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/smp-ops.h>
|
||||
#include <asm/prom.h>
|
||||
|
||||
#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);
|
||||
|
@ -616,6 +621,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;
|
||||
|
@ -640,18 +649,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 (builtin_cmdline[0]) {
|
||||
strlcat(arcs_cmdline, " ", COMMAND_LINE_SIZE);
|
||||
strlcat(arcs_cmdline, builtin_cmdline, COMMAND_LINE_SIZE);
|
||||
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(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);
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
#include <asm/ucontext.h>
|
||||
#include <asm/cpu-features.h>
|
||||
#include <asm/war.h>
|
||||
#include <asm/vdso.h>
|
||||
#include <asm/dsp.h>
|
||||
#include <asm/inst.h>
|
||||
#include <asm/msa.h>
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include <asm/ucontext.h>
|
||||
#include <asm/fpu.h>
|
||||
#include <asm/war.h>
|
||||
#include <asm/vdso.h>
|
||||
#include <asm/dsp.h>
|
||||
|
||||
#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,
|
||||
};
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
#include <asm/fpu.h>
|
||||
#include <asm/cpu-features.h>
|
||||
#include <asm/war.h>
|
||||
#include <asm/vdso.h>
|
||||
|
||||
#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,
|
||||
};
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irqchip/mips-gic.h>
|
||||
#include <linux/sched.h>
|
||||
|
@ -37,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;
|
||||
}
|
||||
|
||||
|
@ -133,11 +135,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);
|
||||
|
@ -190,10 +190,11 @@ 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);
|
||||
mips_cm_lock_other(core, 0);
|
||||
|
||||
/* Set its reset vector */
|
||||
write_gcr_co_reset_base(CKSEG1ADDR((unsigned long)mips_cps_core_entry));
|
||||
|
@ -210,12 +211,36 @@ 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 */
|
||||
write_gcr_co_reset_release(0);
|
||||
}
|
||||
|
||||
mips_cm_unlock_other();
|
||||
|
||||
/* The core is now powered up */
|
||||
bitmap_set(core_power, core, 1);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <linux/debugfs.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <asm/debug.h>
|
||||
|
||||
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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <linux/irq.h>
|
||||
#include <linux/perf_event.h>
|
||||
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/branch.h>
|
||||
#include <asm/break.h>
|
||||
|
@ -1856,12 +1857,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 */
|
||||
|
@ -2204,12 +2207,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);
|
||||
}
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
#include <asm/branch.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/cop2.h>
|
||||
#include <asm/debug.h>
|
||||
#include <asm/fpu.h>
|
||||
#include <asm/fpu_emulator.h>
|
||||
#include <asm/inst.h>
|
||||
|
@ -2295,7 +2296,6 @@ sigbus:
|
|||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
extern struct dentry *mips_debugfs_dir;
|
||||
static int __init debugfs_unaligned(void)
|
||||
{
|
||||
struct dentry *d;
|
||||
|
|
|
@ -1,122 +1,175 @@
|
|||
/*
|
||||
* 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 <alex.smith@imgtec.com>
|
||||
*
|
||||
* 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 <linux/kernel.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/binfmts.h>
|
||||
#include <linux/elf.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/irqchip/mips-gic.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/timekeeper_internal.h>
|
||||
|
||||
#include <asm/abi.h>
|
||||
#include <asm/vdso.h>
|
||||
#include <asm/uasm.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
/* Kernel-provided data used by the VDSO. */
|
||||
static union mips_vdso_data vdso_data __page_aligned_data;
|
||||
|
||||
/*
|
||||
* Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
|
||||
* 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.
|
||||
*/
|
||||
#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;
|
||||
init_vdso_image(&vdso_image);
|
||||
|
||||
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);
|
||||
#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)
|
||||
void update_vsyscall(struct timekeeper *tk)
|
||||
{
|
||||
unsigned long offset = 0UL;
|
||||
vdso_data_write_begin(&vdso_data);
|
||||
|
||||
if (current->flags & PF_RANDOMIZE) {
|
||||
offset = get_random_int();
|
||||
offset <<= PAGE_SHIFT;
|
||||
if (TASK_IS_32BIT_ADDR)
|
||||
offset &= 0xfffffful;
|
||||
else
|
||||
offset &= 0xffffffful;
|
||||
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;
|
||||
}
|
||||
|
||||
return STACK_TOP + offset;
|
||||
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)
|
||||
{
|
||||
int ret;
|
||||
unsigned long addr;
|
||||
struct mips_vdso_image *image = current->thread.abi->vdso;
|
||||
struct mm_struct *mm = current->mm;
|
||||
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);
|
||||
|
||||
addr = vdso_addr(mm->start_stack);
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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, 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);
|
||||
data_addr = base + gic_size;
|
||||
vdso_addr = data_addr + PAGE_SIZE;
|
||||
|
||||
vma = _install_special_mapping(mm, base, vvar_size,
|
||||
VM_READ | VM_MAYREAD,
|
||||
&vdso_vvar_mapping);
|
||||
if (IS_ERR(vma)) {
|
||||
ret = PTR_ERR(vma);
|
||||
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, data_addr,
|
||||
virt_to_phys(&vdso_data) >> PAGE_SHIFT,
|
||||
PAGE_SIZE, PAGE_READONLY);
|
||||
if (ret)
|
||||
goto up_fail;
|
||||
goto out;
|
||||
|
||||
mm->context.vdso = (void *)addr;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
up_fail:
|
||||
mm->context.vdso = (void *)vdso_addr;
|
||||
ret = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
@ -132,6 +139,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
|
||||
|
@ -181,6 +193,7 @@ SECTIONS
|
|||
DISCARDS
|
||||
/DISCARD/ : {
|
||||
/* ABI crap starts here */
|
||||
*(.MIPS.abiflags)
|
||||
*(.MIPS.options)
|
||||
*(.options)
|
||||
*(.pdr)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue