Re: [RFC PATCH v2 16/32] iommu: Add API to preserve/unpreserve a device

From: Baolu Lu

Date: Thu Dec 04 2025 - 00:51:26 EST


On 12/3/25 07:02, Samiullah Khawaja wrote:
iommu_preserve_device/iommu_unpreserve_device can be used to
preserve/unpreserve a device for liveupdate. During device preservation
the state of the associated IOMMU is also preserved. The device can only
be preseved if the attached iommu domain is preserved and the assocated
iommu supports preservation.

If the device supports PASID, multiple domains might be attached to it.

...


Signed-off-by: Samiullah Khawaja<skhawaja@xxxxxxxxxx>
---
drivers/iommu/iommu.c | 3 +
drivers/iommu/liveupdate.c | 115 +++++++++++++++++++++++++++++++++++++
include/linux/iommu-lu.h | 2 +
include/linux/iommu.h | 18 ++++++
4 files changed, 138 insertions(+)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index a70898d11959..3feb440de40a 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -382,6 +382,9 @@ static struct dev_iommu *dev_iommu_get(struct device *dev)
mutex_init(&param->lock);
dev->iommu = param;
+#ifdef CONFIG_LIVEUPDATE
+ dev->iommu->device_ser = NULL;
+#endif
return param;
}
diff --git a/drivers/iommu/liveupdate.c b/drivers/iommu/liveupdate.c
index 25a943e5e1e3..5780761a7024 100644
--- a/drivers/iommu/liveupdate.c
+++ b/drivers/iommu/liveupdate.c
@@ -11,6 +11,7 @@
#include <linux/liveupdate.h>
#include <linux/iommu-lu.h>
#include <linux/iommu.h>
+#include <linux/pci.h>
#include <linux/errno.h>
static void iommu_liveupdate_free_objs(u64 next, bool incoming)
@@ -209,3 +210,117 @@ int iommu_domain_unpreserve(struct iommu_domain *domain)
return 0;
}
EXPORT_SYMBOL_GPL(iommu_domain_unpreserve);
+
+static int iommu_preserve_locked(struct iommu_device *iommu)
+{
+ struct iommu_lu_flb_obj *flb_obj;
+ struct iommu_ser *iommu_ser;
+ int idx, ret;
+
+ if (!iommu->ops->preserve)
+ return -EOPNOTSUPP;
+
+ if (iommu->outgoing_preserved_state) {
+ iommu->outgoing_preserved_state->obj.ref_count++;
+ return 0;
+ }
+
+ ret = liveupdate_flb_get_outgoing(&iommu_flb, (void **)&flb_obj);
+ if (ret)
+ return ret;
+
+ idx = reserve_obj_ser((struct iommu_objs_ser **)&flb_obj->iommus, MAX_IOMMU_SERS);
+ if (idx < 0)
+ return idx;
+
+ iommu_ser = &flb_obj->iommus->iommus[idx];
+ idx = flb_obj->ser->nr_iommus++;
+ iommu_ser->obj.idx = idx;
+ iommu_ser->obj.ref_count = 1;
+
+ ret = iommu->ops->preserve(iommu, iommu_ser);
+ if (ret)
+ iommu_ser->obj.deleted = true;
+
+ iommu->outgoing_preserved_state = iommu_ser;
+ return ret;
+}
+
+static void iommu_unpreserve_locked(struct iommu_device *iommu)
+{
+ struct iommu_ser *iommu_ser = iommu->outgoing_preserved_state;
+
+ iommu_ser->obj.ref_count--;
+ if (iommu_ser->obj.ref_count)
+ return;
+
+ iommu->outgoing_preserved_state = NULL;
+ iommu->ops->unpreserve(iommu, iommu_ser);
+ iommu_ser->obj.deleted = true;
+}
+
+int iommu_preserve_device(struct iommu_domain *domain, struct device *dev)
+{

... but this helper only cares about a single domain.

+ struct iommu_lu_flb_obj *flb_obj;
+ struct device_ser *device_ser;
+ struct dev_iommu *iommu;
+ struct pci_dev *pdev;
+ int ret, idx;

Thanks,
baolu