Merge tag 'sh-for-4.8' of git://git.libc.org/linux-sh
Pull arch/sh updates from Rich Felker: "These changes improve device tree support (including builtin DTB), add support for the J-Core J2 processor, an open source synthesizable reimplementation of the SH-2 ISA, resolve a longstanding sigcontext ABI mismatch issue, and fix various bugs including nommu-specific issues and minor regressions introduced in 4.6. The J-Core arch support is included here but to be usable it needs drivers that are waiting on approval/inclusion from their subsystem maintainers" * tag 'sh-for-4.8' of git://git.libc.org/linux-sh: (23 commits) sh: add device tree source for J2 FPGA on Mimas v2 board sh: add defconfig for J-Core J2 sh: use common clock framework with device tree boards sh: system call wire up sh: Delete unnecessary checks before the function call "mempool_destroy" sh: do not perform IPI-based cache flush except on boards that need it sh: add SMP support for J2 sh: SMP support for SH2 entry.S sh: add working futex atomic ops on userspace addresses for smp sh: add J2 atomics using the cas.l instruction sh: add AT_HWCAP flag for J-Core cas.l instruction sh: add support for J-Core J2 processor sh: fix build regression with CONFIG_OF && !CONFIG_OF_FLATTREE sh: allow clocksource drivers to register sched_clock backends sh: make heartbeat driver explicitly non-modular sh: make board-secureedge5410 explicitly non-modular sh: make mm/asids-debugfs explicitly non-modular sh: make time.c explicitly non-modular sh: fix futex/robust_list on nommu models sh: disable aliased page logic on NOMMU models ...
This commit is contained in:
@@ -24,11 +24,13 @@ int __init clk_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#ifndef CONFIG_COMMON_CLK
|
||||
ret = arch_clk_init();
|
||||
if (unlikely(ret)) {
|
||||
pr_err("%s: CPU clock registration failed.\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sh_mv.mv_clk_init) {
|
||||
ret = sh_mv.mv_clk_init();
|
||||
@@ -39,11 +41,13 @@ int __init clk_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CONFIG_COMMON_CLK
|
||||
/* Kick the child clocks.. */
|
||||
recalculate_root_clocks();
|
||||
|
||||
/* Enable the necessary init clocks */
|
||||
clk_enable_init_clocks();
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@@ -106,7 +106,7 @@ void __attribute__ ((weak)) l2_cache_init(void)
|
||||
/*
|
||||
* Generic first-level cache init
|
||||
*/
|
||||
#ifdef CONFIG_SUPERH32
|
||||
#if defined(CONFIG_SUPERH32) && !defined(CONFIG_CPU_J2)
|
||||
static void cache_init(void)
|
||||
{
|
||||
unsigned long ccr, flags;
|
||||
@@ -323,9 +323,13 @@ asmlinkage void cpu_init(void)
|
||||
cache_init();
|
||||
|
||||
if (raw_smp_processor_id() == 0) {
|
||||
#ifdef CONFIG_MMU
|
||||
shm_align_mask = max_t(unsigned long,
|
||||
current_cpu_data.dcache.way_size - 1,
|
||||
PAGE_SIZE - 1);
|
||||
#else
|
||||
shm_align_mask = PAGE_SIZE - 1;
|
||||
#endif
|
||||
|
||||
/* Boot CPU sets the cache shape */
|
||||
detect_cache_shape();
|
||||
|
@@ -27,6 +27,7 @@ static const char *cpu_name[] = {
|
||||
[CPU_MXG] = "MX-G", [CPU_SH7723] = "SH7723",
|
||||
[CPU_SH7366] = "SH7366", [CPU_SH7724] = "SH7724",
|
||||
[CPU_SH7372] = "SH7372", [CPU_SH7734] = "SH7734",
|
||||
[CPU_J2] = "J2",
|
||||
[CPU_SH_NONE] = "Unknown"
|
||||
};
|
||||
|
||||
|
@@ -5,3 +5,7 @@
|
||||
obj-y := ex.o probe.o entry.o
|
||||
|
||||
obj-$(CONFIG_CPU_SUBTYPE_SH7619) += setup-sh7619.o clock-sh7619.o
|
||||
|
||||
# SMP setup
|
||||
smp-$(CONFIG_CPU_J2) := smp-j2.o
|
||||
obj-$(CONFIG_SMP) += $(smp-y)
|
||||
|
@@ -47,6 +47,13 @@ ENTRY(exception_handler)
|
||||
mov.l r3,@-sp
|
||||
cli
|
||||
mov.l $cpu_mode,r2
|
||||
#ifdef CONFIG_SMP
|
||||
mov.l $cpuid,r3
|
||||
mov.l @r3,r3
|
||||
mov.l @r3,r3
|
||||
shll2 r3
|
||||
add r3,r2
|
||||
#endif
|
||||
mov.l @r2,r0
|
||||
mov.l @(5*4,r15),r3 ! previous SR
|
||||
or r0,r3 ! set MD
|
||||
@@ -57,6 +64,13 @@ ENTRY(exception_handler)
|
||||
mov.l __md_bit,r0
|
||||
mov.l r0,@r2 ! enter kernel mode
|
||||
mov.l $current_thread_info,r2
|
||||
#ifdef CONFIG_SMP
|
||||
mov.l $cpuid,r0
|
||||
mov.l @r0,r0
|
||||
mov.l @r0,r0
|
||||
shll2 r0
|
||||
add r0,r2
|
||||
#endif
|
||||
mov.l @r2,r2
|
||||
mov #(THREAD_SIZE >> 8),r0
|
||||
shll8 r0
|
||||
@@ -147,6 +161,11 @@ ENTRY(exception_handler)
|
||||
mov #31,r8
|
||||
cmp/hs r8,r9
|
||||
bt trap_entry ! 64 > vec >= 31 is trap
|
||||
#ifdef CONFIG_CPU_J2
|
||||
mov #16,r8
|
||||
cmp/hs r8,r9
|
||||
bt interrupt_entry ! 31 > vec >= 16 is interrupt
|
||||
#endif
|
||||
|
||||
mov.l 4f,r8
|
||||
mov r9,r4
|
||||
@@ -260,6 +279,13 @@ restore_all:
|
||||
lds.l @r0+,macl
|
||||
mov r15,r0
|
||||
mov.l $cpu_mode,r2
|
||||
#ifdef CONFIG_SMP
|
||||
mov.l $cpuid,r3
|
||||
mov.l @r3,r3
|
||||
mov.l @r3,r3
|
||||
shll2 r3
|
||||
add r3,r2
|
||||
#endif
|
||||
mov #OFF_SR,r3
|
||||
mov.l @(r0,r3),r1
|
||||
mov.l __md_bit,r3
|
||||
@@ -276,6 +302,13 @@ restore_all:
|
||||
mov.l r1,@r2 ! set pc
|
||||
get_current_thread_info r0, r1
|
||||
mov.l $current_thread_info,r1
|
||||
#ifdef CONFIG_SMP
|
||||
mov.l $cpuid,r3
|
||||
mov.l @r3,r3
|
||||
mov.l @r3,r3
|
||||
shll2 r3
|
||||
add r3,r1
|
||||
#endif
|
||||
mov.l r0,@r1
|
||||
mov.l @r15+,r0
|
||||
mov.l @r15+,r1
|
||||
@@ -303,19 +336,41 @@ $current_thread_info:
|
||||
.long __current_thread_info
|
||||
$cpu_mode:
|
||||
.long __cpu_mode
|
||||
#ifdef CONFIG_SMP
|
||||
$cpuid:
|
||||
.long sh2_cpuid_addr
|
||||
#endif
|
||||
|
||||
! common exception handler
|
||||
#include "../../entry-common.S"
|
||||
|
||||
#ifdef CONFIG_NR_CPUS
|
||||
#define NR_CPUS CONFIG_NR_CPUS
|
||||
#else
|
||||
#define NR_CPUS 1
|
||||
#endif
|
||||
|
||||
.data
|
||||
! cpu operation mode
|
||||
! bit30 = MD (compatible SH3/4)
|
||||
__cpu_mode:
|
||||
.rept NR_CPUS
|
||||
.long 0x40000000
|
||||
.endr
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
.global sh2_cpuid_addr
|
||||
sh2_cpuid_addr:
|
||||
.long dummy_cpuid
|
||||
dummy_cpuid:
|
||||
.long 0
|
||||
#endif
|
||||
|
||||
.section .bss
|
||||
__current_thread_info:
|
||||
.rept NR_CPUS
|
||||
.long 0
|
||||
.endr
|
||||
|
||||
ENTRY(exception_handling_table)
|
||||
.space 4*32
|
||||
|
@@ -10,10 +10,27 @@
|
||||
* for more details.
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/cache.h>
|
||||
|
||||
void cpu_probe(void)
|
||||
#if defined(CONFIG_CPU_J2)
|
||||
extern u32 __iomem *j2_ccr_base;
|
||||
static int __init scan_cache(unsigned long node, const char *uname,
|
||||
int depth, void *data)
|
||||
{
|
||||
if (!of_flat_dt_is_compatible(node, "jcore,cache"))
|
||||
return 0;
|
||||
|
||||
j2_ccr_base = (u32 __iomem *)of_flat_dt_translate_address(node);
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
void __ref cpu_probe(void)
|
||||
{
|
||||
#if defined(CONFIG_CPU_SUBTYPE_SH7619)
|
||||
boot_cpu_data.type = CPU_SH7619;
|
||||
@@ -24,10 +41,30 @@ void cpu_probe(void)
|
||||
boot_cpu_data.dcache.linesz = L1_CACHE_BYTES;
|
||||
boot_cpu_data.dcache.flags = 0;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_CPU_J2)
|
||||
unsigned cpu = hard_smp_processor_id();
|
||||
if (cpu == 0) of_scan_flat_dt(scan_cache, NULL);
|
||||
if (j2_ccr_base) __raw_writel(0x80000303, j2_ccr_base + 4*cpu);
|
||||
if (cpu != 0) return;
|
||||
boot_cpu_data.type = CPU_J2;
|
||||
|
||||
/* These defaults are appropriate for the original/current
|
||||
* J2 cache. Once there is a proper framework for getting cache
|
||||
* info from device tree, we should switch to that. */
|
||||
boot_cpu_data.dcache.ways = 1;
|
||||
boot_cpu_data.dcache.sets = 256;
|
||||
boot_cpu_data.dcache.entry_shift = 5;
|
||||
boot_cpu_data.dcache.linesz = 32;
|
||||
boot_cpu_data.dcache.flags = 0;
|
||||
|
||||
boot_cpu_data.flags |= CPU_HAS_CAS_L;
|
||||
#else
|
||||
/*
|
||||
* SH-2 doesn't have separate caches
|
||||
*/
|
||||
boot_cpu_data.dcache.flags |= SH_CACHE_COMBINED;
|
||||
#endif
|
||||
boot_cpu_data.icache = boot_cpu_data.dcache;
|
||||
boot_cpu_data.family = CPU_FAMILY_SH2;
|
||||
}
|
||||
|
139
arch/sh/kernel/cpu/sh2/smp-j2.c
Normal file
139
arch/sh/kernel/cpu/sh2/smp-j2.c
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* SMP support for J2 processor
|
||||
*
|
||||
* Copyright (C) 2015-2016 Smart Energy Instruments, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/smp.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <asm/cmpxchg.h>
|
||||
|
||||
DEFINE_PER_CPU(unsigned, j2_ipi_messages);
|
||||
|
||||
extern u32 *sh2_cpuid_addr;
|
||||
static u32 *j2_ipi_trigger;
|
||||
static int j2_ipi_irq;
|
||||
|
||||
static irqreturn_t j2_ipi_interrupt_handler(int irq, void *arg)
|
||||
{
|
||||
unsigned cpu = hard_smp_processor_id();
|
||||
volatile unsigned *pmsg = &per_cpu(j2_ipi_messages, cpu);
|
||||
unsigned messages, i;
|
||||
|
||||
do messages = *pmsg;
|
||||
while (cmpxchg(pmsg, messages, 0) != messages);
|
||||
|
||||
if (!messages) return IRQ_NONE;
|
||||
|
||||
for (i=0; i<SMP_MSG_NR; i++)
|
||||
if (messages & (1U<<i))
|
||||
smp_message_recv(i);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void j2_smp_setup(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void j2_prepare_cpus(unsigned int max_cpus)
|
||||
{
|
||||
struct device_node *np;
|
||||
unsigned i, max = 1;
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "jcore,ipi-controller");
|
||||
if (!np)
|
||||
goto out;
|
||||
|
||||
j2_ipi_irq = irq_of_parse_and_map(np, 0);
|
||||
j2_ipi_trigger = of_iomap(np, 0);
|
||||
if (!j2_ipi_irq || !j2_ipi_trigger)
|
||||
goto out;
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "jcore,cpuid-mmio");
|
||||
if (!np)
|
||||
goto out;
|
||||
|
||||
sh2_cpuid_addr = of_iomap(np, 0);
|
||||
if (!sh2_cpuid_addr)
|
||||
goto out;
|
||||
|
||||
if (request_irq(j2_ipi_irq, j2_ipi_interrupt_handler, IRQF_PERCPU,
|
||||
"ipi", (void *)j2_ipi_interrupt_handler) != 0)
|
||||
goto out;
|
||||
|
||||
max = max_cpus;
|
||||
out:
|
||||
/* Disable any cpus past max_cpus, or all secondaries if we didn't
|
||||
* get the necessary resources to support SMP. */
|
||||
for (i=max; i<NR_CPUS; i++) {
|
||||
set_cpu_possible(i, false);
|
||||
set_cpu_present(i, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void j2_start_cpu(unsigned int cpu, unsigned long entry_point)
|
||||
{
|
||||
struct device_node *np;
|
||||
u32 regs[2];
|
||||
void __iomem *release, *initpc;
|
||||
|
||||
if (!cpu) return;
|
||||
|
||||
np = of_get_cpu_node(cpu, NULL);
|
||||
if (!np) return;
|
||||
|
||||
if (of_property_read_u32_array(np, "cpu-release-addr", regs, 2)) return;
|
||||
release = ioremap_nocache(regs[0], sizeof(u32));
|
||||
initpc = ioremap_nocache(regs[1], sizeof(u32));
|
||||
|
||||
__raw_writel(entry_point, initpc);
|
||||
__raw_writel(1, release);
|
||||
|
||||
iounmap(initpc);
|
||||
iounmap(release);
|
||||
|
||||
pr_info("J2 SMP: requested start of cpu %u\n", cpu);
|
||||
}
|
||||
|
||||
static unsigned int j2_smp_processor_id(void)
|
||||
{
|
||||
return __raw_readl(sh2_cpuid_addr);
|
||||
}
|
||||
|
||||
static void j2_send_ipi(unsigned int cpu, unsigned int message)
|
||||
{
|
||||
volatile unsigned *pmsg;
|
||||
unsigned old;
|
||||
unsigned long val;
|
||||
|
||||
/* There is only one IPI interrupt shared by all messages, so
|
||||
* we keep a separate interrupt flag per message type in sw. */
|
||||
pmsg = &per_cpu(j2_ipi_messages, cpu);
|
||||
do old = *pmsg;
|
||||
while (cmpxchg(pmsg, old, old|(1U<<message)) != old);
|
||||
|
||||
/* Generate the actual interrupt by writing to CCRn bit 28. */
|
||||
val = __raw_readl(j2_ipi_trigger + cpu);
|
||||
__raw_writel(val | (1U<<28), j2_ipi_trigger + cpu);
|
||||
}
|
||||
|
||||
static struct plat_smp_ops j2_smp_ops = {
|
||||
.smp_setup = j2_smp_setup,
|
||||
.prepare_cpus = j2_prepare_cpus,
|
||||
.start_cpu = j2_start_cpu,
|
||||
.smp_processor_id = j2_smp_processor_id,
|
||||
.send_ipi = j2_send_ipi,
|
||||
.cpu_die = native_cpu_die,
|
||||
.cpu_disable = native_cpu_disable,
|
||||
.play_dead = native_play_dead,
|
||||
};
|
||||
|
||||
CPU_METHOD_OF_DECLARE(j2_cpu_method, "jcore,spin-table", &j2_smp_ops);
|
@@ -1009,10 +1009,8 @@ static void __init dwarf_unwinder_cleanup(void)
|
||||
rbtree_postorder_for_each_entry_safe(cie, next_cie, &cie_root, node)
|
||||
kfree(cie);
|
||||
|
||||
if (dwarf_reg_pool)
|
||||
mempool_destroy(dwarf_reg_pool);
|
||||
if (dwarf_frame_pool)
|
||||
mempool_destroy(dwarf_frame_pool);
|
||||
mempool_destroy(dwarf_reg_pool);
|
||||
mempool_destroy(dwarf_frame_pool);
|
||||
kmem_cache_destroy(dwarf_reg_cachep);
|
||||
kmem_cache_destroy(dwarf_frame_cachep);
|
||||
}
|
||||
|
@@ -67,7 +67,7 @@ ENTRY(_stext)
|
||||
ldc r0, r6_bank
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
#ifdef CONFIG_OF_FLATTREE
|
||||
mov r4, r12 ! Store device tree blob pointer in r12
|
||||
#endif
|
||||
|
||||
@@ -318,7 +318,7 @@ ENTRY(_stext)
|
||||
10:
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
#ifdef CONFIG_OF_FLATTREE
|
||||
mov.l 8f, r0 ! Make flat device tree available early.
|
||||
jsr @r0
|
||||
mov r12, r4
|
||||
@@ -349,7 +349,7 @@ ENTRY(stack_start)
|
||||
5: .long start_kernel
|
||||
6: .long cpu_init
|
||||
7: .long init_thread_union
|
||||
#if defined(CONFIG_OF)
|
||||
#if defined(CONFIG_OF_FLATTREE)
|
||||
8: .long sh_fdt_init
|
||||
#endif
|
||||
|
||||
|
@@ -242,7 +242,7 @@ void __init __weak plat_early_device_setup(void)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
#ifdef CONFIG_OF_FLATTREE
|
||||
void __ref sh_fdt_init(phys_addr_t dt_phys)
|
||||
{
|
||||
static int done = 0;
|
||||
@@ -251,7 +251,11 @@ void __ref sh_fdt_init(phys_addr_t dt_phys)
|
||||
/* Avoid calling an __init function on secondary cpus. */
|
||||
if (done) return;
|
||||
|
||||
#ifdef CONFIG_USE_BUILTIN_DTB
|
||||
dt_virt = __dtb_start;
|
||||
#else
|
||||
dt_virt = phys_to_virt(dt_phys);
|
||||
#endif
|
||||
|
||||
if (!dt_virt || !early_init_dt_scan(dt_virt)) {
|
||||
pr_crit("Error: invalid device tree blob"
|
||||
|
@@ -386,3 +386,17 @@ ENTRY(sys_call_table)
|
||||
.long sys_process_vm_writev
|
||||
.long sys_kcmp
|
||||
.long sys_finit_module
|
||||
.long sys_sched_getattr
|
||||
.long sys_sched_setattr /* 370 */
|
||||
.long sys_renameat2
|
||||
.long sys_seccomp
|
||||
.long sys_getrandom
|
||||
.long sys_memfd_create
|
||||
.long sys_bpf /* 375 */
|
||||
.long sys_execveat
|
||||
.long sys_userfaultfd
|
||||
.long sys_membarrier
|
||||
.long sys_mlock2
|
||||
.long sys_copy_file_range /* 380 */
|
||||
.long sys_preadv2
|
||||
.long sys_pwritev2
|
||||
|
@@ -406,3 +406,17 @@ sys_call_table:
|
||||
.long sys_process_vm_writev
|
||||
.long sys_kcmp
|
||||
.long sys_finit_module
|
||||
.long sys_sched_getattr /* 380 */
|
||||
.long sys_sched_setattr
|
||||
.long sys_renameat2
|
||||
.long sys_seccomp
|
||||
.long sys_getrandom
|
||||
.long sys_memfd_create /* 385 */
|
||||
.long sys_bpf
|
||||
.long sys_execveat
|
||||
.long sys_userfaultfd
|
||||
.long sys_membarrier
|
||||
.long sys_mlock2 /* 390 */
|
||||
.long sys_copy_file_range
|
||||
.long sys_preadv2
|
||||
.long sys_pwritev2
|
||||
|
@@ -11,7 +11,6 @@
|
||||
* for more details.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/profile.h>
|
||||
#include <linux/timex.h>
|
||||
@@ -90,7 +89,7 @@ static int __init rtc_generic_init(void)
|
||||
|
||||
return PTR_ERR_OR_ZERO(pdev);
|
||||
}
|
||||
module_init(rtc_generic_init);
|
||||
device_initcall(rtc_generic_init);
|
||||
|
||||
void (*board_time_init)(void);
|
||||
|
||||
|
Reference in New Issue
Block a user