Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 707e9d34 authored by Liam Mark's avatar Liam Mark
Browse files

dma-mapping: add support for dma-coherent-hint-cached



When clients configure their device as dma-coherent-hint-cached this will
result in the memory framework only trying to DMA map buffers as
IO-coherent if the framework is confident that the buffers are mapped as
cached in the CPU.

Clients should configure their device as dma-coherent-hint-cached instead
of dma-coherent when they need to DMA map both buffers that have cached
CPU mappings and other buffers which have uncached CPU mappings. By using
dma-coherent-hint-cached the framework will ensure that the client's
buffers with uncached CPU mappings don't get DMA mapped as IO-coherent.

Change-Id: I990184b54d4148bf952cc672ec267b51efd81473
Signed-off-by: default avatarLiam Mark <lmark@codeaurora.org>
parent 333b4ccb
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
 */

#include <linux/dma-noncoherent.h>
@@ -251,7 +251,8 @@ static inline int __msm_dma_map_sg(struct device *dev, struct scatterlist *sg,
				dma_sync_sg_for_device(dev, iommu_map->sgl,
					iommu_map->nents, iommu_map->dir);

			if (dev_is_dma_coherent(dev))
			if (dev_is_dma_coherent(dev) ||
			    (attrs & DMA_ATTR_FORCE_COHERENT))
				/*
				 * Ensure all outstanding changes for coherent
				 * buffers are applied to the cache before any
+25 −0
Original line number Diff line number Diff line
@@ -1015,3 +1015,28 @@ bool of_dma_is_coherent(struct device_node *np)
	return false;
}
EXPORT_SYMBOL_GPL(of_dma_is_coherent);

#if defined(CONFIG_DMA_COHERENT_HINT_CACHED)
/**
 * of_dma_is_coherent_hint_cached - Check if device is coherent hint cached
 * @np: device node
 *
 * It returns true if "dma-coherent-hint-cached" property was found
 * for this device in DT.
 */
bool of_dma_is_coherent_hint_cached(struct device_node *np)
{
	struct device_node *node = of_node_get(np);

	while (node) {
		if (of_property_read_bool(node, "dma-coherent-hint-cached")) {
			of_node_put(node);
			return true;
		}
		node = of_get_next_parent(node);
	}
	of_node_put(node);
	return false;
}
EXPORT_SYMBOL(of_dma_is_coherent_hint_cached);
#endif /* CONFIG_DMA_COHERENT_HINT_CACHED */
+8 −1
Original line number Diff line number Diff line
@@ -90,7 +90,7 @@ int of_dma_configure(struct device *dev, struct device_node *np, bool force_dma)
{
	u64 dma_addr, paddr, size = 0;
	int ret;
	bool coherent;
	bool coherent, coherent_hint_cached;
	unsigned long offset;
	const struct iommu_ops *iommu;
	u64 mask;
@@ -159,6 +159,13 @@ int of_dma_configure(struct device *dev, struct device_node *np, bool force_dma)
	dev_dbg(dev, "device is%sdma coherent\n",
		coherent ? " " : " not ");

	coherent_hint_cached = of_dma_is_coherent_hint_cached(np);
	dev_dbg(dev, "device is%sdma coherent_hint_cached\n",
		coherent_hint_cached ? " " : " not ");
	dma_set_coherent_hint_cached(dev, coherent_hint_cached);
	WARN(coherent && coherent_hint_cached,
	     "Should not set both dma-coherent and dma-coherent-hint-cached on the same device");

	iommu = of_iommu_configure(dev, np);
	if (IS_ERR(iommu) && PTR_ERR(iommu) == -EPROBE_DEFER)
		return -EPROBE_DEFER;
+21 −1
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (C) 2011 Google, Inc.
 * Copyright (c) 2011-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2011-2020, The Linux Foundation. All rights reserved.
 */

#include <linux/device.h>
#include <linux/dma-buf.h>
#include <linux/dma-noncoherent.h>
#include <linux/err.h>
#include <linux/export.h>
#include <linux/file.h>
@@ -163,6 +164,20 @@ static struct sg_table
	    !hlos_accessible_buffer(buffer))
		map_attrs |= DMA_ATTR_SKIP_CPU_SYNC;

	if ((buffer->flags & ION_FLAG_CACHED) &&
	    hlos_accessible_buffer(buffer) &&
	    dev_is_dma_coherent_hint_cached(attachment->dev))
		map_attrs |= DMA_ATTR_FORCE_COHERENT;

	if (((dev_is_dma_coherent(attachment->dev) &&
	      !(map_attrs & DMA_ATTR_FORCE_NON_COHERENT)) ||
	     (map_attrs & DMA_ATTR_FORCE_COHERENT)) &&
	    !(buffer->flags & ION_FLAG_CACHED)) {
		pr_warn_ratelimited("dev:%s Cannot DMA map uncached buffer as IO-coherent attrs:0x%lx\n",
				    dev_name(attachment->dev), map_attrs);
		return ERR_PTR(-EINVAL);
	}

	mutex_lock(&buffer->lock);
	if (map_attrs & DMA_ATTR_SKIP_CPU_SYNC)
		trace_ion_dma_map_cmo_skip(attachment->dev,
@@ -233,6 +248,11 @@ static void msm_ion_unmap_dma_buf(struct dma_buf_attachment *attachment,
	    !hlos_accessible_buffer(buffer))
		map_attrs |= DMA_ATTR_SKIP_CPU_SYNC;

	if ((buffer->flags & ION_FLAG_CACHED) &&
	    hlos_accessible_buffer(buffer) &&
	    dev_is_dma_coherent_hint_cached(attachment->dev))
		map_attrs |= DMA_ATTR_FORCE_COHERENT;

	mutex_lock(&buffer->lock);
	if (map_attrs & DMA_ATTR_SKIP_CPU_SYNC)
		trace_ion_dma_unmap_cmo_skip(attachment->dev,
+7 −1
Original line number Diff line number Diff line
@@ -1245,7 +1245,9 @@ struct dev_links_info {
 *		  sync_state() callback.
 * @dma_coherent: this particular device is dma coherent, even if the
 *		architecture supports non-coherent devices.
 *
 * @dma_coherent_hint_cached: Tell the framework to try and treat the device
 *			      as DMA coherent when working with CPU cached
 *			      buffers.
 * At the lowest level, every device in a Linux system is represented by an
 * instance of struct device. The device structure contains the information
 * that the device model core needs to model the system. Most subsystems,
@@ -1345,6 +1347,10 @@ struct device {
    defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL)
	bool			dma_coherent:1;
#endif
#if defined(CONFIG_DMA_COHERENT_HINT_CACHED)
	bool			dma_coherent_hint_cached:1;
#endif

};

static inline struct device *kobj_to_dev(struct kobject *kobj)
Loading