162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2019 Western Digital Corporation or its affiliates.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Authors:
662306a36Sopenharmony_ci *     Anup Patel <anup.patel@wdc.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/errno.h>
1062306a36Sopenharmony_ci#include <linux/err.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/uaccess.h>
1362306a36Sopenharmony_ci#include <linux/kvm_host.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ciconst struct _kvm_stats_desc kvm_vm_stats_desc[] = {
1662306a36Sopenharmony_ci	KVM_GENERIC_VM_STATS()
1762306a36Sopenharmony_ci};
1862306a36Sopenharmony_cistatic_assert(ARRAY_SIZE(kvm_vm_stats_desc) ==
1962306a36Sopenharmony_ci		sizeof(struct kvm_vm_stat) / sizeof(u64));
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ciconst struct kvm_stats_header kvm_vm_stats_header = {
2262306a36Sopenharmony_ci	.name_size = KVM_STATS_NAME_SIZE,
2362306a36Sopenharmony_ci	.num_desc = ARRAY_SIZE(kvm_vm_stats_desc),
2462306a36Sopenharmony_ci	.id_offset =  sizeof(struct kvm_stats_header),
2562306a36Sopenharmony_ci	.desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,
2662306a36Sopenharmony_ci	.data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +
2762306a36Sopenharmony_ci		       sizeof(kvm_vm_stats_desc),
2862306a36Sopenharmony_ci};
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ciint kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	int r;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	r = kvm_riscv_gstage_alloc_pgd(kvm);
3562306a36Sopenharmony_ci	if (r)
3662306a36Sopenharmony_ci		return r;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	r = kvm_riscv_gstage_vmid_init(kvm);
3962306a36Sopenharmony_ci	if (r) {
4062306a36Sopenharmony_ci		kvm_riscv_gstage_free_pgd(kvm);
4162306a36Sopenharmony_ci		return r;
4262306a36Sopenharmony_ci	}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	kvm_riscv_aia_init_vm(kvm);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	kvm_riscv_guest_timer_init(kvm);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	return 0;
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_civoid kvm_arch_destroy_vm(struct kvm *kvm)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	kvm_destroy_vcpus(kvm);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	kvm_riscv_aia_destroy_vm(kvm);
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ciint kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irql,
5962306a36Sopenharmony_ci			  bool line_status)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	if (!irqchip_in_kernel(kvm))
6262306a36Sopenharmony_ci		return -ENXIO;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	return kvm_riscv_aia_inject_irq(kvm, irql->irq, irql->level);
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ciint kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
6862306a36Sopenharmony_ci		struct kvm *kvm, int irq_source_id,
6962306a36Sopenharmony_ci		int level, bool line_status)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	struct kvm_msi msi;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	if (!level)
7462306a36Sopenharmony_ci		return -1;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	msi.address_lo = e->msi.address_lo;
7762306a36Sopenharmony_ci	msi.address_hi = e->msi.address_hi;
7862306a36Sopenharmony_ci	msi.data = e->msi.data;
7962306a36Sopenharmony_ci	msi.flags = e->msi.flags;
8062306a36Sopenharmony_ci	msi.devid = e->msi.devid;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	return kvm_riscv_aia_inject_msi(kvm, &msi);
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic int kvm_riscv_set_irq(struct kvm_kernel_irq_routing_entry *e,
8662306a36Sopenharmony_ci			     struct kvm *kvm, int irq_source_id,
8762306a36Sopenharmony_ci			     int level, bool line_status)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	return kvm_riscv_aia_inject_irq(kvm, e->irqchip.pin, level);
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ciint kvm_riscv_setup_default_irq_routing(struct kvm *kvm, u32 lines)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	struct kvm_irq_routing_entry *ents;
9562306a36Sopenharmony_ci	int i, rc;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	ents = kcalloc(lines, sizeof(*ents), GFP_KERNEL);
9862306a36Sopenharmony_ci	if (!ents)
9962306a36Sopenharmony_ci		return -ENOMEM;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	for (i = 0; i < lines; i++) {
10262306a36Sopenharmony_ci		ents[i].gsi = i;
10362306a36Sopenharmony_ci		ents[i].type = KVM_IRQ_ROUTING_IRQCHIP;
10462306a36Sopenharmony_ci		ents[i].u.irqchip.irqchip = 0;
10562306a36Sopenharmony_ci		ents[i].u.irqchip.pin = i;
10662306a36Sopenharmony_ci	}
10762306a36Sopenharmony_ci	rc = kvm_set_irq_routing(kvm, ents, lines, 0);
10862306a36Sopenharmony_ci	kfree(ents);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	return rc;
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cibool kvm_arch_can_set_irq_routing(struct kvm *kvm)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	return irqchip_in_kernel(kvm);
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ciint kvm_set_routing_entry(struct kvm *kvm,
11962306a36Sopenharmony_ci			  struct kvm_kernel_irq_routing_entry *e,
12062306a36Sopenharmony_ci			  const struct kvm_irq_routing_entry *ue)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	int r = -EINVAL;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	switch (ue->type) {
12562306a36Sopenharmony_ci	case KVM_IRQ_ROUTING_IRQCHIP:
12662306a36Sopenharmony_ci		e->set = kvm_riscv_set_irq;
12762306a36Sopenharmony_ci		e->irqchip.irqchip = ue->u.irqchip.irqchip;
12862306a36Sopenharmony_ci		e->irqchip.pin = ue->u.irqchip.pin;
12962306a36Sopenharmony_ci		if ((e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS) ||
13062306a36Sopenharmony_ci		    (e->irqchip.irqchip >= KVM_NR_IRQCHIPS))
13162306a36Sopenharmony_ci			goto out;
13262306a36Sopenharmony_ci		break;
13362306a36Sopenharmony_ci	case KVM_IRQ_ROUTING_MSI:
13462306a36Sopenharmony_ci		e->set = kvm_set_msi;
13562306a36Sopenharmony_ci		e->msi.address_lo = ue->u.msi.address_lo;
13662306a36Sopenharmony_ci		e->msi.address_hi = ue->u.msi.address_hi;
13762306a36Sopenharmony_ci		e->msi.data = ue->u.msi.data;
13862306a36Sopenharmony_ci		e->msi.flags = ue->flags;
13962306a36Sopenharmony_ci		e->msi.devid = ue->u.msi.devid;
14062306a36Sopenharmony_ci		break;
14162306a36Sopenharmony_ci	default:
14262306a36Sopenharmony_ci		goto out;
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci	r = 0;
14562306a36Sopenharmony_ciout:
14662306a36Sopenharmony_ci	return r;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ciint kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
15062306a36Sopenharmony_ci			      struct kvm *kvm, int irq_source_id, int level,
15162306a36Sopenharmony_ci			      bool line_status)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	if (!level)
15462306a36Sopenharmony_ci		return -EWOULDBLOCK;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	switch (e->type) {
15762306a36Sopenharmony_ci	case KVM_IRQ_ROUTING_MSI:
15862306a36Sopenharmony_ci		return kvm_set_msi(e, kvm, irq_source_id, level, line_status);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	case KVM_IRQ_ROUTING_IRQCHIP:
16162306a36Sopenharmony_ci		return kvm_riscv_set_irq(e, kvm, irq_source_id,
16262306a36Sopenharmony_ci					 level, line_status);
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	return -EWOULDBLOCK;
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cibool kvm_arch_irqchip_in_kernel(struct kvm *kvm)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	return irqchip_in_kernel(kvm);
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ciint kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
17462306a36Sopenharmony_ci{
17562306a36Sopenharmony_ci	int r;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	switch (ext) {
17862306a36Sopenharmony_ci	case KVM_CAP_IRQCHIP:
17962306a36Sopenharmony_ci		r = kvm_riscv_aia_available();
18062306a36Sopenharmony_ci		break;
18162306a36Sopenharmony_ci	case KVM_CAP_IOEVENTFD:
18262306a36Sopenharmony_ci	case KVM_CAP_DEVICE_CTRL:
18362306a36Sopenharmony_ci	case KVM_CAP_USER_MEMORY:
18462306a36Sopenharmony_ci	case KVM_CAP_SYNC_MMU:
18562306a36Sopenharmony_ci	case KVM_CAP_DESTROY_MEMORY_REGION_WORKS:
18662306a36Sopenharmony_ci	case KVM_CAP_ONE_REG:
18762306a36Sopenharmony_ci	case KVM_CAP_READONLY_MEM:
18862306a36Sopenharmony_ci	case KVM_CAP_MP_STATE:
18962306a36Sopenharmony_ci	case KVM_CAP_IMMEDIATE_EXIT:
19062306a36Sopenharmony_ci		r = 1;
19162306a36Sopenharmony_ci		break;
19262306a36Sopenharmony_ci	case KVM_CAP_NR_VCPUS:
19362306a36Sopenharmony_ci		r = min_t(unsigned int, num_online_cpus(), KVM_MAX_VCPUS);
19462306a36Sopenharmony_ci		break;
19562306a36Sopenharmony_ci	case KVM_CAP_MAX_VCPUS:
19662306a36Sopenharmony_ci		r = KVM_MAX_VCPUS;
19762306a36Sopenharmony_ci		break;
19862306a36Sopenharmony_ci	case KVM_CAP_NR_MEMSLOTS:
19962306a36Sopenharmony_ci		r = KVM_USER_MEM_SLOTS;
20062306a36Sopenharmony_ci		break;
20162306a36Sopenharmony_ci	case KVM_CAP_VM_GPA_BITS:
20262306a36Sopenharmony_ci		r = kvm_riscv_gstage_gpa_bits();
20362306a36Sopenharmony_ci		break;
20462306a36Sopenharmony_ci	default:
20562306a36Sopenharmony_ci		r = 0;
20662306a36Sopenharmony_ci		break;
20762306a36Sopenharmony_ci	}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	return r;
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ciint kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	return -EINVAL;
21562306a36Sopenharmony_ci}
216