iommu/s390: support cleanup of additional table regions

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>
This commit is contained in:
Matthew Rosato 2025-04-11 16:24:30 -04:00 committed by Joerg Roedel
parent 83c1aec210
commit a2392b8f1f

View 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);
}