diff options
Diffstat (limited to 'arch/riscv/include/asm')
| -rw-r--r-- | arch/riscv/include/asm/Kbuild | 1 | ||||
| -rw-r--r-- | arch/riscv/include/asm/asm.h | 12 | ||||
| -rw-r--r-- | arch/riscv/include/asm/atomic.h | 103 | ||||
| -rw-r--r-- | arch/riscv/include/asm/barrier.h | 36 | ||||
| -rw-r--r-- | arch/riscv/include/asm/bitops.h | 2 | ||||
| -rw-r--r-- | arch/riscv/include/asm/bug.h | 6 | ||||
| -rw-r--r-- | arch/riscv/include/asm/cacheflush.h | 30 | ||||
| -rw-r--r-- | arch/riscv/include/asm/csr.h | 8 | ||||
| -rw-r--r-- | arch/riscv/include/asm/io.h | 20 | ||||
| -rw-r--r-- | arch/riscv/include/asm/irqflags.h | 10 | ||||
| -rw-r--r-- | arch/riscv/include/asm/mmu.h | 4 | ||||
| -rw-r--r-- | arch/riscv/include/asm/mmu_context.h | 45 | ||||
| -rw-r--r-- | arch/riscv/include/asm/pgtable.h | 62 | ||||
| -rw-r--r-- | arch/riscv/include/asm/ptrace.h | 2 | ||||
| -rw-r--r-- | arch/riscv/include/asm/spinlock.h | 11 | ||||
| -rw-r--r-- | arch/riscv/include/asm/timex.h | 3 | ||||
| -rw-r--r-- | arch/riscv/include/asm/tlbflush.h | 9 | ||||
| -rw-r--r-- | arch/riscv/include/asm/uaccess.h | 12 | ||||
| -rw-r--r-- | arch/riscv/include/asm/unistd.h | 1 | ||||
| -rw-r--r-- | arch/riscv/include/asm/vdso.h | 4 | 
20 files changed, 220 insertions, 161 deletions
diff --git a/arch/riscv/include/asm/Kbuild b/arch/riscv/include/asm/Kbuild index 18158be62a2b..970460a0b492 100644 --- a/arch/riscv/include/asm/Kbuild +++ b/arch/riscv/include/asm/Kbuild @@ -40,6 +40,7 @@ generic-y += resource.h  generic-y += scatterlist.h  generic-y += sections.h  generic-y += sembuf.h +generic-y += serial.h  generic-y += setup.h  generic-y += shmbuf.h  generic-y += shmparam.h diff --git a/arch/riscv/include/asm/asm.h b/arch/riscv/include/asm/asm.h index 6cbbb6a68d76..5ad4cb622bed 100644 --- a/arch/riscv/include/asm/asm.h +++ b/arch/riscv/include/asm/asm.h @@ -58,17 +58,17 @@  #endif  #if (__SIZEOF_INT__ == 4) -#define INT		__ASM_STR(.word) -#define SZINT		__ASM_STR(4) -#define LGINT		__ASM_STR(2) +#define RISCV_INT		__ASM_STR(.word) +#define RISCV_SZINT		__ASM_STR(4) +#define RISCV_LGINT		__ASM_STR(2)  #else  #error "Unexpected __SIZEOF_INT__"  #endif  #if (__SIZEOF_SHORT__ == 2) -#define SHORT		__ASM_STR(.half) -#define SZSHORT		__ASM_STR(2) -#define LGSHORT		__ASM_STR(1) +#define RISCV_SHORT		__ASM_STR(.half) +#define RISCV_SZSHORT		__ASM_STR(2) +#define RISCV_LGSHORT		__ASM_STR(1)  #else  #error "Unexpected __SIZEOF_SHORT__"  #endif diff --git a/arch/riscv/include/asm/atomic.h b/arch/riscv/include/asm/atomic.h index e2e37c57cbeb..e65d1cd89e28 100644 --- a/arch/riscv/include/asm/atomic.h +++ b/arch/riscv/include/asm/atomic.h @@ -50,30 +50,30 @@ static __always_inline void atomic64_set(atomic64_t *v, long i)   * have the AQ or RL bits set.  These don't return anything, so there's only   * one version to worry about.   */ -#define ATOMIC_OP(op, asm_op, c_op, I, asm_type, c_type, prefix)				\ -static __always_inline void atomic##prefix##_##op(c_type i, atomic##prefix##_t *v)		\ -{												\ -	__asm__ __volatile__ (									\ -		"amo" #asm_op "." #asm_type " zero, %1, %0"					\ -		: "+A" (v->counter)								\ -		: "r" (I)									\ -		: "memory");									\ +#define ATOMIC_OP(op, asm_op, I, asm_type, c_type, prefix)				\ +static __always_inline void atomic##prefix##_##op(c_type i, atomic##prefix##_t *v)	\ +{											\ +	__asm__ __volatile__ (								\ +		"amo" #asm_op "." #asm_type " zero, %1, %0"				\ +		: "+A" (v->counter)							\ +		: "r" (I)								\ +		: "memory");								\  }  #ifdef CONFIG_GENERIC_ATOMIC64 -#define ATOMIC_OPS(op, asm_op, c_op, I)			\ -        ATOMIC_OP (op, asm_op, c_op, I, w,  int,   ) +#define ATOMIC_OPS(op, asm_op, I)			\ +        ATOMIC_OP (op, asm_op, I, w,  int,   )  #else -#define ATOMIC_OPS(op, asm_op, c_op, I)			\ -        ATOMIC_OP (op, asm_op, c_op, I, w,  int,   )	\ -        ATOMIC_OP (op, asm_op, c_op, I, d, long, 64) +#define ATOMIC_OPS(op, asm_op, I)			\ +        ATOMIC_OP (op, asm_op, I, w,  int,   )	\ +        ATOMIC_OP (op, asm_op, I, d, long, 64)  #endif -ATOMIC_OPS(add, add, +,  i) -ATOMIC_OPS(sub, add, +, -i) -ATOMIC_OPS(and, and, &,  i) -ATOMIC_OPS( or,  or, |,  i) -ATOMIC_OPS(xor, xor, ^,  i) +ATOMIC_OPS(add, add,  i) +ATOMIC_OPS(sub, add, -i) +ATOMIC_OPS(and, and,  i) +ATOMIC_OPS( or,  or,  i) +ATOMIC_OPS(xor, xor,  i)  #undef ATOMIC_OP  #undef ATOMIC_OPS @@ -83,7 +83,7 @@ ATOMIC_OPS(xor, xor, ^,  i)   * There's two flavors of these: the arithmatic ops have both fetch and return   * versions, while the logical ops only have fetch versions.   */ -#define ATOMIC_FETCH_OP(op, asm_op, c_op, I, asm_or, c_or, asm_type, c_type, prefix)			\ +#define ATOMIC_FETCH_OP(op, asm_op, I, asm_or, c_or, asm_type, c_type, prefix)				\  static __always_inline c_type atomic##prefix##_fetch_##op##c_or(c_type i, atomic##prefix##_t *v)	\  {													\  	register c_type ret;										\ @@ -103,13 +103,13 @@ static __always_inline c_type atomic##prefix##_##op##_return##c_or(c_type i, ato  #ifdef CONFIG_GENERIC_ATOMIC64  #define ATOMIC_OPS(op, asm_op, c_op, I, asm_or, c_or)				\ -        ATOMIC_FETCH_OP (op, asm_op, c_op, I, asm_or, c_or, w,  int,   )	\ +        ATOMIC_FETCH_OP (op, asm_op,       I, asm_or, c_or, w,  int,   )	\          ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, w,  int,   )  #else  #define ATOMIC_OPS(op, asm_op, c_op, I, asm_or, c_or)				\ -        ATOMIC_FETCH_OP (op, asm_op, c_op, I, asm_or, c_or, w,  int,   )	\ +        ATOMIC_FETCH_OP (op, asm_op,       I, asm_or, c_or, w,  int,   )	\          ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, w,  int,   )	\ -        ATOMIC_FETCH_OP (op, asm_op, c_op, I, asm_or, c_or, d, long, 64)	\ +        ATOMIC_FETCH_OP (op, asm_op,       I, asm_or, c_or, d, long, 64)	\          ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, d, long, 64)  #endif @@ -126,28 +126,28 @@ ATOMIC_OPS(sub, add, +, -i, .aqrl,         )  #undef ATOMIC_OPS  #ifdef CONFIG_GENERIC_ATOMIC64 -#define ATOMIC_OPS(op, asm_op, c_op, I, asm_or, c_or)				\ -        ATOMIC_FETCH_OP(op, asm_op, c_op, I, asm_or, c_or, w,  int,   ) +#define ATOMIC_OPS(op, asm_op, I, asm_or, c_or)				\ +        ATOMIC_FETCH_OP(op, asm_op, I, asm_or, c_or, w,  int,   )  #else -#define ATOMIC_OPS(op, asm_op, c_op, I, asm_or, c_or)				\ -        ATOMIC_FETCH_OP(op, asm_op, c_op, I, asm_or, c_or, w,  int,   )		\ -        ATOMIC_FETCH_OP(op, asm_op, c_op, I, asm_or, c_or, d, long, 64) +#define ATOMIC_OPS(op, asm_op, I, asm_or, c_or)				\ +        ATOMIC_FETCH_OP(op, asm_op, I, asm_or, c_or, w,  int,   )	\ +        ATOMIC_FETCH_OP(op, asm_op, I, asm_or, c_or, d, long, 64)  #endif -ATOMIC_OPS(and, and, &,  i,      , _relaxed) -ATOMIC_OPS(and, and, &,  i, .aq  , _acquire) -ATOMIC_OPS(and, and, &,  i, .rl  , _release) -ATOMIC_OPS(and, and, &,  i, .aqrl,         ) +ATOMIC_OPS(and, and, i,      , _relaxed) +ATOMIC_OPS(and, and, i, .aq  , _acquire) +ATOMIC_OPS(and, and, i, .rl  , _release) +ATOMIC_OPS(and, and, i, .aqrl,         ) -ATOMIC_OPS( or,  or, |,  i,      , _relaxed) -ATOMIC_OPS( or,  or, |,  i, .aq  , _acquire) -ATOMIC_OPS( or,  or, |,  i, .rl  , _release) -ATOMIC_OPS( or,  or, |,  i, .aqrl,         ) +ATOMIC_OPS( or,  or, i,      , _relaxed) +ATOMIC_OPS( or,  or, i, .aq  , _acquire) +ATOMIC_OPS( or,  or, i, .rl  , _release) +ATOMIC_OPS( or,  or, i, .aqrl,         ) -ATOMIC_OPS(xor, xor, ^,  i,      , _relaxed) -ATOMIC_OPS(xor, xor, ^,  i, .aq  , _acquire) -ATOMIC_OPS(xor, xor, ^,  i, .rl  , _release) -ATOMIC_OPS(xor, xor, ^,  i, .aqrl,         ) +ATOMIC_OPS(xor, xor, i,      , _relaxed) +ATOMIC_OPS(xor, xor, i, .aq  , _acquire) +ATOMIC_OPS(xor, xor, i, .rl  , _release) +ATOMIC_OPS(xor, xor, i, .aqrl,         )  #undef ATOMIC_OPS @@ -182,13 +182,13 @@ ATOMIC_OPS(add_negative, add,  <, 0)  #undef ATOMIC_OP  #undef ATOMIC_OPS -#define ATOMIC_OP(op, func_op, c_op, I, c_type, prefix)				\ +#define ATOMIC_OP(op, func_op, I, c_type, prefix)				\  static __always_inline void atomic##prefix##_##op(atomic##prefix##_t *v)	\  {										\  	atomic##prefix##_##func_op(I, v);					\  } -#define ATOMIC_FETCH_OP(op, func_op, c_op, I, c_type, prefix)				\ +#define ATOMIC_FETCH_OP(op, func_op, I, c_type, prefix)					\  static __always_inline c_type atomic##prefix##_fetch_##op(atomic##prefix##_t *v)	\  {											\  	return atomic##prefix##_fetch_##func_op(I, v);					\ @@ -202,16 +202,16 @@ static __always_inline c_type atomic##prefix##_##op##_return(atomic##prefix##_t  #ifdef CONFIG_GENERIC_ATOMIC64  #define ATOMIC_OPS(op, asm_op, c_op, I)						\ -        ATOMIC_OP       (op, asm_op, c_op, I,  int,   )				\ -        ATOMIC_FETCH_OP (op, asm_op, c_op, I,  int,   )				\ +        ATOMIC_OP       (op, asm_op,       I,  int,   )				\ +        ATOMIC_FETCH_OP (op, asm_op,       I,  int,   )				\          ATOMIC_OP_RETURN(op, asm_op, c_op, I,  int,   )  #else  #define ATOMIC_OPS(op, asm_op, c_op, I)						\ -        ATOMIC_OP       (op, asm_op, c_op, I,  int,   )				\ -        ATOMIC_FETCH_OP (op, asm_op, c_op, I,  int,   )				\ +        ATOMIC_OP       (op, asm_op,       I,  int,   )				\ +        ATOMIC_FETCH_OP (op, asm_op,       I,  int,   )				\          ATOMIC_OP_RETURN(op, asm_op, c_op, I,  int,   )				\ -        ATOMIC_OP       (op, asm_op, c_op, I, long, 64)				\ -        ATOMIC_FETCH_OP (op, asm_op, c_op, I, long, 64)				\ +        ATOMIC_OP       (op, asm_op,       I, long, 64)				\ +        ATOMIC_FETCH_OP (op, asm_op,       I, long, 64)				\          ATOMIC_OP_RETURN(op, asm_op, c_op, I, long, 64)  #endif @@ -300,8 +300,13 @@ static __always_inline long atomic64_inc_not_zero(atomic64_t *v)  /*   * atomic_{cmp,}xchg is required to have exactly the same ordering semantics as - * {cmp,}xchg and the operations that return, so they need a barrier.  We just - * use the other implementations directly. + * {cmp,}xchg and the operations that return, so they need a barrier. + */ +/* + * FIXME: atomic_cmpxchg_{acquire,release,relaxed} are all implemented by + * assigning the same barrier to both the LR and SC operations, but that might + * not make any sense.  We're waiting on a memory model specification to + * determine exactly what the right thing to do is here.   */  #define ATOMIC_OP(c_t, prefix, c_or, size, asm_or)						\  static __always_inline c_t atomic##prefix##_cmpxchg##c_or(atomic##prefix##_t *v, c_t o, c_t n) 	\ diff --git a/arch/riscv/include/asm/barrier.h b/arch/riscv/include/asm/barrier.h index 183534b7c39b..c0319cbf1eec 100644 --- a/arch/riscv/include/asm/barrier.h +++ b/arch/riscv/include/asm/barrier.h @@ -39,27 +39,23 @@  #define smp_wmb()	RISCV_FENCE(w,w)  /* - * These fences exist to enforce ordering around the relaxed AMOs.  The - * documentation defines that - * " - *     atomic_fetch_add(); - *   is equivalent to: - *     smp_mb__before_atomic(); - *     atomic_fetch_add_relaxed(); - *     smp_mb__after_atomic(); - * " - * So we emit full fences on both sides. - */ -#define __smb_mb__before_atomic()	smp_mb() -#define __smb_mb__after_atomic()	smp_mb() - -/* - * These barriers prevent accesses performed outside a spinlock from being moved - * inside a spinlock.  Since RISC-V sets the aq/rl bits on our spinlock only - * enforce release consistency, we need full fences here. + * This is a very specific barrier: it's currently only used in two places in + * the kernel, both in the scheduler.  See include/linux/spinlock.h for the two + * orderings it guarantees, but the "critical section is RCsc" guarantee + * mandates a barrier on RISC-V.  The sequence looks like: + * + *    lr.aq lock + *    sc    lock <= LOCKED + *    smp_mb__after_spinlock() + *    // critical section + *    lr    lock + *    sc.rl lock <= UNLOCKED + * + * The AQ/RL pair provides a RCpc critical section, but there's not really any + * way we can take advantage of that here because the ordering is only enforced + * on that one lock.  Thus, we're just doing a full fence.   */ -#define smb_mb__before_spinlock()	smp_mb() -#define smb_mb__after_spinlock()	smp_mb() +#define smp_mb__after_spinlock()	RISCV_FENCE(rw,rw)  #include <asm-generic/barrier.h> diff --git a/arch/riscv/include/asm/bitops.h b/arch/riscv/include/asm/bitops.h index 7c281ef1d583..f30daf26f08f 100644 --- a/arch/riscv/include/asm/bitops.h +++ b/arch/riscv/include/asm/bitops.h @@ -67,7 +67,7 @@  		: "memory");  #define __test_and_op_bit(op, mod, nr, addr) 			\ -	__test_and_op_bit_ord(op, mod, nr, addr, ) +	__test_and_op_bit_ord(op, mod, nr, addr, .aqrl)  #define __op_bit(op, mod, nr, addr)				\  	__op_bit_ord(op, mod, nr, addr, ) diff --git a/arch/riscv/include/asm/bug.h b/arch/riscv/include/asm/bug.h index c3e13764a943..bfc7f099ab1f 100644 --- a/arch/riscv/include/asm/bug.h +++ b/arch/riscv/include/asm/bug.h @@ -27,8 +27,8 @@  typedef u32 bug_insn_t;  #ifdef CONFIG_GENERIC_BUG_RELATIVE_POINTERS -#define __BUG_ENTRY_ADDR	INT " 1b - 2b" -#define __BUG_ENTRY_FILE	INT " %0 - 2b" +#define __BUG_ENTRY_ADDR	RISCV_INT " 1b - 2b" +#define __BUG_ENTRY_FILE	RISCV_INT " %0 - 2b"  #else  #define __BUG_ENTRY_ADDR	RISCV_PTR " 1b"  #define __BUG_ENTRY_FILE	RISCV_PTR " %0" @@ -38,7 +38,7 @@ typedef u32 bug_insn_t;  #define __BUG_ENTRY			\  	__BUG_ENTRY_ADDR "\n\t"		\  	__BUG_ENTRY_FILE "\n\t"		\ -	SHORT " %1" +	RISCV_SHORT " %1"  #else  #define __BUG_ENTRY			\  	__BUG_ENTRY_ADDR diff --git a/arch/riscv/include/asm/cacheflush.h b/arch/riscv/include/asm/cacheflush.h index 0595585013b0..efd89a88d2d0 100644 --- a/arch/riscv/include/asm/cacheflush.h +++ b/arch/riscv/include/asm/cacheflush.h @@ -18,22 +18,44 @@  #undef flush_icache_range  #undef flush_icache_user_range +#undef flush_dcache_page  static inline void local_flush_icache_all(void)  {  	asm volatile ("fence.i" ::: "memory");  } +#define PG_dcache_clean PG_arch_1 + +static inline void flush_dcache_page(struct page *page) +{ +	if (test_bit(PG_dcache_clean, &page->flags)) +		clear_bit(PG_dcache_clean, &page->flags); +} + +/* + * RISC-V doesn't have an instruction to flush parts of the instruction cache, + * so instead we just flush the whole thing. + */ +#define flush_icache_range(start, end) flush_icache_all() +#define flush_icache_user_range(vma, pg, addr, len) flush_icache_all() +  #ifndef CONFIG_SMP -#define flush_icache_range(start, end) local_flush_icache_all() -#define flush_icache_user_range(vma, pg, addr, len) local_flush_icache_all() +#define flush_icache_all() local_flush_icache_all() +#define flush_icache_mm(mm, local) flush_icache_all()  #else /* CONFIG_SMP */ -#define flush_icache_range(start, end) sbi_remote_fence_i(0) -#define flush_icache_user_range(vma, pg, addr, len) sbi_remote_fence_i(0) +#define flush_icache_all() sbi_remote_fence_i(0) +void flush_icache_mm(struct mm_struct *mm, bool local);  #endif /* CONFIG_SMP */ +/* + * Bits in sys_riscv_flush_icache()'s flags argument. + */ +#define SYS_RISCV_FLUSH_ICACHE_LOCAL 1UL +#define SYS_RISCV_FLUSH_ICACHE_ALL   (SYS_RISCV_FLUSH_ICACHE_LOCAL) +  #endif /* _ASM_RISCV_CACHEFLUSH_H */ diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h index 0d64bc9f4f91..3c7a2c97e377 100644 --- a/arch/riscv/include/asm/csr.h +++ b/arch/riscv/include/asm/csr.h @@ -17,10 +17,10 @@  #include <linux/const.h>  /* Status register flags */ -#define SR_IE   _AC(0x00000002, UL) /* Interrupt Enable */ -#define SR_PIE  _AC(0x00000020, UL) /* Previous IE */ -#define SR_PS   _AC(0x00000100, UL) /* Previously Supervisor */ -#define SR_SUM  _AC(0x00040000, UL) /* Supervisor may access User Memory */ +#define SR_SIE	_AC(0x00000002, UL) /* Supervisor Interrupt Enable */ +#define SR_SPIE	_AC(0x00000020, UL) /* Previous Supervisor IE */ +#define SR_SPP	_AC(0x00000100, UL) /* Previously Supervisor */ +#define SR_SUM	_AC(0x00040000, UL) /* Supervisor may access User Memory */  #define SR_FS           _AC(0x00006000, UL) /* Floating-point Status */  #define SR_FS_OFF       _AC(0x00000000, UL) diff --git a/arch/riscv/include/asm/io.h b/arch/riscv/include/asm/io.h index c1f32cfcc79b..b269451e7e85 100644 --- a/arch/riscv/include/asm/io.h +++ b/arch/riscv/include/asm/io.h @@ -19,7 +19,7 @@  #ifndef _ASM_RISCV_IO_H  #define _ASM_RISCV_IO_H -#ifdef CONFIG_MMU +#include <linux/types.h>  extern void __iomem *ioremap(phys_addr_t offset, unsigned long size); @@ -32,9 +32,7 @@ extern void __iomem *ioremap(phys_addr_t offset, unsigned long size);  #define ioremap_wc(addr, size) ioremap((addr), (size))  #define ioremap_wt(addr, size) ioremap((addr), (size)) -extern void iounmap(void __iomem *addr); - -#endif /* CONFIG_MMU */ +extern void iounmap(volatile void __iomem *addr);  /* Generic IO read/write.  These perform native-endian accesses. */  #define __raw_writeb __raw_writeb @@ -250,7 +248,7 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)  			const ctype *buf = buffer;				\  										\  			do {							\ -				__raw_writeq(*buf++, addr);			\ +				__raw_write ## len(*buf++, addr);		\  			} while (--count);					\  		}								\  		afence;								\ @@ -266,9 +264,9 @@ __io_reads_ins(reads, u32, l, __io_br(), __io_ar())  __io_reads_ins(ins,  u8, b, __io_pbr(), __io_par())  __io_reads_ins(ins, u16, w, __io_pbr(), __io_par())  __io_reads_ins(ins, u32, l, __io_pbr(), __io_par()) -#define insb(addr, buffer, count) __insb((void __iomem *)addr, buffer, count) -#define insw(addr, buffer, count) __insw((void __iomem *)addr, buffer, count) -#define insl(addr, buffer, count) __insl((void __iomem *)addr, buffer, count) +#define insb(addr, buffer, count) __insb((void __iomem *)(long)addr, buffer, count) +#define insw(addr, buffer, count) __insw((void __iomem *)(long)addr, buffer, count) +#define insl(addr, buffer, count) __insl((void __iomem *)(long)addr, buffer, count)  __io_writes_outs(writes,  u8, b, __io_bw(), __io_aw())  __io_writes_outs(writes, u16, w, __io_bw(), __io_aw()) @@ -280,9 +278,9 @@ __io_writes_outs(writes, u32, l, __io_bw(), __io_aw())  __io_writes_outs(outs,  u8, b, __io_pbw(), __io_paw())  __io_writes_outs(outs, u16, w, __io_pbw(), __io_paw())  __io_writes_outs(outs, u32, l, __io_pbw(), __io_paw()) -#define outsb(addr, buffer, count) __outsb((void __iomem *)addr, buffer, count) -#define outsw(addr, buffer, count) __outsw((void __iomem *)addr, buffer, count) -#define outsl(addr, buffer, count) __outsl((void __iomem *)addr, buffer, count) +#define outsb(addr, buffer, count) __outsb((void __iomem *)(long)addr, buffer, count) +#define outsw(addr, buffer, count) __outsw((void __iomem *)(long)addr, buffer, count) +#define outsl(addr, buffer, count) __outsl((void __iomem *)(long)addr, buffer, count)  #ifdef CONFIG_64BIT  __io_reads_ins(reads, u64, q, __io_br(), __io_ar()) diff --git a/arch/riscv/include/asm/irqflags.h b/arch/riscv/include/asm/irqflags.h index 6fdc860d7f84..07a3c6d5706f 100644 --- a/arch/riscv/include/asm/irqflags.h +++ b/arch/riscv/include/asm/irqflags.h @@ -27,25 +27,25 @@ static inline unsigned long arch_local_save_flags(void)  /* unconditionally enable interrupts */  static inline void arch_local_irq_enable(void)  { -	csr_set(sstatus, SR_IE); +	csr_set(sstatus, SR_SIE);  }  /* unconditionally disable interrupts */  static inline void arch_local_irq_disable(void)  { -	csr_clear(sstatus, SR_IE); +	csr_clear(sstatus, SR_SIE);  }  /* get status and disable interrupts */  static inline unsigned long arch_local_irq_save(void)  { -	return csr_read_clear(sstatus, SR_IE); +	return csr_read_clear(sstatus, SR_SIE);  }  /* test flags */  static inline int arch_irqs_disabled_flags(unsigned long flags)  { -	return !(flags & SR_IE); +	return !(flags & SR_SIE);  }  /* test hardware interrupt enable bit */ @@ -57,7 +57,7 @@ static inline int arch_irqs_disabled(void)  /* set interrupt enabled status */  static inline void arch_local_irq_restore(unsigned long flags)  { -	csr_set(sstatus, flags & SR_IE); +	csr_set(sstatus, flags & SR_SIE);  }  #endif /* _ASM_RISCV_IRQFLAGS_H */ diff --git a/arch/riscv/include/asm/mmu.h b/arch/riscv/include/asm/mmu.h index 66805cba9a27..5df2dccdba12 100644 --- a/arch/riscv/include/asm/mmu.h +++ b/arch/riscv/include/asm/mmu.h @@ -19,6 +19,10 @@  typedef struct {  	void *vdso; +#ifdef CONFIG_SMP +	/* A local icache flush is needed before user execution can resume. */ +	cpumask_t icache_stale_mask; +#endif  } mm_context_t;  #endif /* __ASSEMBLY__ */ diff --git a/arch/riscv/include/asm/mmu_context.h b/arch/riscv/include/asm/mmu_context.h index de1fc1631fc4..97424834dce2 100644 --- a/arch/riscv/include/asm/mmu_context.h +++ b/arch/riscv/include/asm/mmu_context.h @@ -1,5 +1,6 @@  /*   * Copyright (C) 2012 Regents of the University of California + * Copyright (C) 2017 SiFive   *   *   This program is free software; you can redistribute it and/or   *   modify it under the terms of the GNU General Public License @@ -14,11 +15,13 @@  #ifndef _ASM_RISCV_MMU_CONTEXT_H  #define _ASM_RISCV_MMU_CONTEXT_H +#include <linux/mm_types.h>  #include <asm-generic/mm_hooks.h>  #include <linux/mm.h>  #include <linux/sched.h>  #include <asm/tlbflush.h> +#include <asm/cacheflush.h>  static inline void enter_lazy_tlb(struct mm_struct *mm,  	struct task_struct *task) @@ -46,12 +49,54 @@ static inline void set_pgdir(pgd_t *pgd)  	csr_write(sptbr, virt_to_pfn(pgd) | SPTBR_MODE);  } +/* + * When necessary, performs a deferred icache flush for the given MM context, + * on the local CPU.  RISC-V has no direct mechanism for instruction cache + * shoot downs, so instead we send an IPI that informs the remote harts they + * need to flush their local instruction caches.  To avoid pathologically slow + * behavior in a common case (a bunch of single-hart processes on a many-hart + * machine, ie 'make -j') we avoid the IPIs for harts that are not currently + * executing a MM context and instead schedule a deferred local instruction + * cache flush to be performed before execution resumes on each hart.  This + * actually performs that local instruction cache flush, which implicitly only + * refers to the current hart. + */ +static inline void flush_icache_deferred(struct mm_struct *mm) +{ +#ifdef CONFIG_SMP +	unsigned int cpu = smp_processor_id(); +	cpumask_t *mask = &mm->context.icache_stale_mask; + +	if (cpumask_test_cpu(cpu, mask)) { +		cpumask_clear_cpu(cpu, mask); +		/* +		 * Ensure the remote hart's writes are visible to this hart. +		 * This pairs with a barrier in flush_icache_mm. +		 */ +		smp_mb(); +		local_flush_icache_all(); +	} +#endif +} +  static inline void switch_mm(struct mm_struct *prev,  	struct mm_struct *next, struct task_struct *task)  {  	if (likely(prev != next)) { +		/* +		 * Mark the current MM context as inactive, and the next as +		 * active.  This is at least used by the icache flushing +		 * routines in order to determine who should +		 */ +		unsigned int cpu = smp_processor_id(); + +		cpumask_clear_cpu(cpu, mm_cpumask(prev)); +		cpumask_set_cpu(cpu, mm_cpumask(next)); +  		set_pgdir(next->pgd);  		local_flush_tlb_all(); + +		flush_icache_deferred(next);  	}  } diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index 3399257780b2..16301966d65b 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -20,8 +20,6 @@  #ifndef __ASSEMBLY__ -#ifdef CONFIG_MMU -  /* Page Upper Directory not used in RISC-V */  #include <asm-generic/pgtable-nopud.h>  #include <asm/page.h> @@ -178,28 +176,6 @@ static inline pte_t *pte_offset_kernel(pmd_t *pmd, unsigned long addr)  #define pte_offset_map(dir, addr)	pte_offset_kernel((dir), (addr))  #define pte_unmap(pte)			((void)(pte)) -/* - * Certain architectures need to do special things when PTEs within - * a page table are directly modified.  Thus, the following hook is - * made available. - */ -static inline void set_pte(pte_t *ptep, pte_t pteval) -{ -	*ptep = pteval; -} - -static inline void set_pte_at(struct mm_struct *mm, -	unsigned long addr, pte_t *ptep, pte_t pteval) -{ -	set_pte(ptep, pteval); -} - -static inline void pte_clear(struct mm_struct *mm, -	unsigned long addr, pte_t *ptep) -{ -	set_pte_at(mm, addr, ptep, __pte(0)); -} -  static inline int pte_present(pte_t pte)  {  	return (pte_val(pte) & _PAGE_PRESENT); @@ -210,21 +186,22 @@ static inline int pte_none(pte_t pte)  	return (pte_val(pte) == 0);  } -/* static inline int pte_read(pte_t pte) */ -  static inline int pte_write(pte_t pte)  {  	return pte_val(pte) & _PAGE_WRITE;  } +static inline int pte_exec(pte_t pte) +{ +	return pte_val(pte) & _PAGE_EXEC; +} +  static inline int pte_huge(pte_t pte)  {  	return pte_present(pte)  		&& (pte_val(pte) & (_PAGE_READ | _PAGE_WRITE | _PAGE_EXEC));  } -/* static inline int pte_exec(pte_t pte) */ -  static inline int pte_dirty(pte_t pte)  {  	return pte_val(pte) & _PAGE_DIRTY; @@ -311,6 +288,33 @@ static inline int pte_same(pte_t pte_a, pte_t pte_b)  	return pte_val(pte_a) == pte_val(pte_b);  } +/* + * Certain architectures need to do special things when PTEs within + * a page table are directly modified.  Thus, the following hook is + * made available. + */ +static inline void set_pte(pte_t *ptep, pte_t pteval) +{ +	*ptep = pteval; +} + +void flush_icache_pte(pte_t pte); + +static inline void set_pte_at(struct mm_struct *mm, +	unsigned long addr, pte_t *ptep, pte_t pteval) +{ +	if (pte_present(pteval) && pte_exec(pteval)) +		flush_icache_pte(pteval); + +	set_pte(ptep, pteval); +} + +static inline void pte_clear(struct mm_struct *mm, +	unsigned long addr, pte_t *ptep) +{ +	set_pte_at(mm, addr, ptep, __pte(0)); +} +  #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS  static inline int ptep_set_access_flags(struct vm_area_struct *vma,  					unsigned long address, pte_t *ptep, @@ -407,8 +411,6 @@ static inline void pgtable_cache_init(void)  	/* No page table caches to initialize */  } -#endif /* CONFIG_MMU */ -  #define VMALLOC_SIZE     (KERN_VIRT_SIZE >> 1)  #define VMALLOC_END      (PAGE_OFFSET - 1)  #define VMALLOC_START    (PAGE_OFFSET - VMALLOC_SIZE) diff --git a/arch/riscv/include/asm/ptrace.h b/arch/riscv/include/asm/ptrace.h index 93b8956e25e4..2c5df945d43c 100644 --- a/arch/riscv/include/asm/ptrace.h +++ b/arch/riscv/include/asm/ptrace.h @@ -66,7 +66,7 @@ struct pt_regs {  #define REG_FMT "%08lx"  #endif -#define user_mode(regs) (((regs)->sstatus & SR_PS) == 0) +#define user_mode(regs) (((regs)->sstatus & SR_SPP) == 0)  /* Helpers for working with the instruction pointer */ diff --git a/arch/riscv/include/asm/spinlock.h b/arch/riscv/include/asm/spinlock.h index 04c71d938afd..2fd27e8ef1fd 100644 --- a/arch/riscv/include/asm/spinlock.h +++ b/arch/riscv/include/asm/spinlock.h @@ -24,7 +24,7 @@  /* FIXME: Replace this with a ticket lock, like MIPS. */ -#define arch_spin_is_locked(x)	((x)->lock != 0) +#define arch_spin_is_locked(x)	(READ_ONCE((x)->lock) != 0)  static inline void arch_spin_unlock(arch_spinlock_t *lock)  { @@ -58,15 +58,6 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)  	}  } -static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) -{ -	smp_rmb(); -	do { -		cpu_relax(); -	} while (arch_spin_is_locked(lock)); -	smp_acquire__after_ctrl_dep(); -} -  /***********************************************************/  static inline void arch_read_lock(arch_rwlock_t *lock) diff --git a/arch/riscv/include/asm/timex.h b/arch/riscv/include/asm/timex.h index 3df4932d8964..2f26989cb864 100644 --- a/arch/riscv/include/asm/timex.h +++ b/arch/riscv/include/asm/timex.h @@ -18,7 +18,7 @@  typedef unsigned long cycles_t; -static inline cycles_t get_cycles(void) +static inline cycles_t get_cycles_inline(void)  {  	cycles_t n; @@ -27,6 +27,7 @@ static inline cycles_t get_cycles(void)  		: "=r" (n));  	return n;  } +#define get_cycles get_cycles_inline  #ifdef CONFIG_64BIT  static inline uint64_t get_cycles64(void) diff --git a/arch/riscv/include/asm/tlbflush.h b/arch/riscv/include/asm/tlbflush.h index 5ee4ae370b5e..7b9c24ebdf52 100644 --- a/arch/riscv/include/asm/tlbflush.h +++ b/arch/riscv/include/asm/tlbflush.h @@ -15,9 +15,12 @@  #ifndef _ASM_RISCV_TLBFLUSH_H  #define _ASM_RISCV_TLBFLUSH_H -#ifdef CONFIG_MMU +#include <linux/mm_types.h> -/* Flush entire local TLB */ +/* + * Flush entire local TLB.  'sfence.vma' implicitly fences with the instruction + * cache as well, so a 'fence.i' is not necessary. + */  static inline void local_flush_tlb_all(void)  {  	__asm__ __volatile__ ("sfence.vma" : : : "memory"); @@ -59,6 +62,4 @@ static inline void flush_tlb_kernel_range(unsigned long start,  	flush_tlb_all();  } -#endif /* CONFIG_MMU */ -  #endif /* _ASM_RISCV_TLBFLUSH_H */ diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h index 27b90d64814b..14b0b22fb578 100644 --- a/arch/riscv/include/asm/uaccess.h +++ b/arch/riscv/include/asm/uaccess.h @@ -127,7 +127,6 @@ extern int fixup_exception(struct pt_regs *state);   * call.   */ -#ifdef CONFIG_MMU  #define __get_user_asm(insn, x, ptr, err)			\  do {								\  	uintptr_t __tmp;					\ @@ -153,13 +152,11 @@ do {								\  	__disable_user_access();				\  	(x) = __x;						\  } while (0) -#endif /* CONFIG_MMU */  #ifdef CONFIG_64BIT  #define __get_user_8(x, ptr, err) \  	__get_user_asm("ld", x, ptr, err)  #else /* !CONFIG_64BIT */ -#ifdef CONFIG_MMU  #define __get_user_8(x, ptr, err)				\  do {								\  	u32 __user *__ptr = (u32 __user *)(ptr);		\ @@ -193,7 +190,6 @@ do {								\  	(x) = (__typeof__(x))((__typeof__((x)-(x)))(		\  		(((u64)__hi << 32) | __lo)));			\  } while (0) -#endif /* CONFIG_MMU */  #endif /* CONFIG_64BIT */ @@ -267,8 +263,6 @@ do {								\  		((x) = 0, -EFAULT);				\  }) - -#ifdef CONFIG_MMU  #define __put_user_asm(insn, x, ptr, err)			\  do {								\  	uintptr_t __tmp;					\ @@ -292,14 +286,11 @@ do {								\  		: "rJ" (__x), "i" (-EFAULT));			\  	__disable_user_access();				\  } while (0) -#endif /* CONFIG_MMU */ -  #ifdef CONFIG_64BIT  #define __put_user_8(x, ptr, err) \  	__put_user_asm("sd", x, ptr, err)  #else /* !CONFIG_64BIT */ -#ifdef CONFIG_MMU  #define __put_user_8(x, ptr, err)				\  do {								\  	u32 __user *__ptr = (u32 __user *)(ptr);		\ @@ -329,7 +320,6 @@ do {								\  		: "rJ" (__x), "rJ" (__x >> 32), "i" (-EFAULT));	\  	__disable_user_access();				\  } while (0) -#endif /* CONFIG_MMU */  #endif /* CONFIG_64BIT */ @@ -438,7 +428,6 @@ unsigned long __must_check clear_user(void __user *to, unsigned long n)   * will set "err" to -EFAULT, while successful accesses return the previous   * value.   */ -#ifdef CONFIG_MMU  #define __cmpxchg_user(ptr, old, new, err, size, lrb, scb)	\  ({								\  	__typeof__(ptr) __ptr = (ptr);				\ @@ -508,6 +497,5 @@ unsigned long __must_check clear_user(void __user *to, unsigned long n)  	(err) = __err;						\  	__ret;							\  }) -#endif /* CONFIG_MMU */  #endif /* _ASM_RISCV_UACCESS_H */ diff --git a/arch/riscv/include/asm/unistd.h b/arch/riscv/include/asm/unistd.h index 9f250ed007cd..2f704a5c4196 100644 --- a/arch/riscv/include/asm/unistd.h +++ b/arch/riscv/include/asm/unistd.h @@ -14,3 +14,4 @@  #define __ARCH_HAVE_MMU  #define __ARCH_WANT_SYS_CLONE  #include <uapi/asm/unistd.h> +#include <uapi/asm/syscalls.h> diff --git a/arch/riscv/include/asm/vdso.h b/arch/riscv/include/asm/vdso.h index 602f61257553..541544d64c33 100644 --- a/arch/riscv/include/asm/vdso.h +++ b/arch/riscv/include/asm/vdso.h @@ -38,4 +38,8 @@ struct vdso_data {  	(void __user *)((unsigned long)(base) + __vdso_##name);			\  }) +#ifdef CONFIG_SMP +asmlinkage long sys_riscv_flush_icache(uintptr_t, uintptr_t, uintptr_t); +#endif +  #endif /* _ASM_RISCV_VDSO_H */  | 

