[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 |