Commit 347d81b6 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'dma-mapping-5.11' of git://git.infradead.org/users/hch/dma-mapping

Pull dma-mapping updates from Christoph Hellwig:

 - support for a partial IOMMU bypass (Alexey Kardashevskiy)

 - add a DMA API benchmark (Barry Song)

 - misc fixes (Tiezhu Yang, tangjianqiang)

* tag 'dma-mapping-5.11' of git://git.infradead.org/users/hch/dma-mapping:
  selftests/dma: add test application for DMA_MAP_BENCHMARK
  dma-mapping: add benchmark support for streaming DMA APIs
  dma-contiguous: fix a typo error in a comment
  dma-pool: no need to check return value of debugfs_create functions
  powerpc/dma: Fallback to dma_ops when persistent memory present
  dma-mapping: Allow mixing bypass and mapped DMA operation
parents 4f06f210 76793257
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -5297,6 +5297,12 @@ F: include/linux/dma-mapping.h
F:	include/linux/dma-map-ops.h
F:	kernel/dma/
DMA MAPPING BENCHMARK
M:	Barry Song <song.bao.hua@hisilicon.com>
L:	iommu@lists.linux-foundation.org
F:	kernel/dma/map_benchmark.c
F:	tools/testing/selftests/dma/
DMA-BUF HEAPS FRAMEWORK
M:	Sumit Semwal <sumit.semwal@linaro.org>
R:	Benjamin Gaignard <benjamin.gaignard@linaro.org>
+1 −0
Original line number Diff line number Diff line
@@ -161,6 +161,7 @@ config PPC
	select DCACHE_WORD_ACCESS		if PPC64 && CPU_LITTLE_ENDIAN
	select DMA_OPS				if PPC64
	select DMA_OPS_BYPASS			if PPC64
	select ARCH_HAS_DMA_MAP_DIRECT 		if PPC64 && PPC_PSERIES
	select DYNAMIC_FTRACE			if FUNCTION_TRACER
	select EDAC_ATOMIC_SCRUB
	select EDAC_SUPPORT
+69 −2
Original line number Diff line number Diff line
@@ -10,6 +10,63 @@
#include <linux/pci.h>
#include <asm/iommu.h>

#ifdef CONFIG_ARCH_HAS_DMA_MAP_DIRECT
#define can_map_direct(dev, addr) \
	((dev)->bus_dma_limit >= phys_to_dma((dev), (addr)))

bool arch_dma_map_page_direct(struct device *dev, phys_addr_t addr)
{
	if (likely(!dev->bus_dma_limit))
		return false;

	return can_map_direct(dev, addr);
}

#define is_direct_handle(dev, h) ((h) >= (dev)->archdata.dma_offset)

bool arch_dma_unmap_page_direct(struct device *dev, dma_addr_t dma_handle)
{
	if (likely(!dev->bus_dma_limit))
		return false;

	return is_direct_handle(dev, dma_handle);
}

bool arch_dma_map_sg_direct(struct device *dev, struct scatterlist *sg,
			    int nents)
{
	struct scatterlist *s;
	int i;

	if (likely(!dev->bus_dma_limit))
		return false;

	for_each_sg(sg, s, nents, i) {
		if (!can_map_direct(dev, sg_phys(s) + s->offset + s->length))
			return false;
	}

	return true;
}

bool arch_dma_unmap_sg_direct(struct device *dev, struct scatterlist *sg,
			      int nents)
{
	struct scatterlist *s;
	int i;

	if (likely(!dev->bus_dma_limit))
		return false;

	for_each_sg(sg, s, nents, i) {
		if (!is_direct_handle(dev, s->dma_address + s->length))
			return false;
	}

	return true;
}
#endif /* CONFIG_ARCH_HAS_DMA_MAP_DIRECT */

/*
 * Generic iommu implementation
 */
@@ -90,7 +147,17 @@ int dma_iommu_dma_supported(struct device *dev, u64 mask)
	struct iommu_table *tbl = get_iommu_table_base(dev);

	if (dev_is_pci(dev) && dma_iommu_bypass_supported(dev, mask)) {
		dev->dma_ops_bypass = true;
		/*
		 * dma_iommu_bypass_supported() sets dma_max when there is
		 * 1:1 mapping but it is somehow limited.
		 * ibm,pmemory is one example.
		 */
		dev->dma_ops_bypass = dev->bus_dma_limit == 0;
		if (!dev->dma_ops_bypass)
			dev_warn(dev,
				 "iommu: 64-bit OK but direct DMA is limited by %llx\n",
				 dev->bus_dma_limit);
		else
			dev_dbg(dev, "iommu: 64-bit OK, using fixed ops\n");
		return 1;
	}
+41 −10
Original line number Diff line number Diff line
@@ -839,7 +839,7 @@ static void remove_ddw(struct device_node *np, bool remove_prop)
			np, ret);
}

static u64 find_existing_ddw(struct device_node *pdn)
static u64 find_existing_ddw(struct device_node *pdn, int *window_shift)
{
	struct direct_window *window;
	const struct dynamic_dma_window_prop *direct64;
@@ -851,6 +851,7 @@ static u64 find_existing_ddw(struct device_node *pdn)
		if (window->device == pdn) {
			direct64 = window->prop;
			dma_addr = be64_to_cpu(direct64->dma_base);
			*window_shift = be32_to_cpu(direct64->window_shift);
			break;
		}
	}
@@ -1111,11 +1112,12 @@ static void reset_dma_window(struct pci_dev *dev, struct device_node *par_dn)
 */
static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
{
	int len, ret;
	int len = 0, ret;
	int max_ram_len = order_base_2(ddw_memory_hotplug_max());
	struct ddw_query_response query;
	struct ddw_create_response create;
	int page_shift;
	u64 dma_addr, max_addr;
	u64 dma_addr;
	struct device_node *dn;
	u32 ddw_avail[DDW_APPLICABLE_SIZE];
	struct direct_window *window;
@@ -1123,10 +1125,15 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
	struct dynamic_dma_window_prop *ddwprop;
	struct failed_ddw_pdn *fpdn;
	bool default_win_removed = false;
	bool pmem_present;

	dn = of_find_node_by_type(NULL, "ibm,pmemory");
	pmem_present = dn != NULL;
	of_node_put(dn);

	mutex_lock(&direct_window_init_mutex);

	dma_addr = find_existing_ddw(pdn);
	dma_addr = find_existing_ddw(pdn, &len);
	if (dma_addr != 0)
		goto out_unlock;

@@ -1212,14 +1219,29 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
	}
	/* verify the window * number of ptes will map the partition */
	/* check largest block * page size > max memory hotplug addr */
	max_addr = ddw_memory_hotplug_max();
	if (query.largest_available_block < (max_addr >> page_shift)) {
		dev_dbg(&dev->dev, "can't map partition max 0x%llx with %llu "
			  "%llu-sized pages\n", max_addr,  query.largest_available_block,
	/*
	 * The "ibm,pmemory" can appear anywhere in the address space.
	 * Assuming it is still backed by page structs, try MAX_PHYSMEM_BITS
	 * for the upper limit and fallback to max RAM otherwise but this
	 * disables device::dma_ops_bypass.
	 */
	len = max_ram_len;
	if (pmem_present) {
		if (query.largest_available_block >=
		    (1ULL << (MAX_PHYSMEM_BITS - page_shift)))
			len = MAX_PHYSMEM_BITS - page_shift;
		else
			dev_info(&dev->dev, "Skipping ibm,pmemory");
	}

	if (query.largest_available_block < (1ULL << (len - page_shift))) {
		dev_dbg(&dev->dev,
			"can't map partition max 0x%llx with %llu %llu-sized pages\n",
			1ULL << len,
			query.largest_available_block,
			1ULL << page_shift);
		goto out_failed;
	}
	len = order_base_2(max_addr);
	win64 = kzalloc(sizeof(struct property), GFP_KERNEL);
	if (!win64) {
		dev_info(&dev->dev,
@@ -1299,6 +1321,15 @@ out_failed:

out_unlock:
	mutex_unlock(&direct_window_init_mutex);

	/*
	 * If we have persistent memory and the window size is only as big
	 * as RAM, then we failed to create a window to cover persistent
	 * memory and need to set the DMA limit.
	 */
	if (pmem_present && dma_addr && (len == max_ram_len))
		dev->dev.bus_dma_limit = dma_addr + (1ULL << len);

	return dma_addr;
}

+14 −0
Original line number Diff line number Diff line
@@ -317,6 +317,20 @@ static inline void arch_dma_mark_clean(phys_addr_t paddr, size_t size)
void *arch_dma_set_uncached(void *addr, size_t size);
void arch_dma_clear_uncached(void *addr, size_t size);

#ifdef CONFIG_ARCH_HAS_DMA_MAP_DIRECT
bool arch_dma_map_page_direct(struct device *dev, phys_addr_t addr);
bool arch_dma_unmap_page_direct(struct device *dev, dma_addr_t dma_handle);
bool arch_dma_map_sg_direct(struct device *dev, struct scatterlist *sg,
		int nents);
bool arch_dma_unmap_sg_direct(struct device *dev, struct scatterlist *sg,
		int nents);
#else
#define arch_dma_map_page_direct(d, a)		(false)
#define arch_dma_unmap_page_direct(d, a)	(false)
#define arch_dma_map_sg_direct(d, s, n)		(false)
#define arch_dma_unmap_sg_direct(d, s, n)	(false)
#endif

#ifdef CONFIG_ARCH_HAS_SETUP_DMA_OPS
void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
		const struct iommu_ops *iommu, bool coherent);
Loading