]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
iommu/s390: handle IOAT registration based on domain
authorMatthew Rosato <mjrosato@linux.ibm.com>
Wed, 12 Feb 2025 21:34:17 +0000 (16:34 -0500)
committerJoerg Roedel <jroedel@suse.de>
Fri, 21 Feb 2025 11:01:58 +0000 (12:01 +0100)
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: Niklas Schnelle <schnelle@linux.ibm.com>
Reviewed-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Link: https://lore.kernel.org/r/20250212213418.182902-4-mjrosato@linux.ibm.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
arch/s390/include/asm/pci.h
arch/s390/kvm/pci.c
arch/s390/pci/pci.c
arch/s390/pci/pci_sysfs.c
drivers/iommu/s390-iommu.c

index 8fe4c7a72c0b480be9691105c627761d1449ba75..7cc6a7cc66e757afaae2860f5898b1fbde4a6343 100644 (file)
@@ -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)
index 9b9e7fdd53807886cd24cda103f8f46650ddf53f..8c40154ff50ff277297e45416c7fa1a485365ce7 100644 (file)
@@ -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);
index 88f72745fa59e16df26b1563de27594aac954a78..fa879351efb56b4802c4bf8e36bc6703a86bbbbf 100644 (file)
@@ -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,19 +773,9 @@ int zpci_hot_reset_device(struct zpci_dev *zdev)
                        return rc;
        }
 
-       rc = zpci_enable_device(zdev);
-       if (rc)
-               return rc;
-
-       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;
-       }
+       rc = zpci_reenable_device(zdev);
 
-       return 0;
+       return rc;
 }
 
 /**
index 2de1ea6c3a8cbd7cccc9c1005696eb96fd4d75dd..0ecad08e1b1eeb444b712cc69cbf18ed328060b9 100644 (file)
@@ -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;
 }
 
index fbdeded3d48b5924ec950db74c9fcdc1127c46e6..007ccfdad4954dcb0d4b27938eeed81daa1a636c 100644 (file)
@@ -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;