[PATCH v2 3/6] conf: Introduce @guestReset to hostdev's <source/>

Michal Privoznik mprivozn at redhat.com
Wed Jul 13 13:51:05 UTC 2022


Some USB devices have a buggy firmware that either crashes on
device reset, or make the device unusable in some other way.
Fortunately, QEMU offers a way to skip device reset either
completely, or if device is not initialized yet. Expose this
ability to users under:

    <hostdev mode='subsystem' type='usb'>
      <source guestReset='off'/>
    </hostdev>

Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
Reviewed-by: Ján Tomko <jtomko at redhat.com>
---
 docs/formatdomain.rst                          | 15 ++++++++++++++-
 src/conf/domain_conf.c                         | 18 ++++++++++++++++++
 src/conf/domain_conf.h                         | 13 +++++++++++++
 src/conf/schemas/domaincommon.rng              |  9 +++++++++
 tests/qemuxml2argvdata/hostdev-usb-address.xml |  2 +-
 .../hostdev-usb-address.x86_64-latest.xml      |  2 +-
 6 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index 89b627f4bd..3ea094e64c 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -4051,7 +4051,7 @@ for PCI (KVM only) and 1.0.6 for SCSI (KVM only)` :
    ...
    <devices>
      <hostdev mode='subsystem' type='usb'>
-       <source startupPolicy='optional'>
+       <source startupPolicy='optional' guestReset='off'>
          <vendor id='0x1234'/>
          <product id='0xbeef'/>
        </source>
@@ -4231,6 +4231,19 @@ or:
       optional  drop if missing at any start attempt
       ========= =====================================================================
 
+      :since:`Since 8.6.0`, the ``source`` element can contain ``guestReset``
+      attribute with the following value:
+
+      ============= =====================================================
+      off           all guest initiated device reset requests are ignored
+      uninitialized device request is ignored if device is initialized,
+                    otherwise reset is performed
+      on            device is reset on every guest initiated request
+      ============= =====================================================
+
+      This attribute can be helpful when assigning an USB device with a
+      firmware that crashes on reset.
+
    ``pci``
       PCI devices can only be described by their ``address``.
       :since:`Since 6.8.0 (Xen only)` , the ``source`` element of a PCI device
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index e80616fe7b..4c7a5a044c 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1042,6 +1042,14 @@ VIR_ENUM_IMPL(virDomainHostdevSubsysSCSIProtocol,
               "iscsi",
 );
 
+VIR_ENUM_IMPL(virDomainHostdevSubsysUSBGuestReset,
+              VIR_DOMAIN_HOSTDEV_USB_GUEST_RESET_LAST,
+              "default",
+              "off",
+              "uninitialized",
+              "on",
+);
+
 VIR_ENUM_IMPL(virDomainHostdevSubsysSCSIHostProtocol,
               VIR_DOMAIN_HOSTDEV_SUBSYS_SCSI_HOST_PROTOCOL_TYPE_LAST,
               "none",
@@ -5489,6 +5497,11 @@ virDomainHostdevSubsysUSBDefParseXML(xmlNodePtr node,
         return -1;
     virTristateBoolToBool(autoAddress, &usbsrc->autoAddress);
 
+    if (virXMLPropEnum(node, "guestReset",
+                       virDomainHostdevSubsysUSBGuestResetTypeFromString,
+                       VIR_XML_PROP_NONZERO, &usbsrc->guestReset) < 0)
+        return -1;
+
     /* Product can validly be 0, so we need some extra help to determine
      * if it is uninitialized */
     vendorNode = virXPathNode("./vendor", ctxt);
@@ -22989,6 +23002,11 @@ virDomainHostdevDefFormatSubsysUSB(virBuffer *buf,
     if (def->missing && !(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE))
         virBufferAddLit(&sourceAttrBuf, " missing='yes'");
 
+    if (usbsrc->guestReset) {
+        virBufferAsprintf(&sourceAttrBuf, " guestReset='%s'",
+                          virDomainHostdevSubsysUSBGuestResetTypeToString(usbsrc->guestReset));
+    }
+
     if (usbsrc->vendor) {
         virBufferAsprintf(&sourceChildBuf, "<vendor id='0x%.4x'/>\n", usbsrc->vendor);
         virBufferAsprintf(&sourceChildBuf, "<product id='0x%.4x'/>\n", usbsrc->product);
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index c56b84683c..90de50c12f 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -233,6 +233,17 @@ typedef enum {
 
 VIR_ENUM_DECL(virDomainHostdevSubsysSCSIProtocol);
 
+typedef enum {
+    VIR_DOMAIN_HOSTDEV_USB_GUEST_RESET_DEFAULT = 0,
+    VIR_DOMAIN_HOSTDEV_USB_GUEST_RESET_OFF,           /* reset forbidden */
+    VIR_DOMAIN_HOSTDEV_USB_GUEST_RESET_UNINITIALIZED, /* reset iff uninitialized */
+    VIR_DOMAIN_HOSTDEV_USB_GUEST_RESET_ON,            /* reset allowed */
+
+    VIR_DOMAIN_HOSTDEV_USB_GUEST_RESET_LAST
+} virDomainHostdevSubsysUSBGuestReset;
+
+VIR_ENUM_DECL(virDomainHostdevSubsysUSBGuestReset);
+
 struct _virDomainHostdevSubsysUSB {
     bool autoAddress; /* bus/device were filled automatically based
                          on vendor/product */
@@ -241,6 +252,8 @@ struct _virDomainHostdevSubsysUSB {
 
     unsigned vendor;
     unsigned product;
+
+    virDomainHostdevSubsysUSBGuestReset guestReset;
 };
 
 struct _virDomainHostdevSubsysPCI {
diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng
index da2fb0d5cb..faa2561665 100644
--- a/src/conf/schemas/domaincommon.rng
+++ b/src/conf/schemas/domaincommon.rng
@@ -5936,6 +5936,15 @@
       <optional>
         <ref name="startupPolicy"/>
       </optional>
+      <optional>
+        <attribute name="guestReset">
+          <choice>
+            <value>off</value>
+            <value>uninitialized</value>
+            <value>on</value>
+          </choice>
+        </attribute>
+      </optional>
       <choice>
         <group>
           <ref name="usbproduct"/>
diff --git a/tests/qemuxml2argvdata/hostdev-usb-address.xml b/tests/qemuxml2argvdata/hostdev-usb-address.xml
index 03c802a532..50c02f9b0e 100644
--- a/tests/qemuxml2argvdata/hostdev-usb-address.xml
+++ b/tests/qemuxml2argvdata/hostdev-usb-address.xml
@@ -26,7 +26,7 @@
     <input type='mouse' bus='ps2'/>
     <input type='keyboard' bus='ps2'/>
     <hostdev mode='subsystem' type='usb' managed='no'>
-      <source>
+      <source guestReset='uninitialized'>
         <address bus='14' device='6'/>
       </source>
     </hostdev>
diff --git a/tests/qemuxml2xmloutdata/hostdev-usb-address.x86_64-latest.xml b/tests/qemuxml2xmloutdata/hostdev-usb-address.x86_64-latest.xml
index e5e3620971..2e927252a8 100644
--- a/tests/qemuxml2xmloutdata/hostdev-usb-address.x86_64-latest.xml
+++ b/tests/qemuxml2xmloutdata/hostdev-usb-address.x86_64-latest.xml
@@ -34,7 +34,7 @@
     <input type='keyboard' bus='ps2'/>
     <audio id='1' type='none'/>
     <hostdev mode='subsystem' type='usb' managed='no'>
-      <source>
+      <source guestReset='uninitialized'>
         <address bus='14' device='6'/>
       </source>
     </hostdev>
-- 
2.35.1



More information about the libvir-list mailing list