source: rtems/cpukit/libdrvmgr/drvmgr_translate.c

Last change on this file was 72d83c61, checked in by Joel Sherrill <joel@…>, on 02/28/22 at 23:09:22

cpukit/libdrvmsg: Change license to BSD-2

Updates #3053.

  • Property mode set to 100644
File size: 4.6 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/* Driver Manager Driver Translate Interface Implementation
4 *
5 * COPYRIGHT (c) 2010 Cobham Gaisler AB.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/*
30 * Used by device drivers. The functions rely on that the parent bus driver
31 * has implemented the neccessary operations correctly.
32 *
33 * The translate functions are used to translate addresses between buses
34 * for DMA cores located on a "remote" bus, or for memory-mapped obtaining
35 * an address that can be used to access an remote bus.
36 *
37 * For example, PCI I/O might be memory-mapped at the PCI Host bridge,
38 * say address 0xfff10000-0xfff1ffff is mapped to the PCI I/O address
39 * of 0x00000000-0x0000ffff. The PCI Host bridge driver may then set up
40 * a map so that a driver that get PCI address 0x100 can translate that
41 * into 0xfff10100.
42 */
43
44#include <stdio.h>
45#include <stdlib.h>
46#include <string.h>
47
48#include <drvmgr/drvmgr.h>
49#include "drvmgr_internal.h"
50
51unsigned int drvmgr_translate_bus(
52        struct drvmgr_bus *from,
53        struct drvmgr_bus *to,
54        int reverse,
55        void *src_address,
56        void **dst_address)
57{
58        struct drvmgr_bus *path[16];
59        int dir, levels, i;
60        void *dst, *from_adr, *to_adr;
61        struct drvmgr_map_entry *map;
62        struct drvmgr_bus *bus;
63        unsigned int sz;
64        struct drvmgr_bus *bus_bot, *bus_top;
65
66        dst = src_address;
67        sz = 0xffffffff;
68
69        if (from == to) /* no need translating addresses when on same bus */
70                goto out;
71
72        /* Always find translation path from remote bus towards root bus. All
73         * buses have root bus has parent at some level
74         */
75        if (from->depth > to->depth) {
76                bus_bot = from;
77                bus_top = to;
78                dir = 0;
79        } else {
80                bus_bot = to;
81                bus_top = from;
82                dir = 1;
83        }
84        levels = bus_bot->depth - bus_top->depth;
85        if (levels >= 16)
86                return 0; /* Does not support such a big depth */
87        i = 0;
88        while ((bus_bot != NULL) && bus_bot != bus_top) {
89                if (dir)
90                        path[(levels - 1) - i] = bus_bot;
91                else
92                        path[i] = bus_bot;
93                i++;
94                bus_bot = bus_bot->dev->parent;
95        }
96        if (bus_bot == NULL)
97                return 0; /* from -> to is not linearly connected */
98
99        for (i = 0; i < levels; i++) {
100                bus = path[i];
101
102                if ((dir && reverse) || (!dir && !reverse))
103                        map = bus->maps_up;
104                else
105                        map = bus->maps_down;
106
107                if (map == NULL)
108                        continue; /* No translation needed - 1:1 mapping */
109
110                if (map == DRVMGR_TRANSLATE_NO_BRIDGE) {
111                        sz = 0;
112                        break; /* No bridge interface in this direction */
113                }
114
115                while (map->size != 0) {
116                        if (reverse) {
117                                /* Opposite direction */
118                                from_adr = map->to_adr;
119                                to_adr = map->from_adr;
120                        } else {
121                                from_adr = map->from_adr;
122                                to_adr = map->to_adr;
123                        }
124
125                        if ((dst >= from_adr) &&
126                            (dst <= (from_adr + (map->size - 1)))) {
127                                if (((from_adr + (map->size - 1)) - dst) < sz)
128                                        sz = (from_adr + (map->size - 1)) - dst;
129                                dst = (dst - from_adr) + to_adr;
130                                break;
131                        }
132                        map++;
133                }
134                /* quit if no matching translation information */
135                if (map->size == 0) {
136                        sz = 0;
137                        break;
138                }
139        }
140
141out:
142        if (dst_address)
143                *dst_address = dst;
144
145        return sz;
146}
147
148unsigned int drvmgr_translate(
149        struct drvmgr_dev *dev,
150        unsigned int options,
151        void *src_address,
152        void **dst_address)
153{
154        struct drvmgr_bus *to, *from;
155        int rev = 0;
156
157        rev = (~options) & 1;
158        if ((options == CPUMEM_TO_DMA) || (options == DMAMEM_FROM_CPU)) {
159                from = drvmgr.root_dev.bus;
160                to = dev->parent;
161        } else { /* CPUMEM_FROM_DMA || DMAMEM_TO_CPU */
162                from = dev->parent;
163                to = drvmgr.root_dev.bus;
164        }
165
166        return drvmgr_translate_bus(from, to, rev, src_address, dst_address);
167}
Note: See TracBrowser for help on using the repository browser.