|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [RFC PATCH 19/21] xen/arm: vsmmuv3: Add support to send stage-1 event to guest
Stage-1 translation is handled by guest, therefore stage-1 fault has to
be forwarded to guest.
Signed-off-by: Rahul Singh <rahul.singh@xxxxxxx>
---
xen/drivers/passthrough/arm/smmu-v3.c | 48 ++++++++++++++++++++++++--
xen/drivers/passthrough/arm/vsmmu-v3.c | 45 ++++++++++++++++++++++++
xen/drivers/passthrough/arm/vsmmu-v3.h | 12 +++++++
3 files changed, 103 insertions(+), 2 deletions(-)
diff --git a/xen/drivers/passthrough/arm/smmu-v3.c
b/xen/drivers/passthrough/arm/smmu-v3.c
index c4b4a5d86d..e17debc456 100644
--- a/xen/drivers/passthrough/arm/smmu-v3.c
+++ b/xen/drivers/passthrough/arm/smmu-v3.c
@@ -871,7 +871,6 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device
*smmu, u32 sid)
return 0;
}
-__maybe_unused
static struct arm_smmu_master *
arm_smmu_find_master(struct arm_smmu_device *smmu, u32 sid)
{
@@ -892,10 +891,51 @@ arm_smmu_find_master(struct arm_smmu_device *smmu, u32
sid)
return NULL;
}
+static int arm_smmu_handle_evt(struct arm_smmu_device *smmu, u64 *evt)
+{
+ int ret;
+ struct arm_smmu_master *master;
+ u32 sid = FIELD_GET(EVTQ_0_SID, evt[0]);
+
+ switch (FIELD_GET(EVTQ_0_ID, evt[0])) {
+ case EVT_ID_TRANSLATION_FAULT:
+ break;
+ case EVT_ID_ADDR_SIZE_FAULT:
+ break;
+ case EVT_ID_ACCESS_FAULT:
+ break;
+ case EVT_ID_PERMISSION_FAULT:
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ /* Stage-2 event */
+ if (evt[1] & EVTQ_1_S2)
+ return -EFAULT;
+
+ mutex_lock(&smmu->streams_mutex);
+ master = arm_smmu_find_master(smmu, sid);
+ if (!master) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ ret = arm_vsmmu_handle_evt(master->domain->d, smmu->dev, evt);
+ if (ret) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+out_unlock:
+ mutex_unlock(&smmu->streams_mutex);
+ return ret;
+}
+
/* IRQ and event handlers */
static void arm_smmu_evtq_tasklet(void *dev)
{
- int i;
+ int i, ret;
struct arm_smmu_device *smmu = dev;
struct arm_smmu_queue *q = &smmu->evtq.q;
struct arm_smmu_ll_queue *llq = &q->llq;
@@ -905,6 +945,10 @@ static void arm_smmu_evtq_tasklet(void *dev)
while (!queue_remove_raw(q, evt)) {
u8 id = FIELD_GET(EVTQ_0_ID, evt[0]);
+ ret = arm_smmu_handle_evt(smmu, evt);
+ if (!ret)
+ continue;
+
dev_info(smmu->dev, "event 0x%02x received:\n", id);
for (i = 0; i < ARRAY_SIZE(evt); ++i)
dev_info(smmu->dev, "\t0x%016llx\n",
diff --git a/xen/drivers/passthrough/arm/vsmmu-v3.c
b/xen/drivers/passthrough/arm/vsmmu-v3.c
index b280b70da0..cd8b62d806 100644
--- a/xen/drivers/passthrough/arm/vsmmu-v3.c
+++ b/xen/drivers/passthrough/arm/vsmmu-v3.c
@@ -102,6 +102,7 @@ struct arm_vsmmu_queue {
struct virt_smmu {
struct domain *d;
struct list_head viommu_list;
+ paddr_t addr;
uint8_t sid_split;
uint32_t features;
uint32_t cr[3];
@@ -236,6 +237,49 @@ void arm_vsmmu_send_event(struct virt_smmu *smmu,
return;
}
+static struct virt_smmu *vsmmuv3_find_by_addr(struct domain *d, paddr_t paddr)
+{
+ struct virt_smmu *smmu;
+
+ list_for_each_entry( smmu, &d->arch.viommu_list, viommu_list )
+ {
+ if ( smmu->addr == paddr )
+ return smmu;
+ }
+
+ return NULL;
+}
+
+int arm_vsmmu_handle_evt(struct domain *d, struct device *dev, uint64_t *evt)
+{
+ int ret;
+ struct virt_smmu *smmu;
+
+ if ( is_hardware_domain(d) )
+ {
+ paddr_t paddr;
+ /* Base address */
+ ret = dt_device_get_address(dev_to_dt(dev), 0, &paddr, NULL);
+ if ( ret )
+ return -EINVAL;
+
+ smmu = vsmmuv3_find_by_addr(d, paddr);
+ if ( !smmu )
+ return -ENODEV;
+ }
+ else
+ {
+ smmu = list_entry(d->arch.viommu_list.next,
+ struct virt_smmu, viommu_list);
+ }
+
+ ret = arm_vsmmu_write_evtq(smmu, evt);
+ if ( ret )
+ arm_vsmmu_inject_irq(smmu, true, GERROR_EVTQ_ABT_ERR);
+
+ return 0;
+}
+
static int arm_vsmmu_find_ste(struct virt_smmu *smmu, uint32_t sid,
uint64_t *ste)
{
@@ -737,6 +781,7 @@ static int vsmmuv3_init_single(struct domain *d, paddr_t
addr,
smmu->d = d;
smmu->virq = virq;
+ smmu->addr = addr;
smmu->cmdq.q_base = FIELD_PREP(Q_BASE_LOG2SIZE, SMMU_CMDQS);
smmu->cmdq.ent_size = CMDQ_ENT_DWORDS * DWORDS_BYTES;
smmu->evtq.q_base = FIELD_PREP(Q_BASE_LOG2SIZE, SMMU_EVTQS);
diff --git a/xen/drivers/passthrough/arm/vsmmu-v3.h
b/xen/drivers/passthrough/arm/vsmmu-v3.h
index e11f85b431..c7bfd3fb59 100644
--- a/xen/drivers/passthrough/arm/vsmmu-v3.h
+++ b/xen/drivers/passthrough/arm/vsmmu-v3.h
@@ -8,6 +8,12 @@
void vsmmuv3_set_type(void);
+static inline int arm_vsmmu_handle_evt(struct domain *d,
+ struct device *dev, uint64_t *evt)
+{
+ return -EINVAL;
+}
+
#else
static inline void vsmmuv3_set_type(void)
@@ -15,6 +21,12 @@ static inline void vsmmuv3_set_type(void)
return;
}
+static inline int arm_vsmmu_handle_evt(struct domain *d,
+ struct device *dev, uint64_t *evt)
+{
+ return -EINVAL;
+}
+
#endif /* CONFIG_VIRTUAL_ARM_SMMU_V3 */
#endif /* __ARCH_ARM_VSMMU_V3_H__ */
--
2.25.1
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |