diff options
36 files changed, 635 insertions, 321 deletions
diff --git a/Documentation/devicetree/bindings/riscv/sifive-l2-cache.txt b/Documentation/devicetree/bindings/riscv/sifive-l2-cache.txt new file mode 100644 index 000000000000..73d8f19c3bd9 --- /dev/null +++ b/Documentation/devicetree/bindings/riscv/sifive-l2-cache.txt | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | SiFive L2 Cache Controller | ||
| 2 | -------------------------- | ||
| 3 | The SiFive Level 2 Cache Controller is used to provide access to fast copies | ||
| 4 | of memory for masters in a Core Complex. The Level 2 Cache Controller also | ||
| 5 | acts as directory-based coherency manager. | ||
| 6 | All the properties in ePAPR/DeviceTree specification applies for this platform | ||
| 7 | |||
| 8 | Required Properties: | ||
| 9 | -------------------- | ||
| 10 | - compatible: Should be "sifive,fu540-c000-ccache" and "cache" | ||
| 11 | |||
| 12 | - cache-block-size: Specifies the block size in bytes of the cache. | ||
| 13 | Should be 64 | ||
| 14 | |||
| 15 | - cache-level: Should be set to 2 for a level 2 cache | ||
| 16 | |||
| 17 | - cache-sets: Specifies the number of associativity sets of the cache. | ||
| 18 | Should be 1024 | ||
| 19 | |||
| 20 | - cache-size: Specifies the size in bytes of the cache. Should be 2097152 | ||
| 21 | |||
| 22 | - cache-unified: Specifies the cache is a unified cache | ||
| 23 | |||
| 24 | - interrupts: Must contain 3 entries (DirError, DataError and DataFail signals) | ||
| 25 | |||
| 26 | - reg: Physical base address and size of L2 cache controller registers map | ||
| 27 | |||
| 28 | Optional Properties: | ||
| 29 | -------------------- | ||
| 30 | - next-level-cache: phandle to the next level cache if present. | ||
| 31 | |||
| 32 | - memory-region: reference to the reserved-memory for the L2 Loosely Integrated | ||
| 33 | Memory region. The reserved memory node should be defined as per the bindings | ||
| 34 | in reserved-memory.txt | ||
| 35 | |||
| 36 | |||
| 37 | Example: | ||
| 38 | |||
| 39 | cache-controller@2010000 { | ||
| 40 | compatible = "sifive,fu540-c000-ccache", "cache"; | ||
| 41 | cache-block-size = <64>; | ||
| 42 | cache-level = <2>; | ||
| 43 | cache-sets = <1024>; | ||
| 44 | cache-size = <2097152>; | ||
| 45 | cache-unified; | ||
| 46 | interrupt-parent = <&plic0>; | ||
| 47 | interrupts = <1 2 3>; | ||
| 48 | reg = <0x0 0x2010000 0x0 0x1000>; | ||
| 49 | next-level-cache = <&L25 &L40 &L36>; | ||
| 50 | memory-region = <&l2_lim>; | ||
| 51 | }; | ||
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index e66745decea1..ee32c66e1af3 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig | |||
| @@ -27,7 +27,7 @@ config RISCV | |||
| 27 | select GENERIC_STRNCPY_FROM_USER | 27 | select GENERIC_STRNCPY_FROM_USER |
| 28 | select GENERIC_STRNLEN_USER | 28 | select GENERIC_STRNLEN_USER |
| 29 | select GENERIC_SMP_IDLE_THREAD | 29 | select GENERIC_SMP_IDLE_THREAD |
| 30 | select GENERIC_ATOMIC64 if !64BIT || !RISCV_ISA_A | 30 | select GENERIC_ATOMIC64 if !64BIT |
| 31 | select HAVE_ARCH_AUDITSYSCALL | 31 | select HAVE_ARCH_AUDITSYSCALL |
| 32 | select HAVE_MEMBLOCK_NODE_MAP | 32 | select HAVE_MEMBLOCK_NODE_MAP |
| 33 | select HAVE_DMA_CONTIGUOUS | 33 | select HAVE_DMA_CONTIGUOUS |
| @@ -35,7 +35,6 @@ config RISCV | |||
| 35 | select HAVE_PERF_EVENTS | 35 | select HAVE_PERF_EVENTS |
| 36 | select HAVE_SYSCALL_TRACEPOINTS | 36 | select HAVE_SYSCALL_TRACEPOINTS |
| 37 | select IRQ_DOMAIN | 37 | select IRQ_DOMAIN |
| 38 | select RISCV_ISA_A if SMP | ||
| 39 | select SPARSE_IRQ | 38 | select SPARSE_IRQ |
| 40 | select SYSCTL_EXCEPTION_TRACE | 39 | select SYSCTL_EXCEPTION_TRACE |
| 41 | select HAVE_ARCH_TRACEHOOK | 40 | select HAVE_ARCH_TRACEHOOK |
| @@ -195,9 +194,6 @@ config RISCV_ISA_C | |||
| 195 | 194 | ||
| 196 | If you don't know what to do here, say Y. | 195 | If you don't know what to do here, say Y. |
| 197 | 196 | ||
| 198 | config RISCV_ISA_A | ||
| 199 | def_bool y | ||
| 200 | |||
| 201 | menu "supported PMU type" | 197 | menu "supported PMU type" |
| 202 | depends on PERF_EVENTS | 198 | depends on PERF_EVENTS |
| 203 | 199 | ||
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index c6342e638ef7..6b0741c9f348 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile | |||
| @@ -39,9 +39,8 @@ endif | |||
| 39 | KBUILD_CFLAGS += -Wall | 39 | KBUILD_CFLAGS += -Wall |
| 40 | 40 | ||
| 41 | # ISA string setting | 41 | # ISA string setting |
| 42 | riscv-march-$(CONFIG_ARCH_RV32I) := rv32im | 42 | riscv-march-$(CONFIG_ARCH_RV32I) := rv32ima |
| 43 | riscv-march-$(CONFIG_ARCH_RV64I) := rv64im | 43 | riscv-march-$(CONFIG_ARCH_RV64I) := rv64ima |
| 44 | riscv-march-$(CONFIG_RISCV_ISA_A) := $(riscv-march-y)a | ||
| 45 | riscv-march-$(CONFIG_FPU) := $(riscv-march-y)fd | 44 | riscv-march-$(CONFIG_FPU) := $(riscv-march-y)fd |
| 46 | riscv-march-$(CONFIG_RISCV_ISA_C) := $(riscv-march-y)c | 45 | riscv-march-$(CONFIG_RISCV_ISA_C) := $(riscv-march-y)c |
| 47 | KBUILD_CFLAGS += -march=$(subst fd,,$(riscv-march-y)) | 46 | KBUILD_CFLAGS += -march=$(subst fd,,$(riscv-march-y)) |
diff --git a/arch/riscv/include/asm/Kbuild b/arch/riscv/include/asm/Kbuild index cccd12cf27d4..5a7a19d9aa7f 100644 --- a/arch/riscv/include/asm/Kbuild +++ b/arch/riscv/include/asm/Kbuild | |||
| @@ -4,6 +4,7 @@ generic-y += compat.h | |||
| 4 | generic-y += cputime.h | 4 | generic-y += cputime.h |
| 5 | generic-y += device.h | 5 | generic-y += device.h |
| 6 | generic-y += div64.h | 6 | generic-y += div64.h |
| 7 | generic-y += extable.h | ||
| 7 | generic-y += dma.h | 8 | generic-y += dma.h |
| 8 | generic-y += dma-contiguous.h | 9 | generic-y += dma-contiguous.h |
| 9 | generic-y += dma-mapping.h | 10 | generic-y += dma-mapping.h |
diff --git a/arch/riscv/include/asm/bug.h b/arch/riscv/include/asm/bug.h index bfc7f099ab1f..52a1fbdeab3b 100644 --- a/arch/riscv/include/asm/bug.h +++ b/arch/riscv/include/asm/bug.h | |||
| @@ -21,7 +21,12 @@ | |||
| 21 | #include <asm/asm.h> | 21 | #include <asm/asm.h> |
| 22 | 22 | ||
| 23 | #ifdef CONFIG_GENERIC_BUG | 23 | #ifdef CONFIG_GENERIC_BUG |
| 24 | #define __BUG_INSN _AC(0x00100073, UL) /* ebreak */ | 24 | #define __INSN_LENGTH_MASK _UL(0x3) |
| 25 | #define __INSN_LENGTH_32 _UL(0x3) | ||
| 26 | #define __COMPRESSED_INSN_MASK _UL(0xffff) | ||
| 27 | |||
| 28 | #define __BUG_INSN_32 _UL(0x00100073) /* ebreak */ | ||
| 29 | #define __BUG_INSN_16 _UL(0x9002) /* c.ebreak */ | ||
| 25 | 30 | ||
| 26 | #ifndef __ASSEMBLY__ | 31 | #ifndef __ASSEMBLY__ |
| 27 | typedef u32 bug_insn_t; | 32 | typedef u32 bug_insn_t; |
| @@ -38,38 +43,46 @@ typedef u32 bug_insn_t; | |||
| 38 | #define __BUG_ENTRY \ | 43 | #define __BUG_ENTRY \ |
| 39 | __BUG_ENTRY_ADDR "\n\t" \ | 44 | __BUG_ENTRY_ADDR "\n\t" \ |
| 40 | __BUG_ENTRY_FILE "\n\t" \ | 45 | __BUG_ENTRY_FILE "\n\t" \ |
| 41 | RISCV_SHORT " %1" | 46 | RISCV_SHORT " %1\n\t" \ |
| 47 | RISCV_SHORT " %2" | ||
| 42 | #else | 48 | #else |
| 43 | #define __BUG_ENTRY \ | 49 | #define __BUG_ENTRY \ |
| 44 | __BUG_ENTRY_ADDR | 50 | __BUG_ENTRY_ADDR "\n\t" \ |
| 51 | RISCV_SHORT " %2" | ||
| 45 | #endif | 52 | #endif |
| 46 | 53 | ||
| 47 | #define BUG() \ | 54 | #define __BUG_FLAGS(flags) \ |
| 48 | do { \ | 55 | do { \ |
| 49 | __asm__ __volatile__ ( \ | 56 | __asm__ __volatile__ ( \ |
| 50 | "1:\n\t" \ | 57 | "1:\n\t" \ |
| 51 | "ebreak\n" \ | 58 | "ebreak\n" \ |
| 52 | ".pushsection __bug_table,\"a\"\n\t" \ | 59 | ".pushsection __bug_table,\"aw\"\n\t" \ |
| 53 | "2:\n\t" \ | 60 | "2:\n\t" \ |
| 54 | __BUG_ENTRY "\n\t" \ | 61 | __BUG_ENTRY "\n\t" \ |
| 55 | ".org 2b + %2\n\t" \ | 62 | ".org 2b + %3\n\t" \ |
| 56 | ".popsection" \ | 63 | ".popsection" \ |
| 57 | : \ | 64 | : \ |
| 58 | : "i" (__FILE__), "i" (__LINE__), \ | 65 | : "i" (__FILE__), "i" (__LINE__), \ |
| 59 | "i" (sizeof(struct bug_entry))); \ | 66 | "i" (flags), \ |
| 60 | unreachable(); \ | 67 | "i" (sizeof(struct bug_entry))); \ |
| 61 | } while (0) | 68 | } while (0) |
| 69 | |||
| 62 | #endif /* !__ASSEMBLY__ */ | 70 | #endif /* !__ASSEMBLY__ */ |
| 63 | #else /* CONFIG_GENERIC_BUG */ | 71 | #else /* CONFIG_GENERIC_BUG */ |
| 64 | #ifndef __ASSEMBLY__ | 72 | #ifndef __ASSEMBLY__ |
| 65 | #define BUG() \ | 73 | #define __BUG_FLAGS(flags) do { \ |
| 66 | do { \ | ||
| 67 | __asm__ __volatile__ ("ebreak\n"); \ | 74 | __asm__ __volatile__ ("ebreak\n"); \ |
| 68 | unreachable(); \ | ||
| 69 | } while (0) | 75 | } while (0) |
| 70 | #endif /* !__ASSEMBLY__ */ | 76 | #endif /* !__ASSEMBLY__ */ |
| 71 | #endif /* CONFIG_GENERIC_BUG */ | 77 | #endif /* CONFIG_GENERIC_BUG */ |
| 72 | 78 | ||
| 79 | #define BUG() do { \ | ||
| 80 | __BUG_FLAGS(0); \ | ||
| 81 | unreachable(); \ | ||
| 82 | } while (0) | ||
| 83 | |||
| 84 | #define __WARN_FLAGS(flags) __BUG_FLAGS(BUGFLAG_WARNING|(flags)) | ||
| 85 | |||
| 73 | #define HAVE_ARCH_BUG | 86 | #define HAVE_ARCH_BUG |
| 74 | 87 | ||
| 75 | #include <asm-generic/bug.h> | 88 | #include <asm-generic/bug.h> |
diff --git a/arch/riscv/include/asm/cacheflush.h b/arch/riscv/include/asm/cacheflush.h index 8f13074413a7..1f4ba68ab9aa 100644 --- a/arch/riscv/include/asm/cacheflush.h +++ b/arch/riscv/include/asm/cacheflush.h | |||
| @@ -47,7 +47,7 @@ static inline void flush_dcache_page(struct page *page) | |||
| 47 | 47 | ||
| 48 | #else /* CONFIG_SMP */ | 48 | #else /* CONFIG_SMP */ |
| 49 | 49 | ||
| 50 | #define flush_icache_all() sbi_remote_fence_i(NULL) | 50 | void flush_icache_all(void); |
| 51 | void flush_icache_mm(struct mm_struct *mm, bool local); | 51 | void flush_icache_mm(struct mm_struct *mm, bool local); |
| 52 | 52 | ||
| 53 | #endif /* CONFIG_SMP */ | 53 | #endif /* CONFIG_SMP */ |
diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h index 28a0d1cb374c..3c3c26c3a1f1 100644 --- a/arch/riscv/include/asm/csr.h +++ b/arch/riscv/include/asm/csr.h | |||
| @@ -14,64 +14,95 @@ | |||
| 14 | #ifndef _ASM_RISCV_CSR_H | 14 | #ifndef _ASM_RISCV_CSR_H |
| 15 | #define _ASM_RISCV_CSR_H | 15 | #define _ASM_RISCV_CSR_H |
| 16 | 16 | ||
| 17 | #include <asm/asm.h> | ||
| 17 | #include <linux/const.h> | 18 | #include <linux/const.h> |
| 18 | 19 | ||
| 19 | /* Status register flags */ | 20 | /* Status register flags */ |
| 20 | #define SR_SIE _AC(0x00000002, UL) /* Supervisor Interrupt Enable */ | 21 | #define SR_SIE _AC(0x00000002, UL) /* Supervisor Interrupt Enable */ |
| 21 | #define SR_SPIE _AC(0x00000020, UL) /* Previous Supervisor IE */ | 22 | #define SR_SPIE _AC(0x00000020, UL) /* Previous Supervisor IE */ |
| 22 | #define SR_SPP _AC(0x00000100, UL) /* Previously Supervisor */ | 23 | #define SR_SPP _AC(0x00000100, UL) /* Previously Supervisor */ |
| 23 | #define SR_SUM _AC(0x00040000, UL) /* Supervisor may access User Memory */ | 24 | #define SR_SUM _AC(0x00040000, UL) /* Supervisor User Memory Access */ |
| 24 | 25 | ||
| 25 | #define SR_FS _AC(0x00006000, UL) /* Floating-point Status */ | 26 | #define SR_FS _AC(0x00006000, UL) /* Floating-point Status */ |
| 26 | #define SR_FS_OFF _AC(0x00000000, UL) | 27 | #define SR_FS_OFF _AC(0x00000000, UL) |
| 27 | #define SR_FS_INITIAL _AC(0x00002000, UL) | 28 | #define SR_FS_INITIAL _AC(0x00002000, UL) |
| 28 | #define SR_FS_CLEAN _AC(0x00004000, UL) | 29 | #define SR_FS_CLEAN _AC(0x00004000, UL) |
| 29 | #define SR_FS_DIRTY _AC(0x00006000, UL) | 30 | #define SR_FS_DIRTY _AC(0x00006000, UL) |
| 30 | 31 | ||
| 31 | #define SR_XS _AC(0x00018000, UL) /* Extension Status */ | 32 | #define SR_XS _AC(0x00018000, UL) /* Extension Status */ |
| 32 | #define SR_XS_OFF _AC(0x00000000, UL) | 33 | #define SR_XS_OFF _AC(0x00000000, UL) |
| 33 | #define SR_XS_INITIAL _AC(0x00008000, UL) | 34 | #define SR_XS_INITIAL _AC(0x00008000, UL) |
| 34 | #define SR_XS_CLEAN _AC(0x00010000, UL) | 35 | #define SR_XS_CLEAN _AC(0x00010000, UL) |
| 35 | #define SR_XS_DIRTY _AC(0x00018000, UL) | 36 | #define SR_XS_DIRTY _AC(0x00018000, UL) |
| 36 | 37 | ||
| 37 | #ifndef CONFIG_64BIT | 38 | #ifndef CONFIG_64BIT |
| 38 | #define SR_SD _AC(0x80000000, UL) /* FS/XS dirty */ | 39 | #define SR_SD _AC(0x80000000, UL) /* FS/XS dirty */ |
| 39 | #else | 40 | #else |
| 40 | #define SR_SD _AC(0x8000000000000000, UL) /* FS/XS dirty */ | 41 | #define SR_SD _AC(0x8000000000000000, UL) /* FS/XS dirty */ |
| 41 | #endif | 42 | #endif |
| 42 | 43 | ||
| 43 | /* SATP flags */ | 44 | /* SATP flags */ |
| 44 | #if __riscv_xlen == 32 | 45 | #ifndef CONFIG_64BIT |
| 45 | #define SATP_PPN _AC(0x003FFFFF, UL) | 46 | #define SATP_PPN _AC(0x003FFFFF, UL) |
| 46 | #define SATP_MODE_32 _AC(0x80000000, UL) | 47 | #define SATP_MODE_32 _AC(0x80000000, UL) |
| 47 | #define SATP_MODE SATP_MODE_32 | 48 | #define SATP_MODE SATP_MODE_32 |
| 48 | #else | 49 | #else |
| 49 | #define SATP_PPN _AC(0x00000FFFFFFFFFFF, UL) | 50 | #define SATP_PPN _AC(0x00000FFFFFFFFFFF, UL) |
| 50 | #define SATP_MODE_39 _AC(0x8000000000000000, UL) | 51 | #define SATP_MODE_39 _AC(0x8000000000000000, UL) |
| 51 | #define SATP_MODE SATP_MODE_39 | 52 | #define SATP_MODE SATP_MODE_39 |
| 52 | #endif | 53 | #endif |
| 53 | 54 | ||
| 54 | /* Interrupt Enable and Interrupt Pending flags */ | 55 | /* SCAUSE */ |
| 55 | #define SIE_SSIE _AC(0x00000002, UL) /* Software Interrupt Enable */ | 56 | #define SCAUSE_IRQ_FLAG (_AC(1, UL) << (__riscv_xlen - 1)) |
| 56 | #define SIE_STIE _AC(0x00000020, UL) /* Timer Interrupt Enable */ | 57 | |
| 57 | #define SIE_SEIE _AC(0x00000200, UL) /* External Interrupt Enable */ | 58 | #define IRQ_U_SOFT 0 |
| 58 | 59 | #define IRQ_S_SOFT 1 | |
| 59 | #define EXC_INST_MISALIGNED 0 | 60 | #define IRQ_M_SOFT 3 |
| 60 | #define EXC_INST_ACCESS 1 | 61 | #define IRQ_U_TIMER 4 |
| 61 | #define EXC_BREAKPOINT 3 | 62 | #define IRQ_S_TIMER 5 |
| 62 | #define EXC_LOAD_ACCESS 5 | 63 | #define IRQ_M_TIMER 7 |
| 63 | #define EXC_STORE_ACCESS 7 | 64 | #define IRQ_U_EXT 8 |
| 64 | #define EXC_SYSCALL 8 | 65 | #define IRQ_S_EXT 9 |
| 65 | #define EXC_INST_PAGE_FAULT 12 | 66 | #define IRQ_M_EXT 11 |
| 66 | #define EXC_LOAD_PAGE_FAULT 13 | 67 | |
| 67 | #define EXC_STORE_PAGE_FAULT 15 | 68 | #define EXC_INST_MISALIGNED 0 |
| 69 | #define EXC_INST_ACCESS 1 | ||
| 70 | #define EXC_BREAKPOINT 3 | ||
| 71 | #define EXC_LOAD_ACCESS 5 | ||
| 72 | #define EXC_STORE_ACCESS 7 | ||
| 73 | #define EXC_SYSCALL 8 | ||
| 74 | #define EXC_INST_PAGE_FAULT 12 | ||
| 75 | #define EXC_LOAD_PAGE_FAULT 13 | ||
| 76 | #define EXC_STORE_PAGE_FAULT 15 | ||
| 77 | |||
| 78 | /* SIE (Interrupt Enable) and SIP (Interrupt Pending) flags */ | ||
| 79 | #define SIE_SSIE (_AC(0x1, UL) << IRQ_S_SOFT) | ||
| 80 | #define SIE_STIE (_AC(0x1, UL) << IRQ_S_TIMER) | ||
| 81 | #define SIE_SEIE (_AC(0x1, UL) << IRQ_S_EXT) | ||
| 82 | |||
| 83 | #define CSR_CYCLE 0xc00 | ||
| 84 | #define CSR_TIME 0xc01 | ||
| 85 | #define CSR_INSTRET 0xc02 | ||
| 86 | #define CSR_SSTATUS 0x100 | ||
| 87 | #define CSR_SIE 0x104 | ||
| 88 | #define CSR_STVEC 0x105 | ||
| 89 | #define CSR_SCOUNTEREN 0x106 | ||
| 90 | #define CSR_SSCRATCH 0x140 | ||
| 91 | #define CSR_SEPC 0x141 | ||
| 92 | #define CSR_SCAUSE 0x142 | ||
| 93 | #define CSR_STVAL 0x143 | ||
| 94 | #define CSR_SIP 0x144 | ||
| 95 | #define CSR_SATP 0x180 | ||
| 96 | #define CSR_CYCLEH 0xc80 | ||
| 97 | #define CSR_TIMEH 0xc81 | ||
| 98 | #define CSR_INSTRETH 0xc82 | ||
| 68 | 99 | ||
| 69 | #ifndef __ASSEMBLY__ | 100 | #ifndef __ASSEMBLY__ |
| 70 | 101 | ||
| 71 | #define csr_swap(csr, val) \ | 102 | #define csr_swap(csr, val) \ |
| 72 | ({ \ | 103 | ({ \ |
| 73 | unsigned long __v = (unsigned long)(val); \ | 104 | unsigned long __v = (unsigned long)(val); \ |
| 74 | __asm__ __volatile__ ("csrrw %0, " #csr ", %1" \ | 105 | __asm__ __volatile__ ("csrrw %0, " __ASM_STR(csr) ", %1"\ |
| 75 | : "=r" (__v) : "rK" (__v) \ | 106 | : "=r" (__v) : "rK" (__v) \ |
| 76 | : "memory"); \ | 107 | : "memory"); \ |
| 77 | __v; \ | 108 | __v; \ |
| @@ -80,7 +111,7 @@ | |||
| 80 | #define csr_read(csr) \ | 111 | #define csr_read(csr) \ |
| 81 | ({ \ | 112 | ({ \ |
| 82 | register unsigned long __v; \ | 113 | register unsigned long __v; \ |
| 83 | __asm__ __volatile__ ("csrr %0, " #csr \ | 114 | __asm__ __volatile__ ("csrr %0, " __ASM_STR(csr) \ |
| 84 | : "=r" (__v) : \ | 115 | : "=r" (__v) : \ |
| 85 | : "memory"); \ | 116 | : "memory"); \ |
| 86 | __v; \ | 117 | __v; \ |
| @@ -89,7 +120,7 @@ | |||
| 89 | #define csr_write(csr, val) \ | 120 | #define csr_write(csr, val) \ |
| 90 | ({ \ | 121 | ({ \ |
| 91 | unsigned long __v = (unsigned long)(val); \ | 122 | unsigned long __v = (unsigned long)(val); \ |
| 92 | __asm__ __volatile__ ("csrw " #csr ", %0" \ | 123 | __asm__ __volatile__ ("csrw " __ASM_STR(csr) ", %0" \ |
| 93 | : : "rK" (__v) \ | 124 | : : "rK" (__v) \ |
| 94 | : "memory"); \ | 125 | : "memory"); \ |
| 95 | }) | 126 | }) |
| @@ -97,7 +128,7 @@ | |||
| 97 | #define csr_read_set(csr, val) \ | 128 | #define csr_read_set(csr, val) \ |
| 98 | ({ \ | 129 | ({ \ |
| 99 | unsigned long __v = (unsigned long)(val); \ | 130 | unsigned long __v = (unsigned long)(val); \ |
| 100 | __asm__ __volatile__ ("csrrs %0, " #csr ", %1" \ | 131 | __asm__ __volatile__ ("csrrs %0, " __ASM_STR(csr) ", %1"\ |
| 101 | : "=r" (__v) : "rK" (__v) \ | 132 | : "=r" (__v) : "rK" (__v) \ |
| 102 | : "memory"); \ | 133 | : "memory"); \ |
| 103 | __v; \ | 134 | __v; \ |
| @@ -106,7 +137,7 @@ | |||
| 106 | #define csr_set(csr, val) \ | 137 | #define csr_set(csr, val) \ |
| 107 | ({ \ | 138 | ({ \ |
| 108 | unsigned long __v = (unsigned long)(val); \ | 139 | unsigned long __v = (unsigned long)(val); \ |
| 109 | __asm__ __volatile__ ("csrs " #csr ", %0" \ | 140 | __asm__ __volatile__ ("csrs " __ASM_STR(csr) ", %0" \ |
| 110 | : : "rK" (__v) \ | 141 | : : "rK" (__v) \ |
| 111 | : "memory"); \ | 142 | : "memory"); \ |
| 112 | }) | 143 | }) |
| @@ -114,7 +145,7 @@ | |||
| 114 | #define csr_read_clear(csr, val) \ | 145 | #define csr_read_clear(csr, val) \ |
| 115 | ({ \ | 146 | ({ \ |
| 116 | unsigned long __v = (unsigned long)(val); \ | 147 | unsigned long __v = (unsigned long)(val); \ |
| 117 | __asm__ __volatile__ ("csrrc %0, " #csr ", %1" \ | 148 | __asm__ __volatile__ ("csrrc %0, " __ASM_STR(csr) ", %1"\ |
| 118 | : "=r" (__v) : "rK" (__v) \ | 149 | : "=r" (__v) : "rK" (__v) \ |
| 119 | : "memory"); \ | 150 | : "memory"); \ |
| 120 | __v; \ | 151 | __v; \ |
| @@ -123,7 +154,7 @@ | |||
| 123 | #define csr_clear(csr, val) \ | 154 | #define csr_clear(csr, val) \ |
| 124 | ({ \ | 155 | ({ \ |
| 125 | unsigned long __v = (unsigned long)(val); \ | 156 | unsigned long __v = (unsigned long)(val); \ |
| 126 | __asm__ __volatile__ ("csrc " #csr ", %0" \ | 157 | __asm__ __volatile__ ("csrc " __ASM_STR(csr) ", %0" \ |
| 127 | : : "rK" (__v) \ | 158 | : : "rK" (__v) \ |
| 128 | : "memory"); \ | 159 | : "memory"); \ |
| 129 | }) | 160 | }) |
diff --git a/arch/riscv/include/asm/elf.h b/arch/riscv/include/asm/elf.h index 697fc23b0d5a..ce0cd7d77eb0 100644 --- a/arch/riscv/include/asm/elf.h +++ b/arch/riscv/include/asm/elf.h | |||
| @@ -27,13 +27,7 @@ | |||
| 27 | #define ELF_CLASS ELFCLASS32 | 27 | #define ELF_CLASS ELFCLASS32 |
| 28 | #endif | 28 | #endif |
| 29 | 29 | ||
| 30 | #if defined(__LITTLE_ENDIAN) | ||
| 31 | #define ELF_DATA ELFDATA2LSB | 30 | #define ELF_DATA ELFDATA2LSB |
| 32 | #elif defined(__BIG_ENDIAN) | ||
| 33 | #define ELF_DATA ELFDATA2MSB | ||
| 34 | #else | ||
| 35 | #error "Unknown endianness" | ||
| 36 | #endif | ||
| 37 | 31 | ||
| 38 | /* | 32 | /* |
| 39 | * This is used to ensure we don't load something for the wrong architecture. | 33 | * This is used to ensure we don't load something for the wrong architecture. |
diff --git a/arch/riscv/include/asm/futex.h b/arch/riscv/include/asm/futex.h index 66641624d8a5..4ad6409c4647 100644 --- a/arch/riscv/include/asm/futex.h +++ b/arch/riscv/include/asm/futex.h | |||
| @@ -7,18 +7,6 @@ | |||
| 7 | #ifndef _ASM_FUTEX_H | 7 | #ifndef _ASM_FUTEX_H |
| 8 | #define _ASM_FUTEX_H | 8 | #define _ASM_FUTEX_H |
| 9 | 9 | ||
| 10 | #ifndef CONFIG_RISCV_ISA_A | ||
| 11 | /* | ||
| 12 | * Use the generic interrupt disabling versions if the A extension | ||
| 13 | * is not supported. | ||
| 14 | */ | ||
| 15 | #ifdef CONFIG_SMP | ||
| 16 | #error "Can't support generic futex calls without A extension on SMP" | ||
| 17 | #endif | ||
| 18 | #include <asm-generic/futex.h> | ||
| 19 | |||
| 20 | #else /* CONFIG_RISCV_ISA_A */ | ||
| 21 | |||
| 22 | #include <linux/futex.h> | 10 | #include <linux/futex.h> |
| 23 | #include <linux/uaccess.h> | 11 | #include <linux/uaccess.h> |
| 24 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
| @@ -124,5 +112,4 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, | |||
| 124 | return ret; | 112 | return ret; |
| 125 | } | 113 | } |
| 126 | 114 | ||
| 127 | #endif /* CONFIG_RISCV_ISA_A */ | ||
| 128 | #endif /* _ASM_FUTEX_H */ | 115 | #endif /* _ASM_FUTEX_H */ |
diff --git a/arch/riscv/include/asm/irqflags.h b/arch/riscv/include/asm/irqflags.h index 07a3c6d5706f..1a69b3bcd371 100644 --- a/arch/riscv/include/asm/irqflags.h +++ b/arch/riscv/include/asm/irqflags.h | |||
| @@ -21,25 +21,25 @@ | |||
| 21 | /* read interrupt enabled status */ | 21 | /* read interrupt enabled status */ |
| 22 | static inline unsigned long arch_local_save_flags(void) | 22 | static inline unsigned long arch_local_save_flags(void) |
| 23 | { | 23 | { |
| 24 | return csr_read(sstatus); | 24 | return csr_read(CSR_SSTATUS); |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | /* unconditionally enable interrupts */ | 27 | /* unconditionally enable interrupts */ |
| 28 | static inline void arch_local_irq_enable(void) | 28 | static inline void arch_local_irq_enable(void) |
| 29 | { | 29 | { |
| 30 | csr_set(sstatus, SR_SIE); | 30 | csr_set(CSR_SSTATUS, SR_SIE); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | /* unconditionally disable interrupts */ | 33 | /* unconditionally disable interrupts */ |
| 34 | static inline void arch_local_irq_disable(void) | 34 | static inline void arch_local_irq_disable(void) |
| 35 | { | 35 | { |
| 36 | csr_clear(sstatus, SR_SIE); | 36 | csr_clear(CSR_SSTATUS, SR_SIE); |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | /* get status and disable interrupts */ | 39 | /* get status and disable interrupts */ |
| 40 | static inline unsigned long arch_local_irq_save(void) | 40 | static inline unsigned long arch_local_irq_save(void) |
| 41 | { | 41 | { |
| 42 | return csr_read_clear(sstatus, SR_SIE); | 42 | return csr_read_clear(CSR_SSTATUS, SR_SIE); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | /* test flags */ | 45 | /* test flags */ |
| @@ -57,7 +57,7 @@ static inline int arch_irqs_disabled(void) | |||
| 57 | /* set interrupt enabled status */ | 57 | /* set interrupt enabled status */ |
| 58 | static inline void arch_local_irq_restore(unsigned long flags) | 58 | static inline void arch_local_irq_restore(unsigned long flags) |
| 59 | { | 59 | { |
| 60 | csr_set(sstatus, flags & SR_SIE); | 60 | csr_set(CSR_SSTATUS, flags & SR_SIE); |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | #endif /* _ASM_RISCV_IRQFLAGS_H */ | 63 | #endif /* _ASM_RISCV_IRQFLAGS_H */ |
diff --git a/arch/riscv/include/asm/mmu_context.h b/arch/riscv/include/asm/mmu_context.h index 336d60ec5698..bf4f097a9051 100644 --- a/arch/riscv/include/asm/mmu_context.h +++ b/arch/riscv/include/asm/mmu_context.h | |||
| @@ -20,8 +20,6 @@ | |||
| 20 | 20 | ||
| 21 | #include <linux/mm.h> | 21 | #include <linux/mm.h> |
| 22 | #include <linux/sched.h> | 22 | #include <linux/sched.h> |
| 23 | #include <asm/tlbflush.h> | ||
| 24 | #include <asm/cacheflush.h> | ||
| 25 | 23 | ||
| 26 | static inline void enter_lazy_tlb(struct mm_struct *mm, | 24 | static inline void enter_lazy_tlb(struct mm_struct *mm, |
| 27 | struct task_struct *task) | 25 | struct task_struct *task) |
| @@ -39,61 +37,8 @@ static inline void destroy_context(struct mm_struct *mm) | |||
| 39 | { | 37 | { |
| 40 | } | 38 | } |
| 41 | 39 | ||
| 42 | /* | 40 | void switch_mm(struct mm_struct *prev, struct mm_struct *next, |
| 43 | * When necessary, performs a deferred icache flush for the given MM context, | 41 | struct task_struct *task); |
| 44 | * on the local CPU. RISC-V has no direct mechanism for instruction cache | ||
| 45 | * shoot downs, so instead we send an IPI that informs the remote harts they | ||
| 46 | * need to flush their local instruction caches. To avoid pathologically slow | ||
| 47 | * behavior in a common case (a bunch of single-hart processes on a many-hart | ||
| 48 | * machine, ie 'make -j') we avoid the IPIs for harts that are not currently | ||
| 49 | * executing a MM context and instead schedule a deferred local instruction | ||
| 50 | * cache flush to be performed before execution resumes on each hart. This | ||
| 51 | * actually performs that local instruction cache flush, which implicitly only | ||
| 52 | * refers to the current hart. | ||
| 53 | */ | ||
| 54 | static inline void flush_icache_deferred(struct mm_struct *mm) | ||
| 55 | { | ||
| 56 | #ifdef CONFIG_SMP | ||
| 57 | unsigned int cpu = smp_processor_id(); | ||
| 58 | cpumask_t *mask = &mm->context.icache_stale_mask; | ||
| 59 | |||
| 60 | if (cpumask_test_cpu(cpu, mask)) { | ||
| 61 | cpumask_clear_cpu(cpu, mask); | ||
| 62 | /* | ||
| 63 | * Ensure the remote hart's writes are visible to this hart. | ||
| 64 | * This pairs with a barrier in flush_icache_mm. | ||
| 65 | */ | ||
| 66 | smp_mb(); | ||
| 67 | local_flush_icache_all(); | ||
| 68 | } | ||
| 69 | #endif | ||
| 70 | } | ||
| 71 | |||
| 72 | static inline void switch_mm(struct mm_struct *prev, | ||
| 73 | struct mm_struct *next, struct task_struct *task) | ||
| 74 | { | ||
| 75 | if (likely(prev != next)) { | ||
| 76 | /* | ||
| 77 | * Mark the current MM context as inactive, and the next as | ||
| 78 | * active. This is at least used by the icache flushing | ||
| 79 | * routines in order to determine who should | ||
| 80 | */ | ||
| 81 | unsigned int cpu = smp_processor_id(); | ||
| 82 | |||
| 83 | cpumask_clear_cpu(cpu, mm_cpumask(prev)); | ||
| 84 | cpumask_set_cpu(cpu, mm_cpumask(next)); | ||
| 85 | |||
| 86 | /* | ||
| 87 | * Use the old spbtr name instead of using the current satp | ||
| 88 | * name to support binutils 2.29 which doesn't know about the | ||
| 89 | * privileged ISA 1.10 yet. | ||
| 90 | */ | ||
| 91 | csr_write(sptbr, virt_to_pfn(next->pgd) | SATP_MODE); | ||
| 92 | local_flush_tlb_all(); | ||
| 93 | |||
| 94 | flush_icache_deferred(next); | ||
| 95 | } | ||
| 96 | } | ||
| 97 | 42 | ||
| 98 | static inline void activate_mm(struct mm_struct *prev, | 43 | static inline void activate_mm(struct mm_struct *prev, |
| 99 | struct mm_struct *next) | 44 | struct mm_struct *next) |
diff --git a/arch/riscv/include/asm/ptrace.h b/arch/riscv/include/asm/ptrace.h index d35ec2f41381..9c867a4bac83 100644 --- a/arch/riscv/include/asm/ptrace.h +++ b/arch/riscv/include/asm/ptrace.h | |||
| @@ -70,47 +70,38 @@ struct pt_regs { | |||
| 70 | 70 | ||
| 71 | 71 | ||
| 72 | /* Helpers for working with the instruction pointer */ | 72 | /* Helpers for working with the instruction pointer */ |
| 73 | #define GET_IP(regs) ((regs)->sepc) | ||
| 74 | #define SET_IP(regs, val) (GET_IP(regs) = (val)) | ||
| 75 | |||
| 76 | static inline unsigned long instruction_pointer(struct pt_regs *regs) | 73 | static inline unsigned long instruction_pointer(struct pt_regs *regs) |
| 77 | { | 74 | { |
| 78 | return GET_IP(regs); | 75 | return regs->sepc; |
| 79 | } | 76 | } |
| 80 | static inline void instruction_pointer_set(struct pt_regs *regs, | 77 | static inline void instruction_pointer_set(struct pt_regs *regs, |
| 81 | unsigned long val) | 78 | unsigned long val) |
| 82 | { | 79 | { |
| 83 | SET_IP(regs, val); | 80 | regs->sepc = val; |
| 84 | } | 81 | } |
| 85 | 82 | ||
| 86 | #define profile_pc(regs) instruction_pointer(regs) | 83 | #define profile_pc(regs) instruction_pointer(regs) |
| 87 | 84 | ||
| 88 | /* Helpers for working with the user stack pointer */ | 85 | /* Helpers for working with the user stack pointer */ |
| 89 | #define GET_USP(regs) ((regs)->sp) | ||
| 90 | #define SET_USP(regs, val) (GET_USP(regs) = (val)) | ||
| 91 | |||
| 92 | static inline unsigned long user_stack_pointer(struct pt_regs *regs) | 86 | static inline unsigned long user_stack_pointer(struct pt_regs *regs) |
| 93 | { | 87 | { |
| 94 | return GET_USP(regs); | 88 | return regs->sp; |
| 95 | } | 89 | } |
| 96 | static inline void user_stack_pointer_set(struct pt_regs *regs, | 90 | static inline void user_stack_pointer_set(struct pt_regs *regs, |
| 97 | unsigned long val) | 91 | unsigned long val) |
| 98 | { | 92 | { |
| 99 | SET_USP(regs, val); | 93 | regs->sp = val; |
| 100 | } | 94 | } |
| 101 | 95 | ||
| 102 | /* Helpers for working with the frame pointer */ | 96 | /* Helpers for working with the frame pointer */ |
| 103 | #define GET_FP(regs) ((regs)->s0) | ||
| 104 | #define SET_FP(regs, val) (GET_FP(regs) = (val)) | ||
| 105 | |||
| 106 | static inline unsigned long frame_pointer(struct pt_regs *regs) | 97 | static inline unsigned long frame_pointer(struct pt_regs *regs) |
| 107 | { | 98 | { |
| 108 | return GET_FP(regs); | 99 | return regs->s0; |
| 109 | } | 100 | } |
| 110 | static inline void frame_pointer_set(struct pt_regs *regs, | 101 | static inline void frame_pointer_set(struct pt_regs *regs, |
| 111 | unsigned long val) | 102 | unsigned long val) |
| 112 | { | 103 | { |
| 113 | SET_FP(regs, val); | 104 | regs->s0 = val; |
| 114 | } | 105 | } |
| 115 | 106 | ||
| 116 | static inline unsigned long regs_return_value(struct pt_regs *regs) | 107 | static inline unsigned long regs_return_value(struct pt_regs *regs) |
diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index b6bb10b92fe2..19f231615510 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h | |||
| @@ -26,22 +26,27 @@ | |||
| 26 | #define SBI_REMOTE_SFENCE_VMA_ASID 7 | 26 | #define SBI_REMOTE_SFENCE_VMA_ASID 7 |
| 27 | #define SBI_SHUTDOWN 8 | 27 | #define SBI_SHUTDOWN 8 |
| 28 | 28 | ||
| 29 | #define SBI_CALL(which, arg0, arg1, arg2) ({ \ | 29 | #define SBI_CALL(which, arg0, arg1, arg2, arg3) ({ \ |
| 30 | register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0); \ | 30 | register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0); \ |
| 31 | register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1); \ | 31 | register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1); \ |
| 32 | register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2); \ | 32 | register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2); \ |
| 33 | register uintptr_t a3 asm ("a3") = (uintptr_t)(arg3); \ | ||
| 33 | register uintptr_t a7 asm ("a7") = (uintptr_t)(which); \ | 34 | register uintptr_t a7 asm ("a7") = (uintptr_t)(which); \ |
| 34 | asm volatile ("ecall" \ | 35 | asm volatile ("ecall" \ |
| 35 | : "+r" (a0) \ | 36 | : "+r" (a0) \ |
| 36 | : "r" (a1), "r" (a2), "r" (a7) \ | 37 | : "r" (a1), "r" (a2), "r" (a3), "r" (a7) \ |
| 37 | : "memory"); \ | 38 | : "memory"); \ |
| 38 | a0; \ | 39 | a0; \ |
| 39 | }) | 40 | }) |
| 40 | 41 | ||
| 41 | /* Lazy implementations until SBI is finalized */ | 42 | /* Lazy implementations until SBI is finalized */ |
| 42 | #define SBI_CALL_0(which) SBI_CALL(which, 0, 0, 0) | 43 | #define SBI_CALL_0(which) SBI_CALL(which, 0, 0, 0, 0) |
| 43 | #define SBI_CALL_1(which, arg0) SBI_CALL(which, arg0, 0, 0) | 44 | #define SBI_CALL_1(which, arg0) SBI_CALL(which, arg0, 0, 0, 0) |
| 44 | #define SBI_CALL_2(which, arg0, arg1) SBI_CALL(which, arg0, arg1, 0) | 45 | #define SBI_CALL_2(which, arg0, arg1) SBI_CALL(which, arg0, arg1, 0, 0) |
| 46 | #define SBI_CALL_3(which, arg0, arg1, arg2) \ | ||
| 47 | SBI_CALL(which, arg0, arg1, arg2, 0) | ||
| 48 | #define SBI_CALL_4(which, arg0, arg1, arg2, arg3) \ | ||
| 49 | SBI_CALL(which, arg0, arg1, arg2, arg3) | ||
| 45 | 50 | ||
| 46 | static inline void sbi_console_putchar(int ch) | 51 | static inline void sbi_console_putchar(int ch) |
| 47 | { | 52 | { |
| @@ -86,7 +91,7 @@ static inline void sbi_remote_sfence_vma(const unsigned long *hart_mask, | |||
| 86 | unsigned long start, | 91 | unsigned long start, |
| 87 | unsigned long size) | 92 | unsigned long size) |
| 88 | { | 93 | { |
| 89 | SBI_CALL_1(SBI_REMOTE_SFENCE_VMA, hart_mask); | 94 | SBI_CALL_3(SBI_REMOTE_SFENCE_VMA, hart_mask, start, size); |
| 90 | } | 95 | } |
| 91 | 96 | ||
| 92 | static inline void sbi_remote_sfence_vma_asid(const unsigned long *hart_mask, | 97 | static inline void sbi_remote_sfence_vma_asid(const unsigned long *hart_mask, |
| @@ -94,7 +99,7 @@ static inline void sbi_remote_sfence_vma_asid(const unsigned long *hart_mask, | |||
| 94 | unsigned long size, | 99 | unsigned long size, |
| 95 | unsigned long asid) | 100 | unsigned long asid) |
| 96 | { | 101 | { |
| 97 | SBI_CALL_1(SBI_REMOTE_SFENCE_VMA_ASID, hart_mask); | 102 | SBI_CALL_4(SBI_REMOTE_SFENCE_VMA_ASID, hart_mask, start, size, asid); |
| 98 | } | 103 | } |
| 99 | 104 | ||
| 100 | #endif | 105 | #endif |
diff --git a/arch/riscv/include/asm/sifive_l2_cache.h b/arch/riscv/include/asm/sifive_l2_cache.h new file mode 100644 index 000000000000..04f6748fc50b --- /dev/null +++ b/arch/riscv/include/asm/sifive_l2_cache.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* | ||
| 3 | * SiFive L2 Cache Controller header file | ||
| 4 | * | ||
| 5 | */ | ||
| 6 | |||
| 7 | #ifndef _ASM_RISCV_SIFIVE_L2_CACHE_H | ||
| 8 | #define _ASM_RISCV_SIFIVE_L2_CACHE_H | ||
| 9 | |||
| 10 | extern int register_sifive_l2_error_notifier(struct notifier_block *nb); | ||
| 11 | extern int unregister_sifive_l2_error_notifier(struct notifier_block *nb); | ||
| 12 | |||
| 13 | #define SIFIVE_L2_ERR_TYPE_CE 0 | ||
| 14 | #define SIFIVE_L2_ERR_TYPE_UE 1 | ||
| 15 | |||
| 16 | #endif /* _ASM_RISCV_SIFIVE_L2_CACHE_H */ | ||
diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h index 1c9cc8389928..9c039870019b 100644 --- a/arch/riscv/include/asm/thread_info.h +++ b/arch/riscv/include/asm/thread_info.h | |||
| @@ -28,7 +28,9 @@ | |||
| 28 | #include <asm/processor.h> | 28 | #include <asm/processor.h> |
| 29 | #include <asm/csr.h> | 29 | #include <asm/csr.h> |
| 30 | 30 | ||
| 31 | typedef unsigned long mm_segment_t; | 31 | typedef struct { |
| 32 | unsigned long seg; | ||
| 33 | } mm_segment_t; | ||
| 32 | 34 | ||
| 33 | /* | 35 | /* |
| 34 | * low level task data that entry.S needs immediate access to | 36 | * low level task data that entry.S needs immediate access to |
diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h index fb53a8089e76..b26f407be5c8 100644 --- a/arch/riscv/include/asm/uaccess.h +++ b/arch/riscv/include/asm/uaccess.h | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <linux/compiler.h> | 23 | #include <linux/compiler.h> |
| 24 | #include <linux/thread_info.h> | 24 | #include <linux/thread_info.h> |
| 25 | #include <asm/byteorder.h> | 25 | #include <asm/byteorder.h> |
| 26 | #include <asm/extable.h> | ||
| 26 | #include <asm/asm.h> | 27 | #include <asm/asm.h> |
| 27 | 28 | ||
| 28 | #define __enable_user_access() \ | 29 | #define __enable_user_access() \ |
| @@ -38,8 +39,10 @@ | |||
| 38 | * For historical reasons, these macros are grossly misnamed. | 39 | * For historical reasons, these macros are grossly misnamed. |
| 39 | */ | 40 | */ |
| 40 | 41 | ||
| 41 | #define KERNEL_DS (~0UL) | 42 | #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) |
| 42 | #define USER_DS (TASK_SIZE) | 43 | |
| 44 | #define KERNEL_DS MAKE_MM_SEG(~0UL) | ||
| 45 | #define USER_DS MAKE_MM_SEG(TASK_SIZE) | ||
| 43 | 46 | ||
| 44 | #define get_fs() (current_thread_info()->addr_limit) | 47 | #define get_fs() (current_thread_info()->addr_limit) |
| 45 | 48 | ||
| @@ -48,9 +51,9 @@ static inline void set_fs(mm_segment_t fs) | |||
| 48 | current_thread_info()->addr_limit = fs; | 51 | current_thread_info()->addr_limit = fs; |
| 49 | } | 52 | } |
| 50 | 53 | ||
| 51 | #define segment_eq(a, b) ((a) == (b)) | 54 | #define segment_eq(a, b) ((a).seg == (b).seg) |
| 52 | 55 | ||
| 53 | #define user_addr_max() (get_fs()) | 56 | #define user_addr_max() (get_fs().seg) |
| 54 | 57 | ||
| 55 | 58 | ||
| 56 | /** | 59 | /** |
| @@ -82,7 +85,7 @@ static inline int __access_ok(unsigned long addr, unsigned long size) | |||
| 82 | { | 85 | { |
| 83 | const mm_segment_t fs = get_fs(); | 86 | const mm_segment_t fs = get_fs(); |
| 84 | 87 | ||
| 85 | return (size <= fs) && (addr <= (fs - size)); | 88 | return size <= fs.seg && addr <= fs.seg - size; |
| 86 | } | 89 | } |
| 87 | 90 | ||
| 88 | /* | 91 | /* |
| @@ -98,21 +101,8 @@ static inline int __access_ok(unsigned long addr, unsigned long size) | |||
| 98 | * on our cache or tlb entries. | 101 | * on our cache or tlb entries. |
| 99 | */ | 102 | */ |
| 100 | 103 | ||
| 101 | struct exception_table_entry { | ||
| 102 | unsigned long insn, fixup; | ||
| 103 | }; | ||
| 104 | |||
| 105 | extern int fixup_exception(struct pt_regs *state); | ||
| 106 | |||
| 107 | #if defined(__LITTLE_ENDIAN) | ||
| 108 | #define __MSW 1 | ||
| 109 | #define __LSW 0 | 104 | #define __LSW 0 |
| 110 | #elif defined(__BIG_ENDIAN) | 105 | #define __MSW 1 |
| 111 | #define __MSW 0 | ||
| 112 | #define __LSW 1 | ||
| 113 | #else | ||
| 114 | #error "Unknown endianness" | ||
| 115 | #endif | ||
| 116 | 106 | ||
| 117 | /* | 107 | /* |
| 118 | * The "__xxx" versions of the user access functions do not verify the address | 108 | * The "__xxx" versions of the user access functions do not verify the address |
diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c index dac98348c6a3..578bb5efc085 100644 --- a/arch/riscv/kernel/asm-offsets.c +++ b/arch/riscv/kernel/asm-offsets.c | |||
| @@ -312,9 +312,6 @@ void asm_offsets(void) | |||
| 312 | - offsetof(struct task_struct, thread.fstate.f[0]) | 312 | - offsetof(struct task_struct, thread.fstate.f[0]) |
| 313 | ); | 313 | ); |
| 314 | 314 | ||
| 315 | /* The assembler needs access to THREAD_SIZE as well. */ | ||
| 316 | DEFINE(ASM_THREAD_SIZE, THREAD_SIZE); | ||
| 317 | |||
| 318 | /* | 315 | /* |
| 319 | * We allocate a pt_regs on the stack when entering the kernel. This | 316 | * We allocate a pt_regs on the stack when entering the kernel. This |
| 320 | * ensures the alignment is sane. | 317 | * ensures the alignment is sane. |
diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c index cf2fca12414a..c8d2a3223099 100644 --- a/arch/riscv/kernel/cpu.c +++ b/arch/riscv/kernel/cpu.c | |||
| @@ -136,8 +136,7 @@ static void c_stop(struct seq_file *m, void *v) | |||
| 136 | static int c_show(struct seq_file *m, void *v) | 136 | static int c_show(struct seq_file *m, void *v) |
| 137 | { | 137 | { |
| 138 | unsigned long cpu_id = (unsigned long)v - 1; | 138 | unsigned long cpu_id = (unsigned long)v - 1; |
| 139 | struct device_node *node = of_get_cpu_node(cpuid_to_hartid_map(cpu_id), | 139 | struct device_node *node = of_get_cpu_node(cpu_id, NULL); |
| 140 | NULL); | ||
| 141 | const char *compat, *isa, *mmu; | 140 | const char *compat, *isa, *mmu; |
| 142 | 141 | ||
| 143 | seq_printf(m, "processor\t: %lu\n", cpu_id); | 142 | seq_printf(m, "processor\t: %lu\n", cpu_id); |
diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index fd9b57c8b4ce..1c1ecc238cfa 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S | |||
| @@ -37,11 +37,11 @@ | |||
| 37 | * the kernel thread pointer. If we came from the kernel, sscratch | 37 | * the kernel thread pointer. If we came from the kernel, sscratch |
| 38 | * will contain 0, and we should continue on the current TP. | 38 | * will contain 0, and we should continue on the current TP. |
| 39 | */ | 39 | */ |
| 40 | csrrw tp, sscratch, tp | 40 | csrrw tp, CSR_SSCRATCH, tp |
| 41 | bnez tp, _save_context | 41 | bnez tp, _save_context |
| 42 | 42 | ||
| 43 | _restore_kernel_tpsp: | 43 | _restore_kernel_tpsp: |
| 44 | csrr tp, sscratch | 44 | csrr tp, CSR_SSCRATCH |
| 45 | REG_S sp, TASK_TI_KERNEL_SP(tp) | 45 | REG_S sp, TASK_TI_KERNEL_SP(tp) |
| 46 | _save_context: | 46 | _save_context: |
| 47 | REG_S sp, TASK_TI_USER_SP(tp) | 47 | REG_S sp, TASK_TI_USER_SP(tp) |
| @@ -87,11 +87,11 @@ _save_context: | |||
| 87 | li t0, SR_SUM | SR_FS | 87 | li t0, SR_SUM | SR_FS |
| 88 | 88 | ||
| 89 | REG_L s0, TASK_TI_USER_SP(tp) | 89 | REG_L s0, TASK_TI_USER_SP(tp) |
| 90 | csrrc s1, sstatus, t0 | 90 | csrrc s1, CSR_SSTATUS, t0 |
| 91 | csrr s2, sepc | 91 | csrr s2, CSR_SEPC |
| 92 | csrr s3, sbadaddr | 92 | csrr s3, CSR_STVAL |
| 93 | csrr s4, scause | 93 | csrr s4, CSR_SCAUSE |
| 94 | csrr s5, sscratch | 94 | csrr s5, CSR_SSCRATCH |
| 95 | REG_S s0, PT_SP(sp) | 95 | REG_S s0, PT_SP(sp) |
| 96 | REG_S s1, PT_SSTATUS(sp) | 96 | REG_S s1, PT_SSTATUS(sp) |
| 97 | REG_S s2, PT_SEPC(sp) | 97 | REG_S s2, PT_SEPC(sp) |
| @@ -107,8 +107,8 @@ _save_context: | |||
| 107 | .macro RESTORE_ALL | 107 | .macro RESTORE_ALL |
| 108 | REG_L a0, PT_SSTATUS(sp) | 108 | REG_L a0, PT_SSTATUS(sp) |
| 109 | REG_L a2, PT_SEPC(sp) | 109 | REG_L a2, PT_SEPC(sp) |
| 110 | csrw sstatus, a0 | 110 | csrw CSR_SSTATUS, a0 |
| 111 | csrw sepc, a2 | 111 | csrw CSR_SEPC, a2 |
| 112 | 112 | ||
| 113 | REG_L x1, PT_RA(sp) | 113 | REG_L x1, PT_RA(sp) |
| 114 | REG_L x3, PT_GP(sp) | 114 | REG_L x3, PT_GP(sp) |
| @@ -155,7 +155,7 @@ ENTRY(handle_exception) | |||
| 155 | * Set sscratch register to 0, so that if a recursive exception | 155 | * Set sscratch register to 0, so that if a recursive exception |
| 156 | * occurs, the exception vector knows it came from the kernel | 156 | * occurs, the exception vector knows it came from the kernel |
| 157 | */ | 157 | */ |
| 158 | csrw sscratch, x0 | 158 | csrw CSR_SSCRATCH, x0 |
| 159 | 159 | ||
| 160 | /* Load the global pointer */ | 160 | /* Load the global pointer */ |
| 161 | .option push | 161 | .option push |
| @@ -248,7 +248,7 @@ resume_userspace: | |||
| 248 | * Save TP into sscratch, so we can find the kernel data structures | 248 | * Save TP into sscratch, so we can find the kernel data structures |
| 249 | * again. | 249 | * again. |
| 250 | */ | 250 | */ |
| 251 | csrw sscratch, tp | 251 | csrw CSR_SSCRATCH, tp |
| 252 | 252 | ||
| 253 | restore_all: | 253 | restore_all: |
| 254 | RESTORE_ALL | 254 | RESTORE_ALL |
diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S index fe884cd69abd..370c66ce187a 100644 --- a/arch/riscv/kernel/head.S +++ b/arch/riscv/kernel/head.S | |||
| @@ -23,7 +23,8 @@ | |||
| 23 | __INIT | 23 | __INIT |
| 24 | ENTRY(_start) | 24 | ENTRY(_start) |
| 25 | /* Mask all interrupts */ | 25 | /* Mask all interrupts */ |
| 26 | csrw sie, zero | 26 | csrw CSR_SIE, zero |
| 27 | csrw CSR_SIP, zero | ||
| 27 | 28 | ||
| 28 | /* Load the global pointer */ | 29 | /* Load the global pointer */ |
| 29 | .option push | 30 | .option push |
| @@ -68,14 +69,10 @@ clear_bss_done: | |||
| 68 | /* Restore C environment */ | 69 | /* Restore C environment */ |
| 69 | la tp, init_task | 70 | la tp, init_task |
| 70 | sw zero, TASK_TI_CPU(tp) | 71 | sw zero, TASK_TI_CPU(tp) |
| 71 | 72 | la sp, init_thread_union + THREAD_SIZE | |
| 72 | la sp, init_thread_union | ||
| 73 | li a0, ASM_THREAD_SIZE | ||
| 74 | add sp, sp, a0 | ||
| 75 | 73 | ||
| 76 | /* Start the kernel */ | 74 | /* Start the kernel */ |
| 77 | mv a0, s0 | 75 | mv a0, s1 |
| 78 | mv a1, s1 | ||
| 79 | call parse_dtb | 76 | call parse_dtb |
| 80 | tail start_kernel | 77 | tail start_kernel |
| 81 | 78 | ||
| @@ -89,7 +86,7 @@ relocate: | |||
| 89 | /* Point stvec to virtual address of intruction after satp write */ | 86 | /* Point stvec to virtual address of intruction after satp write */ |
| 90 | la a0, 1f | 87 | la a0, 1f |
| 91 | add a0, a0, a1 | 88 | add a0, a0, a1 |
| 92 | csrw stvec, a0 | 89 | csrw CSR_STVEC, a0 |
| 93 | 90 | ||
| 94 | /* Compute satp for kernel page tables, but don't load it yet */ | 91 | /* Compute satp for kernel page tables, but don't load it yet */ |
| 95 | la a2, swapper_pg_dir | 92 | la a2, swapper_pg_dir |
| @@ -99,18 +96,20 @@ relocate: | |||
| 99 | 96 | ||
| 100 | /* | 97 | /* |
| 101 | * Load trampoline page directory, which will cause us to trap to | 98 | * Load trampoline page directory, which will cause us to trap to |
| 102 | * stvec if VA != PA, or simply fall through if VA == PA | 99 | * stvec if VA != PA, or simply fall through if VA == PA. We need a |
| 100 | * full fence here because setup_vm() just wrote these PTEs and we need | ||
| 101 | * to ensure the new translations are in use. | ||
| 103 | */ | 102 | */ |
| 104 | la a0, trampoline_pg_dir | 103 | la a0, trampoline_pg_dir |
| 105 | srl a0, a0, PAGE_SHIFT | 104 | srl a0, a0, PAGE_SHIFT |
| 106 | or a0, a0, a1 | 105 | or a0, a0, a1 |
| 107 | sfence.vma | 106 | sfence.vma |
| 108 | csrw sptbr, a0 | 107 | csrw CSR_SATP, a0 |
| 109 | .align 2 | 108 | .align 2 |
| 110 | 1: | 109 | 1: |
| 111 | /* Set trap vector to spin forever to help debug */ | 110 | /* Set trap vector to spin forever to help debug */ |
| 112 | la a0, .Lsecondary_park | 111 | la a0, .Lsecondary_park |
| 113 | csrw stvec, a0 | 112 | csrw CSR_STVEC, a0 |
| 114 | 113 | ||
| 115 | /* Reload the global pointer */ | 114 | /* Reload the global pointer */ |
| 116 | .option push | 115 | .option push |
| @@ -118,8 +117,14 @@ relocate: | |||
| 118 | la gp, __global_pointer$ | 117 | la gp, __global_pointer$ |
| 119 | .option pop | 118 | .option pop |
| 120 | 119 | ||
| 121 | /* Switch to kernel page tables */ | 120 | /* |
| 122 | csrw sptbr, a2 | 121 | * Switch to kernel page tables. A full fence is necessary in order to |
| 122 | * avoid using the trampoline translations, which are only correct for | ||
| 123 | * the first superpage. Fetching the fence is guarnteed to work | ||
| 124 | * because that first superpage is translated the same way. | ||
| 125 | */ | ||
| 126 | csrw CSR_SATP, a2 | ||
| 127 | sfence.vma | ||
| 123 | 128 | ||
| 124 | ret | 129 | ret |
| 125 | 130 | ||
| @@ -130,7 +135,7 @@ relocate: | |||
| 130 | 135 | ||
| 131 | /* Set trap vector to spin forever to help debug */ | 136 | /* Set trap vector to spin forever to help debug */ |
| 132 | la a3, .Lsecondary_park | 137 | la a3, .Lsecondary_park |
| 133 | csrw stvec, a3 | 138 | csrw CSR_STVEC, a3 |
| 134 | 139 | ||
| 135 | slli a3, a0, LGREG | 140 | slli a3, a0, LGREG |
| 136 | la a1, __cpu_up_stack_pointer | 141 | la a1, __cpu_up_stack_pointer |
diff --git a/arch/riscv/kernel/irq.c b/arch/riscv/kernel/irq.c index 48e6b7db83a1..6d8659388c49 100644 --- a/arch/riscv/kernel/irq.c +++ b/arch/riscv/kernel/irq.c | |||
| @@ -14,17 +14,9 @@ | |||
| 14 | /* | 14 | /* |
| 15 | * Possible interrupt causes: | 15 | * Possible interrupt causes: |
| 16 | */ | 16 | */ |
| 17 | #define INTERRUPT_CAUSE_SOFTWARE 1 | 17 | #define INTERRUPT_CAUSE_SOFTWARE IRQ_S_SOFT |
| 18 | #define INTERRUPT_CAUSE_TIMER 5 | 18 | #define INTERRUPT_CAUSE_TIMER IRQ_S_TIMER |
| 19 | #define INTERRUPT_CAUSE_EXTERNAL 9 | 19 | #define INTERRUPT_CAUSE_EXTERNAL IRQ_S_EXT |
| 20 | |||
| 21 | /* | ||
| 22 | * The high order bit of the trap cause register is always set for | ||
| 23 | * interrupts, which allows us to differentiate them from exceptions | ||
| 24 | * quickly. The INTERRUPT_CAUSE_* macros don't contain that bit, so we | ||
| 25 | * need to mask it off. | ||
| 26 | */ | ||
| 27 | #define INTERRUPT_CAUSE_FLAG (1UL << (__riscv_xlen - 1)) | ||
| 28 | 20 | ||
| 29 | int arch_show_interrupts(struct seq_file *p, int prec) | 21 | int arch_show_interrupts(struct seq_file *p, int prec) |
| 30 | { | 22 | { |
| @@ -37,7 +29,7 @@ asmlinkage void __irq_entry do_IRQ(struct pt_regs *regs) | |||
| 37 | struct pt_regs *old_regs = set_irq_regs(regs); | 29 | struct pt_regs *old_regs = set_irq_regs(regs); |
| 38 | 30 | ||
| 39 | irq_enter(); | 31 | irq_enter(); |
| 40 | switch (regs->scause & ~INTERRUPT_CAUSE_FLAG) { | 32 | switch (regs->scause & ~SCAUSE_IRQ_FLAG) { |
| 41 | case INTERRUPT_CAUSE_TIMER: | 33 | case INTERRUPT_CAUSE_TIMER: |
| 42 | riscv_timer_interrupt(); | 34 | riscv_timer_interrupt(); |
| 43 | break; | 35 | break; |
| @@ -54,7 +46,8 @@ asmlinkage void __irq_entry do_IRQ(struct pt_regs *regs) | |||
| 54 | handle_arch_irq(regs); | 46 | handle_arch_irq(regs); |
| 55 | break; | 47 | break; |
| 56 | default: | 48 | default: |
| 57 | panic("unexpected interrupt cause"); | 49 | pr_alert("unexpected interrupt cause 0x%lx", regs->scause); |
| 50 | BUG(); | ||
| 58 | } | 51 | } |
| 59 | irq_exit(); | 52 | irq_exit(); |
| 60 | 53 | ||
diff --git a/arch/riscv/kernel/perf_event.c b/arch/riscv/kernel/perf_event.c index 667ee70defea..91626d9ae5f2 100644 --- a/arch/riscv/kernel/perf_event.c +++ b/arch/riscv/kernel/perf_event.c | |||
| @@ -185,10 +185,10 @@ static inline u64 read_counter(int idx) | |||
| 185 | 185 | ||
| 186 | switch (idx) { | 186 | switch (idx) { |
| 187 | case RISCV_PMU_CYCLE: | 187 | case RISCV_PMU_CYCLE: |
| 188 | val = csr_read(cycle); | 188 | val = csr_read(CSR_CYCLE); |
| 189 | break; | 189 | break; |
| 190 | case RISCV_PMU_INSTRET: | 190 | case RISCV_PMU_INSTRET: |
| 191 | val = csr_read(instret); | 191 | val = csr_read(CSR_INSTRET); |
| 192 | break; | 192 | break; |
| 193 | default: | 193 | default: |
| 194 | WARN_ON_ONCE(idx < 0 || idx > RISCV_MAX_COUNTERS); | 194 | WARN_ON_ONCE(idx < 0 || idx > RISCV_MAX_COUNTERS); |
diff --git a/arch/riscv/kernel/reset.c b/arch/riscv/kernel/reset.c index 2a53d26ffdd6..ed637aee514b 100644 --- a/arch/riscv/kernel/reset.c +++ b/arch/riscv/kernel/reset.c | |||
| @@ -12,11 +12,15 @@ | |||
| 12 | */ | 12 | */ |
| 13 | 13 | ||
| 14 | #include <linux/reboot.h> | 14 | #include <linux/reboot.h> |
| 15 | #include <linux/export.h> | ||
| 16 | #include <asm/sbi.h> | 15 | #include <asm/sbi.h> |
| 17 | 16 | ||
| 18 | void (*pm_power_off)(void) = machine_power_off; | 17 | static void default_power_off(void) |
| 19 | EXPORT_SYMBOL(pm_power_off); | 18 | { |
| 19 | sbi_shutdown(); | ||
| 20 | while (1); | ||
| 21 | } | ||
| 22 | |||
| 23 | void (*pm_power_off)(void) = default_power_off; | ||
| 20 | 24 | ||
| 21 | void machine_restart(char *cmd) | 25 | void machine_restart(char *cmd) |
| 22 | { | 26 | { |
| @@ -26,11 +30,10 @@ void machine_restart(char *cmd) | |||
| 26 | 30 | ||
| 27 | void machine_halt(void) | 31 | void machine_halt(void) |
| 28 | { | 32 | { |
| 29 | machine_power_off(); | 33 | pm_power_off(); |
| 30 | } | 34 | } |
| 31 | 35 | ||
| 32 | void machine_power_off(void) | 36 | void machine_power_off(void) |
| 33 | { | 37 | { |
| 34 | sbi_shutdown(); | 38 | pm_power_off(); |
| 35 | while (1); | ||
| 36 | } | 39 | } |
diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c index 540a331d1376..d93bcce004e3 100644 --- a/arch/riscv/kernel/setup.c +++ b/arch/riscv/kernel/setup.c | |||
| @@ -52,9 +52,11 @@ struct screen_info screen_info = { | |||
| 52 | atomic_t hart_lottery; | 52 | atomic_t hart_lottery; |
| 53 | unsigned long boot_cpu_hartid; | 53 | unsigned long boot_cpu_hartid; |
| 54 | 54 | ||
| 55 | void __init parse_dtb(unsigned int hartid, void *dtb) | 55 | void __init parse_dtb(phys_addr_t dtb_phys) |
| 56 | { | 56 | { |
| 57 | if (early_init_dt_scan(__va(dtb))) | 57 | void *dtb = __va(dtb_phys); |
| 58 | |||
| 59 | if (early_init_dt_scan(dtb)) | ||
| 58 | return; | 60 | return; |
| 59 | 61 | ||
| 60 | pr_err("No DTB passed to the kernel\n"); | 62 | pr_err("No DTB passed to the kernel\n"); |
diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index 837e1646091a..804d6ee4f3c5 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c | |||
| @@ -234,6 +234,9 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) | |||
| 234 | 234 | ||
| 235 | /* Are we from a system call? */ | 235 | /* Are we from a system call? */ |
| 236 | if (regs->scause == EXC_SYSCALL) { | 236 | if (regs->scause == EXC_SYSCALL) { |
| 237 | /* Avoid additional syscall restarting via ret_from_exception */ | ||
| 238 | regs->scause = -1UL; | ||
| 239 | |||
| 237 | /* If so, check system call restarting.. */ | 240 | /* If so, check system call restarting.. */ |
| 238 | switch (regs->a0) { | 241 | switch (regs->a0) { |
| 239 | case -ERESTART_RESTARTBLOCK: | 242 | case -ERESTART_RESTARTBLOCK: |
| @@ -272,6 +275,9 @@ static void do_signal(struct pt_regs *regs) | |||
| 272 | 275 | ||
| 273 | /* Did we come from a system call? */ | 276 | /* Did we come from a system call? */ |
| 274 | if (regs->scause == EXC_SYSCALL) { | 277 | if (regs->scause == EXC_SYSCALL) { |
| 278 | /* Avoid additional syscall restarting via ret_from_exception */ | ||
| 279 | regs->scause = -1UL; | ||
| 280 | |||
| 275 | /* Restart the system call - no handlers present */ | 281 | /* Restart the system call - no handlers present */ |
| 276 | switch (regs->a0) { | 282 | switch (regs->a0) { |
| 277 | case -ERESTARTNOHAND: | 283 | case -ERESTARTNOHAND: |
diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c index 0c41d07ec281..b2537ffa855c 100644 --- a/arch/riscv/kernel/smp.c +++ b/arch/riscv/kernel/smp.c | |||
| @@ -42,7 +42,7 @@ unsigned long __cpuid_to_hartid_map[NR_CPUS] = { | |||
| 42 | 42 | ||
| 43 | void __init smp_setup_processor_id(void) | 43 | void __init smp_setup_processor_id(void) |
| 44 | { | 44 | { |
| 45 | cpuid_to_hartid_map(0) = boot_cpu_hartid; | 45 | cpuid_to_hartid_map(0) = boot_cpu_hartid; |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | /* A collection of single bit ipi messages. */ | 48 | /* A collection of single bit ipi messages. */ |
| @@ -53,7 +53,7 @@ static struct { | |||
| 53 | 53 | ||
| 54 | int riscv_hartid_to_cpuid(int hartid) | 54 | int riscv_hartid_to_cpuid(int hartid) |
| 55 | { | 55 | { |
| 56 | int i = -1; | 56 | int i; |
| 57 | 57 | ||
| 58 | for (i = 0; i < NR_CPUS; i++) | 58 | for (i = 0; i < NR_CPUS; i++) |
| 59 | if (cpuid_to_hartid_map(i) == hartid) | 59 | if (cpuid_to_hartid_map(i) == hartid) |
| @@ -70,6 +70,12 @@ void riscv_cpuid_to_hartid_mask(const struct cpumask *in, struct cpumask *out) | |||
| 70 | for_each_cpu(cpu, in) | 70 | for_each_cpu(cpu, in) |
| 71 | cpumask_set_cpu(cpuid_to_hartid_map(cpu), out); | 71 | cpumask_set_cpu(cpuid_to_hartid_map(cpu), out); |
| 72 | } | 72 | } |
| 73 | |||
| 74 | bool arch_match_cpu_phys_id(int cpu, u64 phys_id) | ||
| 75 | { | ||
| 76 | return phys_id == cpuid_to_hartid_map(cpu); | ||
| 77 | } | ||
| 78 | |||
| 73 | /* Unsupported */ | 79 | /* Unsupported */ |
| 74 | int setup_profiling_timer(unsigned int multiplier) | 80 | int setup_profiling_timer(unsigned int multiplier) |
| 75 | { | 81 | { |
| @@ -89,7 +95,7 @@ void riscv_software_interrupt(void) | |||
| 89 | unsigned long *stats = ipi_data[smp_processor_id()].stats; | 95 | unsigned long *stats = ipi_data[smp_processor_id()].stats; |
| 90 | 96 | ||
| 91 | /* Clear pending IPI */ | 97 | /* Clear pending IPI */ |
| 92 | csr_clear(sip, SIE_SSIE); | 98 | csr_clear(CSR_SIP, SIE_SSIE); |
| 93 | 99 | ||
| 94 | while (true) { | 100 | while (true) { |
| 95 | unsigned long ops; | 101 | unsigned long ops; |
| @@ -199,52 +205,3 @@ void smp_send_reschedule(int cpu) | |||
| 199 | send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); | 205 | send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); |
| 200 | } | 206 | } |
| 201 | 207 | ||
| 202 | /* | ||
| 203 | * Performs an icache flush for the given MM context. RISC-V has no direct | ||
| 204 | * mechanism for instruction cache shoot downs, so instead we send an IPI that | ||
| 205 | * informs the remote harts they need to flush their local instruction caches. | ||
| 206 | * To avoid pathologically slow behavior in a common case (a bunch of | ||
| 207 | * single-hart processes on a many-hart machine, ie 'make -j') we avoid the | ||
| 208 | * IPIs for harts that are not currently executing a MM context and instead | ||
| 209 | * schedule a deferred local instruction cache flush to be performed before | ||
| 210 | * execution resumes on each hart. | ||
| 211 | */ | ||
| 212 | void flush_icache_mm(struct mm_struct *mm, bool local) | ||
| 213 | { | ||
| 214 | unsigned int cpu; | ||
| 215 | cpumask_t others, hmask, *mask; | ||
| 216 | |||
| 217 | preempt_disable(); | ||
| 218 | |||
| 219 | /* Mark every hart's icache as needing a flush for this MM. */ | ||
| 220 | mask = &mm->context.icache_stale_mask; | ||
| 221 | cpumask_setall(mask); | ||
| 222 | /* Flush this hart's I$ now, and mark it as flushed. */ | ||
| 223 | cpu = smp_processor_id(); | ||
| 224 | cpumask_clear_cpu(cpu, mask); | ||
| 225 | local_flush_icache_all(); | ||
| 226 | |||
| 227 | /* | ||
| 228 | * Flush the I$ of other harts concurrently executing, and mark them as | ||
| 229 | * flushed. | ||
| 230 | */ | ||
| 231 | cpumask_andnot(&others, mm_cpumask(mm), cpumask_of(cpu)); | ||
| 232 | local |= cpumask_empty(&others); | ||
| 233 | if (mm != current->active_mm || !local) { | ||
| 234 | cpumask_clear(&hmask); | ||
| 235 | riscv_cpuid_to_hartid_mask(&others, &hmask); | ||
| 236 | sbi_remote_fence_i(hmask.bits); | ||
| 237 | } else { | ||
| 238 | /* | ||
| 239 | * It's assumed that at least one strongly ordered operation is | ||
| 240 | * performed on this hart between setting a hart's cpumask bit | ||
| 241 | * and scheduling this MM context on that hart. Sending an SBI | ||
| 242 | * remote message will do this, but in the case where no | ||
| 243 | * messages are sent we still need to order this hart's writes | ||
| 244 | * with flush_icache_deferred(). | ||
| 245 | */ | ||
| 246 | smp_mb(); | ||
| 247 | } | ||
| 248 | |||
| 249 | preempt_enable(); | ||
| 250 | } | ||
diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c index eb533b5c2c8c..7a0b62252524 100644 --- a/arch/riscv/kernel/smpboot.c +++ b/arch/riscv/kernel/smpboot.c | |||
| @@ -47,6 +47,17 @@ void __init smp_prepare_boot_cpu(void) | |||
| 47 | 47 | ||
| 48 | void __init smp_prepare_cpus(unsigned int max_cpus) | 48 | void __init smp_prepare_cpus(unsigned int max_cpus) |
| 49 | { | 49 | { |
| 50 | int cpuid; | ||
| 51 | |||
| 52 | /* This covers non-smp usecase mandated by "nosmp" option */ | ||
| 53 | if (max_cpus == 0) | ||
| 54 | return; | ||
| 55 | |||
| 56 | for_each_possible_cpu(cpuid) { | ||
| 57 | if (cpuid == smp_processor_id()) | ||
| 58 | continue; | ||
| 59 | set_cpu_present(cpuid, true); | ||
| 60 | } | ||
| 50 | } | 61 | } |
| 51 | 62 | ||
| 52 | void __init setup_smp(void) | 63 | void __init setup_smp(void) |
| @@ -73,12 +84,19 @@ void __init setup_smp(void) | |||
| 73 | } | 84 | } |
| 74 | 85 | ||
| 75 | cpuid_to_hartid_map(cpuid) = hart; | 86 | cpuid_to_hartid_map(cpuid) = hart; |
| 76 | set_cpu_possible(cpuid, true); | ||
| 77 | set_cpu_present(cpuid, true); | ||
| 78 | cpuid++; | 87 | cpuid++; |
| 79 | } | 88 | } |
| 80 | 89 | ||
| 81 | BUG_ON(!found_boot_cpu); | 90 | BUG_ON(!found_boot_cpu); |
| 91 | |||
| 92 | if (cpuid > nr_cpu_ids) | ||
| 93 | pr_warn("Total number of cpus [%d] is greater than nr_cpus option value [%d]\n", | ||
| 94 | cpuid, nr_cpu_ids); | ||
| 95 | |||
| 96 | for (cpuid = 1; cpuid < nr_cpu_ids; cpuid++) { | ||
| 97 | if (cpuid_to_hartid_map(cpuid) != INVALID_HARTID) | ||
| 98 | set_cpu_possible(cpuid, true); | ||
| 99 | } | ||
| 82 | } | 100 | } |
| 83 | 101 | ||
| 84 | int __cpu_up(unsigned int cpu, struct task_struct *tidle) | 102 | int __cpu_up(unsigned int cpu, struct task_struct *tidle) |
diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c index 4d403274c2e8..e80a5e8da119 100644 --- a/arch/riscv/kernel/stacktrace.c +++ b/arch/riscv/kernel/stacktrace.c | |||
| @@ -33,9 +33,9 @@ static void notrace walk_stackframe(struct task_struct *task, | |||
| 33 | unsigned long fp, sp, pc; | 33 | unsigned long fp, sp, pc; |
| 34 | 34 | ||
| 35 | if (regs) { | 35 | if (regs) { |
| 36 | fp = GET_FP(regs); | 36 | fp = frame_pointer(regs); |
| 37 | sp = GET_USP(regs); | 37 | sp = user_stack_pointer(regs); |
| 38 | pc = GET_IP(regs); | 38 | pc = instruction_pointer(regs); |
| 39 | } else if (task == NULL || task == current) { | 39 | } else if (task == NULL || task == current) { |
| 40 | const register unsigned long current_sp __asm__ ("sp"); | 40 | const register unsigned long current_sp __asm__ ("sp"); |
| 41 | fp = (unsigned long)__builtin_frame_address(0); | 41 | fp = (unsigned long)__builtin_frame_address(0); |
| @@ -64,12 +64,8 @@ static void notrace walk_stackframe(struct task_struct *task, | |||
| 64 | frame = (struct stackframe *)fp - 1; | 64 | frame = (struct stackframe *)fp - 1; |
| 65 | sp = fp; | 65 | sp = fp; |
| 66 | fp = frame->fp; | 66 | fp = frame->fp; |
| 67 | #ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR | ||
| 68 | pc = ftrace_graph_ret_addr(current, NULL, frame->ra, | 67 | pc = ftrace_graph_ret_addr(current, NULL, frame->ra, |
| 69 | (unsigned long *)(fp - 8)); | 68 | (unsigned long *)(fp - 8)); |
| 70 | #else | ||
| 71 | pc = frame->ra - 0x4; | ||
| 72 | #endif | ||
| 73 | } | 69 | } |
| 74 | } | 70 | } |
| 75 | 71 | ||
| @@ -82,8 +78,8 @@ static void notrace walk_stackframe(struct task_struct *task, | |||
| 82 | unsigned long *ksp; | 78 | unsigned long *ksp; |
| 83 | 79 | ||
| 84 | if (regs) { | 80 | if (regs) { |
| 85 | sp = GET_USP(regs); | 81 | sp = user_stack_pointer(regs); |
| 86 | pc = GET_IP(regs); | 82 | pc = instruction_pointer(regs); |
| 87 | } else if (task == NULL || task == current) { | 83 | } else if (task == NULL || task == current) { |
| 88 | const register unsigned long current_sp __asm__ ("sp"); | 84 | const register unsigned long current_sp __asm__ ("sp"); |
| 89 | sp = current_sp; | 85 | sp = current_sp; |
diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c index 24a9333dda2c..3d1a651dc54c 100644 --- a/arch/riscv/kernel/traps.c +++ b/arch/riscv/kernel/traps.c | |||
| @@ -70,7 +70,7 @@ void do_trap(struct pt_regs *regs, int signo, int code, | |||
| 70 | && printk_ratelimit()) { | 70 | && printk_ratelimit()) { |
| 71 | pr_info("%s[%d]: unhandled signal %d code 0x%x at 0x" REG_FMT, | 71 | pr_info("%s[%d]: unhandled signal %d code 0x%x at 0x" REG_FMT, |
| 72 | tsk->comm, task_pid_nr(tsk), signo, code, addr); | 72 | tsk->comm, task_pid_nr(tsk), signo, code, addr); |
| 73 | print_vma_addr(KERN_CONT " in ", GET_IP(regs)); | 73 | print_vma_addr(KERN_CONT " in ", instruction_pointer(regs)); |
| 74 | pr_cont("\n"); | 74 | pr_cont("\n"); |
| 75 | show_regs(regs); | 75 | show_regs(regs); |
| 76 | } | 76 | } |
| @@ -118,6 +118,17 @@ DO_ERROR_INFO(do_trap_ecall_s, | |||
| 118 | DO_ERROR_INFO(do_trap_ecall_m, | 118 | DO_ERROR_INFO(do_trap_ecall_m, |
| 119 | SIGILL, ILL_ILLTRP, "environment call from M-mode"); | 119 | SIGILL, ILL_ILLTRP, "environment call from M-mode"); |
| 120 | 120 | ||
| 121 | #ifdef CONFIG_GENERIC_BUG | ||
| 122 | static inline unsigned long get_break_insn_length(unsigned long pc) | ||
| 123 | { | ||
| 124 | bug_insn_t insn; | ||
| 125 | |||
| 126 | if (probe_kernel_address((bug_insn_t *)pc, insn)) | ||
| 127 | return 0; | ||
| 128 | return (((insn & __INSN_LENGTH_MASK) == __INSN_LENGTH_32) ? 4UL : 2UL); | ||
| 129 | } | ||
| 130 | #endif /* CONFIG_GENERIC_BUG */ | ||
| 131 | |||
| 121 | asmlinkage void do_trap_break(struct pt_regs *regs) | 132 | asmlinkage void do_trap_break(struct pt_regs *regs) |
| 122 | { | 133 | { |
| 123 | #ifdef CONFIG_GENERIC_BUG | 134 | #ifdef CONFIG_GENERIC_BUG |
| @@ -129,8 +140,8 @@ asmlinkage void do_trap_break(struct pt_regs *regs) | |||
| 129 | case BUG_TRAP_TYPE_NONE: | 140 | case BUG_TRAP_TYPE_NONE: |
| 130 | break; | 141 | break; |
| 131 | case BUG_TRAP_TYPE_WARN: | 142 | case BUG_TRAP_TYPE_WARN: |
| 132 | regs->sepc += sizeof(bug_insn_t); | 143 | regs->sepc += get_break_insn_length(regs->sepc); |
| 133 | return; | 144 | break; |
| 134 | case BUG_TRAP_TYPE_BUG: | 145 | case BUG_TRAP_TYPE_BUG: |
| 135 | die(regs, "Kernel BUG"); | 146 | die(regs, "Kernel BUG"); |
| 136 | } | 147 | } |
| @@ -145,11 +156,14 @@ int is_valid_bugaddr(unsigned long pc) | |||
| 145 | { | 156 | { |
| 146 | bug_insn_t insn; | 157 | bug_insn_t insn; |
| 147 | 158 | ||
| 148 | if (pc < PAGE_OFFSET) | 159 | if (pc < VMALLOC_START) |
| 149 | return 0; | 160 | return 0; |
| 150 | if (probe_kernel_address((bug_insn_t *)pc, insn)) | 161 | if (probe_kernel_address((bug_insn_t *)pc, insn)) |
| 151 | return 0; | 162 | return 0; |
| 152 | return (insn == __BUG_INSN); | 163 | if ((insn & __INSN_LENGTH_MASK) == __INSN_LENGTH_32) |
| 164 | return (insn == __BUG_INSN_32); | ||
| 165 | else | ||
| 166 | return ((insn & __COMPRESSED_INSN_MASK) == __BUG_INSN_16); | ||
| 153 | } | 167 | } |
| 154 | #endif /* CONFIG_GENERIC_BUG */ | 168 | #endif /* CONFIG_GENERIC_BUG */ |
| 155 | 169 | ||
| @@ -159,9 +173,9 @@ void __init trap_init(void) | |||
| 159 | * Set sup0 scratch register to 0, indicating to exception vector | 173 | * Set sup0 scratch register to 0, indicating to exception vector |
| 160 | * that we are presently executing in the kernel | 174 | * that we are presently executing in the kernel |
| 161 | */ | 175 | */ |
| 162 | csr_write(sscratch, 0); | 176 | csr_write(CSR_SSCRATCH, 0); |
| 163 | /* Set the exception vector address */ | 177 | /* Set the exception vector address */ |
| 164 | csr_write(stvec, &handle_exception); | 178 | csr_write(CSR_STVEC, &handle_exception); |
| 165 | /* Enable all interrupts */ | 179 | /* Enable all interrupts */ |
| 166 | csr_write(sie, -1); | 180 | csr_write(CSR_SIE, -1); |
| 167 | } | 181 | } |
diff --git a/arch/riscv/kernel/vdso/Makefile b/arch/riscv/kernel/vdso/Makefile index fec62b24df89..b07b765f312a 100644 --- a/arch/riscv/kernel/vdso/Makefile +++ b/arch/riscv/kernel/vdso/Makefile | |||
| @@ -36,7 +36,7 @@ $(obj)/vdso.so.dbg: $(src)/vdso.lds $(obj-vdso) FORCE | |||
| 36 | # these symbols in the kernel code rather than hand-coded addresses. | 36 | # these symbols in the kernel code rather than hand-coded addresses. |
| 37 | 37 | ||
| 38 | SYSCFLAGS_vdso.so.dbg = -shared -s -Wl,-soname=linux-vdso.so.1 \ | 38 | SYSCFLAGS_vdso.so.dbg = -shared -s -Wl,-soname=linux-vdso.so.1 \ |
| 39 | $(call cc-ldoption, -Wl$(comma)--hash-style=both) | 39 | -Wl,--hash-style=both |
| 40 | $(obj)/vdso-dummy.o: $(src)/vdso.lds $(obj)/rt_sigreturn.o FORCE | 40 | $(obj)/vdso-dummy.o: $(src)/vdso.lds $(obj)/rt_sigreturn.o FORCE |
| 41 | $(call if_changed,vdsold) | 41 | $(call if_changed,vdsold) |
| 42 | 42 | ||
diff --git a/arch/riscv/mm/Makefile b/arch/riscv/mm/Makefile index b68aac701803..8db569141485 100644 --- a/arch/riscv/mm/Makefile +++ b/arch/riscv/mm/Makefile | |||
| @@ -9,3 +9,5 @@ obj-y += fault.o | |||
| 9 | obj-y += extable.o | 9 | obj-y += extable.o |
| 10 | obj-y += ioremap.o | 10 | obj-y += ioremap.o |
| 11 | obj-y += cacheflush.o | 11 | obj-y += cacheflush.o |
| 12 | obj-y += context.o | ||
| 13 | obj-y += sifive_l2_cache.o | ||
diff --git a/arch/riscv/mm/cacheflush.c b/arch/riscv/mm/cacheflush.c index 498c0a0814fe..497b7d07af0c 100644 --- a/arch/riscv/mm/cacheflush.c +++ b/arch/riscv/mm/cacheflush.c | |||
| @@ -14,6 +14,67 @@ | |||
| 14 | #include <asm/pgtable.h> | 14 | #include <asm/pgtable.h> |
| 15 | #include <asm/cacheflush.h> | 15 | #include <asm/cacheflush.h> |
| 16 | 16 | ||
| 17 | #ifdef CONFIG_SMP | ||
| 18 | |||
| 19 | #include <asm/sbi.h> | ||
| 20 | |||
| 21 | void flush_icache_all(void) | ||
| 22 | { | ||
| 23 | sbi_remote_fence_i(NULL); | ||
| 24 | } | ||
| 25 | |||
| 26 | /* | ||
| 27 | * Performs an icache flush for the given MM context. RISC-V has no direct | ||
| 28 | * mechanism for instruction cache shoot downs, so instead we send an IPI that | ||
| 29 | * informs the remote harts they need to flush their local instruction caches. | ||
| 30 | * To avoid pathologically slow behavior in a common case (a bunch of | ||
| 31 | * single-hart processes on a many-hart machine, ie 'make -j') we avoid the | ||
| 32 | * IPIs for harts that are not currently executing a MM context and instead | ||
| 33 | * schedule a deferred local instruction cache flush to be performed before | ||
| 34 | * execution resumes on each hart. | ||
| 35 | */ | ||
| 36 | void flush_icache_mm(struct mm_struct *mm, bool local) | ||
| 37 | { | ||
| 38 | unsigned int cpu; | ||
| 39 | cpumask_t others, hmask, *mask; | ||
| 40 | |||
| 41 | preempt_disable(); | ||
| 42 | |||
| 43 | /* Mark every hart's icache as needing a flush for this MM. */ | ||
| 44 | mask = &mm->context.icache_stale_mask; | ||
| 45 | cpumask_setall(mask); | ||
| 46 | /* Flush this hart's I$ now, and mark it as flushed. */ | ||
| 47 | cpu = smp_processor_id(); | ||
| 48 | cpumask_clear_cpu(cpu, mask); | ||
| 49 | local_flush_icache_all(); | ||
| 50 | |||
| 51 | /* | ||
| 52 | * Flush the I$ of other harts concurrently executing, and mark them as | ||
| 53 | * flushed. | ||
| 54 | */ | ||
| 55 | cpumask_andnot(&others, mm_cpumask(mm), cpumask_of(cpu)); | ||
| 56 | local |= cpumask_empty(&others); | ||
| 57 | if (mm != current->active_mm || !local) { | ||
| 58 | cpumask_clear(&hmask); | ||
| 59 | riscv_cpuid_to_hartid_mask(&others, &hmask); | ||
| 60 | sbi_remote_fence_i(hmask.bits); | ||
| 61 | } else { | ||
| 62 | /* | ||
| 63 | * It's assumed that at least one strongly ordered operation is | ||
| 64 | * performed on this hart between setting a hart's cpumask bit | ||
| 65 | * and scheduling this MM context on that hart. Sending an SBI | ||
| 66 | * remote message will do this, but in the case where no | ||
| 67 | * messages are sent we still need to order this hart's writes | ||
| 68 | * with flush_icache_deferred(). | ||
| 69 | */ | ||
| 70 | smp_mb(); | ||
| 71 | } | ||
| 72 | |||
| 73 | preempt_enable(); | ||
| 74 | } | ||
| 75 | |||
| 76 | #endif /* CONFIG_SMP */ | ||
| 77 | |||
| 17 | void flush_icache_pte(pte_t pte) | 78 | void flush_icache_pte(pte_t pte) |
| 18 | { | 79 | { |
| 19 | struct page *page = pte_page(pte); | 80 | struct page *page = pte_page(pte); |
diff --git a/arch/riscv/mm/context.c b/arch/riscv/mm/context.c new file mode 100644 index 000000000000..89ceb3cbe218 --- /dev/null +++ b/arch/riscv/mm/context.c | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Copyright (C) 2012 Regents of the University of California | ||
| 4 | * Copyright (C) 2017 SiFive | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <linux/mm.h> | ||
| 8 | #include <asm/tlbflush.h> | ||
| 9 | #include <asm/cacheflush.h> | ||
| 10 | |||
| 11 | /* | ||
| 12 | * When necessary, performs a deferred icache flush for the given MM context, | ||
| 13 | * on the local CPU. RISC-V has no direct mechanism for instruction cache | ||
| 14 | * shoot downs, so instead we send an IPI that informs the remote harts they | ||
| 15 | * need to flush their local instruction caches. To avoid pathologically slow | ||
| 16 | * behavior in a common case (a bunch of single-hart processes on a many-hart | ||
| 17 | * machine, ie 'make -j') we avoid the IPIs for harts that are not currently | ||
| 18 | * executing a MM context and instead schedule a deferred local instruction | ||
| 19 | * cache flush to be performed before execution resumes on each hart. This | ||
| 20 | * actually performs that local instruction cache flush, which implicitly only | ||
| 21 | * refers to the current hart. | ||
| 22 | */ | ||
| 23 | static inline void flush_icache_deferred(struct mm_struct *mm) | ||
| 24 | { | ||
| 25 | #ifdef CONFIG_SMP | ||
| 26 | unsigned int cpu = smp_processor_id(); | ||
| 27 | cpumask_t *mask = &mm->context.icache_stale_mask; | ||
| 28 | |||
| 29 | if (cpumask_test_cpu(cpu, mask)) { | ||
| 30 | cpumask_clear_cpu(cpu, mask); | ||
| 31 | /* | ||
| 32 | * Ensure the remote hart's writes are visible to this hart. | ||
| 33 | * This pairs with a barrier in flush_icache_mm. | ||
| 34 | */ | ||
| 35 | smp_mb(); | ||
| 36 | local_flush_icache_all(); | ||
| 37 | } | ||
| 38 | |||
| 39 | #endif | ||
| 40 | } | ||
| 41 | |||
| 42 | void switch_mm(struct mm_struct *prev, struct mm_struct *next, | ||
| 43 | struct task_struct *task) | ||
| 44 | { | ||
| 45 | unsigned int cpu; | ||
| 46 | |||
| 47 | if (unlikely(prev == next)) | ||
| 48 | return; | ||
| 49 | |||
| 50 | /* | ||
| 51 | * Mark the current MM context as inactive, and the next as | ||
| 52 | * active. This is at least used by the icache flushing | ||
| 53 | * routines in order to determine who should be flushed. | ||
| 54 | */ | ||
| 55 | cpu = smp_processor_id(); | ||
| 56 | |||
| 57 | cpumask_clear_cpu(cpu, mm_cpumask(prev)); | ||
| 58 | cpumask_set_cpu(cpu, mm_cpumask(next)); | ||
| 59 | |||
| 60 | /* | ||
| 61 | * Use the old spbtr name instead of using the current satp | ||
| 62 | * name to support binutils 2.29 which doesn't know about the | ||
| 63 | * privileged ISA 1.10 yet. | ||
| 64 | */ | ||
| 65 | csr_write(sptbr, virt_to_pfn(next->pgd) | SATP_MODE); | ||
| 66 | local_flush_tlb_all(); | ||
| 67 | |||
| 68 | flush_icache_deferred(next); | ||
| 69 | } | ||
diff --git a/arch/riscv/mm/fault.c b/arch/riscv/mm/fault.c index 88401d5125bc..cec8be9e2d6a 100644 --- a/arch/riscv/mm/fault.c +++ b/arch/riscv/mm/fault.c | |||
| @@ -229,8 +229,9 @@ vmalloc_fault: | |||
| 229 | pte_t *pte_k; | 229 | pte_t *pte_k; |
| 230 | int index; | 230 | int index; |
| 231 | 231 | ||
| 232 | /* User mode accesses just cause a SIGSEGV */ | ||
| 232 | if (user_mode(regs)) | 233 | if (user_mode(regs)) |
| 233 | goto bad_area; | 234 | return do_trap(regs, SIGSEGV, code, addr, tsk); |
| 234 | 235 | ||
| 235 | /* | 236 | /* |
| 236 | * Synchronize this task's top level page-table | 237 | * Synchronize this task's top level page-table |
| @@ -239,13 +240,9 @@ vmalloc_fault: | |||
| 239 | * Do _not_ use "tsk->active_mm->pgd" here. | 240 | * Do _not_ use "tsk->active_mm->pgd" here. |
| 240 | * We might be inside an interrupt in the middle | 241 | * We might be inside an interrupt in the middle |
| 241 | * of a task switch. | 242 | * of a task switch. |
| 242 | * | ||
| 243 | * Note: Use the old spbtr name instead of using the current | ||
| 244 | * satp name to support binutils 2.29 which doesn't know about | ||
| 245 | * the privileged ISA 1.10 yet. | ||
| 246 | */ | 243 | */ |
| 247 | index = pgd_index(addr); | 244 | index = pgd_index(addr); |
| 248 | pgd = (pgd_t *)pfn_to_virt(csr_read(sptbr)) + index; | 245 | pgd = (pgd_t *)pfn_to_virt(csr_read(CSR_SATP)) + index; |
| 249 | pgd_k = init_mm.pgd + index; | 246 | pgd_k = init_mm.pgd + index; |
| 250 | 247 | ||
| 251 | if (!pgd_present(*pgd_k)) | 248 | if (!pgd_present(*pgd_k)) |
diff --git a/arch/riscv/mm/sifive_l2_cache.c b/arch/riscv/mm/sifive_l2_cache.c new file mode 100644 index 000000000000..4eb64619b3f4 --- /dev/null +++ b/arch/riscv/mm/sifive_l2_cache.c | |||
| @@ -0,0 +1,175 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * SiFive L2 cache controller Driver | ||
| 4 | * | ||
| 5 | * Copyright (C) 2018-2019 SiFive, Inc. | ||
| 6 | * | ||
| 7 | */ | ||
| 8 | #include <linux/debugfs.h> | ||
| 9 | #include <linux/interrupt.h> | ||
| 10 | #include <linux/of_irq.h> | ||
| 11 | #include <linux/of_address.h> | ||
| 12 | #include <asm/sifive_l2_cache.h> | ||
| 13 | |||
| 14 | #define SIFIVE_L2_DIRECCFIX_LOW 0x100 | ||
| 15 | #define SIFIVE_L2_DIRECCFIX_HIGH 0x104 | ||
| 16 | #define SIFIVE_L2_DIRECCFIX_COUNT 0x108 | ||
| 17 | |||
| 18 | #define SIFIVE_L2_DATECCFIX_LOW 0x140 | ||
| 19 | #define SIFIVE_L2_DATECCFIX_HIGH 0x144 | ||
| 20 | #define SIFIVE_L2_DATECCFIX_COUNT 0x148 | ||
| 21 | |||
| 22 | #define SIFIVE_L2_DATECCFAIL_LOW 0x160 | ||
| 23 | #define SIFIVE_L2_DATECCFAIL_HIGH 0x164 | ||
| 24 | #define SIFIVE_L2_DATECCFAIL_COUNT 0x168 | ||
| 25 | |||
| 26 | #define SIFIVE_L2_CONFIG 0x00 | ||
| 27 | #define SIFIVE_L2_WAYENABLE 0x08 | ||
| 28 | #define SIFIVE_L2_ECCINJECTERR 0x40 | ||
| 29 | |||
| 30 | #define SIFIVE_L2_MAX_ECCINTR 3 | ||
| 31 | |||
| 32 | static void __iomem *l2_base; | ||
| 33 | static int g_irq[SIFIVE_L2_MAX_ECCINTR]; | ||
| 34 | |||
| 35 | enum { | ||
| 36 | DIR_CORR = 0, | ||
| 37 | DATA_CORR, | ||
| 38 | DATA_UNCORR, | ||
| 39 | }; | ||
| 40 | |||
| 41 | #ifdef CONFIG_DEBUG_FS | ||
| 42 | static struct dentry *sifive_test; | ||
| 43 | |||
| 44 | static ssize_t l2_write(struct file *file, const char __user *data, | ||
| 45 | size_t count, loff_t *ppos) | ||
| 46 | { | ||
| 47 | unsigned int val; | ||
| 48 | |||
| 49 | if (kstrtouint_from_user(data, count, 0, &val)) | ||
| 50 | return -EINVAL; | ||
| 51 | if ((val >= 0 && val < 0xFF) || (val >= 0x10000 && val < 0x100FF)) | ||
| 52 | writel(val, l2_base + SIFIVE_L2_ECCINJECTERR); | ||
| 53 | else | ||
| 54 | return -EINVAL; | ||
| 55 | return count; | ||
| 56 | } | ||
| 57 | |||
| 58 | static const struct file_operations l2_fops = { | ||
| 59 | .owner = THIS_MODULE, | ||
| 60 | .open = simple_open, | ||
| 61 | .write = l2_write | ||
| 62 | }; | ||
| 63 | |||
| 64 | static void setup_sifive_debug(void) | ||
| 65 | { | ||
| 66 | sifive_test = debugfs_create_dir("sifive_l2_cache", NULL); | ||
| 67 | |||
| 68 | debugfs_create_file("sifive_debug_inject_error", 0200, | ||
| 69 | sifive_test, NULL, &l2_fops); | ||
| 70 | } | ||
| 71 | #endif | ||
| 72 | |||
| 73 | static void l2_config_read(void) | ||
| 74 | { | ||
| 75 | u32 regval, val; | ||
| 76 | |||
| 77 | regval = readl(l2_base + SIFIVE_L2_CONFIG); | ||
| 78 | val = regval & 0xFF; | ||
| 79 | pr_info("L2CACHE: No. of Banks in the cache: %d\n", val); | ||
| 80 | val = (regval & 0xFF00) >> 8; | ||
| 81 | pr_info("L2CACHE: No. of ways per bank: %d\n", val); | ||
| 82 | val = (regval & 0xFF0000) >> 16; | ||
| 83 | pr_info("L2CACHE: Sets per bank: %llu\n", (uint64_t)1 << val); | ||
| 84 | val = (regval & 0xFF000000) >> 24; | ||
| 85 | pr_info("L2CACHE: Bytes per cache block: %llu\n", (uint64_t)1 << val); | ||
| 86 | |||
| 87 | regval = readl(l2_base + SIFIVE_L2_WAYENABLE); | ||
| 88 | pr_info("L2CACHE: Index of the largest way enabled: %d\n", regval); | ||
| 89 | } | ||
| 90 | |||
| 91 | static const struct of_device_id sifive_l2_ids[] = { | ||
| 92 | { .compatible = "sifive,fu540-c000-ccache" }, | ||
| 93 | { /* end of table */ }, | ||
| 94 | }; | ||
| 95 | |||
| 96 | static ATOMIC_NOTIFIER_HEAD(l2_err_chain); | ||
| 97 | |||
| 98 | int register_sifive_l2_error_notifier(struct notifier_block *nb) | ||
| 99 | { | ||
| 100 | return atomic_notifier_chain_register(&l2_err_chain, nb); | ||
| 101 | } | ||
| 102 | EXPORT_SYMBOL_GPL(register_sifive_l2_error_notifier); | ||
| 103 | |||
| 104 | int unregister_sifive_l2_error_notifier(struct notifier_block *nb) | ||
| 105 | { | ||
| 106 | return atomic_notifier_chain_unregister(&l2_err_chain, nb); | ||
| 107 | } | ||
| 108 | EXPORT_SYMBOL_GPL(unregister_sifive_l2_error_notifier); | ||
| 109 | |||
| 110 | static irqreturn_t l2_int_handler(int irq, void *device) | ||
| 111 | { | ||
| 112 | unsigned int regval, add_h, add_l; | ||
| 113 | |||
| 114 | if (irq == g_irq[DIR_CORR]) { | ||
| 115 | add_h = readl(l2_base + SIFIVE_L2_DIRECCFIX_HIGH); | ||
| 116 | add_l = readl(l2_base + SIFIVE_L2_DIRECCFIX_LOW); | ||
| 117 | pr_err("L2CACHE: DirError @ 0x%08X.%08X\n", add_h, add_l); | ||
| 118 | regval = readl(l2_base + SIFIVE_L2_DIRECCFIX_COUNT); | ||
| 119 | atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_CE, | ||
| 120 | "DirECCFix"); | ||
| 121 | } | ||
| 122 | if (irq == g_irq[DATA_CORR]) { | ||
| 123 | add_h = readl(l2_base + SIFIVE_L2_DATECCFIX_HIGH); | ||
| 124 | add_l = readl(l2_base + SIFIVE_L2_DATECCFIX_LOW); | ||
| 125 | pr_err("L2CACHE: DataError @ 0x%08X.%08X\n", add_h, add_l); | ||
| 126 | regval = readl(l2_base + SIFIVE_L2_DATECCFIX_COUNT); | ||
| 127 | atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_CE, | ||
| 128 | "DatECCFix"); | ||
| 129 | } | ||
| 130 | if (irq == g_irq[DATA_UNCORR]) { | ||
| 131 | add_h = readl(l2_base + SIFIVE_L2_DATECCFAIL_HIGH); | ||
| 132 | add_l = readl(l2_base + SIFIVE_L2_DATECCFAIL_LOW); | ||
| 133 | pr_err("L2CACHE: DataFail @ 0x%08X.%08X\n", add_h, add_l); | ||
| 134 | regval = readl(l2_base + SIFIVE_L2_DATECCFAIL_COUNT); | ||
| 135 | atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_UE, | ||
| 136 | "DatECCFail"); | ||
| 137 | } | ||
| 138 | |||
| 139 | return IRQ_HANDLED; | ||
| 140 | } | ||
| 141 | |||
| 142 | int __init sifive_l2_init(void) | ||
| 143 | { | ||
| 144 | struct device_node *np; | ||
| 145 | struct resource res; | ||
| 146 | int i, rc; | ||
| 147 | |||
| 148 | np = of_find_matching_node(NULL, sifive_l2_ids); | ||
| 149 | if (!np) | ||
| 150 | return -ENODEV; | ||
| 151 | |||
| 152 | if (of_address_to_resource(np, 0, &res)) | ||
| 153 | return -ENODEV; | ||
| 154 | |||
| 155 | l2_base = ioremap(res.start, resource_size(&res)); | ||
| 156 | if (!l2_base) | ||
| 157 | return -ENOMEM; | ||
| 158 | |||
| 159 | for (i = 0; i < SIFIVE_L2_MAX_ECCINTR; i++) { | ||
| 160 | g_irq[i] = irq_of_parse_and_map(np, i); | ||
| 161 | rc = request_irq(g_irq[i], l2_int_handler, 0, "l2_ecc", NULL); | ||
| 162 | if (rc) { | ||
| 163 | pr_err("L2CACHE: Could not request IRQ %d\n", g_irq[i]); | ||
| 164 | return rc; | ||
| 165 | } | ||
| 166 | } | ||
| 167 | |||
| 168 | l2_config_read(); | ||
| 169 | |||
| 170 | #ifdef CONFIG_DEBUG_FS | ||
| 171 | setup_sifive_debug(); | ||
| 172 | #endif | ||
| 173 | return 0; | ||
| 174 | } | ||
| 175 | device_initcall(sifive_l2_init); | ||
diff --git a/drivers/tty/hvc/hvc_riscv_sbi.c b/drivers/tty/hvc/hvc_riscv_sbi.c index 75155bde2b88..31f53fa77e4a 100644 --- a/drivers/tty/hvc/hvc_riscv_sbi.c +++ b/drivers/tty/hvc/hvc_riscv_sbi.c | |||
| @@ -53,7 +53,6 @@ device_initcall(hvc_sbi_init); | |||
| 53 | static int __init hvc_sbi_console_init(void) | 53 | static int __init hvc_sbi_console_init(void) |
| 54 | { | 54 | { |
| 55 | hvc_instantiate(0, 0, &hvc_sbi_ops); | 55 | hvc_instantiate(0, 0, &hvc_sbi_ops); |
| 56 | add_preferred_console("hvc", 0, NULL); | ||
| 57 | 56 | ||
| 58 | return 0; | 57 | return 0; |
| 59 | } | 58 | } |
