1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (C) 2019 Western Digital Corporation or its affiliates. |
4 | * |
5 | * Authors: |
6 | * Anup Patel <anup.patel@wdc.com> |
7 | */ |
8 | |
9 | #include <linux/errno.h> |
10 | #include <linux/err.h> |
11 | #include <linux/module.h> |
12 | #include <linux/uaccess.h> |
13 | #include <linux/kvm_host.h> |
14 | |
15 | const struct _kvm_stats_desc kvm_vm_stats_desc[] = { |
16 | KVM_GENERIC_VM_STATS() |
17 | }; |
18 | static_assert(ARRAY_SIZE(kvm_vm_stats_desc) == |
19 | sizeof(struct kvm_vm_stat) / sizeof(u64)); |
20 | |
21 | const struct kvm_stats_header = { |
22 | .name_size = KVM_STATS_NAME_SIZE, |
23 | .num_desc = ARRAY_SIZE(kvm_vm_stats_desc), |
24 | .id_offset = sizeof(struct kvm_stats_header), |
25 | .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE, |
26 | .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE + |
27 | sizeof(kvm_vm_stats_desc), |
28 | }; |
29 | |
30 | int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) |
31 | { |
32 | int r; |
33 | |
34 | r = kvm_riscv_gstage_alloc_pgd(kvm); |
35 | if (r) |
36 | return r; |
37 | |
38 | r = kvm_riscv_gstage_vmid_init(kvm); |
39 | if (r) { |
40 | kvm_riscv_gstage_free_pgd(kvm); |
41 | return r; |
42 | } |
43 | |
44 | kvm_riscv_aia_init_vm(kvm); |
45 | |
46 | kvm_riscv_guest_timer_init(kvm); |
47 | |
48 | return 0; |
49 | } |
50 | |
51 | void kvm_arch_destroy_vm(struct kvm *kvm) |
52 | { |
53 | kvm_destroy_vcpus(kvm); |
54 | |
55 | kvm_riscv_aia_destroy_vm(kvm); |
56 | } |
57 | |
58 | int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irql, |
59 | bool line_status) |
60 | { |
61 | if (!irqchip_in_kernel(kvm)) |
62 | return -ENXIO; |
63 | |
64 | return kvm_riscv_aia_inject_irq(kvm, irql->irq, irql->level); |
65 | } |
66 | |
67 | int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, |
68 | struct kvm *kvm, int irq_source_id, |
69 | int level, bool line_status) |
70 | { |
71 | struct kvm_msi msi; |
72 | |
73 | if (!level) |
74 | return -1; |
75 | |
76 | msi.address_lo = e->msi.address_lo; |
77 | msi.address_hi = e->msi.address_hi; |
78 | msi.data = e->msi.data; |
79 | msi.flags = e->msi.flags; |
80 | msi.devid = e->msi.devid; |
81 | |
82 | return kvm_riscv_aia_inject_msi(kvm, &msi); |
83 | } |
84 | |
85 | static int kvm_riscv_set_irq(struct kvm_kernel_irq_routing_entry *e, |
86 | struct kvm *kvm, int irq_source_id, |
87 | int level, bool line_status) |
88 | { |
89 | return kvm_riscv_aia_inject_irq(kvm, e->irqchip.pin, level); |
90 | } |
91 | |
92 | int kvm_riscv_setup_default_irq_routing(struct kvm *kvm, u32 lines) |
93 | { |
94 | struct kvm_irq_routing_entry *ents; |
95 | int i, rc; |
96 | |
97 | ents = kcalloc(n: lines, size: sizeof(*ents), GFP_KERNEL); |
98 | if (!ents) |
99 | return -ENOMEM; |
100 | |
101 | for (i = 0; i < lines; i++) { |
102 | ents[i].gsi = i; |
103 | ents[i].type = KVM_IRQ_ROUTING_IRQCHIP; |
104 | ents[i].u.irqchip.irqchip = 0; |
105 | ents[i].u.irqchip.pin = i; |
106 | } |
107 | rc = kvm_set_irq_routing(kvm, entries: ents, nr: lines, flags: 0); |
108 | kfree(objp: ents); |
109 | |
110 | return rc; |
111 | } |
112 | |
113 | bool kvm_arch_can_set_irq_routing(struct kvm *kvm) |
114 | { |
115 | return irqchip_in_kernel(kvm); |
116 | } |
117 | |
118 | int kvm_set_routing_entry(struct kvm *kvm, |
119 | struct kvm_kernel_irq_routing_entry *e, |
120 | const struct kvm_irq_routing_entry *ue) |
121 | { |
122 | int r = -EINVAL; |
123 | |
124 | switch (ue->type) { |
125 | case KVM_IRQ_ROUTING_IRQCHIP: |
126 | e->set = kvm_riscv_set_irq; |
127 | e->irqchip.irqchip = ue->u.irqchip.irqchip; |
128 | e->irqchip.pin = ue->u.irqchip.pin; |
129 | if ((e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS) || |
130 | (e->irqchip.irqchip >= KVM_NR_IRQCHIPS)) |
131 | goto out; |
132 | break; |
133 | case KVM_IRQ_ROUTING_MSI: |
134 | e->set = kvm_set_msi; |
135 | e->msi.address_lo = ue->u.msi.address_lo; |
136 | e->msi.address_hi = ue->u.msi.address_hi; |
137 | e->msi.data = ue->u.msi.data; |
138 | e->msi.flags = ue->flags; |
139 | e->msi.devid = ue->u.msi.devid; |
140 | break; |
141 | default: |
142 | goto out; |
143 | } |
144 | r = 0; |
145 | out: |
146 | return r; |
147 | } |
148 | |
149 | int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e, |
150 | struct kvm *kvm, int irq_source_id, int level, |
151 | bool line_status) |
152 | { |
153 | if (!level) |
154 | return -EWOULDBLOCK; |
155 | |
156 | switch (e->type) { |
157 | case KVM_IRQ_ROUTING_MSI: |
158 | return kvm_set_msi(e, kvm, irq_source_id, level, line_status); |
159 | |
160 | case KVM_IRQ_ROUTING_IRQCHIP: |
161 | return kvm_riscv_set_irq(e, kvm, irq_source_id, |
162 | level, line_status); |
163 | } |
164 | |
165 | return -EWOULDBLOCK; |
166 | } |
167 | |
168 | bool kvm_arch_irqchip_in_kernel(struct kvm *kvm) |
169 | { |
170 | return irqchip_in_kernel(kvm); |
171 | } |
172 | |
173 | int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) |
174 | { |
175 | int r; |
176 | |
177 | switch (ext) { |
178 | case KVM_CAP_IRQCHIP: |
179 | r = kvm_riscv_aia_available(); |
180 | break; |
181 | case KVM_CAP_IOEVENTFD: |
182 | case KVM_CAP_USER_MEMORY: |
183 | case KVM_CAP_SYNC_MMU: |
184 | case KVM_CAP_DESTROY_MEMORY_REGION_WORKS: |
185 | case KVM_CAP_ONE_REG: |
186 | case KVM_CAP_READONLY_MEM: |
187 | case KVM_CAP_MP_STATE: |
188 | case KVM_CAP_IMMEDIATE_EXIT: |
189 | r = 1; |
190 | break; |
191 | case KVM_CAP_NR_VCPUS: |
192 | r = min_t(unsigned int, num_online_cpus(), KVM_MAX_VCPUS); |
193 | break; |
194 | case KVM_CAP_MAX_VCPUS: |
195 | r = KVM_MAX_VCPUS; |
196 | break; |
197 | case KVM_CAP_NR_MEMSLOTS: |
198 | r = KVM_USER_MEM_SLOTS; |
199 | break; |
200 | case KVM_CAP_VM_GPA_BITS: |
201 | r = kvm_riscv_gstage_gpa_bits(); |
202 | break; |
203 | default: |
204 | r = 0; |
205 | break; |
206 | } |
207 | |
208 | return r; |
209 | } |
210 | |
211 | int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) |
212 | { |
213 | return -EINVAL; |
214 | } |
215 | |