xref: /linux/virt/kvm/irqchip.c (revision b3ffd74a2f6fbec131eff6d81bc7a6dbbac57bc7)
11c9f8520SAlexander Graf /*
21c9f8520SAlexander Graf  * irqchip.c: Common API for in kernel interrupt controllers
31c9f8520SAlexander Graf  * Copyright (c) 2007, Intel Corporation.
41c9f8520SAlexander Graf  * Copyright 2010 Red Hat, Inc. and/or its affiliates.
51c9f8520SAlexander Graf  * Copyright (c) 2013, Alexander Graf <agraf@suse.de>
61c9f8520SAlexander Graf  *
71c9f8520SAlexander Graf  * This program is free software; you can redistribute it and/or modify it
81c9f8520SAlexander Graf  * under the terms and conditions of the GNU General Public License,
91c9f8520SAlexander Graf  * version 2, as published by the Free Software Foundation.
101c9f8520SAlexander Graf  *
111c9f8520SAlexander Graf  * This program is distributed in the hope it will be useful, but WITHOUT
121c9f8520SAlexander Graf  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
131c9f8520SAlexander Graf  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
141c9f8520SAlexander Graf  * more details.
151c9f8520SAlexander Graf  *
161c9f8520SAlexander Graf  * You should have received a copy of the GNU General Public License along with
171c9f8520SAlexander Graf  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
181c9f8520SAlexander Graf  * Place - Suite 330, Boston, MA 02111-1307 USA.
191c9f8520SAlexander Graf  *
201c9f8520SAlexander Graf  * This file is derived from virt/kvm/irq_comm.c.
211c9f8520SAlexander Graf  *
221c9f8520SAlexander Graf  * Authors:
231c9f8520SAlexander Graf  *   Yaozu (Eddie) Dong <Eddie.dong@intel.com>
241c9f8520SAlexander Graf  *   Alexander Graf <agraf@suse.de>
251c9f8520SAlexander Graf  */
261c9f8520SAlexander Graf 
271c9f8520SAlexander Graf #include <linux/kvm_host.h>
281c9f8520SAlexander Graf #include <linux/slab.h>
29719d93cdSChristian Borntraeger #include <linux/srcu.h>
301c9f8520SAlexander Graf #include <linux/export.h>
311c9f8520SAlexander Graf #include <trace/events/kvm.h>
321c9f8520SAlexander Graf #include "irq.h"
331c9f8520SAlexander Graf 
349957c86dSPaul Mackerras int kvm_irq_map_gsi(struct kvm *kvm,
359957c86dSPaul Mackerras 		    struct kvm_kernel_irq_routing_entry *entries, int gsi)
368ba918d4SPaul Mackerras {
379957c86dSPaul Mackerras 	struct kvm_irq_routing_table *irq_rt;
388ba918d4SPaul Mackerras 	struct kvm_kernel_irq_routing_entry *e;
398ba918d4SPaul Mackerras 	int n = 0;
408ba918d4SPaul Mackerras 
419957c86dSPaul Mackerras 	irq_rt = srcu_dereference_check(kvm->irq_routing, &kvm->irq_srcu,
429957c86dSPaul Mackerras 					lockdep_is_held(&kvm->irq_lock));
43c622a3c2SPaolo Bonzini 	if (irq_rt && gsi < irq_rt->nr_rt_entries) {
448ba918d4SPaul Mackerras 		hlist_for_each_entry(e, &irq_rt->map[gsi], link) {
458ba918d4SPaul Mackerras 			entries[n] = *e;
468ba918d4SPaul Mackerras 			++n;
478ba918d4SPaul Mackerras 		}
488ba918d4SPaul Mackerras 	}
498ba918d4SPaul Mackerras 
508ba918d4SPaul Mackerras 	return n;
518ba918d4SPaul Mackerras }
528ba918d4SPaul Mackerras 
539957c86dSPaul Mackerras int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned irqchip, unsigned pin)
548ba918d4SPaul Mackerras {
559957c86dSPaul Mackerras 	struct kvm_irq_routing_table *irq_rt;
569957c86dSPaul Mackerras 
579957c86dSPaul Mackerras 	irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu);
588ba918d4SPaul Mackerras 	return irq_rt->chip[irqchip][pin];
598ba918d4SPaul Mackerras }
608ba918d4SPaul Mackerras 
611c9f8520SAlexander Graf int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)
621c9f8520SAlexander Graf {
631c9f8520SAlexander Graf 	struct kvm_kernel_irq_routing_entry route;
641c9f8520SAlexander Graf 
65ebe91525SEric Auger 	if (!irqchip_in_kernel(kvm) || (msi->flags & ~KVM_MSI_VALID_DEVID))
661c9f8520SAlexander Graf 		return -EINVAL;
671c9f8520SAlexander Graf 
681c9f8520SAlexander Graf 	route.msi.address_lo = msi->address_lo;
691c9f8520SAlexander Graf 	route.msi.address_hi = msi->address_hi;
701c9f8520SAlexander Graf 	route.msi.data = msi->data;
71ebe91525SEric Auger 	route.msi.flags = msi->flags;
72ebe91525SEric Auger 	route.msi.devid = msi->devid;
731c9f8520SAlexander Graf 
741c9f8520SAlexander Graf 	return kvm_set_msi(&route, kvm, KVM_USERSPACE_IRQ_SOURCE_ID, 1, false);
751c9f8520SAlexander Graf }
761c9f8520SAlexander Graf 
771c9f8520SAlexander Graf /*
781c9f8520SAlexander Graf  * Return value:
791c9f8520SAlexander Graf  *  < 0   Interrupt was ignored (masked or not delivered for other reasons)
801c9f8520SAlexander Graf  *  = 0   Interrupt was coalesced (previous irq is still pending)
811c9f8520SAlexander Graf  *  > 0   Number of CPUs interrupt was delivered to
821c9f8520SAlexander Graf  */
831c9f8520SAlexander Graf int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level,
841c9f8520SAlexander Graf 		bool line_status)
851c9f8520SAlexander Graf {
868ba918d4SPaul Mackerras 	struct kvm_kernel_irq_routing_entry irq_set[KVM_NR_IRQCHIPS];
878ba918d4SPaul Mackerras 	int ret = -1, i, idx;
881c9f8520SAlexander Graf 
891c9f8520SAlexander Graf 	trace_kvm_set_irq(irq, level, irq_source_id);
901c9f8520SAlexander Graf 
911c9f8520SAlexander Graf 	/* Not possible to detect if the guest uses the PIC or the
921c9f8520SAlexander Graf 	 * IOAPIC.  So set the bit in both. The guest will ignore
931c9f8520SAlexander Graf 	 * writes to the unused one.
941c9f8520SAlexander Graf 	 */
95719d93cdSChristian Borntraeger 	idx = srcu_read_lock(&kvm->irq_srcu);
969957c86dSPaul Mackerras 	i = kvm_irq_map_gsi(kvm, irq_set, irq);
97719d93cdSChristian Borntraeger 	srcu_read_unlock(&kvm->irq_srcu, idx);
981c9f8520SAlexander Graf 
991c9f8520SAlexander Graf 	while (i--) {
1001c9f8520SAlexander Graf 		int r;
1011c9f8520SAlexander Graf 		r = irq_set[i].set(&irq_set[i], kvm, irq_source_id, level,
1021c9f8520SAlexander Graf 				   line_status);
1031c9f8520SAlexander Graf 		if (r < 0)
1041c9f8520SAlexander Graf 			continue;
1051c9f8520SAlexander Graf 
1061c9f8520SAlexander Graf 		ret = r + ((ret < 0) ? 0 : ret);
1071c9f8520SAlexander Graf 	}
1081c9f8520SAlexander Graf 
1091c9f8520SAlexander Graf 	return ret;
1101c9f8520SAlexander Graf }
1111c9f8520SAlexander Graf 
112e73f61e4SJoerg Roedel static void free_irq_routing_table(struct kvm_irq_routing_table *rt)
113e73f61e4SJoerg Roedel {
114e73f61e4SJoerg Roedel 	int i;
115e73f61e4SJoerg Roedel 
116e73f61e4SJoerg Roedel 	if (!rt)
117e73f61e4SJoerg Roedel 		return;
118e73f61e4SJoerg Roedel 
119e73f61e4SJoerg Roedel 	for (i = 0; i < rt->nr_rt_entries; ++i) {
120e73f61e4SJoerg Roedel 		struct kvm_kernel_irq_routing_entry *e;
121e73f61e4SJoerg Roedel 		struct hlist_node *n;
122e73f61e4SJoerg Roedel 
123e73f61e4SJoerg Roedel 		hlist_for_each_entry_safe(e, n, &rt->map[i], link) {
124e73f61e4SJoerg Roedel 			hlist_del(&e->link);
125e73f61e4SJoerg Roedel 			kfree(e);
126e73f61e4SJoerg Roedel 		}
127e73f61e4SJoerg Roedel 	}
128e73f61e4SJoerg Roedel 
129e73f61e4SJoerg Roedel 	kfree(rt);
130e73f61e4SJoerg Roedel }
131e73f61e4SJoerg Roedel 
1321c9f8520SAlexander Graf void kvm_free_irq_routing(struct kvm *kvm)
1331c9f8520SAlexander Graf {
1341c9f8520SAlexander Graf 	/* Called only during vm destruction. Nobody can use the pointer
1351c9f8520SAlexander Graf 	   at this stage */
136e73f61e4SJoerg Roedel 	struct kvm_irq_routing_table *rt = rcu_access_pointer(kvm->irq_routing);
137e73f61e4SJoerg Roedel 	free_irq_routing_table(rt);
1381c9f8520SAlexander Graf }
139e8cde093SAlexander Graf 
140c63cf538SRadim Krčmář static int setup_routing_entry(struct kvm *kvm,
141c63cf538SRadim Krčmář 			       struct kvm_irq_routing_table *rt,
142e8cde093SAlexander Graf 			       struct kvm_kernel_irq_routing_entry *e,
143e8cde093SAlexander Graf 			       const struct kvm_irq_routing_entry *ue)
144e8cde093SAlexander Graf {
145e8cde093SAlexander Graf 	struct kvm_kernel_irq_routing_entry *ei;
1468c6b7828SDavid Hildenbrand 	int r;
1471d487e9bSPaolo Bonzini 	u32 gsi = array_index_nospec(ue->gsi, KVM_MAX_IRQ_ROUTES);
148e8cde093SAlexander Graf 
149e8cde093SAlexander Graf 	/*
150e8cde093SAlexander Graf 	 * Do not allow GSI to be mapped to the same irqchip more than once.
151f33143d8SAndrey Smetanin 	 * Allow only one to one mapping between GSI and non-irqchip routing.
152e8cde093SAlexander Graf 	 */
1531d487e9bSPaolo Bonzini 	hlist_for_each_entry(ei, &rt->map[gsi], link)
154f33143d8SAndrey Smetanin 		if (ei->type != KVM_IRQ_ROUTING_IRQCHIP ||
155f33143d8SAndrey Smetanin 		    ue->type != KVM_IRQ_ROUTING_IRQCHIP ||
156e8cde093SAlexander Graf 		    ue->u.irqchip.irqchip == ei->irqchip.irqchip)
1578c6b7828SDavid Hildenbrand 			return -EINVAL;
158e8cde093SAlexander Graf 
1591d487e9bSPaolo Bonzini 	e->gsi = gsi;
160e8cde093SAlexander Graf 	e->type = ue->type;
161c63cf538SRadim Krčmář 	r = kvm_set_routing_entry(kvm, e, ue);
162e8cde093SAlexander Graf 	if (r)
1638c6b7828SDavid Hildenbrand 		return r;
1648ba918d4SPaul Mackerras 	if (e->type == KVM_IRQ_ROUTING_IRQCHIP)
1658ba918d4SPaul Mackerras 		rt->chip[e->irqchip.irqchip][e->irqchip.pin] = e->gsi;
166e8cde093SAlexander Graf 
167e8cde093SAlexander Graf 	hlist_add_head(&e->link, &rt->map[e->gsi]);
1688c6b7828SDavid Hildenbrand 
1698c6b7828SDavid Hildenbrand 	return 0;
170e8cde093SAlexander Graf }
171e8cde093SAlexander Graf 
172abdb080fSAndrey Smetanin void __attribute__((weak)) kvm_arch_irq_routing_update(struct kvm *kvm)
173abdb080fSAndrey Smetanin {
174abdb080fSAndrey Smetanin }
175abdb080fSAndrey Smetanin 
1765c0aea0eSDavid Hildenbrand bool __weak kvm_arch_can_set_irq_routing(struct kvm *kvm)
1775c0aea0eSDavid Hildenbrand {
1785c0aea0eSDavid Hildenbrand 	return true;
1795c0aea0eSDavid Hildenbrand }
1805c0aea0eSDavid Hildenbrand 
181e8cde093SAlexander Graf int kvm_set_irq_routing(struct kvm *kvm,
182e8cde093SAlexander Graf 			const struct kvm_irq_routing_entry *ue,
183e8cde093SAlexander Graf 			unsigned nr,
184e8cde093SAlexander Graf 			unsigned flags)
185e8cde093SAlexander Graf {
186e8cde093SAlexander Graf 	struct kvm_irq_routing_table *new, *old;
187995a0ee9SEric Auger 	struct kvm_kernel_irq_routing_entry *e;
188e8cde093SAlexander Graf 	u32 i, j, nr_rt_entries = 0;
189e8cde093SAlexander Graf 	int r;
190e8cde093SAlexander Graf 
191e8cde093SAlexander Graf 	for (i = 0; i < nr; ++i) {
192e8cde093SAlexander Graf 		if (ue[i].gsi >= KVM_MAX_IRQ_ROUTES)
193e8cde093SAlexander Graf 			return -EINVAL;
194e8cde093SAlexander Graf 		nr_rt_entries = max(nr_rt_entries, ue[i].gsi);
195e8cde093SAlexander Graf 	}
196e8cde093SAlexander Graf 
197e8cde093SAlexander Graf 	nr_rt_entries += 1;
198e8cde093SAlexander Graf 
199*b3ffd74aSGustavo A. R. Silva 	new = kzalloc(struct_size(new, map, nr_rt_entries), GFP_KERNEL_ACCOUNT);
200e8cde093SAlexander Graf 	if (!new)
201e8cde093SAlexander Graf 		return -ENOMEM;
202e8cde093SAlexander Graf 
203e8cde093SAlexander Graf 	new->nr_rt_entries = nr_rt_entries;
204e8cde093SAlexander Graf 	for (i = 0; i < KVM_NR_IRQCHIPS; i++)
205e8cde093SAlexander Graf 		for (j = 0; j < KVM_IRQCHIP_NUM_PINS; j++)
206e8cde093SAlexander Graf 			new->chip[i][j] = -1;
207e8cde093SAlexander Graf 
208e8cde093SAlexander Graf 	for (i = 0; i < nr; ++i) {
209e73f61e4SJoerg Roedel 		r = -ENOMEM;
210b12ce36aSBen Gardon 		e = kzalloc(sizeof(*e), GFP_KERNEL_ACCOUNT);
211e73f61e4SJoerg Roedel 		if (!e)
212e73f61e4SJoerg Roedel 			goto out;
213e73f61e4SJoerg Roedel 
214e8cde093SAlexander Graf 		r = -EINVAL;
215995a0ee9SEric Auger 		switch (ue->type) {
216995a0ee9SEric Auger 		case KVM_IRQ_ROUTING_MSI:
217995a0ee9SEric Auger 			if (ue->flags & ~KVM_MSI_VALID_DEVID)
218995a0ee9SEric Auger 				goto free_entry;
219995a0ee9SEric Auger 			break;
220995a0ee9SEric Auger 		default:
221995a0ee9SEric Auger 			if (ue->flags)
222995a0ee9SEric Auger 				goto free_entry;
223995a0ee9SEric Auger 			break;
224ba60c41aSSudip Mukherjee 		}
225c63cf538SRadim Krčmář 		r = setup_routing_entry(kvm, new, e, ue);
226995a0ee9SEric Auger 		if (r)
227995a0ee9SEric Auger 			goto free_entry;
228e8cde093SAlexander Graf 		++ue;
229e8cde093SAlexander Graf 	}
230e8cde093SAlexander Graf 
231e8cde093SAlexander Graf 	mutex_lock(&kvm->irq_lock);
2325535f800SChristian Borntraeger 	old = rcu_dereference_protected(kvm->irq_routing, 1);
2339957c86dSPaul Mackerras 	rcu_assign_pointer(kvm->irq_routing, new);
2349957c86dSPaul Mackerras 	kvm_irq_routing_update(kvm);
235abdb080fSAndrey Smetanin 	kvm_arch_irq_routing_update(kvm);
236e8cde093SAlexander Graf 	mutex_unlock(&kvm->irq_lock);
237e8cde093SAlexander Graf 
238abdb080fSAndrey Smetanin 	kvm_arch_post_irq_routing_update(kvm);
239b053b2aeSSteve Rutherford 
240719d93cdSChristian Borntraeger 	synchronize_srcu_expedited(&kvm->irq_srcu);
241e8cde093SAlexander Graf 
242e8cde093SAlexander Graf 	new = old;
243e8cde093SAlexander Graf 	r = 0;
244995a0ee9SEric Auger 	goto out;
245e8cde093SAlexander Graf 
246995a0ee9SEric Auger free_entry:
247995a0ee9SEric Auger 	kfree(e);
248e8cde093SAlexander Graf out:
249e73f61e4SJoerg Roedel 	free_irq_routing_table(new);
250e73f61e4SJoerg Roedel 
251e8cde093SAlexander Graf 	return r;
252e8cde093SAlexander Graf }
253