hw/arm/smmuv3: Post-load stage 1 configurations to the host

In nested mode, we call the set_pasid_table() callback on each
STE update to pass the guest stage 1 configuration to the host
and apply it at physical level.

In the case of live migration, we need to manually call the
set_pasid_table() to load the guest stage 1 configurations to
the host. If this operation fails, the migration fails.

Signed-off-by: Kunkun Jiang <jiangkunkun@huawei.com>
This commit is contained in:
Chen Qun 2021-05-11 10:08:16 +08:00
parent 7644dd1549
commit b06e551676

View File

@ -0,0 +1,110 @@
From 06e43bc658aa80bb5f4da3e43c1c13d4cab6ebdd Mon Sep 17 00:00:00 2001
From: Kunkun Jiang <jiangkunkun@huawei.com>
Date: Tue, 11 May 2021 10:08:16 +0800
Subject: [PATCH] hw/arm/smmuv3: Post-load stage 1 configurations to the host
In nested mode, we call the set_pasid_table() callback on each
STE update to pass the guest stage 1 configuration to the host
and apply it at physical level.
In the case of live migration, we need to manually call the
set_pasid_table() to load the guest stage 1 configurations to
the host. If this operation fails, the migration fails.
Signed-off-by: Kunkun Jiang <jiangkunkun@huawei.com>
---
hw/arm/smmuv3.c | 33 ++++++++++++++++++++++++++++-----
1 file changed, 28 insertions(+), 5 deletions(-)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index c26fba118c..f383143db1 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -876,7 +876,7 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova,
}
}
-static void smmuv3_notify_config_change(SMMUState *bs, uint32_t sid)
+static int smmuv3_notify_config_change(SMMUState *bs, uint32_t sid)
{
#ifdef __linux__
IOMMUMemoryRegion *mr = smmu_iommu_mr(bs, sid);
@@ -884,9 +884,10 @@ static void smmuv3_notify_config_change(SMMUState *bs, uint32_t sid)
IOMMUConfig iommu_config = {};
SMMUTransCfg *cfg;
SMMUDevice *sdev;
+ int ret;
if (!mr) {
- return;
+ return 0;
}
sdev = container_of(mr, SMMUDevice, iommu);
@@ -895,13 +896,13 @@ static void smmuv3_notify_config_change(SMMUState *bs, uint32_t sid)
smmuv3_flush_config(sdev);
if (!pci_device_is_pasid_ops_set(sdev->bus, sdev->devfn)) {
- return;
+ return 0;
}
cfg = smmuv3_get_config(sdev, &event);
if (!cfg) {
- return;
+ return 0;
}
iommu_config.pasid_cfg.argsz = sizeof(struct iommu_pasid_table_config);
@@ -923,10 +924,13 @@ static void smmuv3_notify_config_change(SMMUState *bs, uint32_t sid)
iommu_config.pasid_cfg.config,
iommu_config.pasid_cfg.base_ptr);
- if (pci_device_set_pasid_table(sdev->bus, sdev->devfn, &iommu_config)) {
+ ret = pci_device_set_pasid_table(sdev->bus, sdev->devfn, &iommu_config);
+ if (ret) {
error_report("Failed to pass PASID table to host for iommu mr %s (%m)",
mr->parent_obj.name);
}
+
+ return ret;
#endif
}
@@ -1494,6 +1498,24 @@ static void smmu_realize(DeviceState *d, Error **errp)
smmu_init_irq(s, dev);
}
+static int smmuv3_post_load(void *opaque, int version_id)
+{
+ SMMUv3State *s3 = opaque;
+ SMMUState *s = &(s3->smmu_state);
+ SMMUDevice *sdev;
+ int ret = 0;
+
+ QLIST_FOREACH(sdev, &s->devices_with_notifiers, next) {
+ uint32_t sid = smmu_get_sid(sdev);
+ ret = smmuv3_notify_config_change(s, sid);
+ if (ret) {
+ break;
+ }
+ }
+
+ return ret;
+}
+
static const VMStateDescription vmstate_smmuv3_queue = {
.name = "smmuv3_queue",
.version_id = 1,
@@ -1512,6 +1534,7 @@ static const VMStateDescription vmstate_smmuv3 = {
.version_id = 1,
.minimum_version_id = 1,
.priority = MIG_PRI_IOMMU,
+ .post_load = smmuv3_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT32(features, SMMUv3State),
VMSTATE_UINT8(sid_size, SMMUv3State),
--
2.27.0