[libvirt] [PATCH 4/5] nodedev: add drm capability

marcandre.lureau at redhat.com marcandre.lureau at redhat.com
Tue Feb 14 21:04:12 UTC 2017


From: Marc-André Lureau <marcandre.lureau at redhat.com>

Add a new 'drm' capability for Direct Rendering Manager (DRM) devices,
providing device type information.

Teach the udev backend to populate those devices.

Signed-off-by: Marc-André Lureau <marcandre.lureau at redhat.com>
---
 docs/formatnode.html.in                    | 10 +++++++
 docs/schemas/nodedev.rng                   | 14 ++++++++++
 src/conf/node_device_conf.c                | 44 +++++++++++++++++++++++++++++-
 src/conf/node_device_conf.h                | 15 ++++++++++
 src/node_device/node_device_driver.c       |  1 +
 src/node_device/node_device_udev.c         | 41 ++++++++++++++++++++++++++++
 tests/nodedevschemadata/drm_renderD129.xml | 10 +++++++
 tests/nodedevxml2xmltest.c                 |  1 +
 8 files changed, 135 insertions(+), 1 deletion(-)
 create mode 100644 tests/nodedevschemadata/drm_renderD129.xml

diff --git a/docs/formatnode.html.in b/docs/formatnode.html.in
index ecdd1dbcb..a368ffc07 100644
--- a/docs/formatnode.html.in
+++ b/docs/formatnode.html.in
@@ -314,6 +314,16 @@
                 and <code>media_label</code>.</dd>
             </dl>
           </dd>
+          <dt><code>drm</code></dt>
+          <dd>Describes a Direct Rendering Manager (DRM) device.
+          Sub-elements include:
+            <dl>
+              <dt><code>type</code></dt>
+              <dd>The type of DRM device. Could be
+              <code>primary</code>, <code>control</code> or
+              <code>render</code>.</dd>
+            </dl>
+          </dd>
         </dl>
       </dd>
     </dl>
diff --git a/docs/schemas/nodedev.rng b/docs/schemas/nodedev.rng
index 62e29b6cc..0f90a73c8 100644
--- a/docs/schemas/nodedev.rng
+++ b/docs/schemas/nodedev.rng
@@ -82,6 +82,7 @@
         <ref name="capscsitarget"/>
         <ref name="capscsi"/>
         <ref name="capstorage"/>
+        <ref name="capdrm"/>
       </choice>
     </element>
   </define>
@@ -540,6 +541,19 @@
     </element>
   </define>
 
+  <define name='capdrm'>
+    <attribute name='type'>
+      <value>drm</value>
+    </attribute>
+    <element name='type'>
+      <choice>
+        <value>primary</value>
+        <value>control</value>
+        <value>render</value>
+      </choice>
+    </element>
+  </define>
+
   <define name='address'>
     <element name='address'>
       <attribute name='domain'><ref name='hexuint'/></attribute>
diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
index 0d1dafcd6..04b63cc93 100644
--- a/src/conf/node_device_conf.c
+++ b/src/conf/node_device_conf.c
@@ -56,12 +56,18 @@ VIR_ENUM_IMPL(virNodeDevCap, VIR_NODE_DEV_CAP_LAST,
               "storage",
               "fc_host",
               "vports",
-              "scsi_generic")
+              "scsi_generic",
+              "drm")
 
 VIR_ENUM_IMPL(virNodeDevNetCap, VIR_NODE_DEV_CAP_NET_LAST,
               "80203",
               "80211")
 
+VIR_ENUM_IMPL(virNodeDevDRM, VIR_NODE_DEV_DRM_LAST,
+              "primary",
+              "control",
+              "render")
+
 static int
 virNodeDevCapsDefParseString(const char *xpath,
                              xmlXPathContextPtr ctxt,
@@ -698,6 +704,9 @@ char *virNodeDeviceDefFormat(const virNodeDeviceDef *def)
             virBufferEscapeString(&buf, "<char>%s</char>\n",
                                   data->sg.path);
             break;
+        case VIR_NODE_DEV_CAP_DRM:
+            virBufferEscapeString(&buf, "<type>%s</type>\n", virNodeDevDRMTypeToString(data->drm.type));
+            break;
         case VIR_NODE_DEV_CAP_FC_HOST:
         case VIR_NODE_DEV_CAP_VPORTS:
         case VIR_NODE_DEV_CAP_LAST:
@@ -799,6 +808,35 @@ virNodeDevCapsDefParseULongLong(const char *xpath,
 }
 
 static int
+virNodeDevCapDRMParseXML(xmlXPathContextPtr ctxt,
+                         virNodeDeviceDefPtr def,
+                         xmlNodePtr node,
+                         virNodeDevCapDataPtr data)
+{
+    xmlNodePtr orignode;
+    int ret = -1;
+    char *type = NULL;
+
+    orignode = ctxt->node;
+    ctxt->node = node;
+
+    type = virXPathString("string(./type[1])", ctxt);
+
+    if ((data->drm.type = virNodeDevDRMTypeFromString(type)) < 0) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("unknown drm type '%s' for '%s'"), type, def->name);
+        goto out;
+    }
+
+    ret = 0;
+
+out:
+    VIR_FREE(type);
+    ctxt->node = orignode;
+    return ret;
+}
+
+static int
 virNodeDevCapStorageParseXML(xmlXPathContextPtr ctxt,
                              virNodeDeviceDefPtr def,
                              xmlNodePtr node,
@@ -1689,6 +1727,9 @@ virNodeDevCapsDefParseXML(xmlXPathContextPtr ctxt,
     case VIR_NODE_DEV_CAP_STORAGE:
         ret = virNodeDevCapStorageParseXML(ctxt, def, node, &caps->data);
         break;
+    case VIR_NODE_DEV_CAP_DRM:
+        ret = virNodeDevCapDRMParseXML(ctxt, def, node, &caps->data);
+        break;
     case VIR_NODE_DEV_CAP_FC_HOST:
     case VIR_NODE_DEV_CAP_VPORTS:
     case VIR_NODE_DEV_CAP_SCSI_GENERIC:
@@ -2116,6 +2157,7 @@ void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps)
     case VIR_NODE_DEV_CAP_SCSI_GENERIC:
         VIR_FREE(data->sg.path);
         break;
+    case VIR_NODE_DEV_CAP_DRM:
     case VIR_NODE_DEV_CAP_FC_HOST:
     case VIR_NODE_DEV_CAP_VPORTS:
     case VIR_NODE_DEV_CAP_LAST:
diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h
index f46e9841a..be7e0e003 100644
--- a/src/conf/node_device_conf.h
+++ b/src/conf/node_device_conf.h
@@ -62,6 +62,7 @@ typedef enum {
     VIR_NODE_DEV_CAP_FC_HOST,		/* FC Host Bus Adapter */
     VIR_NODE_DEV_CAP_VPORTS,		/* HBA which is capable of vports */
     VIR_NODE_DEV_CAP_SCSI_GENERIC,      /* SCSI generic device */
+    VIR_NODE_DEV_CAP_DRM,               /* DRM device */
 
     VIR_NODE_DEV_CAP_LAST
 } virNodeDevCapType;
@@ -93,6 +94,17 @@ typedef enum {
     VIR_NODE_DEV_CAP_FLAG_PCIE                      = (1 << 2),
 } virNodeDevPCICapFlags;
 
+typedef enum {
+    /* Keep in sync with VIR_ENUM_IMPL in node_device_conf.c */
+    VIR_NODE_DEV_DRM_PRIMARY,
+    VIR_NODE_DEV_DRM_CONTROL,
+    VIR_NODE_DEV_DRM_RENDER,
+
+    VIR_NODE_DEV_DRM_LAST
+} virNodeDevDRMType;
+
+VIR_ENUM_DECL(virNodeDevDRM)
+
 typedef struct _virNodeDevCapData {
     virNodeDevCapType type;
     union {
@@ -192,6 +204,9 @@ typedef struct _virNodeDevCapData {
         struct {
             char *path;
         } sg; /* SCSI generic device */
+        struct {
+            virNodeDevDRMType type;
+        } drm;
     };
 } virNodeDevCapData, *virNodeDevCapDataPtr;
 
diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c
index 5238e231d..d04713f5e 100644
--- a/src/node_device/node_device_driver.c
+++ b/src/node_device/node_device_driver.c
@@ -72,6 +72,7 @@ static int update_caps(virNodeDeviceObjPtr dev)
         /* all types that (supposedly) don't require any updates
          * relative to what's in the cache.
          */
+        case VIR_NODE_DEV_CAP_DRM:
         case VIR_NODE_DEV_CAP_SYSTEM:
         case VIR_NODE_DEV_CAP_USB_DEV:
         case VIR_NODE_DEV_CAP_USB_INTERFACE:
diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c
index d7658410a..6a91e0722 100644
--- a/src/node_device/node_device_udev.c
+++ b/src/node_device/node_device_udev.c
@@ -410,6 +410,42 @@ static int udevProcessPCI(struct udev_device *device,
     return ret;
 }
 
+static int drmGetMinorType(int minor)
+{
+    int type = minor >> 6;
+
+    if (minor < 0)
+        return -1;
+
+    switch (type) {
+    case VIR_NODE_DEV_DRM_PRIMARY:
+    case VIR_NODE_DEV_DRM_CONTROL:
+    case VIR_NODE_DEV_DRM_RENDER:
+        return type;
+    default:
+        return -1;
+    }
+}
+
+static int udevProcessDRMDevice(struct udev_device *device,
+                                virNodeDeviceDefPtr def)
+{
+    virNodeDevCapDataPtr data = &def->caps->data;
+    int minor;
+
+    if (udevGenerateDeviceName(device, def, NULL) != 0)
+        return -1;
+
+    if (udevGetIntProperty(device, "MINOR", &minor, 10) < 0)
+        return -1;
+
+    if ((minor = drmGetMinorType(minor)) == -1)
+        return -1;
+
+    data->drm.type = minor;
+
+    return 0;
+}
 
 static int udevProcessUSBDevice(struct udev_device *device,
                                 virNodeDeviceDefPtr def)
@@ -971,6 +1007,8 @@ udevGetDeviceType(struct udev_device *device,
             *type = VIR_NODE_DEV_CAP_STORAGE;
         else if (STREQ(devtype, "wlan"))
             *type = VIR_NODE_DEV_CAP_NET;
+        else if (STREQ(devtype, "drm_minor"))
+            *type = VIR_NODE_DEV_CAP_DRM;
     } else {
         /* PCI devices don't set the DEVTYPE property. */
         if (udevHasDeviceProperty(device, "PCI_CLASS"))
@@ -1039,6 +1077,9 @@ static int udevGetDeviceDetails(struct udev_device *device,
     case VIR_NODE_DEV_CAP_SCSI_GENERIC:
         ret = udevProcessSCSIGeneric(device, def);
         break;
+    case VIR_NODE_DEV_CAP_DRM:
+        ret = udevProcessDRMDevice(device, def);
+        break;
     default:
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Unknown device type %d"), def->caps->data.type);
diff --git a/tests/nodedevschemadata/drm_renderD129.xml b/tests/nodedevschemadata/drm_renderD129.xml
new file mode 100644
index 000000000..161481624
--- /dev/null
+++ b/tests/nodedevschemadata/drm_renderD129.xml
@@ -0,0 +1,10 @@
+<device>
+  <name>drm_renderD129</name>
+  <path>/sys/devices/pci0000:00/0000:00:02.0/drm/renderD129</path>
+  <devnode type='dev'>/dev/dri/renderD129</devnode>
+  <devnode type='link'>/dev/dri/by-path/pci-0000:00:02.0-render</devnode>
+  <parent>pci_0000_00_02_0</parent>
+  <capability type='drm'>
+    <type>render</type>
+  </capability>
+</device>
diff --git a/tests/nodedevxml2xmltest.c b/tests/nodedevxml2xmltest.c
index ec96943cb..5e1ae170c 100644
--- a/tests/nodedevxml2xmltest.c
+++ b/tests/nodedevxml2xmltest.c
@@ -100,6 +100,7 @@ mymain(void)
     DO_TEST("pci_0000_02_10_7_sriov_zero_vfs_max_count");
     DO_TEST("pci_0000_02_10_7_sriov_pf_vfs_all");
     DO_TEST("pci_0000_02_10_7_sriov_pf_vfs_all_header_type");
+    DO_TEST("drm_renderD129");
 
     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }
-- 
2.11.0.295.gd7dffce1c.dirty




More information about the libvir-list mailing list