Commit a2392b8f authored by Matthew Rosato's avatar Matthew Rosato Committed by Joerg Roedel
Browse files

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: default avatarNiklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: default avatarMatthew Rosato <mjrosato@linux.ibm.com>
Tested-by: default avatarNiklas Schnelle <schnelle@linux.ibm.com>
Link: https://lore.kernel.org/r/20250411202433.181683-3-mjrosato@linux.ibm.com


Signed-off-by: default avatarJoerg Roedel <jroedel@suse.de>
parent 83c1aec2
Loading
Loading
Loading
Loading
+64 −7
Original line number Diff line number Diff line
@@ -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;

	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(table[rtx]))
			dma_free_seg_table(table[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);
}