xref: /kvmtool/vfio/pci.c (revision 6078a4548cfdca42c766c67947986c90310a8546)
1*6078a454SJean-Philippe Brucker #include "kvm/irq.h"
2*6078a454SJean-Philippe Brucker #include "kvm/kvm.h"
3*6078a454SJean-Philippe Brucker #include "kvm/kvm-cpu.h"
4*6078a454SJean-Philippe Brucker #include "kvm/vfio.h"
5*6078a454SJean-Philippe Brucker 
6*6078a454SJean-Philippe Brucker #include <sys/ioctl.h>
7*6078a454SJean-Philippe Brucker #include <sys/eventfd.h>
8*6078a454SJean-Philippe Brucker 
9*6078a454SJean-Philippe Brucker /* Wrapper around UAPI vfio_irq_set */
10*6078a454SJean-Philippe Brucker struct vfio_irq_eventfd {
11*6078a454SJean-Philippe Brucker 	struct vfio_irq_set	irq;
12*6078a454SJean-Philippe Brucker 	int			fd;
13*6078a454SJean-Philippe Brucker };
14*6078a454SJean-Philippe Brucker 
15*6078a454SJean-Philippe Brucker static void vfio_pci_cfg_read(struct kvm *kvm, struct pci_device_header *pci_hdr,
16*6078a454SJean-Philippe Brucker 			      u8 offset, void *data, int sz)
17*6078a454SJean-Philippe Brucker {
18*6078a454SJean-Philippe Brucker 	struct vfio_region_info *info;
19*6078a454SJean-Philippe Brucker 	struct vfio_pci_device *pdev;
20*6078a454SJean-Philippe Brucker 	struct vfio_device *vdev;
21*6078a454SJean-Philippe Brucker 	char base[sz];
22*6078a454SJean-Philippe Brucker 
23*6078a454SJean-Philippe Brucker 	pdev = container_of(pci_hdr, struct vfio_pci_device, hdr);
24*6078a454SJean-Philippe Brucker 	vdev = container_of(pdev, struct vfio_device, pci);
25*6078a454SJean-Philippe Brucker 	info = &vdev->regions[VFIO_PCI_CONFIG_REGION_INDEX].info;
26*6078a454SJean-Philippe Brucker 
27*6078a454SJean-Philippe Brucker 	/* Dummy read in case of side-effects */
28*6078a454SJean-Philippe Brucker 	if (pread(vdev->fd, base, sz, info->offset + offset) != sz)
29*6078a454SJean-Philippe Brucker 		vfio_dev_warn(vdev, "failed to read %d bytes from Configuration Space at 0x%x",
30*6078a454SJean-Philippe Brucker 			      sz, offset);
31*6078a454SJean-Philippe Brucker }
32*6078a454SJean-Philippe Brucker 
33*6078a454SJean-Philippe Brucker static void vfio_pci_cfg_write(struct kvm *kvm, struct pci_device_header *pci_hdr,
34*6078a454SJean-Philippe Brucker 			       u8 offset, void *data, int sz)
35*6078a454SJean-Philippe Brucker {
36*6078a454SJean-Philippe Brucker 	struct vfio_region_info *info;
37*6078a454SJean-Philippe Brucker 	struct vfio_pci_device *pdev;
38*6078a454SJean-Philippe Brucker 	struct vfio_device *vdev;
39*6078a454SJean-Philippe Brucker 	void *base = pci_hdr;
40*6078a454SJean-Philippe Brucker 
41*6078a454SJean-Philippe Brucker 	pdev = container_of(pci_hdr, struct vfio_pci_device, hdr);
42*6078a454SJean-Philippe Brucker 	vdev = container_of(pdev, struct vfio_device, pci);
43*6078a454SJean-Philippe Brucker 	info = &vdev->regions[VFIO_PCI_CONFIG_REGION_INDEX].info;
44*6078a454SJean-Philippe Brucker 
45*6078a454SJean-Philippe Brucker 	if (pwrite(vdev->fd, data, sz, info->offset + offset) != sz)
46*6078a454SJean-Philippe Brucker 		vfio_dev_warn(vdev, "Failed to write %d bytes to Configuration Space at 0x%x",
47*6078a454SJean-Philippe Brucker 			      sz, offset);
48*6078a454SJean-Philippe Brucker 
49*6078a454SJean-Philippe Brucker 	if (pread(vdev->fd, base + offset, sz, info->offset + offset) != sz)
50*6078a454SJean-Philippe Brucker 		vfio_dev_warn(vdev, "Failed to read %d bytes from Configuration Space at 0x%x",
51*6078a454SJean-Philippe Brucker 			      sz, offset);
52*6078a454SJean-Philippe Brucker }
53*6078a454SJean-Philippe Brucker 
54*6078a454SJean-Philippe Brucker static int vfio_pci_parse_caps(struct vfio_device *vdev)
55*6078a454SJean-Philippe Brucker {
56*6078a454SJean-Philippe Brucker 	struct vfio_pci_device *pdev = &vdev->pci;
57*6078a454SJean-Philippe Brucker 
58*6078a454SJean-Philippe Brucker 	if (!(pdev->hdr.status & PCI_STATUS_CAP_LIST))
59*6078a454SJean-Philippe Brucker 		return 0;
60*6078a454SJean-Philippe Brucker 
61*6078a454SJean-Philippe Brucker 	pdev->hdr.status &= ~PCI_STATUS_CAP_LIST;
62*6078a454SJean-Philippe Brucker 	pdev->hdr.capabilities = 0;
63*6078a454SJean-Philippe Brucker 
64*6078a454SJean-Philippe Brucker 	/* TODO: install virtual capabilities */
65*6078a454SJean-Philippe Brucker 
66*6078a454SJean-Philippe Brucker 	return 0;
67*6078a454SJean-Philippe Brucker }
68*6078a454SJean-Philippe Brucker 
69*6078a454SJean-Philippe Brucker static int vfio_pci_parse_cfg_space(struct vfio_device *vdev)
70*6078a454SJean-Philippe Brucker {
71*6078a454SJean-Philippe Brucker 	ssize_t sz = PCI_STD_HEADER_SIZEOF;
72*6078a454SJean-Philippe Brucker 	struct vfio_region_info *info;
73*6078a454SJean-Philippe Brucker 	struct vfio_pci_device *pdev = &vdev->pci;
74*6078a454SJean-Philippe Brucker 
75*6078a454SJean-Philippe Brucker 	if (vdev->info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX) {
76*6078a454SJean-Philippe Brucker 		vfio_dev_err(vdev, "Config Space not found");
77*6078a454SJean-Philippe Brucker 		return -ENODEV;
78*6078a454SJean-Philippe Brucker 	}
79*6078a454SJean-Philippe Brucker 
80*6078a454SJean-Philippe Brucker 	info = &vdev->regions[VFIO_PCI_CONFIG_REGION_INDEX].info;
81*6078a454SJean-Philippe Brucker 	*info = (struct vfio_region_info) {
82*6078a454SJean-Philippe Brucker 			.argsz = sizeof(*info),
83*6078a454SJean-Philippe Brucker 			.index = VFIO_PCI_CONFIG_REGION_INDEX,
84*6078a454SJean-Philippe Brucker 	};
85*6078a454SJean-Philippe Brucker 
86*6078a454SJean-Philippe Brucker 	ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, info);
87*6078a454SJean-Philippe Brucker 	if (!info->size) {
88*6078a454SJean-Philippe Brucker 		vfio_dev_err(vdev, "Config Space has size zero?!");
89*6078a454SJean-Philippe Brucker 		return -EINVAL;
90*6078a454SJean-Philippe Brucker 	}
91*6078a454SJean-Philippe Brucker 
92*6078a454SJean-Philippe Brucker 	if (pread(vdev->fd, &pdev->hdr, sz, info->offset) != sz) {
93*6078a454SJean-Philippe Brucker 		vfio_dev_err(vdev, "failed to read %zd bytes of Config Space", sz);
94*6078a454SJean-Philippe Brucker 		return -EIO;
95*6078a454SJean-Philippe Brucker 	}
96*6078a454SJean-Philippe Brucker 
97*6078a454SJean-Philippe Brucker 	/* Strip bit 7, that indicates multifunction */
98*6078a454SJean-Philippe Brucker 	pdev->hdr.header_type &= 0x7f;
99*6078a454SJean-Philippe Brucker 
100*6078a454SJean-Philippe Brucker 	if (pdev->hdr.header_type != PCI_HEADER_TYPE_NORMAL) {
101*6078a454SJean-Philippe Brucker 		vfio_dev_err(vdev, "unsupported header type %u",
102*6078a454SJean-Philippe Brucker 			     pdev->hdr.header_type);
103*6078a454SJean-Philippe Brucker 		return -EOPNOTSUPP;
104*6078a454SJean-Philippe Brucker 	}
105*6078a454SJean-Philippe Brucker 
106*6078a454SJean-Philippe Brucker 	vfio_pci_parse_caps(vdev);
107*6078a454SJean-Philippe Brucker 
108*6078a454SJean-Philippe Brucker 	return 0;
109*6078a454SJean-Philippe Brucker }
110*6078a454SJean-Philippe Brucker 
111*6078a454SJean-Philippe Brucker static int vfio_pci_fixup_cfg_space(struct vfio_device *vdev)
112*6078a454SJean-Philippe Brucker {
113*6078a454SJean-Philippe Brucker 	int i;
114*6078a454SJean-Philippe Brucker 	ssize_t hdr_sz;
115*6078a454SJean-Philippe Brucker 	struct vfio_region_info *info;
116*6078a454SJean-Philippe Brucker 	struct vfio_pci_device *pdev = &vdev->pci;
117*6078a454SJean-Philippe Brucker 
118*6078a454SJean-Philippe Brucker 	/* Enable exclusively MMIO and bus mastering */
119*6078a454SJean-Philippe Brucker 	pdev->hdr.command &= ~PCI_COMMAND_IO;
120*6078a454SJean-Philippe Brucker 	pdev->hdr.command |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
121*6078a454SJean-Philippe Brucker 
122*6078a454SJean-Philippe Brucker 	/* Initialise the BARs */
123*6078a454SJean-Philippe Brucker 	for (i = VFIO_PCI_BAR0_REGION_INDEX; i <= VFIO_PCI_BAR5_REGION_INDEX; ++i) {
124*6078a454SJean-Philippe Brucker 		struct vfio_region *region = &vdev->regions[i];
125*6078a454SJean-Philippe Brucker 		u64 base = region->guest_phys_addr;
126*6078a454SJean-Philippe Brucker 
127*6078a454SJean-Philippe Brucker 		if (!base)
128*6078a454SJean-Philippe Brucker 			continue;
129*6078a454SJean-Philippe Brucker 
130*6078a454SJean-Philippe Brucker 		pdev->hdr.bar_size[i] = region->info.size;
131*6078a454SJean-Philippe Brucker 
132*6078a454SJean-Philippe Brucker 		/* Construct a fake reg to match what we've mapped. */
133*6078a454SJean-Philippe Brucker 		pdev->hdr.bar[i] = (base & PCI_BASE_ADDRESS_MEM_MASK) |
134*6078a454SJean-Philippe Brucker 					PCI_BASE_ADDRESS_SPACE_MEMORY |
135*6078a454SJean-Philippe Brucker 					PCI_BASE_ADDRESS_MEM_TYPE_32;
136*6078a454SJean-Philippe Brucker 	}
137*6078a454SJean-Philippe Brucker 
138*6078a454SJean-Philippe Brucker 	/* I really can't be bothered to support cardbus. */
139*6078a454SJean-Philippe Brucker 	pdev->hdr.card_bus = 0;
140*6078a454SJean-Philippe Brucker 
141*6078a454SJean-Philippe Brucker 	/*
142*6078a454SJean-Philippe Brucker 	 * Nuke the expansion ROM for now. If we want to do this properly,
143*6078a454SJean-Philippe Brucker 	 * we need to save its size somewhere and map into the guest.
144*6078a454SJean-Philippe Brucker 	 */
145*6078a454SJean-Philippe Brucker 	pdev->hdr.exp_rom_bar = 0;
146*6078a454SJean-Philippe Brucker 
147*6078a454SJean-Philippe Brucker 	/* Install our fake Configuration Space */
148*6078a454SJean-Philippe Brucker 	info = &vdev->regions[VFIO_PCI_CONFIG_REGION_INDEX].info;
149*6078a454SJean-Philippe Brucker 	hdr_sz = PCI_DEV_CFG_SIZE;
150*6078a454SJean-Philippe Brucker 	if (pwrite(vdev->fd, &pdev->hdr, hdr_sz, info->offset) != hdr_sz) {
151*6078a454SJean-Philippe Brucker 		vfio_dev_err(vdev, "failed to write %zd bytes to Config Space",
152*6078a454SJean-Philippe Brucker 			     hdr_sz);
153*6078a454SJean-Philippe Brucker 		return -EIO;
154*6078a454SJean-Philippe Brucker 	}
155*6078a454SJean-Philippe Brucker 
156*6078a454SJean-Philippe Brucker 	/* Register callbacks for cfg accesses */
157*6078a454SJean-Philippe Brucker 	pdev->hdr.cfg_ops = (struct pci_config_operations) {
158*6078a454SJean-Philippe Brucker 		.read	= vfio_pci_cfg_read,
159*6078a454SJean-Philippe Brucker 		.write	= vfio_pci_cfg_write,
160*6078a454SJean-Philippe Brucker 	};
161*6078a454SJean-Philippe Brucker 
162*6078a454SJean-Philippe Brucker 	pdev->hdr.irq_type = IRQ_TYPE_LEVEL_HIGH;
163*6078a454SJean-Philippe Brucker 
164*6078a454SJean-Philippe Brucker 	return 0;
165*6078a454SJean-Philippe Brucker }
166*6078a454SJean-Philippe Brucker 
167*6078a454SJean-Philippe Brucker static int vfio_pci_configure_bar(struct kvm *kvm, struct vfio_device *vdev,
168*6078a454SJean-Philippe Brucker 				  size_t nr)
169*6078a454SJean-Philippe Brucker {
170*6078a454SJean-Philippe Brucker 	int ret;
171*6078a454SJean-Philippe Brucker 	size_t map_size;
172*6078a454SJean-Philippe Brucker 	struct vfio_region *region = &vdev->regions[nr];
173*6078a454SJean-Philippe Brucker 
174*6078a454SJean-Philippe Brucker 	if (nr >= vdev->info.num_regions)
175*6078a454SJean-Philippe Brucker 		return 0;
176*6078a454SJean-Philippe Brucker 
177*6078a454SJean-Philippe Brucker 	region->info = (struct vfio_region_info) {
178*6078a454SJean-Philippe Brucker 		.argsz = sizeof(region->info),
179*6078a454SJean-Philippe Brucker 		.index = nr,
180*6078a454SJean-Philippe Brucker 	};
181*6078a454SJean-Philippe Brucker 
182*6078a454SJean-Philippe Brucker 	ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, &region->info);
183*6078a454SJean-Philippe Brucker 	if (ret) {
184*6078a454SJean-Philippe Brucker 		ret = -errno;
185*6078a454SJean-Philippe Brucker 		vfio_dev_err(vdev, "cannot get info for BAR %zu", nr);
186*6078a454SJean-Philippe Brucker 		return ret;
187*6078a454SJean-Philippe Brucker 	}
188*6078a454SJean-Philippe Brucker 
189*6078a454SJean-Philippe Brucker 	/* Ignore invalid or unimplemented regions */
190*6078a454SJean-Philippe Brucker 	if (!region->info.size)
191*6078a454SJean-Philippe Brucker 		return 0;
192*6078a454SJean-Philippe Brucker 
193*6078a454SJean-Philippe Brucker 	/* Grab some MMIO space in the guest */
194*6078a454SJean-Philippe Brucker 	map_size = ALIGN(region->info.size, PAGE_SIZE);
195*6078a454SJean-Philippe Brucker 	region->guest_phys_addr = pci_get_io_space_block(map_size);
196*6078a454SJean-Philippe Brucker 
197*6078a454SJean-Philippe Brucker 	/*
198*6078a454SJean-Philippe Brucker 	 * Map the BARs into the guest. We'll later need to update
199*6078a454SJean-Philippe Brucker 	 * configuration space to reflect our allocation.
200*6078a454SJean-Philippe Brucker 	 */
201*6078a454SJean-Philippe Brucker 	ret = vfio_map_region(kvm, vdev, region);
202*6078a454SJean-Philippe Brucker 	if (ret)
203*6078a454SJean-Philippe Brucker 		return ret;
204*6078a454SJean-Philippe Brucker 
205*6078a454SJean-Philippe Brucker 	return 0;
206*6078a454SJean-Philippe Brucker }
207*6078a454SJean-Philippe Brucker 
208*6078a454SJean-Philippe Brucker static int vfio_pci_configure_dev_regions(struct kvm *kvm,
209*6078a454SJean-Philippe Brucker 					  struct vfio_device *vdev)
210*6078a454SJean-Philippe Brucker {
211*6078a454SJean-Philippe Brucker 	int ret;
212*6078a454SJean-Philippe Brucker 	u32 bar;
213*6078a454SJean-Philippe Brucker 	size_t i;
214*6078a454SJean-Philippe Brucker 	bool is_64bit = false;
215*6078a454SJean-Philippe Brucker 	struct vfio_pci_device *pdev = &vdev->pci;
216*6078a454SJean-Philippe Brucker 
217*6078a454SJean-Philippe Brucker 	ret = vfio_pci_parse_cfg_space(vdev);
218*6078a454SJean-Philippe Brucker 	if (ret)
219*6078a454SJean-Philippe Brucker 		return ret;
220*6078a454SJean-Philippe Brucker 
221*6078a454SJean-Philippe Brucker 	for (i = VFIO_PCI_BAR0_REGION_INDEX; i <= VFIO_PCI_BAR5_REGION_INDEX; ++i) {
222*6078a454SJean-Philippe Brucker 		/* Ignore top half of 64-bit BAR */
223*6078a454SJean-Philippe Brucker 		if (i % 2 && is_64bit)
224*6078a454SJean-Philippe Brucker 			continue;
225*6078a454SJean-Philippe Brucker 
226*6078a454SJean-Philippe Brucker 		ret = vfio_pci_configure_bar(kvm, vdev, i);
227*6078a454SJean-Philippe Brucker 		if (ret)
228*6078a454SJean-Philippe Brucker 			return ret;
229*6078a454SJean-Philippe Brucker 
230*6078a454SJean-Philippe Brucker 		bar = pdev->hdr.bar[i];
231*6078a454SJean-Philippe Brucker 		is_64bit = (bar & PCI_BASE_ADDRESS_SPACE) ==
232*6078a454SJean-Philippe Brucker 			   PCI_BASE_ADDRESS_SPACE_MEMORY &&
233*6078a454SJean-Philippe Brucker 			   bar & PCI_BASE_ADDRESS_MEM_TYPE_64;
234*6078a454SJean-Philippe Brucker 	}
235*6078a454SJean-Philippe Brucker 
236*6078a454SJean-Philippe Brucker 	/* We've configured the BARs, fake up a Configuration Space */
237*6078a454SJean-Philippe Brucker 	return vfio_pci_fixup_cfg_space(vdev);
238*6078a454SJean-Philippe Brucker }
239*6078a454SJean-Philippe Brucker 
240*6078a454SJean-Philippe Brucker static int vfio_pci_enable_intx(struct kvm *kvm, struct vfio_device *vdev)
241*6078a454SJean-Philippe Brucker {
242*6078a454SJean-Philippe Brucker 	int ret;
243*6078a454SJean-Philippe Brucker 	int trigger_fd, unmask_fd;
244*6078a454SJean-Philippe Brucker 	struct vfio_irq_eventfd	trigger;
245*6078a454SJean-Philippe Brucker 	struct vfio_irq_eventfd	unmask;
246*6078a454SJean-Philippe Brucker 	struct vfio_pci_device *pdev = &vdev->pci;
247*6078a454SJean-Philippe Brucker 	int gsi = pdev->hdr.irq_line - KVM_IRQ_OFFSET;
248*6078a454SJean-Philippe Brucker 
249*6078a454SJean-Philippe Brucker 	struct vfio_irq_info irq_info = {
250*6078a454SJean-Philippe Brucker 		.argsz = sizeof(irq_info),
251*6078a454SJean-Philippe Brucker 		.index = VFIO_PCI_INTX_IRQ_INDEX,
252*6078a454SJean-Philippe Brucker 	};
253*6078a454SJean-Philippe Brucker 
254*6078a454SJean-Philippe Brucker 	ret = ioctl(vdev->fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info);
255*6078a454SJean-Philippe Brucker 	if (ret || irq_info.count == 0) {
256*6078a454SJean-Philippe Brucker 		vfio_dev_err(vdev, "no INTx reported by VFIO");
257*6078a454SJean-Philippe Brucker 		return -ENODEV;
258*6078a454SJean-Philippe Brucker 	}
259*6078a454SJean-Philippe Brucker 
260*6078a454SJean-Philippe Brucker 	if (!(irq_info.flags & VFIO_IRQ_INFO_EVENTFD)) {
261*6078a454SJean-Philippe Brucker 		vfio_dev_err(vdev, "interrupt not eventfd capable");
262*6078a454SJean-Philippe Brucker 		return -EINVAL;
263*6078a454SJean-Philippe Brucker 	}
264*6078a454SJean-Philippe Brucker 
265*6078a454SJean-Philippe Brucker 	if (!(irq_info.flags & VFIO_IRQ_INFO_AUTOMASKED)) {
266*6078a454SJean-Philippe Brucker 		vfio_dev_err(vdev, "INTx interrupt not AUTOMASKED");
267*6078a454SJean-Philippe Brucker 		return -EINVAL;
268*6078a454SJean-Philippe Brucker 	}
269*6078a454SJean-Philippe Brucker 
270*6078a454SJean-Philippe Brucker 	/*
271*6078a454SJean-Philippe Brucker 	 * PCI IRQ is level-triggered, so we use two eventfds. trigger_fd
272*6078a454SJean-Philippe Brucker 	 * signals an interrupt from host to guest, and unmask_fd signals the
273*6078a454SJean-Philippe Brucker 	 * deassertion of the line from guest to host.
274*6078a454SJean-Philippe Brucker 	 */
275*6078a454SJean-Philippe Brucker 	trigger_fd = eventfd(0, 0);
276*6078a454SJean-Philippe Brucker 	if (trigger_fd < 0) {
277*6078a454SJean-Philippe Brucker 		vfio_dev_err(vdev, "failed to create trigger eventfd");
278*6078a454SJean-Philippe Brucker 		return trigger_fd;
279*6078a454SJean-Philippe Brucker 	}
280*6078a454SJean-Philippe Brucker 
281*6078a454SJean-Philippe Brucker 	unmask_fd = eventfd(0, 0);
282*6078a454SJean-Philippe Brucker 	if (unmask_fd < 0) {
283*6078a454SJean-Philippe Brucker 		vfio_dev_err(vdev, "failed to create unmask eventfd");
284*6078a454SJean-Philippe Brucker 		close(trigger_fd);
285*6078a454SJean-Philippe Brucker 		return unmask_fd;
286*6078a454SJean-Philippe Brucker 	}
287*6078a454SJean-Philippe Brucker 
288*6078a454SJean-Philippe Brucker 	ret = irq__add_irqfd(kvm, gsi, trigger_fd, unmask_fd);
289*6078a454SJean-Philippe Brucker 	if (ret)
290*6078a454SJean-Philippe Brucker 		goto err_close;
291*6078a454SJean-Philippe Brucker 
292*6078a454SJean-Philippe Brucker 	trigger.irq = (struct vfio_irq_set) {
293*6078a454SJean-Philippe Brucker 		.argsz	= sizeof(trigger),
294*6078a454SJean-Philippe Brucker 		.flags	= VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER,
295*6078a454SJean-Philippe Brucker 		.index	= VFIO_PCI_INTX_IRQ_INDEX,
296*6078a454SJean-Philippe Brucker 		.start	= 0,
297*6078a454SJean-Philippe Brucker 		.count	= 1,
298*6078a454SJean-Philippe Brucker 	};
299*6078a454SJean-Philippe Brucker 	trigger.fd = trigger_fd;
300*6078a454SJean-Philippe Brucker 
301*6078a454SJean-Philippe Brucker 	ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &trigger);
302*6078a454SJean-Philippe Brucker 	if (ret < 0) {
303*6078a454SJean-Philippe Brucker 		vfio_dev_err(vdev, "failed to setup VFIO IRQ");
304*6078a454SJean-Philippe Brucker 		goto err_delete_line;
305*6078a454SJean-Philippe Brucker 	}
306*6078a454SJean-Philippe Brucker 
307*6078a454SJean-Philippe Brucker 	unmask.irq = (struct vfio_irq_set) {
308*6078a454SJean-Philippe Brucker 		.argsz	= sizeof(unmask),
309*6078a454SJean-Philippe Brucker 		.flags	= VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_UNMASK,
310*6078a454SJean-Philippe Brucker 		.index	= VFIO_PCI_INTX_IRQ_INDEX,
311*6078a454SJean-Philippe Brucker 		.start	= 0,
312*6078a454SJean-Philippe Brucker 		.count	= 1,
313*6078a454SJean-Philippe Brucker 	};
314*6078a454SJean-Philippe Brucker 	unmask.fd = unmask_fd;
315*6078a454SJean-Philippe Brucker 
316*6078a454SJean-Philippe Brucker 	ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &unmask);
317*6078a454SJean-Philippe Brucker 	if (ret < 0) {
318*6078a454SJean-Philippe Brucker 		vfio_dev_err(vdev, "failed to setup unmask IRQ");
319*6078a454SJean-Philippe Brucker 		goto err_remove_event;
320*6078a454SJean-Philippe Brucker 	}
321*6078a454SJean-Philippe Brucker 
322*6078a454SJean-Philippe Brucker 	return 0;
323*6078a454SJean-Philippe Brucker 
324*6078a454SJean-Philippe Brucker err_remove_event:
325*6078a454SJean-Philippe Brucker 	/* Remove trigger event */
326*6078a454SJean-Philippe Brucker 	trigger.irq.flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER;
327*6078a454SJean-Philippe Brucker 	trigger.irq.count = 0;
328*6078a454SJean-Philippe Brucker 	ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &trigger);
329*6078a454SJean-Philippe Brucker 
330*6078a454SJean-Philippe Brucker err_delete_line:
331*6078a454SJean-Philippe Brucker 	irq__del_irqfd(kvm, gsi, trigger_fd);
332*6078a454SJean-Philippe Brucker 
333*6078a454SJean-Philippe Brucker err_close:
334*6078a454SJean-Philippe Brucker 	close(trigger_fd);
335*6078a454SJean-Philippe Brucker 	close(unmask_fd);
336*6078a454SJean-Philippe Brucker 	return ret;
337*6078a454SJean-Philippe Brucker }
338*6078a454SJean-Philippe Brucker 
339*6078a454SJean-Philippe Brucker static int vfio_pci_configure_dev_irqs(struct kvm *kvm, struct vfio_device *vdev)
340*6078a454SJean-Philippe Brucker {
341*6078a454SJean-Philippe Brucker 	struct vfio_pci_device *pdev = &vdev->pci;
342*6078a454SJean-Philippe Brucker 
343*6078a454SJean-Philippe Brucker 	struct vfio_irq_info irq_info = {
344*6078a454SJean-Philippe Brucker 		.argsz = sizeof(irq_info),
345*6078a454SJean-Philippe Brucker 		.index = VFIO_PCI_INTX_IRQ_INDEX,
346*6078a454SJean-Philippe Brucker 	};
347*6078a454SJean-Philippe Brucker 
348*6078a454SJean-Philippe Brucker 	if (!pdev->hdr.irq_pin) {
349*6078a454SJean-Philippe Brucker 		/* TODO: add MSI support */
350*6078a454SJean-Philippe Brucker 		vfio_dev_err(vdev, "INTx not available, MSI-X not implemented");
351*6078a454SJean-Philippe Brucker 		return -ENOSYS;
352*6078a454SJean-Philippe Brucker 	}
353*6078a454SJean-Philippe Brucker 
354*6078a454SJean-Philippe Brucker 	return vfio_pci_enable_intx(kvm, vdev);
355*6078a454SJean-Philippe Brucker }
356*6078a454SJean-Philippe Brucker 
357*6078a454SJean-Philippe Brucker int vfio_pci_setup_device(struct kvm *kvm, struct vfio_device *vdev)
358*6078a454SJean-Philippe Brucker {
359*6078a454SJean-Philippe Brucker 	int ret;
360*6078a454SJean-Philippe Brucker 
361*6078a454SJean-Philippe Brucker 	ret = vfio_pci_configure_dev_regions(kvm, vdev);
362*6078a454SJean-Philippe Brucker 	if (ret) {
363*6078a454SJean-Philippe Brucker 		vfio_dev_err(vdev, "failed to configure regions");
364*6078a454SJean-Philippe Brucker 		return ret;
365*6078a454SJean-Philippe Brucker 	}
366*6078a454SJean-Philippe Brucker 
367*6078a454SJean-Philippe Brucker 	vdev->dev_hdr = (struct device_header) {
368*6078a454SJean-Philippe Brucker 		.bus_type	= DEVICE_BUS_PCI,
369*6078a454SJean-Philippe Brucker 		.data		= &vdev->pci.hdr,
370*6078a454SJean-Philippe Brucker 	};
371*6078a454SJean-Philippe Brucker 
372*6078a454SJean-Philippe Brucker 	ret = device__register(&vdev->dev_hdr);
373*6078a454SJean-Philippe Brucker 	if (ret) {
374*6078a454SJean-Philippe Brucker 		vfio_dev_err(vdev, "failed to register VFIO device");
375*6078a454SJean-Philippe Brucker 		return ret;
376*6078a454SJean-Philippe Brucker 	}
377*6078a454SJean-Philippe Brucker 
378*6078a454SJean-Philippe Brucker 	ret = vfio_pci_configure_dev_irqs(kvm, vdev);
379*6078a454SJean-Philippe Brucker 	if (ret) {
380*6078a454SJean-Philippe Brucker 		vfio_dev_err(vdev, "failed to configure IRQs");
381*6078a454SJean-Philippe Brucker 		return ret;
382*6078a454SJean-Philippe Brucker 	}
383*6078a454SJean-Philippe Brucker 
384*6078a454SJean-Philippe Brucker 	return 0;
385*6078a454SJean-Philippe Brucker }
386*6078a454SJean-Philippe Brucker 
387*6078a454SJean-Philippe Brucker void vfio_pci_teardown_device(struct kvm *kvm, struct vfio_device *vdev)
388*6078a454SJean-Philippe Brucker {
389*6078a454SJean-Philippe Brucker 	size_t i;
390*6078a454SJean-Philippe Brucker 
391*6078a454SJean-Philippe Brucker 	for (i = 0; i < vdev->info.num_regions; i++)
392*6078a454SJean-Philippe Brucker 		vfio_unmap_region(kvm, &vdev->regions[i]);
393*6078a454SJean-Philippe Brucker 
394*6078a454SJean-Philippe Brucker 	device__unregister(&vdev->dev_hdr);
395*6078a454SJean-Philippe Brucker }
396