diff options
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r-- | arch/sh/kernel/cpu/clock.c | 4 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/init.c | 6 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/proc.c | 1 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh2/Makefile | 4 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh2/entry.S | 55 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh2/probe.c | 39 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh2/smp-j2.c | 139 | ||||
-rw-r--r-- | arch/sh/kernel/dma-nommu.c | 4 | ||||
-rw-r--r-- | arch/sh/kernel/dwarf.c | 6 | ||||
-rw-r--r-- | arch/sh/kernel/head_32.S | 6 | ||||
-rw-r--r-- | arch/sh/kernel/perf_event.c | 23 | ||||
-rw-r--r-- | arch/sh/kernel/setup.c | 6 | ||||
-rw-r--r-- | arch/sh/kernel/syscalls_32.S | 14 | ||||
-rw-r--r-- | arch/sh/kernel/syscalls_64.S | 14 | ||||
-rw-r--r-- | arch/sh/kernel/time.c | 36 |
15 files changed, 311 insertions, 46 deletions
diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c index 4187cf4fe..fca9b1e78 100644 --- a/arch/sh/kernel/cpu/clock.c +++ b/arch/sh/kernel/cpu/clock.c @@ -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; } diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c index 0d7360d54..c8b3be1b5 100644 --- a/arch/sh/kernel/cpu/init.c +++ b/arch/sh/kernel/cpu/init.c @@ -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(); diff --git a/arch/sh/kernel/cpu/proc.c b/arch/sh/kernel/cpu/proc.c index 9e6624c91..4df4b284f 100644 --- a/arch/sh/kernel/cpu/proc.c +++ b/arch/sh/kernel/cpu/proc.c @@ -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" }; diff --git a/arch/sh/kernel/cpu/sh2/Makefile b/arch/sh/kernel/cpu/sh2/Makefile index f0f059acf..904c4283d 100644 --- a/arch/sh/kernel/cpu/sh2/Makefile +++ b/arch/sh/kernel/cpu/sh2/Makefile @@ -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) diff --git a/arch/sh/kernel/cpu/sh2/entry.S b/arch/sh/kernel/cpu/sh2/entry.S index a1505956e..1ee0a6e77 100644 --- a/arch/sh/kernel/cpu/sh2/entry.S +++ b/arch/sh/kernel/cpu/sh2/entry.S @@ -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 diff --git a/arch/sh/kernel/cpu/sh2/probe.c b/arch/sh/kernel/cpu/sh2/probe.c index 6c687ae81..4205f6d42 100644 --- a/arch/sh/kernel/cpu/sh2/probe.c +++ b/arch/sh/kernel/cpu/sh2/probe.c @@ -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; } diff --git a/arch/sh/kernel/cpu/sh2/smp-j2.c b/arch/sh/kernel/cpu/sh2/smp-j2.c new file mode 100644 index 000000000..6ccd7e4dc --- /dev/null +++ b/arch/sh/kernel/cpu/sh2/smp-j2.c @@ -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); diff --git a/arch/sh/kernel/dma-nommu.c b/arch/sh/kernel/dma-nommu.c index 5b0bfcda6..eadb669a7 100644 --- a/arch/sh/kernel/dma-nommu.c +++ b/arch/sh/kernel/dma-nommu.c @@ -13,7 +13,7 @@ static dma_addr_t nommu_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction dir, - struct dma_attrs *attrs) + unsigned long attrs) { dma_addr_t addr = page_to_phys(page) + offset; @@ -25,7 +25,7 @@ static dma_addr_t nommu_map_page(struct device *dev, struct page *page, static int nommu_map_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir, - struct dma_attrs *attrs) + unsigned long attrs) { struct scatterlist *s; int i; diff --git a/arch/sh/kernel/dwarf.c b/arch/sh/kernel/dwarf.c index 9d209a072..e1d751ae2 100644 --- a/arch/sh/kernel/dwarf.c +++ b/arch/sh/kernel/dwarf.c @@ -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); } diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S index 974bc152c..4e352c3f7 100644 --- a/arch/sh/kernel/head_32.S +++ b/arch/sh/kernel/head_32.S @@ -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 diff --git a/arch/sh/kernel/perf_event.c b/arch/sh/kernel/perf_event.c index 4dca18347..ba3269a83 100644 --- a/arch/sh/kernel/perf_event.c +++ b/arch/sh/kernel/perf_event.c @@ -352,28 +352,12 @@ static struct pmu pmu = { .read = sh_pmu_read, }; -static void sh_pmu_setup(int cpu) +static int sh_pmu_prepare_cpu(unsigned int cpu) { struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu); memset(cpuhw, 0, sizeof(struct cpu_hw_events)); -} - -static int -sh_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu) -{ - unsigned int cpu = (long)hcpu; - - switch (action & ~CPU_TASKS_FROZEN) { - case CPU_UP_PREPARE: - sh_pmu_setup(cpu); - break; - - default: - break; - } - - return NOTIFY_OK; + return 0; } int register_sh_pmu(struct sh_pmu *_pmu) @@ -394,6 +378,7 @@ int register_sh_pmu(struct sh_pmu *_pmu) WARN_ON(_pmu->num_events > MAX_HWEVENTS); perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW); - perf_cpu_notifier(sh_pmu_notifier); + cpuhp_setup_state(CPUHP_PERF_SUPERH, "PERF_SUPERH", sh_pmu_prepare_cpu, + NULL); return 0; } diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 5d34605b5..e7b49d810 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -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" diff --git a/arch/sh/kernel/syscalls_32.S b/arch/sh/kernel/syscalls_32.S index 734234be2..254bc22ee 100644 --- a/arch/sh/kernel/syscalls_32.S +++ b/arch/sh/kernel/syscalls_32.S @@ -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 diff --git a/arch/sh/kernel/syscalls_64.S b/arch/sh/kernel/syscalls_64.S index 579fcb9a8..d6a27f7a4 100644 --- a/arch/sh/kernel/syscalls_64.S +++ b/arch/sh/kernel/syscalls_64.S @@ -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 diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c index d6d0a986c..fcd5e4197 100644 --- a/arch/sh/kernel/time.c +++ b/arch/sh/kernel/time.c @@ -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> @@ -50,27 +49,31 @@ int update_persistent_clock(struct timespec now) } #endif -unsigned int get_rtc_time(struct rtc_time *tm) +static int rtc_generic_get_time(struct device *dev, struct rtc_time *tm) { - if (rtc_sh_get_time != null_rtc_get_time) { - struct timespec tv; + struct timespec tv; - rtc_sh_get_time(&tv); - rtc_time_to_tm(tv.tv_sec, tm); - } - - return RTC_24H; + rtc_sh_get_time(&tv); + rtc_time_to_tm(tv.tv_sec, tm); + return 0; } -EXPORT_SYMBOL(get_rtc_time); -int set_rtc_time(struct rtc_time *tm) +static int rtc_generic_set_time(struct device *dev, struct rtc_time *tm) { unsigned long secs; rtc_tm_to_time(tm, &secs); - return rtc_sh_set_time(secs); + if ((rtc_sh_set_time == null_rtc_set_time) || + (rtc_sh_set_time(secs) < 0)) + return -EOPNOTSUPP; + + return 0; } -EXPORT_SYMBOL(set_rtc_time); + +static const struct rtc_class_ops rtc_generic_ops = { + .read_time = rtc_generic_get_time, + .set_time = rtc_generic_set_time, +}; static int __init rtc_generic_init(void) { @@ -79,11 +82,14 @@ static int __init rtc_generic_init(void) if (rtc_sh_get_time == null_rtc_get_time) return -ENODEV; - pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0); + pdev = platform_device_register_data(NULL, "rtc-generic", -1, + &rtc_generic_ops, + sizeof(rtc_generic_ops)); + return PTR_ERR_OR_ZERO(pdev); } -module_init(rtc_generic_init); +device_initcall(rtc_generic_init); void (*board_time_init)(void); |