Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:16

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /* Driver Manager Driver Translate Interface Implementation
0004  *
0005  * COPYRIGHT (c) 2010 Cobham Gaisler AB.
0006  *
0007  * Redistribution and use in source and binary forms, with or without
0008  * modification, are permitted provided that the following conditions
0009  * are met:
0010  * 1. Redistributions of source code must retain the above copyright
0011  *    notice, this list of conditions and the following disclaimer.
0012  * 2. Redistributions in binary form must reproduce the above copyright
0013  *    notice, this list of conditions and the following disclaimer in the
0014  *    documentation and/or other materials provided with the distribution.
0015  *
0016  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0017  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0018  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0019  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0020  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0021  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0022  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0023  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0024  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0025  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0026  * POSSIBILITY OF SUCH DAMAGE.
0027  */
0028 
0029 /*
0030  * Used by device drivers. The functions rely on that the parent bus driver
0031  * has implemented the neccessary operations correctly.
0032  *
0033  * The translate functions are used to translate addresses between buses
0034  * for DMA cores located on a "remote" bus, or for memory-mapped obtaining
0035  * an address that can be used to access an remote bus.
0036  *
0037  * For example, PCI I/O might be memory-mapped at the PCI Host bridge,
0038  * say address 0xfff10000-0xfff1ffff is mapped to the PCI I/O address
0039  * of 0x00000000-0x0000ffff. The PCI Host bridge driver may then set up
0040  * a map so that a driver that get PCI address 0x100 can translate that
0041  * into 0xfff10100.
0042  */
0043 
0044 #include <stdio.h>
0045 #include <stdlib.h>
0046 #include <string.h>
0047 
0048 #include <drvmgr/drvmgr.h>
0049 #include "drvmgr_internal.h"
0050 
0051 unsigned int drvmgr_translate_bus(
0052     struct drvmgr_bus *from,
0053     struct drvmgr_bus *to,
0054     int reverse,
0055     void *src_address,
0056     void **dst_address)
0057 {
0058     struct drvmgr_bus *path[16];
0059     int dir, levels, i;
0060     void *dst, *from_adr, *to_adr;
0061     struct drvmgr_map_entry *map;
0062     struct drvmgr_bus *bus;
0063     unsigned int sz;
0064     struct drvmgr_bus *bus_bot, *bus_top;
0065 
0066     dst = src_address;
0067     sz = 0xffffffff;
0068 
0069     if (from == to) /* no need translating addresses when on same bus */
0070         goto out;
0071 
0072     /* Always find translation path from remote bus towards root bus. All
0073      * buses have root bus has parent at some level
0074      */
0075     if (from->depth > to->depth) {
0076         bus_bot = from;
0077         bus_top = to;
0078         dir = 0;
0079     } else {
0080         bus_bot = to;
0081         bus_top = from;
0082         dir = 1;
0083     }
0084     levels = bus_bot->depth - bus_top->depth;
0085     if (levels >= 16)
0086         return 0; /* Does not support such a big depth */
0087     i = 0;
0088     while ((bus_bot != NULL) && bus_bot != bus_top) {
0089         if (dir)
0090             path[(levels - 1) - i] = bus_bot;
0091         else
0092             path[i] = bus_bot;
0093         i++;
0094         bus_bot = bus_bot->dev->parent;
0095     }
0096     if (bus_bot == NULL)
0097         return 0; /* from -> to is not linearly connected */
0098 
0099     for (i = 0; i < levels; i++) {
0100         bus = path[i];
0101 
0102         if ((dir && reverse) || (!dir && !reverse))
0103             map = bus->maps_up;
0104         else
0105             map = bus->maps_down;
0106 
0107         if (map == NULL)
0108             continue; /* No translation needed - 1:1 mapping */
0109 
0110         if (map == DRVMGR_TRANSLATE_NO_BRIDGE) {
0111             sz = 0;
0112             break; /* No bridge interface in this direction */
0113         }
0114 
0115         while (map->size != 0) {
0116             if (reverse) {
0117                 /* Opposite direction */
0118                 from_adr = map->to_adr;
0119                 to_adr = map->from_adr;
0120             } else {
0121                 from_adr = map->from_adr;
0122                 to_adr = map->to_adr;
0123             }
0124 
0125             if ((dst >= from_adr) &&
0126                 (dst <= (from_adr + (map->size - 1)))) {
0127                 if (((from_adr + (map->size - 1)) - dst) < sz)
0128                     sz = (from_adr + (map->size - 1)) - dst;
0129                 dst = (dst - from_adr) + to_adr;
0130                 break;
0131             }
0132             map++;
0133         }
0134         /* quit if no matching translation information */
0135         if (map->size == 0) {
0136             sz = 0;
0137             break;
0138         }
0139     }
0140 
0141 out:
0142     if (dst_address)
0143         *dst_address = dst;
0144 
0145     return sz;
0146 }
0147 
0148 unsigned int drvmgr_translate(
0149     struct drvmgr_dev *dev,
0150     unsigned int options,
0151     void *src_address,
0152     void **dst_address)
0153 {
0154     struct drvmgr_bus *to, *from;
0155     int rev = 0;
0156 
0157     rev = (~options) & 1;
0158     if ((options == CPUMEM_TO_DMA) || (options == DMAMEM_FROM_CPU)) {
0159         from = drvmgr.root_dev.bus;
0160         to = dev->parent;
0161     } else { /* CPUMEM_FROM_DMA || DMAMEM_TO_CPU */
0162         from = dev->parent;
0163         to = drvmgr.root_dev.bus;
0164     }
0165 
0166     return drvmgr_translate_bus(from, to, rev, src_address, dst_address);
0167 }