Add detection of mdev_types capability to channel subsystem devices.
Signed-off-by: Boris Fiuczynski <fiuczy(a)linux.ibm.com>
Reviewed-by: Bjoern Walk <bwalk(a)linux.ibm.com>
---
docs/drvnodedev.html.in | 5 +-
docs/formatnode.html.in | 39 ++++++++
docs/schemas/nodedev.rng | 4 +
src/conf/node_device_conf.c | 92 ++++++++++++++++++-
src/conf/node_device_conf.h | 11 +++
src/conf/virnodedeviceobj.c | 7 +-
src/libvirt_private.syms | 1 +
src/node_device/node_device_udev.c | 3 +
.../css_0_0_fffe_mdev_types.xml | 17 ++++
tests/nodedevxml2xmltest.c | 1 +
10 files changed, 175 insertions(+), 5 deletions(-)
create mode 100644 tests/nodedevschemadata/css_0_0_fffe_mdev_types.xml
diff --git a/docs/drvnodedev.html.in b/docs/drvnodedev.html.in
index 0823c1888d..d5191d6d93 100644
--- a/docs/drvnodedev.html.in
+++ b/docs/drvnodedev.html.in
@@ -139,12 +139,13 @@
<h3><a id="MDEVCap">MDEV capability</a></h3>
<p>
- A PCI device capable of creating mediated devices will include a nested
+ A device capable of creating mediated devices will include a nested
capability <code>mdev_types</code> which enumerates all supported mdev
types on the physical device, along with the type attributes available
through sysfs. A detailed description of the XML format for the
<code>mdev_types</code> capability can be found
- <a href="formatnode.html#MDEVCap">here</a>.
+ <a href="formatnode.html#MDEVCap">here for PCI</a> or
+ <a href="formatnode.html#MDEVCapCSS">here for CSS</a>.
</p>
<p>
The following example shows how we might represent an NVIDIA GPU device
diff --git a/docs/formatnode.html.in b/docs/formatnode.html.in
index 594427468b..7f3c71941d 100644
--- a/docs/formatnode.html.in
+++ b/docs/formatnode.html.in
@@ -430,6 +430,45 @@
<dd>The subchannel-set identifier.</dd>
<dt><code>devno</code></dt>
<dd>The device number.</dd>
+ <dt><code>capability</code></dt>
+ <dd>
+ This optional element can occur multiple times. If it
+ exists, it has a mandatory <code>type</code> attribute
+ which will be set to:
+ <dl>
+ <dt><code><a
id="MDEVCapCSS">mdev_types</a></code></dt>
+ <dd>
+ This device is capable of creating mediated devices, and
+ the capability will contain a list of <code>type</code>
+ elements, which list all mdev types supported on the
+ physical device. <span class="since">Since
6.9.0</span>
+ Each <code>type</code> element has a single
<code>id</code>
+ attribute that holds an official vendor-supplied identifier
+ for the type. It supports the following sub-elements:
+ <dl>
+ <dt><code>name</code></dt>
+ <dd>
+ The <code>name</code> element holds a
vendor-supplied
+ code name for the given mediated device type. This is
+ an optional element.
+ </dd>
+ <dt><code>deviceAPI</code></dt>
+ <dd>
+ The value of this element describes how an instance of
+ the given type will be presented to the guest by the
+ VFIO framework.
+ </dd>
+ <dt><code>availableInstances</code></dt>
+ <dd>
+ This element reports the current state of resource
+ allocation. In other words, how many instances of the
+ given type can still be successfully created on the
+ physical device.
+ </dd>
+ </dl>
+ </dd>
+ </dl>
+ </dd>
</dl>
</dd>
</dl>
diff --git a/docs/schemas/nodedev.rng b/docs/schemas/nodedev.rng
index 9548412999..d3248e90a9 100644
--- a/docs/schemas/nodedev.rng
+++ b/docs/schemas/nodedev.rng
@@ -653,6 +653,9 @@
<element name="devno">
<ref name="ccwDevnoRange"/>
</element>
+ <optional>
+ <ref name="mdev_types"/>
+ </optional>
</define>
<define name="address">
@@ -692,6 +695,7 @@
<element name="deviceAPI">
<choice>
<value>vfio-pci</value>
+ <value>vfio-ccw</value>
</choice>
</element>
<element name="availableInstances">
diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
index 39950565b5..75c033b0e1 100644
--- a/src/conf/node_device_conf.c
+++ b/src/conf/node_device_conf.c
@@ -544,6 +544,10 @@ virNodeDeviceCapCCWDefFormat(virBufferPtr buf,
data->ccw_dev.ssid);
virBufferAsprintf(buf, "<devno>0x%04x</devno>\n",
data->ccw_dev.devno);
+ if (data->ccw_dev.flags & VIR_NODE_DEV_CAP_FLAG_CSS_MDEV)
+ virNodeDeviceCapMdevTypesFormat(buf,
+ data->ccw_dev.mdev_types,
+ data->ccw_dev.nmdev_types);
}
@@ -832,6 +836,33 @@ virNodeDevCapMdevTypesParseXML(xmlXPathContextPtr ctxt,
}
+static int
+virNodeDevCSSCapabilityParseXML(xmlXPathContextPtr ctxt,
+ xmlNodePtr node,
+ virNodeDevCapCCWPtr ccw_dev)
+{
+ g_autofree char *type = virXMLPropString(node, "type");
+ VIR_XPATH_NODE_AUTORESTORE(ctxt)
+
+ ctxt->node = node;
+
+ if (!type) {
+ virReportError(VIR_ERR_XML_ERROR, "%s", _("Missing capability
type"));
+ return -1;
+ }
+
+ if (STREQ(type, "mdev_types")) {
+ if (virNodeDevCapMdevTypesParseXML(ctxt,
+ &ccw_dev->mdev_types,
+ &ccw_dev->nmdev_types) < 0)
+ return -1;
+ ccw_dev->flags |= VIR_NODE_DEV_CAP_FLAG_CSS_MDEV;
+ }
+
+ return 0;
+}
+
+
static int
virNodeDevCapCCWParseXML(xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def,
@@ -839,6 +870,9 @@ virNodeDevCapCCWParseXML(xmlXPathContextPtr ctxt,
virNodeDevCapCCWPtr ccw_dev)
{
VIR_XPATH_NODE_AUTORESTORE(ctxt)
+ g_autofree xmlNodePtr *nodes = NULL;
+ int n = 0;
+ size_t i = 0;
g_autofree char *cssid = NULL;
g_autofree char *ssid = NULL;
g_autofree char *devno = NULL;
@@ -884,6 +918,14 @@ virNodeDevCapCCWParseXML(xmlXPathContextPtr ctxt,
return -1;
}
+ if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0)
+ return -1;
+
+ for (i = 0; i < n; i++) {
+ if (virNodeDevCSSCapabilityParseXML(ctxt, nodes[i], ccw_dev) < 0)
+ return -1;
+ }
+
return 0;
}
@@ -2241,12 +2283,16 @@ virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps)
virMediatedDeviceAttrFree(data->mdev.attributes[i]);
VIR_FREE(data->mdev.attributes);
break;
+ case VIR_NODE_DEV_CAP_CSS_DEV:
+ for (i = 0; i < data->ccw_dev.nmdev_types; i++)
+ virMediatedDeviceTypeFree(data->ccw_dev.mdev_types[i]);
+ VIR_FREE(data->ccw_dev.mdev_types);
+ break;
case VIR_NODE_DEV_CAP_MDEV_TYPES:
case VIR_NODE_DEV_CAP_DRM:
case VIR_NODE_DEV_CAP_FC_HOST:
case VIR_NODE_DEV_CAP_VPORTS:
case VIR_NODE_DEV_CAP_CCW_DEV:
- case VIR_NODE_DEV_CAP_CSS_DEV:
case VIR_NODE_DEV_CAP_LAST:
/* This case is here to shutup the compiler */
break;
@@ -2284,6 +2330,11 @@ virNodeDeviceUpdateCaps(virNodeDeviceDefPtr def)
&cap->data.pci_dev) < 0)
return -1;
break;
+ case VIR_NODE_DEV_CAP_CSS_DEV:
+ if (virNodeDeviceGetCSSDynamicCaps(def->sysfs_path,
+ &cap->data.ccw_dev) < 0)
+ return -1;
+ break;
/* all types that (supposedly) don't require any updates
* relative to what's in the cache.
@@ -2300,7 +2351,6 @@ virNodeDeviceUpdateCaps(virNodeDeviceDefPtr def)
case VIR_NODE_DEV_CAP_MDEV_TYPES:
case VIR_NODE_DEV_CAP_MDEV:
case VIR_NODE_DEV_CAP_CCW_DEV:
- case VIR_NODE_DEV_CAP_CSS_DEV:
case VIR_NODE_DEV_CAP_LAST:
break;
}
@@ -2374,6 +2424,15 @@ virNodeDeviceCapsListExport(virNodeDeviceDefPtr def,
ncaps++;
}
}
+
+ if (caps->data.type == VIR_NODE_DEV_CAP_CSS_DEV) {
+ flags = caps->data.ccw_dev.flags;
+
+ if (flags & VIR_NODE_DEV_CAP_FLAG_CSS_MDEV) {
+ MAYBE_ADD_CAP(VIR_NODE_DEV_CAP_MDEV_TYPES);
+ ncaps++;
+ }
+ }
}
#undef MAYBE_ADD_CAP
@@ -2639,6 +2698,28 @@ virNodeDeviceGetPCIDynamicCaps(const char *sysfsPath,
return 0;
}
+
+/* virNodeDeviceGetCSSDynamicCaps() get info that is stored in sysfs
+ * about devices related to this device, i.e. things that can change
+ * without this device itself changing. These must be refreshed
+ * anytime full XML of the device is requested, because they can
+ * change with no corresponding notification from the kernel/udev.
+ */
+int
+virNodeDeviceGetCSSDynamicCaps(const char *sysfsPath,
+ virNodeDevCapCCWPtr ccw_dev)
+{
+ ccw_dev->flags &= ~VIR_NODE_DEV_CAP_FLAG_CSS_MDEV;
+ if (virNodeDeviceGetMdevTypesCaps(sysfsPath,
+ &ccw_dev->mdev_types,
+ &ccw_dev->nmdev_types) < 0)
+ return -1;
+ if (ccw_dev->nmdev_types > 0)
+ ccw_dev->flags |= VIR_NODE_DEV_CAP_FLAG_CSS_MDEV;
+
+ return 0;
+}
+
#else
int
@@ -2661,4 +2742,11 @@ int virNodeDeviceGetSCSITargetCaps(const char *sysfsPath
G_GNUC_UNUSED,
return -1;
}
+int
+virNodeDeviceGetCSSDynamicCaps(const char *sysfsPath G_GNUC_UNUSED,
+ virNodeDevCapCCWPtr ccw_dev G_GNUC_UNUSED)
+{
+ return -1;
+}
+
#endif /* __linux__ */
diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h
index 5484bc340f..c72b943ba3 100644
--- a/src/conf/node_device_conf.h
+++ b/src/conf/node_device_conf.h
@@ -101,6 +101,10 @@ typedef enum {
VIR_NODE_DEV_CAP_FLAG_PCI_MDEV = (1 << 3),
} virNodeDevPCICapFlags;
+typedef enum {
+ VIR_NODE_DEV_CAP_FLAG_CSS_MDEV = (1 << 0),
+} virNodeDevCCWCapFlags;
+
typedef enum {
/* Keep in sync with VIR_ENUM_IMPL in node_device_conf.c */
VIR_NODE_DEV_DRM_PRIMARY,
@@ -273,6 +277,9 @@ struct _virNodeDevCapCCW {
unsigned int cssid;
unsigned int ssid;
unsigned int devno;
+ unsigned int flags; /* enum virNodeDevCCWCapFlags */
+ virMediatedDeviceTypePtr *mdev_types;
+ size_t nmdev_types;
};
typedef struct _virNodeDevCapData virNodeDevCapData;
@@ -382,6 +389,10 @@ int
virNodeDeviceGetPCIDynamicCaps(const char *sysfsPath,
virNodeDevCapPCIDevPtr pci_dev);
+int
+virNodeDeviceGetCSSDynamicCaps(const char *sysfsPath,
+ virNodeDevCapCCWPtr ccw_dev);
+
int
virNodeDeviceUpdateCaps(virNodeDeviceDefPtr def);
diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c
index f240abf315..e5a1af8b3b 100644
--- a/src/conf/virnodedeviceobj.c
+++ b/src/conf/virnodedeviceobj.c
@@ -696,6 +696,12 @@ virNodeDeviceObjHasCap(const virNodeDeviceObj *obj,
return true;
break;
+ case VIR_NODE_DEV_CAP_CSS_DEV:
+ if (type == VIR_NODE_DEV_CAP_MDEV_TYPES &&
+ (cap->data.ccw_dev.flags & VIR_NODE_DEV_CAP_FLAG_CSS_MDEV))
+ return true;
+ break;
+
case VIR_NODE_DEV_CAP_SYSTEM:
case VIR_NODE_DEV_CAP_USB_DEV:
case VIR_NODE_DEV_CAP_USB_INTERFACE:
@@ -710,7 +716,6 @@ virNodeDeviceObjHasCap(const virNodeDeviceObj *obj,
case VIR_NODE_DEV_CAP_MDEV_TYPES:
case VIR_NODE_DEV_CAP_MDEV:
case VIR_NODE_DEV_CAP_CCW_DEV:
- case VIR_NODE_DEV_CAP_CSS_DEV:
case VIR_NODE_DEV_CAP_LAST:
break;
}
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 9029ea4fa2..d9c8df81a7 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -823,6 +823,7 @@ virNodeDeviceDefFree;
virNodeDeviceDefParseFile;
virNodeDeviceDefParseNode;
virNodeDeviceDefParseString;
+virNodeDeviceGetCSSDynamicCaps;
virNodeDeviceGetPCIDynamicCaps;
virNodeDeviceGetSCSIHostCaps;
virNodeDeviceGetSCSITargetCaps;
diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c
index 29a7eaa07c..062c0fc52e 100644
--- a/src/node_device/node_device_udev.c
+++ b/src/node_device/node_device_udev.c
@@ -1139,6 +1139,9 @@ udevProcessCSS(struct udev_device *device,
if (udevGenerateDeviceName(device, def, NULL) != 0)
return -1;
+ if (virNodeDeviceGetCSSDynamicCaps(def->sysfs_path,
&def->caps->data.ccw_dev) < 0)
+ return -1;
+
return 0;
}
diff --git a/tests/nodedevschemadata/css_0_0_fffe_mdev_types.xml
b/tests/nodedevschemadata/css_0_0_fffe_mdev_types.xml
new file mode 100644
index 0000000000..5058b6434e
--- /dev/null
+++ b/tests/nodedevschemadata/css_0_0_fffe_mdev_types.xml
@@ -0,0 +1,17 @@
+<device>
+ <name>css_0_0_fffe</name>
+ <path>/sys/devices/css0/0.0.fffe</path>
+ <parent>computer</parent>
+ <capability type='css'>
+ <cssid>0x0</cssid>
+ <ssid>0x0</ssid>
+ <devno>0xfffe</devno>
+ <capability type='mdev_types'>
+ <type id='vfio_ccw-io'>
+ <name>I/O subchannel (Non-QDIO)</name>
+ <deviceAPI>vfio-ccw</deviceAPI>
+ <availableInstances>1</availableInstances>
+ </type>
+ </capability>
+ </capability>
+</device>
diff --git a/tests/nodedevxml2xmltest.c b/tests/nodedevxml2xmltest.c
index 3cb23b1df4..a009ecb343 100644
--- a/tests/nodedevxml2xmltest.c
+++ b/tests/nodedevxml2xmltest.c
@@ -124,6 +124,7 @@ mymain(void)
DO_TEST("mdev_3627463d_b7f0_4fea_b468_f1da537d301b");
DO_TEST("ccw_0_0_ffff");
DO_TEST("css_0_0_ffff");
+ DO_TEST("css_0_0_fffe_mdev_types");
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
--
2.25.1