xref: /dpdk/drivers/bus/pci/linux/pci_vfio.c (revision 77dad68c20f8f77e20dd9618c00d211b650c387e)
1c752998bSGaetan Rivet /*-
2c752998bSGaetan Rivet  *   BSD LICENSE
3c752998bSGaetan Rivet  *
4c752998bSGaetan Rivet  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5c752998bSGaetan Rivet  *   All rights reserved.
6c752998bSGaetan Rivet  *
7c752998bSGaetan Rivet  *   Redistribution and use in source and binary forms, with or without
8c752998bSGaetan Rivet  *   modification, are permitted provided that the following conditions
9c752998bSGaetan Rivet  *   are met:
10c752998bSGaetan Rivet  *
11c752998bSGaetan Rivet  *     * Redistributions of source code must retain the above copyright
12c752998bSGaetan Rivet  *       notice, this list of conditions and the following disclaimer.
13c752998bSGaetan Rivet  *     * Redistributions in binary form must reproduce the above copyright
14c752998bSGaetan Rivet  *       notice, this list of conditions and the following disclaimer in
15c752998bSGaetan Rivet  *       the documentation and/or other materials provided with the
16c752998bSGaetan Rivet  *       distribution.
17c752998bSGaetan Rivet  *     * Neither the name of Intel Corporation nor the names of its
18c752998bSGaetan Rivet  *       contributors may be used to endorse or promote products derived
19c752998bSGaetan Rivet  *       from this software without specific prior written permission.
20c752998bSGaetan Rivet  *
21c752998bSGaetan Rivet  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22c752998bSGaetan Rivet  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23c752998bSGaetan Rivet  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24c752998bSGaetan Rivet  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25c752998bSGaetan Rivet  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26c752998bSGaetan Rivet  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27c752998bSGaetan Rivet  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28c752998bSGaetan Rivet  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29c752998bSGaetan Rivet  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30c752998bSGaetan Rivet  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31c752998bSGaetan Rivet  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32c752998bSGaetan Rivet  */
33c752998bSGaetan Rivet 
34c752998bSGaetan Rivet #include <string.h>
35c752998bSGaetan Rivet #include <fcntl.h>
36c752998bSGaetan Rivet #include <linux/pci_regs.h>
37c752998bSGaetan Rivet #include <sys/eventfd.h>
38c752998bSGaetan Rivet #include <sys/socket.h>
39c752998bSGaetan Rivet #include <sys/ioctl.h>
40c752998bSGaetan Rivet #include <sys/mman.h>
41c752998bSGaetan Rivet #include <stdbool.h>
42c752998bSGaetan Rivet 
43c752998bSGaetan Rivet #include <rte_log.h>
44c752998bSGaetan Rivet #include <rte_pci.h>
45c752998bSGaetan Rivet #include <rte_bus_pci.h>
46c752998bSGaetan Rivet #include <rte_eal_memconfig.h>
47c752998bSGaetan Rivet #include <rte_malloc.h>
48c752998bSGaetan Rivet #include <rte_vfio.h>
49c752998bSGaetan Rivet 
50c752998bSGaetan Rivet #include "eal_filesystem.h"
51c752998bSGaetan Rivet 
52c752998bSGaetan Rivet #include "pci_init.h"
53c752998bSGaetan Rivet #include "private.h"
54c752998bSGaetan Rivet 
55c752998bSGaetan Rivet /**
56c752998bSGaetan Rivet  * @file
57c752998bSGaetan Rivet  * PCI probing under linux (VFIO version)
58c752998bSGaetan Rivet  *
59c752998bSGaetan Rivet  * This code tries to determine if the PCI device is bound to VFIO driver,
60c752998bSGaetan Rivet  * and initialize it (map BARs, set up interrupts) if that's the case.
61c752998bSGaetan Rivet  *
62c752998bSGaetan Rivet  * This file is only compiled if CONFIG_RTE_EAL_VFIO is set to "y".
63c752998bSGaetan Rivet  */
64c752998bSGaetan Rivet 
65bc104bb8SFerruh Yigit #ifdef VFIO_PRESENT
66c752998bSGaetan Rivet 
67c752998bSGaetan Rivet #define PAGE_SIZE   (sysconf(_SC_PAGESIZE))
68c752998bSGaetan Rivet #define PAGE_MASK   (~(PAGE_SIZE - 1))
69c752998bSGaetan Rivet 
70c752998bSGaetan Rivet static struct rte_tailq_elem rte_vfio_tailq = {
71c752998bSGaetan Rivet 	.name = "VFIO_RESOURCE_LIST",
72c752998bSGaetan Rivet };
73c752998bSGaetan Rivet EAL_REGISTER_TAILQ(rte_vfio_tailq)
74c752998bSGaetan Rivet 
75c752998bSGaetan Rivet int
76c752998bSGaetan Rivet pci_vfio_read_config(const struct rte_intr_handle *intr_handle,
77c752998bSGaetan Rivet 		    void *buf, size_t len, off_t offs)
78c752998bSGaetan Rivet {
79c752998bSGaetan Rivet 	return pread64(intr_handle->vfio_dev_fd, buf, len,
80c752998bSGaetan Rivet 	       VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX) + offs);
81c752998bSGaetan Rivet }
82c752998bSGaetan Rivet 
83c752998bSGaetan Rivet int
84c752998bSGaetan Rivet pci_vfio_write_config(const struct rte_intr_handle *intr_handle,
85c752998bSGaetan Rivet 		    const void *buf, size_t len, off_t offs)
86c752998bSGaetan Rivet {
87c752998bSGaetan Rivet 	return pwrite64(intr_handle->vfio_dev_fd, buf, len,
88c752998bSGaetan Rivet 	       VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX) + offs);
89c752998bSGaetan Rivet }
90c752998bSGaetan Rivet 
91c752998bSGaetan Rivet /* get PCI BAR number where MSI-X interrupts are */
92c752998bSGaetan Rivet static int
93c752998bSGaetan Rivet pci_vfio_get_msix_bar(int fd, struct pci_msix_table *msix_table)
94c752998bSGaetan Rivet {
95c752998bSGaetan Rivet 	int ret;
96c752998bSGaetan Rivet 	uint32_t reg;
97c752998bSGaetan Rivet 	uint16_t flags;
98c752998bSGaetan Rivet 	uint8_t cap_id, cap_offset;
99c752998bSGaetan Rivet 
100c752998bSGaetan Rivet 	/* read PCI capability pointer from config space */
101c752998bSGaetan Rivet 	ret = pread64(fd, &reg, sizeof(reg),
102c752998bSGaetan Rivet 			VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX) +
103c752998bSGaetan Rivet 			PCI_CAPABILITY_LIST);
104c752998bSGaetan Rivet 	if (ret != sizeof(reg)) {
105c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "Cannot read capability pointer from PCI "
106c752998bSGaetan Rivet 				"config space!\n");
107c752998bSGaetan Rivet 		return -1;
108c752998bSGaetan Rivet 	}
109c752998bSGaetan Rivet 
110c752998bSGaetan Rivet 	/* we need first byte */
111c752998bSGaetan Rivet 	cap_offset = reg & 0xFF;
112c752998bSGaetan Rivet 
113c752998bSGaetan Rivet 	while (cap_offset) {
114c752998bSGaetan Rivet 
115c752998bSGaetan Rivet 		/* read PCI capability ID */
116c752998bSGaetan Rivet 		ret = pread64(fd, &reg, sizeof(reg),
117c752998bSGaetan Rivet 				VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX) +
118c752998bSGaetan Rivet 				cap_offset);
119c752998bSGaetan Rivet 		if (ret != sizeof(reg)) {
120c752998bSGaetan Rivet 			RTE_LOG(ERR, EAL, "Cannot read capability ID from PCI "
121c752998bSGaetan Rivet 					"config space!\n");
122c752998bSGaetan Rivet 			return -1;
123c752998bSGaetan Rivet 		}
124c752998bSGaetan Rivet 
125c752998bSGaetan Rivet 		/* we need first byte */
126c752998bSGaetan Rivet 		cap_id = reg & 0xFF;
127c752998bSGaetan Rivet 
128c752998bSGaetan Rivet 		/* if we haven't reached MSI-X, check next capability */
129c752998bSGaetan Rivet 		if (cap_id != PCI_CAP_ID_MSIX) {
130c752998bSGaetan Rivet 			ret = pread64(fd, &reg, sizeof(reg),
131c752998bSGaetan Rivet 					VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX) +
132c752998bSGaetan Rivet 					cap_offset);
133c752998bSGaetan Rivet 			if (ret != sizeof(reg)) {
134c752998bSGaetan Rivet 				RTE_LOG(ERR, EAL, "Cannot read capability pointer from PCI "
135c752998bSGaetan Rivet 						"config space!\n");
136c752998bSGaetan Rivet 				return -1;
137c752998bSGaetan Rivet 			}
138c752998bSGaetan Rivet 
139c752998bSGaetan Rivet 			/* we need second byte */
140c752998bSGaetan Rivet 			cap_offset = (reg & 0xFF00) >> 8;
141c752998bSGaetan Rivet 
142c752998bSGaetan Rivet 			continue;
143c752998bSGaetan Rivet 		}
144c752998bSGaetan Rivet 		/* else, read table offset */
145c752998bSGaetan Rivet 		else {
146c752998bSGaetan Rivet 			/* table offset resides in the next 4 bytes */
147c752998bSGaetan Rivet 			ret = pread64(fd, &reg, sizeof(reg),
148c752998bSGaetan Rivet 					VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX) +
149c752998bSGaetan Rivet 					cap_offset + 4);
150c752998bSGaetan Rivet 			if (ret != sizeof(reg)) {
151c752998bSGaetan Rivet 				RTE_LOG(ERR, EAL, "Cannot read table offset from PCI config "
152c752998bSGaetan Rivet 						"space!\n");
153c752998bSGaetan Rivet 				return -1;
154c752998bSGaetan Rivet 			}
155c752998bSGaetan Rivet 
156c752998bSGaetan Rivet 			ret = pread64(fd, &flags, sizeof(flags),
157c752998bSGaetan Rivet 					VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX) +
158c752998bSGaetan Rivet 					cap_offset + 2);
159c752998bSGaetan Rivet 			if (ret != sizeof(flags)) {
160c752998bSGaetan Rivet 				RTE_LOG(ERR, EAL, "Cannot read table flags from PCI config "
161c752998bSGaetan Rivet 						"space!\n");
162c752998bSGaetan Rivet 				return -1;
163c752998bSGaetan Rivet 			}
164c752998bSGaetan Rivet 
165c752998bSGaetan Rivet 			msix_table->bar_index = reg & RTE_PCI_MSIX_TABLE_BIR;
166c752998bSGaetan Rivet 			msix_table->offset = reg & RTE_PCI_MSIX_TABLE_OFFSET;
167c752998bSGaetan Rivet 			msix_table->size =
168c752998bSGaetan Rivet 				16 * (1 + (flags & RTE_PCI_MSIX_FLAGS_QSIZE));
169c752998bSGaetan Rivet 
170c752998bSGaetan Rivet 			return 0;
171c752998bSGaetan Rivet 		}
172c752998bSGaetan Rivet 	}
173c752998bSGaetan Rivet 	return 0;
174c752998bSGaetan Rivet }
175c752998bSGaetan Rivet 
176c752998bSGaetan Rivet /* set PCI bus mastering */
177c752998bSGaetan Rivet static int
178c752998bSGaetan Rivet pci_vfio_set_bus_master(int dev_fd, bool op)
179c752998bSGaetan Rivet {
180c752998bSGaetan Rivet 	uint16_t reg;
181c752998bSGaetan Rivet 	int ret;
182c752998bSGaetan Rivet 
183c752998bSGaetan Rivet 	ret = pread64(dev_fd, &reg, sizeof(reg),
184c752998bSGaetan Rivet 			VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX) +
185c752998bSGaetan Rivet 			PCI_COMMAND);
186c752998bSGaetan Rivet 	if (ret != sizeof(reg)) {
187c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "Cannot read command from PCI config space!\n");
188c752998bSGaetan Rivet 		return -1;
189c752998bSGaetan Rivet 	}
190c752998bSGaetan Rivet 
191c752998bSGaetan Rivet 	if (op)
192c752998bSGaetan Rivet 		/* set the master bit */
193c752998bSGaetan Rivet 		reg |= PCI_COMMAND_MASTER;
194c752998bSGaetan Rivet 	else
195c752998bSGaetan Rivet 		reg &= ~(PCI_COMMAND_MASTER);
196c752998bSGaetan Rivet 
197c752998bSGaetan Rivet 	ret = pwrite64(dev_fd, &reg, sizeof(reg),
198c752998bSGaetan Rivet 			VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX) +
199c752998bSGaetan Rivet 			PCI_COMMAND);
200c752998bSGaetan Rivet 
201c752998bSGaetan Rivet 	if (ret != sizeof(reg)) {
202c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "Cannot write command to PCI config space!\n");
203c752998bSGaetan Rivet 		return -1;
204c752998bSGaetan Rivet 	}
205c752998bSGaetan Rivet 
206c752998bSGaetan Rivet 	return 0;
207c752998bSGaetan Rivet }
208c752998bSGaetan Rivet 
209c752998bSGaetan Rivet /* set up interrupt support (but not enable interrupts) */
210c752998bSGaetan Rivet static int
211c752998bSGaetan Rivet pci_vfio_setup_interrupts(struct rte_pci_device *dev, int vfio_dev_fd)
212c752998bSGaetan Rivet {
213c752998bSGaetan Rivet 	int i, ret, intr_idx;
214c752998bSGaetan Rivet 	enum rte_intr_mode intr_mode;
215c752998bSGaetan Rivet 
216c752998bSGaetan Rivet 	/* default to invalid index */
217c752998bSGaetan Rivet 	intr_idx = VFIO_PCI_NUM_IRQS;
218c752998bSGaetan Rivet 
219c752998bSGaetan Rivet 	/* Get default / configured intr_mode */
220c752998bSGaetan Rivet 	intr_mode = rte_eal_vfio_intr_mode();
221c752998bSGaetan Rivet 
222c752998bSGaetan Rivet 	/* get interrupt type from internal config (MSI-X by default, can be
223c752998bSGaetan Rivet 	 * overridden from the command line
224c752998bSGaetan Rivet 	 */
225c752998bSGaetan Rivet 	switch (intr_mode) {
226c752998bSGaetan Rivet 	case RTE_INTR_MODE_MSIX:
227c752998bSGaetan Rivet 		intr_idx = VFIO_PCI_MSIX_IRQ_INDEX;
228c752998bSGaetan Rivet 		break;
229c752998bSGaetan Rivet 	case RTE_INTR_MODE_MSI:
230c752998bSGaetan Rivet 		intr_idx = VFIO_PCI_MSI_IRQ_INDEX;
231c752998bSGaetan Rivet 		break;
232c752998bSGaetan Rivet 	case RTE_INTR_MODE_LEGACY:
233c752998bSGaetan Rivet 		intr_idx = VFIO_PCI_INTX_IRQ_INDEX;
234c752998bSGaetan Rivet 		break;
235c752998bSGaetan Rivet 	/* don't do anything if we want to automatically determine interrupt type */
236c752998bSGaetan Rivet 	case RTE_INTR_MODE_NONE:
237c752998bSGaetan Rivet 		break;
238c752998bSGaetan Rivet 	default:
239c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "  unknown default interrupt type!\n");
240c752998bSGaetan Rivet 		return -1;
241c752998bSGaetan Rivet 	}
242c752998bSGaetan Rivet 
243c752998bSGaetan Rivet 	/* start from MSI-X interrupt type */
244c752998bSGaetan Rivet 	for (i = VFIO_PCI_MSIX_IRQ_INDEX; i >= 0; i--) {
245c752998bSGaetan Rivet 		struct vfio_irq_info irq = { .argsz = sizeof(irq) };
246c752998bSGaetan Rivet 		int fd = -1;
247c752998bSGaetan Rivet 
248c752998bSGaetan Rivet 		/* skip interrupt modes we don't want */
249c752998bSGaetan Rivet 		if (intr_mode != RTE_INTR_MODE_NONE &&
250c752998bSGaetan Rivet 				i != intr_idx)
251c752998bSGaetan Rivet 			continue;
252c752998bSGaetan Rivet 
253c752998bSGaetan Rivet 		irq.index = i;
254c752998bSGaetan Rivet 
255c752998bSGaetan Rivet 		ret = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_IRQ_INFO, &irq);
256c752998bSGaetan Rivet 		if (ret < 0) {
257c752998bSGaetan Rivet 			RTE_LOG(ERR, EAL, "  cannot get IRQ info, "
258c752998bSGaetan Rivet 					"error %i (%s)\n", errno, strerror(errno));
259c752998bSGaetan Rivet 			return -1;
260c752998bSGaetan Rivet 		}
261c752998bSGaetan Rivet 
262c752998bSGaetan Rivet 		/* if this vector cannot be used with eventfd, fail if we explicitly
263c752998bSGaetan Rivet 		 * specified interrupt type, otherwise continue */
264c752998bSGaetan Rivet 		if ((irq.flags & VFIO_IRQ_INFO_EVENTFD) == 0) {
265c752998bSGaetan Rivet 			if (intr_mode != RTE_INTR_MODE_NONE) {
266c752998bSGaetan Rivet 				RTE_LOG(ERR, EAL,
267c752998bSGaetan Rivet 						"  interrupt vector does not support eventfd!\n");
268c752998bSGaetan Rivet 				return -1;
269c752998bSGaetan Rivet 			} else
270c752998bSGaetan Rivet 				continue;
271c752998bSGaetan Rivet 		}
272c752998bSGaetan Rivet 
273c752998bSGaetan Rivet 		/* set up an eventfd for interrupts */
274c752998bSGaetan Rivet 		fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
275c752998bSGaetan Rivet 		if (fd < 0) {
276c752998bSGaetan Rivet 			RTE_LOG(ERR, EAL, "  cannot set up eventfd, "
277c752998bSGaetan Rivet 					"error %i (%s)\n", errno, strerror(errno));
278c752998bSGaetan Rivet 			return -1;
279c752998bSGaetan Rivet 		}
280c752998bSGaetan Rivet 
281c752998bSGaetan Rivet 		dev->intr_handle.fd = fd;
282c752998bSGaetan Rivet 		dev->intr_handle.vfio_dev_fd = vfio_dev_fd;
283c752998bSGaetan Rivet 
284c752998bSGaetan Rivet 		switch (i) {
285c752998bSGaetan Rivet 		case VFIO_PCI_MSIX_IRQ_INDEX:
286c752998bSGaetan Rivet 			intr_mode = RTE_INTR_MODE_MSIX;
287c752998bSGaetan Rivet 			dev->intr_handle.type = RTE_INTR_HANDLE_VFIO_MSIX;
288c752998bSGaetan Rivet 			break;
289c752998bSGaetan Rivet 		case VFIO_PCI_MSI_IRQ_INDEX:
290c752998bSGaetan Rivet 			intr_mode = RTE_INTR_MODE_MSI;
291c752998bSGaetan Rivet 			dev->intr_handle.type = RTE_INTR_HANDLE_VFIO_MSI;
292c752998bSGaetan Rivet 			break;
293c752998bSGaetan Rivet 		case VFIO_PCI_INTX_IRQ_INDEX:
294c752998bSGaetan Rivet 			intr_mode = RTE_INTR_MODE_LEGACY;
295c752998bSGaetan Rivet 			dev->intr_handle.type = RTE_INTR_HANDLE_VFIO_LEGACY;
296c752998bSGaetan Rivet 			break;
297c752998bSGaetan Rivet 		default:
298c752998bSGaetan Rivet 			RTE_LOG(ERR, EAL, "  unknown interrupt type!\n");
299c752998bSGaetan Rivet 			return -1;
300c752998bSGaetan Rivet 		}
301c752998bSGaetan Rivet 
302c752998bSGaetan Rivet 		return 0;
303c752998bSGaetan Rivet 	}
304c752998bSGaetan Rivet 
305c752998bSGaetan Rivet 	/* if we're here, we haven't found a suitable interrupt vector */
306c752998bSGaetan Rivet 	return -1;
307c752998bSGaetan Rivet }
308c752998bSGaetan Rivet 
309c752998bSGaetan Rivet static int
310c752998bSGaetan Rivet pci_vfio_is_ioport_bar(int vfio_dev_fd, int bar_index)
311c752998bSGaetan Rivet {
312c752998bSGaetan Rivet 	uint32_t ioport_bar;
313c752998bSGaetan Rivet 	int ret;
314c752998bSGaetan Rivet 
315c752998bSGaetan Rivet 	ret = pread64(vfio_dev_fd, &ioport_bar, sizeof(ioport_bar),
316c752998bSGaetan Rivet 			  VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX)
317c752998bSGaetan Rivet 			  + PCI_BASE_ADDRESS_0 + bar_index*4);
318c752998bSGaetan Rivet 	if (ret != sizeof(ioport_bar)) {
319c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "Cannot read command (%x) from config space!\n",
320c752998bSGaetan Rivet 			PCI_BASE_ADDRESS_0 + bar_index*4);
321c752998bSGaetan Rivet 		return -1;
322c752998bSGaetan Rivet 	}
323c752998bSGaetan Rivet 
324c752998bSGaetan Rivet 	return (ioport_bar & PCI_BASE_ADDRESS_SPACE_IO) != 0;
325c752998bSGaetan Rivet }
326c752998bSGaetan Rivet 
327c752998bSGaetan Rivet static int
328*77dad68cSGaetan Rivet pci_rte_vfio_setup_device(struct rte_pci_device *dev, int vfio_dev_fd)
329c752998bSGaetan Rivet {
330c752998bSGaetan Rivet 	if (pci_vfio_setup_interrupts(dev, vfio_dev_fd) != 0) {
331c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "Error setting up interrupts!\n");
332c752998bSGaetan Rivet 		return -1;
333c752998bSGaetan Rivet 	}
334c752998bSGaetan Rivet 
335c752998bSGaetan Rivet 	/* set bus mastering for the device */
336c752998bSGaetan Rivet 	if (pci_vfio_set_bus_master(vfio_dev_fd, true)) {
337c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "Cannot set up bus mastering!\n");
338c752998bSGaetan Rivet 		return -1;
339c752998bSGaetan Rivet 	}
340c752998bSGaetan Rivet 
3416fb00f8bSJerin Jacob 	/*
3426fb00f8bSJerin Jacob 	 * Reset the device. If the device is not capable of resetting,
3436fb00f8bSJerin Jacob 	 * then it updates errno as EINVAL.
3446fb00f8bSJerin Jacob 	 */
3456fb00f8bSJerin Jacob 	if (ioctl(vfio_dev_fd, VFIO_DEVICE_RESET) && errno != EINVAL) {
346f25f8f36SJonas Pfefferle 		RTE_LOG(ERR, EAL, "Unable to reset device! Error: %d (%s)\n",
347f25f8f36SJonas Pfefferle 				errno, strerror(errno));
348f25f8f36SJonas Pfefferle 		return -1;
349f25f8f36SJonas Pfefferle 	}
350c752998bSGaetan Rivet 
351c752998bSGaetan Rivet 	return 0;
352c752998bSGaetan Rivet }
353c752998bSGaetan Rivet 
354c752998bSGaetan Rivet static int
355c752998bSGaetan Rivet pci_vfio_mmap_bar(int vfio_dev_fd, struct mapped_pci_resource *vfio_res,
356c752998bSGaetan Rivet 		int bar_index, int additional_flags)
357c752998bSGaetan Rivet {
358c752998bSGaetan Rivet 	struct memreg {
359c752998bSGaetan Rivet 		unsigned long offset, size;
360c752998bSGaetan Rivet 	} memreg[2] = {};
361c752998bSGaetan Rivet 	void *bar_addr;
362c752998bSGaetan Rivet 	struct pci_msix_table *msix_table = &vfio_res->msix_table;
363c752998bSGaetan Rivet 	struct pci_map *bar = &vfio_res->maps[bar_index];
364c752998bSGaetan Rivet 
365c752998bSGaetan Rivet 	if (bar->size == 0)
366c752998bSGaetan Rivet 		/* Skip this BAR */
367c752998bSGaetan Rivet 		return 0;
368c752998bSGaetan Rivet 
369c752998bSGaetan Rivet 	if (msix_table->bar_index == bar_index) {
370c752998bSGaetan Rivet 		/*
371c752998bSGaetan Rivet 		 * VFIO will not let us map the MSI-X table,
372c752998bSGaetan Rivet 		 * but we can map around it.
373c752998bSGaetan Rivet 		 */
374c752998bSGaetan Rivet 		uint32_t table_start = msix_table->offset;
375c752998bSGaetan Rivet 		uint32_t table_end = table_start + msix_table->size;
376c752998bSGaetan Rivet 		table_end = (table_end + ~PAGE_MASK) & PAGE_MASK;
377c752998bSGaetan Rivet 		table_start &= PAGE_MASK;
378c752998bSGaetan Rivet 
379c752998bSGaetan Rivet 		if (table_start == 0 && table_end >= bar->size) {
380c752998bSGaetan Rivet 			/* Cannot map this BAR */
381c752998bSGaetan Rivet 			RTE_LOG(DEBUG, EAL, "Skipping BAR%d\n", bar_index);
382c752998bSGaetan Rivet 			bar->size = 0;
383c752998bSGaetan Rivet 			bar->addr = 0;
384c752998bSGaetan Rivet 			return 0;
385c752998bSGaetan Rivet 		}
386c752998bSGaetan Rivet 
387c752998bSGaetan Rivet 		memreg[0].offset = bar->offset;
388c752998bSGaetan Rivet 		memreg[0].size = table_start;
389c752998bSGaetan Rivet 		memreg[1].offset = bar->offset + table_end;
390c752998bSGaetan Rivet 		memreg[1].size = bar->size - table_end;
391c752998bSGaetan Rivet 
392c752998bSGaetan Rivet 		RTE_LOG(DEBUG, EAL,
393c752998bSGaetan Rivet 			"Trying to map BAR%d that contains the MSI-X "
394c752998bSGaetan Rivet 			"table. Trying offsets: "
395c752998bSGaetan Rivet 			"0x%04lx:0x%04lx, 0x%04lx:0x%04lx\n", bar_index,
396c752998bSGaetan Rivet 			memreg[0].offset, memreg[0].size,
397c752998bSGaetan Rivet 			memreg[1].offset, memreg[1].size);
398c752998bSGaetan Rivet 	} else {
399c752998bSGaetan Rivet 		memreg[0].offset = bar->offset;
400c752998bSGaetan Rivet 		memreg[0].size = bar->size;
401c752998bSGaetan Rivet 	}
402c752998bSGaetan Rivet 
403c752998bSGaetan Rivet 	/* reserve the address using an inaccessible mapping */
404c752998bSGaetan Rivet 	bar_addr = mmap(bar->addr, bar->size, 0, MAP_PRIVATE |
405c752998bSGaetan Rivet 			MAP_ANONYMOUS | additional_flags, -1, 0);
406c752998bSGaetan Rivet 	if (bar_addr != MAP_FAILED) {
407c752998bSGaetan Rivet 		void *map_addr = NULL;
408c752998bSGaetan Rivet 		if (memreg[0].size) {
409c752998bSGaetan Rivet 			/* actual map of first part */
410c752998bSGaetan Rivet 			map_addr = pci_map_resource(bar_addr, vfio_dev_fd,
411c752998bSGaetan Rivet 							memreg[0].offset,
412c752998bSGaetan Rivet 							memreg[0].size,
413c752998bSGaetan Rivet 							MAP_FIXED);
414c752998bSGaetan Rivet 		}
415c752998bSGaetan Rivet 
416c752998bSGaetan Rivet 		/* if there's a second part, try to map it */
417c752998bSGaetan Rivet 		if (map_addr != MAP_FAILED
418c752998bSGaetan Rivet 			&& memreg[1].offset && memreg[1].size) {
419c752998bSGaetan Rivet 			void *second_addr = RTE_PTR_ADD(bar_addr,
420c752998bSGaetan Rivet 							memreg[1].offset -
421c752998bSGaetan Rivet 							(uintptr_t)bar->offset);
422c752998bSGaetan Rivet 			map_addr = pci_map_resource(second_addr,
423c752998bSGaetan Rivet 							vfio_dev_fd,
424c752998bSGaetan Rivet 							memreg[1].offset,
425c752998bSGaetan Rivet 							memreg[1].size,
426c752998bSGaetan Rivet 							MAP_FIXED);
427c752998bSGaetan Rivet 		}
428c752998bSGaetan Rivet 
429c752998bSGaetan Rivet 		if (map_addr == MAP_FAILED || !map_addr) {
430c752998bSGaetan Rivet 			munmap(bar_addr, bar->size);
431c752998bSGaetan Rivet 			bar_addr = MAP_FAILED;
432c752998bSGaetan Rivet 			RTE_LOG(ERR, EAL, "Failed to map pci BAR%d\n",
433c752998bSGaetan Rivet 					bar_index);
434c752998bSGaetan Rivet 			return -1;
435c752998bSGaetan Rivet 		}
436c752998bSGaetan Rivet 	} else {
437c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL,
438c752998bSGaetan Rivet 				"Failed to create inaccessible mapping for BAR%d\n",
439c752998bSGaetan Rivet 				bar_index);
440c752998bSGaetan Rivet 		return -1;
441c752998bSGaetan Rivet 	}
442c752998bSGaetan Rivet 
443c752998bSGaetan Rivet 	bar->addr = bar_addr;
444c752998bSGaetan Rivet 	return 0;
445c752998bSGaetan Rivet }
446c752998bSGaetan Rivet 
447c752998bSGaetan Rivet static int
448c752998bSGaetan Rivet pci_vfio_map_resource_primary(struct rte_pci_device *dev)
449c752998bSGaetan Rivet {
450c752998bSGaetan Rivet 	struct vfio_device_info device_info = { .argsz = sizeof(device_info) };
451c752998bSGaetan Rivet 	char pci_addr[PATH_MAX] = {0};
452c752998bSGaetan Rivet 	int vfio_dev_fd;
453c752998bSGaetan Rivet 	struct rte_pci_addr *loc = &dev->addr;
454c752998bSGaetan Rivet 	int i, ret;
455c752998bSGaetan Rivet 	struct mapped_pci_resource *vfio_res = NULL;
456c752998bSGaetan Rivet 	struct mapped_pci_res_list *vfio_res_list =
457c752998bSGaetan Rivet 		RTE_TAILQ_CAST(rte_vfio_tailq.head, mapped_pci_res_list);
458c752998bSGaetan Rivet 
459c752998bSGaetan Rivet 	struct pci_map *maps;
460c752998bSGaetan Rivet 
461c752998bSGaetan Rivet 	dev->intr_handle.fd = -1;
462c752998bSGaetan Rivet 	dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
463c752998bSGaetan Rivet 
464c752998bSGaetan Rivet 	/* store PCI address string */
465c752998bSGaetan Rivet 	snprintf(pci_addr, sizeof(pci_addr), PCI_PRI_FMT,
466c752998bSGaetan Rivet 			loc->domain, loc->bus, loc->devid, loc->function);
467c752998bSGaetan Rivet 
468*77dad68cSGaetan Rivet 	ret = rte_vfio_setup_device(pci_get_sysfs_path(), pci_addr,
469c752998bSGaetan Rivet 					&vfio_dev_fd, &device_info);
470c752998bSGaetan Rivet 	if (ret)
471c752998bSGaetan Rivet 		return ret;
472c752998bSGaetan Rivet 
473c752998bSGaetan Rivet 	/* allocate vfio_res and get region info */
474c752998bSGaetan Rivet 	vfio_res = rte_zmalloc("VFIO_RES", sizeof(*vfio_res), 0);
475c752998bSGaetan Rivet 	if (vfio_res == NULL) {
476c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL,
477c752998bSGaetan Rivet 			"%s(): cannot store uio mmap details\n", __func__);
478c752998bSGaetan Rivet 		goto err_vfio_dev_fd;
479c752998bSGaetan Rivet 	}
480c752998bSGaetan Rivet 	memcpy(&vfio_res->pci_addr, &dev->addr, sizeof(vfio_res->pci_addr));
481c752998bSGaetan Rivet 
482c752998bSGaetan Rivet 	/* get number of registers (up to BAR5) */
483c752998bSGaetan Rivet 	vfio_res->nb_maps = RTE_MIN((int) device_info.num_regions,
484c752998bSGaetan Rivet 			VFIO_PCI_BAR5_REGION_INDEX + 1);
485c752998bSGaetan Rivet 
486c752998bSGaetan Rivet 	/* map BARs */
487c752998bSGaetan Rivet 	maps = vfio_res->maps;
488c752998bSGaetan Rivet 
489c752998bSGaetan Rivet 	vfio_res->msix_table.bar_index = -1;
490c752998bSGaetan Rivet 	/* get MSI-X BAR, if any (we have to know where it is because we can't
491c752998bSGaetan Rivet 	 * easily mmap it when using VFIO)
492c752998bSGaetan Rivet 	 */
493c752998bSGaetan Rivet 	ret = pci_vfio_get_msix_bar(vfio_dev_fd, &vfio_res->msix_table);
494c752998bSGaetan Rivet 	if (ret < 0) {
495c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "  %s cannot get MSI-X BAR number!\n",
496c752998bSGaetan Rivet 				pci_addr);
497c752998bSGaetan Rivet 		goto err_vfio_dev_fd;
498c752998bSGaetan Rivet 	}
499c752998bSGaetan Rivet 
500c752998bSGaetan Rivet 	for (i = 0; i < (int) vfio_res->nb_maps; i++) {
501c752998bSGaetan Rivet 		struct vfio_region_info reg = { .argsz = sizeof(reg) };
502c752998bSGaetan Rivet 		void *bar_addr;
503c752998bSGaetan Rivet 
504c752998bSGaetan Rivet 		reg.index = i;
505c752998bSGaetan Rivet 
506c752998bSGaetan Rivet 		ret = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_REGION_INFO, &reg);
507c752998bSGaetan Rivet 		if (ret) {
508c752998bSGaetan Rivet 			RTE_LOG(ERR, EAL, "  %s cannot get device region info "
509c752998bSGaetan Rivet 					"error %i (%s)\n", pci_addr, errno, strerror(errno));
510c752998bSGaetan Rivet 			goto err_vfio_res;
511c752998bSGaetan Rivet 		}
512c752998bSGaetan Rivet 
513c752998bSGaetan Rivet 		/* chk for io port region */
514c752998bSGaetan Rivet 		ret = pci_vfio_is_ioport_bar(vfio_dev_fd, i);
515c752998bSGaetan Rivet 		if (ret < 0)
516c752998bSGaetan Rivet 			goto err_vfio_res;
517c752998bSGaetan Rivet 		else if (ret) {
518c752998bSGaetan Rivet 			RTE_LOG(INFO, EAL, "Ignore mapping IO port bar(%d)\n",
519c752998bSGaetan Rivet 					i);
520c752998bSGaetan Rivet 			continue;
521c752998bSGaetan Rivet 		}
522c752998bSGaetan Rivet 
523c752998bSGaetan Rivet 		/* skip non-mmapable BARs */
524c752998bSGaetan Rivet 		if ((reg.flags & VFIO_REGION_INFO_FLAG_MMAP) == 0)
525c752998bSGaetan Rivet 			continue;
526c752998bSGaetan Rivet 
527c752998bSGaetan Rivet 		/* try mapping somewhere close to the end of hugepages */
528c752998bSGaetan Rivet 		if (pci_map_addr == NULL)
529c752998bSGaetan Rivet 			pci_map_addr = pci_find_max_end_va();
530c752998bSGaetan Rivet 
531c752998bSGaetan Rivet 		bar_addr = pci_map_addr;
532c752998bSGaetan Rivet 		pci_map_addr = RTE_PTR_ADD(bar_addr, (size_t) reg.size);
533c752998bSGaetan Rivet 
534c752998bSGaetan Rivet 		maps[i].addr = bar_addr;
535c752998bSGaetan Rivet 		maps[i].offset = reg.offset;
536c752998bSGaetan Rivet 		maps[i].size = reg.size;
537c752998bSGaetan Rivet 		maps[i].path = NULL; /* vfio doesn't have per-resource paths */
538c752998bSGaetan Rivet 
539c752998bSGaetan Rivet 		ret = pci_vfio_mmap_bar(vfio_dev_fd, vfio_res, i, 0);
540c752998bSGaetan Rivet 		if (ret < 0) {
541c752998bSGaetan Rivet 			RTE_LOG(ERR, EAL, "  %s mapping BAR%i failed: %s\n",
542c752998bSGaetan Rivet 					pci_addr, i, strerror(errno));
543c752998bSGaetan Rivet 			goto err_vfio_res;
544c752998bSGaetan Rivet 		}
545c752998bSGaetan Rivet 
546c752998bSGaetan Rivet 		dev->mem_resource[i].addr = maps[i].addr;
547c752998bSGaetan Rivet 	}
548c752998bSGaetan Rivet 
549*77dad68cSGaetan Rivet 	if (pci_rte_vfio_setup_device(dev, vfio_dev_fd) < 0) {
550c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "  %s setup device failed\n", pci_addr);
551c752998bSGaetan Rivet 		goto err_vfio_res;
552c752998bSGaetan Rivet 	}
553c752998bSGaetan Rivet 
554c752998bSGaetan Rivet 	TAILQ_INSERT_TAIL(vfio_res_list, vfio_res, next);
555c752998bSGaetan Rivet 
556c752998bSGaetan Rivet 	return 0;
557c752998bSGaetan Rivet err_vfio_res:
558c752998bSGaetan Rivet 	rte_free(vfio_res);
559c752998bSGaetan Rivet err_vfio_dev_fd:
560c752998bSGaetan Rivet 	close(vfio_dev_fd);
561c752998bSGaetan Rivet 	return -1;
562c752998bSGaetan Rivet }
563c752998bSGaetan Rivet 
564c752998bSGaetan Rivet static int
565c752998bSGaetan Rivet pci_vfio_map_resource_secondary(struct rte_pci_device *dev)
566c752998bSGaetan Rivet {
567c752998bSGaetan Rivet 	struct vfio_device_info device_info = { .argsz = sizeof(device_info) };
568c752998bSGaetan Rivet 	char pci_addr[PATH_MAX] = {0};
569c752998bSGaetan Rivet 	int vfio_dev_fd;
570c752998bSGaetan Rivet 	struct rte_pci_addr *loc = &dev->addr;
571c752998bSGaetan Rivet 	int i, ret;
572c752998bSGaetan Rivet 	struct mapped_pci_resource *vfio_res = NULL;
573c752998bSGaetan Rivet 	struct mapped_pci_res_list *vfio_res_list =
574c752998bSGaetan Rivet 		RTE_TAILQ_CAST(rte_vfio_tailq.head, mapped_pci_res_list);
575c752998bSGaetan Rivet 
576c752998bSGaetan Rivet 	struct pci_map *maps;
577c752998bSGaetan Rivet 
578c752998bSGaetan Rivet 	dev->intr_handle.fd = -1;
579c752998bSGaetan Rivet 	dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
580c752998bSGaetan Rivet 
581c752998bSGaetan Rivet 	/* store PCI address string */
582c752998bSGaetan Rivet 	snprintf(pci_addr, sizeof(pci_addr), PCI_PRI_FMT,
583c752998bSGaetan Rivet 			loc->domain, loc->bus, loc->devid, loc->function);
584c752998bSGaetan Rivet 
585*77dad68cSGaetan Rivet 	ret = rte_vfio_setup_device(pci_get_sysfs_path(), pci_addr,
586c752998bSGaetan Rivet 					&vfio_dev_fd, &device_info);
587c752998bSGaetan Rivet 	if (ret)
588c752998bSGaetan Rivet 		return ret;
589c752998bSGaetan Rivet 
590c752998bSGaetan Rivet 	/* if we're in a secondary process, just find our tailq entry */
591c752998bSGaetan Rivet 	TAILQ_FOREACH(vfio_res, vfio_res_list, next) {
592c752998bSGaetan Rivet 		if (pci_addr_cmp(&vfio_res->pci_addr,
593c752998bSGaetan Rivet 						 &dev->addr))
594c752998bSGaetan Rivet 			continue;
595c752998bSGaetan Rivet 		break;
596c752998bSGaetan Rivet 	}
597c752998bSGaetan Rivet 	/* if we haven't found our tailq entry, something's wrong */
598c752998bSGaetan Rivet 	if (vfio_res == NULL) {
599c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "  %s cannot find TAILQ entry for PCI device!\n",
600c752998bSGaetan Rivet 				pci_addr);
601c752998bSGaetan Rivet 		goto err_vfio_dev_fd;
602c752998bSGaetan Rivet 	}
603c752998bSGaetan Rivet 
604c752998bSGaetan Rivet 	/* map BARs */
605c752998bSGaetan Rivet 	maps = vfio_res->maps;
606c752998bSGaetan Rivet 
607c752998bSGaetan Rivet 	for (i = 0; i < (int) vfio_res->nb_maps; i++) {
608c752998bSGaetan Rivet 		ret = pci_vfio_mmap_bar(vfio_dev_fd, vfio_res, i, MAP_FIXED);
609c752998bSGaetan Rivet 		if (ret < 0) {
610c752998bSGaetan Rivet 			RTE_LOG(ERR, EAL, "  %s mapping BAR%i failed: %s\n",
611c752998bSGaetan Rivet 					pci_addr, i, strerror(errno));
612c752998bSGaetan Rivet 			goto err_vfio_dev_fd;
613c752998bSGaetan Rivet 		}
614c752998bSGaetan Rivet 
615c752998bSGaetan Rivet 		dev->mem_resource[i].addr = maps[i].addr;
616c752998bSGaetan Rivet 	}
617c752998bSGaetan Rivet 
618c752998bSGaetan Rivet 	return 0;
619c752998bSGaetan Rivet err_vfio_dev_fd:
620c752998bSGaetan Rivet 	close(vfio_dev_fd);
621c752998bSGaetan Rivet 	return -1;
622c752998bSGaetan Rivet }
623c752998bSGaetan Rivet 
624c752998bSGaetan Rivet /*
625c752998bSGaetan Rivet  * map the PCI resources of a PCI device in virtual memory (VFIO version).
626c752998bSGaetan Rivet  * primary and secondary processes follow almost exactly the same path
627c752998bSGaetan Rivet  */
628c752998bSGaetan Rivet int
629c752998bSGaetan Rivet pci_vfio_map_resource(struct rte_pci_device *dev)
630c752998bSGaetan Rivet {
631c752998bSGaetan Rivet 	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
632c752998bSGaetan Rivet 		return pci_vfio_map_resource_primary(dev);
633c752998bSGaetan Rivet 	else
634c752998bSGaetan Rivet 		return pci_vfio_map_resource_secondary(dev);
635c752998bSGaetan Rivet }
636c752998bSGaetan Rivet 
637c752998bSGaetan Rivet int
638c752998bSGaetan Rivet pci_vfio_unmap_resource(struct rte_pci_device *dev)
639c752998bSGaetan Rivet {
640c752998bSGaetan Rivet 	char pci_addr[PATH_MAX] = {0};
641c752998bSGaetan Rivet 	struct rte_pci_addr *loc = &dev->addr;
642c752998bSGaetan Rivet 	int i, ret;
643c752998bSGaetan Rivet 	struct mapped_pci_resource *vfio_res = NULL;
644c752998bSGaetan Rivet 	struct mapped_pci_res_list *vfio_res_list;
645c752998bSGaetan Rivet 
646c752998bSGaetan Rivet 	struct pci_map *maps;
647c752998bSGaetan Rivet 
648c752998bSGaetan Rivet 	/* store PCI address string */
649c752998bSGaetan Rivet 	snprintf(pci_addr, sizeof(pci_addr), PCI_PRI_FMT,
650c752998bSGaetan Rivet 			loc->domain, loc->bus, loc->devid, loc->function);
651c752998bSGaetan Rivet 
652c752998bSGaetan Rivet 
653c752998bSGaetan Rivet 	if (close(dev->intr_handle.fd) < 0) {
654c752998bSGaetan Rivet 		RTE_LOG(INFO, EAL, "Error when closing eventfd file descriptor for %s\n",
655c752998bSGaetan Rivet 			pci_addr);
656c752998bSGaetan Rivet 		return -1;
657c752998bSGaetan Rivet 	}
658c752998bSGaetan Rivet 
659c752998bSGaetan Rivet 	if (pci_vfio_set_bus_master(dev->intr_handle.vfio_dev_fd, false)) {
660c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "  %s cannot unset bus mastering for PCI device!\n",
661c752998bSGaetan Rivet 				pci_addr);
662c752998bSGaetan Rivet 		return -1;
663c752998bSGaetan Rivet 	}
664c752998bSGaetan Rivet 
665*77dad68cSGaetan Rivet 	ret = rte_vfio_release_device(pci_get_sysfs_path(), pci_addr,
666c752998bSGaetan Rivet 				  dev->intr_handle.vfio_dev_fd);
667c752998bSGaetan Rivet 	if (ret < 0) {
668c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL,
669c752998bSGaetan Rivet 			"%s(): cannot release device\n", __func__);
670c752998bSGaetan Rivet 		return ret;
671c752998bSGaetan Rivet 	}
672c752998bSGaetan Rivet 
673c752998bSGaetan Rivet 	vfio_res_list = RTE_TAILQ_CAST(rte_vfio_tailq.head, mapped_pci_res_list);
674c752998bSGaetan Rivet 	/* Get vfio_res */
675c752998bSGaetan Rivet 	TAILQ_FOREACH(vfio_res, vfio_res_list, next) {
676c752998bSGaetan Rivet 		if (memcmp(&vfio_res->pci_addr, &dev->addr, sizeof(dev->addr)))
677c752998bSGaetan Rivet 			continue;
678c752998bSGaetan Rivet 		break;
679c752998bSGaetan Rivet 	}
680c752998bSGaetan Rivet 	/* if we haven't found our tailq entry, something's wrong */
681c752998bSGaetan Rivet 	if (vfio_res == NULL) {
682c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "  %s cannot find TAILQ entry for PCI device!\n",
683c752998bSGaetan Rivet 				pci_addr);
684c752998bSGaetan Rivet 		return -1;
685c752998bSGaetan Rivet 	}
686c752998bSGaetan Rivet 
687c752998bSGaetan Rivet 	/* unmap BARs */
688c752998bSGaetan Rivet 	maps = vfio_res->maps;
689c752998bSGaetan Rivet 
690c752998bSGaetan Rivet 	RTE_LOG(INFO, EAL, "Releasing pci mapped resource for %s\n",
691c752998bSGaetan Rivet 		pci_addr);
692c752998bSGaetan Rivet 	for (i = 0; i < (int) vfio_res->nb_maps; i++) {
693c752998bSGaetan Rivet 
694c752998bSGaetan Rivet 		/*
695c752998bSGaetan Rivet 		 * We do not need to be aware of MSI-X table BAR mappings as
696c752998bSGaetan Rivet 		 * when mapping. Just using current maps array is enough
697c752998bSGaetan Rivet 		 */
698c752998bSGaetan Rivet 		if (maps[i].addr) {
699c752998bSGaetan Rivet 			RTE_LOG(INFO, EAL, "Calling pci_unmap_resource for %s at %p\n",
700c752998bSGaetan Rivet 				pci_addr, maps[i].addr);
701c752998bSGaetan Rivet 			pci_unmap_resource(maps[i].addr, maps[i].size);
702c752998bSGaetan Rivet 		}
703c752998bSGaetan Rivet 	}
704c752998bSGaetan Rivet 
705c752998bSGaetan Rivet 	TAILQ_REMOVE(vfio_res_list, vfio_res, next);
706c752998bSGaetan Rivet 
707c752998bSGaetan Rivet 	return 0;
708c752998bSGaetan Rivet }
709c752998bSGaetan Rivet 
710c752998bSGaetan Rivet int
711c752998bSGaetan Rivet pci_vfio_ioport_map(struct rte_pci_device *dev, int bar,
712c752998bSGaetan Rivet 		    struct rte_pci_ioport *p)
713c752998bSGaetan Rivet {
714c752998bSGaetan Rivet 	if (bar < VFIO_PCI_BAR0_REGION_INDEX ||
715c752998bSGaetan Rivet 	    bar > VFIO_PCI_BAR5_REGION_INDEX) {
716c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "invalid bar (%d)!\n", bar);
717c752998bSGaetan Rivet 		return -1;
718c752998bSGaetan Rivet 	}
719c752998bSGaetan Rivet 
720c752998bSGaetan Rivet 	p->dev = dev;
721c752998bSGaetan Rivet 	p->base = VFIO_GET_REGION_ADDR(bar);
722c752998bSGaetan Rivet 	return 0;
723c752998bSGaetan Rivet }
724c752998bSGaetan Rivet 
725c752998bSGaetan Rivet void
726c752998bSGaetan Rivet pci_vfio_ioport_read(struct rte_pci_ioport *p,
727c752998bSGaetan Rivet 		     void *data, size_t len, off_t offset)
728c752998bSGaetan Rivet {
729c752998bSGaetan Rivet 	const struct rte_intr_handle *intr_handle = &p->dev->intr_handle;
730c752998bSGaetan Rivet 
731c752998bSGaetan Rivet 	if (pread64(intr_handle->vfio_dev_fd, data,
732c752998bSGaetan Rivet 		    len, p->base + offset) <= 0)
733c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL,
734c752998bSGaetan Rivet 			"Can't read from PCI bar (%" PRIu64 ") : offset (%x)\n",
735c752998bSGaetan Rivet 			VFIO_GET_REGION_IDX(p->base), (int)offset);
736c752998bSGaetan Rivet }
737c752998bSGaetan Rivet 
738c752998bSGaetan Rivet void
739c752998bSGaetan Rivet pci_vfio_ioport_write(struct rte_pci_ioport *p,
740c752998bSGaetan Rivet 		      const void *data, size_t len, off_t offset)
741c752998bSGaetan Rivet {
742c752998bSGaetan Rivet 	const struct rte_intr_handle *intr_handle = &p->dev->intr_handle;
743c752998bSGaetan Rivet 
744c752998bSGaetan Rivet 	if (pwrite64(intr_handle->vfio_dev_fd, data,
745c752998bSGaetan Rivet 		     len, p->base + offset) <= 0)
746c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL,
747c752998bSGaetan Rivet 			"Can't write to PCI bar (%" PRIu64 ") : offset (%x)\n",
748c752998bSGaetan Rivet 			VFIO_GET_REGION_IDX(p->base), (int)offset);
749c752998bSGaetan Rivet }
750c752998bSGaetan Rivet 
751c752998bSGaetan Rivet int
752c752998bSGaetan Rivet pci_vfio_ioport_unmap(struct rte_pci_ioport *p)
753c752998bSGaetan Rivet {
754c752998bSGaetan Rivet 	RTE_SET_USED(p);
755c752998bSGaetan Rivet 	return -1;
756c752998bSGaetan Rivet }
757c752998bSGaetan Rivet 
758c752998bSGaetan Rivet int
759c752998bSGaetan Rivet pci_vfio_is_enabled(void)
760c752998bSGaetan Rivet {
761*77dad68cSGaetan Rivet 	return rte_vfio_is_enabled("vfio_pci");
762c752998bSGaetan Rivet }
763c752998bSGaetan Rivet #endif
764