From 03964c037862a594b4eb7d2e3754acd32c01c80b Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Thu, 22 Sep 2022 14:06:07 -0700 Subject: [PATCH] hw/arm/smmuv3: Read host SMMU device info Read the underlying SMMU device info and set corresponding IDR bits. Signed-off-by: Nicolin Chen --- hw/arm/smmuv3.c | 77 ++++++++++++++++++++++++++++++++++++ hw/arm/trace-events | 1 + include/hw/arm/smmu-common.h | 1 + 3 files changed, 79 insertions(+) diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index db111220c7..4208325ab3 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -254,6 +254,80 @@ void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info) info->recorded = true; } +static void smmuv3_nested_init_regs(SMMUv3State *s) +{ + SMMUState *bs = ARM_SMMU(s); + SMMUDevice *sdev; + uint32_t data_type; + uint32_t val; + int ret; + + if (!bs->nested || !bs->viommu) { + return; + } + + sdev = QLIST_FIRST(&bs->viommu->device_list); + if (!sdev) { + return; + } + + if (sdev->info.idr[0]) { + error_report("reusing the previous hw_info"); + goto out; + } + + ret = smmu_dev_get_info(sdev, &data_type, sizeof(sdev->info), &sdev->info); + if (ret) { + error_report("failed to get SMMU device info"); + return; + } + + if (data_type != IOMMU_HW_INFO_TYPE_ARM_SMMUV3) { + error_report( "Wrong data type (%d)!", data_type); + return; + } + +out: + trace_smmuv3_get_device_info(sdev->info.idr[0], sdev->info.idr[1], + sdev->info.idr[3], sdev->info.idr[5]); + + val = FIELD_EX32(sdev->info.idr[0], IDR0, BTM); + s->idr[0] = FIELD_DP32(s->idr[0], IDR0, BTM, val); + val = FIELD_EX32(sdev->info.idr[0], IDR0, ATS); + s->idr[0] = FIELD_DP32(s->idr[0], IDR0, ATS, val); + val = FIELD_EX32(sdev->info.idr[0], IDR0, ASID16); + s->idr[0] = FIELD_DP32(s->idr[0], IDR0, ASID16, val); + val = FIELD_EX32(sdev->info.idr[0], IDR0, TERM_MODEL); + s->idr[0] = FIELD_DP32(s->idr[0], IDR0, TERM_MODEL, val); + val = FIELD_EX32(sdev->info.idr[0], IDR0, STALL_MODEL); + s->idr[0] = FIELD_DP32(s->idr[0], IDR0, STALL_MODEL, val); + val = FIELD_EX32(sdev->info.idr[0], IDR0, STLEVEL); + s->idr[0] = FIELD_DP32(s->idr[0], IDR0, STLEVEL, val); + + val = FIELD_EX32(sdev->info.idr[1], IDR1, SIDSIZE); + s->idr[1] = FIELD_DP32(s->idr[1], IDR1, SIDSIZE, val); + val = FIELD_EX32(sdev->info.idr[1], IDR1, SSIDSIZE); + s->idr[1] = FIELD_DP32(s->idr[1], IDR1, SSIDSIZE, val); + + val = FIELD_EX32(sdev->info.idr[3], IDR3, HAD); + s->idr[3] = FIELD_DP32(s->idr[3], IDR3, HAD, val); + val = FIELD_EX32(sdev->info.idr[3], IDR3, RIL); + s->idr[3] = FIELD_DP32(s->idr[3], IDR3, RIL, val); + val = FIELD_EX32(sdev->info.idr[3], IDR3, BBML); + s->idr[3] = FIELD_DP32(s->idr[3], IDR3, BBML, val); + + val = FIELD_EX32(sdev->info.idr[5], IDR5, GRAN4K); + s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN4K, val); + val = FIELD_EX32(sdev->info.idr[5], IDR5, GRAN16K); + s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN16K, val); + val = FIELD_EX32(sdev->info.idr[5], IDR5, GRAN64K); + s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN64K, val); + val = FIELD_EX32(sdev->info.idr[5], IDR5, OAS); + s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, val); + + /* FIXME check iidr and aidr registrs too */ +} + static void smmuv3_init_regs(SMMUv3State *s) { /* Based on sys property, the stages supported in smmu will be advertised.*/ @@ -292,6 +366,9 @@ static void smmuv3_init_regs(SMMUv3State *s) s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN16K, 1); s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN64K, 1); + /* Override IDR fields with HW caps */ + smmuv3_nested_init_regs(s); + s->cmdq.base = deposit64(s->cmdq.base, 0, 5, SMMU_CMDQS); s->cmdq.prod = 0; s->cmdq.cons = 0; diff --git a/hw/arm/trace-events b/hw/arm/trace-events index 58e0636e95..1e3d86382d 100644 --- a/hw/arm/trace-events +++ b/hw/arm/trace-events @@ -55,5 +55,6 @@ smmuv3_cmdq_tlbi_s12_vmid(uint16_t vmid) "vmid=%d" 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_get_device_info(uint32_t idr0, uint32_t idr1, uint32_t idr3, uint32_t idr5) "idr0=0x%x idr1=0x%x idr3=0x%x idr5=0x%x" smmuv3_inv_notifiers_iova(const char *name, uint16_t asid, uint16_t vmid, uint64_t iova, uint8_t tg, uint64_t num_pages) "iommu mr=%s asid=%d vmid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64 diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h index 37dfeed026..d120c352cf 100644 --- a/include/hw/arm/smmu-common.h +++ b/include/hw/arm/smmu-common.h @@ -146,6 +146,7 @@ typedef struct SMMUDevice { AddressSpace as_sysmem; uint32_t cfg_cache_hits; uint32_t cfg_cache_misses; + struct iommu_hw_info_arm_smmuv3 info; QLIST_ENTRY(SMMUDevice) next; } SMMUDevice; -- 2.41.0.windows.1