node_device: detecting mdev_types capability on CSS devices

Add detection of mdev_types capability to channel subsystem devices.

Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Bjoern Walk <bwalk@linux.ibm.com>
Reviewed-by: Erik Skultety <eskultet@redhat.com>
This commit is contained in:
Boris Fiuczynski 2020-11-11 13:45:22 +01:00 committed by Erik Skultety
parent 9c7ac83bd9
commit 0c841f9b70
10 changed files with 153 additions and 8 deletions

View File

@ -139,7 +139,7 @@
<h3><a id="MDEVCap">MDEV capability</a></h3> <h3><a id="MDEVCap">MDEV capability</a></h3>
<p> <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 capability <code>mdev_types</code> which enumerates all supported mdev
types on the physical device, along with the type attributes available types on the physical device, along with the type attributes available
through sysfs. A detailed description of the XML format for the through sysfs. A detailed description of the XML format for the

View File

@ -405,6 +405,21 @@
<dd>The subchannel-set identifier.</dd> <dd>The subchannel-set identifier.</dd>
<dt><code>devno</code></dt> <dt><code>devno</code></dt>
<dd>The device number.</dd> <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="MDEVTypesCapCSS">mdev_types</a></code></dt>
<dd>
<span class="since">Since 6.10.0</span>
This device is capable of creating mediated devices.
The sub-elements are summarized in
<a href="#MDevTypesCap">mdev_types capability</a>.
</dd>
</dl>
</dd>
</dl> </dl>
</dd> </dd>
<dt><code>vdpa</code></dt> <dt><code>vdpa</code></dt>
@ -423,10 +438,10 @@
<h3><a id="MDEVTypesCap">mdev_types capability</a></h3> <h3><a id="MDEVTypesCap">mdev_types capability</a></h3>
<p> <p>
<a href="#MDEVTypesCapPCI">PCI</a> devices can be capable of <a href="#MDEVTypesCapPCI">PCI</a> and <a href="#MDEVTypesCapCSS">CSS</a>
creating mediated devices. If they indeed are capable, devices can be capable of creating mediated devices.
then the parent <code>capability</code> element for If they indeed are capable, then the parent <code>capability</code>
<code>mdev_types</code> type will contain a list of element for <code>mdev_types</code> type will contain a list of
<code>type</code> elements, which list all mdev types supported <code>type</code> elements, which list all mdev types supported
on the physical device. <span class="since">Since 3.4.0</span> on the physical device. <span class="since">Since 3.4.0</span>
Each <code>type</code> element has a single <code>id</code> Each <code>type</code> element has a single <code>id</code>

View File

@ -654,6 +654,9 @@
<element name="devno"> <element name="devno">
<ref name="ccwDevnoRange"/> <ref name="ccwDevnoRange"/>
</element> </element>
<optional>
<ref name="mdev_types"/>
</optional>
</define> </define>
<define name="capvdpa"> <define name="capvdpa">
@ -702,6 +705,7 @@
<element name="deviceAPI"> <element name="deviceAPI">
<choice> <choice>
<value>vfio-pci</value> <value>vfio-pci</value>
<value>vfio-ccw</value>
</choice> </choice>
</element> </element>
<element name="availableInstances"> <element name="availableInstances">

View File

@ -552,6 +552,10 @@ virNodeDeviceCapCCWDefFormat(virBufferPtr buf,
data->ccw_dev.ssid); data->ccw_dev.ssid);
virBufferAsprintf(buf, "<devno>0x%04x</devno>\n", virBufferAsprintf(buf, "<devno>0x%04x</devno>\n",
data->ccw_dev.devno); 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);
} }
@ -843,6 +847,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 static int
virNodeDevCapCCWParseXML(xmlXPathContextPtr ctxt, virNodeDevCapCCWParseXML(xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def, virNodeDeviceDefPtr def,
@ -850,6 +881,9 @@ virNodeDevCapCCWParseXML(xmlXPathContextPtr ctxt,
virNodeDevCapCCWPtr ccw_dev) virNodeDevCapCCWPtr ccw_dev)
{ {
VIR_XPATH_NODE_AUTORESTORE(ctxt) 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 *cssid = NULL;
g_autofree char *ssid = NULL; g_autofree char *ssid = NULL;
g_autofree char *devno = NULL; g_autofree char *devno = NULL;
@ -895,6 +929,14 @@ virNodeDevCapCCWParseXML(xmlXPathContextPtr ctxt,
return -1; 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; return 0;
} }
@ -2253,12 +2295,16 @@ virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps)
virMediatedDeviceAttrFree(data->mdev.attributes[i]); virMediatedDeviceAttrFree(data->mdev.attributes[i]);
VIR_FREE(data->mdev.attributes); VIR_FREE(data->mdev.attributes);
break; 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_MDEV_TYPES:
case VIR_NODE_DEV_CAP_DRM: case VIR_NODE_DEV_CAP_DRM:
case VIR_NODE_DEV_CAP_FC_HOST: case VIR_NODE_DEV_CAP_FC_HOST:
case VIR_NODE_DEV_CAP_VPORTS: case VIR_NODE_DEV_CAP_VPORTS:
case VIR_NODE_DEV_CAP_CCW_DEV: case VIR_NODE_DEV_CAP_CCW_DEV:
case VIR_NODE_DEV_CAP_CSS_DEV:
case VIR_NODE_DEV_CAP_VDPA: case VIR_NODE_DEV_CAP_VDPA:
case VIR_NODE_DEV_CAP_LAST: case VIR_NODE_DEV_CAP_LAST:
/* This case is here to shutup the compiler */ /* This case is here to shutup the compiler */
@ -2297,6 +2343,11 @@ virNodeDeviceUpdateCaps(virNodeDeviceDefPtr def)
&cap->data.pci_dev) < 0) &cap->data.pci_dev) < 0)
return -1; return -1;
break; 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 /* all types that (supposedly) don't require any updates
* relative to what's in the cache. * relative to what's in the cache.
@ -2313,7 +2364,6 @@ virNodeDeviceUpdateCaps(virNodeDeviceDefPtr def)
case VIR_NODE_DEV_CAP_MDEV_TYPES: case VIR_NODE_DEV_CAP_MDEV_TYPES:
case VIR_NODE_DEV_CAP_MDEV: case VIR_NODE_DEV_CAP_MDEV:
case VIR_NODE_DEV_CAP_CCW_DEV: case VIR_NODE_DEV_CAP_CCW_DEV:
case VIR_NODE_DEV_CAP_CSS_DEV:
case VIR_NODE_DEV_CAP_VDPA: case VIR_NODE_DEV_CAP_VDPA:
case VIR_NODE_DEV_CAP_LAST: case VIR_NODE_DEV_CAP_LAST:
break; break;
@ -2388,6 +2438,15 @@ virNodeDeviceCapsListExport(virNodeDeviceDefPtr def,
ncaps++; 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 #undef MAYBE_ADD_CAP
@ -2653,6 +2712,28 @@ virNodeDeviceGetPCIDynamicCaps(const char *sysfsPath,
return 0; 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 #else
int int
@ -2675,4 +2756,11 @@ int virNodeDeviceGetSCSITargetCaps(const char *sysfsPath G_GNUC_UNUSED,
return -1; return -1;
} }
int
virNodeDeviceGetCSSDynamicCaps(const char *sysfsPath G_GNUC_UNUSED,
virNodeDevCapCCWPtr ccw_dev G_GNUC_UNUSED)
{
return -1;
}
#endif /* __linux__ */ #endif /* __linux__ */

View File

@ -102,6 +102,10 @@ typedef enum {
VIR_NODE_DEV_CAP_FLAG_PCI_MDEV = (1 << 3), VIR_NODE_DEV_CAP_FLAG_PCI_MDEV = (1 << 3),
} virNodeDevPCICapFlags; } virNodeDevPCICapFlags;
typedef enum {
VIR_NODE_DEV_CAP_FLAG_CSS_MDEV = (1 << 0),
} virNodeDevCCWCapFlags;
typedef enum { typedef enum {
/* Keep in sync with VIR_ENUM_IMPL in node_device_conf.c */ /* Keep in sync with VIR_ENUM_IMPL in node_device_conf.c */
VIR_NODE_DEV_DRM_PRIMARY, VIR_NODE_DEV_DRM_PRIMARY,
@ -274,6 +278,9 @@ struct _virNodeDevCapCCW {
unsigned int cssid; unsigned int cssid;
unsigned int ssid; unsigned int ssid;
unsigned int devno; unsigned int devno;
unsigned int flags; /* enum virNodeDevCCWCapFlags */
virMediatedDeviceTypePtr *mdev_types;
size_t nmdev_types;
}; };
typedef struct _virNodeDevCapVDPA virNodeDevCapVDPA; typedef struct _virNodeDevCapVDPA virNodeDevCapVDPA;
@ -391,6 +398,10 @@ int
virNodeDeviceGetPCIDynamicCaps(const char *sysfsPath, virNodeDeviceGetPCIDynamicCaps(const char *sysfsPath,
virNodeDevCapPCIDevPtr pci_dev); virNodeDevCapPCIDevPtr pci_dev);
int
virNodeDeviceGetCSSDynamicCaps(const char *sysfsPath,
virNodeDevCapCCWPtr ccw_dev);
int int
virNodeDeviceUpdateCaps(virNodeDeviceDefPtr def); virNodeDeviceUpdateCaps(virNodeDeviceDefPtr def);

View File

@ -696,6 +696,12 @@ virNodeDeviceObjHasCap(const virNodeDeviceObj *obj,
return true; return true;
break; 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_SYSTEM:
case VIR_NODE_DEV_CAP_USB_DEV: case VIR_NODE_DEV_CAP_USB_DEV:
case VIR_NODE_DEV_CAP_USB_INTERFACE: 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_TYPES:
case VIR_NODE_DEV_CAP_MDEV: case VIR_NODE_DEV_CAP_MDEV:
case VIR_NODE_DEV_CAP_CCW_DEV: case VIR_NODE_DEV_CAP_CCW_DEV:
case VIR_NODE_DEV_CAP_CSS_DEV:
case VIR_NODE_DEV_CAP_VDPA: case VIR_NODE_DEV_CAP_VDPA:
case VIR_NODE_DEV_CAP_LAST: case VIR_NODE_DEV_CAP_LAST:
break; break;

View File

@ -824,6 +824,7 @@ virNodeDeviceDefFree;
virNodeDeviceDefParseFile; virNodeDeviceDefParseFile;
virNodeDeviceDefParseNode; virNodeDeviceDefParseNode;
virNodeDeviceDefParseString; virNodeDeviceDefParseString;
virNodeDeviceGetCSSDynamicCaps;
virNodeDeviceGetPCIDynamicCaps; virNodeDeviceGetPCIDynamicCaps;
virNodeDeviceGetSCSIHostCaps; virNodeDeviceGetSCSIHostCaps;
virNodeDeviceGetSCSITargetCaps; virNodeDeviceGetSCSITargetCaps;

View File

@ -1139,6 +1139,9 @@ udevProcessCSS(struct udev_device *device,
if (udevGenerateDeviceName(device, def, NULL) != 0) if (udevGenerateDeviceName(device, def, NULL) != 0)
return -1; return -1;
if (virNodeDeviceGetCSSDynamicCaps(def->sysfs_path, &def->caps->data.ccw_dev) < 0)
return -1;
return 0; return 0;
} }

View File

@ -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>

View File

@ -124,6 +124,7 @@ mymain(void)
DO_TEST("mdev_3627463d_b7f0_4fea_b468_f1da537d301b"); DO_TEST("mdev_3627463d_b7f0_4fea_b468_f1da537d301b");
DO_TEST("ccw_0_0_ffff"); DO_TEST("ccw_0_0_ffff");
DO_TEST("css_0_0_ffff"); DO_TEST("css_0_0_ffff");
DO_TEST("css_0_0_fffe_mdev_types");
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
} }