source: rtems/cpukit/libdrvmgr/drvmgr_translate.c @ 7075fb11

Last change on this file since 7075fb11 was bb2f220, checked in by Daniel Hellstrom <daniel@…>, on Apr 13, 2015 at 8:49:47 AM

DRVMGR: renamed private drv_mgr and its struct name

  • Property mode set to 100644
File size: 3.5 KB
Line 
1/* Driver Manager Driver Translate Interface Implementation
2 *
3 * COPYRIGHT (c) 2010 Cobham Gaisler AB.
4 *
5 * The license and distribution terms for this file may be
6 * found in the file LICENSE in this distribution or at
7 * http://www.rtems.org/license/LICENSE.
8 */
9
10/*
11 * Used by device drivers. The functions rely on that the parent bus driver
12 * has implemented the neccessary operations correctly.
13 *
14 * The translate functions are used to translate addresses between buses
15 * for DMA cores located on a "remote" bus, or for memory-mapped obtaining
16 * an address that can be used to access an remote bus.
17 *
18 * For example, PCI I/O might be memory-mapped at the PCI Host bridge,
19 * say address 0xfff10000-0xfff1ffff is mapped to the PCI I/O address
20 * of 0x00000000-0x0000ffff. The PCI Host bridge driver may then set up
21 * a map so that a driver that get PCI address 0x100 can translate that
22 * into 0xfff10100.
23 */
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28
29#include <drvmgr/drvmgr.h>
30#include "drvmgr_internal.h"
31
32unsigned int drvmgr_translate_bus(
33        struct drvmgr_bus *from,
34        struct drvmgr_bus *to,
35        int reverse,
36        void *src_address,
37        void **dst_address)
38{
39        struct drvmgr_bus *path[16];
40        int dir, levels, i;
41        void *dst, *from_adr, *to_adr;
42        struct drvmgr_map_entry *map;
43        struct drvmgr_bus *bus;
44        unsigned int sz;
45        struct drvmgr_bus *bus_bot, *bus_top;
46
47        dst = src_address;
48        sz = 0xffffffff;
49
50        if (from == to) /* no need translating addresses when on same bus */
51                goto out;
52
53        /* Always find translation path from remote bus towards root bus. All
54         * buses have root bus has parent at some level
55         */
56        if (from->depth > to->depth) {
57                bus_bot = from;
58                bus_top = to;
59                dir = 0;
60        } else {
61                bus_bot = to;
62                bus_top = from;
63                dir = 1;
64        }
65        levels = bus_bot->depth - bus_top->depth;
66        if (levels >= 16)
67                return 0; /* Does not support such a big depth */
68        i = 0;
69        while ((bus_bot != NULL) && bus_bot != bus_top) {
70                if (dir)
71                        path[(levels - 1) - i] = bus_bot;
72                else
73                        path[i] = bus_bot;
74                i++;
75                bus_bot = bus_bot->dev->parent;
76        }
77        if (bus_bot == NULL)
78                return 0; /* from -> to is not linearly connected */
79
80        for (i = 0; i < levels; i++) {
81                bus = path[i];
82
83                if ((dir && reverse) || (!dir && !reverse))
84                        map = bus->maps_up;
85                else
86                        map = bus->maps_down;
87
88                if (map == NULL)
89                        continue; /* No translation needed - 1:1 mapping */
90
91                if (map == DRVMGR_TRANSLATE_NO_BRIDGE) {
92                        sz = 0;
93                        break; /* No bridge interface in this direction */
94                }
95
96                while (map->size != 0) {
97                        if (reverse) {
98                                /* Opposite direction */
99                                from_adr = map->to_adr;
100                                to_adr = map->from_adr;
101                        } else {
102                                from_adr = map->from_adr;
103                                to_adr = map->to_adr;
104                        }
105
106                        if ((dst >= from_adr) &&
107                            (dst <= (from_adr + (map->size - 1)))) {
108                                if (((from_adr + (map->size - 1)) - dst) < sz)
109                                        sz = (from_adr + (map->size - 1)) - dst;
110                                dst = (dst - from_adr) + to_adr;
111                                break;
112                        }
113                        map++;
114                }
115                /* quit if no matching translation information */
116                if (map->size == 0) {
117                        sz = 0;
118                        break;
119                }
120        }
121
122out:
123        if (dst_address)
124                *dst_address = dst;
125
126        return sz;
127}
128
129unsigned int drvmgr_translate(
130        struct drvmgr_dev *dev,
131        unsigned int options,
132        void *src_address,
133        void **dst_address)
134{
135        struct drvmgr_bus *to, *from;
136        int rev = 0;
137
138        rev = (~options) & 1;
139        if ((options == CPUMEM_TO_DMA) || (options == DMAMEM_FROM_CPU)) {
140                from = drvmgr.root_dev.bus;
141                to = dev->parent;
142        } else { /* CPUMEM_FROM_DMA || DMAMEM_TO_CPU */
143                from = dev->parent;
144                to = drvmgr.root_dev.bus;
145        }
146
147        return drvmgr_translate_bus(from, to, rev, src_address, dst_address);
148}
Note: See TracBrowser for help on using the repository browser.