18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2012
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Author(s):
68c2ecf20Sopenharmony_ci *   Jan Glauber <jang@linux.vnet.ibm.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/kernel.h>
108c2ecf20Sopenharmony_ci#include <linux/slab.h>
118c2ecf20Sopenharmony_ci#include <linux/export.h>
128c2ecf20Sopenharmony_ci#include <linux/iommu-helper.h>
138c2ecf20Sopenharmony_ci#include <linux/dma-map-ops.h>
148c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
158c2ecf20Sopenharmony_ci#include <linux/pci.h>
168c2ecf20Sopenharmony_ci#include <asm/pci_dma.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic struct kmem_cache *dma_region_table_cache;
198c2ecf20Sopenharmony_cistatic struct kmem_cache *dma_page_table_cache;
208c2ecf20Sopenharmony_cistatic int s390_iommu_strict;
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic int zpci_refresh_global(struct zpci_dev *zdev)
238c2ecf20Sopenharmony_ci{
248c2ecf20Sopenharmony_ci	return zpci_refresh_trans((u64) zdev->fh << 32, zdev->start_dma,
258c2ecf20Sopenharmony_ci				  zdev->iommu_pages * PAGE_SIZE);
268c2ecf20Sopenharmony_ci}
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ciunsigned long *dma_alloc_cpu_table(void)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	unsigned long *table, *entry;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	table = kmem_cache_alloc(dma_region_table_cache, GFP_ATOMIC);
338c2ecf20Sopenharmony_ci	if (!table)
348c2ecf20Sopenharmony_ci		return NULL;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	for (entry = table; entry < table + ZPCI_TABLE_ENTRIES; entry++)
378c2ecf20Sopenharmony_ci		*entry = ZPCI_TABLE_INVALID;
388c2ecf20Sopenharmony_ci	return table;
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic void dma_free_cpu_table(void *table)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	kmem_cache_free(dma_region_table_cache, table);
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic unsigned long *dma_alloc_page_table(void)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	unsigned long *table, *entry;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	table = kmem_cache_alloc(dma_page_table_cache, GFP_ATOMIC);
518c2ecf20Sopenharmony_ci	if (!table)
528c2ecf20Sopenharmony_ci		return NULL;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	for (entry = table; entry < table + ZPCI_PT_ENTRIES; entry++)
558c2ecf20Sopenharmony_ci		*entry = ZPCI_PTE_INVALID;
568c2ecf20Sopenharmony_ci	return table;
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic void dma_free_page_table(void *table)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	kmem_cache_free(dma_page_table_cache, table);
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic unsigned long *dma_get_seg_table_origin(unsigned long *entry)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	unsigned long *sto;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	if (reg_entry_isvalid(*entry))
698c2ecf20Sopenharmony_ci		sto = get_rt_sto(*entry);
708c2ecf20Sopenharmony_ci	else {
718c2ecf20Sopenharmony_ci		sto = dma_alloc_cpu_table();
728c2ecf20Sopenharmony_ci		if (!sto)
738c2ecf20Sopenharmony_ci			return NULL;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci		set_rt_sto(entry, sto);
768c2ecf20Sopenharmony_ci		validate_rt_entry(entry);
778c2ecf20Sopenharmony_ci		entry_clr_protected(entry);
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci	return sto;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic unsigned long *dma_get_page_table_origin(unsigned long *entry)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	unsigned long *pto;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	if (reg_entry_isvalid(*entry))
878c2ecf20Sopenharmony_ci		pto = get_st_pto(*entry);
888c2ecf20Sopenharmony_ci	else {
898c2ecf20Sopenharmony_ci		pto = dma_alloc_page_table();
908c2ecf20Sopenharmony_ci		if (!pto)
918c2ecf20Sopenharmony_ci			return NULL;
928c2ecf20Sopenharmony_ci		set_st_pto(entry, pto);
938c2ecf20Sopenharmony_ci		validate_st_entry(entry);
948c2ecf20Sopenharmony_ci		entry_clr_protected(entry);
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci	return pto;
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ciunsigned long *dma_walk_cpu_trans(unsigned long *rto, dma_addr_t dma_addr)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	unsigned long *sto, *pto;
1028c2ecf20Sopenharmony_ci	unsigned int rtx, sx, px;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	rtx = calc_rtx(dma_addr);
1058c2ecf20Sopenharmony_ci	sto = dma_get_seg_table_origin(&rto[rtx]);
1068c2ecf20Sopenharmony_ci	if (!sto)
1078c2ecf20Sopenharmony_ci		return NULL;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	sx = calc_sx(dma_addr);
1108c2ecf20Sopenharmony_ci	pto = dma_get_page_table_origin(&sto[sx]);
1118c2ecf20Sopenharmony_ci	if (!pto)
1128c2ecf20Sopenharmony_ci		return NULL;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	px = calc_px(dma_addr);
1158c2ecf20Sopenharmony_ci	return &pto[px];
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_civoid dma_update_cpu_trans(unsigned long *entry, void *page_addr, int flags)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	if (flags & ZPCI_PTE_INVALID) {
1218c2ecf20Sopenharmony_ci		invalidate_pt_entry(entry);
1228c2ecf20Sopenharmony_ci	} else {
1238c2ecf20Sopenharmony_ci		set_pt_pfaa(entry, page_addr);
1248c2ecf20Sopenharmony_ci		validate_pt_entry(entry);
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	if (flags & ZPCI_TABLE_PROTECTED)
1288c2ecf20Sopenharmony_ci		entry_set_protected(entry);
1298c2ecf20Sopenharmony_ci	else
1308c2ecf20Sopenharmony_ci		entry_clr_protected(entry);
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic int __dma_update_trans(struct zpci_dev *zdev, unsigned long pa,
1348c2ecf20Sopenharmony_ci			      dma_addr_t dma_addr, size_t size, int flags)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	unsigned int nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
1378c2ecf20Sopenharmony_ci	u8 *page_addr = (u8 *) (pa & PAGE_MASK);
1388c2ecf20Sopenharmony_ci	unsigned long irq_flags;
1398c2ecf20Sopenharmony_ci	unsigned long *entry;
1408c2ecf20Sopenharmony_ci	int i, rc = 0;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	if (!nr_pages)
1438c2ecf20Sopenharmony_ci		return -EINVAL;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	spin_lock_irqsave(&zdev->dma_table_lock, irq_flags);
1468c2ecf20Sopenharmony_ci	if (!zdev->dma_table) {
1478c2ecf20Sopenharmony_ci		rc = -EINVAL;
1488c2ecf20Sopenharmony_ci		goto out_unlock;
1498c2ecf20Sopenharmony_ci	}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	for (i = 0; i < nr_pages; i++) {
1528c2ecf20Sopenharmony_ci		entry = dma_walk_cpu_trans(zdev->dma_table, dma_addr);
1538c2ecf20Sopenharmony_ci		if (!entry) {
1548c2ecf20Sopenharmony_ci			rc = -ENOMEM;
1558c2ecf20Sopenharmony_ci			goto undo_cpu_trans;
1568c2ecf20Sopenharmony_ci		}
1578c2ecf20Sopenharmony_ci		dma_update_cpu_trans(entry, page_addr, flags);
1588c2ecf20Sopenharmony_ci		page_addr += PAGE_SIZE;
1598c2ecf20Sopenharmony_ci		dma_addr += PAGE_SIZE;
1608c2ecf20Sopenharmony_ci	}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ciundo_cpu_trans:
1638c2ecf20Sopenharmony_ci	if (rc && ((flags & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID)) {
1648c2ecf20Sopenharmony_ci		flags = ZPCI_PTE_INVALID;
1658c2ecf20Sopenharmony_ci		while (i-- > 0) {
1668c2ecf20Sopenharmony_ci			page_addr -= PAGE_SIZE;
1678c2ecf20Sopenharmony_ci			dma_addr -= PAGE_SIZE;
1688c2ecf20Sopenharmony_ci			entry = dma_walk_cpu_trans(zdev->dma_table, dma_addr);
1698c2ecf20Sopenharmony_ci			if (!entry)
1708c2ecf20Sopenharmony_ci				break;
1718c2ecf20Sopenharmony_ci			dma_update_cpu_trans(entry, page_addr, flags);
1728c2ecf20Sopenharmony_ci		}
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ciout_unlock:
1758c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&zdev->dma_table_lock, irq_flags);
1768c2ecf20Sopenharmony_ci	return rc;
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic int __dma_purge_tlb(struct zpci_dev *zdev, dma_addr_t dma_addr,
1808c2ecf20Sopenharmony_ci			   size_t size, int flags)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	unsigned long irqflags;
1838c2ecf20Sopenharmony_ci	int ret;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	/*
1868c2ecf20Sopenharmony_ci	 * With zdev->tlb_refresh == 0, rpcit is not required to establish new
1878c2ecf20Sopenharmony_ci	 * translations when previously invalid translation-table entries are
1888c2ecf20Sopenharmony_ci	 * validated. With lazy unmap, rpcit is skipped for previously valid
1898c2ecf20Sopenharmony_ci	 * entries, but a global rpcit is then required before any address can
1908c2ecf20Sopenharmony_ci	 * be re-used, i.e. after each iommu bitmap wrap-around.
1918c2ecf20Sopenharmony_ci	 */
1928c2ecf20Sopenharmony_ci	if ((flags & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID) {
1938c2ecf20Sopenharmony_ci		if (!zdev->tlb_refresh)
1948c2ecf20Sopenharmony_ci			return 0;
1958c2ecf20Sopenharmony_ci	} else {
1968c2ecf20Sopenharmony_ci		if (!s390_iommu_strict)
1978c2ecf20Sopenharmony_ci			return 0;
1988c2ecf20Sopenharmony_ci	}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	ret = zpci_refresh_trans((u64) zdev->fh << 32, dma_addr,
2018c2ecf20Sopenharmony_ci				 PAGE_ALIGN(size));
2028c2ecf20Sopenharmony_ci	if (ret == -ENOMEM && !s390_iommu_strict) {
2038c2ecf20Sopenharmony_ci		/* enable the hypervisor to free some resources */
2048c2ecf20Sopenharmony_ci		if (zpci_refresh_global(zdev))
2058c2ecf20Sopenharmony_ci			goto out;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci		spin_lock_irqsave(&zdev->iommu_bitmap_lock, irqflags);
2088c2ecf20Sopenharmony_ci		bitmap_andnot(zdev->iommu_bitmap, zdev->iommu_bitmap,
2098c2ecf20Sopenharmony_ci			      zdev->lazy_bitmap, zdev->iommu_pages);
2108c2ecf20Sopenharmony_ci		bitmap_zero(zdev->lazy_bitmap, zdev->iommu_pages);
2118c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&zdev->iommu_bitmap_lock, irqflags);
2128c2ecf20Sopenharmony_ci		ret = 0;
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ciout:
2158c2ecf20Sopenharmony_ci	return ret;
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_cistatic int dma_update_trans(struct zpci_dev *zdev, unsigned long pa,
2198c2ecf20Sopenharmony_ci			    dma_addr_t dma_addr, size_t size, int flags)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	int rc;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	rc = __dma_update_trans(zdev, pa, dma_addr, size, flags);
2248c2ecf20Sopenharmony_ci	if (rc)
2258c2ecf20Sopenharmony_ci		return rc;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	rc = __dma_purge_tlb(zdev, dma_addr, size, flags);
2288c2ecf20Sopenharmony_ci	if (rc && ((flags & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID))
2298c2ecf20Sopenharmony_ci		__dma_update_trans(zdev, pa, dma_addr, size, ZPCI_PTE_INVALID);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	return rc;
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_civoid dma_free_seg_table(unsigned long entry)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	unsigned long *sto = get_rt_sto(entry);
2378c2ecf20Sopenharmony_ci	int sx;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	for (sx = 0; sx < ZPCI_TABLE_ENTRIES; sx++)
2408c2ecf20Sopenharmony_ci		if (reg_entry_isvalid(sto[sx]))
2418c2ecf20Sopenharmony_ci			dma_free_page_table(get_st_pto(sto[sx]));
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	dma_free_cpu_table(sto);
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_civoid dma_cleanup_tables(unsigned long *table)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	int rtx;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	if (!table)
2518c2ecf20Sopenharmony_ci		return;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	for (rtx = 0; rtx < ZPCI_TABLE_ENTRIES; rtx++)
2548c2ecf20Sopenharmony_ci		if (reg_entry_isvalid(table[rtx]))
2558c2ecf20Sopenharmony_ci			dma_free_seg_table(table[rtx]);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	dma_free_cpu_table(table);
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic unsigned long __dma_alloc_iommu(struct device *dev,
2618c2ecf20Sopenharmony_ci				       unsigned long start, int size)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	return iommu_area_alloc(zdev->iommu_bitmap, zdev->iommu_pages,
2668c2ecf20Sopenharmony_ci				start, size, zdev->start_dma >> PAGE_SHIFT,
2678c2ecf20Sopenharmony_ci				dma_get_seg_boundary_nr_pages(dev, PAGE_SHIFT),
2688c2ecf20Sopenharmony_ci				0);
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_cistatic dma_addr_t dma_alloc_address(struct device *dev, int size)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
2748c2ecf20Sopenharmony_ci	unsigned long offset, flags;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	spin_lock_irqsave(&zdev->iommu_bitmap_lock, flags);
2778c2ecf20Sopenharmony_ci	offset = __dma_alloc_iommu(dev, zdev->next_bit, size);
2788c2ecf20Sopenharmony_ci	if (offset == -1) {
2798c2ecf20Sopenharmony_ci		if (!s390_iommu_strict) {
2808c2ecf20Sopenharmony_ci			/* global flush before DMA addresses are reused */
2818c2ecf20Sopenharmony_ci			if (zpci_refresh_global(zdev))
2828c2ecf20Sopenharmony_ci				goto out_error;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci			bitmap_andnot(zdev->iommu_bitmap, zdev->iommu_bitmap,
2858c2ecf20Sopenharmony_ci				      zdev->lazy_bitmap, zdev->iommu_pages);
2868c2ecf20Sopenharmony_ci			bitmap_zero(zdev->lazy_bitmap, zdev->iommu_pages);
2878c2ecf20Sopenharmony_ci		}
2888c2ecf20Sopenharmony_ci		/* wrap-around */
2898c2ecf20Sopenharmony_ci		offset = __dma_alloc_iommu(dev, 0, size);
2908c2ecf20Sopenharmony_ci		if (offset == -1)
2918c2ecf20Sopenharmony_ci			goto out_error;
2928c2ecf20Sopenharmony_ci	}
2938c2ecf20Sopenharmony_ci	zdev->next_bit = offset + size;
2948c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&zdev->iommu_bitmap_lock, flags);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	return zdev->start_dma + offset * PAGE_SIZE;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ciout_error:
2998c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&zdev->iommu_bitmap_lock, flags);
3008c2ecf20Sopenharmony_ci	return DMA_MAPPING_ERROR;
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic void dma_free_address(struct device *dev, dma_addr_t dma_addr, int size)
3048c2ecf20Sopenharmony_ci{
3058c2ecf20Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
3068c2ecf20Sopenharmony_ci	unsigned long flags, offset;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	offset = (dma_addr - zdev->start_dma) >> PAGE_SHIFT;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	spin_lock_irqsave(&zdev->iommu_bitmap_lock, flags);
3118c2ecf20Sopenharmony_ci	if (!zdev->iommu_bitmap)
3128c2ecf20Sopenharmony_ci		goto out;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	if (s390_iommu_strict)
3158c2ecf20Sopenharmony_ci		bitmap_clear(zdev->iommu_bitmap, offset, size);
3168c2ecf20Sopenharmony_ci	else
3178c2ecf20Sopenharmony_ci		bitmap_set(zdev->lazy_bitmap, offset, size);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ciout:
3208c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&zdev->iommu_bitmap_lock, flags);
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_cistatic inline void zpci_err_dma(unsigned long rc, unsigned long addr)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci	struct {
3268c2ecf20Sopenharmony_ci		unsigned long rc;
3278c2ecf20Sopenharmony_ci		unsigned long addr;
3288c2ecf20Sopenharmony_ci	} __packed data = {rc, addr};
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	zpci_err_hex(&data, sizeof(data));
3318c2ecf20Sopenharmony_ci}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page,
3348c2ecf20Sopenharmony_ci				     unsigned long offset, size_t size,
3358c2ecf20Sopenharmony_ci				     enum dma_data_direction direction,
3368c2ecf20Sopenharmony_ci				     unsigned long attrs)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
3398c2ecf20Sopenharmony_ci	unsigned long pa = page_to_phys(page) + offset;
3408c2ecf20Sopenharmony_ci	int flags = ZPCI_PTE_VALID;
3418c2ecf20Sopenharmony_ci	unsigned long nr_pages;
3428c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
3438c2ecf20Sopenharmony_ci	int ret;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	/* This rounds up number of pages based on size and offset */
3468c2ecf20Sopenharmony_ci	nr_pages = iommu_num_pages(pa, size, PAGE_SIZE);
3478c2ecf20Sopenharmony_ci	dma_addr = dma_alloc_address(dev, nr_pages);
3488c2ecf20Sopenharmony_ci	if (dma_addr == DMA_MAPPING_ERROR) {
3498c2ecf20Sopenharmony_ci		ret = -ENOSPC;
3508c2ecf20Sopenharmony_ci		goto out_err;
3518c2ecf20Sopenharmony_ci	}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	/* Use rounded up size */
3548c2ecf20Sopenharmony_ci	size = nr_pages * PAGE_SIZE;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	if (direction == DMA_NONE || direction == DMA_TO_DEVICE)
3578c2ecf20Sopenharmony_ci		flags |= ZPCI_TABLE_PROTECTED;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	ret = dma_update_trans(zdev, pa, dma_addr, size, flags);
3608c2ecf20Sopenharmony_ci	if (ret)
3618c2ecf20Sopenharmony_ci		goto out_free;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	atomic64_add(nr_pages, &zdev->mapped_pages);
3648c2ecf20Sopenharmony_ci	return dma_addr + (offset & ~PAGE_MASK);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ciout_free:
3678c2ecf20Sopenharmony_ci	dma_free_address(dev, dma_addr, nr_pages);
3688c2ecf20Sopenharmony_ciout_err:
3698c2ecf20Sopenharmony_ci	zpci_err("map error:\n");
3708c2ecf20Sopenharmony_ci	zpci_err_dma(ret, pa);
3718c2ecf20Sopenharmony_ci	return DMA_MAPPING_ERROR;
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_cistatic void s390_dma_unmap_pages(struct device *dev, dma_addr_t dma_addr,
3758c2ecf20Sopenharmony_ci				 size_t size, enum dma_data_direction direction,
3768c2ecf20Sopenharmony_ci				 unsigned long attrs)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
3798c2ecf20Sopenharmony_ci	int npages, ret;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	npages = iommu_num_pages(dma_addr, size, PAGE_SIZE);
3828c2ecf20Sopenharmony_ci	dma_addr = dma_addr & PAGE_MASK;
3838c2ecf20Sopenharmony_ci	ret = dma_update_trans(zdev, 0, dma_addr, npages * PAGE_SIZE,
3848c2ecf20Sopenharmony_ci			       ZPCI_PTE_INVALID);
3858c2ecf20Sopenharmony_ci	if (ret) {
3868c2ecf20Sopenharmony_ci		zpci_err("unmap error:\n");
3878c2ecf20Sopenharmony_ci		zpci_err_dma(ret, dma_addr);
3888c2ecf20Sopenharmony_ci		return;
3898c2ecf20Sopenharmony_ci	}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	atomic64_add(npages, &zdev->unmapped_pages);
3928c2ecf20Sopenharmony_ci	dma_free_address(dev, dma_addr, npages);
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_cistatic void *s390_dma_alloc(struct device *dev, size_t size,
3968c2ecf20Sopenharmony_ci			    dma_addr_t *dma_handle, gfp_t flag,
3978c2ecf20Sopenharmony_ci			    unsigned long attrs)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
4008c2ecf20Sopenharmony_ci	struct page *page;
4018c2ecf20Sopenharmony_ci	unsigned long pa;
4028c2ecf20Sopenharmony_ci	dma_addr_t map;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	size = PAGE_ALIGN(size);
4058c2ecf20Sopenharmony_ci	page = alloc_pages(flag | __GFP_ZERO, get_order(size));
4068c2ecf20Sopenharmony_ci	if (!page)
4078c2ecf20Sopenharmony_ci		return NULL;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	pa = page_to_phys(page);
4108c2ecf20Sopenharmony_ci	map = s390_dma_map_pages(dev, page, 0, size, DMA_BIDIRECTIONAL, 0);
4118c2ecf20Sopenharmony_ci	if (dma_mapping_error(dev, map)) {
4128c2ecf20Sopenharmony_ci		free_pages(pa, get_order(size));
4138c2ecf20Sopenharmony_ci		return NULL;
4148c2ecf20Sopenharmony_ci	}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	atomic64_add(size / PAGE_SIZE, &zdev->allocated_pages);
4178c2ecf20Sopenharmony_ci	if (dma_handle)
4188c2ecf20Sopenharmony_ci		*dma_handle = map;
4198c2ecf20Sopenharmony_ci	return (void *) pa;
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cistatic void s390_dma_free(struct device *dev, size_t size,
4238c2ecf20Sopenharmony_ci			  void *pa, dma_addr_t dma_handle,
4248c2ecf20Sopenharmony_ci			  unsigned long attrs)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	size = PAGE_ALIGN(size);
4298c2ecf20Sopenharmony_ci	atomic64_sub(size / PAGE_SIZE, &zdev->allocated_pages);
4308c2ecf20Sopenharmony_ci	s390_dma_unmap_pages(dev, dma_handle, size, DMA_BIDIRECTIONAL, 0);
4318c2ecf20Sopenharmony_ci	free_pages((unsigned long) pa, get_order(size));
4328c2ecf20Sopenharmony_ci}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci/* Map a segment into a contiguous dma address area */
4358c2ecf20Sopenharmony_cistatic int __s390_dma_map_sg(struct device *dev, struct scatterlist *sg,
4368c2ecf20Sopenharmony_ci			     size_t size, dma_addr_t *handle,
4378c2ecf20Sopenharmony_ci			     enum dma_data_direction dir)
4388c2ecf20Sopenharmony_ci{
4398c2ecf20Sopenharmony_ci	unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
4408c2ecf20Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
4418c2ecf20Sopenharmony_ci	dma_addr_t dma_addr_base, dma_addr;
4428c2ecf20Sopenharmony_ci	int flags = ZPCI_PTE_VALID;
4438c2ecf20Sopenharmony_ci	struct scatterlist *s;
4448c2ecf20Sopenharmony_ci	unsigned long pa = 0;
4458c2ecf20Sopenharmony_ci	int ret;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	dma_addr_base = dma_alloc_address(dev, nr_pages);
4488c2ecf20Sopenharmony_ci	if (dma_addr_base == DMA_MAPPING_ERROR)
4498c2ecf20Sopenharmony_ci		return -ENOMEM;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	dma_addr = dma_addr_base;
4528c2ecf20Sopenharmony_ci	if (dir == DMA_NONE || dir == DMA_TO_DEVICE)
4538c2ecf20Sopenharmony_ci		flags |= ZPCI_TABLE_PROTECTED;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	for (s = sg; dma_addr < dma_addr_base + size; s = sg_next(s)) {
4568c2ecf20Sopenharmony_ci		pa = page_to_phys(sg_page(s));
4578c2ecf20Sopenharmony_ci		ret = __dma_update_trans(zdev, pa, dma_addr,
4588c2ecf20Sopenharmony_ci					 s->offset + s->length, flags);
4598c2ecf20Sopenharmony_ci		if (ret)
4608c2ecf20Sopenharmony_ci			goto unmap;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci		dma_addr += s->offset + s->length;
4638c2ecf20Sopenharmony_ci	}
4648c2ecf20Sopenharmony_ci	ret = __dma_purge_tlb(zdev, dma_addr_base, size, flags);
4658c2ecf20Sopenharmony_ci	if (ret)
4668c2ecf20Sopenharmony_ci		goto unmap;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	*handle = dma_addr_base;
4698c2ecf20Sopenharmony_ci	atomic64_add(nr_pages, &zdev->mapped_pages);
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	return ret;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ciunmap:
4748c2ecf20Sopenharmony_ci	dma_update_trans(zdev, 0, dma_addr_base, dma_addr - dma_addr_base,
4758c2ecf20Sopenharmony_ci			 ZPCI_PTE_INVALID);
4768c2ecf20Sopenharmony_ci	dma_free_address(dev, dma_addr_base, nr_pages);
4778c2ecf20Sopenharmony_ci	zpci_err("map error:\n");
4788c2ecf20Sopenharmony_ci	zpci_err_dma(ret, pa);
4798c2ecf20Sopenharmony_ci	return ret;
4808c2ecf20Sopenharmony_ci}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_cistatic int s390_dma_map_sg(struct device *dev, struct scatterlist *sg,
4838c2ecf20Sopenharmony_ci			   int nr_elements, enum dma_data_direction dir,
4848c2ecf20Sopenharmony_ci			   unsigned long attrs)
4858c2ecf20Sopenharmony_ci{
4868c2ecf20Sopenharmony_ci	struct scatterlist *s = sg, *start = sg, *dma = sg;
4878c2ecf20Sopenharmony_ci	unsigned int max = dma_get_max_seg_size(dev);
4888c2ecf20Sopenharmony_ci	unsigned int size = s->offset + s->length;
4898c2ecf20Sopenharmony_ci	unsigned int offset = s->offset;
4908c2ecf20Sopenharmony_ci	int count = 0, i;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	for (i = 1; i < nr_elements; i++) {
4938c2ecf20Sopenharmony_ci		s = sg_next(s);
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci		s->dma_address = DMA_MAPPING_ERROR;
4968c2ecf20Sopenharmony_ci		s->dma_length = 0;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci		if (s->offset || (size & ~PAGE_MASK) ||
4998c2ecf20Sopenharmony_ci		    size + s->length > max) {
5008c2ecf20Sopenharmony_ci			if (__s390_dma_map_sg(dev, start, size,
5018c2ecf20Sopenharmony_ci					      &dma->dma_address, dir))
5028c2ecf20Sopenharmony_ci				goto unmap;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci			dma->dma_address += offset;
5058c2ecf20Sopenharmony_ci			dma->dma_length = size - offset;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci			size = offset = s->offset;
5088c2ecf20Sopenharmony_ci			start = s;
5098c2ecf20Sopenharmony_ci			dma = sg_next(dma);
5108c2ecf20Sopenharmony_ci			count++;
5118c2ecf20Sopenharmony_ci		}
5128c2ecf20Sopenharmony_ci		size += s->length;
5138c2ecf20Sopenharmony_ci	}
5148c2ecf20Sopenharmony_ci	if (__s390_dma_map_sg(dev, start, size, &dma->dma_address, dir))
5158c2ecf20Sopenharmony_ci		goto unmap;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	dma->dma_address += offset;
5188c2ecf20Sopenharmony_ci	dma->dma_length = size - offset;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	return count + 1;
5218c2ecf20Sopenharmony_ciunmap:
5228c2ecf20Sopenharmony_ci	for_each_sg(sg, s, count, i)
5238c2ecf20Sopenharmony_ci		s390_dma_unmap_pages(dev, sg_dma_address(s), sg_dma_len(s),
5248c2ecf20Sopenharmony_ci				     dir, attrs);
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	return 0;
5278c2ecf20Sopenharmony_ci}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_cistatic void s390_dma_unmap_sg(struct device *dev, struct scatterlist *sg,
5308c2ecf20Sopenharmony_ci			      int nr_elements, enum dma_data_direction dir,
5318c2ecf20Sopenharmony_ci			      unsigned long attrs)
5328c2ecf20Sopenharmony_ci{
5338c2ecf20Sopenharmony_ci	struct scatterlist *s;
5348c2ecf20Sopenharmony_ci	int i;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	for_each_sg(sg, s, nr_elements, i) {
5378c2ecf20Sopenharmony_ci		if (s->dma_length)
5388c2ecf20Sopenharmony_ci			s390_dma_unmap_pages(dev, s->dma_address, s->dma_length,
5398c2ecf20Sopenharmony_ci					     dir, attrs);
5408c2ecf20Sopenharmony_ci		s->dma_address = 0;
5418c2ecf20Sopenharmony_ci		s->dma_length = 0;
5428c2ecf20Sopenharmony_ci	}
5438c2ecf20Sopenharmony_ci}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_cistatic unsigned long *bitmap_vzalloc(size_t bits, gfp_t flags)
5468c2ecf20Sopenharmony_ci{
5478c2ecf20Sopenharmony_ci	size_t n = BITS_TO_LONGS(bits);
5488c2ecf20Sopenharmony_ci	size_t bytes;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	if (unlikely(check_mul_overflow(n, sizeof(unsigned long), &bytes)))
5518c2ecf20Sopenharmony_ci		return NULL;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	return vzalloc(bytes);
5548c2ecf20Sopenharmony_ci}
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ciint zpci_dma_init_device(struct zpci_dev *zdev)
5578c2ecf20Sopenharmony_ci{
5588c2ecf20Sopenharmony_ci	int rc;
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	/*
5618c2ecf20Sopenharmony_ci	 * At this point, if the device is part of an IOMMU domain, this would
5628c2ecf20Sopenharmony_ci	 * be a strong hint towards a bug in the IOMMU API (common) code and/or
5638c2ecf20Sopenharmony_ci	 * simultaneous access via IOMMU and DMA API. So let's issue a warning.
5648c2ecf20Sopenharmony_ci	 */
5658c2ecf20Sopenharmony_ci	WARN_ON(zdev->s390_domain);
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	spin_lock_init(&zdev->iommu_bitmap_lock);
5688c2ecf20Sopenharmony_ci	spin_lock_init(&zdev->dma_table_lock);
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	zdev->dma_table = dma_alloc_cpu_table();
5718c2ecf20Sopenharmony_ci	if (!zdev->dma_table) {
5728c2ecf20Sopenharmony_ci		rc = -ENOMEM;
5738c2ecf20Sopenharmony_ci		goto out;
5748c2ecf20Sopenharmony_ci	}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	/*
5778c2ecf20Sopenharmony_ci	 * Restrict the iommu bitmap size to the minimum of the following:
5788c2ecf20Sopenharmony_ci	 * - main memory size
5798c2ecf20Sopenharmony_ci	 * - 3-level pagetable address limit minus start_dma offset
5808c2ecf20Sopenharmony_ci	 * - DMA address range allowed by the hardware (clp query pci fn)
5818c2ecf20Sopenharmony_ci	 *
5828c2ecf20Sopenharmony_ci	 * Also set zdev->end_dma to the actual end address of the usable
5838c2ecf20Sopenharmony_ci	 * range, instead of the theoretical maximum as reported by hardware.
5848c2ecf20Sopenharmony_ci	 */
5858c2ecf20Sopenharmony_ci	zdev->start_dma = PAGE_ALIGN(zdev->start_dma);
5868c2ecf20Sopenharmony_ci	zdev->iommu_size = min3((u64) high_memory,
5878c2ecf20Sopenharmony_ci				ZPCI_TABLE_SIZE_RT - zdev->start_dma,
5888c2ecf20Sopenharmony_ci				zdev->end_dma - zdev->start_dma + 1);
5898c2ecf20Sopenharmony_ci	zdev->end_dma = zdev->start_dma + zdev->iommu_size - 1;
5908c2ecf20Sopenharmony_ci	zdev->iommu_pages = zdev->iommu_size >> PAGE_SHIFT;
5918c2ecf20Sopenharmony_ci	zdev->iommu_bitmap = bitmap_vzalloc(zdev->iommu_pages, GFP_KERNEL);
5928c2ecf20Sopenharmony_ci	if (!zdev->iommu_bitmap) {
5938c2ecf20Sopenharmony_ci		rc = -ENOMEM;
5948c2ecf20Sopenharmony_ci		goto free_dma_table;
5958c2ecf20Sopenharmony_ci	}
5968c2ecf20Sopenharmony_ci	if (!s390_iommu_strict) {
5978c2ecf20Sopenharmony_ci		zdev->lazy_bitmap = bitmap_vzalloc(zdev->iommu_pages, GFP_KERNEL);
5988c2ecf20Sopenharmony_ci		if (!zdev->lazy_bitmap) {
5998c2ecf20Sopenharmony_ci			rc = -ENOMEM;
6008c2ecf20Sopenharmony_ci			goto free_bitmap;
6018c2ecf20Sopenharmony_ci		}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	}
6048c2ecf20Sopenharmony_ci	rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
6058c2ecf20Sopenharmony_ci				(u64) zdev->dma_table);
6068c2ecf20Sopenharmony_ci	if (rc)
6078c2ecf20Sopenharmony_ci		goto free_bitmap;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	return 0;
6108c2ecf20Sopenharmony_cifree_bitmap:
6118c2ecf20Sopenharmony_ci	vfree(zdev->iommu_bitmap);
6128c2ecf20Sopenharmony_ci	zdev->iommu_bitmap = NULL;
6138c2ecf20Sopenharmony_ci	vfree(zdev->lazy_bitmap);
6148c2ecf20Sopenharmony_ci	zdev->lazy_bitmap = NULL;
6158c2ecf20Sopenharmony_cifree_dma_table:
6168c2ecf20Sopenharmony_ci	dma_free_cpu_table(zdev->dma_table);
6178c2ecf20Sopenharmony_ci	zdev->dma_table = NULL;
6188c2ecf20Sopenharmony_ciout:
6198c2ecf20Sopenharmony_ci	return rc;
6208c2ecf20Sopenharmony_ci}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_civoid zpci_dma_exit_device(struct zpci_dev *zdev)
6238c2ecf20Sopenharmony_ci{
6248c2ecf20Sopenharmony_ci	/*
6258c2ecf20Sopenharmony_ci	 * At this point, if the device is part of an IOMMU domain, this would
6268c2ecf20Sopenharmony_ci	 * be a strong hint towards a bug in the IOMMU API (common) code and/or
6278c2ecf20Sopenharmony_ci	 * simultaneous access via IOMMU and DMA API. So let's issue a warning.
6288c2ecf20Sopenharmony_ci	 */
6298c2ecf20Sopenharmony_ci	WARN_ON(zdev->s390_domain);
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	if (zpci_unregister_ioat(zdev, 0))
6328c2ecf20Sopenharmony_ci		return;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	dma_cleanup_tables(zdev->dma_table);
6358c2ecf20Sopenharmony_ci	zdev->dma_table = NULL;
6368c2ecf20Sopenharmony_ci	vfree(zdev->iommu_bitmap);
6378c2ecf20Sopenharmony_ci	zdev->iommu_bitmap = NULL;
6388c2ecf20Sopenharmony_ci	vfree(zdev->lazy_bitmap);
6398c2ecf20Sopenharmony_ci	zdev->lazy_bitmap = NULL;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	zdev->next_bit = 0;
6428c2ecf20Sopenharmony_ci}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_cistatic int __init dma_alloc_cpu_table_caches(void)
6458c2ecf20Sopenharmony_ci{
6468c2ecf20Sopenharmony_ci	dma_region_table_cache = kmem_cache_create("PCI_DMA_region_tables",
6478c2ecf20Sopenharmony_ci					ZPCI_TABLE_SIZE, ZPCI_TABLE_ALIGN,
6488c2ecf20Sopenharmony_ci					0, NULL);
6498c2ecf20Sopenharmony_ci	if (!dma_region_table_cache)
6508c2ecf20Sopenharmony_ci		return -ENOMEM;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	dma_page_table_cache = kmem_cache_create("PCI_DMA_page_tables",
6538c2ecf20Sopenharmony_ci					ZPCI_PT_SIZE, ZPCI_PT_ALIGN,
6548c2ecf20Sopenharmony_ci					0, NULL);
6558c2ecf20Sopenharmony_ci	if (!dma_page_table_cache) {
6568c2ecf20Sopenharmony_ci		kmem_cache_destroy(dma_region_table_cache);
6578c2ecf20Sopenharmony_ci		return -ENOMEM;
6588c2ecf20Sopenharmony_ci	}
6598c2ecf20Sopenharmony_ci	return 0;
6608c2ecf20Sopenharmony_ci}
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ciint __init zpci_dma_init(void)
6638c2ecf20Sopenharmony_ci{
6648c2ecf20Sopenharmony_ci	return dma_alloc_cpu_table_caches();
6658c2ecf20Sopenharmony_ci}
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_civoid zpci_dma_exit(void)
6688c2ecf20Sopenharmony_ci{
6698c2ecf20Sopenharmony_ci	kmem_cache_destroy(dma_page_table_cache);
6708c2ecf20Sopenharmony_ci	kmem_cache_destroy(dma_region_table_cache);
6718c2ecf20Sopenharmony_ci}
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ciconst struct dma_map_ops s390_pci_dma_ops = {
6748c2ecf20Sopenharmony_ci	.alloc		= s390_dma_alloc,
6758c2ecf20Sopenharmony_ci	.free		= s390_dma_free,
6768c2ecf20Sopenharmony_ci	.map_sg		= s390_dma_map_sg,
6778c2ecf20Sopenharmony_ci	.unmap_sg	= s390_dma_unmap_sg,
6788c2ecf20Sopenharmony_ci	.map_page	= s390_dma_map_pages,
6798c2ecf20Sopenharmony_ci	.unmap_page	= s390_dma_unmap_pages,
6808c2ecf20Sopenharmony_ci	.mmap		= dma_common_mmap,
6818c2ecf20Sopenharmony_ci	.get_sgtable	= dma_common_get_sgtable,
6828c2ecf20Sopenharmony_ci	.alloc_pages	= dma_common_alloc_pages,
6838c2ecf20Sopenharmony_ci	.free_pages	= dma_common_free_pages,
6848c2ecf20Sopenharmony_ci	/* dma_supported is unconditionally true without a callback */
6858c2ecf20Sopenharmony_ci};
6868c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(s390_pci_dma_ops);
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_cistatic int __init s390_iommu_setup(char *str)
6898c2ecf20Sopenharmony_ci{
6908c2ecf20Sopenharmony_ci	if (!strcmp(str, "strict"))
6918c2ecf20Sopenharmony_ci		s390_iommu_strict = 1;
6928c2ecf20Sopenharmony_ci	return 1;
6938c2ecf20Sopenharmony_ci}
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci__setup("s390_iommu=", s390_iommu_setup);
696