diff --git a/docs/formatnode.html.in b/docs/formatnode.html.in
index ecdd1dbcb482a23bec8a4b6dfed47e26f8e344e1..a368ffc07dadbd4d22b4fbf93c9147a3c52230b4 100644
--- a/docs/formatnode.html.in
+++ b/docs/formatnode.html.in
@@ -314,6 +314,16 @@
and media_label
.
+
drm
+ Describes a Direct Rendering Manager (DRM) device.
+ Sub-elements include:
+
+ type
+ - The type of DRM device. Could be
+
primary
, control
or
+ render
.
+
+
diff --git a/docs/schemas/nodedev.rng b/docs/schemas/nodedev.rng
index 62e29b6cc1ab0884b2b69f8ddae5cc25d9fa8337..0f90a73c8ad8d14cd4246213639ba780526c44b9 100644
--- a/docs/schemas/nodedev.rng
+++ b/docs/schemas/nodedev.rng
@@ -82,6 +82,7 @@
+
@@ -540,6 +541,19 @@
+
+
+ drm
+
+
+
+ primary
+ control
+ render
+
+
+
+
diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
index a3cefcda8d8bd96e665052943b8d703db0c49e6c..f996db115221a7807d42c8aa491a2a600956e1d2 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, "%s\n",
data->sg.path);
break;
+ case VIR_NODE_DEV_CAP_DRM:
+ virBufferEscapeString(&buf, "%s\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:
@@ -798,6 +807,35 @@ virNodeDevCapsDefParseULongLong(const char *xpath,
return 0;
}
+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,
@@ -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 f46e9841aeeffc854a4cd6f53b4aa5fe729f4540..be7e0e003afbac50ce472e9120fcdfa99cee4b81 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 4900e322270d784999b7e85547ec04b9261e7600..df217f847b76882e259682ef9c75f9ef0b648d36 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 d7658410a94937d64382d1d96c620259891f07cd..6a91e0722f87282637e93cf868ccf5db48f0abf5 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 0000000000000000000000000000000000000000..161481624f50264b860698df7947cc0a8fcaa2ed
--- /dev/null
+++ b/tests/nodedevschemadata/drm_renderD129.xml
@@ -0,0 +1,10 @@
+
+ drm_renderD129
+ /sys/devices/pci0000:00/0000:00:02.0/drm/renderD129
+ /dev/dri/renderD129
+ /dev/dri/by-path/pci-0000:00:02.0-render
+ pci_0000_00_02_0
+
+ render
+
+
diff --git a/tests/nodedevxml2xmltest.c b/tests/nodedevxml2xmltest.c
index ec96943cb16c7a200cda5de579dbe2a0af51d365..5e1ae170c37839711302870d11cebf24d3045fba 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;
}