162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _ASM_X86_INVPCID
362306a36Sopenharmony_ci#define _ASM_X86_INVPCID
462306a36Sopenharmony_ci
562306a36Sopenharmony_cistatic inline void __invpcid(unsigned long pcid, unsigned long addr,
662306a36Sopenharmony_ci			     unsigned long type)
762306a36Sopenharmony_ci{
862306a36Sopenharmony_ci	struct { u64 d[2]; } desc = { { pcid, addr } };
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci	/*
1162306a36Sopenharmony_ci	 * The memory clobber is because the whole point is to invalidate
1262306a36Sopenharmony_ci	 * stale TLB entries and, especially if we're flushing global
1362306a36Sopenharmony_ci	 * mappings, we don't want the compiler to reorder any subsequent
1462306a36Sopenharmony_ci	 * memory accesses before the TLB flush.
1562306a36Sopenharmony_ci	 */
1662306a36Sopenharmony_ci	asm volatile("invpcid %[desc], %[type]"
1762306a36Sopenharmony_ci		     :: [desc] "m" (desc), [type] "r" (type) : "memory");
1862306a36Sopenharmony_ci}
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define INVPCID_TYPE_INDIV_ADDR		0
2162306a36Sopenharmony_ci#define INVPCID_TYPE_SINGLE_CTXT	1
2262306a36Sopenharmony_ci#define INVPCID_TYPE_ALL_INCL_GLOBAL	2
2362306a36Sopenharmony_ci#define INVPCID_TYPE_ALL_NON_GLOBAL	3
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* Flush all mappings for a given pcid and addr, not including globals. */
2662306a36Sopenharmony_cistatic inline void invpcid_flush_one(unsigned long pcid,
2762306a36Sopenharmony_ci				     unsigned long addr)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	__invpcid(pcid, addr, INVPCID_TYPE_INDIV_ADDR);
3062306a36Sopenharmony_ci}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/* Flush all mappings for a given PCID, not including globals. */
3362306a36Sopenharmony_cistatic inline void invpcid_flush_single_context(unsigned long pcid)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	__invpcid(pcid, 0, INVPCID_TYPE_SINGLE_CTXT);
3662306a36Sopenharmony_ci}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci/* Flush all mappings, including globals, for all PCIDs. */
3962306a36Sopenharmony_cistatic inline void invpcid_flush_all(void)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	__invpcid(0, 0, INVPCID_TYPE_ALL_INCL_GLOBAL);
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/* Flush all mappings for all PCIDs except globals. */
4562306a36Sopenharmony_cistatic inline void invpcid_flush_all_nonglobals(void)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	__invpcid(0, 0, INVPCID_TYPE_ALL_NON_GLOBAL);
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#endif /* _ASM_X86_INVPCID */
51