]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
conf: Introduce @guestReset to hostdev's <source/>
authorMichal Privoznik <mprivozn@redhat.com>
Thu, 7 Jul 2022 11:11:06 +0000 (13:11 +0200)
committerMichal Privoznik <mprivozn@redhat.com>
Wed, 13 Jul 2022 14:00:50 +0000 (16:00 +0200)
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@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
docs/formatdomain.rst
src/conf/domain_conf.c
src/conf/domain_conf.h
src/conf/schemas/domaincommon.rng
tests/qemuxml2argvdata/hostdev-usb-address.xml
tests/qemuxml2xmloutdata/hostdev-usb-address.x86_64-latest.xml

index 89b627f4bdcc5bf4dbe41e19e582e4ce1f4f2a88..3ea094e64c27eb3470c4dc2b1ee24afd708b2feb 100644 (file)
@@ -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
index e80616fe7b499f0b12e9789ddec21ffcea2179da..4c7a5a044c4cfe207c965ea8b34c780c50267400 100644 (file)
@@ -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);
index c56b84683cc2525042e191c9165efa72ab887fea..90de50c12fe349db392d69e814d71e3e49fde123 100644 (file)
@@ -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 {
index da2fb0d5cb9c61be5b287e07df780bf1db8a94b7..faa256166503667fa9d0dd27428e3ce44f78d822 100644 (file)
       <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"/>
index 03c802a532b6ff379a9adf51f3c92561d11f4292..50c02f9b0edde5e43999154a4cbff89ac796e42e 100644 (file)
@@ -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>
index e5e36209719b310e958dea25bb2a2a23dcf51785..2e927252a842d872683f12c4323cb70b0f6728d9 100644 (file)
@@ -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>