From e7fade3ac4559214ab0508dc54a71a3d1f522afb Mon Sep 17 00:00:00 2001 From: Daniel Hellstrom Date: Mon, 28 Nov 2011 09:52:03 +0100 Subject: DRVMGR: added driver manager to cpukit/libdrvmgr --- cpukit/libdrvmgr/drvmgr_translate.c | 149 ++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 cpukit/libdrvmgr/drvmgr_translate.c (limited to 'cpukit/libdrvmgr/drvmgr_translate.c') diff --git a/cpukit/libdrvmgr/drvmgr_translate.c b/cpukit/libdrvmgr/drvmgr_translate.c new file mode 100644 index 0000000000..7febf77d60 --- /dev/null +++ b/cpukit/libdrvmgr/drvmgr_translate.c @@ -0,0 +1,149 @@ +/* Driver Manager Driver Translate Interface Implementation + * + * COPYRIGHT (c) 2010. + * Cobham Gaisler AB. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +/* + * Used by device drivers. The functions rely on that the parent bus driver + * has implemented the neccessary operations correctly. + * + * The translate functions are used to translate addresses between buses + * for DMA cores located on a "remote" bus, or for memory-mapped obtaining + * an address that can be used to access an remote bus. + * + * For example, PCI I/O might be memory-mapped at the PCI Host bridge, + * say address 0xfff10000-0xfff1ffff is mapped to the PCI I/O address + * of 0x00000000-0x0000ffff. The PCI Host bridge driver may then set up + * a map so that a driver that get PCI address 0x100 can translate that + * into 0xfff10100. + */ + +#include +#include +#include + +#include +#include "drvmgr_internal.h" + +unsigned int drvmgr_translate_bus( + struct drvmgr_bus *from, + struct drvmgr_bus *to, + int reverse, + void *src_address, + void **dst_address) +{ + struct drvmgr_bus *path[16]; + int dir, levels, i; + void *dst, *from_adr, *to_adr; + struct drvmgr_map_entry *map; + struct drvmgr_bus *bus; + unsigned int sz; + struct drvmgr_bus *bus_bot, *bus_top; + + dst = src_address; + sz = 0xffffffff; + + if (from == to) /* no need translating addresses when on same bus */ + goto out; + + /* Always find translation path from remote bus towards root bus. All + * buses have root bus has parent at some level + */ + if (from->depth > to->depth) { + bus_bot = from; + bus_top = to; + dir = 0; + } else { + bus_bot = to; + bus_top = from; + dir = 1; + } + levels = bus_bot->depth - bus_top->depth; + if (levels >= 16) + return 0; /* Does not support such a big depth */ + i = 0; + while ((bus_bot != NULL) && bus_bot != bus_top) { + if (dir) + path[(levels - 1) - i] = bus_bot; + else + path[i] = bus_bot; + i++; + bus_bot = bus_bot->dev->parent; + } + if (bus_bot == NULL) + return 0; /* from -> to is not linearly connected */ + + for (i = 0; i < levels; i++) { + bus = path[i]; + + if ((dir && reverse) || (!dir && !reverse)) + map = bus->maps_up; + else + map = bus->maps_down; + + if (map == NULL) + continue; /* No translation needed - 1:1 mapping */ + + if (map == DRVMGR_TRANSLATE_NO_BRIDGE) { + sz = 0; + break; /* No bridge interface in this direction */ + } + + while (map->size != 0) { + if (reverse) { + /* Opposite direction */ + from_adr = map->to_adr; + to_adr = map->from_adr; + } else { + from_adr = map->from_adr; + to_adr = map->to_adr; + } + + if ((dst >= from_adr) && + (dst <= (from_adr + (map->size - 1)))) { + if (((from_adr + (map->size - 1)) - dst) < sz) + sz = (from_adr + (map->size - 1)) - dst; + dst = (dst - from_adr) + to_adr; + break; + } + map++; + } + /* quit if no matching translation information */ + if (map->size == 0) { + sz = 0; + break; + } + } + +out: + if (dst_address) + *dst_address = dst; + + return sz; +} + +unsigned int drvmgr_translate( + struct drvmgr_dev *dev, + unsigned int options, + void *src_address, + void **dst_address) +{ + struct drvmgr_bus *to, *from; + int rev = 0; + + rev = (~options) & 1; + if ((options == CPUMEM_TO_DMA) || (options == DMAMEM_FROM_CPU)) { + from = drv_mgr.root_dev.bus; + to = dev->parent; + } else { /* CPUMEM_FROM_DMA || DMAMEM_TO_CPU */ + from = dev->parent; + to = drv_mgr.root_dev.bus; + } + + return drvmgr_translate_bus(from, to, rev, src_address, dst_address); +} -- cgit v1.2.3