File Index
Files and directories
Sign in
FILE

nacl.c

File preview with syntax highlighting.

linux-6.19.14/arch/riscv/kvm/nacl.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (c) 2024 Ventana Micro Systems Inc.
  4 */
  5
  6#include <linux/kvm_host.h>
  7#include <linux/vmalloc.h>
  8#include <asm/kvm_nacl.h>
  9
 10DEFINE_STATIC_KEY_FALSE(kvm_riscv_nacl_available);
 11DEFINE_STATIC_KEY_FALSE(kvm_riscv_nacl_sync_csr_available);
 12DEFINE_STATIC_KEY_FALSE(kvm_riscv_nacl_sync_hfence_available);
 13DEFINE_STATIC_KEY_FALSE(kvm_riscv_nacl_sync_sret_available);
 14DEFINE_STATIC_KEY_FALSE(kvm_riscv_nacl_autoswap_csr_available);
 15DEFINE_PER_CPU(struct kvm_riscv_nacl, kvm_riscv_nacl);
 16
 17void __kvm_riscv_nacl_hfence(void *shmem,
 18			     unsigned long control,
 19			     unsigned long page_num,
 20			     unsigned long page_count)
 21{
 22	int i, ent = -1, try_count = 5;
 23	unsigned long *entp;
 24
 25again:
 26	for (i = 0; i < SBI_NACL_SHMEM_HFENCE_ENTRY_MAX; i++) {
 27		entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_CONFIG(i);
 28		if (lelong_to_cpu(*entp) & SBI_NACL_SHMEM_HFENCE_CONFIG_PEND)
 29			continue;
 30
 31		ent = i;
 32		break;
 33	}
 34
 35	if (ent < 0) {
 36		if (try_count) {
 37			nacl_sync_hfence(-1UL);
 38			goto again;
 39		} else {
 40			pr_warn("KVM: No free entry in NACL shared memory\n");
 41			return;
 42		}
 43	}
 44
 45	entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_CONFIG(i);
 46	*entp = cpu_to_lelong(control);
 47	entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_PNUM(i);
 48	*entp = cpu_to_lelong(page_num);
 49	entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_PCOUNT(i);
 50	*entp = cpu_to_lelong(page_count);
 51}
 52
 53int kvm_riscv_nacl_enable(void)
 54{
 55	int rc;
 56	struct sbiret ret;
 57	struct kvm_riscv_nacl *nacl;
 58
 59	if (!kvm_riscv_nacl_available())
 60		return 0;
 61	nacl = this_cpu_ptr(&kvm_riscv_nacl);
 62
 63	ret = sbi_ecall(SBI_EXT_NACL, SBI_EXT_NACL_SET_SHMEM,
 64			nacl->shmem_phys, 0, 0, 0, 0, 0);
 65	rc = sbi_err_map_linux_errno(ret.error);
 66	if (rc)
 67		return rc;
 68
 69	return 0;
 70}
 71
 72void kvm_riscv_nacl_disable(void)
 73{
 74	if (!kvm_riscv_nacl_available())
 75		return;
 76
 77	sbi_ecall(SBI_EXT_NACL, SBI_EXT_NACL_SET_SHMEM,
 78		  SBI_SHMEM_DISABLE, SBI_SHMEM_DISABLE, 0, 0, 0, 0);
 79}
 80
 81void kvm_riscv_nacl_exit(void)
 82{
 83	int cpu;
 84	struct kvm_riscv_nacl *nacl;
 85
 86	if (!kvm_riscv_nacl_available())
 87		return;
 88
 89	/* Allocate per-CPU shared memory */
 90	for_each_possible_cpu(cpu) {
 91		nacl = per_cpu_ptr(&kvm_riscv_nacl, cpu);
 92		if (!nacl->shmem)
 93			continue;
 94
 95		free_pages((unsigned long)nacl->shmem,
 96			   get_order(SBI_NACL_SHMEM_SIZE));
 97		nacl->shmem = NULL;
 98		nacl->shmem_phys = 0;
 99	}
100}
101
102static long nacl_probe_feature(long feature_id)
103{
104	struct sbiret ret;
105
106	if (!kvm_riscv_nacl_available())
107		return 0;
108
109	ret = sbi_ecall(SBI_EXT_NACL, SBI_EXT_NACL_PROBE_FEATURE,
110			feature_id, 0, 0, 0, 0, 0);
111	return ret.value;
112}
113
114int kvm_riscv_nacl_init(void)
115{
116	int cpu;
117	struct page *shmem_page;
118	struct kvm_riscv_nacl *nacl;
119
120	if (sbi_spec_version < sbi_mk_version(1, 0) ||
121	    sbi_probe_extension(SBI_EXT_NACL) <= 0)
122		return -ENODEV;
123
124	/* Enable NACL support */
125	static_branch_enable(&kvm_riscv_nacl_available);
126
127	/* Probe NACL features */
128	if (nacl_probe_feature(SBI_NACL_FEAT_SYNC_CSR))
129		static_branch_enable(&kvm_riscv_nacl_sync_csr_available);
130	if (nacl_probe_feature(SBI_NACL_FEAT_SYNC_HFENCE))
131		static_branch_enable(&kvm_riscv_nacl_sync_hfence_available);
132	if (nacl_probe_feature(SBI_NACL_FEAT_SYNC_SRET))
133		static_branch_enable(&kvm_riscv_nacl_sync_sret_available);
134	if (nacl_probe_feature(SBI_NACL_FEAT_AUTOSWAP_CSR))
135		static_branch_enable(&kvm_riscv_nacl_autoswap_csr_available);
136
137	/* Allocate per-CPU shared memory */
138	for_each_possible_cpu(cpu) {
139		nacl = per_cpu_ptr(&kvm_riscv_nacl, cpu);
140
141		shmem_page = alloc_pages(GFP_KERNEL | __GFP_ZERO,
142					 get_order(SBI_NACL_SHMEM_SIZE));
143		if (!shmem_page) {
144			kvm_riscv_nacl_exit();
145			return -ENOMEM;
146		}
147		nacl->shmem = page_to_virt(shmem_page);
148		nacl->shmem_phys = page_to_phys(shmem_page);
149	}
150
151	return 0;
152}
~/ Read-only file preview.