18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * IOMMU API for s390 PCI devices 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2015 68c2ecf20Sopenharmony_ci * Author(s): Gerald Schaefer <gerald.schaefer@de.ibm.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/pci.h> 108c2ecf20Sopenharmony_ci#include <linux/iommu.h> 118c2ecf20Sopenharmony_ci#include <linux/iommu-helper.h> 128c2ecf20Sopenharmony_ci#include <linux/sizes.h> 138c2ecf20Sopenharmony_ci#include <asm/pci_dma.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* 168c2ecf20Sopenharmony_ci * Physically contiguous memory regions can be mapped with 4 KiB alignment, 178c2ecf20Sopenharmony_ci * we allow all page sizes that are an order of 4KiB (no special large page 188c2ecf20Sopenharmony_ci * support so far). 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci#define S390_IOMMU_PGSIZES (~0xFFFUL) 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic const struct iommu_ops s390_iommu_ops; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistruct s390_domain { 258c2ecf20Sopenharmony_ci struct iommu_domain domain; 268c2ecf20Sopenharmony_ci struct list_head devices; 278c2ecf20Sopenharmony_ci unsigned long *dma_table; 288c2ecf20Sopenharmony_ci spinlock_t dma_table_lock; 298c2ecf20Sopenharmony_ci spinlock_t list_lock; 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistruct s390_domain_device { 338c2ecf20Sopenharmony_ci struct list_head list; 348c2ecf20Sopenharmony_ci struct zpci_dev *zdev; 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic struct s390_domain *to_s390_domain(struct iommu_domain *dom) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci return container_of(dom, struct s390_domain, domain); 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic bool s390_iommu_capable(enum iommu_cap cap) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci switch (cap) { 458c2ecf20Sopenharmony_ci case IOMMU_CAP_CACHE_COHERENCY: 468c2ecf20Sopenharmony_ci return true; 478c2ecf20Sopenharmony_ci case IOMMU_CAP_INTR_REMAP: 488c2ecf20Sopenharmony_ci return true; 498c2ecf20Sopenharmony_ci default: 508c2ecf20Sopenharmony_ci return false; 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic struct iommu_domain *s390_domain_alloc(unsigned domain_type) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci struct s390_domain *s390_domain; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (domain_type != IOMMU_DOMAIN_UNMANAGED) 598c2ecf20Sopenharmony_ci return NULL; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci s390_domain = kzalloc(sizeof(*s390_domain), GFP_KERNEL); 628c2ecf20Sopenharmony_ci if (!s390_domain) 638c2ecf20Sopenharmony_ci return NULL; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci s390_domain->dma_table = dma_alloc_cpu_table(); 668c2ecf20Sopenharmony_ci if (!s390_domain->dma_table) { 678c2ecf20Sopenharmony_ci kfree(s390_domain); 688c2ecf20Sopenharmony_ci return NULL; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci spin_lock_init(&s390_domain->dma_table_lock); 728c2ecf20Sopenharmony_ci spin_lock_init(&s390_domain->list_lock); 738c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&s390_domain->devices); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci return &s390_domain->domain; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic void s390_domain_free(struct iommu_domain *domain) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci struct s390_domain *s390_domain = to_s390_domain(domain); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci dma_cleanup_tables(s390_domain->dma_table); 838c2ecf20Sopenharmony_ci kfree(s390_domain); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic int s390_iommu_attach_device(struct iommu_domain *domain, 878c2ecf20Sopenharmony_ci struct device *dev) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct s390_domain *s390_domain = to_s390_domain(domain); 908c2ecf20Sopenharmony_ci struct zpci_dev *zdev = to_zpci_dev(dev); 918c2ecf20Sopenharmony_ci struct s390_domain_device *domain_device; 928c2ecf20Sopenharmony_ci unsigned long flags; 938c2ecf20Sopenharmony_ci int rc; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (!zdev) 968c2ecf20Sopenharmony_ci return -ENODEV; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci domain_device = kzalloc(sizeof(*domain_device), GFP_KERNEL); 998c2ecf20Sopenharmony_ci if (!domain_device) 1008c2ecf20Sopenharmony_ci return -ENOMEM; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (zdev->dma_table) 1038c2ecf20Sopenharmony_ci zpci_dma_exit_device(zdev); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci zdev->dma_table = s390_domain->dma_table; 1068c2ecf20Sopenharmony_ci rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma, 1078c2ecf20Sopenharmony_ci (u64) zdev->dma_table); 1088c2ecf20Sopenharmony_ci if (rc) 1098c2ecf20Sopenharmony_ci goto out_restore; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci spin_lock_irqsave(&s390_domain->list_lock, flags); 1128c2ecf20Sopenharmony_ci /* First device defines the DMA range limits */ 1138c2ecf20Sopenharmony_ci if (list_empty(&s390_domain->devices)) { 1148c2ecf20Sopenharmony_ci domain->geometry.aperture_start = zdev->start_dma; 1158c2ecf20Sopenharmony_ci domain->geometry.aperture_end = zdev->end_dma; 1168c2ecf20Sopenharmony_ci domain->geometry.force_aperture = true; 1178c2ecf20Sopenharmony_ci /* Allow only devices with identical DMA range limits */ 1188c2ecf20Sopenharmony_ci } else if (domain->geometry.aperture_start != zdev->start_dma || 1198c2ecf20Sopenharmony_ci domain->geometry.aperture_end != zdev->end_dma) { 1208c2ecf20Sopenharmony_ci rc = -EINVAL; 1218c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&s390_domain->list_lock, flags); 1228c2ecf20Sopenharmony_ci goto out_restore; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci domain_device->zdev = zdev; 1258c2ecf20Sopenharmony_ci zdev->s390_domain = s390_domain; 1268c2ecf20Sopenharmony_ci list_add(&domain_device->list, &s390_domain->devices); 1278c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&s390_domain->list_lock, flags); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci return 0; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ciout_restore: 1328c2ecf20Sopenharmony_ci zpci_dma_init_device(zdev); 1338c2ecf20Sopenharmony_ci kfree(domain_device); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci return rc; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic void s390_iommu_detach_device(struct iommu_domain *domain, 1398c2ecf20Sopenharmony_ci struct device *dev) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci struct s390_domain *s390_domain = to_s390_domain(domain); 1428c2ecf20Sopenharmony_ci struct zpci_dev *zdev = to_zpci_dev(dev); 1438c2ecf20Sopenharmony_ci struct s390_domain_device *domain_device, *tmp; 1448c2ecf20Sopenharmony_ci unsigned long flags; 1458c2ecf20Sopenharmony_ci int found = 0; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (!zdev) 1488c2ecf20Sopenharmony_ci return; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci spin_lock_irqsave(&s390_domain->list_lock, flags); 1518c2ecf20Sopenharmony_ci list_for_each_entry_safe(domain_device, tmp, &s390_domain->devices, 1528c2ecf20Sopenharmony_ci list) { 1538c2ecf20Sopenharmony_ci if (domain_device->zdev == zdev) { 1548c2ecf20Sopenharmony_ci list_del(&domain_device->list); 1558c2ecf20Sopenharmony_ci kfree(domain_device); 1568c2ecf20Sopenharmony_ci found = 1; 1578c2ecf20Sopenharmony_ci break; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&s390_domain->list_lock, flags); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (found) { 1638c2ecf20Sopenharmony_ci zdev->s390_domain = NULL; 1648c2ecf20Sopenharmony_ci zpci_unregister_ioat(zdev, 0); 1658c2ecf20Sopenharmony_ci zpci_dma_init_device(zdev); 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic struct iommu_device *s390_iommu_probe_device(struct device *dev) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci struct zpci_dev *zdev = to_zpci_dev(dev); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci return &zdev->iommu_dev; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic void s390_iommu_release_device(struct device *dev) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci struct zpci_dev *zdev = to_zpci_dev(dev); 1798c2ecf20Sopenharmony_ci struct iommu_domain *domain; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci /* 1828c2ecf20Sopenharmony_ci * This is a workaround for a scenario where the IOMMU API common code 1838c2ecf20Sopenharmony_ci * "forgets" to call the detach_dev callback: After binding a device 1848c2ecf20Sopenharmony_ci * to vfio-pci and completing the VFIO_SET_IOMMU ioctl (which triggers 1858c2ecf20Sopenharmony_ci * the attach_dev), removing the device via 1868c2ecf20Sopenharmony_ci * "echo 1 > /sys/bus/pci/devices/.../remove" won't trigger detach_dev, 1878c2ecf20Sopenharmony_ci * only release_device will be called via the BUS_NOTIFY_REMOVED_DEVICE 1888c2ecf20Sopenharmony_ci * notifier. 1898c2ecf20Sopenharmony_ci * 1908c2ecf20Sopenharmony_ci * So let's call detach_dev from here if it hasn't been called before. 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_ci if (zdev && zdev->s390_domain) { 1938c2ecf20Sopenharmony_ci domain = iommu_get_domain_for_dev(dev); 1948c2ecf20Sopenharmony_ci if (domain) 1958c2ecf20Sopenharmony_ci s390_iommu_detach_device(domain, dev); 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic int s390_iommu_update_trans(struct s390_domain *s390_domain, 2008c2ecf20Sopenharmony_ci unsigned long pa, dma_addr_t dma_addr, 2018c2ecf20Sopenharmony_ci size_t size, int flags) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci struct s390_domain_device *domain_device; 2048c2ecf20Sopenharmony_ci u8 *page_addr = (u8 *) (pa & PAGE_MASK); 2058c2ecf20Sopenharmony_ci dma_addr_t start_dma_addr = dma_addr; 2068c2ecf20Sopenharmony_ci unsigned long irq_flags, nr_pages, i; 2078c2ecf20Sopenharmony_ci unsigned long *entry; 2088c2ecf20Sopenharmony_ci int rc = 0; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (dma_addr < s390_domain->domain.geometry.aperture_start || 2118c2ecf20Sopenharmony_ci dma_addr + size > s390_domain->domain.geometry.aperture_end) 2128c2ecf20Sopenharmony_ci return -EINVAL; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; 2158c2ecf20Sopenharmony_ci if (!nr_pages) 2168c2ecf20Sopenharmony_ci return 0; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci spin_lock_irqsave(&s390_domain->dma_table_lock, irq_flags); 2198c2ecf20Sopenharmony_ci for (i = 0; i < nr_pages; i++) { 2208c2ecf20Sopenharmony_ci entry = dma_walk_cpu_trans(s390_domain->dma_table, dma_addr); 2218c2ecf20Sopenharmony_ci if (!entry) { 2228c2ecf20Sopenharmony_ci rc = -ENOMEM; 2238c2ecf20Sopenharmony_ci goto undo_cpu_trans; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci dma_update_cpu_trans(entry, page_addr, flags); 2268c2ecf20Sopenharmony_ci page_addr += PAGE_SIZE; 2278c2ecf20Sopenharmony_ci dma_addr += PAGE_SIZE; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci spin_lock(&s390_domain->list_lock); 2318c2ecf20Sopenharmony_ci list_for_each_entry(domain_device, &s390_domain->devices, list) { 2328c2ecf20Sopenharmony_ci rc = zpci_refresh_trans((u64) domain_device->zdev->fh << 32, 2338c2ecf20Sopenharmony_ci start_dma_addr, nr_pages * PAGE_SIZE); 2348c2ecf20Sopenharmony_ci if (rc) 2358c2ecf20Sopenharmony_ci break; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci spin_unlock(&s390_domain->list_lock); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ciundo_cpu_trans: 2408c2ecf20Sopenharmony_ci if (rc && ((flags & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID)) { 2418c2ecf20Sopenharmony_ci flags = ZPCI_PTE_INVALID; 2428c2ecf20Sopenharmony_ci while (i-- > 0) { 2438c2ecf20Sopenharmony_ci page_addr -= PAGE_SIZE; 2448c2ecf20Sopenharmony_ci dma_addr -= PAGE_SIZE; 2458c2ecf20Sopenharmony_ci entry = dma_walk_cpu_trans(s390_domain->dma_table, 2468c2ecf20Sopenharmony_ci dma_addr); 2478c2ecf20Sopenharmony_ci if (!entry) 2488c2ecf20Sopenharmony_ci break; 2498c2ecf20Sopenharmony_ci dma_update_cpu_trans(entry, page_addr, flags); 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&s390_domain->dma_table_lock, irq_flags); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci return rc; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic int s390_iommu_map(struct iommu_domain *domain, unsigned long iova, 2588c2ecf20Sopenharmony_ci phys_addr_t paddr, size_t size, int prot, gfp_t gfp) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci struct s390_domain *s390_domain = to_s390_domain(domain); 2618c2ecf20Sopenharmony_ci int flags = ZPCI_PTE_VALID, rc = 0; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (!(prot & IOMMU_READ)) 2648c2ecf20Sopenharmony_ci return -EINVAL; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (!(prot & IOMMU_WRITE)) 2678c2ecf20Sopenharmony_ci flags |= ZPCI_TABLE_PROTECTED; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci rc = s390_iommu_update_trans(s390_domain, (unsigned long) paddr, iova, 2708c2ecf20Sopenharmony_ci size, flags); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return rc; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic phys_addr_t s390_iommu_iova_to_phys(struct iommu_domain *domain, 2768c2ecf20Sopenharmony_ci dma_addr_t iova) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct s390_domain *s390_domain = to_s390_domain(domain); 2798c2ecf20Sopenharmony_ci unsigned long *sto, *pto, *rto, flags; 2808c2ecf20Sopenharmony_ci unsigned int rtx, sx, px; 2818c2ecf20Sopenharmony_ci phys_addr_t phys = 0; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (iova < domain->geometry.aperture_start || 2848c2ecf20Sopenharmony_ci iova > domain->geometry.aperture_end) 2858c2ecf20Sopenharmony_ci return 0; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci rtx = calc_rtx(iova); 2888c2ecf20Sopenharmony_ci sx = calc_sx(iova); 2898c2ecf20Sopenharmony_ci px = calc_px(iova); 2908c2ecf20Sopenharmony_ci rto = s390_domain->dma_table; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci spin_lock_irqsave(&s390_domain->dma_table_lock, flags); 2938c2ecf20Sopenharmony_ci if (rto && reg_entry_isvalid(rto[rtx])) { 2948c2ecf20Sopenharmony_ci sto = get_rt_sto(rto[rtx]); 2958c2ecf20Sopenharmony_ci if (sto && reg_entry_isvalid(sto[sx])) { 2968c2ecf20Sopenharmony_ci pto = get_st_pto(sto[sx]); 2978c2ecf20Sopenharmony_ci if (pto && pt_entry_isvalid(pto[px])) 2988c2ecf20Sopenharmony_ci phys = pto[px] & ZPCI_PTE_ADDR_MASK; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&s390_domain->dma_table_lock, flags); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci return phys; 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic size_t s390_iommu_unmap(struct iommu_domain *domain, 3078c2ecf20Sopenharmony_ci unsigned long iova, size_t size, 3088c2ecf20Sopenharmony_ci struct iommu_iotlb_gather *gather) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci struct s390_domain *s390_domain = to_s390_domain(domain); 3118c2ecf20Sopenharmony_ci int flags = ZPCI_PTE_INVALID; 3128c2ecf20Sopenharmony_ci phys_addr_t paddr; 3138c2ecf20Sopenharmony_ci int rc; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci paddr = s390_iommu_iova_to_phys(domain, iova); 3168c2ecf20Sopenharmony_ci if (!paddr) 3178c2ecf20Sopenharmony_ci return 0; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci rc = s390_iommu_update_trans(s390_domain, (unsigned long) paddr, iova, 3208c2ecf20Sopenharmony_ci size, flags); 3218c2ecf20Sopenharmony_ci if (rc) 3228c2ecf20Sopenharmony_ci return 0; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci return size; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ciint zpci_init_iommu(struct zpci_dev *zdev) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci int rc = 0; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci rc = iommu_device_sysfs_add(&zdev->iommu_dev, NULL, NULL, 3328c2ecf20Sopenharmony_ci "s390-iommu.%08x", zdev->fid); 3338c2ecf20Sopenharmony_ci if (rc) 3348c2ecf20Sopenharmony_ci goto out_err; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci iommu_device_set_ops(&zdev->iommu_dev, &s390_iommu_ops); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci rc = iommu_device_register(&zdev->iommu_dev); 3398c2ecf20Sopenharmony_ci if (rc) 3408c2ecf20Sopenharmony_ci goto out_sysfs; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci return 0; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ciout_sysfs: 3458c2ecf20Sopenharmony_ci iommu_device_sysfs_remove(&zdev->iommu_dev); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ciout_err: 3488c2ecf20Sopenharmony_ci return rc; 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_civoid zpci_destroy_iommu(struct zpci_dev *zdev) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci iommu_device_unregister(&zdev->iommu_dev); 3548c2ecf20Sopenharmony_ci iommu_device_sysfs_remove(&zdev->iommu_dev); 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic const struct iommu_ops s390_iommu_ops = { 3588c2ecf20Sopenharmony_ci .capable = s390_iommu_capable, 3598c2ecf20Sopenharmony_ci .domain_alloc = s390_domain_alloc, 3608c2ecf20Sopenharmony_ci .domain_free = s390_domain_free, 3618c2ecf20Sopenharmony_ci .attach_dev = s390_iommu_attach_device, 3628c2ecf20Sopenharmony_ci .detach_dev = s390_iommu_detach_device, 3638c2ecf20Sopenharmony_ci .map = s390_iommu_map, 3648c2ecf20Sopenharmony_ci .unmap = s390_iommu_unmap, 3658c2ecf20Sopenharmony_ci .iova_to_phys = s390_iommu_iova_to_phys, 3668c2ecf20Sopenharmony_ci .probe_device = s390_iommu_probe_device, 3678c2ecf20Sopenharmony_ci .release_device = s390_iommu_release_device, 3688c2ecf20Sopenharmony_ci .device_group = generic_device_group, 3698c2ecf20Sopenharmony_ci .pgsize_bitmap = S390_IOMMU_PGSIZES, 3708c2ecf20Sopenharmony_ci}; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic int __init s390_iommu_init(void) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci return bus_set_iommu(&pci_bus_type, &s390_iommu_ops); 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_cisubsys_initcall(s390_iommu_init); 377