diff options
Diffstat (limited to 'arch/powerpc/kvm/powerpc.c')
| -rw-r--r-- | arch/powerpc/kvm/powerpc.c | 144 | 
1 files changed, 119 insertions, 25 deletions
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 70739a08956..6316ee336e8 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -25,6 +25,7 @@  #include <linux/hrtimer.h>  #include <linux/fs.h>  #include <linux/slab.h> +#include <linux/file.h>  #include <asm/cputable.h>  #include <asm/uaccess.h>  #include <asm/kvm_ppc.h> @@ -32,6 +33,7 @@  #include <asm/cputhreads.h>  #include <asm/irqflags.h>  #include "timing.h" +#include "irq.h"  #include "../mm/mmu_decl.h"  #define CREATE_TRACE_POINTS @@ -237,7 +239,8 @@ int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)  		r = RESUME_HOST;  		break;  	default: -		BUG(); +		WARN_ON(1); +		r = RESUME_GUEST;  	}  	return r; @@ -305,6 +308,7 @@ int kvm_dev_ioctl_check_extension(long ext)  #ifdef CONFIG_BOOKE  	case KVM_CAP_PPC_BOOKE_SREGS:  	case KVM_CAP_PPC_BOOKE_WATCHDOG: +	case KVM_CAP_PPC_EPR:  #else  	case KVM_CAP_PPC_SEGSTATE:  	case KVM_CAP_PPC_HIOR: @@ -315,6 +319,7 @@ int kvm_dev_ioctl_check_extension(long ext)  	case KVM_CAP_ENABLE_CAP:  	case KVM_CAP_ONE_REG:  	case KVM_CAP_IOEVENTFD: +	case KVM_CAP_DEVICE_CTRL:  		r = 1;  		break;  #ifndef CONFIG_KVM_BOOK3S_64_HV @@ -324,6 +329,9 @@ int kvm_dev_ioctl_check_extension(long ext)  #if defined(CONFIG_KVM_E500V2) || defined(CONFIG_KVM_E500MC)  	case KVM_CAP_SW_TLB:  #endif +#ifdef CONFIG_KVM_MPIC +	case KVM_CAP_IRQ_MPIC: +#endif  		r = 1;  		break;  	case KVM_CAP_COALESCED_MMIO: @@ -333,6 +341,10 @@ int kvm_dev_ioctl_check_extension(long ext)  #ifdef CONFIG_PPC_BOOK3S_64  	case KVM_CAP_SPAPR_TCE:  	case KVM_CAP_PPC_ALLOC_HTAB: +	case KVM_CAP_PPC_RTAS: +#ifdef CONFIG_KVM_XICS +	case KVM_CAP_IRQ_XICS: +#endif  		r = 1;  		break;  #endif /* CONFIG_PPC_BOOK3S_64 */ @@ -409,18 +421,17 @@ int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)  }  int kvm_arch_prepare_memory_region(struct kvm *kvm, -                                   struct kvm_memory_slot *memslot, -                                   struct kvm_memory_slot old, -                                   struct kvm_userspace_memory_region *mem, -                                   int user_alloc) +				   struct kvm_memory_slot *memslot, +				   struct kvm_userspace_memory_region *mem, +				   enum kvm_mr_change change)  {  	return kvmppc_core_prepare_memory_region(kvm, memslot, mem);  }  void kvm_arch_commit_memory_region(struct kvm *kvm, -               struct kvm_userspace_memory_region *mem, -               struct kvm_memory_slot old, -               int user_alloc) +				   struct kvm_userspace_memory_region *mem, +				   const struct kvm_memory_slot *old, +				   enum kvm_mr_change change)  {  	kvmppc_core_commit_memory_region(kvm, mem, old);  } @@ -458,6 +469,16 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)  	tasklet_kill(&vcpu->arch.tasklet);  	kvmppc_remove_vcpu_debugfs(vcpu); + +	switch (vcpu->arch.irq_type) { +	case KVMPPC_IRQ_MPIC: +		kvmppc_mpic_disconnect_vcpu(vcpu->arch.mpic, vcpu); +		break; +	case KVMPPC_IRQ_XICS: +		kvmppc_xics_free_icp(vcpu); +		break; +	} +  	kvmppc_core_vcpu_free(vcpu);  } @@ -530,12 +551,6 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)  #endif  } -int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, -                                        struct kvm_guest_debug *dbg) -{ -	return -EINVAL; -} -  static void kvmppc_complete_dcr_load(struct kvm_vcpu *vcpu,                                       struct kvm_run *run)  { @@ -610,6 +625,8 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,  int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,                         unsigned int rt, unsigned int bytes, int is_bigendian)  { +	int idx, ret; +  	if (bytes > sizeof(run->mmio.data)) {  		printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__,  		       run->mmio.len); @@ -625,8 +642,14 @@ int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,  	vcpu->mmio_is_write = 0;  	vcpu->arch.mmio_sign_extend = 0; -	if (!kvm_io_bus_read(vcpu->kvm, KVM_MMIO_BUS, run->mmio.phys_addr, -			     bytes, &run->mmio.data)) { +	idx = srcu_read_lock(&vcpu->kvm->srcu); + +	ret = kvm_io_bus_read(vcpu->kvm, KVM_MMIO_BUS, run->mmio.phys_addr, +			      bytes, &run->mmio.data); + +	srcu_read_unlock(&vcpu->kvm->srcu, idx); + +	if (!ret) {  		kvmppc_complete_mmio_load(vcpu, run);  		vcpu->mmio_needed = 0;  		return EMULATE_DONE; @@ -651,6 +674,7 @@ int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,                          u64 val, unsigned int bytes, int is_bigendian)  {  	void *data = run->mmio.data; +	int idx, ret;  	if (bytes > sizeof(run->mmio.data)) {  		printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__, @@ -680,9 +704,14 @@ int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,  		}  	} -	if (!kvm_io_bus_write(vcpu->kvm, KVM_MMIO_BUS, run->mmio.phys_addr, -			      bytes, &run->mmio.data)) { -		kvmppc_complete_mmio_load(vcpu, run); +	idx = srcu_read_lock(&vcpu->kvm->srcu); + +	ret = kvm_io_bus_write(vcpu->kvm, KVM_MMIO_BUS, run->mmio.phys_addr, +			       bytes, &run->mmio.data); + +	srcu_read_unlock(&vcpu->kvm->srcu, idx); + +	if (!ret) {  		vcpu->mmio_needed = 0;  		return EMULATE_DONE;  	} @@ -720,6 +749,11 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)  		for (i = 0; i < 9; ++i)  			kvmppc_set_gpr(vcpu, 4 + i, run->papr_hcall.args[i]);  		vcpu->arch.hcall_needed = 0; +#ifdef CONFIG_BOOKE +	} else if (vcpu->arch.epr_needed) { +		kvmppc_set_epr(vcpu, run->epr.epr); +		vcpu->arch.epr_needed = 0; +#endif  	}  	r = kvmppc_vcpu_run(run, vcpu); @@ -733,7 +767,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)  int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq)  {  	if (irq->irq == KVM_INTERRUPT_UNSET) { -		kvmppc_core_dequeue_external(vcpu, irq); +		kvmppc_core_dequeue_external(vcpu);  		return 0;  	} @@ -761,6 +795,13 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,  		r = 0;  		vcpu->arch.papr_enabled = true;  		break; +	case KVM_CAP_PPC_EPR: +		r = 0; +		if (cap->args[0]) +			vcpu->arch.epr_flags |= KVMPPC_EPR_USER; +		else +			vcpu->arch.epr_flags &= ~KVMPPC_EPR_USER; +		break;  #ifdef CONFIG_BOOKE  	case KVM_CAP_PPC_BOOKE_WATCHDOG:  		r = 0; @@ -780,6 +821,44 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,  		break;  	}  #endif +#ifdef CONFIG_KVM_MPIC +	case KVM_CAP_IRQ_MPIC: { +		struct file *filp; +		struct kvm_device *dev; + +		r = -EBADF; +		filp = fget(cap->args[0]); +		if (!filp) +			break; + +		r = -EPERM; +		dev = kvm_device_from_filp(filp); +		if (dev) +			r = kvmppc_mpic_connect_vcpu(dev, vcpu, cap->args[1]); + +		fput(filp); +		break; +	} +#endif +#ifdef CONFIG_KVM_XICS +	case KVM_CAP_IRQ_XICS: { +		struct file *filp; +		struct kvm_device *dev; + +		r = -EBADF; +		filp = fget(cap->args[0]); +		if (!filp) +			break; + +		r = -EPERM; +		dev = kvm_device_from_filp(filp); +		if (dev) +			r = kvmppc_xics_connect_vcpu(dev, vcpu, cap->args[1]); + +		fput(filp); +		break; +	} +#endif /* CONFIG_KVM_XICS */  	default:  		r = -EINVAL;  		break; @@ -902,9 +981,22 @@ static int kvm_vm_ioctl_get_pvinfo(struct kvm_ppc_pvinfo *pvinfo)  	return 0;  } +int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event, +			  bool line_status) +{ +	if (!irqchip_in_kernel(kvm)) +		return -ENXIO; + +	irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, +					irq_event->irq, irq_event->level, +					line_status); +	return 0; +} +  long kvm_arch_vm_ioctl(struct file *filp,                         unsigned int ioctl, unsigned long arg)  { +	struct kvm *kvm __maybe_unused = filp->private_data;  	void __user *argp = (void __user *)arg;  	long r; @@ -923,7 +1015,6 @@ long kvm_arch_vm_ioctl(struct file *filp,  #ifdef CONFIG_PPC_BOOK3S_64  	case KVM_CREATE_SPAPR_TCE: {  		struct kvm_create_spapr_tce create_tce; -		struct kvm *kvm = filp->private_data;  		r = -EFAULT;  		if (copy_from_user(&create_tce, argp, sizeof(create_tce))) @@ -935,8 +1026,8 @@ long kvm_arch_vm_ioctl(struct file *filp,  #ifdef CONFIG_KVM_BOOK3S_64_HV  	case KVM_ALLOCATE_RMA: { -		struct kvm *kvm = filp->private_data;  		struct kvm_allocate_rma rma; +		struct kvm *kvm = filp->private_data;  		r = kvm_vm_ioctl_allocate_rma(kvm, &rma);  		if (r >= 0 && copy_to_user(argp, &rma, sizeof(rma))) @@ -945,7 +1036,6 @@ long kvm_arch_vm_ioctl(struct file *filp,  	}  	case KVM_PPC_ALLOCATE_HTAB: { -		struct kvm *kvm = filp->private_data;  		u32 htab_order;  		r = -EFAULT; @@ -962,7 +1052,6 @@ long kvm_arch_vm_ioctl(struct file *filp,  	}  	case KVM_PPC_GET_HTAB_FD: { -		struct kvm *kvm = filp->private_data;  		struct kvm_get_htab_fd ghf;  		r = -EFAULT; @@ -975,7 +1064,6 @@ long kvm_arch_vm_ioctl(struct file *filp,  #ifdef CONFIG_PPC_BOOK3S_64  	case KVM_PPC_GET_SMMU_INFO: { -		struct kvm *kvm = filp->private_data;  		struct kvm_ppc_smmu_info info;  		memset(&info, 0, sizeof(info)); @@ -984,6 +1072,12 @@ long kvm_arch_vm_ioctl(struct file *filp,  			r = -EFAULT;  		break;  	} +	case KVM_PPC_RTAS_DEFINE_TOKEN: { +		struct kvm *kvm = filp->private_data; + +		r = kvm_vm_ioctl_rtas_define_token(kvm, argp); +		break; +	}  #endif /* CONFIG_PPC_BOOK3S_64 */  	default:  		r = -ENOTTY;  |