Add detection of mdev_types capability to channel subsystem devices. Signed-off-by: Boris Fiuczynski <fiuczy@xxxxxxxxxxxxx> Reviewed-by: Bjoern Walk <bwalk@xxxxxxxxxxxxx> --- 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