ANDROID: dma-buf: system_heap: Reject uncached SWIOTLB buffers

Uncached system heap buffers skip dma_sync_sgtable_for_*, but those
calls are required even for uncached buffers when a SWIOTLB bounce
buffer is involved. Since SWIOTLB copies greatly reduce the performance
of uncached dma-bufers, reject maps for devices which require them.

Test: Force SWIOTLB in mali_kbase on Pixel 6 which provides no
Test: dma_map_ops with: dev->dma_io_tlb_mem->force_bounce = true;
Fixes: 560ecde1b0 ("FROMLIST: dma-buf: system_heap: Add a system-uncached heap re-using the system heap")
Bug: 289327060
Change-Id: I11a62c62cd684c8cb517fd96014b8110c37fd12b
Signed-off-by: T.J. Mercier <tjmercier@google.com>
This commit is contained in:
T.J. Mercier
2024-04-15 18:15:24 +00:00
parent f2e5227422
commit 4f140e67f3
+33 -1
View File
@@ -11,14 +11,17 @@
*/
#include <linux/dma-buf.h>
#include <linux/dma-direct.h>
#include <linux/dma-mapping.h>
#include <linux/dma-heap.h>
#include <linux/err.h>
#include <linux/highmem.h>
#include <linux/iommu.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/swiotlb.h>
#include <linux/vmalloc.h>
static struct dma_heap *sys_heap;
@@ -59,6 +62,28 @@ static gfp_t order_flags[] = {HIGH_ORDER_GFP, HIGH_ORDER_GFP, LOW_ORDER_GFP};
static const unsigned int orders[] = {8, 4, 0};
#define NUM_ORDERS ARRAY_SIZE(orders)
static bool needs_swiotlb_bounce(struct device *dev, struct sg_table *table)
{
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
struct scatterlist *sg;
int i;
for_each_sgtable_dma_sg(table, sg, i) {
// SG_DMA_SWIOTLB is set only for dma-iommu, not for dma-direct
if (domain && IS_ENABLED(CONFIG_NEED_SG_DMA_FLAGS)) {
if (sg_dma_is_swiotlb(table->sgl))
return true;
} else {
phys_addr_t paddr = domain ?
iommu_iova_to_phys(domain, sg_dma_address(sg)) :
dma_to_phys(dev, sg_dma_address(sg));
if (is_swiotlb_buffer(dev, paddr))
return true;
}
}
return false;
}
static struct sg_table *dup_sg_table(struct sg_table *table)
{
struct sg_table *new_table;
@@ -145,6 +170,13 @@ static struct sg_table *system_heap_map_dma_buf(struct dma_buf_attachment *attac
if (ret)
return ERR_PTR(ret);
if (a->uncached && needs_swiotlb_bounce(attachment->dev, table)) {
pr_err("Cannot map uncached system heap buffer for %s, as it requires SWIOTLB",
dev_name(attachment->dev));
dma_unmap_sgtable(attachment->dev, table, direction, attr);
return ERR_PTR(-EINVAL);
}
a->mapped = true;
return table;
}