summaryrefslogtreecommitdiffstats
path: root/lib/dma-debug.c
diff options
context:
space:
mode:
authorRobin Murphy <robin.murphy@arm.com>2018-05-21 07:35:13 -0400
committerChristoph Hellwig <hch@lst.de>2018-05-24 03:24:17 -0400
commit78c47830a5cbb5d22dc91819a95af3d5c4bec084 (patch)
tree43665ea5d3d05e734ea6a1399e7e5fdfd06b7792 /lib/dma-debug.c
parent7f5c1ea3b707f349af539c7cb4ade8c9d0ad8452 (diff)
dma-debug: check scatterlist segments
Drivers/subsystems creating scatterlists for DMA should be taking care to respect the scatter-gather limitations of the appropriate device, as described by dma_parms. A DMA API implementation cannot feasibly split a scatterlist into *more* entries than originally passed, so it is not well defined what they should do when given a segment larger than the limit they are also required to respect. Conversely, devices which are less limited than the rather conservative defaults, or indeed have no limitations at all (e.g. GPUs with their own internal MMU), should be encouraged to set appropriate dma_parms, as they may get more efficient DMA mapping performance out of it. Signed-off-by: Robin Murphy <robin.murphy@arm.com> Signed-off-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'lib/dma-debug.c')
-rw-r--r--lib/dma-debug.c28
1 files changed, 28 insertions, 0 deletions
diff --git a/lib/dma-debug.c b/lib/dma-debug.c
index 6a1ebaa83623..c007d25bee09 100644
--- a/lib/dma-debug.c
+++ b/lib/dma-debug.c
@@ -1286,6 +1286,32 @@ out:
1286 put_hash_bucket(bucket, &flags); 1286 put_hash_bucket(bucket, &flags);
1287} 1287}
1288 1288
1289static void check_sg_segment(struct device *dev, struct scatterlist *sg)
1290{
1291#ifdef CONFIG_DMA_API_DEBUG_SG
1292 unsigned int max_seg = dma_get_max_seg_size(dev);
1293 u64 start, end, boundary = dma_get_seg_boundary(dev);
1294
1295 /*
1296 * Either the driver forgot to set dma_parms appropriately, or
1297 * whoever generated the list forgot to check them.
1298 */
1299 if (sg->length > max_seg)
1300 err_printk(dev, NULL, "DMA-API: mapping sg segment longer than device claims to support [len=%u] [max=%u]\n",
1301 sg->length, max_seg);
1302 /*
1303 * In some cases this could potentially be the DMA API
1304 * implementation's fault, but it would usually imply that
1305 * the scatterlist was built inappropriately to begin with.
1306 */
1307 start = sg_dma_address(sg);
1308 end = start + sg_dma_len(sg) - 1;
1309 if ((start ^ end) & ~boundary)
1310 err_printk(dev, NULL, "DMA-API: mapping sg segment across boundary [start=0x%016llx] [end=0x%016llx] [boundary=0x%016llx]\n",
1311 start, end, boundary);
1312#endif
1313}
1314
1289void debug_dma_map_page(struct device *dev, struct page *page, size_t offset, 1315void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
1290 size_t size, int direction, dma_addr_t dma_addr, 1316 size_t size, int direction, dma_addr_t dma_addr,
1291 bool map_single) 1317 bool map_single)
@@ -1416,6 +1442,8 @@ void debug_dma_map_sg(struct device *dev, struct scatterlist *sg,
1416 check_for_illegal_area(dev, sg_virt(s), sg_dma_len(s)); 1442 check_for_illegal_area(dev, sg_virt(s), sg_dma_len(s));
1417 } 1443 }
1418 1444
1445 check_sg_segment(dev, s);
1446
1419 add_dma_entry(entry); 1447 add_dma_entry(entry);
1420 } 1448 }
1421} 1449}