summaryrefslogtreecommitdiff
path: root/arch/xtensa/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-10-05 17:44:48 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2016-10-05 17:44:48 -0700
commitd8ea757b25ec82687c497fc90aa83f9bcea24b5b (patch)
tree4789c4d89f1ec77dcb27b855e2f479c3afd511cb /arch/xtensa/kernel
parent41844e36206be90cd4d962ea49b0abc3612a99d0 (diff)
parenta4c6be5ad1d0c7af0c5421b68a00b6406b28a325 (diff)
Merge tag 'xtensa-20161005' of git://github.com/jcmvbkbc/linux-xtensa
Pull Xtensa updates from Max Filippov: "Updates for the xtensa architecture. It is a combined set of patches for 4.8 that never got to the mainline and new patches for 4.9. - add new kernel memory layouts for MMUv3 cores: with 256MB and 512MB KSEG size, starting at physical address other than 0 - make kernel load address configurable - clean up kernel memory layout macros - drop sysmem early allocator and switch to memblock - enable kmemleak and memory reservation from the device tree - wire up new syscalls: userfaultfd, membarrier, mlock2, copy_file_range, preadv2 and pwritev2 - add new platform: Cadence Configurable System Platform (CSP) and new core variant for it: xt_lnx - rearrange CCOUNT calibration code, make most of it generic - improve machine reset code (XTFPGA now reboots reliably with MMUv3 cores) - provide default memmap command line option for configurations without device tree support - ISS fixes: simdisk is now capable of using highmem pages, panic correctly terminates simulator" * tag 'xtensa-20161005' of git://github.com/jcmvbkbc/linux-xtensa: (24 commits) xtensa: disable MMU initialization option on MMUv2 cores xtensa: add default memmap and mmio32native options to defconfigs xtensa: add default memmap option to common_defconfig xtensa: add default memmap option to iss_defconfig xtensa: ISS: allow simdisk to use high memory buffers xtensa: ISS: define simc_exit and use it instead of inline asm xtensa: xtfpga: group platform_* functions together xtensa: rearrange CCOUNT calibration xtensa: xtfpga: use clock provider, don't update DT xtensa: Tweak xuartps UART driver Rx watermark for Cadence CSP config. xtensa: initialize MMU before jumping to reset vector xtensa: fix icountlevel setting in cpu_reset xtensa: extract common CPU reset code into separate function xtensa: Added Cadence CSP kernel configuration for Xtensa xtensa: fix default kernel load address xtensa: wire up new syscalls xtensa: support reserved-memory DT node xtensa: drop sysmem and switch to memblock xtensa: minimize use of PLATFORM_DEFAULT_MEM_{ADDR,SIZE} xtensa: cleanup MMU setup and kernel layout macros ...
Diffstat (limited to 'arch/xtensa/kernel')
-rw-r--r--arch/xtensa/kernel/entry.S5
-rw-r--r--arch/xtensa/kernel/head.S2
-rw-r--r--arch/xtensa/kernel/setup.c188
-rw-r--r--arch/xtensa/kernel/time.c40
-rw-r--r--arch/xtensa/kernel/vmlinux.lds.S4
5 files changed, 194 insertions, 45 deletions
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
index fe8f7e7efb9d..fa04d9d368a7 100644
--- a/arch/xtensa/kernel/entry.S
+++ b/arch/xtensa/kernel/entry.S
@@ -1632,10 +1632,11 @@ ENTRY(fast_second_level_miss)
* The messy computation for 'pteval' above really simplifies
* into the following:
*
- * pteval = ((pmdval - PAGE_OFFSET) & PAGE_MASK) | PAGE_DIRECTORY
+ * pteval = ((pmdval - PAGE_OFFSET + PHYS_OFFSET) & PAGE_MASK)
+ * | PAGE_DIRECTORY
*/
- movi a1, (-PAGE_OFFSET) & 0xffffffff
+ movi a1, (PHYS_OFFSET - PAGE_OFFSET) & 0xffffffff
add a0, a0, a1 # pmdval - PAGE_OFFSET
extui a1, a0, 0, PAGE_SHIFT # ... & PAGE_MASK
xor a0, a0, a1
diff --git a/arch/xtensa/kernel/head.S b/arch/xtensa/kernel/head.S
index bc4f4bf05099..23ce62e60435 100644
--- a/arch/xtensa/kernel/head.S
+++ b/arch/xtensa/kernel/head.S
@@ -113,7 +113,7 @@ ENTRY(_startup)
movi a0, 0
#if XCHAL_HAVE_VECBASE
- movi a2, VECBASE_RESET_VADDR
+ movi a2, VECBASE_VADDR
wsr a2, vecbase
#endif
diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c
index 143251ede897..88a044af7504 100644
--- a/arch/xtensa/kernel/setup.c
+++ b/arch/xtensa/kernel/setup.c
@@ -7,6 +7,7 @@
*
* Copyright (C) 1995 Linus Torvalds
* Copyright (C) 2001 - 2005 Tensilica Inc.
+ * Copyright (C) 2014 - 2016 Cadence Design Systems Inc.
*
* Chris Zankel <chris@zankel.net>
* Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
@@ -22,7 +23,6 @@
#include <linux/bootmem.h>
#include <linux/kernel.h>
#include <linux/percpu.h>
-#include <linux/clk-provider.h>
#include <linux/cpu.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
@@ -114,7 +114,7 @@ static int __init parse_tag_mem(const bp_tag_t *tag)
if (mi->type != MEMORY_TYPE_CONVENTIONAL)
return -1;
- return add_sysmem_bank(mi->start, mi->end);
+ return memblock_add(mi->start, mi->end - mi->start);
}
__tagtable(BP_TAG_MEMORY, parse_tag_mem);
@@ -188,7 +188,6 @@ static int __init parse_bootparam(const bp_tag_t* tag)
}
#ifdef CONFIG_OF
-bool __initdata dt_memory_scan = false;
#if !XCHAL_HAVE_PTP_MMU || XCHAL_HAVE_SPANNING_WAY
unsigned long xtensa_kio_paddr = XCHAL_KIO_DEFAULT_PADDR;
@@ -228,11 +227,8 @@ static int __init xtensa_dt_io_area(unsigned long node, const char *uname,
void __init early_init_dt_add_memory_arch(u64 base, u64 size)
{
- if (!dt_memory_scan)
- return;
-
size &= PAGE_MASK;
- add_sysmem_bank(base, base + size);
+ memblock_add(base, size);
}
void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
@@ -242,9 +238,6 @@ void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
void __init early_init_devtree(void *params)
{
- if (sysmem.nr_banks == 0)
- dt_memory_scan = true;
-
early_init_dt_scan(params);
of_scan_flat_dt(xtensa_dt_io_area, NULL);
@@ -252,14 +245,6 @@ void __init early_init_devtree(void *params)
strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
}
-static int __init xtensa_device_probe(void)
-{
- of_clk_init(NULL);
- return 0;
-}
-
-device_initcall(xtensa_device_probe);
-
#endif /* CONFIG_OF */
/*
@@ -277,12 +262,6 @@ void __init init_arch(bp_tag_t *bp_start)
early_init_devtree(dtb_start);
#endif
- if (sysmem.nr_banks == 0) {
- add_sysmem_bank(PLATFORM_DEFAULT_MEM_START,
- PLATFORM_DEFAULT_MEM_START +
- PLATFORM_DEFAULT_MEM_SIZE);
- }
-
#ifdef CONFIG_CMDLINE_BOOL
if (!command_line[0])
strlcpy(command_line, default_command_line, COMMAND_LINE_SIZE);
@@ -452,6 +431,10 @@ static int __init check_s32c1i(void)
early_initcall(check_s32c1i);
#endif /* CONFIG_S32C1I_SELFTEST */
+static inline int mem_reserve(unsigned long start, unsigned long end)
+{
+ return memblock_reserve(start, end - start);
+}
void __init setup_arch(char **cmdline_p)
{
@@ -463,54 +446,54 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start < initrd_end) {
initrd_is_mapped = mem_reserve(__pa(initrd_start),
- __pa(initrd_end), 0) == 0;
+ __pa(initrd_end)) == 0;
initrd_below_start_ok = 1;
} else {
initrd_start = 0;
}
#endif
- mem_reserve(__pa(&_stext),__pa(&_end), 1);
+ mem_reserve(__pa(&_stext), __pa(&_end));
mem_reserve(__pa(&_WindowVectors_text_start),
- __pa(&_WindowVectors_text_end), 0);
+ __pa(&_WindowVectors_text_end));
mem_reserve(__pa(&_DebugInterruptVector_literal_start),
- __pa(&_DebugInterruptVector_text_end), 0);
+ __pa(&_DebugInterruptVector_text_end));
mem_reserve(__pa(&_KernelExceptionVector_literal_start),
- __pa(&_KernelExceptionVector_text_end), 0);
+ __pa(&_KernelExceptionVector_text_end));
mem_reserve(__pa(&_UserExceptionVector_literal_start),
- __pa(&_UserExceptionVector_text_end), 0);
+ __pa(&_UserExceptionVector_text_end));
mem_reserve(__pa(&_DoubleExceptionVector_literal_start),
- __pa(&_DoubleExceptionVector_text_end), 0);
+ __pa(&_DoubleExceptionVector_text_end));
#if XCHAL_EXCM_LEVEL >= 2
mem_reserve(__pa(&_Level2InterruptVector_text_start),
- __pa(&_Level2InterruptVector_text_end), 0);
+ __pa(&_Level2InterruptVector_text_end));
#endif
#if XCHAL_EXCM_LEVEL >= 3
mem_reserve(__pa(&_Level3InterruptVector_text_start),
- __pa(&_Level3InterruptVector_text_end), 0);
+ __pa(&_Level3InterruptVector_text_end));
#endif
#if XCHAL_EXCM_LEVEL >= 4
mem_reserve(__pa(&_Level4InterruptVector_text_start),
- __pa(&_Level4InterruptVector_text_end), 0);
+ __pa(&_Level4InterruptVector_text_end));
#endif
#if XCHAL_EXCM_LEVEL >= 5
mem_reserve(__pa(&_Level5InterruptVector_text_start),
- __pa(&_Level5InterruptVector_text_end), 0);
+ __pa(&_Level5InterruptVector_text_end));
#endif
#if XCHAL_EXCM_LEVEL >= 6
mem_reserve(__pa(&_Level6InterruptVector_text_start),
- __pa(&_Level6InterruptVector_text_end), 0);
+ __pa(&_Level6InterruptVector_text_end));
#endif
#ifdef CONFIG_SMP
mem_reserve(__pa(&_SecondaryResetVector_text_start),
- __pa(&_SecondaryResetVector_text_end), 0);
+ __pa(&_SecondaryResetVector_text_end));
#endif
parse_early_param();
bootmem_init();
@@ -555,6 +538,137 @@ static int __init topology_init(void)
}
subsys_initcall(topology_init);
+void cpu_reset(void)
+{
+#if XCHAL_HAVE_PTP_MMU
+ local_irq_disable();
+ /*
+ * We have full MMU: all autoload ways, ways 7, 8 and 9 of DTLB must
+ * be flushed.
+ * Way 4 is not currently used by linux.
+ * Ways 5 and 6 shall not be touched on MMUv2 as they are hardwired.
+ * Way 5 shall be flushed and way 6 shall be set to identity mapping
+ * on MMUv3.
+ */
+ local_flush_tlb_all();
+ invalidate_page_directory();
+#if XCHAL_HAVE_SPANNING_WAY
+ /* MMU v3 */
+ {
+ unsigned long vaddr = (unsigned long)cpu_reset;
+ unsigned long paddr = __pa(vaddr);
+ unsigned long tmpaddr = vaddr + SZ_512M;
+ unsigned long tmp0, tmp1, tmp2, tmp3;
+
+ /*
+ * Find a place for the temporary mapping. It must not be
+ * in the same 512MB region with vaddr or paddr, otherwise
+ * there may be multihit exception either on entry to the
+ * temporary mapping, or on entry to the identity mapping.
+ * (512MB is the biggest page size supported by TLB.)
+ */
+ while (((tmpaddr ^ paddr) & -SZ_512M) == 0)
+ tmpaddr += SZ_512M;
+
+ /* Invalidate mapping in the selected temporary area */
+ if (itlb_probe(tmpaddr) & 0x8)
+ invalidate_itlb_entry(itlb_probe(tmpaddr));
+ if (itlb_probe(tmpaddr + PAGE_SIZE) & 0x8)
+ invalidate_itlb_entry(itlb_probe(tmpaddr + PAGE_SIZE));
+
+ /*
+ * Map two consecutive pages starting at the physical address
+ * of this function to the temporary mapping area.
+ */
+ write_itlb_entry(__pte((paddr & PAGE_MASK) |
+ _PAGE_HW_VALID |
+ _PAGE_HW_EXEC |
+ _PAGE_CA_BYPASS),
+ tmpaddr & PAGE_MASK);
+ write_itlb_entry(__pte(((paddr & PAGE_MASK) + PAGE_SIZE) |
+ _PAGE_HW_VALID |
+ _PAGE_HW_EXEC |
+ _PAGE_CA_BYPASS),
+ (tmpaddr & PAGE_MASK) + PAGE_SIZE);
+
+ /* Reinitialize TLB */
+ __asm__ __volatile__ ("movi %0, 1f\n\t"
+ "movi %3, 2f\n\t"
+ "add %0, %0, %4\n\t"
+ "add %3, %3, %5\n\t"
+ "jx %0\n"
+ /*
+ * No literal, data or stack access
+ * below this point
+ */
+ "1:\n\t"
+ /* Initialize *tlbcfg */
+ "movi %0, 0\n\t"
+ "wsr %0, itlbcfg\n\t"
+ "wsr %0, dtlbcfg\n\t"
+ /* Invalidate TLB way 5 */
+ "movi %0, 4\n\t"
+ "movi %1, 5\n"
+ "1:\n\t"
+ "iitlb %1\n\t"
+ "idtlb %1\n\t"
+ "add %1, %1, %6\n\t"
+ "addi %0, %0, -1\n\t"
+ "bnez %0, 1b\n\t"
+ /* Initialize TLB way 6 */
+ "movi %0, 7\n\t"
+ "addi %1, %9, 3\n\t"
+ "addi %2, %9, 6\n"
+ "1:\n\t"
+ "witlb %1, %2\n\t"
+ "wdtlb %1, %2\n\t"
+ "add %1, %1, %7\n\t"
+ "add %2, %2, %7\n\t"
+ "addi %0, %0, -1\n\t"
+ "bnez %0, 1b\n\t"
+ /* Jump to identity mapping */
+ "jx %3\n"
+ "2:\n\t"
+ /* Complete way 6 initialization */
+ "witlb %1, %2\n\t"
+ "wdtlb %1, %2\n\t"
+ /* Invalidate temporary mapping */
+ "sub %0, %9, %7\n\t"
+ "iitlb %0\n\t"
+ "add %0, %0, %8\n\t"
+ "iitlb %0"
+ : "=&a"(tmp0), "=&a"(tmp1), "=&a"(tmp2),
+ "=&a"(tmp3)
+ : "a"(tmpaddr - vaddr),
+ "a"(paddr - vaddr),
+ "a"(SZ_128M), "a"(SZ_512M),
+ "a"(PAGE_SIZE),
+ "a"((tmpaddr + SZ_512M) & PAGE_MASK)
+ : "memory");
+ }
+#endif
+#endif
+ __asm__ __volatile__ ("movi a2, 0\n\t"
+ "wsr a2, icountlevel\n\t"
+ "movi a2, 0\n\t"
+ "wsr a2, icount\n\t"
+#if XCHAL_NUM_IBREAK > 0
+ "wsr a2, ibreakenable\n\t"
+#endif
+#if XCHAL_HAVE_LOOPS
+ "wsr a2, lcount\n\t"
+#endif
+ "movi a2, 0x1f\n\t"
+ "wsr a2, ps\n\t"
+ "isync\n\t"
+ "jx %0\n\t"
+ :
+ : "a" (XCHAL_RESET_VECTOR_VADDR)
+ : "a2");
+ for (;;)
+ ;
+}
+
void machine_restart(char * cmd)
{
platform_restart();
diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c
index b9ad9feadc2d..9a5bcd0381a7 100644
--- a/arch/xtensa/kernel/time.c
+++ b/arch/xtensa/kernel/time.c
@@ -12,6 +12,8 @@
* Chris Zankel <chris@zankel.net>
*/
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/time.h>
@@ -134,16 +136,52 @@ void local_timer_setup(unsigned cpu)
0xf, 0xffffffff);
}
+#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
+#ifdef CONFIG_OF
+static void __init calibrate_ccount(void)
+{
+ struct device_node *cpu;
+ struct clk *clk;
+
+ cpu = of_find_compatible_node(NULL, NULL, "cdns,xtensa-cpu");
+ if (cpu) {
+ clk = of_clk_get(cpu, 0);
+ if (!IS_ERR(clk)) {
+ ccount_freq = clk_get_rate(clk);
+ return;
+ } else {
+ pr_warn("%s: CPU input clock not found\n",
+ __func__);
+ }
+ } else {
+ pr_warn("%s: CPU node not found in the device tree\n",
+ __func__);
+ }
+
+ platform_calibrate_ccount();
+}
+#else
+static inline void calibrate_ccount(void)
+{
+ platform_calibrate_ccount();
+}
+#endif
+#endif
+
void __init time_init(void)
{
+ of_clk_init(NULL);
#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
printk("Calibrating CPU frequency ");
- platform_calibrate_ccount();
+ calibrate_ccount();
printk("%d.%02d MHz\n", (int)ccount_freq/1000000,
(int)(ccount_freq/10000)%100);
#else
ccount_freq = CONFIG_XTENSA_CPU_CLOCK*1000000UL;
#endif
+ WARN(!ccount_freq,
+ "%s: CPU clock frequency is not set up correctly\n",
+ __func__);
clocksource_register_hz(&ccount_clocksource, ccount_freq);
local_timer_setup(0);
setup_irq(this_cpu_ptr(&ccount_timer)->evt.irq, &timer_irqaction);
diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S
index c417cbe4ec87..72cfe3587dd8 100644
--- a/arch/xtensa/kernel/vmlinux.lds.S
+++ b/arch/xtensa/kernel/vmlinux.lds.S
@@ -30,10 +30,6 @@ jiffies = jiffies_64 + 4;
jiffies = jiffies_64;
#endif
-#ifndef KERNELOFFSET
-#define KERNELOFFSET 0xd0003000
-#endif
-
/* Note: In the following macros, it would be nice to specify only the
vector name and section kind and construct "sym" and "section" using
CPP concatenation, but that does not work reliably. Concatenating a