#include <rte_vfio.h>
#include <rte_eal.h>
#include <rte_bus.h>
+#include <rte_spinlock.h>
+#include <rte_tailq.h>
#include "eal_filesystem.h"
}
#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)
{
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;
}
/*
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) */
ret = rte_intr_callback_unregister(&dev->vfio_req_intr_handle,
pci_vfio_req_handler,
(void *)&dev->device);
- if (ret)
+ if (ret < 0)
RTE_LOG(ERR, EAL,
"Fail to unregister req notifier handler.\n");
goto error;
ret = rte_intr_callback_unregister(&dev->vfio_req_intr_handle,
pci_vfio_req_handler,
(void *)&dev->device);
- if (ret) {
+ if (ret < 0) {
RTE_LOG(ERR, EAL,
"fail to unregister req notifier handler.\n");
return -1;
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) {
/*
*/
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 */
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 "
vfio_res = rte_zmalloc("VFIO_RES", sizeof(*vfio_res), 0);
if (vfio_res == NULL) {
RTE_LOG(ERR, EAL,
- "%s(): cannot store uio mmap details\n", __func__);
+ "%s(): cannot store vfio mmap details\n", __func__);
goto err_vfio_dev_fd;
}
memcpy(&vfio_res->pci_addr, &dev->addr, sizeof(vfio_res->pci_addr));
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,
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;