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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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, ®); 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