1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 273196cd3SScott Wood /* 3c7ba7771SMihai Caraman * Copyright (C) 2010,2012 Freescale Semiconductor, Inc. All rights reserved. 473196cd3SScott Wood * 573196cd3SScott Wood * Author: Varun Sethi, <varun.sethi@freescale.com> 673196cd3SScott Wood * 773196cd3SScott Wood * Description: 873196cd3SScott Wood * This file is derived from arch/powerpc/kvm/e500.c, 973196cd3SScott Wood * by Yu Liu <yu.liu@freescale.com>. 1073196cd3SScott Wood */ 1173196cd3SScott Wood 1273196cd3SScott Wood #include <linux/kvm_host.h> 1373196cd3SScott Wood #include <linux/slab.h> 1473196cd3SScott Wood #include <linux/err.h> 1573196cd3SScott Wood #include <linux/export.h> 16398a76c6SAlexander Graf #include <linux/miscdevice.h> 17398a76c6SAlexander Graf #include <linux/module.h> 1873196cd3SScott Wood 1973196cd3SScott Wood #include <asm/reg.h> 2073196cd3SScott Wood #include <asm/cputable.h> 2173196cd3SScott Wood #include <asm/kvm_ppc.h> 2273196cd3SScott Wood #include <asm/dbell.h> 2373196cd3SScott Wood 2473196cd3SScott Wood #include "booke.h" 2573196cd3SScott Wood #include "e500.h" 2673196cd3SScott Wood 2773196cd3SScott Wood void kvmppc_set_pending_interrupt(struct kvm_vcpu *vcpu, enum int_class type) 2873196cd3SScott Wood { 2973196cd3SScott Wood enum ppc_dbell dbell_type; 3073196cd3SScott Wood unsigned long tag; 3173196cd3SScott Wood 3273196cd3SScott Wood switch (type) { 3373196cd3SScott Wood case INT_CLASS_NONCRIT: 3473196cd3SScott Wood dbell_type = PPC_G_DBELL; 3573196cd3SScott Wood break; 3673196cd3SScott Wood case INT_CLASS_CRIT: 3773196cd3SScott Wood dbell_type = PPC_G_DBELL_CRIT; 3873196cd3SScott Wood break; 3973196cd3SScott Wood case INT_CLASS_MC: 4073196cd3SScott Wood dbell_type = PPC_G_DBELL_MC; 4173196cd3SScott Wood break; 4273196cd3SScott Wood default: 4373196cd3SScott Wood WARN_ONCE(1, "%s: unknown int type %d\n", __func__, type); 4473196cd3SScott Wood return; 4573196cd3SScott Wood } 4673196cd3SScott Wood 47188e267cSMihai Caraman preempt_disable(); 48188e267cSMihai Caraman tag = PPC_DBELL_LPID(get_lpid(vcpu)) | vcpu->vcpu_id; 4973196cd3SScott Wood mb(); 5073196cd3SScott Wood ppc_msgsnd(dbell_type, 0, tag); 51188e267cSMihai Caraman preempt_enable(); 5273196cd3SScott Wood } 5373196cd3SScott Wood 5473196cd3SScott Wood /* gtlbe must not be mapped by more than one host tlb entry */ 5573196cd3SScott Wood void kvmppc_e500_tlbil_one(struct kvmppc_vcpu_e500 *vcpu_e500, 5673196cd3SScott Wood struct kvm_book3e_206_tlb_entry *gtlbe) 5773196cd3SScott Wood { 5873196cd3SScott Wood unsigned int tid, ts; 5966c9897dSMihai Caraman gva_t eaddr; 60188e267cSMihai Caraman u32 val; 6173196cd3SScott Wood unsigned long flags; 6273196cd3SScott Wood 6373196cd3SScott Wood ts = get_tlb_ts(gtlbe); 6473196cd3SScott Wood tid = get_tlb_tid(gtlbe); 6573196cd3SScott Wood 6673196cd3SScott Wood /* We search the host TLB to invalidate its shadow TLB entry */ 6773196cd3SScott Wood val = (tid << 16) | ts; 6873196cd3SScott Wood eaddr = get_tlb_eaddr(gtlbe); 6973196cd3SScott Wood 7073196cd3SScott Wood local_irq_save(flags); 7173196cd3SScott Wood 7273196cd3SScott Wood mtspr(SPRN_MAS6, val); 73188e267cSMihai Caraman mtspr(SPRN_MAS5, MAS5_SGS | get_lpid(&vcpu_e500->vcpu)); 7473196cd3SScott Wood 7573196cd3SScott Wood asm volatile("tlbsx 0, %[eaddr]\n" : : [eaddr] "r" (eaddr)); 7673196cd3SScott Wood val = mfspr(SPRN_MAS1); 7773196cd3SScott Wood if (val & MAS1_VALID) { 7873196cd3SScott Wood mtspr(SPRN_MAS1, val & ~MAS1_VALID); 7973196cd3SScott Wood asm volatile("tlbwe"); 8073196cd3SScott Wood } 8173196cd3SScott Wood mtspr(SPRN_MAS5, 0); 8273196cd3SScott Wood /* NOTE: tlbsx also updates mas8, so clear it for host tlbwe */ 8373196cd3SScott Wood mtspr(SPRN_MAS8, 0); 8473196cd3SScott Wood isync(); 8573196cd3SScott Wood 8673196cd3SScott Wood local_irq_restore(flags); 8773196cd3SScott Wood } 8873196cd3SScott Wood 8973196cd3SScott Wood void kvmppc_e500_tlbil_all(struct kvmppc_vcpu_e500 *vcpu_e500) 9073196cd3SScott Wood { 9173196cd3SScott Wood unsigned long flags; 9273196cd3SScott Wood 9373196cd3SScott Wood local_irq_save(flags); 94188e267cSMihai Caraman mtspr(SPRN_MAS5, MAS5_SGS | get_lpid(&vcpu_e500->vcpu)); 9573196cd3SScott Wood asm volatile("tlbilxlpid"); 9673196cd3SScott Wood mtspr(SPRN_MAS5, 0); 9773196cd3SScott Wood local_irq_restore(flags); 9873196cd3SScott Wood } 9973196cd3SScott Wood 10073196cd3SScott Wood void kvmppc_set_pid(struct kvm_vcpu *vcpu, u32 pid) 10173196cd3SScott Wood { 10273196cd3SScott Wood vcpu->arch.pid = pid; 10373196cd3SScott Wood } 10473196cd3SScott Wood 10573196cd3SScott Wood void kvmppc_mmu_msr_notify(struct kvm_vcpu *vcpu, u32 old_msr) 10673196cd3SScott Wood { 10773196cd3SScott Wood } 10873196cd3SScott Wood 109188e267cSMihai Caraman /* We use two lpids per VM */ 1101f0eeb7eSMihai Caraman static DEFINE_PER_CPU(struct kvm_vcpu *[KVMPPC_NR_LPIDS], last_vcpu_of_lpid); 111c5e6cb05SScott Wood 1123a167beaSAneesh Kumar K.V static void kvmppc_core_vcpu_load_e500mc(struct kvm_vcpu *vcpu, int cpu) 11373196cd3SScott Wood { 11473196cd3SScott Wood struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); 11573196cd3SScott Wood 11673196cd3SScott Wood kvmppc_booke_vcpu_load(vcpu, cpu); 11773196cd3SScott Wood 118188e267cSMihai Caraman mtspr(SPRN_LPID, get_lpid(vcpu)); 11973196cd3SScott Wood mtspr(SPRN_EPCR, vcpu->arch.shadow_epcr); 12073196cd3SScott Wood mtspr(SPRN_GPIR, vcpu->vcpu_id); 12173196cd3SScott Wood mtspr(SPRN_MSRP, vcpu->arch.shadow_msrp); 122188e267cSMihai Caraman vcpu->arch.eplc = EPC_EGS | (get_lpid(vcpu) << EPC_ELPID_SHIFT); 123188e267cSMihai Caraman vcpu->arch.epsc = vcpu->arch.eplc; 12473196cd3SScott Wood mtspr(SPRN_EPLC, vcpu->arch.eplc); 12573196cd3SScott Wood mtspr(SPRN_EPSC, vcpu->arch.epsc); 12673196cd3SScott Wood 12773196cd3SScott Wood mtspr(SPRN_GIVPR, vcpu->arch.ivpr); 12873196cd3SScott Wood mtspr(SPRN_GIVOR2, vcpu->arch.ivor[BOOKE_IRQPRIO_DATA_STORAGE]); 12973196cd3SScott Wood mtspr(SPRN_GIVOR8, vcpu->arch.ivor[BOOKE_IRQPRIO_SYSCALL]); 13073196cd3SScott Wood mtspr(SPRN_GSPRG0, (unsigned long)vcpu->arch.shared->sprg0); 13173196cd3SScott Wood mtspr(SPRN_GSPRG1, (unsigned long)vcpu->arch.shared->sprg1); 13273196cd3SScott Wood mtspr(SPRN_GSPRG2, (unsigned long)vcpu->arch.shared->sprg2); 13373196cd3SScott Wood mtspr(SPRN_GSPRG3, (unsigned long)vcpu->arch.shared->sprg3); 13473196cd3SScott Wood 13573196cd3SScott Wood mtspr(SPRN_GSRR0, vcpu->arch.shared->srr0); 13673196cd3SScott Wood mtspr(SPRN_GSRR1, vcpu->arch.shared->srr1); 13773196cd3SScott Wood 13873196cd3SScott Wood mtspr(SPRN_GEPR, vcpu->arch.epr); 13973196cd3SScott Wood mtspr(SPRN_GDEAR, vcpu->arch.shared->dar); 14073196cd3SScott Wood mtspr(SPRN_GESR, vcpu->arch.shared->esr); 14173196cd3SScott Wood 142c5e6cb05SScott Wood if (vcpu->arch.oldpir != mfspr(SPRN_PIR) || 14369111bacSChristoph Lameter __this_cpu_read(last_vcpu_of_lpid[get_lpid(vcpu)]) != vcpu) { 14473196cd3SScott Wood kvmppc_e500_tlbil_all(vcpu_e500); 14569111bacSChristoph Lameter __this_cpu_write(last_vcpu_of_lpid[get_lpid(vcpu)], vcpu); 146c5e6cb05SScott Wood } 14773196cd3SScott Wood } 14873196cd3SScott Wood 1493a167beaSAneesh Kumar K.V static void kvmppc_core_vcpu_put_e500mc(struct kvm_vcpu *vcpu) 15073196cd3SScott Wood { 15173196cd3SScott Wood vcpu->arch.eplc = mfspr(SPRN_EPLC); 15273196cd3SScott Wood vcpu->arch.epsc = mfspr(SPRN_EPSC); 15373196cd3SScott Wood 15473196cd3SScott Wood vcpu->arch.shared->sprg0 = mfspr(SPRN_GSPRG0); 15573196cd3SScott Wood vcpu->arch.shared->sprg1 = mfspr(SPRN_GSPRG1); 15673196cd3SScott Wood vcpu->arch.shared->sprg2 = mfspr(SPRN_GSPRG2); 15773196cd3SScott Wood vcpu->arch.shared->sprg3 = mfspr(SPRN_GSPRG3); 15873196cd3SScott Wood 15973196cd3SScott Wood vcpu->arch.shared->srr0 = mfspr(SPRN_GSRR0); 16073196cd3SScott Wood vcpu->arch.shared->srr1 = mfspr(SPRN_GSRR1); 16173196cd3SScott Wood 16273196cd3SScott Wood vcpu->arch.epr = mfspr(SPRN_GEPR); 16373196cd3SScott Wood vcpu->arch.shared->dar = mfspr(SPRN_GDEAR); 16473196cd3SScott Wood vcpu->arch.shared->esr = mfspr(SPRN_GESR); 16573196cd3SScott Wood 16673196cd3SScott Wood vcpu->arch.oldpir = mfspr(SPRN_PIR); 16773196cd3SScott Wood 16873196cd3SScott Wood kvmppc_booke_vcpu_put(vcpu); 16973196cd3SScott Wood } 17073196cd3SScott Wood 17173196cd3SScott Wood int kvmppc_core_check_processor_compat(void) 17273196cd3SScott Wood { 17373196cd3SScott Wood int r; 17473196cd3SScott Wood 17573196cd3SScott Wood if (strcmp(cur_cpu_spec->cpu_name, "e500mc") == 0) 17673196cd3SScott Wood r = 0; 17773196cd3SScott Wood else if (strcmp(cur_cpu_spec->cpu_name, "e5500") == 0) 17873196cd3SScott Wood r = 0; 179d2ca32a2SMihai Caraman #ifdef CONFIG_ALTIVEC 180d2ca32a2SMihai Caraman /* 181446957baSAdam Buchbinder * Since guests have the privilege to enable AltiVec, we need AltiVec 182d2ca32a2SMihai Caraman * support in the host to save/restore their context. 183d2ca32a2SMihai Caraman * Don't use CPU_FTR_ALTIVEC to identify cores with AltiVec unit 184d2ca32a2SMihai Caraman * because it's cleared in the absence of CONFIG_ALTIVEC! 185d2ca32a2SMihai Caraman */ 186d2ca32a2SMihai Caraman else if (strcmp(cur_cpu_spec->cpu_name, "e6500") == 0) 187d2ca32a2SMihai Caraman r = 0; 188d2ca32a2SMihai Caraman #endif 18973196cd3SScott Wood else 19073196cd3SScott Wood r = -ENOTSUPP; 19173196cd3SScott Wood 19273196cd3SScott Wood return r; 19373196cd3SScott Wood } 19473196cd3SScott Wood 19573196cd3SScott Wood int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu) 19673196cd3SScott Wood { 19773196cd3SScott Wood struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); 19873196cd3SScott Wood 19973196cd3SScott Wood vcpu->arch.shadow_epcr = SPRN_EPCR_DSIGS | SPRN_EPCR_DGTMI | \ 20073196cd3SScott Wood SPRN_EPCR_DUVD; 201c7ba7771SMihai Caraman #ifdef CONFIG_64BIT 202c7ba7771SMihai Caraman vcpu->arch.shadow_epcr |= SPRN_EPCR_ICM; 203c7ba7771SMihai Caraman #endif 20437277b11SBharat Bhushan vcpu->arch.shadow_msrp = MSRP_UCLEP | MSRP_PMMP; 20573196cd3SScott Wood 20673196cd3SScott Wood vcpu->arch.pvr = mfspr(SPRN_PVR); 20773196cd3SScott Wood vcpu_e500->svr = mfspr(SPRN_SVR); 20873196cd3SScott Wood 20973196cd3SScott Wood vcpu->arch.cpu_type = KVM_CPU_E500MC; 21073196cd3SScott Wood 21173196cd3SScott Wood return 0; 21273196cd3SScott Wood } 21373196cd3SScott Wood 2143a167beaSAneesh Kumar K.V static int kvmppc_core_get_sregs_e500mc(struct kvm_vcpu *vcpu, 2153a167beaSAneesh Kumar K.V struct kvm_sregs *sregs) 21673196cd3SScott Wood { 21773196cd3SScott Wood struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); 21873196cd3SScott Wood 21973196cd3SScott Wood sregs->u.e.features |= KVM_SREGS_E_ARCH206_MMU | KVM_SREGS_E_PM | 22073196cd3SScott Wood KVM_SREGS_E_PC; 22173196cd3SScott Wood sregs->u.e.impl_id = KVM_SREGS_E_IMPL_FSL; 22273196cd3SScott Wood 22373196cd3SScott Wood sregs->u.e.impl.fsl.features = 0; 22473196cd3SScott Wood sregs->u.e.impl.fsl.svr = vcpu_e500->svr; 22573196cd3SScott Wood sregs->u.e.impl.fsl.hid0 = vcpu_e500->hid0; 22673196cd3SScott Wood sregs->u.e.impl.fsl.mcar = vcpu_e500->mcar; 22773196cd3SScott Wood 22873196cd3SScott Wood kvmppc_get_sregs_e500_tlb(vcpu, sregs); 22973196cd3SScott Wood 23073196cd3SScott Wood sregs->u.e.ivor_high[3] = 23173196cd3SScott Wood vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR]; 23273196cd3SScott Wood sregs->u.e.ivor_high[4] = vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL]; 23373196cd3SScott Wood sregs->u.e.ivor_high[5] = vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL_CRIT]; 23473196cd3SScott Wood 2353a167beaSAneesh Kumar K.V return kvmppc_get_sregs_ivor(vcpu, sregs); 23673196cd3SScott Wood } 23773196cd3SScott Wood 2383a167beaSAneesh Kumar K.V static int kvmppc_core_set_sregs_e500mc(struct kvm_vcpu *vcpu, 2393a167beaSAneesh Kumar K.V struct kvm_sregs *sregs) 24073196cd3SScott Wood { 24173196cd3SScott Wood struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); 24273196cd3SScott Wood int ret; 24373196cd3SScott Wood 24473196cd3SScott Wood if (sregs->u.e.impl_id == KVM_SREGS_E_IMPL_FSL) { 24573196cd3SScott Wood vcpu_e500->svr = sregs->u.e.impl.fsl.svr; 24673196cd3SScott Wood vcpu_e500->hid0 = sregs->u.e.impl.fsl.hid0; 24773196cd3SScott Wood vcpu_e500->mcar = sregs->u.e.impl.fsl.mcar; 24873196cd3SScott Wood } 24973196cd3SScott Wood 25073196cd3SScott Wood ret = kvmppc_set_sregs_e500_tlb(vcpu, sregs); 25173196cd3SScott Wood if (ret < 0) 25273196cd3SScott Wood return ret; 25373196cd3SScott Wood 25473196cd3SScott Wood if (!(sregs->u.e.features & KVM_SREGS_E_IVOR)) 25573196cd3SScott Wood return 0; 25673196cd3SScott Wood 25773196cd3SScott Wood if (sregs->u.e.features & KVM_SREGS_E_PM) { 25873196cd3SScott Wood vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR] = 25973196cd3SScott Wood sregs->u.e.ivor_high[3]; 26073196cd3SScott Wood } 26173196cd3SScott Wood 26273196cd3SScott Wood if (sregs->u.e.features & KVM_SREGS_E_PC) { 26373196cd3SScott Wood vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL] = 26473196cd3SScott Wood sregs->u.e.ivor_high[4]; 26573196cd3SScott Wood vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL_CRIT] = 26673196cd3SScott Wood sregs->u.e.ivor_high[5]; 26773196cd3SScott Wood } 26873196cd3SScott Wood 26973196cd3SScott Wood return kvmppc_set_sregs_ivor(vcpu, sregs); 27073196cd3SScott Wood } 27173196cd3SScott Wood 2723a167beaSAneesh Kumar K.V static int kvmppc_get_one_reg_e500mc(struct kvm_vcpu *vcpu, u64 id, 27335b299e2SMihai Caraman union kvmppc_one_reg *val) 27435b299e2SMihai Caraman { 27528d2f421SBharat Bhushan int r = 0; 27628d2f421SBharat Bhushan 27728d2f421SBharat Bhushan switch (id) { 27828d2f421SBharat Bhushan case KVM_REG_PPC_SPRG9: 27928d2f421SBharat Bhushan *val = get_reg_val(id, vcpu->arch.sprg9); 28028d2f421SBharat Bhushan break; 28128d2f421SBharat Bhushan default: 28228d2f421SBharat Bhushan r = kvmppc_get_one_reg_e500_tlb(vcpu, id, val); 28328d2f421SBharat Bhushan } 28428d2f421SBharat Bhushan 285a85d2aa2SMihai Caraman return r; 28635b299e2SMihai Caraman } 28735b299e2SMihai Caraman 2883a167beaSAneesh Kumar K.V static int kvmppc_set_one_reg_e500mc(struct kvm_vcpu *vcpu, u64 id, 28935b299e2SMihai Caraman union kvmppc_one_reg *val) 29035b299e2SMihai Caraman { 29128d2f421SBharat Bhushan int r = 0; 29228d2f421SBharat Bhushan 29328d2f421SBharat Bhushan switch (id) { 29428d2f421SBharat Bhushan case KVM_REG_PPC_SPRG9: 29528d2f421SBharat Bhushan vcpu->arch.sprg9 = set_reg_val(id, *val); 29628d2f421SBharat Bhushan break; 29728d2f421SBharat Bhushan default: 29828d2f421SBharat Bhushan r = kvmppc_set_one_reg_e500_tlb(vcpu, id, val); 29928d2f421SBharat Bhushan } 30028d2f421SBharat Bhushan 301a85d2aa2SMihai Caraman return r; 30235b299e2SMihai Caraman } 30335b299e2SMihai Caraman 304ff030fdfSSean Christopherson static int kvmppc_core_vcpu_create_e500mc(struct kvm_vcpu *vcpu) 30573196cd3SScott Wood { 30673196cd3SScott Wood struct kvmppc_vcpu_e500 *vcpu_e500; 30773196cd3SScott Wood int err; 30873196cd3SScott Wood 3093ec8ca29SSean Christopherson BUILD_BUG_ON(offsetof(struct kvmppc_vcpu_e500, vcpu) != 0); 310c50bfbdcSSean Christopherson vcpu_e500 = to_e500(vcpu); 31173196cd3SScott Wood 3124dbf6fecSSean Christopherson /* Invalid PIR value -- this LPID dosn't have valid state on any cpu */ 3134dbf6fecSSean Christopherson vcpu->arch.oldpir = 0xffffffff; 3144dbf6fecSSean Christopherson 31573196cd3SScott Wood err = kvmppc_e500_tlb_init(vcpu_e500); 31673196cd3SScott Wood if (err) 317ff030fdfSSean Christopherson return err; 31873196cd3SScott Wood 31973196cd3SScott Wood vcpu->arch.shared = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); 32050a1a259SDan Carpenter if (!vcpu->arch.shared) { 32150a1a259SDan Carpenter err = -ENOMEM; 32273196cd3SScott Wood goto uninit_tlb; 32350a1a259SDan Carpenter } 32473196cd3SScott Wood 325c50bfbdcSSean Christopherson return 0; 32673196cd3SScott Wood 32773196cd3SScott Wood uninit_tlb: 32873196cd3SScott Wood kvmppc_e500_tlb_uninit(vcpu_e500); 329c50bfbdcSSean Christopherson return err; 33073196cd3SScott Wood } 33173196cd3SScott Wood 3323a167beaSAneesh Kumar K.V static void kvmppc_core_vcpu_free_e500mc(struct kvm_vcpu *vcpu) 33373196cd3SScott Wood { 33473196cd3SScott Wood struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); 33573196cd3SScott Wood 33673196cd3SScott Wood free_page((unsigned long)vcpu->arch.shared); 33773196cd3SScott Wood kvmppc_e500_tlb_uninit(vcpu_e500); 33873196cd3SScott Wood } 33973196cd3SScott Wood 3403a167beaSAneesh Kumar K.V static int kvmppc_core_init_vm_e500mc(struct kvm *kvm) 34173196cd3SScott Wood { 34273196cd3SScott Wood int lpid; 34373196cd3SScott Wood 34473196cd3SScott Wood lpid = kvmppc_alloc_lpid(); 34573196cd3SScott Wood if (lpid < 0) 34673196cd3SScott Wood return lpid; 34773196cd3SScott Wood 348188e267cSMihai Caraman /* 349188e267cSMihai Caraman * Use two lpids per VM on cores with two threads like e6500. Use 350188e267cSMihai Caraman * even numbers to speedup vcpu lpid computation with consecutive lpids 351188e267cSMihai Caraman * per VM. vm1 will use lpids 2 and 3, vm2 lpids 4 and 5, and so on. 352188e267cSMihai Caraman */ 353188e267cSMihai Caraman if (threads_per_core == 2) 354188e267cSMihai Caraman lpid <<= 1; 355188e267cSMihai Caraman 35673196cd3SScott Wood kvm->arch.lpid = lpid; 35773196cd3SScott Wood return 0; 35873196cd3SScott Wood } 35973196cd3SScott Wood 3603a167beaSAneesh Kumar K.V static void kvmppc_core_destroy_vm_e500mc(struct kvm *kvm) 36173196cd3SScott Wood { 362188e267cSMihai Caraman int lpid = kvm->arch.lpid; 363188e267cSMihai Caraman 364188e267cSMihai Caraman if (threads_per_core == 2) 365188e267cSMihai Caraman lpid >>= 1; 366188e267cSMihai Caraman 367188e267cSMihai Caraman kvmppc_free_lpid(lpid); 36873196cd3SScott Wood } 36973196cd3SScott Wood 3703a167beaSAneesh Kumar K.V static struct kvmppc_ops kvm_ops_e500mc = { 3713a167beaSAneesh Kumar K.V .get_sregs = kvmppc_core_get_sregs_e500mc, 3723a167beaSAneesh Kumar K.V .set_sregs = kvmppc_core_set_sregs_e500mc, 3733a167beaSAneesh Kumar K.V .get_one_reg = kvmppc_get_one_reg_e500mc, 3743a167beaSAneesh Kumar K.V .set_one_reg = kvmppc_set_one_reg_e500mc, 3753a167beaSAneesh Kumar K.V .vcpu_load = kvmppc_core_vcpu_load_e500mc, 3763a167beaSAneesh Kumar K.V .vcpu_put = kvmppc_core_vcpu_put_e500mc, 3773a167beaSAneesh Kumar K.V .vcpu_create = kvmppc_core_vcpu_create_e500mc, 3783a167beaSAneesh Kumar K.V .vcpu_free = kvmppc_core_vcpu_free_e500mc, 3793a167beaSAneesh Kumar K.V .init_vm = kvmppc_core_init_vm_e500mc, 3803a167beaSAneesh Kumar K.V .destroy_vm = kvmppc_core_destroy_vm_e500mc, 3813a167beaSAneesh Kumar K.V .emulate_op = kvmppc_core_emulate_op_e500, 3823a167beaSAneesh Kumar K.V .emulate_mtspr = kvmppc_core_emulate_mtspr_e500, 3833a167beaSAneesh Kumar K.V .emulate_mfspr = kvmppc_core_emulate_mfspr_e500, 384*faf01aefSAlexey Kardashevskiy .create_vcpu_debugfs = kvmppc_create_vcpu_debugfs_e500, 3853a167beaSAneesh Kumar K.V }; 3863a167beaSAneesh Kumar K.V 38773196cd3SScott Wood static int __init kvmppc_e500mc_init(void) 38873196cd3SScott Wood { 38973196cd3SScott Wood int r; 39073196cd3SScott Wood 39173196cd3SScott Wood r = kvmppc_booke_init(); 39273196cd3SScott Wood if (r) 3933a167beaSAneesh Kumar K.V goto err_out; 39473196cd3SScott Wood 395188e267cSMihai Caraman /* 396188e267cSMihai Caraman * Use two lpids per VM on dual threaded processors like e6500 397188e267cSMihai Caraman * to workarround the lack of tlb write conditional instruction. 398188e267cSMihai Caraman * Expose half the number of available hardware lpids to the lpid 399188e267cSMihai Caraman * allocator. 400188e267cSMihai Caraman */ 401188e267cSMihai Caraman kvmppc_init_lpid(KVMPPC_NR_LPIDS/threads_per_core); 40273196cd3SScott Wood kvmppc_claim_lpid(0); /* host */ 40373196cd3SScott Wood 404cbbc58d4SAneesh Kumar K.V r = kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE); 4053a167beaSAneesh Kumar K.V if (r) 4063a167beaSAneesh Kumar K.V goto err_out; 407cbbc58d4SAneesh Kumar K.V kvm_ops_e500mc.owner = THIS_MODULE; 408cbbc58d4SAneesh Kumar K.V kvmppc_pr_ops = &kvm_ops_e500mc; 409cbbc58d4SAneesh Kumar K.V 4103a167beaSAneesh Kumar K.V err_out: 4113a167beaSAneesh Kumar K.V return r; 41273196cd3SScott Wood } 41373196cd3SScott Wood 41473196cd3SScott Wood static void __exit kvmppc_e500mc_exit(void) 41573196cd3SScott Wood { 416cbbc58d4SAneesh Kumar K.V kvmppc_pr_ops = NULL; 41773196cd3SScott Wood kvmppc_booke_exit(); 41873196cd3SScott Wood } 41973196cd3SScott Wood 42073196cd3SScott Wood module_init(kvmppc_e500mc_init); 42173196cd3SScott Wood module_exit(kvmppc_e500mc_exit); 422398a76c6SAlexander Graf MODULE_ALIAS_MISCDEV(KVM_MINOR); 423398a76c6SAlexander Graf MODULE_ALIAS("devname:kvm"); 424