diff options
author | Paul Burton <paul.burton@mips.com> | 2019-02-02 01:43:27 +0000 |
---|---|---|
committer | Paul Burton <paul.burton@mips.com> | 2019-02-04 10:56:35 -0800 |
commit | 535113896e802e9f8f92c05a887d1761c34ae903 (patch) | |
tree | 4d0b573a5ad008f478f806e585aec22db77e03cc /arch/mips/include/asm/ginvt.h | |
parent | 0b317c389c6771cbe1c5a12fe9322285a808a9bd (diff) | |
download | linux-535113896e802e9f8f92c05a887d1761c34ae903.tar.bz2 |
MIPS: Add GINVT instruction helpers
Add a family of ginvt_* functions making it easy to emit a GINVT
instruction to globally invalidate TLB entries. We make use of the
_ASM_MACRO infrastructure to support emitting the instructions even if
the assembler isn't new enough to support them natively.
An associated STYPE_GINV definition & sync_ginv() function are added to
emit a sync instruction of type 0x14, which operates as a completion
barrier for these new GINVT (and GINVI) instructions.
Signed-off-by: Paul Burton <paul.burton@mips.com>
Cc: linux-mips@vger.kernel.org
Diffstat (limited to 'arch/mips/include/asm/ginvt.h')
-rw-r--r-- | arch/mips/include/asm/ginvt.h | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/arch/mips/include/asm/ginvt.h b/arch/mips/include/asm/ginvt.h new file mode 100644 index 000000000000..49c6dbe37338 --- /dev/null +++ b/arch/mips/include/asm/ginvt.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __MIPS_ASM_GINVT_H__ +#define __MIPS_ASM_GINVT_H__ + +#include <asm/mipsregs.h> + +enum ginvt_type { + GINVT_FULL, + GINVT_VA, + GINVT_MMID, +}; + +#ifdef TOOLCHAIN_SUPPORTS_GINV +# define _ASM_SET_GINV ".set ginv\n" +#else +_ASM_MACRO_1R1I(ginvt, rs, type, + _ASM_INSN_IF_MIPS(0x7c0000bd | (__rs << 21) | (\\type << 8)) + _ASM_INSN32_IF_MM(0x0000717c | (__rs << 16) | (\\type << 9))); +# define _ASM_SET_GINV +#endif + +static inline void ginvt(unsigned long addr, enum ginvt_type type) +{ + asm volatile( + ".set push\n" + _ASM_SET_GINV + " ginvt %0, %1\n" + ".set pop" + : /* no outputs */ + : "r"(addr), "i"(type) + : "memory"); +} + +static inline void ginvt_full(void) +{ + ginvt(0, GINVT_FULL); +} + +static inline void ginvt_va(unsigned long addr) +{ + addr &= PAGE_MASK << 1; + ginvt(addr, GINVT_VA); +} + +static inline void ginvt_mmid(void) +{ + ginvt(0, GINVT_MMID); +} + +static inline void ginvt_va_mmid(unsigned long addr) +{ + addr &= PAGE_MASK << 1; + ginvt(addr, GINVT_VA | GINVT_MMID); +} + +#endif /* __MIPS_ASM_GINVT_H__ */ |