]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
iommu/s390: support cleanup of additional table regions
authorMatthew Rosato <mjrosato@linux.ibm.com>
Fri, 11 Apr 2025 20:24:30 +0000 (16:24 -0400)
committerJoerg Roedel <jroedel@suse.de>
Thu, 17 Apr 2025 14:43:10 +0000 (16:43 +0200)
Extend the existing dma_cleanup_tables to also handle region second and
region first tables.

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-3-mjrosato@linux.ibm.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/s390-iommu.c

index cad032d4c9a6469490650fc46440d0f1f09017a7..f2cda0ce0fe92dc856248f38bce53c5866c28979 100644 (file)
@@ -121,6 +121,22 @@ static inline int pt_entry_isvalid(unsigned long entry)
        return (entry & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID;
 }
 
+static inline unsigned long *get_rf_rso(unsigned long entry)
+{
+       if ((entry & ZPCI_TABLE_TYPE_MASK) == ZPCI_TABLE_TYPE_RFX)
+               return phys_to_virt(entry & ZPCI_RTE_ADDR_MASK);
+       else
+               return NULL;
+}
+
+static inline unsigned long *get_rs_rto(unsigned long entry)
+{
+       if ((entry & ZPCI_TABLE_TYPE_MASK) == ZPCI_TABLE_TYPE_RSX)
+               return phys_to_virt(entry & ZPCI_RTE_ADDR_MASK);
+       else
+               return NULL;
+}
+
 static inline unsigned long *get_rt_sto(unsigned long entry)
 {
        if ((entry & ZPCI_TABLE_TYPE_MASK) == ZPCI_TABLE_TYPE_RTX)
@@ -192,18 +208,59 @@ static void dma_free_seg_table(unsigned long entry)
        dma_free_cpu_table(sto);
 }
 
-static void dma_cleanup_tables(unsigned long *table)
+static void dma_free_rt_table(unsigned long entry)
 {
+       unsigned long *rto = get_rs_rto(entry);
        int rtx;
 
-       if (!table)
+       for (rtx = 0; rtx < ZPCI_TABLE_ENTRIES; rtx++)
+               if (reg_entry_isvalid(rto[rtx]))
+                       dma_free_seg_table(rto[rtx]);
+
+       dma_free_cpu_table(rto);
+}
+
+static void dma_free_rs_table(unsigned long entry)
+{
+       unsigned long *rso = get_rf_rso(entry);
+       int rsx;
+
+       for (rsx = 0; rsx < ZPCI_TABLE_ENTRIES; rsx++)
+               if (reg_entry_isvalid(rso[rsx]))
+                       dma_free_rt_table(rso[rsx]);
+
+       dma_free_cpu_table(rso);
+}
+
+static void dma_cleanup_tables(struct s390_domain *domain)
+{
+       int rtx, rsx, rfx;
+
+       if (!domain->dma_table)
                return;
 
-       for (rtx = 0; rtx < ZPCI_TABLE_ENTRIES; rtx++)
-               if (reg_entry_isvalid(table[rtx]))
-                       dma_free_seg_table(table[rtx]);
+       switch (domain->origin_type) {
+       case ZPCI_TABLE_TYPE_RFX:
+               for (rfx = 0; rfx < ZPCI_TABLE_ENTRIES; rfx++)
+                       if (reg_entry_isvalid(domain->dma_table[rfx]))
+                               dma_free_rs_table(domain->dma_table[rfx]);
+               break;
+       case ZPCI_TABLE_TYPE_RSX:
+               for (rsx = 0; rsx < ZPCI_TABLE_ENTRIES; rsx++)
+                       if (reg_entry_isvalid(domain->dma_table[rsx]))
+                               dma_free_rt_table(domain->dma_table[rsx]);
+               break;
+       case ZPCI_TABLE_TYPE_RTX:
+               for (rtx = 0; rtx < ZPCI_TABLE_ENTRIES; rtx++)
+                       if (reg_entry_isvalid(domain->dma_table[rtx]))
+                               dma_free_seg_table(domain->dma_table[rtx]);
+               break;
+       default:
+               WARN_ONCE(1, "Invalid IOMMU table (%x)\n", domain->origin_type);
+               return;
+       }
 
-       dma_free_cpu_table(table);
+       dma_free_cpu_table(domain->dma_table);
 }
 
 static unsigned long *dma_alloc_page_table(gfp_t gfp)
@@ -358,7 +415,7 @@ static void s390_iommu_rcu_free_domain(struct rcu_head *head)
 {
        struct s390_domain *s390_domain = container_of(head, struct s390_domain, rcu);
 
-       dma_cleanup_tables(s390_domain->dma_table);
+       dma_cleanup_tables(s390_domain);
        kfree(s390_domain);
 }