From 7c6a3358e5144aca709f485c2cab06c1a306b06b Mon Sep 17 00:00:00 2001 From: Chen Qun Date: Thu, 9 Aug 2018 21:04:19 +0200 Subject: [PATCH] hw/arm/smmuv3: Pass stage 1 configurations to the host In case PASID PciOps are set for the device we call the set_pasid_table() callback on each STE update. This allows to pass the guest stage 1 configuration to the host and apply it at physical level. Signed-off-by: Eric Auger Signed-off-by: Kunkun Jiang Signed-off-by: imxcc (cherry picked from commit 6b84c577acac4c464c47edffb669b1b48641cbcc) --- ...ss-stage-1-configurations-to-the-hos.patch | 161 ++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 hw-arm-smmuv3-Pass-stage-1-configurations-to-the-hos.patch diff --git a/hw-arm-smmuv3-Pass-stage-1-configurations-to-the-hos.patch b/hw-arm-smmuv3-Pass-stage-1-configurations-to-the-hos.patch new file mode 100644 index 0000000..012c5d0 --- /dev/null +++ b/hw-arm-smmuv3-Pass-stage-1-configurations-to-the-hos.patch @@ -0,0 +1,161 @@ +From 2e5929ec2a35a7a227dc7ba70a557a84993a366d Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Thu, 9 Aug 2018 21:04:19 +0200 +Subject: [PATCH] hw/arm/smmuv3: Pass stage 1 configurations to the host + +In case PASID PciOps are set for the device we call +the set_pasid_table() callback on each STE update. + +This allows to pass the guest stage 1 configuration +to the host and apply it at physical level. + +Signed-off-by: Eric Auger +Signed-off-by: Kunkun Jiang +--- + hw/arm/smmu-internal.h | 1 + + hw/arm/smmuv3.c | 71 ++++++++++++++++++++++++++++++++++++------ + hw/arm/trace-events | 1 + + 3 files changed, 64 insertions(+), 9 deletions(-) + +diff --git a/hw/arm/smmu-internal.h b/hw/arm/smmu-internal.h +index 2d75b31953..5ef8c598c6 100644 +--- a/hw/arm/smmu-internal.h ++++ b/hw/arm/smmu-internal.h +@@ -105,6 +105,7 @@ typedef struct SMMUIOTLBPageInvInfo { + } SMMUIOTLBPageInvInfo; + + typedef struct SMMUSIDRange { ++ SMMUState *state; + uint32_t start; + uint32_t end; + } SMMUSIDRange; +diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c +index ad816e850c..58139f707d 100644 +--- a/hw/arm/smmuv3.c ++++ b/hw/arm/smmuv3.c +@@ -16,6 +16,10 @@ + * with this program; if not, see . + */ + ++#ifdef __linux__ ++#include "linux/iommu.h" ++#endif ++ + #include "qemu/osdep.h" + #include "qemu/bitops.h" + #include "hw/irq.h" +@@ -928,6 +932,61 @@ static void smmuv3_s1_range_inval(SMMUState *s, Cmd *cmd) + } + } + ++static void smmuv3_notify_config_change(SMMUState *bs, uint32_t sid) ++{ ++#ifdef __linux__ ++ IOMMUMemoryRegion *mr = smmu_iommu_mr(bs, sid); ++ SMMUEventInfo event = {.type = SMMU_EVT_NONE, .sid = sid, ++ .inval_ste_allowed = true}; ++ IOMMUConfig iommu_config = {}; ++ SMMUTransCfg *cfg; ++ SMMUDevice *sdev; ++ ++ if (!mr) { ++ return; ++ } ++ ++ sdev = container_of(mr, SMMUDevice, iommu); ++ ++ /* flush QEMU config cache */ ++ smmuv3_flush_config(sdev); ++ ++ if (!pci_device_is_pasid_ops_set(sdev->bus, sdev->devfn)) { ++ return; ++ } ++ ++ cfg = smmuv3_get_config(sdev, &event); ++ ++ if (!cfg) { ++ return; ++ } ++ ++ iommu_config.pasid_cfg.argsz = sizeof(struct iommu_pasid_table_config); ++ iommu_config.pasid_cfg.version = PASID_TABLE_CFG_VERSION_1; ++ iommu_config.pasid_cfg.format = IOMMU_PASID_FORMAT_SMMUV3; ++ iommu_config.pasid_cfg.base_ptr = cfg->s1ctxptr; ++ iommu_config.pasid_cfg.pasid_bits = 0; ++ iommu_config.pasid_cfg.vendor_data.smmuv3.version = PASID_TABLE_SMMUV3_CFG_VERSION_1; ++ ++ if (cfg->disabled || cfg->bypassed) { ++ iommu_config.pasid_cfg.config = IOMMU_PASID_CONFIG_BYPASS; ++ } else if (cfg->aborted) { ++ iommu_config.pasid_cfg.config = IOMMU_PASID_CONFIG_ABORT; ++ } else { ++ iommu_config.pasid_cfg.config = IOMMU_PASID_CONFIG_TRANSLATE; ++ } ++ ++ trace_smmuv3_notify_config_change(mr->parent_obj.name, ++ iommu_config.pasid_cfg.config, ++ iommu_config.pasid_cfg.base_ptr); ++ ++ if (pci_device_set_pasid_table(sdev->bus, sdev->devfn, &iommu_config)) { ++ error_report("Failed to pass PASID table to host for iommu mr %s (%m)", ++ mr->parent_obj.name); ++ } ++#endif ++} ++ + static gboolean + smmuv3_invalidate_ste(gpointer key, gpointer value, gpointer user_data) + { +@@ -938,6 +997,7 @@ smmuv3_invalidate_ste(gpointer key, gpointer value, gpointer user_data) + if (sid < sid_range->start || sid > sid_range->end) { + return false; + } ++ smmuv3_notify_config_change(sid_range->state, sid); + trace_smmuv3_config_cache_inv(sid); + return true; + } +@@ -1008,22 +1068,14 @@ static int smmuv3_cmdq_consume(SMMUv3State *s) + case SMMU_CMD_CFGI_STE: + { + uint32_t sid = CMD_SID(&cmd); +- IOMMUMemoryRegion *mr = smmu_iommu_mr(bs, sid); +- SMMUDevice *sdev; + + if (CMD_SSEC(&cmd)) { + cmd_error = SMMU_CERROR_ILL; + break; + } + +- if (!mr) { +- break; +- } +- + trace_smmuv3_cmdq_cfgi_ste(sid); +- sdev = container_of(mr, SMMUDevice, iommu); +- smmuv3_flush_config(sdev); +- ++ smmuv3_notify_config_change(bs, sid); + break; + } + case SMMU_CMD_CFGI_STE_RANGE: /* same as SMMU_CMD_CFGI_ALL */ +@@ -1038,6 +1090,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s) + } + + mask = (1ULL << (range + 1)) - 1; ++ sid_range.state = bs; + sid_range.start = sid & ~mask; + sid_range.end = sid_range.start + mask; + +diff --git a/hw/arm/trace-events b/hw/arm/trace-events +index 1447ad5a90..d9851d663e 100644 +--- a/hw/arm/trace-events ++++ b/hw/arm/trace-events +@@ -53,4 +53,5 @@ smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x" + smmuv3_notify_flag_add(const char *iommu) "ADD SMMUNotifier node for iommu mr=%s" + smmuv3_notify_flag_del(const char *iommu) "DEL SMMUNotifier node for iommu mr=%s" + smmuv3_inv_notifiers_iova(const char *name, uint16_t asid, uint64_t iova, uint8_t tg, uint64_t num_pages) "iommu mr=%s asid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64 ++smmuv3_notify_config_change(const char *name, uint8_t config, uint64_t s1ctxptr) "iommu mr=%s config=%d s1ctxptr=0x%"PRIx64 + +-- +2.27.0 +