The origin_type of the dma_table is used to determine how many table levels must be traversed for the translation. Signed-off-by: Matthew Rosato <mjrosato@xxxxxxxxxxxxx> --- drivers/iommu/s390-iommu.c | 42 +++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c index 5782f329cae9..cea528bf61db 100644 --- a/drivers/iommu/s390-iommu.c +++ b/drivers/iommu/s390-iommu.c @@ -744,6 +744,43 @@ static int s390_iommu_map_pages(struct iommu_domain *domain, return rc; } +static unsigned long *get_rto_from_iova(struct s390_domain *domain, + dma_addr_t iova) +{ + unsigned long *rfo, *rso, *rto; + unsigned long rfe, rse; + unsigned int rfx, rsx; + + switch (domain->origin_type) { + case ZPCI_TABLE_TYPE_RFX: + rfo = domain->dma_table; + goto itp_rf; + case ZPCI_TABLE_TYPE_RSX: + rso = domain->dma_table; + goto itp_rs; + case ZPCI_TABLE_TYPE_RTX: + return domain->dma_table; + default: + return NULL; + } + +itp_rf: + rfx = calc_rfx(iova); + rfe = READ_ONCE(rfo[rfx]); + if (!reg_entry_isvalid(rfe)) + return NULL; + rso = get_rf_rso(rfe); + +itp_rs: + rsx = calc_rsx(iova); + rse = READ_ONCE(rso[rsx]); + if (!reg_entry_isvalid(rse)) + return NULL; + rto = get_rs_rto(rse); + + return rto; +} + static phys_addr_t s390_iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova) { @@ -757,10 +794,13 @@ static phys_addr_t s390_iommu_iova_to_phys(struct iommu_domain *domain, iova > domain->geometry.aperture_end) return 0; + rto = get_rto_from_iova(s390_domain, iova); + if (!rto) + return 0; + rtx = calc_rtx(iova); sx = calc_sx(iova); px = calc_px(iova); - rto = s390_domain->dma_table; rte = READ_ONCE(rto[rtx]); if (reg_entry_isvalid(rte)) { -- 2.47.0