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

iommu/s390: support iova_to_phys for additional table regions



The origin_type of the dma_table is used to determine how many table
levels must be traversed for the translation.

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-4-mjrosato@linux.ibm.com


Signed-off-by: default avatarJoerg Roedel <jroedel@suse.de>
parent a2392b8f
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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)
+59 −1
Original line number Diff line number Diff line
@@ -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)) {