[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251202230303.1017519-28-skhawaja@google.com>
Date: Tue, 2 Dec 2025 23:02:57 +0000
From: Samiullah Khawaja <skhawaja@...gle.com>
To: David Woodhouse <dwmw2@...radead.org>, Lu Baolu <baolu.lu@...ux.intel.com>,
Joerg Roedel <joro@...tes.org>, Will Deacon <will@...nel.org>,
Pasha Tatashin <pasha.tatashin@...een.com>, Jason Gunthorpe <jgg@...pe.ca>, iommu@...ts.linux.dev
Cc: Samiullah Khawaja <skhawaja@...gle.com>, Robin Murphy <robin.murphy@....com>,
Pratyush Yadav <pratyush@...nel.org>, Kevin Tian <kevin.tian@...el.com>,
Alex Williamson <alex@...zbot.org>, linux-kernel@...r.kernel.org,
Saeed Mahameed <saeedm@...dia.com>, Adithya Jayachandran <ajayachandra@...dia.com>,
Parav Pandit <parav@...dia.com>, Leon Romanovsky <leonro@...dia.com>, William Tu <witu@...dia.com>,
Vipin Sharma <vipinsh@...gle.com>, dmatlack@...gle.com, YiFei Zhu <zhuyifei@...gle.com>,
Chris Li <chrisl@...nel.org>, praan@...gle.com
Subject: [RFC PATCH v2 27/32] iommu: restore preserved domain and reattach
During boot the preserved iommu domains need to be recreated and
reattached to the preserved devices. Once the device is reattached to
the preserved domain, the preserved_state set in the dev_iommu can be
unset.
Signed-off-by: Samiullah Khawaja <skhawaja@...gle.com>
---
drivers/iommu/iommu.c | 39 ++++++++++++++++++++++++++++++++++++--
drivers/iommu/liveupdate.c | 31 ++++++++++++++++++++++++++++++
include/linux/iommu-lu.h | 1 +
3 files changed, 69 insertions(+), 2 deletions(-)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 3feb440de40a..07453611cf8e 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -18,6 +18,7 @@
#include <linux/errno.h>
#include <linux/host1x_context_bus.h>
#include <linux/iommu.h>
+#include <linux/iommu-lu.h>
#include <linux/iommufd.h>
#include <linux/idr.h>
#include <linux/err.h>
@@ -489,6 +490,10 @@ static int iommu_init_device(struct device *dev)
}
dev->iommu->iommu_dev = iommu_dev;
+#ifdef CONFIG_LIVEUPDATE
+ dev->iommu->device_ser = iommu_get_device_preserved_data(dev);
+#endif
+
ret = iommu_device_link(iommu_dev, dev);
if (ret)
goto err_release;
@@ -2161,6 +2166,12 @@ static int __iommu_attach_device(struct iommu_domain *domain,
if (old)
atomic_dec(&old->attach_count);
+#ifdef CONFIG_LIVEUPDATE
+ /* The associated state can be unset once restored. */
+ if (dev_iommu_restored_state(dev))
+ WRITE_ONCE(dev->iommu->device_ser, NULL);
+#endif
+
dev->iommu->attach_deferred = 0;
trace_attach_device_to_domain(dev);
return 0;
@@ -3006,6 +3017,27 @@ int iommu_fwspec_add_ids(struct device *dev, const u32 *ids, int num_ids)
}
EXPORT_SYMBOL_GPL(iommu_fwspec_add_ids);
+static struct iommu_domain *__iommu_group_maybe_restore_domain(struct iommu_group *group)
+{
+ struct device_ser *device_ser;
+ struct iommu_domain *domain;
+ struct device *dev;
+
+ dev = iommu_group_first_dev(group);
+ if (!dev_is_pci(dev))
+ return NULL;
+
+ device_ser = dev_iommu_restored_state(dev);
+ if (!device_ser)
+ return NULL;
+
+ domain = iommu_restore_domain(dev, device_ser);
+ if (WARN_ON(IS_ERR(domain)))
+ return NULL;
+
+ return domain;
+}
+
/**
* iommu_setup_default_domain - Set the default_domain for the group
* @group: Group to change
@@ -3020,8 +3052,8 @@ static int iommu_setup_default_domain(struct iommu_group *group,
int target_type)
{
struct iommu_domain *old_dom = group->default_domain;
+ struct iommu_domain *dom, *restored_domain;
struct group_device *gdev;
- struct iommu_domain *dom;
bool direct_failed;
int req_type;
int ret;
@@ -3065,6 +3097,9 @@ static int iommu_setup_default_domain(struct iommu_group *group,
/* We must set default_domain early for __iommu_device_set_domain */
group->default_domain = dom;
if (!group->domain) {
+ restored_domain = __iommu_group_maybe_restore_domain(group);
+ if (!restored_domain)
+ restored_domain = dom;
/*
* Drivers are not allowed to fail the first domain attach.
* The only way to recover from this is to fail attaching the
@@ -3072,7 +3107,7 @@ static int iommu_setup_default_domain(struct iommu_group *group,
* in group->default_domain so it is freed after.
*/
ret = __iommu_group_set_domain_internal(
- group, dom, IOMMU_SET_DOMAIN_MUST_SUCCEED);
+ group, restored_domain, IOMMU_SET_DOMAIN_MUST_SUCCEED);
if (WARN_ON(ret))
goto out_free_old;
} else {
diff --git a/drivers/iommu/liveupdate.c b/drivers/iommu/liveupdate.c
index 1ca97612c501..735b7d9417c7 100644
--- a/drivers/iommu/liveupdate.c
+++ b/drivers/iommu/liveupdate.c
@@ -467,3 +467,34 @@ int iommu_unpreserve_device(struct iommu_domain *domain, struct device *dev)
{
return -EOPNOTSUPP;
}
+
+struct iommu_domain *iommu_restore_domain(struct device *dev, struct device_ser *ser)
+{
+ struct iommu_domain_ser *domain_ser;
+ struct iommu_lu_flb_obj *flb_obj;
+ struct iommu_domain *domain;
+ int ret;
+
+ domain_ser = __va(ser->domain_iommu_ser.domain_phys);
+
+ ret = liveupdate_flb_get_incoming(&iommu_flb, (void **)&flb_obj);
+ if (ret)
+ return ERR_PTR(ret);
+
+ guard(mutex)(&flb_obj->lock);
+ if (domain_ser->restored_domain)
+ return domain_ser->restored_domain;
+
+ domain_ser->obj.incoming = true;
+ domain = iommu_paging_domain_alloc(dev);
+ if (IS_ERR(domain))
+ return domain;
+
+ ret = domain->ops->restore(domain, domain_ser);
+ if (ret)
+ return ERR_PTR(ret);
+
+ domain->preserved_state = domain_ser;
+ domain_ser->restored_domain = domain;
+ return domain;
+}
diff --git a/include/linux/iommu-lu.h b/include/linux/iommu-lu.h
index d0226ec19b2f..1f90f4fb0328 100644
--- a/include/linux/iommu-lu.h
+++ b/include/linux/iommu-lu.h
@@ -78,6 +78,7 @@ static inline void *iommu_domain_restored_state(struct iommu_domain *domain)
}
#endif
+struct iommu_domain *iommu_restore_domain(struct device *dev, struct device_ser *ser);
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);
--
2.52.0.158.g65b55ccf14-goog
Powered by blists - more mailing lists