typedef struct
{
+ int fd;
+ void *addr;
+ size_t size;
+} linux_pci_region_t;
+
+
+typedef enum
+{
+ LINUX_PCI_DEVICE_TYPE_UNKNOWN,
+ LINUX_PCI_DEVICE_TYPE_UIO,
+ LINUX_PCI_DEVICE_TYPE_VFIO,
+} linux_pci_device_type_t;
+
+typedef struct
+{
+ linux_pci_device_type_t type;
vlib_pci_dev_handle_t handle;
vlib_pci_addr_t addr;
/* Resource file descriptors. */
- int *resource_fds;
+ linux_pci_region_t *regions;
/* File descriptor for config space read/write. */
int config_fd;
+ u64 config_offset;
- /* File descriptor for /dev/uio%d */
- int uio_fd;
+ /* Device File descriptor */
+ int fd;
/* Minor device for uio device. */
u32 uio_minor;
- /* vfio */
- int vfio_device_fd;
-
/* Index given by clib_file_add. */
u32 clib_file_index;
/* You can only read more that 64 bytes of config space as root; so we try to
read the full space but fall back to just the first 64 bytes. */
- if (read (fd, &di->config_data, sizeof (di->config_data)) !=
- sizeof (di->config_data)
- && read (fd, &di->config0,
- sizeof (di->config0)) != sizeof (di->config0))
+ if (read (fd, &di->config_data, sizeof (di->config_data)) <
+ sizeof (di->config0))
{
err = clib_error_return_unix (0, "read `%s'", f);
close (fd);
.flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK,
};
- if (ioctl (d->vfio_device_fd, VFIO_DEVICE_SET_IRQS, &i) < 0)
+ if (ioctl (d->fd, VFIO_DEVICE_SET_IRQS, &i) < 0)
{
err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_SET_IRQS) '%U'",
format_vlib_pci_addr, &d->addr);
u8 *s = 0;
p->addr.as_u32 = di->addr.as_u32;
- p->uio_fd = -1;
+ p->fd = -1;
+ p->type = LINUX_PCI_DEVICE_TYPE_UIO;
s = format (s, "%s/%U/config%c", sysfs_pci_dev_path,
format_vlib_pci_addr, &di->addr, 0);
p->config_fd = open ((char *) s, O_RDWR);
+ p->config_offset = 0;
vec_reset_length (s);
if (p->config_fd == -1)
vec_reset_length (s);
s = format (s, "/dev/uio%d%c", p->uio_minor, 0);
- p->uio_fd = open ((char *) s, O_RDWR);
- if (p->uio_fd < 0)
+ p->fd = open ((char *) s, O_RDWR);
+ if (p->fd < 0)
{
err = clib_error_return_unix (0, "open '%s'", s);
goto error;
}
t.read_function = linux_pci_uio_read_ready;
- t.file_descriptor = p->uio_fd;
+ t.file_descriptor = p->fd;
t.error_function = linux_pci_uio_error_ready;
t.private_data = p->handle;
{
if (p->config_fd != -1)
close (p->config_fd);
- if (p->uio_fd != -1)
- close (p->uio_fd);
+ if (p->fd != -1)
+ close (p->fd);
}
return err;
}
vlib_pci_device_info_t * di, pci_device_registration_t * r)
{
linux_pci_vfio_iommu_group_t *g;
- struct vfio_device_info device_info;
+ struct vfio_device_info device_info = { 0 };
+ struct vfio_region_info reg = { 0 };
struct vfio_irq_info irq_info = { 0 };
clib_error_t *err = 0;
u8 *s = 0;
- int dfd;
p->addr.as_u32 = di->addr.as_u32;
+ p->type = LINUX_PCI_DEVICE_TYPE_VFIO;
if (di->driver_name == 0 ||
(strcmp ("vfio-pci", (char *) di->driver_name) != 0))
g = get_vfio_iommu_group (di->iommu_group);
s = format (s, "%U%c", format_vlib_pci_addr, &di->addr, 0);
- if ((dfd = ioctl (g->fd, VFIO_GROUP_GET_DEVICE_FD, (char *) s)) < 0)
+ if ((p->fd = ioctl (g->fd, VFIO_GROUP_GET_DEVICE_FD, (char *) s)) < 0)
{
err = clib_error_return_unix (0, "ioctl(VFIO_GROUP_GET_DEVICE_FD) '%U'",
format_vlib_pci_addr, &di->addr);
goto error;
}
vec_reset_length (s);
- p->vfio_device_fd = dfd;
device_info.argsz = sizeof (device_info);
- if (ioctl (dfd, VFIO_DEVICE_GET_INFO, &device_info) < 0)
+ if (ioctl (p->fd, VFIO_DEVICE_GET_INFO, &device_info) < 0)
{
err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_INFO) '%U'",
format_vlib_pci_addr, &di->addr);
irq_info.argsz = sizeof (struct vfio_irq_info);
irq_info.index = VFIO_PCI_INTX_IRQ_INDEX;
- if (ioctl (dfd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info) < 0)
+ if (ioctl (p->fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info) < 0)
{
err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_IRQ_INFO) "
"'%U'", format_vlib_pci_addr, &di->addr);
/* reset if device supports it */
if (device_info.flags & VFIO_DEVICE_FLAGS_RESET)
- if (ioctl (dfd, VFIO_DEVICE_RESET) < 0)
+ if (ioctl (p->fd, VFIO_DEVICE_RESET) < 0)
{
err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_RESET) '%U'",
format_vlib_pci_addr, &di->addr);
VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
clib_memcpy (&irq_set->data, &efd, sizeof (int));
- if (ioctl (dfd, VFIO_DEVICE_SET_IRQS, irq_set) < 0)
+ if (ioctl (p->fd, VFIO_DEVICE_SET_IRQS, irq_set) < 0)
{
err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_SET_IRQS) '%U'",
format_vlib_pci_addr, &di->addr);
p->interrupt_handler = r->interrupt_handler;
- s = format (s, "%s/%U/config%c", sysfs_pci_dev_path,
- format_vlib_pci_addr, &di->addr, 0);
-
- p->config_fd = open ((char *) s, O_RDWR);
- vec_reset_length (s);
-
- if (p->config_fd == -1)
+ reg.argsz = sizeof (struct vfio_region_info);
+ reg.index = VFIO_PCI_CONFIG_REGION_INDEX;
+ if (ioctl (p->fd, VFIO_DEVICE_GET_REGION_INFO, ®) < 0)
{
- err = clib_error_return_unix (0, "open '%s'", s);
+ err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_REGION_INFO) "
+ "'%U'", format_vlib_pci_addr, &di->addr);
goto error;
}
+ p->config_offset = reg.offset;
+ p->config_fd = p->fd;
err = r->init_function (vm, p->handle);
vec_free (s);
if (err)
{
- if (dfd != -1)
- close (dfd);
+ if (p->fd != -1)
+ close (p->fd);
if (p->config_fd != -1)
close (p->config_fd);
}
int n;
if (read_or_write == VLIB_READ)
- n = pread (p->config_fd, data, n_bytes, address);
+ n = pread (p->config_fd, data, n_bytes, p->config_offset + address);
else
- n = pwrite (p->config_fd, data, n_bytes, address);
+ n = pwrite (p->config_fd, data, n_bytes, p->config_offset + address);
if (n != n_bytes)
return clib_error_return_unix (0, "%s",
}
static clib_error_t *
-vlib_pci_map_resource_int (vlib_pci_dev_handle_t h,
- u32 resource, u8 * addr, void **result)
+vlib_pci_map_region_int (vlib_pci_dev_handle_t h,
+ u32 bar, u8 * addr, void **result)
{
linux_pci_device_t *p = linux_pci_get_device (h);
- struct stat stat_buf;
- u8 *file_name;
- int fd;
+ int fd = -1;
clib_error_t *error;
int flags = MAP_SHARED;
+ u64 size = 0, offset = 0;
- error = 0;
+ ASSERT (bar <= 5);
- file_name = format (0, "%s/%U/resource%d%c", sysfs_pci_dev_path,
- format_vlib_pci_addr, &p->addr, resource, 0);
+ error = 0;
- fd = open ((char *) file_name, O_RDWR);
- if (fd < 0)
+ if (p->type == LINUX_PCI_DEVICE_TYPE_UIO)
{
- error = clib_error_return_unix (0, "open `%s'", file_name);
- goto done;
- }
+ u8 *file_name;
+ struct stat stat_buf;
+ file_name = format (0, "%s/%U/resource%d%c", sysfs_pci_dev_path,
+ format_vlib_pci_addr, &p->addr, bar, 0);
- if (fstat (fd, &stat_buf) < 0)
- {
- error = clib_error_return_unix (0, "fstat `%s'", file_name);
- goto done;
- }
+ fd = open ((char *) file_name, O_RDWR);
+ if (fd < 0)
+ {
+ error = clib_error_return_unix (0, "open `%s'", file_name);
+ vec_free (file_name);
+ return error;
+ }
- vec_validate (p->resource_fds, resource);
- p->resource_fds[resource] = fd;
- if (addr != 0)
- flags |= MAP_FIXED;
+ if (fstat (fd, &stat_buf) < 0)
+ {
+ error = clib_error_return_unix (0, "fstat `%s'", file_name);
+ vec_free (file_name);
+ close (fd);
+ return error;
+ }
- *result = mmap (addr,
- /* size */ stat_buf.st_size,
- PROT_READ | PROT_WRITE, flags,
- /* file */ fd,
- /* offset */ 0);
- if (*result == (void *) -1)
+ vec_free (file_name);
+ if (addr != 0)
+ flags |= MAP_FIXED;
+ size = stat_buf.st_size;
+ offset = 0;
+ }
+ else if (p->type == LINUX_PCI_DEVICE_TYPE_VFIO)
{
- error = clib_error_return_unix (0, "mmap `%s'", file_name);
- goto done;
+ struct vfio_region_info reg = { 0 };
+ reg.argsz = sizeof (struct vfio_region_info);
+ reg.index = bar;
+ if (ioctl (p->fd, VFIO_DEVICE_GET_REGION_INFO, ®) < 0)
+ return clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_INFO) "
+ "'%U'", format_vlib_pci_addr,
+ &p->addr);
+ fd = p->fd;
+ size = reg.size;
+ offset = reg.offset;
}
+ else
+ ASSERT (0);
-done:
- if (error)
+ *result = mmap (addr, size, PROT_READ | PROT_WRITE, flags, fd, offset);
+ if (*result == (void *) -1)
{
- if (fd >= 0)
+ error = clib_error_return_unix (0, "mmap `BAR%u'", bar);
+ if (p->type == LINUX_PCI_DEVICE_TYPE_UIO)
close (fd);
+ return error;
}
- vec_free (file_name);
- return error;
+
+ /* *INDENT-OFF* */
+ vec_validate_init_empty (p->regions, bar,
+ (linux_pci_region_t) { .fd = -1});
+ /* *INDENT-ON* */
+ if (p->type == LINUX_PCI_DEVICE_TYPE_UIO)
+ p->regions[bar].fd = fd;
+ p->regions[bar].addr = *result;
+ p->regions[bar].size = size;
+ return 0;
}
clib_error_t *
-vlib_pci_map_resource (vlib_pci_dev_handle_t h, u32 resource, void **result)
+vlib_pci_map_region (vlib_pci_dev_handle_t h, u32 resource, void **result)
{
- return (vlib_pci_map_resource_int (h, resource, 0 /* addr */ , result));
+ return (vlib_pci_map_region_int (h, resource, 0 /* addr */ , result));
}
clib_error_t *
-vlib_pci_map_resource_fixed (vlib_pci_dev_handle_t h,
- u32 resource, u8 * addr, void **result)
+vlib_pci_map_region_fixed (vlib_pci_dev_handle_t h, u32 resource, u8 * addr,
+ void **result)
{
- return (vlib_pci_map_resource_int (h, resource, addr, result));
+ return (vlib_pci_map_region_int (h, resource, addr, result));
}
void