X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;ds=sidebyside;f=drivers%2Fbus%2Fpci%2Flinux%2Fpci_vfio.c;h=fa8cfbb0bd11669ab5e6f4671947434c1574565e;hb=9cea8774cf1c466cdd6dc8bade4350cc28161905;hp=305cc0601d0942f2f6bbbc55d6ade47775deff8b;hpb=d59ba0296e886adb38ede9505ea7508e62df304d;p=dpdk.git diff --git a/drivers/bus/pci/linux/pci_vfio.c b/drivers/bus/pci/linux/pci_vfio.c index 305cc0601d..fa8cfbb0bd 100644 --- a/drivers/bus/pci/linux/pci_vfio.c +++ b/drivers/bus/pci/linux/pci_vfio.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "eal_filesystem.h" @@ -282,6 +283,14 @@ pci_vfio_setup_interrupts(struct rte_pci_device *dev, int vfio_dev_fd) } #ifdef HAVE_VFIO_DEV_REQ_INTERFACE +/* + * Spinlock for device hot-unplug failure handling. + * If it tries to access bus or device, such as handle sigbus on bus + * or handle memory failure for device, just need to use this lock. + * It could protect the bus and the device to avoid race condition. + */ +static rte_spinlock_t failure_handle_lock = RTE_SPINLOCK_INITIALIZER; + static void pci_vfio_req_handler(void *param) { @@ -289,11 +298,12 @@ pci_vfio_req_handler(void *param) int ret; struct rte_device *device = (struct rte_device *)param; + rte_spinlock_lock(&failure_handle_lock); bus = rte_bus_find_by_device(device); if (bus == NULL) { RTE_LOG(ERR, EAL, "Cannot find bus for device (%s)\n", device->name); - return; + goto handle_end; } /* @@ -306,6 +316,8 @@ pci_vfio_req_handler(void *param) RTE_LOG(ERR, EAL, "Can not handle hot-unplug for device (%s)\n", device->name); +handle_end: + rte_spinlock_unlock(&failure_handle_lock); } /* enable notifier (only enable req now) */ @@ -445,9 +457,10 @@ pci_vfio_mmap_bar(int vfio_dev_fd, struct mapped_pci_resource *vfio_res, struct pci_msix_table *msix_table = &vfio_res->msix_table; struct pci_map *bar = &vfio_res->maps[bar_index]; - if (bar->size == 0) - /* Skip this BAR */ + if (bar->size == 0) { + RTE_LOG(DEBUG, EAL, "Bar size is 0, skip BAR%d\n", bar_index); return 0; + } if (msix_table->bar_index == bar_index) { /* @@ -456,8 +469,15 @@ pci_vfio_mmap_bar(int vfio_dev_fd, struct mapped_pci_resource *vfio_res, */ uint32_t table_start = msix_table->offset; uint32_t table_end = table_start + msix_table->size; - table_end = (table_end + ~PAGE_MASK) & PAGE_MASK; - table_start &= PAGE_MASK; + table_end = RTE_ALIGN(table_end, PAGE_SIZE); + table_start = RTE_ALIGN_FLOOR(table_start, PAGE_SIZE); + + /* If page-aligned start of MSI-X table is less than the + * actual MSI-X table start address, reassign to the actual + * start address. + */ + if (table_start < msix_table->offset) + table_start = msix_table->offset; if (table_start == 0 && table_end >= bar->size) { /* Cannot map this BAR */ @@ -469,8 +489,17 @@ pci_vfio_mmap_bar(int vfio_dev_fd, struct mapped_pci_resource *vfio_res, memreg[0].offset = bar->offset; memreg[0].size = table_start; - memreg[1].offset = bar->offset + table_end; - memreg[1].size = bar->size - table_end; + if (bar->size < table_end) { + /* + * If MSI-X table end is beyond BAR end, don't attempt + * to perform second mapping. + */ + memreg[1].offset = 0; + memreg[1].size = 0; + } else { + memreg[1].offset = bar->offset + table_end; + memreg[1].size = bar->size - table_end; + } RTE_LOG(DEBUG, EAL, "Trying to map BAR%d that contains the MSI-X " @@ -782,11 +811,6 @@ pci_vfio_map_resource_secondary(struct rte_pci_device *dev) snprintf(pci_addr, sizeof(pci_addr), PCI_PRI_FMT, loc->domain, loc->bus, loc->devid, loc->function); - ret = rte_vfio_setup_device(rte_pci_get_sysfs_path(), pci_addr, - &vfio_dev_fd, &device_info); - if (ret) - return ret; - /* if we're in a secondary process, just find our tailq entry */ TAILQ_FOREACH(vfio_res, vfio_res_list, next) { if (rte_pci_addr_cmp(&vfio_res->pci_addr, @@ -798,9 +822,14 @@ pci_vfio_map_resource_secondary(struct rte_pci_device *dev) if (vfio_res == NULL) { RTE_LOG(ERR, EAL, " %s cannot find TAILQ entry for PCI device!\n", pci_addr); - goto err_vfio_dev_fd; + return -1; } + ret = rte_vfio_setup_device(rte_pci_get_sysfs_path(), pci_addr, + &vfio_dev_fd, &device_info); + if (ret) + return ret; + /* map BARs */ maps = vfio_res->maps;