diff options
Diffstat (limited to 'virt/kvm')
| -rw-r--r-- | virt/kvm/Kconfig | 3 | ||||
| -rw-r--r-- | virt/kvm/assigned-dev.c | 30 | ||||
| -rw-r--r-- | virt/kvm/eventfd.c | 6 | ||||
| -rw-r--r-- | virt/kvm/irq_comm.c | 194 | ||||
| -rw-r--r-- | virt/kvm/irqchip.c | 237 | ||||
| -rw-r--r-- | virt/kvm/kvm_main.c | 173 | 
6 files changed, 418 insertions, 225 deletions
diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig index d01b24b72c6..779262f59e2 100644 --- a/virt/kvm/Kconfig +++ b/virt/kvm/Kconfig @@ -6,6 +6,9 @@ config HAVE_KVM  config HAVE_KVM_IRQCHIP         bool +config HAVE_KVM_IRQ_ROUTING +       bool +  config HAVE_KVM_EVENTFD         bool         select EVENTFD diff --git a/virt/kvm/assigned-dev.c b/virt/kvm/assigned-dev.c index f4c7f591b5d..8db43701016 100644 --- a/virt/kvm/assigned-dev.c +++ b/virt/kvm/assigned-dev.c @@ -983,36 +983,6 @@ long kvm_vm_ioctl_assigned_device(struct kvm *kvm, unsigned ioctl,  			goto out;  		break;  	} -#ifdef KVM_CAP_IRQ_ROUTING -	case KVM_SET_GSI_ROUTING: { -		struct kvm_irq_routing routing; -		struct kvm_irq_routing __user *urouting; -		struct kvm_irq_routing_entry *entries; - -		r = -EFAULT; -		if (copy_from_user(&routing, argp, sizeof(routing))) -			goto out; -		r = -EINVAL; -		if (routing.nr >= KVM_MAX_IRQ_ROUTES) -			goto out; -		if (routing.flags) -			goto out; -		r = -ENOMEM; -		entries = vmalloc(routing.nr * sizeof(*entries)); -		if (!entries) -			goto out; -		r = -EFAULT; -		urouting = argp; -		if (copy_from_user(entries, urouting->entries, -				   routing.nr * sizeof(*entries))) -			goto out_free_irq_routing; -		r = kvm_set_irq_routing(kvm, entries, routing.nr, -					routing.flags); -	out_free_irq_routing: -		vfree(entries); -		break; -	} -#endif /* KVM_CAP_IRQ_ROUTING */  #ifdef __KVM_HAVE_MSIX  	case KVM_ASSIGN_SET_MSIX_NR: {  		struct kvm_assigned_msix_nr entry_nr; diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c index c5d43ffbf1f..64ee720b75c 100644 --- a/virt/kvm/eventfd.c +++ b/virt/kvm/eventfd.c @@ -35,7 +35,7 @@  #include "iodev.h" -#ifdef __KVM_HAVE_IOAPIC +#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING  /*   * --------------------------------------------------------------------   * irqfd: Allows an fd to be used to inject an interrupt to the guest @@ -433,7 +433,7 @@ fail:  void  kvm_eventfd_init(struct kvm *kvm)  { -#ifdef __KVM_HAVE_IOAPIC +#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING  	spin_lock_init(&kvm->irqfds.lock);  	INIT_LIST_HEAD(&kvm->irqfds.items);  	INIT_LIST_HEAD(&kvm->irqfds.resampler_list); @@ -442,7 +442,7 @@ kvm_eventfd_init(struct kvm *kvm)  	INIT_LIST_HEAD(&kvm->ioeventfds);  } -#ifdef __KVM_HAVE_IOAPIC +#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING  /*   * shutdown any irqfd's that match fd+gsi   */ diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c index 25ab48007ad..e2e6b4473a9 100644 --- a/virt/kvm/irq_comm.c +++ b/virt/kvm/irq_comm.c @@ -151,59 +151,6 @@ static int kvm_set_msi_inatomic(struct kvm_kernel_irq_routing_entry *e,  		return -EWOULDBLOCK;  } -int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi) -{ -	struct kvm_kernel_irq_routing_entry route; - -	if (!irqchip_in_kernel(kvm) || msi->flags != 0) -		return -EINVAL; - -	route.msi.address_lo = msi->address_lo; -	route.msi.address_hi = msi->address_hi; -	route.msi.data = msi->data; - -	return kvm_set_msi(&route, kvm, KVM_USERSPACE_IRQ_SOURCE_ID, 1, false); -} - -/* - * Return value: - *  < 0   Interrupt was ignored (masked or not delivered for other reasons) - *  = 0   Interrupt was coalesced (previous irq is still pending) - *  > 0   Number of CPUs interrupt was delivered to - */ -int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level, -		bool line_status) -{ -	struct kvm_kernel_irq_routing_entry *e, irq_set[KVM_NR_IRQCHIPS]; -	int ret = -1, i = 0; -	struct kvm_irq_routing_table *irq_rt; - -	trace_kvm_set_irq(irq, level, irq_source_id); - -	/* Not possible to detect if the guest uses the PIC or the -	 * IOAPIC.  So set the bit in both. The guest will ignore -	 * writes to the unused one. -	 */ -	rcu_read_lock(); -	irq_rt = rcu_dereference(kvm->irq_routing); -	if (irq < irq_rt->nr_rt_entries) -		hlist_for_each_entry(e, &irq_rt->map[irq], link) -			irq_set[i++] = *e; -	rcu_read_unlock(); - -	while(i--) { -		int r; -		r = irq_set[i].set(&irq_set[i], kvm, irq_source_id, level, -				line_status); -		if (r < 0) -			continue; - -		ret = r + ((ret < 0) ? 0 : ret); -	} - -	return ret; -} -  /*   * Deliver an IRQ in an atomic context if we can, or return a failure,   * user can retry in a process context. @@ -241,63 +188,6 @@ int kvm_set_irq_inatomic(struct kvm *kvm, int irq_source_id, u32 irq, int level)  	return ret;  } -bool kvm_irq_has_notifier(struct kvm *kvm, unsigned irqchip, unsigned pin) -{ -	struct kvm_irq_ack_notifier *kian; -	int gsi; - -	rcu_read_lock(); -	gsi = rcu_dereference(kvm->irq_routing)->chip[irqchip][pin]; -	if (gsi != -1) -		hlist_for_each_entry_rcu(kian, &kvm->irq_ack_notifier_list, -					 link) -			if (kian->gsi == gsi) { -				rcu_read_unlock(); -				return true; -			} - -	rcu_read_unlock(); - -	return false; -} -EXPORT_SYMBOL_GPL(kvm_irq_has_notifier); - -void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin) -{ -	struct kvm_irq_ack_notifier *kian; -	int gsi; - -	trace_kvm_ack_irq(irqchip, pin); - -	rcu_read_lock(); -	gsi = rcu_dereference(kvm->irq_routing)->chip[irqchip][pin]; -	if (gsi != -1) -		hlist_for_each_entry_rcu(kian, &kvm->irq_ack_notifier_list, -					 link) -			if (kian->gsi == gsi) -				kian->irq_acked(kian); -	rcu_read_unlock(); -} - -void kvm_register_irq_ack_notifier(struct kvm *kvm, -				   struct kvm_irq_ack_notifier *kian) -{ -	mutex_lock(&kvm->irq_lock); -	hlist_add_head_rcu(&kian->link, &kvm->irq_ack_notifier_list); -	mutex_unlock(&kvm->irq_lock); -	kvm_vcpu_request_scan_ioapic(kvm); -} - -void kvm_unregister_irq_ack_notifier(struct kvm *kvm, -				    struct kvm_irq_ack_notifier *kian) -{ -	mutex_lock(&kvm->irq_lock); -	hlist_del_init_rcu(&kian->link); -	mutex_unlock(&kvm->irq_lock); -	synchronize_rcu(); -	kvm_vcpu_request_scan_ioapic(kvm); -} -  int kvm_request_irq_source_id(struct kvm *kvm)  {  	unsigned long *bitmap = &kvm->arch.irq_sources_bitmap; @@ -381,34 +271,14 @@ void kvm_fire_mask_notifiers(struct kvm *kvm, unsigned irqchip, unsigned pin,  	rcu_read_unlock();  } -void kvm_free_irq_routing(struct kvm *kvm) -{ -	/* Called only during vm destruction. Nobody can use the pointer -	   at this stage */ -	kfree(kvm->irq_routing); -} - -static int setup_routing_entry(struct kvm_irq_routing_table *rt, -			       struct kvm_kernel_irq_routing_entry *e, -			       const struct kvm_irq_routing_entry *ue) +int kvm_set_routing_entry(struct kvm_irq_routing_table *rt, +			  struct kvm_kernel_irq_routing_entry *e, +			  const struct kvm_irq_routing_entry *ue)  {  	int r = -EINVAL;  	int delta;  	unsigned max_pin; -	struct kvm_kernel_irq_routing_entry *ei; -	/* -	 * Do not allow GSI to be mapped to the same irqchip more than once. -	 * Allow only one to one mapping between GSI and MSI. -	 */ -	hlist_for_each_entry(ei, &rt->map[ue->gsi], link) -		if (ei->type == KVM_IRQ_ROUTING_MSI || -		    ue->type == KVM_IRQ_ROUTING_MSI || -		    ue->u.irqchip.irqchip == ei->irqchip.irqchip) -			return r; - -	e->gsi = ue->gsi; -	e->type = ue->type;  	switch (ue->type) {  	case KVM_IRQ_ROUTING_IRQCHIP:  		delta = 0; @@ -445,66 +315,8 @@ static int setup_routing_entry(struct kvm_irq_routing_table *rt,  		goto out;  	} -	hlist_add_head(&e->link, &rt->map[e->gsi]); -	r = 0; -out: -	return r; -} - - -int kvm_set_irq_routing(struct kvm *kvm, -			const struct kvm_irq_routing_entry *ue, -			unsigned nr, -			unsigned flags) -{ -	struct kvm_irq_routing_table *new, *old; -	u32 i, j, nr_rt_entries = 0; -	int r; - -	for (i = 0; i < nr; ++i) { -		if (ue[i].gsi >= KVM_MAX_IRQ_ROUTES) -			return -EINVAL; -		nr_rt_entries = max(nr_rt_entries, ue[i].gsi); -	} - -	nr_rt_entries += 1; - -	new = kzalloc(sizeof(*new) + (nr_rt_entries * sizeof(struct hlist_head)) -		      + (nr * sizeof(struct kvm_kernel_irq_routing_entry)), -		      GFP_KERNEL); - -	if (!new) -		return -ENOMEM; - -	new->rt_entries = (void *)&new->map[nr_rt_entries]; - -	new->nr_rt_entries = nr_rt_entries; -	for (i = 0; i < 3; i++) -		for (j = 0; j < KVM_IOAPIC_NUM_PINS; j++) -			new->chip[i][j] = -1; - -	for (i = 0; i < nr; ++i) { -		r = -EINVAL; -		if (ue->flags) -			goto out; -		r = setup_routing_entry(new, &new->rt_entries[i], ue); -		if (r) -			goto out; -		++ue; -	} - -	mutex_lock(&kvm->irq_lock); -	old = kvm->irq_routing; -	kvm_irq_routing_update(kvm, new); -	mutex_unlock(&kvm->irq_lock); - -	synchronize_rcu(); - -	new = old;  	r = 0; -  out: -	kfree(new);  	return r;  } diff --git a/virt/kvm/irqchip.c b/virt/kvm/irqchip.c new file mode 100644 index 00000000000..20dc9e4a8f6 --- /dev/null +++ b/virt/kvm/irqchip.c @@ -0,0 +1,237 @@ +/* + * irqchip.c: Common API for in kernel interrupt controllers + * Copyright (c) 2007, Intel Corporation. + * Copyright 2010 Red Hat, Inc. and/or its affiliates. + * Copyright (c) 2013, Alexander Graf <agraf@suse.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + * This file is derived from virt/kvm/irq_comm.c. + * + * Authors: + *   Yaozu (Eddie) Dong <Eddie.dong@intel.com> + *   Alexander Graf <agraf@suse.de> + */ + +#include <linux/kvm_host.h> +#include <linux/slab.h> +#include <linux/export.h> +#include <trace/events/kvm.h> +#include "irq.h" + +bool kvm_irq_has_notifier(struct kvm *kvm, unsigned irqchip, unsigned pin) +{ +	struct kvm_irq_ack_notifier *kian; +	int gsi; + +	rcu_read_lock(); +	gsi = rcu_dereference(kvm->irq_routing)->chip[irqchip][pin]; +	if (gsi != -1) +		hlist_for_each_entry_rcu(kian, &kvm->irq_ack_notifier_list, +					 link) +			if (kian->gsi == gsi) { +				rcu_read_unlock(); +				return true; +			} + +	rcu_read_unlock(); + +	return false; +} +EXPORT_SYMBOL_GPL(kvm_irq_has_notifier); + +void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin) +{ +	struct kvm_irq_ack_notifier *kian; +	int gsi; + +	trace_kvm_ack_irq(irqchip, pin); + +	rcu_read_lock(); +	gsi = rcu_dereference(kvm->irq_routing)->chip[irqchip][pin]; +	if (gsi != -1) +		hlist_for_each_entry_rcu(kian, &kvm->irq_ack_notifier_list, +					 link) +			if (kian->gsi == gsi) +				kian->irq_acked(kian); +	rcu_read_unlock(); +} + +void kvm_register_irq_ack_notifier(struct kvm *kvm, +				   struct kvm_irq_ack_notifier *kian) +{ +	mutex_lock(&kvm->irq_lock); +	hlist_add_head_rcu(&kian->link, &kvm->irq_ack_notifier_list); +	mutex_unlock(&kvm->irq_lock); +#ifdef __KVM_HAVE_IOAPIC +	kvm_vcpu_request_scan_ioapic(kvm); +#endif +} + +void kvm_unregister_irq_ack_notifier(struct kvm *kvm, +				    struct kvm_irq_ack_notifier *kian) +{ +	mutex_lock(&kvm->irq_lock); +	hlist_del_init_rcu(&kian->link); +	mutex_unlock(&kvm->irq_lock); +	synchronize_rcu(); +#ifdef __KVM_HAVE_IOAPIC +	kvm_vcpu_request_scan_ioapic(kvm); +#endif +} + +int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi) +{ +	struct kvm_kernel_irq_routing_entry route; + +	if (!irqchip_in_kernel(kvm) || msi->flags != 0) +		return -EINVAL; + +	route.msi.address_lo = msi->address_lo; +	route.msi.address_hi = msi->address_hi; +	route.msi.data = msi->data; + +	return kvm_set_msi(&route, kvm, KVM_USERSPACE_IRQ_SOURCE_ID, 1, false); +} + +/* + * Return value: + *  < 0   Interrupt was ignored (masked or not delivered for other reasons) + *  = 0   Interrupt was coalesced (previous irq is still pending) + *  > 0   Number of CPUs interrupt was delivered to + */ +int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level, +		bool line_status) +{ +	struct kvm_kernel_irq_routing_entry *e, irq_set[KVM_NR_IRQCHIPS]; +	int ret = -1, i = 0; +	struct kvm_irq_routing_table *irq_rt; + +	trace_kvm_set_irq(irq, level, irq_source_id); + +	/* Not possible to detect if the guest uses the PIC or the +	 * IOAPIC.  So set the bit in both. The guest will ignore +	 * writes to the unused one. +	 */ +	rcu_read_lock(); +	irq_rt = rcu_dereference(kvm->irq_routing); +	if (irq < irq_rt->nr_rt_entries) +		hlist_for_each_entry(e, &irq_rt->map[irq], link) +			irq_set[i++] = *e; +	rcu_read_unlock(); + +	while(i--) { +		int r; +		r = irq_set[i].set(&irq_set[i], kvm, irq_source_id, level, +				   line_status); +		if (r < 0) +			continue; + +		ret = r + ((ret < 0) ? 0 : ret); +	} + +	return ret; +} + +void kvm_free_irq_routing(struct kvm *kvm) +{ +	/* Called only during vm destruction. Nobody can use the pointer +	   at this stage */ +	kfree(kvm->irq_routing); +} + +static int setup_routing_entry(struct kvm_irq_routing_table *rt, +			       struct kvm_kernel_irq_routing_entry *e, +			       const struct kvm_irq_routing_entry *ue) +{ +	int r = -EINVAL; +	struct kvm_kernel_irq_routing_entry *ei; + +	/* +	 * Do not allow GSI to be mapped to the same irqchip more than once. +	 * Allow only one to one mapping between GSI and MSI. +	 */ +	hlist_for_each_entry(ei, &rt->map[ue->gsi], link) +		if (ei->type == KVM_IRQ_ROUTING_MSI || +		    ue->type == KVM_IRQ_ROUTING_MSI || +		    ue->u.irqchip.irqchip == ei->irqchip.irqchip) +			return r; + +	e->gsi = ue->gsi; +	e->type = ue->type; +	r = kvm_set_routing_entry(rt, e, ue); +	if (r) +		goto out; + +	hlist_add_head(&e->link, &rt->map[e->gsi]); +	r = 0; +out: +	return r; +} + +int kvm_set_irq_routing(struct kvm *kvm, +			const struct kvm_irq_routing_entry *ue, +			unsigned nr, +			unsigned flags) +{ +	struct kvm_irq_routing_table *new, *old; +	u32 i, j, nr_rt_entries = 0; +	int r; + +	for (i = 0; i < nr; ++i) { +		if (ue[i].gsi >= KVM_MAX_IRQ_ROUTES) +			return -EINVAL; +		nr_rt_entries = max(nr_rt_entries, ue[i].gsi); +	} + +	nr_rt_entries += 1; + +	new = kzalloc(sizeof(*new) + (nr_rt_entries * sizeof(struct hlist_head)) +		      + (nr * sizeof(struct kvm_kernel_irq_routing_entry)), +		      GFP_KERNEL); + +	if (!new) +		return -ENOMEM; + +	new->rt_entries = (void *)&new->map[nr_rt_entries]; + +	new->nr_rt_entries = nr_rt_entries; +	for (i = 0; i < KVM_NR_IRQCHIPS; i++) +		for (j = 0; j < KVM_IRQCHIP_NUM_PINS; j++) +			new->chip[i][j] = -1; + +	for (i = 0; i < nr; ++i) { +		r = -EINVAL; +		if (ue->flags) +			goto out; +		r = setup_routing_entry(new, &new->rt_entries[i], ue); +		if (r) +			goto out; +		++ue; +	} + +	mutex_lock(&kvm->irq_lock); +	old = kvm->irq_routing; +	kvm_irq_routing_update(kvm, new); +	mutex_unlock(&kvm->irq_lock); + +	synchronize_rcu(); + +	new = old; +	r = 0; + +out: +	kfree(new); +	return r; +} diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index aaac1a7a9ea..5da9f02a2a6 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -504,6 +504,7 @@ static struct kvm *kvm_create_vm(unsigned long type)  	mutex_init(&kvm->irq_lock);  	mutex_init(&kvm->slots_lock);  	atomic_set(&kvm->users_count, 1); +	INIT_LIST_HEAD(&kvm->devices);  	r = kvm_init_mmu_notifier(kvm);  	if (r) @@ -581,6 +582,19 @@ void kvm_free_physmem(struct kvm *kvm)  	kfree(kvm->memslots);  } +static void kvm_destroy_devices(struct kvm *kvm) +{ +	struct list_head *node, *tmp; + +	list_for_each_safe(node, tmp, &kvm->devices) { +		struct kvm_device *dev = +			list_entry(node, struct kvm_device, vm_node); + +		list_del(node); +		dev->ops->destroy(dev); +	} +} +  static void kvm_destroy_vm(struct kvm *kvm)  {  	int i; @@ -600,6 +614,7 @@ static void kvm_destroy_vm(struct kvm *kvm)  	kvm_arch_flush_shadow_all(kvm);  #endif  	kvm_arch_destroy_vm(kvm); +	kvm_destroy_devices(kvm);  	kvm_free_physmem(kvm);  	cleanup_srcu_struct(&kvm->srcu);  	kvm_arch_free_vm(kvm); @@ -2159,6 +2174,111 @@ out:  }  #endif +static int kvm_device_ioctl_attr(struct kvm_device *dev, +				 int (*accessor)(struct kvm_device *dev, +						 struct kvm_device_attr *attr), +				 unsigned long arg) +{ +	struct kvm_device_attr attr; + +	if (!accessor) +		return -EPERM; + +	if (copy_from_user(&attr, (void __user *)arg, sizeof(attr))) +		return -EFAULT; + +	return accessor(dev, &attr); +} + +static long kvm_device_ioctl(struct file *filp, unsigned int ioctl, +			     unsigned long arg) +{ +	struct kvm_device *dev = filp->private_data; + +	switch (ioctl) { +	case KVM_SET_DEVICE_ATTR: +		return kvm_device_ioctl_attr(dev, dev->ops->set_attr, arg); +	case KVM_GET_DEVICE_ATTR: +		return kvm_device_ioctl_attr(dev, dev->ops->get_attr, arg); +	case KVM_HAS_DEVICE_ATTR: +		return kvm_device_ioctl_attr(dev, dev->ops->has_attr, arg); +	default: +		if (dev->ops->ioctl) +			return dev->ops->ioctl(dev, ioctl, arg); + +		return -ENOTTY; +	} +} + +static int kvm_device_release(struct inode *inode, struct file *filp) +{ +	struct kvm_device *dev = filp->private_data; +	struct kvm *kvm = dev->kvm; + +	kvm_put_kvm(kvm); +	return 0; +} + +static const struct file_operations kvm_device_fops = { +	.unlocked_ioctl = kvm_device_ioctl, +	.release = kvm_device_release, +}; + +struct kvm_device *kvm_device_from_filp(struct file *filp) +{ +	if (filp->f_op != &kvm_device_fops) +		return NULL; + +	return filp->private_data; +} + +static int kvm_ioctl_create_device(struct kvm *kvm, +				   struct kvm_create_device *cd) +{ +	struct kvm_device_ops *ops = NULL; +	struct kvm_device *dev; +	bool test = cd->flags & KVM_CREATE_DEVICE_TEST; +	int ret; + +	switch (cd->type) { +#ifdef CONFIG_KVM_MPIC +	case KVM_DEV_TYPE_FSL_MPIC_20: +	case KVM_DEV_TYPE_FSL_MPIC_42: +		ops = &kvm_mpic_ops; +		break; +#endif +	default: +		return -ENODEV; +	} + +	if (test) +		return 0; + +	dev = kzalloc(sizeof(*dev), GFP_KERNEL); +	if (!dev) +		return -ENOMEM; + +	dev->ops = ops; +	dev->kvm = kvm; + +	ret = ops->create(dev, cd->type); +	if (ret < 0) { +		kfree(dev); +		return ret; +	} + +	ret = anon_inode_getfd(ops->name, &kvm_device_fops, dev, O_RDWR); +	if (ret < 0) { +		ops->destroy(dev); +		return ret; +	} + +	list_add(&dev->vm_node, &kvm->devices); +	kvm_get_kvm(kvm); +	cd->fd = ret; +	return 0; +} +  static long kvm_vm_ioctl(struct file *filp,  			   unsigned int ioctl, unsigned long arg)  { @@ -2274,6 +2394,54 @@ static long kvm_vm_ioctl(struct file *filp,  		break;  	}  #endif +#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING +	case KVM_SET_GSI_ROUTING: { +		struct kvm_irq_routing routing; +		struct kvm_irq_routing __user *urouting; +		struct kvm_irq_routing_entry *entries; + +		r = -EFAULT; +		if (copy_from_user(&routing, argp, sizeof(routing))) +			goto out; +		r = -EINVAL; +		if (routing.nr >= KVM_MAX_IRQ_ROUTES) +			goto out; +		if (routing.flags) +			goto out; +		r = -ENOMEM; +		entries = vmalloc(routing.nr * sizeof(*entries)); +		if (!entries) +			goto out; +		r = -EFAULT; +		urouting = argp; +		if (copy_from_user(entries, urouting->entries, +				   routing.nr * sizeof(*entries))) +			goto out_free_irq_routing; +		r = kvm_set_irq_routing(kvm, entries, routing.nr, +					routing.flags); +	out_free_irq_routing: +		vfree(entries); +		break; +	} +#endif /* CONFIG_HAVE_KVM_IRQ_ROUTING */ +	case KVM_CREATE_DEVICE: { +		struct kvm_create_device cd; + +		r = -EFAULT; +		if (copy_from_user(&cd, argp, sizeof(cd))) +			goto out; + +		r = kvm_ioctl_create_device(kvm, &cd); +		if (r) +			goto out; + +		r = -EFAULT; +		if (copy_to_user(argp, &cd, sizeof(cd))) +			goto out; + +		r = 0; +		break; +	}  	default:  		r = kvm_arch_vm_ioctl(filp, ioctl, arg);  		if (r == -ENOTTY) @@ -2403,8 +2571,11 @@ static long kvm_dev_ioctl_check_extension_generic(long arg)  #ifdef CONFIG_HAVE_KVM_MSI  	case KVM_CAP_SIGNAL_MSI:  #endif +#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING +	case KVM_CAP_IRQFD_RESAMPLE: +#endif  		return 1; -#ifdef KVM_CAP_IRQ_ROUTING +#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING  	case KVM_CAP_IRQ_ROUTING:  		return KVM_MAX_IRQ_ROUTES;  #endif  |