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

iommu/s390: handle IOAT registration based on domain



At this point, the dma_table is really a property of the s390-iommu
domain.  Rather than checking its contents elsewhere in the codebase,
move the code that registers the table with firmware into
s390-iommu and make a decision what to register with firmware based
upon the type of domain in use for the device in question.

Tested-by: default avatarNiklas Schnelle <schnelle@linux.ibm.com>
Reviewed-by: default avatarNiklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: default avatarMatthew Rosato <mjrosato@linux.ibm.com>
Link: https://lore.kernel.org/r/20250212213418.182902-4-mjrosato@linux.ibm.com


Signed-off-by: default avatarJoerg Roedel <jroedel@suse.de>
parent d236843a
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -217,6 +217,7 @@ extern struct airq_iv *zpci_aif_sbv;
struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state);
int zpci_add_device(struct zpci_dev *zdev);
int zpci_enable_device(struct zpci_dev *);
int zpci_reenable_device(struct zpci_dev *zdev);
int zpci_disable_device(struct zpci_dev *);
int zpci_scan_configured_device(struct zpci_dev *zdev, u32 fh);
int zpci_deconfigure_device(struct zpci_dev *zdev);
@@ -245,6 +246,7 @@ void update_uid_checking(bool new);
/* IOMMU Interface */
int zpci_init_iommu(struct zpci_dev *zdev);
void zpci_destroy_iommu(struct zpci_dev *zdev);
int zpci_iommu_register_ioat(struct zpci_dev *zdev, u8 *status);

#ifdef CONFIG_PCI
static inline bool zpci_use_mio(struct zpci_dev *zdev)
+2 −15
Original line number Diff line number Diff line
@@ -433,7 +433,6 @@ static void kvm_s390_pci_dev_release(struct zpci_dev *zdev)
static int kvm_s390_pci_register_kvm(void *opaque, struct kvm *kvm)
{
	struct zpci_dev *zdev = opaque;
	u8 status;
	int rc;

	if (!zdev)
@@ -480,13 +479,7 @@ static int kvm_s390_pci_register_kvm(void *opaque, struct kvm *kvm)
	 */
	zdev->gisa = (u32)virt_to_phys(&kvm->arch.sie_page2->gisa);

	rc = zpci_enable_device(zdev);
	if (rc)
		goto clear_gisa;

	/* Re-register the IOMMU that was already created */
	rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
				virt_to_phys(zdev->dma_table), &status);
	rc = zpci_reenable_device(zdev);
	if (rc)
		goto clear_gisa;

@@ -516,7 +509,6 @@ static void kvm_s390_pci_unregister_kvm(void *opaque)
{
	struct zpci_dev *zdev = opaque;
	struct kvm *kvm;
	u8 status;

	if (!zdev)
		return;
@@ -550,12 +542,7 @@ static void kvm_s390_pci_unregister_kvm(void *opaque)
			goto out;
	}

	if (zpci_enable_device(zdev))
		goto out;

	/* Re-register the IOMMU that was already created */
	zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
			   virt_to_phys(zdev->dma_table), &status);
	zpci_reenable_device(zdev);

out:
	spin_lock(&kvm->arch.kzdev_list_lock);
+20 −15
Original line number Diff line number Diff line
@@ -124,14 +124,13 @@ int zpci_register_ioat(struct zpci_dev *zdev, u8 dmaas,
	struct zpci_fib fib = {0};
	u8 cc;

	WARN_ON_ONCE(iota & 0x3fff);
	fib.pba = base;
	/* Work around off by one in ISM virt device */
	if (zdev->pft == PCI_FUNC_TYPE_ISM && limit > base)
		fib.pal = limit + (1 << 12);
	else
		fib.pal = limit;
	fib.iota = iota | ZPCI_IOTA_RTTO_FLAG;
	fib.iota = iota;
	fib.gd = zdev->gisa;
	cc = zpci_mod_fc(req, &fib, status);
	if (cc)
@@ -690,6 +689,23 @@ int zpci_enable_device(struct zpci_dev *zdev)
}
EXPORT_SYMBOL_GPL(zpci_enable_device);

int zpci_reenable_device(struct zpci_dev *zdev)
{
	u8 status;
	int rc;

	rc = zpci_enable_device(zdev);
	if (rc)
		return rc;

	rc = zpci_iommu_register_ioat(zdev, &status);
	if (rc)
		zpci_disable_device(zdev);

	return rc;
}
EXPORT_SYMBOL_GPL(zpci_reenable_device);

int zpci_disable_device(struct zpci_dev *zdev)
{
	u32 fh = zdev->fh;
@@ -739,7 +755,6 @@ EXPORT_SYMBOL_GPL(zpci_disable_device);
 */
int zpci_hot_reset_device(struct zpci_dev *zdev)
{
	u8 status;
	int rc;

	lockdep_assert_held(&zdev->state_lock);
@@ -758,21 +773,11 @@ int zpci_hot_reset_device(struct zpci_dev *zdev)
			return rc;
	}

	rc = zpci_enable_device(zdev);
	if (rc)
		return rc;
	rc = zpci_reenable_device(zdev);

	if (zdev->dma_table)
		rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
					virt_to_phys(zdev->dma_table), &status);
	if (rc) {
		zpci_disable_device(zdev);
	return rc;
}

	return 0;
}

/**
 * zpci_create_device() - Create a new zpci_dev and add it to the zbus
 * @fid: Function ID of the device to be created
+1 −10
Original line number Diff line number Diff line
@@ -52,7 +52,6 @@ static DEVICE_ATTR_RO(mio_enabled);

static int _do_recover(struct pci_dev *pdev, struct zpci_dev *zdev)
{
	u8 status;
	int ret;

	pci_stop_and_remove_bus_device(pdev);
@@ -70,16 +69,8 @@ static int _do_recover(struct pci_dev *pdev, struct zpci_dev *zdev)
			return ret;
	}

	ret = zpci_enable_device(zdev);
	if (ret)
		return ret;
	ret = zpci_reenable_device(zdev);

	if (zdev->dma_table) {
		ret = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
					 virt_to_phys(zdev->dma_table), &status);
		if (ret)
			zpci_disable_device(zdev);
	}
	return ret;
}

+41 −2
Original line number Diff line number Diff line
@@ -381,6 +381,46 @@ static void zdev_s390_domain_update(struct zpci_dev *zdev,
	spin_unlock_irqrestore(&zdev->dom_lock, flags);
}

static int s390_iommu_domain_reg_ioat(struct zpci_dev *zdev,
				      struct iommu_domain *domain, u8 *status)
{
	struct s390_domain *s390_domain;
	int rc = 0;
	u64 iota;

	switch (domain->type) {
	case IOMMU_DOMAIN_IDENTITY:
		rc = zpci_register_ioat(zdev, 0, zdev->start_dma,
					zdev->end_dma, 0, status);
		break;
	case IOMMU_DOMAIN_BLOCKED:
		/* Nothing to do in this case */
		break;
	default:
		s390_domain = to_s390_domain(domain);
		iota = virt_to_phys(s390_domain->dma_table) |
		       ZPCI_IOTA_RTTO_FLAG;
		rc = zpci_register_ioat(zdev, 0, zdev->start_dma,
					zdev->end_dma, iota, status);
	}

	return rc;
}

int zpci_iommu_register_ioat(struct zpci_dev *zdev, u8 *status)
{
	unsigned long flags;
	int rc;

	spin_lock_irqsave(&zdev->dom_lock, flags);

	rc = s390_iommu_domain_reg_ioat(zdev, zdev->s390_domain, status);

	spin_unlock_irqrestore(&zdev->dom_lock, flags);

	return rc;
}

static int blocking_domain_attach_device(struct iommu_domain *domain,
					 struct device *dev)
{
@@ -422,8 +462,7 @@ static int s390_iommu_attach_device(struct iommu_domain *domain,
	blocking_domain_attach_device(&blocking_domain, dev);

	/* If we fail now DMA remains blocked via blocking domain */
	cc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
				virt_to_phys(s390_domain->dma_table), &status);
	cc = s390_iommu_domain_reg_ioat(zdev, domain, &status);
	if (cc && status != ZPCI_PCI_ST_FUNC_NOT_AVAIL)
		return -EIO;
	zdev->dma_table = s390_domain->dma_table;