diff options
| -rw-r--r-- | include/linux/kvm_host.h | 3 | ||||
| -rw-r--r-- | virt/kvm/irq_comm.c | 76 | ||||
| -rw-r--r-- | virt/kvm/irqchip.c | 85 | 
3 files changed, 91 insertions, 73 deletions
| diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index a7bfe9d3aa5e..dcef724f4ba6 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -961,6 +961,9 @@ int kvm_set_irq_routing(struct kvm *kvm,  			const struct kvm_irq_routing_entry *entries,  			unsigned nr,  			unsigned flags); +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);  void kvm_free_irq_routing(struct kvm *kvm);  int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi); diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c index d5008f4aade7..e2e6b4473a96 100644 --- a/virt/kvm/irq_comm.c +++ b/virt/kvm/irq_comm.c @@ -271,27 +271,14 @@ void kvm_fire_mask_notifiers(struct kvm *kvm, unsigned irqchip, unsigned pin,  	rcu_read_unlock();  } -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; @@ -328,68 +315,11 @@ 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_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; -} -  #define IOAPIC_ROUTING_ENTRY(irq) \  	{ .gsi = irq, .type = KVM_IRQ_ROUTING_IRQCHIP,	\  	  .u.irqchip.irqchip = KVM_IRQCHIP_IOAPIC, .u.irqchip.pin = (irq) } diff --git a/virt/kvm/irqchip.c b/virt/kvm/irqchip.c index 12f7f26af4f8..20dc9e4a8f6c 100644 --- a/virt/kvm/irqchip.c +++ b/virt/kvm/irqchip.c @@ -150,3 +150,88 @@ void kvm_free_irq_routing(struct kvm *kvm)  	   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; +} |