723943821b
OBS-URL: https://build.opensuse.org/request/show/858525 OBS-URL: https://build.opensuse.org/package/show/hardware:boot/u-boot?expand=0&rev=118
157 lines
4.7 KiB
Diff
157 lines
4.7 KiB
Diff
From 8d35d23d658c1a50b591f67951a5c24890687fea Mon Sep 17 00:00:00 2001
|
|
From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
|
|
Date: Thu, 19 Nov 2020 17:17:24 +0100
|
|
Subject: [PATCH] dm: Introduce DMA constraints into the core device model
|
|
|
|
Calculating the DMA offset between a bus address space and CPU's every
|
|
time we call phys_to_bus() and bus_to_phys() isn't ideal performance
|
|
wise, as it implies traversing the device tree from the device's node up
|
|
to the root. Since this information is static and available before the
|
|
device's initialization, parse it before the probe call an provide the
|
|
DMA offset in 'struct udevice' for the address translation code to use
|
|
it.
|
|
|
|
Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
|
|
Reviewed-by: Simon Glass <sjg@chromium.org>
|
|
|
|
---
|
|
Changes since v4:
|
|
- Use macros to access dma_offset
|
|
|
|
Changes since v3:
|
|
- Comment functions and struct variables
|
|
- Correct typos
|
|
|
|
Changes since v2:
|
|
- Return/Fail on error
|
|
- Add config option
|
|
- use ulong instead for u64 for dev->dma_offset
|
|
|
|
Changes since v1:
|
|
- Update commit message so as to explain better the reasoning behind
|
|
this
|
|
---
|
|
drivers/core/Kconfig | 10 ++++++++++
|
|
drivers/core/device.c | 41 +++++++++++++++++++++++++++++++++++++++++
|
|
include/dm/device.h | 13 +++++++++++++
|
|
3 files changed, 64 insertions(+)
|
|
|
|
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
|
|
index 00d1d80dc3..ea90cecc86 100644
|
|
--- a/drivers/core/Kconfig
|
|
+++ b/drivers/core/Kconfig
|
|
@@ -99,6 +99,16 @@ config SPL_DM_SEQ_ALIAS
|
|
numbered devices (e.g. serial0 = &serial0). This feature can be
|
|
disabled if it is not required, to save code space in SPL.
|
|
|
|
+config DM_DMA
|
|
+ bool "Support per-device DMA constraints"
|
|
+ depends on DM
|
|
+ default n
|
|
+ help
|
|
+ Enable this to extract per-device DMA constraints, only supported on
|
|
+ device-tree systems for now. This is needed in order translate
|
|
+ addresses on systems where different buses have different views of
|
|
+ the physical address space.
|
|
+
|
|
config REGMAP
|
|
bool "Support register maps"
|
|
depends on DM
|
|
diff --git a/drivers/core/device.c b/drivers/core/device.c
|
|
index 355dbd147a..d41dab88da 100644
|
|
--- a/drivers/core/device.c
|
|
+++ b/drivers/core/device.c
|
|
@@ -402,6 +402,43 @@ fail:
|
|
return ret;
|
|
}
|
|
|
|
+/**
|
|
+ * device_get_dma_constraints() - Populate device's DMA constraints
|
|
+ *
|
|
+ * Gets a device's DMA constraints from firmware. This information is later
|
|
+ * used by drivers to translate physcal addresses to the device's bus address
|
|
+ * space. For now only device-tree is supported.
|
|
+ *
|
|
+ * @dev: Pointer to target device
|
|
+ * Return: 0 if OK or if no DMA constraints were found, error otherwise
|
|
+ */
|
|
+static int device_get_dma_constraints(struct udevice *dev)
|
|
+{
|
|
+ struct udevice *parent = dev->parent;
|
|
+ phys_addr_t cpu = 0;
|
|
+ dma_addr_t bus = 0;
|
|
+ u64 size = 0;
|
|
+ int ret;
|
|
+
|
|
+ if (!CONFIG_IS_ENABLED(DM_DMA) || !parent || !dev_of_valid(parent))
|
|
+ return 0;
|
|
+
|
|
+ /*
|
|
+ * We start parsing for dma-ranges from the device's bus node. This is
|
|
+ * specially important on nested buses.
|
|
+ */
|
|
+ ret = dev_get_dma_range(parent, &cpu, &bus, &size);
|
|
+ /* Don't return an error if no 'dma-ranges' were found */
|
|
+ if (ret && ret != -ENOENT) {
|
|
+ dm_warn("%s: failed to get DMA range, %d\n", dev->name, ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ dev_set_dma_offset(dev, cpu - bus);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int device_probe(struct udevice *dev)
|
|
{
|
|
const struct driver *drv;
|
|
@@ -463,6 +500,10 @@ int device_probe(struct udevice *dev)
|
|
goto fail;
|
|
}
|
|
|
|
+ ret = device_get_dma_constraints(dev);
|
|
+ if (ret)
|
|
+ goto fail;
|
|
+
|
|
ret = uclass_pre_probe_device(dev);
|
|
if (ret)
|
|
goto fail;
|
|
diff --git a/include/dm/device.h b/include/dm/device.h
|
|
index 953706cf52..9d4670424b 100644
|
|
--- a/include/dm/device.h
|
|
+++ b/include/dm/device.h
|
|
@@ -138,6 +138,8 @@ enum {
|
|
* When CONFIG_DEVRES is enabled, devm_kmalloc() and friends will
|
|
* add to this list. Memory so-allocated will be freed
|
|
* automatically when the device is removed / unbound
|
|
+ * @dma_offset: Offset between the physical address space (CPU's) and the
|
|
+ * device's bus address space
|
|
*/
|
|
struct udevice {
|
|
const struct driver *driver;
|
|
@@ -161,6 +163,9 @@ struct udevice {
|
|
#ifdef CONFIG_DEVRES
|
|
struct list_head devres_head;
|
|
#endif
|
|
+#if CONFIG_IS_ENABLED(DM_DMA)
|
|
+ ulong dma_offset;
|
|
+#endif
|
|
};
|
|
|
|
/* Maximum sequence number supported */
|
|
@@ -172,6 +177,14 @@ struct udevice {
|
|
/* Returns non-zero if the device is active (probed and not removed) */
|
|
#define device_active(dev) ((dev)->flags & DM_FLAG_ACTIVATED)
|
|
|
|
+#if CONFIG_IS_ENABLED(DM_DMA)
|
|
+#define dev_set_dma_offset(_dev, _offset) _dev->dma_offset = _offset
|
|
+#define dev_get_dma_offset(_dev) _dev->dma_offset
|
|
+#else
|
|
+#define dev_set_dma_offset(_dev, _offset)
|
|
+#define dev_get_dma_offset(_dev) 0
|
|
+#endif
|
|
+
|
|
static inline int dev_of_offset(const struct udevice *dev)
|
|
{
|
|
return ofnode_to_offset(dev->node);
|