xref: /openbmc/linux/drivers/acpi/arm64/dma.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1db59e1b6SJean-Philippe Brucker // SPDX-License-Identifier: GPL-2.0-only
2db59e1b6SJean-Philippe Brucker #include <linux/acpi.h>
3db59e1b6SJean-Philippe Brucker #include <linux/acpi_iort.h>
4db59e1b6SJean-Philippe Brucker #include <linux/device.h>
5db59e1b6SJean-Philippe Brucker #include <linux/dma-direct.h>
6db59e1b6SJean-Philippe Brucker 
acpi_arch_dma_setup(struct device * dev)7*bf2ee8d0SJianmin Lv void acpi_arch_dma_setup(struct device *dev)
8db59e1b6SJean-Philippe Brucker {
9db59e1b6SJean-Philippe Brucker 	int ret;
10db59e1b6SJean-Philippe Brucker 	u64 end, mask;
11*bf2ee8d0SJianmin Lv 	u64 size = 0;
12*bf2ee8d0SJianmin Lv 	const struct bus_dma_region *map = NULL;
13db59e1b6SJean-Philippe Brucker 
14db59e1b6SJean-Philippe Brucker 	/*
15db59e1b6SJean-Philippe Brucker 	 * If @dev is expected to be DMA-capable then the bus code that created
16db59e1b6SJean-Philippe Brucker 	 * it should have initialised its dma_mask pointer by this point. For
17db59e1b6SJean-Philippe Brucker 	 * now, we'll continue the legacy behaviour of coercing it to the
18db59e1b6SJean-Philippe Brucker 	 * coherent mask if not, but we'll no longer do so quietly.
19db59e1b6SJean-Philippe Brucker 	 */
20db59e1b6SJean-Philippe Brucker 	if (!dev->dma_mask) {
21db59e1b6SJean-Philippe Brucker 		dev_warn(dev, "DMA mask not set\n");
22db59e1b6SJean-Philippe Brucker 		dev->dma_mask = &dev->coherent_dma_mask;
23db59e1b6SJean-Philippe Brucker 	}
24db59e1b6SJean-Philippe Brucker 
25db59e1b6SJean-Philippe Brucker 	if (dev->coherent_dma_mask)
26db59e1b6SJean-Philippe Brucker 		size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1);
27db59e1b6SJean-Philippe Brucker 	else
28db59e1b6SJean-Philippe Brucker 		size = 1ULL << 32;
29db59e1b6SJean-Philippe Brucker 
30*bf2ee8d0SJianmin Lv 	ret = acpi_dma_get_range(dev, &map);
31*bf2ee8d0SJianmin Lv 	if (!ret && map) {
32*bf2ee8d0SJianmin Lv 		const struct bus_dma_region *r = map;
33*bf2ee8d0SJianmin Lv 
34*bf2ee8d0SJianmin Lv 		for (end = 0; r->size; r++) {
35*bf2ee8d0SJianmin Lv 			if (r->dma_start + r->size - 1 > end)
36*bf2ee8d0SJianmin Lv 				end = r->dma_start + r->size - 1;
37*bf2ee8d0SJianmin Lv 		}
38*bf2ee8d0SJianmin Lv 
39*bf2ee8d0SJianmin Lv 		size = end + 1;
40*bf2ee8d0SJianmin Lv 		dev->dma_range_map = map;
41*bf2ee8d0SJianmin Lv 	}
42*bf2ee8d0SJianmin Lv 
43db59e1b6SJean-Philippe Brucker 	if (ret == -ENODEV)
44db59e1b6SJean-Philippe Brucker 		ret = iort_dma_get_ranges(dev, &size);
45db59e1b6SJean-Philippe Brucker 	if (!ret) {
46db59e1b6SJean-Philippe Brucker 		/*
47db59e1b6SJean-Philippe Brucker 		 * Limit coherent and dma mask based on size retrieved from
48db59e1b6SJean-Philippe Brucker 		 * firmware.
49db59e1b6SJean-Philippe Brucker 		 */
50*bf2ee8d0SJianmin Lv 		end = size - 1;
51db59e1b6SJean-Philippe Brucker 		mask = DMA_BIT_MASK(ilog2(end) + 1);
52db59e1b6SJean-Philippe Brucker 		dev->bus_dma_limit = end;
53db59e1b6SJean-Philippe Brucker 		dev->coherent_dma_mask = min(dev->coherent_dma_mask, mask);
54db59e1b6SJean-Philippe Brucker 		*dev->dma_mask = min(*dev->dma_mask, mask);
55db59e1b6SJean-Philippe Brucker 	}
56db59e1b6SJean-Philippe Brucker }
57