]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
iommu/s390: support iova_to_phys for additional table regions
authorMatthew Rosato <mjrosato@linux.ibm.com>
Fri, 11 Apr 2025 20:24:31 +0000 (16:24 -0400)
committerJoerg Roedel <jroedel@suse.de>
Thu, 17 Apr 2025 14:43:11 +0000 (16:43 +0200)
The origin_type of the dma_table is used to determine how many table
levels must be traversed for the translation.

Reviewed-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Tested-by: Niklas Schnelle <schnelle@linux.ibm.com>
Link: https://lore.kernel.org/r/20250411202433.181683-4-mjrosato@linux.ibm.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
arch/s390/include/asm/pci_dma.h
drivers/iommu/s390-iommu.c

index 42d7cc4262ca48d1368cc31ab804f07bf558a7b7..8d8962e4fd58f2156f6f154cc32f716c518a3e5d 100644 (file)
@@ -55,6 +55,8 @@ enum zpci_ioat_dtype {
 #define ZPCI_PT_BITS                   8
 #define ZPCI_ST_SHIFT                  (ZPCI_PT_BITS + PAGE_SHIFT)
 #define ZPCI_RT_SHIFT                  (ZPCI_ST_SHIFT + ZPCI_TABLE_BITS)
+#define ZPCI_RS_SHIFT                  (ZPCI_RT_SHIFT + ZPCI_TABLE_BITS)
+#define ZPCI_RF_SHIFT                  (ZPCI_RS_SHIFT + ZPCI_TABLE_BITS)
 
 #define ZPCI_RTE_FLAG_MASK             0x3fffUL
 #define ZPCI_RTE_ADDR_MASK             (~ZPCI_RTE_FLAG_MASK)
index f2cda0ce0fe92dc856248f38bce53c5866c28979..338a7381e918698fe4a40ca42ed463d293476186 100644 (file)
@@ -36,6 +36,16 @@ struct s390_domain {
 
 static struct iommu_domain blocking_domain;
 
+static inline unsigned int calc_rfx(dma_addr_t ptr)
+{
+       return ((unsigned long)ptr >> ZPCI_RF_SHIFT) & ZPCI_INDEX_MASK;
+}
+
+static inline unsigned int calc_rsx(dma_addr_t ptr)
+{
+       return ((unsigned long)ptr >> ZPCI_RS_SHIFT) & ZPCI_INDEX_MASK;
+}
+
 static inline unsigned int calc_rtx(dma_addr_t ptr)
 {
        return ((unsigned long)ptr >> ZPCI_RT_SHIFT) & ZPCI_INDEX_MASK;
@@ -759,6 +769,51 @@ static int s390_iommu_map_pages(struct iommu_domain *domain,
        return rc;
 }
 
+static unsigned long *get_rso_from_iova(struct s390_domain *domain,
+                                       dma_addr_t iova)
+{
+       unsigned long *rfo;
+       unsigned long rfe;
+       unsigned int rfx;
+
+       switch (domain->origin_type) {
+       case ZPCI_TABLE_TYPE_RFX:
+               rfo = domain->dma_table;
+               rfx = calc_rfx(iova);
+               rfe = READ_ONCE(rfo[rfx]);
+               if (!reg_entry_isvalid(rfe))
+                       return NULL;
+               return get_rf_rso(rfe);
+       case ZPCI_TABLE_TYPE_RSX:
+               return domain->dma_table;
+       default:
+               return NULL;
+       }
+}
+
+static unsigned long *get_rto_from_iova(struct s390_domain *domain,
+                                       dma_addr_t iova)
+{
+       unsigned long *rso;
+       unsigned long rse;
+       unsigned int rsx;
+
+       switch (domain->origin_type) {
+       case ZPCI_TABLE_TYPE_RFX:
+       case ZPCI_TABLE_TYPE_RSX:
+               rso = get_rso_from_iova(domain, iova);
+               rsx = calc_rsx(iova);
+               rse = READ_ONCE(rso[rsx]);
+               if (!reg_entry_isvalid(rse))
+                       return NULL;
+               return get_rs_rto(rse);
+       case ZPCI_TABLE_TYPE_RTX:
+               return domain->dma_table;
+       default:
+               return NULL;
+       }
+}
+
 static phys_addr_t s390_iommu_iova_to_phys(struct iommu_domain *domain,
                                           dma_addr_t iova)
 {
@@ -772,10 +827,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)) {