Skip to content

Commit 73516e9

Browse files
bibo-maochenhuacai
authored andcommitted
LoongArch: KVM: Add vcpu mapping from physical cpuid
Physical CPUID is used for interrupt routing for irqchips such as ipi, msgint and eiointc interrupt controllers. Physical CPUID is stored at the CSR register LOONGARCH_CSR_CPUID, it can not be changed once vcpu is created and the physical CPUIDs of two vcpus cannot be the same. Different irqchips have different size declaration about physical CPUID, the max CPUID value for CSR LOONGARCH_CSR_CPUID on Loongson-3A5000 is 512, the max CPUID supported by IPI hardware is 1024, while for eiointc irqchip is 256, and for msgint irqchip is 65536. The smallest value from all interrupt controllers is selected now, and the max cpuid size is defines as 256 by KVM which comes from the eiointc irqchip. Signed-off-by: Bibo Mao <[email protected]> Signed-off-by: Huacai Chen <[email protected]>
1 parent 9753d30 commit 73516e9

File tree

4 files changed

+129
-0
lines changed

4 files changed

+129
-0
lines changed

arch/loongarch/include/asm/kvm_host.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,40 @@ struct kvm_world_switch {
6464

6565
#define MAX_PGTABLE_LEVELS 4
6666

67+
/*
68+
* Physical CPUID is used for interrupt routing, there are different
69+
* definitions about physical cpuid on different hardwares.
70+
*
71+
* For LOONGARCH_CSR_CPUID register, max CPUID size if 512
72+
* For IPI hardware, max destination CPUID size 1024
73+
* For extioi interrupt controller, max destination CPUID size is 256
74+
* For msgint interrupt controller, max supported CPUID size is 65536
75+
*
76+
* Currently max CPUID is defined as 256 for KVM hypervisor, in future
77+
* it will be expanded to 4096, including 16 packages at most. And every
78+
* package supports at most 256 vcpus
79+
*/
80+
#define KVM_MAX_PHYID 256
81+
82+
struct kvm_phyid_info {
83+
struct kvm_vcpu *vcpu;
84+
bool enabled;
85+
};
86+
87+
struct kvm_phyid_map {
88+
int max_phyid;
89+
struct kvm_phyid_info phys_map[KVM_MAX_PHYID];
90+
};
91+
6792
struct kvm_arch {
6893
/* Guest physical mm */
6994
kvm_pte_t *pgd;
7095
unsigned long gpa_size;
7196
unsigned long invalid_ptes[MAX_PGTABLE_LEVELS];
7297
unsigned int pte_shifts[MAX_PGTABLE_LEVELS];
7398
unsigned int root_level;
99+
spinlock_t phyid_map_lock;
100+
struct kvm_phyid_map *phyid_map;
74101

75102
s64 time_offset;
76103
struct kvm_context __percpu *vmcs;

arch/loongarch/include/asm/kvm_vcpu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ void kvm_save_timer(struct kvm_vcpu *vcpu);
8181
void kvm_restore_timer(struct kvm_vcpu *vcpu);
8282

8383
int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq);
84+
struct kvm_vcpu *kvm_get_vcpu_by_cpuid(struct kvm *kvm, int cpuid);
8485

8586
/*
8687
* Loongarch KVM guest interrupt handling

arch/loongarch/kvm/vcpu.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,92 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
250250
return -EINVAL;
251251
}
252252

253+
static inline int kvm_set_cpuid(struct kvm_vcpu *vcpu, u64 val)
254+
{
255+
int cpuid;
256+
struct kvm_phyid_map *map;
257+
struct loongarch_csrs *csr = vcpu->arch.csr;
258+
259+
if (val >= KVM_MAX_PHYID)
260+
return -EINVAL;
261+
262+
map = vcpu->kvm->arch.phyid_map;
263+
cpuid = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_CPUID);
264+
265+
spin_lock(&vcpu->kvm->arch.phyid_map_lock);
266+
if ((cpuid < KVM_MAX_PHYID) && map->phys_map[cpuid].enabled) {
267+
/* Discard duplicated CPUID set operation */
268+
if (cpuid == val) {
269+
spin_unlock(&vcpu->kvm->arch.phyid_map_lock);
270+
return 0;
271+
}
272+
273+
/*
274+
* CPUID is already set before
275+
* Forbid changing to a different CPUID at runtime
276+
*/
277+
spin_unlock(&vcpu->kvm->arch.phyid_map_lock);
278+
return -EINVAL;
279+
}
280+
281+
if (map->phys_map[val].enabled) {
282+
/* Discard duplicated CPUID set operation */
283+
if (vcpu == map->phys_map[val].vcpu) {
284+
spin_unlock(&vcpu->kvm->arch.phyid_map_lock);
285+
return 0;
286+
}
287+
288+
/*
289+
* New CPUID is already set with other vcpu
290+
* Forbid sharing the same CPUID between different vcpus
291+
*/
292+
spin_unlock(&vcpu->kvm->arch.phyid_map_lock);
293+
return -EINVAL;
294+
}
295+
296+
kvm_write_sw_gcsr(csr, LOONGARCH_CSR_CPUID, val);
297+
map->phys_map[val].enabled = true;
298+
map->phys_map[val].vcpu = vcpu;
299+
spin_unlock(&vcpu->kvm->arch.phyid_map_lock);
300+
301+
return 0;
302+
}
303+
304+
static inline void kvm_drop_cpuid(struct kvm_vcpu *vcpu)
305+
{
306+
int cpuid;
307+
struct kvm_phyid_map *map;
308+
struct loongarch_csrs *csr = vcpu->arch.csr;
309+
310+
map = vcpu->kvm->arch.phyid_map;
311+
cpuid = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_CPUID);
312+
313+
if (cpuid >= KVM_MAX_PHYID)
314+
return;
315+
316+
spin_lock(&vcpu->kvm->arch.phyid_map_lock);
317+
if (map->phys_map[cpuid].enabled) {
318+
map->phys_map[cpuid].vcpu = NULL;
319+
map->phys_map[cpuid].enabled = false;
320+
kvm_write_sw_gcsr(csr, LOONGARCH_CSR_CPUID, KVM_MAX_PHYID);
321+
}
322+
spin_unlock(&vcpu->kvm->arch.phyid_map_lock);
323+
}
324+
325+
struct kvm_vcpu *kvm_get_vcpu_by_cpuid(struct kvm *kvm, int cpuid)
326+
{
327+
struct kvm_phyid_map *map;
328+
329+
if (cpuid >= KVM_MAX_PHYID)
330+
return NULL;
331+
332+
map = kvm->arch.phyid_map;
333+
if (!map->phys_map[cpuid].enabled)
334+
return NULL;
335+
336+
return map->phys_map[cpuid].vcpu;
337+
}
338+
253339
static int _kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *val)
254340
{
255341
unsigned long gintc;
@@ -282,6 +368,9 @@ static int _kvm_setcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 val)
282368
if (get_gcsr_flag(id) & INVALID_GCSR)
283369
return -EINVAL;
284370

371+
if (id == LOONGARCH_CSR_CPUID)
372+
return kvm_set_cpuid(vcpu, val);
373+
285374
if (id == LOONGARCH_CSR_ESTAT) {
286375
/* ESTAT IP0~IP7 inject through GINTC */
287376
gintc = (val >> 2) & 0xff;
@@ -924,6 +1013,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
9241013

9251014
/* Set cpuid */
9261015
kvm_write_sw_gcsr(csr, LOONGARCH_CSR_TMID, vcpu->vcpu_id);
1016+
kvm_write_sw_gcsr(csr, LOONGARCH_CSR_CPUID, KVM_MAX_PHYID);
9271017

9281018
/* Start with no pending virtual guest interrupts */
9291019
csr->csrs[LOONGARCH_CSR_GINTC] = 0;
@@ -942,6 +1032,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
9421032

9431033
hrtimer_cancel(&vcpu->arch.swtimer);
9441034
kvm_mmu_free_memory_cache(&vcpu->arch.mmu_page_cache);
1035+
kvm_drop_cpuid(vcpu);
9451036
kfree(vcpu->arch.csr);
9461037

9471038
/*

arch/loongarch/kvm/vm.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
3030
if (!kvm->arch.pgd)
3131
return -ENOMEM;
3232

33+
kvm->arch.phyid_map = kvzalloc(sizeof(struct kvm_phyid_map), GFP_KERNEL_ACCOUNT);
34+
if (!kvm->arch.phyid_map) {
35+
free_page((unsigned long)kvm->arch.pgd);
36+
kvm->arch.pgd = NULL;
37+
return -ENOMEM;
38+
}
39+
spin_lock_init(&kvm->arch.phyid_map_lock);
40+
3341
kvm_init_vmcs(kvm);
3442
kvm->arch.gpa_size = BIT(cpu_vabits - 1);
3543
kvm->arch.root_level = CONFIG_PGTABLE_LEVELS - 1;
@@ -52,6 +60,8 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
5260
kvm_destroy_vcpus(kvm);
5361
free_page((unsigned long)kvm->arch.pgd);
5462
kvm->arch.pgd = NULL;
63+
kvfree(kvm->arch.phyid_map);
64+
kvm->arch.phyid_map = NULL;
5565
}
5666

5767
int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)

0 commit comments

Comments
 (0)