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:
Linus Torvalds 2015-11-15 09:10:53 -08:00
commit b84da9fa47
151 changed files with 4596 additions and 755 deletions

View file

@ -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

View 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

View file

@ -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

View file

@ -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;
}

View file

@ -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);

View file

@ -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;

View file

@ -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 */

View file

@ -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)

View file

@ -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)

View file

@ -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) {

View file

@ -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);

View file

@ -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);
}

View file

@ -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,
};

View file

@ -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,
};

View file

@ -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);
}

View file

@ -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();
}
}

View file

@ -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;

View file

@ -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);

View file

@ -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);
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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)