Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: PPC: Book3S HV: Host-side RM data structures

This patch defines the data structures to support the setting up
of host side operations while running in real mode in the guest,
and also the functions to allocate and free it.

The operations are for now limited to virtual XICS operations.
Currently, we have only defined one operation in the data
structure:
- Wake up a VCPU sleeping in the host when it
receives a virtual interrupt

The operations are assigned at the core level because PowerKVM
requires that the host run in SMT off mode. For each core,
we will need to manage its state atomically - where the state
is defined by:
1. Is the core running in the host?
2. Is there a Real Mode (RM) operation pending on the host?

Currently, core state is only managed at the whole-core level
even when the system is in split-core mode. This just limits
the number of free or "available" cores in the host to perform
any host-side operations.

The kvmppc_host_rm_core.rm_data allows any data to be passed by
KVM in real mode to the host core along with the operation to
be performed.

The kvmppc_host_rm_ops structure is allocated the very first time
a guest VM is started. Initial core state is also set - all online
cores are in the host. This structure is never deleted, not even
when there are no active guests. However, it needs to be freed
when the module is unloaded because the kvmppc_host_rm_ops_hv
can contain function pointers to kvm-hv.ko functions for the
different supported host operations.

Signed-off-by: Suresh Warrier <warrier@linux.vnet.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>

authored by

Suresh Warrier and committed by
Paul Mackerras
79b6c247 ec13e9b6

+104
+31
arch/powerpc/include/asm/kvm_ppc.h
··· 453 453 { 454 454 return vcpu->arch.irq_type == KVMPPC_IRQ_XICS; 455 455 } 456 + extern void kvmppc_alloc_host_rm_ops(void); 457 + extern void kvmppc_free_host_rm_ops(void); 456 458 extern void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu); 457 459 extern int kvmppc_xics_create_icp(struct kvm_vcpu *vcpu, unsigned long server); 458 460 extern int kvm_vm_ioctl_xics_irq(struct kvm *kvm, struct kvm_irq_level *args); ··· 464 462 extern int kvmppc_xics_connect_vcpu(struct kvm_device *dev, 465 463 struct kvm_vcpu *vcpu, u32 cpu); 466 464 #else 465 + static inline void kvmppc_alloc_host_rm_ops(void) {}; 466 + static inline void kvmppc_free_host_rm_ops(void) {}; 467 467 static inline int kvmppc_xics_enabled(struct kvm_vcpu *vcpu) 468 468 { return 0; } 469 469 static inline void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu) { } ··· 478 474 static inline int kvmppc_xics_hcall(struct kvm_vcpu *vcpu, u32 cmd) 479 475 { return 0; } 480 476 #endif 477 + 478 + /* 479 + * Host-side operations we want to set up while running in real 480 + * mode in the guest operating on the xics. 481 + * Currently only VCPU wakeup is supported. 482 + */ 483 + 484 + union kvmppc_rm_state { 485 + unsigned long raw; 486 + struct { 487 + u32 in_host; 488 + u32 rm_action; 489 + }; 490 + }; 491 + 492 + struct kvmppc_host_rm_core { 493 + union kvmppc_rm_state rm_state; 494 + void *rm_data; 495 + char pad[112]; 496 + }; 497 + 498 + struct kvmppc_host_rm_ops { 499 + struct kvmppc_host_rm_core *rm_core; 500 + void (*vcpu_kick)(struct kvm_vcpu *vcpu); 501 + }; 502 + 503 + extern struct kvmppc_host_rm_ops *kvmppc_host_rm_ops_hv; 481 504 482 505 static inline unsigned long kvmppc_get_epr(struct kvm_vcpu *vcpu) 483 506 {
+70
arch/powerpc/kvm/book3s_hv.c
··· 3008 3008 goto out_srcu; 3009 3009 } 3010 3010 3011 + #ifdef CONFIG_KVM_XICS 3012 + /* 3013 + * Allocate a per-core structure for managing state about which cores are 3014 + * running in the host versus the guest and for exchanging data between 3015 + * real mode KVM and CPU running in the host. 3016 + * This is only done for the first VM. 3017 + * The allocated structure stays even if all VMs have stopped. 3018 + * It is only freed when the kvm-hv module is unloaded. 3019 + * It's OK for this routine to fail, we just don't support host 3020 + * core operations like redirecting H_IPI wakeups. 3021 + */ 3022 + void kvmppc_alloc_host_rm_ops(void) 3023 + { 3024 + struct kvmppc_host_rm_ops *ops; 3025 + unsigned long l_ops; 3026 + int cpu, core; 3027 + int size; 3028 + 3029 + /* Not the first time here ? */ 3030 + if (kvmppc_host_rm_ops_hv != NULL) 3031 + return; 3032 + 3033 + ops = kzalloc(sizeof(struct kvmppc_host_rm_ops), GFP_KERNEL); 3034 + if (!ops) 3035 + return; 3036 + 3037 + size = cpu_nr_cores() * sizeof(struct kvmppc_host_rm_core); 3038 + ops->rm_core = kzalloc(size, GFP_KERNEL); 3039 + 3040 + if (!ops->rm_core) { 3041 + kfree(ops); 3042 + return; 3043 + } 3044 + 3045 + for (cpu = 0; cpu < nr_cpu_ids; cpu += threads_per_core) { 3046 + if (!cpu_online(cpu)) 3047 + continue; 3048 + 3049 + core = cpu >> threads_shift; 3050 + ops->rm_core[core].rm_state.in_host = 1; 3051 + } 3052 + 3053 + /* 3054 + * Make the contents of the kvmppc_host_rm_ops structure visible 3055 + * to other CPUs before we assign it to the global variable. 3056 + * Do an atomic assignment (no locks used here), but if someone 3057 + * beats us to it, just free our copy and return. 3058 + */ 3059 + smp_wmb(); 3060 + l_ops = (unsigned long) ops; 3061 + 3062 + if (cmpxchg64((unsigned long *)&kvmppc_host_rm_ops_hv, 0, l_ops)) { 3063 + kfree(ops->rm_core); 3064 + kfree(ops); 3065 + } 3066 + } 3067 + 3068 + void kvmppc_free_host_rm_ops(void) 3069 + { 3070 + if (kvmppc_host_rm_ops_hv) { 3071 + kfree(kvmppc_host_rm_ops_hv->rm_core); 3072 + kfree(kvmppc_host_rm_ops_hv); 3073 + kvmppc_host_rm_ops_hv = NULL; 3074 + } 3075 + } 3076 + #endif 3077 + 3011 3078 static int kvmppc_core_init_vm_hv(struct kvm *kvm) 3012 3079 { 3013 3080 unsigned long lpcr, lpid; ··· 3086 3019 if ((long)lpid < 0) 3087 3020 return -ENOMEM; 3088 3021 kvm->arch.lpid = lpid; 3022 + 3023 + kvmppc_alloc_host_rm_ops(); 3089 3024 3090 3025 /* 3091 3026 * Since we don't flush the TLB when tearing down a VM, ··· 3322 3253 3323 3254 static void kvmppc_book3s_exit_hv(void) 3324 3255 { 3256 + kvmppc_free_host_rm_ops(); 3325 3257 kvmppc_hv_ops = NULL; 3326 3258 } 3327 3259
+3
arch/powerpc/kvm/book3s_hv_builtin.c
··· 283 283 kvmhv_interrupt_vcore(vc, ee); 284 284 } 285 285 } 286 + 287 + struct kvmppc_host_rm_ops *kvmppc_host_rm_ops_hv; 288 + EXPORT_SYMBOL_GPL(kvmppc_host_rm_ops_hv);