diff options
Diffstat (limited to 'arch/arc')
39 files changed, 289 insertions, 736 deletions
diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index bd204bfa29ed..283099c9560a 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -8,9 +8,10 @@ config ARC def_bool y + select ARC_TIMERS + select ARCH_HAS_SG_CHAIN select ARCH_SUPPORTS_ATOMIC_RMW if ARC_HAS_LLSC select BUILDTIME_EXTABLE_SORT - select CLKSRC_OF select CLONE_BACKWARDS select COMMON_CLK select GENERIC_ATOMIC64 if !ISA_ARCV2 || !(ARC_HAS_LL64 && ARC_HAS_LLSC) @@ -28,7 +29,7 @@ config ARC select HAVE_KPROBES select HAVE_KRETPROBES select HAVE_MEMBLOCK - select HAVE_MOD_ARCH_SPECIFIC if ARC_DW2_UNWIND + select HAVE_MOD_ARCH_SPECIFIC select HAVE_OPROFILE select HAVE_PERF_EVENTS select HANDLE_DOMAIN_IRQ @@ -115,6 +116,7 @@ config ISA_ARCOMPACT config ISA_ARCV2 bool "ARC ISA v2" + select ARC_TIMERS_64BIT help ISA for the Next Generation ARC-HS cores @@ -410,16 +412,6 @@ config ARC_HAS_DIV_REM bool "Insn: div, divu, rem, remu" default y -config ARC_HAS_RTC - bool "Local 64-bit r/o cycle counter" - default n - depends on !SMP - -config ARC_HAS_GFRC - bool "SMP synchronized 64-bit cycle counter" - default y - depends on SMP - config ARC_NUMBER_OF_INTERRUPTS int "Number of interrupts" range 8 240 diff --git a/arch/arc/boot/dts/abilis_tb10x.dtsi b/arch/arc/boot/dts/abilis_tb10x.dtsi index de53f5c3251c..3121536b25a3 100644 --- a/arch/arc/boot/dts/abilis_tb10x.dtsi +++ b/arch/arc/boot/dts/abilis_tb10x.dtsi @@ -129,6 +129,7 @@ data-width = <4>; clocks = <&ahb_clk>; clock-names = "hclk"; + multi-block = <1 1 1 1 1 1>; }; i2c0: i2c@FF120000 { diff --git a/arch/arc/boot/dts/axs101.dts b/arch/arc/boot/dts/axs101.dts index d9b9b9dcfc4c..70aec7d6ca60 100644 --- a/arch/arc/boot/dts/axs101.dts +++ b/arch/arc/boot/dts/axs101.dts @@ -17,6 +17,6 @@ compatible = "snps,axs101", "snps,arc-sdp"; chosen { - bootargs = "earlycon=uart8250,mmio32,0xe0022000,115200n8 console=tty0 console=ttyS3,115200n8 consoleblank=0"; + bootargs = "earlycon=uart8250,mmio32,0xe0022000,115200n8 console=tty0 console=ttyS3,115200n8 consoleblank=0 video=1280x720@60"; }; }; diff --git a/arch/arc/boot/dts/axs103_idu.dts b/arch/arc/boot/dts/axs103_idu.dts index 070c29782216..5c843d9b4ac8 100644 --- a/arch/arc/boot/dts/axs103_idu.dts +++ b/arch/arc/boot/dts/axs103_idu.dts @@ -20,6 +20,6 @@ compatible = "snps,axs103", "snps,arc-sdp"; chosen { - bootargs = "earlycon=uart8250,mmio32,0xe0022000,115200n8 console=ttyS3,115200n8 debug print-fatal-signals=1"; + bootargs = "earlycon=uart8250,mmio32,0xe0022000,115200n8 console=tty0 console=ttyS3,115200n8 print-fatal-signals=1 consoleblank=0 video=1280x720@60"; }; }; diff --git a/arch/arc/boot/dts/zebu_hs.dts b/arch/arc/boot/dts/haps_hs.dts index 1c1324e84965..1c1324e84965 100644 --- a/arch/arc/boot/dts/zebu_hs.dts +++ b/arch/arc/boot/dts/haps_hs.dts diff --git a/arch/arc/boot/dts/zebu_hs_idu.dts b/arch/arc/boot/dts/haps_hs_idu.dts index 65204b4c0f13..65204b4c0f13 100644 --- a/arch/arc/boot/dts/zebu_hs_idu.dts +++ b/arch/arc/boot/dts/haps_hs_idu.dts diff --git a/arch/arc/configs/axs101_defconfig b/arch/arc/configs/axs101_defconfig index 0a0eaf09aac7..6980b966a364 100644 --- a/arch/arc/configs/axs101_defconfig +++ b/arch/arc/configs/axs101_defconfig @@ -75,9 +75,11 @@ CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_DESIGNWARE_PLATFORM=y # CONFIG_HWMON is not set +CONFIG_DRM=m +CONFIG_DRM_I2C_ADV7511=m +CONFIG_DRM_ARCPGU=m CONFIG_FB=y CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set diff --git a/arch/arc/configs/axs103_smp_defconfig b/arch/arc/configs/axs103_smp_defconfig index 110874705085..30a3d4cf53d2 100644 --- a/arch/arc/configs/axs103_smp_defconfig +++ b/arch/arc/configs/axs103_smp_defconfig @@ -77,9 +77,11 @@ CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_DESIGNWARE_PLATFORM=y # CONFIG_HWMON is not set +CONFIG_DRM=m +CONFIG_DRM_I2C_ADV7511=m +CONFIG_DRM_ARCPGU=m CONFIG_FB=y CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set diff --git a/arch/arc/configs/zebu_hs_defconfig b/arch/arc/configs/haps_hs_defconfig index 9f6166be7145..57b3e599322f 100644 --- a/arch/arc/configs/zebu_hs_defconfig +++ b/arch/arc/configs/haps_hs_defconfig @@ -23,7 +23,7 @@ CONFIG_MODULES=y # CONFIG_IOSCHED_CFQ is not set CONFIG_ARC_PLAT_SIM=y CONFIG_ISA_ARCV2=y -CONFIG_ARC_BUILTIN_DTB_NAME="zebu_hs" +CONFIG_ARC_BUILTIN_DTB_NAME="haps_hs" CONFIG_PREEMPT=y # CONFIG_COMPACTION is not set CONFIG_NET=y diff --git a/arch/arc/configs/zebu_hs_smp_defconfig b/arch/arc/configs/haps_hs_smp_defconfig index 44e9693f4257..f85985adebb2 100644 --- a/arch/arc/configs/zebu_hs_smp_defconfig +++ b/arch/arc/configs/haps_hs_smp_defconfig @@ -26,7 +26,7 @@ CONFIG_MODULES=y CONFIG_ARC_PLAT_SIM=y CONFIG_ISA_ARCV2=y CONFIG_SMP=y -CONFIG_ARC_BUILTIN_DTB_NAME="zebu_hs_idu" +CONFIG_ARC_BUILTIN_DTB_NAME="haps_hs_idu" CONFIG_PREEMPT=y # CONFIG_COMPACTION is not set CONFIG_NET=y diff --git a/arch/arc/configs/nsimosci_hs_smp_defconfig b/arch/arc/configs/nsimosci_hs_smp_defconfig index 6da71ba253a9..155add7761ed 100644 --- a/arch/arc/configs/nsimosci_hs_smp_defconfig +++ b/arch/arc/configs/nsimosci_hs_smp_defconfig @@ -21,7 +21,7 @@ CONFIG_MODULES=y CONFIG_ARC_PLAT_SIM=y CONFIG_ISA_ARCV2=y CONFIG_SMP=y -# CONFIG_ARC_HAS_GFRC is not set +# CONFIG_ARC_TIMERS_64BIT is not set CONFIG_ARC_BUILTIN_DTB_NAME="nsimosci_hs_idu" CONFIG_PREEMPT=y # CONFIG_COMPACTION is not set diff --git a/arch/arc/configs/vdk_hs38_smp_defconfig b/arch/arc/configs/vdk_hs38_smp_defconfig index 969b206d6c67..573028f19de7 100644 --- a/arch/arc/configs/vdk_hs38_smp_defconfig +++ b/arch/arc/configs/vdk_hs38_smp_defconfig @@ -15,7 +15,7 @@ CONFIG_ARC_PLAT_AXS10X=y CONFIG_AXS103=y CONFIG_ISA_ARCV2=y CONFIG_SMP=y -# CONFIG_ARC_HAS_GFRC is not set +# CONFIG_ARC_TIMERS_64BIT is not set CONFIG_ARC_UBOOT_SUPPORT=y CONFIG_ARC_BUILTIN_DTB_NAME="vdk_hs38_smp" CONFIG_PREEMPT=y diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h index 1bd24ec3e350..f659942744de 100644 --- a/arch/arc/include/asm/arcregs.h +++ b/arch/arc/include/asm/arcregs.h @@ -20,7 +20,6 @@ #define ARC_REG_FP_V2_BCR 0xc8 /* ARCv2 FPU */ #define ARC_REG_SLC_BCR 0xce #define ARC_REG_DCCM_BUILD 0x74 /* DCCM size (common) */ -#define ARC_REG_TIMERS_BCR 0x75 #define ARC_REG_AP_BCR 0x76 #define ARC_REG_ICCM_BUILD 0x78 /* ICCM size (common) */ #define ARC_REG_XY_MEM_BCR 0x79 @@ -112,90 +111,7 @@ #ifndef __ASSEMBLY__ -/* - ****************************************************************** - * Inline ASM macros to read/write AUX Regs - * Essentially invocation of lr/sr insns from "C" - */ - -#if 1 - -#define read_aux_reg(reg) __builtin_arc_lr(reg) - -/* gcc builtin sr needs reg param to be long immediate */ -#define write_aux_reg(reg_immed, val) \ - __builtin_arc_sr((unsigned int)(val), reg_immed) - -#else - -#define read_aux_reg(reg) \ -({ \ - unsigned int __ret; \ - __asm__ __volatile__( \ - " lr %0, [%1]" \ - : "=r"(__ret) \ - : "i"(reg)); \ - __ret; \ -}) - -/* - * Aux Reg address is specified as long immediate by caller - * e.g. - * write_aux_reg(0x69, some_val); - * This generates tightest code. - */ -#define write_aux_reg(reg_imm, val) \ -({ \ - __asm__ __volatile__( \ - " sr %0, [%1] \n" \ - : \ - : "ir"(val), "i"(reg_imm)); \ -}) - -/* - * Aux Reg address is specified in a variable - * * e.g. - * reg_num = 0x69 - * write_aux_reg2(reg_num, some_val); - * This has to generate glue code to load the reg num from - * memory to a reg hence not recommended. - */ -#define write_aux_reg2(reg_in_var, val) \ -({ \ - unsigned int tmp; \ - \ - __asm__ __volatile__( \ - " ld %0, [%2] \n\t" \ - " sr %1, [%0] \n\t" \ - : "=&r"(tmp) \ - : "r"(val), "memory"(®_in_var)); \ -}) - -#endif - -#define READ_BCR(reg, into) \ -{ \ - unsigned int tmp; \ - tmp = read_aux_reg(reg); \ - if (sizeof(tmp) == sizeof(into)) { \ - into = *((typeof(into) *)&tmp); \ - } else { \ - extern void bogus_undefined(void); \ - bogus_undefined(); \ - } \ -} - -#define WRITE_AUX(reg, into) \ -{ \ - unsigned int tmp; \ - if (sizeof(tmp) == sizeof(into)) { \ - tmp = (*(unsigned int *)&(into)); \ - write_aux_reg(reg, tmp); \ - } else { \ - extern void bogus_undefined(void); \ - bogus_undefined(); \ - } \ -} +#include <soc/arc/aux.h> /* Helpers */ #define TO_KB(bytes) ((bytes) >> 10) @@ -291,13 +207,7 @@ struct bcr_fp_arcv2 { #endif }; -struct bcr_timer { -#ifdef CONFIG_CPU_BIG_ENDIAN - unsigned int pad2:15, rtsc:1, pad1:5, rtc:1, t1:1, t0:1, ver:8; -#else - unsigned int ver:8, t0:1, t1:1, rtc:1, pad1:5, rtsc:1, pad2:15; -#endif -}; +#include <soc/arc/timers.h> struct bcr_bpu_arcompact { #ifdef CONFIG_CPU_BIG_ENDIAN @@ -334,7 +244,7 @@ struct cpuinfo_arc_mmu { }; struct cpuinfo_arc_cache { - unsigned int sz_k:14, line_len:8, assoc:4, ver:4, alias:1, vipt:1; + unsigned int sz_k:14, line_len:8, assoc:4, alias:1, vipt:1, pad:4; }; struct cpuinfo_arc_bpu { diff --git a/arch/arc/include/asm/cache.h b/arch/arc/include/asm/cache.h index b3410ff6a62d..5008021fba98 100644 --- a/arch/arc/include/asm/cache.h +++ b/arch/arc/include/asm/cache.h @@ -67,7 +67,7 @@ extern unsigned long perip_base, perip_end; #define ARC_REG_IC_PTAG_HI 0x1F /* Bit val in IC_CTRL */ -#define IC_CTRL_CACHE_DISABLE 0x1 +#define IC_CTRL_DIS 0x1 /* Data cache related Auxiliary registers */ #define ARC_REG_DC_BCR 0x72 /* Build Config reg */ @@ -80,8 +80,9 @@ extern unsigned long perip_base, perip_end; #define ARC_REG_DC_PTAG_HI 0x5F /* Bit val in DC_CTRL */ -#define DC_CTRL_INV_MODE_FLUSH 0x40 -#define DC_CTRL_FLUSH_STATUS 0x100 +#define DC_CTRL_DIS 0x001 +#define DC_CTRL_INV_MODE_FLUSH 0x040 +#define DC_CTRL_FLUSH_STATUS 0x100 /*System-level cache (L2 cache) related Auxiliary registers */ #define ARC_REG_SLC_CFG 0x901 @@ -92,8 +93,8 @@ extern unsigned long perip_base, perip_end; #define ARC_REG_SLC_RGN_END 0x916 /* Bit val in SLC_CONTROL */ +#define SLC_CTRL_DIS 0x001 #define SLC_CTRL_IM 0x040 -#define SLC_CTRL_DISABLE 0x001 #define SLC_CTRL_BUSY 0x100 #define SLC_CTRL_RGN_OP_INV 0x200 diff --git a/arch/arc/include/asm/cacheflush.h b/arch/arc/include/asm/cacheflush.h index a093adbdb017..fc662f49c55a 100644 --- a/arch/arc/include/asm/cacheflush.h +++ b/arch/arc/include/asm/cacheflush.h @@ -85,6 +85,10 @@ void flush_anon_page(struct vm_area_struct *vma, */ #define PG_dc_clean PG_arch_1 +#define CACHE_COLORS_NUM 4 +#define CACHE_COLORS_MSK (CACHE_COLORS_NUM - 1) +#define CACHE_COLOR(addr) (((unsigned long)(addr) >> (PAGE_SHIFT)) & CACHE_COLORS_MSK) + /* * Simple wrapper over config option * Bootup code ensures that hardware matches kernel configuration @@ -94,8 +98,6 @@ static inline int cache_is_vipt_aliasing(void) return IS_ENABLED(CONFIG_ARC_CACHE_VIPT_ALIASING); } -#define CACHE_COLOR(addr) (((unsigned long)(addr) >> (PAGE_SHIFT)) & 1) - /* * checks if two addresses (after page aligning) index into same cache set */ diff --git a/arch/arc/include/asm/delay.h b/arch/arc/include/asm/delay.h index a36e8601114d..d5da2115d78a 100644 --- a/arch/arc/include/asm/delay.h +++ b/arch/arc/include/asm/delay.h @@ -26,7 +26,9 @@ static inline void __delay(unsigned long loops) " lp 1f \n" " nop \n" "1: \n" - : : "r"(loops)); + : + : "r"(loops) + : "lp_count"); } extern void __bad_udelay(void); diff --git a/arch/arc/include/asm/entry-arcv2.h b/arch/arc/include/asm/entry-arcv2.h index b5ff87e6f4b7..aee1a77934cf 100644 --- a/arch/arc/include/asm/entry-arcv2.h +++ b/arch/arc/include/asm/entry-arcv2.h @@ -16,6 +16,7 @@ ; ; Now manually save: r12, sp, fp, gp, r25 + PUSH r30 PUSH r12 ; Saving pt_regs->sp correctly requires some extra work due to the way @@ -72,6 +73,7 @@ POPAX AUX_USER_SP 1: POP r12 + POP r30 .endm diff --git a/arch/arc/include/asm/irqflags-arcv2.h b/arch/arc/include/asm/irqflags-arcv2.h index e880dfa3fcd3..a64c447b0337 100644 --- a/arch/arc/include/asm/irqflags-arcv2.h +++ b/arch/arc/include/asm/irqflags-arcv2.h @@ -38,10 +38,10 @@ #define AUX_IRQ_ACT_BIT_U 31 /* - * User space should be interruptable even by lowest prio interrupt - * Safe even if actual interrupt priorities is fewer or even one + * Hardware supports 16 priorities (0 highest, 15 lowest) + * Linux by default runs at 1, priority 0 reserved for NMI style interrupts */ -#define ARCV2_IRQ_DEF_PRIO 15 +#define ARCV2_IRQ_DEF_PRIO 1 /* seed value for status register */ #define ISA_INIT_STATUS_BITS (STATUS_IE_MASK | STATUS_AD_MASK | \ diff --git a/arch/arc/include/asm/mcip.h b/arch/arc/include/asm/mcip.h deleted file mode 100644 index c8fbe4114bad..000000000000 --- a/arch/arc/include/asm/mcip.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * ARConnect IP Support (Multi core enabler: Cross core IPI, RTC ...) - * - * Copyright (C) 2014-15 Synopsys, Inc. (www.synopsys.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __ASM_MCIP_H -#define __ASM_MCIP_H - -#ifdef CONFIG_ISA_ARCV2 - -#include <asm/arcregs.h> - -#define ARC_REG_MCIP_BCR 0x0d0 -#define ARC_REG_MCIP_CMD 0x600 -#define ARC_REG_MCIP_WDATA 0x601 -#define ARC_REG_MCIP_READBACK 0x602 - -struct mcip_cmd { -#ifdef CONFIG_CPU_BIG_ENDIAN - unsigned int pad:8, param:16, cmd:8; -#else - unsigned int cmd:8, param:16, pad:8; -#endif - -#define CMD_INTRPT_GENERATE_IRQ 0x01 -#define CMD_INTRPT_GENERATE_ACK 0x02 -#define CMD_INTRPT_READ_STATUS 0x03 -#define CMD_INTRPT_CHECK_SOURCE 0x04 - -/* Semaphore Commands */ -#define CMD_SEMA_CLAIM_AND_READ 0x11 -#define CMD_SEMA_RELEASE 0x12 - -#define CMD_DEBUG_SET_MASK 0x34 -#define CMD_DEBUG_SET_SELECT 0x36 - -#define CMD_GFRC_READ_LO 0x42 -#define CMD_GFRC_READ_HI 0x43 - -#define CMD_IDU_ENABLE 0x71 -#define CMD_IDU_DISABLE 0x72 -#define CMD_IDU_SET_MODE 0x74 -#define CMD_IDU_SET_DEST 0x76 -#define CMD_IDU_SET_MASK 0x7C - -#define IDU_M_TRIG_LEVEL 0x0 -#define IDU_M_TRIG_EDGE 0x1 - -#define IDU_M_DISTRI_RR 0x0 -#define IDU_M_DISTRI_DEST 0x2 -}; - -struct mcip_bcr { -#ifdef CONFIG_CPU_BIG_ENDIAN - unsigned int pad3:8, - idu:1, llm:1, num_cores:6, - iocoh:1, gfrc:1, dbg:1, pad2:1, - msg:1, sem:1, ipi:1, pad:1, - ver:8; -#else - unsigned int ver:8, - pad:1, ipi:1, sem:1, msg:1, - pad2:1, dbg:1, gfrc:1, iocoh:1, - num_cores:6, llm:1, idu:1, - pad3:8; -#endif -}; - -/* - * MCIP programming model - * - * - Simple commands write {cmd:8,param:16} to MCIP_CMD aux reg - * (param could be irq, common_irq, core_id ...) - * - More involved commands setup MCIP_WDATA with cmd specific data - * before invoking the simple command - */ -static inline void __mcip_cmd(unsigned int cmd, unsigned int param) -{ - struct mcip_cmd buf; - - buf.pad = 0; - buf.cmd = cmd; - buf.param = param; - - WRITE_AUX(ARC_REG_MCIP_CMD, buf); -} - -/* - * Setup additional data for a cmd - * Callers need to lock to ensure atomicity - */ -static inline void __mcip_cmd_data(unsigned int cmd, unsigned int param, - unsigned int data) -{ - write_aux_reg(ARC_REG_MCIP_WDATA, data); - - __mcip_cmd(cmd, param); -} - -#endif - -#endif diff --git a/arch/arc/include/asm/module.h b/arch/arc/include/asm/module.h index 6e91d8b339c3..567590ea8f6c 100644 --- a/arch/arc/include/asm/module.h +++ b/arch/arc/include/asm/module.h @@ -14,13 +14,13 @@ #include <asm-generic/module.h> -#ifdef CONFIG_ARC_DW2_UNWIND struct mod_arch_specific { +#ifdef CONFIG_ARC_DW2_UNWIND void *unw_info; int unw_sec_idx; +#endif const char *secstr; }; -#endif #define MODULE_PROC_FAMILY "ARC700" diff --git a/arch/arc/include/asm/ptrace.h b/arch/arc/include/asm/ptrace.h index 69095da1fcfd..47111d565a95 100644 --- a/arch/arc/include/asm/ptrace.h +++ b/arch/arc/include/asm/ptrace.h @@ -84,7 +84,7 @@ struct pt_regs { unsigned long fp; unsigned long sp; /* user/kernel sp depending on where we came from */ - unsigned long r12; + unsigned long r12, r30; /*------- Below list auto saved by h/w -----------*/ unsigned long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11; diff --git a/arch/arc/include/asm/setup.h b/arch/arc/include/asm/setup.h index cb954cdab070..c568a9df82b1 100644 --- a/arch/arc/include/asm/setup.h +++ b/arch/arc/include/asm/setup.h @@ -31,6 +31,7 @@ extern int root_mountflags, end_mem; void setup_processor(void); void __init setup_arch_memory(void); +long __init arc_get_mem_sz(void); /* Helpers used in arc_*_mumbojumbo routines */ #define IS_AVAIL1(v, s) ((v) ? s : "") diff --git a/arch/arc/kernel/Makefile b/arch/arc/kernel/Makefile index cfcdedf52ff8..8942c5c3b4c5 100644 --- a/arch/arc/kernel/Makefile +++ b/arch/arc/kernel/Makefile @@ -8,7 +8,7 @@ # Pass UTS_MACHINE for user_regset definition CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' -obj-y := arcksyms.o setup.o irq.o time.o reset.o ptrace.o process.o devtree.o +obj-y := arcksyms.o setup.o irq.o reset.o ptrace.o process.o devtree.o obj-y += signal.o traps.o sys.o troubleshoot.o stacktrace.o disasm.o obj-$(CONFIG_ISA_ARCOMPACT) += entry-compact.o intc-compact.o obj-$(CONFIG_ISA_ARCV2) += entry-arcv2.o intc-arcv2.o diff --git a/arch/arc/kernel/entry-arcv2.S b/arch/arc/kernel/entry-arcv2.S index 7a1c124ff021..0b6388a5f0b8 100644 --- a/arch/arc/kernel/entry-arcv2.S +++ b/arch/arc/kernel/entry-arcv2.S @@ -67,12 +67,23 @@ ENTRY(handle_interrupt) INTERRUPT_PROLOGUE irq - clri ; To make status32.IE agree with CPU internal state - -#ifdef CONFIG_TRACE_IRQFLAGS - TRACE_ASM_IRQ_DISABLE -#endif - + # irq control APIs local_irq_save/restore/disable/enable fiddle with + # global interrupt enable bits in STATUS32 (.IE for 1 prio, .E[] for 2 prio) + # However a taken interrupt doesn't clear these bits. Thus irqs_disabled() + # query in hard ISR path would return false (since .IE is set) which would + # trips genirq interrupt handling asserts. + # + # So do a "soft" disable of interrutps here. + # + # Note this disable is only for consistent book-keeping as further interrupts + # will be disabled anyways even w/o this. Hardware tracks active interrupts + # seperately in AUX_IRQ_ACTIVE.active and will not take new interrupts + # unless this one returns (or higher prio becomes pending in 2-prio scheme) + + IRQ_DISABLE + + ; icause is banked: one per priority level + ; so a higher prio interrupt taken here won't clobber prev prio icause lr r0, [ICAUSE] mov blink, ret_from_exception @@ -171,6 +182,7 @@ END(EV_TLBProtV) ; All 2 entry points to here already disable interrupts .Lrestore_regs: +restore_regs: # Interrpts are actually disabled from this point on, but will get # reenabled after we return from interrupt/exception. diff --git a/arch/arc/kernel/entry-compact.S b/arch/arc/kernel/entry-compact.S index 98812c1248df..9211707634dc 100644 --- a/arch/arc/kernel/entry-compact.S +++ b/arch/arc/kernel/entry-compact.S @@ -259,7 +259,7 @@ ENTRY(EV_TLBProtV) EXCEPTION_PROLOGUE - lr r2, [ecr] + mov r2, r9 ; ECR set into r9 already lr r0, [efa] ; Faulting Data address (not part of pt_regs saved above) ; Exception auto-disables further Intr/exceptions. diff --git a/arch/arc/kernel/head.S b/arch/arc/kernel/head.S index 689dd867fdff..8b90d25a15cc 100644 --- a/arch/arc/kernel/head.S +++ b/arch/arc/kernel/head.S @@ -71,14 +71,14 @@ ENTRY(stext) GET_CPU_ID r5 cmp r5, 0 mov.nz r0, r5 -#ifdef CONFIG_ARC_SMP_HALT_ON_RESET - ; Non-Master can proceed as system would be booted sufficiently - jnz first_lines_of_secondary -#else + bz .Lmaster_proceed + ; Non-Masters wait for Master to boot enough and bring them up - jnz arc_platform_smp_wait_to_boot -#endif - ; Master falls thru + ; when they resume, tail-call to entry point + mov blink, @first_lines_of_secondary + j arc_platform_smp_wait_to_boot + +.Lmaster_proceed: #endif ; Clear BSS before updating any globals diff --git a/arch/arc/kernel/intc-arcv2.c b/arch/arc/kernel/intc-arcv2.c index 62b59409a5d9..ecef0fb0b66c 100644 --- a/arch/arc/kernel/intc-arcv2.c +++ b/arch/arc/kernel/intc-arcv2.c @@ -14,8 +14,6 @@ #include <linux/irqchip.h> #include <asm/irq.h> -static int irq_prio; - /* * Early Hardware specific Interrupt setup * -Called very early (start_kernel -> setup_arch -> setup_processor) @@ -24,7 +22,7 @@ static int irq_prio; */ void arc_init_IRQ(void) { - unsigned int tmp; + unsigned int tmp, irq_prio; struct irq_build { #ifdef CONFIG_CPU_BIG_ENDIAN @@ -67,33 +65,33 @@ void arc_init_IRQ(void) irq_prio = irq_bcr.prio; /* Encoded as N-1 for N levels */ pr_info("archs-intc\t: %d priority levels (default %d)%s\n", - irq_prio + 1, irq_prio, + irq_prio + 1, ARCV2_IRQ_DEF_PRIO, irq_bcr.firq ? " FIRQ (not used)":""); /* setup status32, don't enable intr yet as kernel doesn't want */ tmp = read_aux_reg(0xa); - tmp |= STATUS_AD_MASK | (irq_prio << 1); + tmp |= STATUS_AD_MASK | (ARCV2_IRQ_DEF_PRIO << 1); tmp &= ~STATUS_IE_MASK; asm volatile("kflag %0 \n"::"r"(tmp)); } static void arcv2_irq_mask(struct irq_data *data) { - write_aux_reg(AUX_IRQ_SELECT, data->irq); + write_aux_reg(AUX_IRQ_SELECT, data->hwirq); write_aux_reg(AUX_IRQ_ENABLE, 0); } static void arcv2_irq_unmask(struct irq_data *data) { - write_aux_reg(AUX_IRQ_SELECT, data->irq); + write_aux_reg(AUX_IRQ_SELECT, data->hwirq); write_aux_reg(AUX_IRQ_ENABLE, 1); } void arcv2_irq_enable(struct irq_data *data) { /* set default priority */ - write_aux_reg(AUX_IRQ_SELECT, data->irq); - write_aux_reg(AUX_IRQ_PRIORITY, irq_prio); + write_aux_reg(AUX_IRQ_SELECT, data->hwirq); + write_aux_reg(AUX_IRQ_PRIORITY, ARCV2_IRQ_DEF_PRIO); /* * hw auto enables (linux unmask) all by default diff --git a/arch/arc/kernel/intc-compact.c b/arch/arc/kernel/intc-compact.c index ce9deb953ca9..8c1fd5c00782 100644 --- a/arch/arc/kernel/intc-compact.c +++ b/arch/arc/kernel/intc-compact.c @@ -57,7 +57,7 @@ static void arc_irq_mask(struct irq_data *data) unsigned int ienb; ienb = read_aux_reg(AUX_IENABLE); - ienb &= ~(1 << data->irq); + ienb &= ~(1 << data->hwirq); write_aux_reg(AUX_IENABLE, ienb); } @@ -66,7 +66,7 @@ static void arc_irq_unmask(struct irq_data *data) unsigned int ienb; ienb = read_aux_reg(AUX_IENABLE); - ienb |= (1 << data->irq); + ienb |= (1 << data->hwirq); write_aux_reg(AUX_IENABLE, ienb); } diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index f39142acc89e..9f6b68fd4f3b 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -10,9 +10,10 @@ #include <linux/smp.h> #include <linux/irq.h> +#include <linux/irqchip/chained_irq.h> #include <linux/spinlock.h> +#include <soc/arc/mcip.h> #include <asm/irqflags-arcv2.h> -#include <asm/mcip.h> #include <asm/setup.h> static DEFINE_RAW_SPINLOCK(mcip_lock); @@ -92,11 +93,10 @@ static void mcip_probe_n_setup(void) READ_BCR(ARC_REG_MCIP_BCR, mp); sprintf(smp_cpuinfo_buf, - "Extn [SMP]\t: ARConnect (v%d): %d cores with %s%s%s%s%s\n", + "Extn [SMP]\t: ARConnect (v%d): %d cores with %s%s%s%s\n", mp.ver, mp.num_cores, IS_AVAIL1(mp.ipi, "IPI "), IS_AVAIL1(mp.idu, "IDU "), - IS_AVAIL1(mp.llm, "LLM "), IS_AVAIL1(mp.dbg, "DEBUG "), IS_AVAIL1(mp.gfrc, "GFRC")); @@ -174,7 +174,6 @@ static void idu_irq_unmask(struct irq_data *data) raw_spin_unlock_irqrestore(&mcip_lock, flags); } -#ifdef CONFIG_SMP static int idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask, bool force) @@ -204,12 +203,27 @@ idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask, return IRQ_SET_MASK_OK; } -#endif + +static void idu_irq_enable(struct irq_data *data) +{ + /* + * By default send all common interrupts to all available online CPUs. + * The affinity of common interrupts in IDU must be set manually since + * in some cases the kernel will not call irq_set_affinity() by itself: + * 1. When the kernel is not configured with support of SMP. + * 2. When the kernel is configured with support of SMP but upper + * interrupt controllers does not support setting of the affinity + * and cannot propagate it to IDU. + */ + idu_irq_set_affinity(data, cpu_online_mask, false); + idu_irq_unmask(data); +} static struct irq_chip idu_irq_chip = { .name = "MCIP IDU Intc", .irq_mask = idu_irq_mask, .irq_unmask = idu_irq_unmask, + .irq_enable = idu_irq_enable, #ifdef CONFIG_SMP .irq_set_affinity = idu_irq_set_affinity, #endif @@ -221,10 +235,13 @@ static irq_hw_number_t idu_first_hwirq; static void idu_cascade_isr(struct irq_desc *desc) { struct irq_domain *idu_domain = irq_desc_get_handler_data(desc); + struct irq_chip *core_chip = irq_desc_get_chip(desc); irq_hw_number_t core_hwirq = irqd_to_hwirq(irq_desc_get_irq_data(desc)); irq_hw_number_t idu_hwirq = core_hwirq - idu_first_hwirq; + chained_irq_enter(core_chip, desc); generic_handle_irq(irq_find_mapping(idu_domain, idu_hwirq)); + chained_irq_exit(core_chip, desc); } static int idu_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq) @@ -239,36 +256,14 @@ static int idu_irq_xlate(struct irq_domain *d, struct device_node *n, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_type) { - irq_hw_number_t hwirq = *out_hwirq = intspec[0]; - int distri = intspec[1]; - unsigned long flags; - + /* + * Ignore value of interrupt distribution mode for common interrupts in + * IDU which resides in intspec[1] since setting an affinity using value + * from Device Tree is deprecated in ARC. + */ + *out_hwirq = intspec[0]; *out_type = IRQ_TYPE_NONE; - /* XXX: validate distribution scheme again online cpu mask */ - if (distri == 0) { - /* 0 - Round Robin to all cpus, otherwise 1 bit per core */ - raw_spin_lock_irqsave(&mcip_lock, flags); - idu_set_dest(hwirq, BIT(num_online_cpus()) - 1); - idu_set_mode(hwirq, IDU_M_TRIG_LEVEL, IDU_M_DISTRI_RR); - raw_spin_unlock_irqrestore(&mcip_lock, flags); - } else { - /* - * DEST based distribution for Level Triggered intr can only - * have 1 CPU, so generalize it to always contain 1 cpu - */ - int cpu = ffs(distri); - - if (cpu != fls(distri)) - pr_warn("IDU irq %lx distri mode set to cpu %x\n", - hwirq, cpu); - - raw_spin_lock_irqsave(&mcip_lock, flags); - idu_set_dest(hwirq, cpu); - idu_set_mode(hwirq, IDU_M_TRIG_LEVEL, IDU_M_DISTRI_DEST); - raw_spin_unlock_irqrestore(&mcip_lock, flags); - } - return 0; } diff --git a/arch/arc/kernel/module.c b/arch/arc/kernel/module.c index 42e964db2967..3d99a6091332 100644 --- a/arch/arc/kernel/module.c +++ b/arch/arc/kernel/module.c @@ -32,8 +32,8 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, #ifdef CONFIG_ARC_DW2_UNWIND mod->arch.unw_sec_idx = 0; mod->arch.unw_info = NULL; - mod->arch.secstr = secstr; #endif + mod->arch.secstr = secstr; return 0; } @@ -113,8 +113,10 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, } +#ifdef CONFIG_ARC_DW2_UNWIND if (strcmp(module->arch.secstr+sechdrs[tgtsec].sh_name, ".eh_frame") == 0) module->arch.unw_sec_idx = tgtsec; +#endif return 0; diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c index 0385df77a697..3093fa898a23 100644 --- a/arch/arc/kernel/setup.c +++ b/arch/arc/kernel/setup.c @@ -10,6 +10,8 @@ #include <linux/fs.h> #include <linux/delay.h> #include <linux/root_dev.h> +#include <linux/clk-provider.h> +#include <linux/clocksource.h> #include <linux/console.h> #include <linux/module.h> #include <linux/cpu.h> @@ -234,11 +236,11 @@ static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len) is_isa_arcompact() ? "ARCompact" : "ARCv2", IS_AVAIL1(cpu->isa.be, "[Big-Endian]")); - n += scnprintf(buf + n, len - n, "Timers\t\t: %s%s%s%s\nISA Extn\t: ", + n += scnprintf(buf + n, len - n, "Timers\t\t: %s%s%s%s%s%s\nISA Extn\t: ", IS_AVAIL1(cpu->extn.timer0, "Timer0 "), IS_AVAIL1(cpu->extn.timer1, "Timer1 "), - IS_AVAIL2(cpu->extn.rtc, "Local-64-bit-Ctr ", - CONFIG_ARC_HAS_RTC)); + IS_AVAIL2(cpu->extn.rtc, "RTC [UP 64-bit] ", CONFIG_ARC_TIMERS_64BIT), + IS_AVAIL2(cpu->extn.gfrc, "GFRC [SMP 64-bit] ", CONFIG_ARC_TIMERS_64BIT)); n += i = scnprintf(buf + n, len - n, "%s%s%s%s%s", IS_AVAIL2(cpu->isa.atomic, "atomic ", CONFIG_ARC_HAS_LLSC), @@ -449,6 +451,15 @@ void __init setup_arch(char **cmdline_p) arc_unwind_init(); } +/* + * Called from start_kernel() - boot CPU only + */ +void __init time_init(void) +{ + of_clk_init(NULL); + clocksource_probe(); +} + static int __init customize_machine(void) { if (machine_desc->init_machine) diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c index 88674d972c9d..2afbafadb6ab 100644 --- a/arch/arc/kernel/smp.c +++ b/arch/arc/kernel/smp.c @@ -90,22 +90,37 @@ void __init smp_cpus_done(unsigned int max_cpus) */ static volatile int wake_flag; +#ifdef CONFIG_ISA_ARCOMPACT + +#define __boot_read(f) f +#define __boot_write(f, v) f = v + +#else + +#define __boot_read(f) arc_read_uncached_32(&f) +#define __boot_write(f, v) arc_write_uncached_32(&f, v) + +#endif + static void arc_default_smp_cpu_kick(int cpu, unsigned long pc) { BUG_ON(cpu == 0); - wake_flag = cpu; + + __boot_write(wake_flag, cpu); } void arc_platform_smp_wait_to_boot(int cpu) { - while (wake_flag != cpu) + /* for halt-on-reset, we've waited already */ + if (IS_ENABLED(CONFIG_ARC_SMP_HALT_ON_RESET)) + return; + + while (__boot_read(wake_flag) != cpu) ; - wake_flag = 0; - __asm__ __volatile__("j @first_lines_of_secondary \n"); + __boot_write(wake_flag, 0); } - const char *arc_platform_smp_cpuinfo(void) { return plat_smp_ops.info ? : ""; diff --git a/arch/arc/kernel/time.c b/arch/arc/kernel/time.c deleted file mode 100644 index c10390d1ddb6..000000000000 --- a/arch/arc/kernel/time.c +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * vineetg: Jan 1011 - * -sched_clock( ) no longer jiffies based. Uses the same clocksource - * as gtod - * - * Rajeshwarr/Vineetg: Mar 2008 - * -Implemented CONFIG_GENERIC_TIME (rather deleted arch specific code) - * for arch independent gettimeofday() - * -Implemented CONFIG_GENERIC_CLOCKEVENTS as base for hrtimers - * - * Vineetg: Mar 2008: Forked off from time.c which now is time-jiff.c - */ - -/* ARC700 has two 32bit independent prog Timers: TIMER0 and TIMER1 - * Each can programmed to go from @count to @limit and optionally - * interrupt when that happens. - * A write to Control Register clears the Interrupt - * - * We've designated TIMER0 for events (clockevents) - * while TIMER1 for free running (clocksource) - * - * Newer ARC700 cores have 64bit clk fetching RTSC insn, preferred over TIMER1 - * which however is currently broken - */ - -#include <linux/interrupt.h> -#include <linux/clk.h> -#include <linux/clk-provider.h> -#include <linux/clocksource.h> -#include <linux/clockchips.h> -#include <linux/cpu.h> -#include <linux/of.h> -#include <linux/of_irq.h> -#include <asm/irq.h> -#include <asm/arcregs.h> - -#include <asm/mcip.h> - -/* Timer related Aux registers */ -#define ARC_REG_TIMER0_LIMIT 0x23 /* timer 0 limit */ -#define ARC_REG_TIMER0_CTRL 0x22 /* timer 0 control */ -#define ARC_REG_TIMER0_CNT 0x21 /* timer 0 count */ -#define ARC_REG_TIMER1_LIMIT 0x102 /* timer 1 limit */ -#define ARC_REG_TIMER1_CTRL 0x101 /* timer 1 control */ -#define ARC_REG_TIMER1_CNT 0x100 /* timer 1 count */ - -#define TIMER_CTRL_IE (1 << 0) /* Interrupt when Count reaches limit */ -#define TIMER_CTRL_NH (1 << 1) /* Count only when CPU NOT halted */ - -#define ARC_TIMER_MAX 0xFFFFFFFF - -static unsigned long arc_timer_freq; - -static int noinline arc_get_timer_clk(struct device_node *node) -{ - struct clk *clk; - int ret; - - clk = of_clk_get(node, 0); - if (IS_ERR(clk)) { - pr_err("timer missing clk"); - return PTR_ERR(clk); - } - - ret = clk_prepare_enable(clk); - if (ret) { - pr_err("Couldn't enable parent clk\n"); - return ret; - } - - arc_timer_freq = clk_get_rate(clk); - - return 0; -} - -/********** Clock Source Device *********/ - -#ifdef CONFIG_ARC_HAS_GFRC - -static cycle_t arc_read_gfrc(struct clocksource *cs) -{ - unsigned long flags; - union { -#ifdef CONFIG_CPU_BIG_ENDIAN - struct { u32 h, l; }; -#else - struct { u32 l, h; }; -#endif - cycle_t full; - } stamp; - - local_irq_save(flags); - - __mcip_cmd(CMD_GFRC_READ_LO, 0); - stamp.l = read_aux_reg(ARC_REG_MCIP_READBACK); - - __mcip_cmd(CMD_GFRC_READ_HI, 0); - stamp.h = read_aux_reg(ARC_REG_MCIP_READBACK); - - local_irq_restore(flags); - - return stamp.full; -} - -static struct clocksource arc_counter_gfrc = { - .name = "ARConnect GFRC", - .rating = 400, - .read = arc_read_gfrc, - .mask = CLOCKSOURCE_MASK(64), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -static int __init arc_cs_setup_gfrc(struct device_node *node) -{ - int exists = cpuinfo_arc700[0].extn.gfrc; - int ret; - - if (WARN(!exists, "Global-64-bit-Ctr clocksource not detected")) - return -ENXIO; - - ret = arc_get_timer_clk(node); - if (ret) - return ret; - - return clocksource_register_hz(&arc_counter_gfrc, arc_timer_freq); -} -CLOCKSOURCE_OF_DECLARE(arc_gfrc, "snps,archs-timer-gfrc", arc_cs_setup_gfrc); - -#endif - -#ifdef CONFIG_ARC_HAS_RTC - -#define AUX_RTC_CTRL 0x103 -#define AUX_RTC_LOW 0x104 -#define AUX_RTC_HIGH 0x105 - -static cycle_t arc_read_rtc(struct clocksource *cs) -{ - unsigned long status; - union { -#ifdef CONFIG_CPU_BIG_ENDIAN - struct { u32 high, low; }; -#else - struct { u32 low, high; }; -#endif - cycle_t full; - } stamp; - - /* - * hardware has an internal state machine which tracks readout of - * low/high and updates the CTRL.status if - * - interrupt/exception taken between the two reads - * - high increments after low has been read - */ - do { - stamp.low = read_aux_reg(AUX_RTC_LOW); - stamp.high = read_aux_reg(AUX_RTC_HIGH); - status = read_aux_reg(AUX_RTC_CTRL); - } while (!(status & _BITUL(31))); - - return stamp.full; -} - -static struct clocksource arc_counter_rtc = { - .name = "ARCv2 RTC", - .rating = 350, - .read = arc_read_rtc, - .mask = CLOCKSOURCE_MASK(64), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -static int __init arc_cs_setup_rtc(struct device_node *node) -{ - int exists = cpuinfo_arc700[smp_processor_id()].extn.rtc; - int ret; - - if (WARN(!exists, "Local-64-bit-Ctr clocksource not detected")) - return -ENXIO; - - /* Local to CPU hence not usable in SMP */ - if (WARN(IS_ENABLED(CONFIG_SMP), "Local-64-bit-Ctr not usable in SMP")) - return -EINVAL; - - ret = arc_get_timer_clk(node); - if (ret) - return ret; - - write_aux_reg(AUX_RTC_CTRL, 1); - - return clocksource_register_hz(&arc_counter_rtc, arc_timer_freq); -} -CLOCKSOURCE_OF_DECLARE(arc_rtc, "snps,archs-timer-rtc", arc_cs_setup_rtc); - -#endif - -/* - * 32bit TIMER1 to keep counting monotonically and wraparound - */ - -static cycle_t arc_read_timer1(struct clocksource *cs) -{ - return (cycle_t) read_aux_reg(ARC_REG_TIMER1_CNT); -} - -static struct clocksource arc_counter_timer1 = { - .name = "ARC Timer1", - .rating = 300, - .read = arc_read_timer1, - .mask = CLOCKSOURCE_MASK(32), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -static int __init arc_cs_setup_timer1(struct device_node *node) -{ - int ret; - - /* Local to CPU hence not usable in SMP */ - if (IS_ENABLED(CONFIG_SMP)) - return -EINVAL; - - ret = arc_get_timer_clk(node); - if (ret) - return ret; - - write_aux_reg(ARC_REG_TIMER1_LIMIT, ARC_TIMER_MAX); - write_aux_reg(ARC_REG_TIMER1_CNT, 0); - write_aux_reg(ARC_REG_TIMER1_CTRL, TIMER_CTRL_NH); - - return clocksource_register_hz(&arc_counter_timer1, arc_timer_freq); -} - -/********** Clock Event Device *********/ - -static int arc_timer_irq; - -/* - * Arm the timer to interrupt after @cycles - * The distinction for oneshot/periodic is done in arc_event_timer_ack() below - */ -static void arc_timer_event_setup(unsigned int cycles) -{ - write_aux_reg(ARC_REG_TIMER0_LIMIT, cycles); - write_aux_reg(ARC_REG_TIMER0_CNT, 0); /* start from 0 */ - - write_aux_reg(ARC_REG_TIMER0_CTRL, TIMER_CTRL_IE | TIMER_CTRL_NH); -} - - -static int arc_clkevent_set_next_event(unsigned long delta, - struct clock_event_device *dev) -{ - arc_timer_event_setup(delta); - return 0; -} - -static int arc_clkevent_set_periodic(struct clock_event_device *dev) -{ - /* - * At X Hz, 1 sec = 1000ms -> X cycles; - * 10ms -> X / 100 cycles - */ - arc_timer_event_setup(arc_timer_freq / HZ); - return 0; -} - -static DEFINE_PER_CPU(struct clock_event_device, arc_clockevent_device) = { - .name = "ARC Timer0", - .features = CLOCK_EVT_FEAT_ONESHOT | - CLOCK_EVT_FEAT_PERIODIC, - .rating = 300, - .set_next_event = arc_clkevent_set_next_event, - .set_state_periodic = arc_clkevent_set_periodic, -}; - -static irqreturn_t timer_irq_handler(int irq, void *dev_id) -{ - /* - * Note that generic IRQ core could have passed @evt for @dev_id if - * irq_set_chip_and_handler() asked for handle_percpu_devid_irq() - */ - struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device); - int irq_reenable = clockevent_state_periodic(evt); - - /* - * Any write to CTRL reg ACks the interrupt, we rewrite the - * Count when [N]ot [H]alted bit. - * And re-arm it if perioid by [I]nterrupt [E]nable bit - */ - write_aux_reg(ARC_REG_TIMER0_CTRL, irq_reenable | TIMER_CTRL_NH); - - evt->event_handler(evt); - - return IRQ_HANDLED; -} - - -static int arc_timer_starting_cpu(unsigned int cpu) -{ - struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device); - - evt->cpumask = cpumask_of(smp_processor_id()); - - clockevents_config_and_register(evt, arc_timer_freq, 0, ARC_TIMER_MAX); - enable_percpu_irq(arc_timer_irq, 0); - return 0; -} - -static int arc_timer_dying_cpu(unsigned int cpu) -{ - disable_percpu_irq(arc_timer_irq); - return 0; -} - -/* - * clockevent setup for boot CPU - */ -static int __init arc_clockevent_setup(struct device_node *node) -{ - struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device); - int ret; - - arc_timer_irq = irq_of_parse_and_map(node, 0); - if (arc_timer_irq <= 0) { - pr_err("clockevent: missing irq"); - return -EINVAL; - } - - ret = arc_get_timer_clk(node); - if (ret) { - pr_err("clockevent: missing clk"); - return ret; - } - - /* Needs apriori irq_set_percpu_devid() done in intc map function */ - ret = request_percpu_irq(arc_timer_irq, timer_irq_handler, - "Timer0 (per-cpu-tick)", evt); - if (ret) { - pr_err("clockevent: unable to request irq\n"); - return ret; - } - - ret = cpuhp_setup_state(CPUHP_AP_ARC_TIMER_STARTING, - "AP_ARC_TIMER_STARTING", - arc_timer_starting_cpu, - arc_timer_dying_cpu); - if (ret) { - pr_err("Failed to setup hotplug state"); - return ret; - } - return 0; -} - -static int __init arc_of_timer_init(struct device_node *np) -{ - static int init_count = 0; - int ret; - - if (!init_count) { - init_count = 1; - ret = arc_clockevent_setup(np); - } else { - ret = arc_cs_setup_timer1(np); - } - - return ret; -} -CLOCKSOURCE_OF_DECLARE(arc_clkevt, "snps,arc-timer", arc_of_timer_init); - -/* - * Called from start_kernel() - boot CPU only - */ -void __init time_init(void) -{ - of_clk_init(NULL); - clocksource_probe(); -} diff --git a/arch/arc/kernel/unaligned.c b/arch/arc/kernel/unaligned.c index abd961f3e763..5f69c3bd59bb 100644 --- a/arch/arc/kernel/unaligned.c +++ b/arch/arc/kernel/unaligned.c @@ -241,8 +241,9 @@ int misaligned_fixup(unsigned long address, struct pt_regs *regs, if (state.fault) goto fault; + /* clear any remanants of delay slot */ if (delay_mode(regs)) { - regs->ret = regs->bta; + regs->ret = regs->bta & ~1U; regs->status32 &= ~STATUS_DE_MASK; } else { regs->ret += state.instr_len; diff --git a/arch/arc/mm/cache.c b/arch/arc/mm/cache.c index 50d71695cd4e..d408fa21a07c 100644 --- a/arch/arc/mm/cache.c +++ b/arch/arc/mm/cache.c @@ -23,7 +23,7 @@ static int l2_line_sz; static int ioc_exists; -int slc_enable = 1, ioc_enable = 0; +int slc_enable = 1, ioc_enable = 1; unsigned long perip_base = ARC_UNCACHED_ADDR_SPACE; /* legacy value for boot */ unsigned long perip_end = 0xFFFFFFFF; /* legacy value */ @@ -40,7 +40,7 @@ char *arc_cache_mumbojumbo(int c, char *buf, int len) struct cpuinfo_arc_cache *p; #define PR_CACHE(p, cfg, str) \ - if (!(p)->ver) \ + if (!(p)->line_len) \ n += scnprintf(buf + n, len - n, str"\t\t: N/A\n"); \ else \ n += scnprintf(buf + n, len - n, \ @@ -54,7 +54,7 @@ char *arc_cache_mumbojumbo(int c, char *buf, int len) PR_CACHE(&cpuinfo_arc700[c].dcache, CONFIG_ARC_HAS_DCACHE, "D-Cache"); p = &cpuinfo_arc700[c].slc; - if (p->ver) + if (p->line_len) n += scnprintf(buf + n, len - n, "SLC\t\t: %uK, %uB Line%s\n", p->sz_k, p->line_len, IS_USED_RUN(slc_enable)); @@ -104,7 +104,6 @@ static void read_decode_cache_bcr_arcv2(int cpu) READ_BCR(ARC_REG_SLC_BCR, sbcr); if (sbcr.ver) { READ_BCR(ARC_REG_SLC_CFG, slc_cfg); - p_slc->ver = sbcr.ver; p_slc->sz_k = 128 << slc_cfg.sz; l2_line_sz = p_slc->line_len = (slc_cfg.lsz == 0) ? 128 : 64; } @@ -152,7 +151,6 @@ void read_decode_cache_bcr(void) p_ic->line_len = 8 << ibcr.line_len; p_ic->sz_k = 1 << (ibcr.sz - 1); - p_ic->ver = ibcr.ver; p_ic->vipt = 1; p_ic->alias = p_ic->sz_k/p_ic->assoc/TO_KB(PAGE_SIZE) > 1; @@ -176,7 +174,6 @@ dc_chk: p_dc->line_len = 16 << dbcr.line_len; p_dc->sz_k = 1 << (dbcr.sz - 1); - p_dc->ver = dbcr.ver; slc_chk: if (is_isa_arcv2()) @@ -274,7 +271,11 @@ void __cache_line_loop_v2(phys_addr_t paddr, unsigned long vaddr, /* * For ARC700 MMUv3 I-cache and D-cache flushes - * Also reused for HS38 aliasing I-cache configuration + * - ARC700 programming model requires paddr and vaddr be passed in seperate + * AUX registers (*_IV*L and *_PTAG respectively) irrespective of whether the + * caches actually alias or not. + * - For HS38, only the aliasing I-cache configuration uses the PTAG reg + * (non aliasing I-cache version doesn't; while D-cache can't possibly alias) */ static inline void __cache_line_loop_v3(phys_addr_t paddr, unsigned long vaddr, @@ -461,6 +462,21 @@ static inline void __dc_entire_op(const int op) __after_dc_op(op); } +static inline void __dc_disable(void) +{ + const int r = ARC_REG_DC_CTRL; + + __dc_entire_op(OP_FLUSH_N_INV); + write_aux_reg(r, read_aux_reg(r) | DC_CTRL_DIS); +} + +static void __dc_enable(void) +{ + const int r = ARC_REG_DC_CTRL; + + write_aux_reg(r, read_aux_reg(r) & ~DC_CTRL_DIS); +} + /* For kernel mappings cache operation: index is same as paddr */ #define __dc_line_op_k(p, sz, op) __dc_line_op(p, p, sz, op) @@ -486,6 +502,8 @@ static inline void __dc_line_op(phys_addr_t paddr, unsigned long vaddr, #else #define __dc_entire_op(op) +#define __dc_disable() +#define __dc_enable() #define __dc_line_op(paddr, vaddr, sz, op) #define __dc_line_op_k(paddr, sz, op) @@ -600,6 +618,40 @@ noinline void slc_op(phys_addr_t paddr, unsigned long sz, const int op) #endif } +noinline static void slc_entire_op(const int op) +{ + unsigned int ctrl, r = ARC_REG_SLC_CTRL; + + ctrl = read_aux_reg(r); + + if (!(op & OP_FLUSH)) /* i.e. OP_INV */ + ctrl &= ~SLC_CTRL_IM; /* clear IM: Disable flush before Inv */ + else + ctrl |= SLC_CTRL_IM; + + write_aux_reg(r, ctrl); + + write_aux_reg(ARC_REG_SLC_INVALIDATE, 1); + + /* Important to wait for flush to complete */ + while (read_aux_reg(r) & SLC_CTRL_BUSY); +} + +static inline void arc_slc_disable(void) +{ + const int r = ARC_REG_SLC_CTRL; + + slc_entire_op(OP_FLUSH_N_INV); + write_aux_reg(r, read_aux_reg(r) | SLC_CTRL_DIS); +} + +static inline void arc_slc_enable(void) +{ + const int r = ARC_REG_SLC_CTRL; + + write_aux_reg(r, read_aux_reg(r) & ~SLC_CTRL_DIS); +} + /*********************************************************** * Exported APIs */ @@ -926,36 +978,65 @@ SYSCALL_DEFINE3(cacheflush, uint32_t, start, uint32_t, sz, uint32_t, flags) return 0; } -void arc_cache_init(void) +/* + * IO-Coherency (IOC) setup rules: + * + * 1. Needs to be at system level, so only once by Master core + * Non-Masters need not be accessing caches at that time + * - They are either HALT_ON_RESET and kick started much later or + * - if run on reset, need to ensure that arc_platform_smp_wait_to_boot() + * doesn't perturb caches or coherency unit + * + * 2. caches (L1 and SLC) need to be purged (flush+inv) before setting up IOC, + * otherwise any straggler data might behave strangely post IOC enabling + * + * 3. All Caches need to be disabled when setting up IOC to elide any in-flight + * Coherency transactions + */ +noinline void __init arc_ioc_setup(void) { - unsigned int __maybe_unused cpu = smp_processor_id(); - char str[256]; + unsigned int ap_sz; - printk(arc_cache_mumbojumbo(0, str, sizeof(str))); + /* Flush + invalidate + disable L1 dcache */ + __dc_disable(); + + /* Flush + invalidate SLC */ + if (read_aux_reg(ARC_REG_SLC_BCR)) + slc_entire_op(OP_FLUSH_N_INV); + + /* IOC Aperture start: TDB: handle non default CONFIG_LINUX_LINK_BASE */ + write_aux_reg(ARC_REG_IO_COH_AP0_BASE, 0x80000); /* - * Only master CPU needs to execute rest of function: - * - Assume SMP so all cores will have same cache config so - * any geomtry checks will be same for all - * - IOC setup / dma callbacks only need to be setup once + * IOC Aperture size: + * decoded as 2 ^ (SIZE + 2) KB: so setting 0x11 implies 512M + * TBD: fix for PGU + 1GB of low mem + * TBD: fix for PAE */ - if (cpu) - return; + ap_sz = order_base_2(arc_get_mem_sz()/1024) - 2; + write_aux_reg(ARC_REG_IO_COH_AP0_SIZE, ap_sz); + + write_aux_reg(ARC_REG_IO_COH_PARTIAL, 1); + write_aux_reg(ARC_REG_IO_COH_ENABLE, 1); + + /* Re-enable L1 dcache */ + __dc_enable(); +} + +void __init arc_cache_init_master(void) +{ + unsigned int __maybe_unused cpu = smp_processor_id(); if (IS_ENABLED(CONFIG_ARC_HAS_ICACHE)) { struct cpuinfo_arc_cache *ic = &cpuinfo_arc700[cpu].icache; - if (!ic->ver) + if (!ic->line_len) panic("cache support enabled but non-existent cache\n"); if (ic->line_len != L1_CACHE_BYTES) panic("ICache line [%d] != kernel Config [%d]", ic->line_len, L1_CACHE_BYTES); - if (ic->ver != CONFIG_ARC_MMU_VER) - panic("Cache ver [%d] doesn't match MMU ver [%d]\n", - ic->ver, CONFIG_ARC_MMU_VER); - /* * In MMU v4 (HS38x) the aliasing icache config uses IVIL/PTAG * pair to provide vaddr/paddr respectively, just as in MMU v3 @@ -969,7 +1050,7 @@ void arc_cache_init(void) if (IS_ENABLED(CONFIG_ARC_HAS_DCACHE)) { struct cpuinfo_arc_cache *dc = &cpuinfo_arc700[cpu].dcache; - if (!dc->ver) + if (!dc->line_len) panic("cache support enabled but non-existent cache\n"); if (dc->line_len != L1_CACHE_BYTES) @@ -979,38 +1060,27 @@ void arc_cache_init(void) /* check for D-Cache aliasing on ARCompact: ARCv2 has PIPT */ if (is_isa_arcompact()) { int handled = IS_ENABLED(CONFIG_ARC_CACHE_VIPT_ALIASING); - - if (dc->alias && !handled) - panic("Enable CONFIG_ARC_CACHE_VIPT_ALIASING\n"); - else if (!dc->alias && handled) + int num_colors = dc->sz_k/dc->assoc/TO_KB(PAGE_SIZE); + + if (dc->alias) { + if (!handled) + panic("Enable CONFIG_ARC_CACHE_VIPT_ALIASING\n"); + if (CACHE_COLORS_NUM != num_colors) + panic("CACHE_COLORS_NUM not optimized for config\n"); + } else if (!dc->alias && handled) { panic("Disable CONFIG_ARC_CACHE_VIPT_ALIASING\n"); + } } } - if (is_isa_arcv2() && l2_line_sz && !slc_enable) { - - /* IM set : flush before invalidate */ - write_aux_reg(ARC_REG_SLC_CTRL, - read_aux_reg(ARC_REG_SLC_CTRL) | SLC_CTRL_IM); + /* Note that SLC disable not formally supported till HS 3.0 */ + if (is_isa_arcv2() && l2_line_sz && !slc_enable) + arc_slc_disable(); - write_aux_reg(ARC_REG_SLC_INVALIDATE, 1); - - /* Important to wait for flush to complete */ - while (read_aux_reg(ARC_REG_SLC_CTRL) & SLC_CTRL_BUSY); - write_aux_reg(ARC_REG_SLC_CTRL, - read_aux_reg(ARC_REG_SLC_CTRL) | SLC_CTRL_DISABLE); - } + if (is_isa_arcv2() && ioc_enable) + arc_ioc_setup(); if (is_isa_arcv2() && ioc_enable) { - /* IO coherency base - 0x8z */ - write_aux_reg(ARC_REG_IO_COH_AP0_BASE, 0x80000); - /* IO coherency aperture size - 512Mb: 0x8z-0xAz */ - write_aux_reg(ARC_REG_IO_COH_AP0_SIZE, 0x11); - /* Enable partial writes */ - write_aux_reg(ARC_REG_IO_COH_PARTIAL, 1); - /* Enable IO coherency */ - write_aux_reg(ARC_REG_IO_COH_ENABLE, 1); - __dma_cache_wback_inv = __dma_cache_wback_inv_ioc; __dma_cache_inv = __dma_cache_inv_ioc; __dma_cache_wback = __dma_cache_wback_ioc; @@ -1024,3 +1094,20 @@ void arc_cache_init(void) __dma_cache_wback = __dma_cache_wback_l1; } } + +void __ref arc_cache_init(void) +{ + unsigned int __maybe_unused cpu = smp_processor_id(); + char str[256]; + + printk(arc_cache_mumbojumbo(0, str, sizeof(str))); + + /* + * Only master CPU needs to execute rest of function: + * - Assume SMP so all cores will have same cache config so + * any geomtry checks will be same for all + * - IOC setup / dma callbacks only need to be setup once + */ + if (!cpu) + arc_cache_init_master(); +} diff --git a/arch/arc/mm/dma.c b/arch/arc/mm/dma.c index cd8aad8226dd..08450a1a5b5f 100644 --- a/arch/arc/mm/dma.c +++ b/arch/arc/mm/dma.c @@ -158,7 +158,10 @@ static dma_addr_t arc_dma_map_page(struct device *dev, struct page *page, unsigned long attrs) { phys_addr_t paddr = page_to_phys(page) + offset; - _dma_cache_sync(paddr, size, dir); + + if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC)) + _dma_cache_sync(paddr, size, dir); + return plat_phys_to_dma(dev, paddr); } diff --git a/arch/arc/mm/init.c b/arch/arc/mm/init.c index 399e2f223d25..8c9415ed6280 100644 --- a/arch/arc/mm/init.c +++ b/arch/arc/mm/init.c @@ -40,6 +40,11 @@ struct pglist_data node_data[MAX_NUMNODES] __read_mostly; EXPORT_SYMBOL(node_data); #endif +long __init arc_get_mem_sz(void) +{ + return low_mem_sz; +} + /* User can over-ride above with "mem=nnn[KkMm]" in cmdline */ static int __init setup_mem_sz(char *str) { diff --git a/arch/arc/plat-axs10x/axs10x.c b/arch/arc/plat-axs10x/axs10x.c index 86548701023c..38ff349d7f2a 100644 --- a/arch/arc/plat-axs10x/axs10x.c +++ b/arch/arc/plat-axs10x/axs10x.c @@ -21,7 +21,7 @@ #include <asm/asm-offsets.h> #include <asm/io.h> #include <asm/mach_desc.h> -#include <asm/mcip.h> +#include <soc/arc/mcip.h> #define AXS_MB_CGU 0xE0010000 #define AXS_MB_CREG 0xE0011000 diff --git a/arch/arc/plat-eznps/include/plat/ctop.h b/arch/arc/plat-eznps/include/plat/ctop.h index 9d6718c1a199..ee2e32df5e90 100644 --- a/arch/arc/plat-eznps/include/plat/ctop.h +++ b/arch/arc/plat-eznps/include/plat/ctop.h @@ -46,9 +46,7 @@ #define CTOP_AUX_UDMC (CTOP_AUX_BASE + 0x300) /* EZchip core instructions */ -#define CTOP_INST_HWSCHD_OFF_R3 0x3B6F00BF #define CTOP_INST_HWSCHD_OFF_R4 0x3C6F00BF -#define CTOP_INST_HWSCHD_RESTORE_R3 0x3E6F70C3 #define CTOP_INST_HWSCHD_RESTORE_R4 0x3E6F7103 #define CTOP_INST_SCHD_RW 0x3E6F7004 #define CTOP_INST_SCHD_RD 0x3E6F7084 |