[RFC PATCH v2 25/32] iommu: Add helper APIs to fetch preserved device state
From: Samiullah Khawaja
Date: Tue Dec 02 2025 - 18:09:16 EST
Add two APIs to fetch state of the preserved devices. An API to iterate
through state of all preserved devices and another API to fetch the
state of a single preserved device. Note that these APIs only fetch the
preserved state from the previous kernel.
Signed-off-by: Samiullah Khawaja <skhawaja@xxxxxxxxxx>
---
drivers/iommu/liveupdate.c | 68 ++++++++++++++++++++++++++++++++++++++
include/linux/iommu-lu.h | 2 ++
2 files changed, 70 insertions(+)
diff --git a/drivers/iommu/liveupdate.c b/drivers/iommu/liveupdate.c
index e7ecf2e9aa4e..1ca97612c501 100644
--- a/drivers/iommu/liveupdate.c
+++ b/drivers/iommu/liveupdate.c
@@ -175,6 +175,74 @@ int iommu_liveupdate_unregister_flb(struct liveupdate_file_handler *handler)
}
EXPORT_SYMBOL(iommu_liveupdate_unregister_flb);
+int iommu_for_each_preserved_device(int (*fn)(struct device_ser *ser, void *arg), void *arg)
+{
+ struct iommu_lu_flb_obj *obj;
+ struct devices_ser *devices;
+ int ret, i, idx;
+
+ ret = liveupdate_flb_get_incoming(&iommu_flb, (void **)&obj);
+ if (ret)
+ return -ENOENT;
+
+ devices = __va(obj->ser->devices_phys);
+ for (i = 0, idx = 0; i < obj->ser->nr_devices; ++i, ++idx) {
+ if (idx >= MAX_DEVICE_SERS) {
+ devices = __va(devices->objs.next_objs);
+ idx = 0;
+ }
+
+ if (devices->devices[idx].obj.deleted)
+ continue;
+
+ ret = fn(&devices->devices[idx], arg);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(iommu_for_each_preserved_device);
+
+static inline bool device_ser_match(struct device_ser *match,
+ struct pci_dev *pdev)
+{
+ return match->devid == pci_dev_id(pdev) && match->pci_domain == pci_domain_nr(pdev->bus);
+}
+
+struct device_ser *iommu_get_device_preserved_data(struct device *dev)
+{
+ struct iommu_lu_flb_obj *obj;
+ struct devices_ser *devices;
+ int ret, i, idx;
+
+ if (!dev_is_pci(dev))
+ return NULL;
+
+ ret = liveupdate_flb_get_incoming(&iommu_flb, (void **)&obj);
+ if (ret)
+ return NULL;
+
+ devices = __va(obj->ser->devices_phys);
+ for (i = 0, idx = 0; i < obj->ser->nr_devices; ++i, ++idx) {
+ if (idx >= MAX_DEVICE_SERS) {
+ devices = __va(devices->objs.next_objs);
+ idx = 0;
+ }
+
+ if (devices->devices[idx].obj.deleted)
+ continue;
+
+ if (device_ser_match(&devices->devices[idx], to_pci_dev(dev))) {
+ devices->devices[idx].obj.incoming = true;
+ return &devices->devices[idx];
+ }
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(iommu_get_device_preserved_data);
+
struct iommu_ser *iommu_get_preserved_data(u64 token, enum iommu_lu_type type)
{
struct iommu_lu_flb_obj *obj;
diff --git a/include/linux/iommu-lu.h b/include/linux/iommu-lu.h
index ffce7043e997..d0226ec19b2f 100644
--- a/include/linux/iommu-lu.h
+++ b/include/linux/iommu-lu.h
@@ -78,6 +78,8 @@ static inline void *iommu_domain_restored_state(struct iommu_domain *domain)
}
#endif
+int iommu_for_each_preserved_device(int (*fn)(struct device_ser *ser, void *arg), void *arg);
+struct device_ser *iommu_get_device_preserved_data(struct device *dev);
struct iommu_ser *iommu_get_preserved_data(u64 token, enum iommu_lu_type type);
int iommu_domain_preserve(struct iommu_domain *domain, struct iommu_domain_ser **ser);
int iommu_domain_unpreserve(struct iommu_domain *domain);
--
2.52.0.158.g65b55ccf14-goog