avf: allocate descriptor memory from local numa
[vpp.git] / src / vlib / linux / pci.c
index 69fca9e..b99f54f 100644 (file)
@@ -97,6 +97,7 @@ typedef struct
   linux_pci_device_type_t type;
   vlib_pci_dev_handle_t handle;
   vlib_pci_addr_t addr;
+  u32 numa_node;
 
   /* Resource file descriptors. */
   linux_pci_region_t *regions;
@@ -108,6 +109,10 @@ typedef struct
   /* Device File descriptor */
   int fd;
 
+  /* read/write file descriptor for io bar */
+  int io_fd;
+  u64 io_offset;
+
   /* Minor device for uio device. */
   u32 uio_minor;
 
@@ -161,6 +166,13 @@ vlib_pci_get_addr (vlib_main_t * vm, vlib_pci_dev_handle_t h)
   return &d->addr;
 }
 
+u32
+vlib_pci_get_numa_node (vlib_main_t * vm, vlib_pci_dev_handle_t h)
+{
+  linux_pci_device_t *d = linux_pci_get_device (h);
+  return d->numa_node;
+}
+
 /* Call to allocate/initialize the pci subsystem.
    This is not an init function so that users can explicitly enable
    pci only when it's needed. */
@@ -180,7 +192,7 @@ vlib_pci_get_device_info (vlib_main_t * vm, vlib_pci_addr_t * addr,
   int fd;
 
   di = clib_mem_alloc (sizeof (vlib_pci_device_info_t));
-  memset (di, 0, sizeof (vlib_pci_device_info_t));
+  clib_memset (di, 0, sizeof (vlib_pci_device_info_t));
   di->addr.as_u32 = addr->as_u32;
 
   u8 *dev_dir_name = format (0, "%s/%U", sysfs_pci_dev_path,
@@ -212,7 +224,7 @@ vlib_pci_get_device_info (vlib_main_t * vm, vlib_pci_addr_t * addr,
   {
     static pci_config_header_t all_ones;
     if (all_ones.vendor_id == 0)
-      memset (&all_ones, ~0, sizeof (all_ones));
+      clib_memset (&all_ones, ~0, sizeof (all_ones));
 
     if (!memcmp (&di->config0.header, &all_ones, sizeof (all_ones)))
       {
@@ -451,8 +463,8 @@ vlib_pci_bind_to_uio (vlib_main_t * vm, vlib_pci_addr_t * addr,
       if (e->d_name[0] == '.') /* skip . and .. */
        continue;
 
-      memset (&ifr, 0, sizeof ifr);
-      memset (&drvinfo, 0, sizeof drvinfo);
+      clib_memset (&ifr, 0, sizeof ifr);
+      clib_memset (&drvinfo, 0, sizeof drvinfo);
       ifr.ifr_data = (char *) &drvinfo;
       strncpy (ifr.ifr_name, e->d_name, sizeof (ifr.ifr_name));
       ifr.ifr_name[ARRAY_LEN (ifr.ifr_name) - 1] = '\0';
@@ -469,7 +481,7 @@ vlib_pci_bind_to_uio (vlib_main_t * vm, vlib_pci_addr_t * addr,
       if (strcmp ((char *) s, drvinfo.bus_info))
        continue;
 
-      memset (&ifr, 0, sizeof (ifr));
+      clib_memset (&ifr, 0, sizeof (ifr));
       strncpy (ifr.ifr_name, e->d_name, sizeof (ifr.ifr_name));
       ifr.ifr_name[ARRAY_LEN (ifr.ifr_name) - 1] = '\0';
       if (ioctl (fd, SIOCGIFFLAGS, &ifr) < 0)
@@ -580,7 +592,7 @@ vfio_set_irqs (vlib_main_t * vm, linux_pci_device_t * p, u32 index, u32 start,
   if (efds)
     {
       flags |= VFIO_IRQ_SET_DATA_EVENTFD;
-      clib_memcpy (&irq_set->data, efds, data_len);
+      clib_memcpy_fast (&irq_set->data, efds, data_len);
     }
   else
     flags |= VFIO_IRQ_SET_DATA_NONE;
@@ -951,6 +963,21 @@ add_device_vfio (vlib_main_t * vm, linux_pci_device_t * p,
       linux_pci_vfio_unmask_intx (vm, p);
     }
 
+  if (p->supports_va_dma)
+    {
+      vlib_buffer_pool_t *bp;
+      /* *INDENT-OFF* */
+      vec_foreach (bp, buffer_main.buffer_pools)
+       {
+         u32 i;
+         vlib_physmem_map_t *pm;
+         pm = vlib_physmem_get_map (vm, bp->physmem_map_index);
+         for (i = 0; i < pm->n_pages; i++)
+           vfio_map_physmem_page (vm, pm->base + (i << pm->log2_page_size));
+       }
+      /* *INDENT-ON* */
+    }
+
   if (r && r->init_function)
     err = r->init_function (lpm->vlib_main, p->handle);
 
@@ -990,21 +1017,18 @@ vlib_pci_read_write_config (vlib_main_t * vm, vlib_pci_dev_handle_t h,
 }
 
 static clib_error_t *
-vlib_pci_map_region_int (vlib_main_t * vm, vlib_pci_dev_handle_t h,
-                        u32 bar, u8 * addr, void **result)
+vlib_pci_region (vlib_main_t * vm, vlib_pci_dev_handle_t h, u32 bar, int *fd,
+                u64 * size, u64 * offset)
 {
   linux_pci_device_t *p = linux_pci_get_device (h);
-  int fd = -1;
-  clib_error_t *error;
-  int flags = MAP_SHARED;
-  u64 size = 0, offset = 0;
+  clib_error_t *error = 0;
+  int _fd = -1;
+  u64 _size = 0, _offset = 0;
 
   ASSERT (bar <= 5);
 
   error = 0;
 
-  pci_log_debug (vm, p, "map region %u to va %p", bar, addr);
-
   if (p->type == LINUX_PCI_DEVICE_TYPE_UIO)
     {
       u8 *file_name;
@@ -1012,27 +1036,25 @@ vlib_pci_map_region_int (vlib_main_t * vm, vlib_pci_dev_handle_t h,
       file_name = format (0, "%s/%U/resource%d%c", sysfs_pci_dev_path,
                          format_vlib_pci_addr, &p->addr, bar, 0);
 
-      fd = open ((char *) file_name, O_RDWR);
-      if (fd < 0)
+      _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;
        }
 
-      if (fstat (fd, &stat_buf) < 0)
+      if (fstat (_fd, &stat_buf) < 0)
        {
          error = clib_error_return_unix (0, "fstat `%s'", file_name);
          vec_free (file_name);
-         close (fd);
+         close (_fd);
          return error;
        }
 
       vec_free (file_name);
-      if (addr != 0)
-       flags |= MAP_FIXED;
-      size = stat_buf.st_size;
-      offset = 0;
+      _size = stat_buf.st_size;
+      _offset = 0;
     }
   else if (p->type == LINUX_PCI_DEVICE_TYPE_VFIO)
     {
@@ -1043,9 +1065,9 @@ vlib_pci_map_region_int (vlib_main_t * vm, vlib_pci_dev_handle_t h,
        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;
+      _fd = p->fd;
+      _size = reg.size;
+      _offset = reg.offset;
       pci_log_debug (vm, p, "%s region_info index:%u size:0x%lx offset:0x%lx "
                     "flags: %s%s%s(0x%x)", __func__,
                     reg.index, reg.size, reg.offset,
@@ -1057,6 +1079,31 @@ vlib_pci_map_region_int (vlib_main_t * vm, vlib_pci_dev_handle_t h,
   else
     ASSERT (0);
 
+  *fd = _fd;
+  *size = _size;
+  *offset = _offset;
+
+  return error;
+}
+
+static clib_error_t *
+vlib_pci_map_region_int (vlib_main_t * vm, vlib_pci_dev_handle_t h,
+                        u32 bar, u8 * addr, void **result)
+{
+  linux_pci_device_t *p = linux_pci_get_device (h);
+  int fd = -1;
+  clib_error_t *error;
+  int flags = MAP_SHARED;
+  u64 size = 0, offset = 0;
+
+  pci_log_debug (vm, p, "map region %u to va %p", bar, addr);
+
+  if ((error = vlib_pci_region (vm, h, bar, &fd, &size, &offset)))
+    return error;
+
+  if (p->type == LINUX_PCI_DEVICE_TYPE_UIO && addr != 0)
+    flags |= MAP_FIXED;
+
   *result = mmap (addr, size, PROT_READ | PROT_WRITE, flags, fd, offset);
   if (*result == (void *) -1)
     {
@@ -1091,6 +1138,61 @@ vlib_pci_map_region_fixed (vlib_main_t * vm, vlib_pci_dev_handle_t h,
   return (vlib_pci_map_region_int (vm, h, resource, addr, result));
 }
 
+clib_error_t *
+vlib_pci_io_region (vlib_main_t * vm, vlib_pci_dev_handle_t h, u32 resource)
+{
+  linux_pci_device_t *p = linux_pci_get_device (h);
+  clib_error_t *error = 0;
+  int fd = -1;
+  u64 size = 0, offset = 0;
+
+  if ((error = vlib_pci_region (vm, h, resource, &fd, &size, &offset)))
+    return error;
+
+  p->io_fd = fd;
+  p->io_offset = offset;
+  return error;
+}
+
+clib_error_t *
+vlib_pci_read_write_io (vlib_main_t * vm, vlib_pci_dev_handle_t h,
+                       vlib_read_or_write_t read_or_write,
+                       uword offset, void *data, u32 length)
+{
+  linux_pci_device_t *p = linux_pci_get_device (h);
+  int n = 0;
+
+  if (read_or_write == VLIB_READ)
+    n = pread (p->io_fd, data, length, p->io_offset + offset);
+  else
+    n = pwrite (p->io_fd, data, length, p->io_offset + offset);
+
+  if (n != length)
+    return clib_error_return_unix (0, "%s",
+                                  read_or_write == VLIB_READ
+                                  ? "read" : "write");
+  return 0;
+}
+
+clib_error_t *
+vlib_pci_map_dma (vlib_main_t * vm, vlib_pci_dev_handle_t h, void *ptr)
+{
+  linux_pci_device_t *p = linux_pci_get_device (h);
+
+  if (!p->supports_va_dma)
+    return 0;
+
+  return vfio_map_physmem_page (vm, ptr);
+}
+
+int
+vlib_pci_supports_virtual_addr_dma (vlib_main_t * vm, vlib_pci_dev_handle_t h)
+{
+  linux_pci_device_t *p = linux_pci_get_device (h);
+
+  return p->supports_va_dma != 0;
+}
+
 clib_error_t *
 vlib_pci_device_open (vlib_main_t * vm, vlib_pci_addr_t * addr,
                      pci_device_id_t ids[], vlib_pci_dev_handle_t * handle)
@@ -1116,6 +1218,11 @@ vlib_pci_device_open (vlib_main_t * vm, vlib_pci_addr_t * addr,
   p->handle = p - lpm->linux_pci_devices;
   p->addr.as_u32 = di->addr.as_u32;
   p->intx_irq.fd = -1;
+  p->numa_node = di->numa_node;
+  /*
+   * pci io bar read/write fd
+   */
+  p->io_fd = -1;
 
   pci_log_debug (vm, p, "open vid:0x%04x did:0x%04x driver:%s iommu_group:%d",
                 di->vendor_id, di->device_id, di->driver_name,
@@ -1138,7 +1245,7 @@ error:
   if (err)
     {
       pci_log_err (vm, p, "%U", format_clib_error, err);
-      memset (p, 0, sizeof (linux_pci_device_t));
+      clib_memset (p, 0, sizeof (linux_pci_device_t));
       pool_put (lpm->linux_pci_devices, p);
     }
 
@@ -1159,6 +1266,8 @@ vlib_pci_device_close (vlib_main_t * vm, vlib_pci_dev_handle_t h)
       irq = &p->intx_irq;
       clib_file_del_by_index (&file_main, irq->clib_file_index);
       close (p->config_fd);
+      if (p->io_fd != -1)
+       close (p->io_fd);
     }
   else if (p->type == LINUX_PCI_DEVICE_TYPE_VFIO)
     {
@@ -1205,7 +1314,7 @@ vlib_pci_device_close (vlib_main_t * vm, vlib_pci_dev_handle_t h)
   vec_free (p->regions);
 
   close (p->fd);
-  memset (p, 0, sizeof (linux_pci_device_t));
+  clib_memset (p, 0, sizeof (linux_pci_device_t));
   pool_put (lpm->linux_pci_devices, p);
 }
 
@@ -1244,7 +1353,7 @@ init_device_from_registered (vlib_main_t * vm, vlib_pci_device_info_t * di)
     }
 
   /* No driver, close the PCI config-space FD */
-  memset (p, 0, sizeof (linux_pci_device_t));
+  clib_memset (p, 0, sizeof (linux_pci_device_t));
   pool_put (lpm->linux_pci_devices, p);
 }