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 <smostafa@google.com>
This commit is contained in:
Mostafa Saleh
2024-12-12 18:03:53 +00:00
parent c7d7c29253
commit 4b3a037eea
@@ -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;