From 4b3a037eea727fc70911e3e030cfb427807a01a2 Mon Sep 17 00:00:00 2001 From: Mostafa Saleh Date: Thu, 12 Dec 2024 18:03:53 +0000 Subject: [PATCH] BACKPORT: FROMLIST: KVM: arm64: smmu-v3: Setup event queue The host can use the event queue for debuging, and unlike the command queue, it would be managed by the kernel. However, it must set in a shared state so it can't be donated to the hypervisor later. This relies on the ARM_SMMU_EVTQ_BASE can't be changed after de-privilege. Link: https://lore.kernel.org/all/20241212180423.1578358-30-smostafa@google.com/ Bug: 357781595 Bug: 384432312 Change-Id: I121ee7931edb890b95278c8e9c25c113d9a06d91 Signed-off-by: Mostafa Saleh --- arch/arm64/kvm/hyp/nvhe/iommu/arm-smmu-v3.c | 44 +++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/arch/arm64/kvm/hyp/nvhe/iommu/arm-smmu-v3.c b/arch/arm64/kvm/hyp/nvhe/iommu/arm-smmu-v3.c index 43d2ce7828c1..0a06631f80b4 100644 --- a/arch/arm64/kvm/hyp/nvhe/iommu/arm-smmu-v3.c +++ b/arch/arm64/kvm/hyp/nvhe/iommu/arm-smmu-v3.c @@ -342,6 +342,46 @@ static int smmu_init_cmdq(struct hyp_arm_smmu_v3_device *smmu) return 0; } +/* + * Event q support is optional and managed by the kernel, + * However, it must set in a shared state so it can't be donated + * to the hypervisor later. + * This relies on the ARM_SMMU_EVTQ_BASE can't be changed after + * de-privilege. + */ +static int smmu_init_evtq(struct hyp_arm_smmu_v3_device *smmu) +{ + u64 evtq_base, evtq_pfn; + size_t evtq_nr_entries, evtq_size, evtq_nr_pages; + void *evtq_va, *evtq_end; + size_t i; + int ret; + + evtq_base = readq_relaxed(smmu->base + ARM_SMMU_EVTQ_BASE); + if (!evtq_base) + return 0; + + if (evtq_base & ~(Q_BASE_RWA | Q_BASE_ADDR_MASK | Q_BASE_LOG2SIZE)) + return -EINVAL; + + evtq_nr_entries = 1 << (evtq_base & Q_BASE_LOG2SIZE); + evtq_size = evtq_nr_entries * EVTQ_ENT_DWORDS * 8; + evtq_nr_pages = PAGE_ALIGN(evtq_size) >> PAGE_SHIFT; + + evtq_pfn = PAGE_ALIGN(evtq_base & Q_BASE_ADDR_MASK) >> PAGE_SHIFT; + + for (i = 0 ; i < evtq_nr_pages ; ++i) { + ret = __pkvm_host_share_hyp(evtq_pfn + i); + if (ret) + return ret; + } + + evtq_va = hyp_phys_to_virt(evtq_pfn << PAGE_SHIFT); + evtq_end = hyp_phys_to_virt((evtq_pfn + evtq_nr_pages) << PAGE_SHIFT); + + return hyp_pin_shared_mem(evtq_va, evtq_end); +} + static int smmu_init_strtab(struct hyp_arm_smmu_v3_device *smmu) { int ret; @@ -429,6 +469,10 @@ static int smmu_init_device(struct hyp_arm_smmu_v3_device *smmu) if (ret) return ret; + ret = smmu_init_evtq(smmu); + if (ret) + return ret; + ret = smmu_init_strtab(smmu); if (ret) return ret;