pci: improve vfio logging

Type: improvement
Change-Id: Ic49a43651b80b79fa278e29964da5cb2ead2a818
Signed-off-by: Damjan Marion <damarion@cisco.com>
diff --git a/src/vlib/linux/pci.c b/src/vlib/linux/pci.c
index 722fb88..168acde 100644
--- a/src/vlib/linux/pci.c
+++ b/src/vlib/linux/pci.c
@@ -966,13 +966,7 @@
       goto error;
     }
 
-  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,
-		 reg.flags & VFIO_REGION_INFO_FLAG_READ ? "rd " : "",
-		 reg.flags & VFIO_REGION_INFO_FLAG_WRITE ? "wr " : "",
-		 reg.flags & VFIO_REGION_INFO_FLAG_MMAP ? "mmap " : "",
-		 reg.flags);
+  pci_log_debug (vm, p, "%s %U", __func__, format_vfio_region_info, &reg);
 
   p->config_offset = reg.offset;
   p->config_fd = p->fd;
@@ -1087,23 +1081,28 @@
     }
   else if (p->type == LINUX_PCI_DEVICE_TYPE_VFIO)
     {
-      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, &reg) < 0)
+      struct vfio_region_info *r;
+      u32 sz = sizeof (struct vfio_region_info);
+    again:
+      r = clib_mem_alloc (sz);
+      clib_memset (r, 0, sz);
+      r->argsz = sz;
+      r->index = bar;
+      if (ioctl (p->fd, VFIO_DEVICE_GET_REGION_INFO, r) < 0)
 	return clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_INFO) "
 				       "'%U'", format_vlib_pci_addr,
 				       &p->addr);
+      if (sz != r->argsz)
+	{
+	  sz = r->argsz;
+	  clib_mem_free (r);
+	  goto again;
+	}
       _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,
-		     reg.flags & VFIO_REGION_INFO_FLAG_READ ? "rd " : "",
-		     reg.flags & VFIO_REGION_INFO_FLAG_WRITE ? "wr " : "",
-		     reg.flags & VFIO_REGION_INFO_FLAG_MMAP ? "mmap " : "",
-		     reg.flags);
+      _size = r->size;
+      _offset = r->offset;
+      pci_log_debug (vm, p, "%s %U", __func__, format_vfio_region_info, r);
+      clib_mem_free (r);
     }
   else
     ASSERT (0);
diff --git a/src/vlib/linux/vfio.c b/src/vlib/linux/vfio.c
index 1ed99ce..33de135 100644
--- a/src/vlib/linux/vfio.c
+++ b/src/vlib/linux/vfio.c
@@ -246,6 +246,62 @@
   return 0;
 }
 
+u8 *
+format_vfio_region_info (u8 * s, va_list * args)
+{
+  struct vfio_region_info *r = va_arg (*args, struct vfio_region_info *);
+
+  s = format (s, "region_info index:%u size:0x%lx offset:0x%lx flags:",
+	      r->index, r->size, r->offset);
+
+  if (r->flags & VFIO_REGION_INFO_FLAG_READ)
+    s = format (s, " rd");
+
+  if (r->flags & VFIO_REGION_INFO_FLAG_WRITE)
+    s = format (s, " wr");
+
+  if (r->flags & VFIO_REGION_INFO_FLAG_MMAP)
+    s = format (s, " mmap");
+
+#ifdef VFIO_REGION_INFO_FLAG_CAPS
+  if (r->flags & VFIO_REGION_INFO_FLAG_CAPS)
+    s = format (s, " caps");
+#endif
+
+  s = format (s, " (0x%x)", r->flags);
+
+#ifdef VFIO_REGION_INFO_FLAG_CAPS
+  u32 cap_offset;
+
+  if ((r->flags & VFIO_REGION_INFO_FLAG_CAPS) == 0)
+    return s;
+
+  s = format (s, "\n caps:");
+  cap_offset = r->cap_offset;
+
+  do
+    {
+      struct vfio_info_cap_header *cap = (void *) r + cap_offset;
+#ifdef VFIO_REGION_INFO_CAP_SPARSE_MMAP
+      if (cap->id == VFIO_REGION_INFO_CAP_SPARSE_MMAP)
+	s = format (s, " sparse-mmap");
+#endif
+#ifdef VFIO_REGION_INFO_CAP_TYPE
+      if (cap->id == VFIO_REGION_INFO_CAP_TYPE)
+	s = format (s, " type");
+#endif
+#ifdef VFIO_REGION_INFO_CAP_MSIX_MAPPABLE
+      if (cap->id == VFIO_REGION_INFO_CAP_MSIX_MAPPABLE)
+	s = format (s, " msix-mappable");
+#endif
+      cap_offset = cap->next;
+    }
+  while (cap_offset);
+#endif
+
+  return s;
+}
+
 /*
  * fd.io coding-style-patch-verification: ON
  *
diff --git a/src/vlib/linux/vfio.h b/src/vlib/linux/vfio.h
index c1d8156..fe4f0f7 100644
--- a/src/vlib/linux/vfio.h
+++ b/src/vlib/linux/vfio.h
@@ -49,6 +49,8 @@
 clib_error_t *linux_vfio_group_get_device_fd (vlib_pci_addr_t * addr,
 					      int *fd, int *is_noiommu);
 
+format_function_t format_vfio_region_info;
+
 
 #endif /* included_vlib_linux_vfio_h */