pci: fix VFIO set IRQ code
[vpp.git] / src / vlib / linux / pci.c
index 75d9edf..62db820 100644 (file)
@@ -61,12 +61,17 @@ static const char *sysfs_pci_drv_path = "/sys/bus/pci/drivers";
 static char *sysfs_mod_vfio_noiommu =
   "/sys/module/vfio/parameters/enable_unsafe_noiommu_mode";
 
-#define pci_log_debug(vm, dev, f, ...) \
-  vlib_log(VLIB_LOG_LEVEL_DEBUG, pci_main.log_default, "%U: " f, \
-           format_vlib_pci_addr, vlib_pci_get_addr(vm, dev->handle), ## __VA_ARGS__)
-#define pci_log_err(vm, dev, f, ...) \
-  vlib_log(VLIB_LOG_LEVEL_ERR, pci_main.log_default, "%U: " f, \
-           format_vlib_pci_addr, vlib_pci_get_addr(vm, dev->handle), ## __VA_ARGS__)
+VLIB_REGISTER_LOG_CLASS (pci_log, static) = {
+  .class_name = "pci",
+  .subclass_name = "linux",
+};
+
+#define log_debug(p, f, ...)                                                  \
+  vlib_log (VLIB_LOG_LEVEL_DEBUG, pci_log.class, "%U: " f,                    \
+           format_vlib_pci_log, p->handle, ##__VA_ARGS__)
+#define log_err(p, f, ...)                                                    \
+  vlib_log (VLIB_LOG_LEVEL_ERR, pci_log.class, "%U: " f, format_vlib_pci_log, \
+           p->handle, ##__VA_ARGS__)
 
 typedef struct
 {
@@ -233,32 +238,14 @@ vlib_pci_get_device_info (vlib_main_t * vm, vlib_pci_addr_t * addr,
 
   /* 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->config0))
+  if (read (fd, &di->config, sizeof (di->config)) <
+      sizeof (vlib_pci_config_hdr_t))
     {
       err = clib_error_return_unix (0, "read `%s'", f);
       close (fd);
       goto error;
     }
 
-  {
-    static pci_config_header_t all_ones;
-    if (all_ones.vendor_id == 0)
-      clib_memset (&all_ones, ~0, sizeof (all_ones));
-
-    if (!memcmp (&di->config0.header, &all_ones, sizeof (all_ones)))
-      {
-       err = clib_error_return (0, "invalid PCI config for `%s'", f);
-       close (fd);
-       goto error;
-      }
-  }
-
-  if (di->config0.header.header_type == 0)
-    pci_config_type0_little_to_host (&di->config0);
-  else
-    pci_config_type1_little_to_host (&di->config1);
-
   di->numa_node = -1;
   vec_reset_length (f);
   f = format (f, "%v/numa_node%c", dev_dir_name, 0);
@@ -301,15 +288,19 @@ vlib_pci_get_device_info (vlib_main_t * vm, vlib_pci_addr_t * addr,
   di->device_id = tmp;
 
   vec_reset_length (f);
-  f = format (f, "%v/driver%c", dev_dir_name, 0);
-  di->driver_name = clib_sysfs_link_to_name ((char *) f);
+  f = format (f, "%v/revision%c", dev_dir_name, 0);
+  err = clib_sysfs_read ((char *) f, "0x%x", &tmp);
+  if (err)
+    goto error;
+  di->revision = tmp;
+
+  di->driver_name =
+    clib_file_get_resolved_basename ("%v/driver", dev_dir_name);
   if (!di->driver_name)
     di->driver_name = format (0, "<NONE>%c", 0);
 
   di->iommu_group = -1;
-  vec_reset_length (f);
-  f = format (f, "%v/iommu_group%c", dev_dir_name, 0);
-  tmpstr = clib_sysfs_link_to_name ((char *) f);
+  tmpstr = clib_file_get_resolved_basename ("%v/iommu_group", dev_dir_name);
   if (tmpstr)
     {
       di->iommu_group = atoi ((char *) tmpstr);
@@ -513,9 +504,7 @@ vlib_pci_bind_to_uio (vlib_main_t *vm, vlib_pci_addr_t *addr,
        }
     }
 
-  s = format (s, "%v/driver%c", dev_dir_name, 0);
-  driver_name = clib_sysfs_link_to_name ((char *) s);
-  vec_reset_length (s);
+  driver_name = clib_file_get_resolved_basename ("%v/driver", dev_dir_name);
 
   if (driver_name &&
       ((strcmp ("vfio-pci", (char *) driver_name) == 0) ||
@@ -670,13 +659,12 @@ vfio_set_irqs (vlib_main_t * vm, linux_pci_device_t * p, u32 index, u32 start,
     return clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_IRQ_INFO) "
                                   "'%U'", format_vlib_pci_addr, &p->addr);
 
-  pci_log_debug (vm, p, "%s index:%u count:%u flags: %s%s%s%s(0x%x)",
-                __func__, ii.index, ii.count,
-                ii.flags & VFIO_IRQ_INFO_EVENTFD ? "eventfd " : "",
-                ii.flags & VFIO_IRQ_INFO_MASKABLE ? "maskable " : "",
-                ii.flags & VFIO_IRQ_INFO_AUTOMASKED ? "automasked " : "",
-                ii.flags & VFIO_IRQ_INFO_NORESIZE ? "noresize " : "",
-                ii.flags);
+  log_debug (p, "%s index:%u count:%u flags: %s%s%s%s(0x%x)", __func__,
+            ii.index, ii.count,
+            ii.flags & VFIO_IRQ_INFO_EVENTFD ? "eventfd " : "",
+            ii.flags & VFIO_IRQ_INFO_MASKABLE ? "maskable " : "",
+            ii.flags & VFIO_IRQ_INFO_AUTOMASKED ? "automasked " : "",
+            ii.flags & VFIO_IRQ_INFO_NORESIZE ? "noresize " : "", ii.flags);
 
   if (ii.count < start + count)
     return clib_error_return_unix (0, "vfio_set_irq: unexistng interrupt on "
@@ -864,13 +852,12 @@ vlib_pci_register_intx_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h,
       if (ioctl (p->fd, VFIO_DEVICE_GET_IRQ_INFO, &ii) < 0)
        return clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_IRQ_INFO) '"
                                       "%U'", format_vlib_pci_addr, &p->addr);
-      pci_log_debug (vm, p, "%s index:%u count:%u flags: %s%s%s%s(0x%x)",
-                    __func__, ii.index, ii.count,
-                    ii.flags & VFIO_IRQ_INFO_EVENTFD ? "eventfd " : "",
-                    ii.flags & VFIO_IRQ_INFO_MASKABLE ? "maskable " : "",
-                    ii.flags & VFIO_IRQ_INFO_AUTOMASKED ? "automasked " : "",
-                    ii.flags & VFIO_IRQ_INFO_NORESIZE ? "noresize " : "",
-                    ii.flags);
+      log_debug (
+       p, "%s index:%u count:%u flags: %s%s%s%s(0x%x)", __func__, ii.index,
+       ii.count, ii.flags & VFIO_IRQ_INFO_EVENTFD ? "eventfd " : "",
+       ii.flags & VFIO_IRQ_INFO_MASKABLE ? "maskable " : "",
+       ii.flags & VFIO_IRQ_INFO_AUTOMASKED ? "automasked " : "",
+       ii.flags & VFIO_IRQ_INFO_NORESIZE ? "noresize " : "", ii.flags);
       if (ii.count != 1)
        return clib_error_return (0, "INTx interrupt does not exist on device"
                                  "'%U'", format_vlib_pci_addr, &p->addr);
@@ -898,6 +885,27 @@ vlib_pci_register_intx_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h,
   return 0;
 }
 
+clib_error_t *
+vlib_pci_unregister_intx_handler (vlib_main_t *vm, vlib_pci_dev_handle_t h)
+{
+  linux_pci_device_t *p = linux_pci_get_device (h);
+  linux_pci_irq_t *irq = &p->intx_irq;
+
+  if (irq->intx_handler == 0)
+    return 0;
+
+  clib_file_del_by_index (&file_main, irq->clib_file_index);
+  if (p->type == LINUX_PCI_DEVICE_TYPE_VFIO)
+    {
+      close (irq->fd);
+      irq->fd = -1;
+    }
+
+  irq->intx_handler = 0;
+
+  return 0;
+}
+
 clib_error_t *
 vlib_pci_register_msix_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h,
                                u32 start, u32 count,
@@ -955,6 +963,33 @@ error:
   return err;
 }
 
+clib_error_t *
+vlib_pci_unregister_msix_handler (vlib_main_t *vm, vlib_pci_dev_handle_t h,
+                                 u32 start, u32 count)
+{
+  clib_error_t *err = 0;
+  linux_pci_device_t *p = linux_pci_get_device (h);
+  u32 i;
+
+  if (p->type != LINUX_PCI_DEVICE_TYPE_VFIO)
+    return clib_error_return (0, "vfio driver is needed for MSI-X interrupt "
+                                "support");
+
+  for (i = start; i < start + count; i++)
+    {
+      linux_pci_irq_t *irq = vec_elt_at_index (p->msix_irqs, i);
+
+      if (irq->fd != -1)
+       {
+         clib_file_del_by_index (&file_main, irq->clib_file_index);
+         close (irq->fd);
+         irq->fd = -1;
+       }
+    }
+
+  return err;
+}
+
 clib_error_t *
 vlib_pci_enable_msix_irq (vlib_main_t * vm, vlib_pci_dev_handle_t h,
                          u16 start, u16 count)
@@ -967,9 +1002,9 @@ vlib_pci_enable_msix_irq (vlib_main_t * vm, vlib_pci_dev_handle_t h,
     return clib_error_return (0, "vfio driver is needed for MSI-X interrupt "
                              "support");
 
-  for (i = start; i < start + count; i++)
+  for (i = 0; i < count; i++)
     {
-      linux_pci_irq_t *irq = vec_elt_at_index (p->msix_irqs, i);
+      linux_pci_irq_t *irq = vec_elt_at_index (p->msix_irqs, start + i);
       fds[i] = irq->fd;
     }
 
@@ -1042,7 +1077,7 @@ add_device_vfio (vlib_main_t * vm, linux_pci_device_t * p,
       goto error;
     }
 
-  pci_log_debug (vm, p, "%s %U", __func__, format_vfio_region_info, &reg);
+  log_debug (p, "%s %U", __func__, format_vfio_region_info, &reg);
 
   p->config_offset = reg.offset;
   p->config_fd = p->fd;
@@ -1177,7 +1212,7 @@ vlib_pci_region (vlib_main_t * vm, vlib_pci_dev_handle_t h, u32 bar, int *fd,
       _fd = p->fd;
       _size = r->size;
       _offset = r->offset;
-      pci_log_debug (vm, p, "%s %U", __func__, format_vfio_region_info, r);
+      log_debug (p, "%s %U", __func__, format_vfio_region_info, r);
       clib_mem_free (r);
     }
   else
@@ -1198,18 +1233,18 @@ vlib_pci_map_region_int (vlib_main_t * vm, vlib_pci_dev_handle_t h,
   int fd = -1;
   clib_error_t *error;
   u64 size = 0, offset = 0;
-  u16 command;
+  vlib_pci_config_reg_command_t command;
 
-  pci_log_debug (vm, p, "map region %u to va %p", bar, addr);
+  log_debug (p, "map region %u to va %p", bar, addr);
 
-  if ((error = vlib_pci_read_config_u16 (vm, h, 4, &command)))
+  if ((error = vlib_pci_read_config_u16 (vm, h, 4, &command.as_u16)))
     return error;
 
-  if (!(command & PCI_COMMAND_MEMORY))
+  if (!(command.mem_space))
     {
-      pci_log_debug (vm, p, "setting memory enable bit");
-      command |= PCI_COMMAND_MEMORY;
-      if ((error = vlib_pci_write_config_u16 (vm, h, 4, &command)))
+      log_debug (p, "setting memory enable bit");
+      command.mem_space = 1;
+      if ((error = vlib_pci_write_config_u16 (vm, h, 4, &command.as_u16)))
        return error;
     }
 
@@ -1321,12 +1356,19 @@ vlib_pci_device_open (vlib_main_t * vm, vlib_pci_addr_t * addr,
 
   if (err)
     return err;
-  for (i = ids; i->vendor_id != 0; i++)
-    if (i->vendor_id == di->vendor_id && i->device_id == di->device_id)
-      break;
 
-  if (i->vendor_id == 0)
-    return clib_error_return (0, "Wrong vendor or device id");
+  if (ids)
+    {
+      for (i = ids; i->vendor_id != 0; i++)
+       if (i->vendor_id == di->vendor_id && i->device_id == di->device_id)
+         break;
+
+      if (i->vendor_id == 0)
+       {
+         vlib_pci_free_device_info (di);
+         return clib_error_return (0, "Wrong vendor or device id");
+       }
+    }
 
   pool_get (lpm->linux_pci_devices, p);
   p->handle = p - lpm->linux_pci_devices;
@@ -1339,9 +1381,8 @@ vlib_pci_device_open (vlib_main_t * vm, vlib_pci_addr_t * addr,
    */
   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,
-                di->iommu_group);
+  log_debug (p, "open vid:0x%04x did:0x%04x driver:%s iommu_group:%d",
+            di->vendor_id, di->device_id, di->driver_name, di->iommu_group);
 
   if (clib_strncmp ("vfio-pci", (char *) di->driver_name, 8) == 0)
     err = add_device_vfio (vm, p, di, 0);
@@ -1359,7 +1400,7 @@ error:
   vlib_pci_free_device_info (di);
   if (err)
     {
-      pci_log_err (vm, p, "%U", format_clib_error, err);
+      log_err (p, "%U", format_clib_error, err);
       clib_memset (p, 0, sizeof (linux_pci_device_t));
       pool_put (lpm->linux_pci_devices, p);
     }