devices: vfio_pci: identify intel-lpss devices via cmdline

intel-lpss devices need special handling during BAR accesses due to PV
operations in the guest (when compiled with the direct feature). Allow
identification of such devices via a new vfio parameter, intel-lpss, so
that it can tag them for PV handling.

BUG=b:232887201
TEST=crosvm accepts the intel-lpss parameter in --vfio

Change-Id: I6ce710b112e7d286e43014d7dc55ec4e68939731
Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/3764936
Tested-by: Peter Fang <peter.fang@intel.corp-partner.google.com>
Commit-Queue: Tomasz Nowicki <tnowicki@google.com>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
diff --git a/devices/src/pci/vfio_pci.rs b/devices/src/pci/vfio_pci.rs
index 852eb31..47b68c2 100644
--- a/devices/src/pci/vfio_pci.rs
+++ b/devices/src/pci/vfio_pci.rs
@@ -587,6 +587,9 @@
     header_type_reg: Option<u32>,
     // PCI Express Extended Capabilities
     ext_caps: Vec<ExtCap>,
+    #[cfg(feature = "direct")]
+    #[allow(dead_code)]
+    is_intel_lpss: bool,
     mapped_mmio_bars: BTreeMap<PciBarIndex, (u64, Vec<MemSlot>)>,
 }
 
@@ -602,6 +605,7 @@
         vfio_device_socket_msix: Tube,
         vfio_device_socket_mem: Tube,
         vfio_device_socket_vm: Option<Tube>,
+        #[cfg(feature = "direct")] is_intel_lpss: bool,
     ) -> Result<Self, PciDeviceError> {
         let preferred_address = if let Some(bus_num) = hotplug_bus_number {
             debug!("hotplug bus {}", bus_num);
@@ -766,6 +770,8 @@
             #[cfg(feature = "direct")]
             header_type_reg,
             ext_caps,
+            #[cfg(feature = "direct")]
+            is_intel_lpss,
             mapped_mmio_bars: BTreeMap::new(),
         })
     }
diff --git a/src/crosvm/sys/unix.rs b/src/crosvm/sys/unix.rs
index c22eec5..f2909aa 100644
--- a/src/crosvm/sys/unix.rs
+++ b/src/crosvm/sys/unix.rs
@@ -687,6 +687,8 @@
                 vfio_dev.guest_address(),
                 Some(&mut coiommu_attached_endpoints),
                 vfio_dev.iommu_dev_type(),
+                #[cfg(feature = "direct")]
+                vfio_dev.is_intel_lpss(),
             )?;
 
             *iova_max_addr = Some(max(
@@ -1915,6 +1917,8 @@
                 } else {
                     IommuDevType::NoIommu
                 },
+                #[cfg(feature = "direct")]
+                false,
             )?;
             let pci_address = Arch::register_pci_device(
                 linux,
diff --git a/src/crosvm/sys/unix/config.rs b/src/crosvm/sys/unix/config.rs
index f30af7d..0a0cc22 100644
--- a/src/crosvm/sys/unix/config.rs
+++ b/src/crosvm/sys/unix/config.rs
@@ -280,6 +280,17 @@
                     ))
                 }
             }
+            #[cfg(feature = "direct")]
+            "intel-lpss" => {
+                if value.parse::<bool>().is_ok() {
+                    Ok(())
+                } else {
+                    Err(invalid_value_err(
+                        format!("{}={}", kind, value),
+                        "option must be `intel-lpss=true|false`",
+                    ))
+                }
+            }
             _ => Err(invalid_value_err(
                 format!("{}={}", kind, value),
                 "option must be `guest-address=<val>` and/or `iommu=<val>`",
@@ -305,6 +316,14 @@
         }
         IommuDevType::NoIommu
     }
+
+    #[cfg(feature = "direct")]
+    pub fn is_intel_lpss(&self) -> bool {
+        if let Some(lpss) = self.params.get("intel-lpss") {
+            return lpss.parse::<bool>().unwrap_or(false);
+        }
+        false
+    }
 }
 
 #[cfg(test)]
diff --git a/src/crosvm/sys/unix/device_helpers.rs b/src/crosvm/sys/unix/device_helpers.rs
index 58f9c67..c1f403f 100644
--- a/src/crosvm/sys/unix/device_helpers.rs
+++ b/src/crosvm/sys/unix/device_helpers.rs
@@ -1433,6 +1433,7 @@
     guest_address: Option<PciAddress>,
     coiommu_endpoints: Option<&mut Vec<u16>>,
     iommu_dev: IommuDevType,
+    #[cfg(feature = "direct")] is_intel_lpss: bool,
 ) -> DeviceResult<(Box<VfioPciDevice>, Option<Minijail>, Option<VfioWrapper>)> {
     let vfio_container = VfioCommonSetup::vfio_get_container(iommu_dev, Some(vfio_path))
         .context("failed to get vfio container")?;
@@ -1476,6 +1477,8 @@
         vfio_device_tube_msix,
         vfio_device_tube_mem,
         vfio_device_tube_vm,
+        #[cfg(feature = "direct")]
+        is_intel_lpss,
     )?);
     // early reservation for pass-through PCI devices.
     let endpoint_addr = vfio_pci_device