mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-06-22 14:41:42 +00:00
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> Tested-by: Peter Robinson <pbrobinson@gmail.com> Signed-off-by: Matthias Brugger <mbrugger@suse.com>
This commit is contained in:
parent
283628c412
commit
4abf68d57d
3 changed files with 64 additions and 0 deletions
|
@ -129,6 +129,16 @@ config TPL_DM_INLINE_OFNODE
|
||||||
This applies to several ofnode functions (see ofnode.h) which are
|
This applies to several ofnode functions (see ofnode.h) which are
|
||||||
seldom used. Inlining them can help reduce code size.
|
seldom used. Inlining them can help reduce code size.
|
||||||
|
|
||||||
|
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
|
config REGMAP
|
||||||
bool "Support register maps"
|
bool "Support register maps"
|
||||||
depends on DM
|
depends on DM
|
||||||
|
|
|
@ -422,6 +422,43 @@ fail:
|
||||||
return ret;
|
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_has_ofnode(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)
|
int device_probe(struct udevice *dev)
|
||||||
{
|
{
|
||||||
const struct driver *drv;
|
const struct driver *drv;
|
||||||
|
@ -484,6 +521,10 @@ int device_probe(struct udevice *dev)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = device_get_dma_constraints(dev);
|
||||||
|
if (ret)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
ret = uclass_pre_probe_device(dev);
|
ret = uclass_pre_probe_device(dev);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
|
@ -159,6 +159,8 @@ enum {
|
||||||
* When CONFIG_DEVRES is enabled, devm_kmalloc() and friends will
|
* When CONFIG_DEVRES is enabled, devm_kmalloc() and friends will
|
||||||
* add to this list. Memory so-allocated will be freed
|
* add to this list. Memory so-allocated will be freed
|
||||||
* automatically when the device is removed / unbound
|
* 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 {
|
struct udevice {
|
||||||
const struct driver *driver;
|
const struct driver *driver;
|
||||||
|
@ -183,6 +185,9 @@ struct udevice {
|
||||||
#ifdef CONFIG_DEVRES
|
#ifdef CONFIG_DEVRES
|
||||||
struct list_head devres_head;
|
struct list_head devres_head;
|
||||||
#endif
|
#endif
|
||||||
|
#if CONFIG_IS_ENABLED(DM_DMA)
|
||||||
|
ulong dma_offset;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Maximum sequence number supported */
|
/* Maximum sequence number supported */
|
||||||
|
@ -224,6 +229,14 @@ static inline ofnode dev_ofnode(const struct udevice *dev)
|
||||||
/* Returns non-zero if the device is active (probed and not removed) */
|
/* Returns non-zero if the device is active (probed and not removed) */
|
||||||
#define device_active(dev) (dev_get_flags(dev) & DM_FLAG_ACTIVATED)
|
#define device_active(dev) (dev_get_flags(dev) & 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)
|
static inline int dev_of_offset(const struct udevice *dev)
|
||||||
{
|
{
|
||||||
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue