/* Uncomment me to enable of_dump_addr() debugging output */ // #define DEBUG
#include"of_private.h"
/* Callbacks for bus specific translators */ struct of_bus { constchar *name; constchar *addresses; int (*match)(struct device_node *parent); void (*count_cells)(struct device_node *child, int *addrc, int *sizec);
u64 (*map)(__be32 *addr, const __be32 *range, int na, int ns, int pna, int fna); int (*translate)(__be32 *addr, u64 offset, int na); int flag_cells; unsignedint (*get_flags)(const __be32 *addr);
};
/* * Default translator (generic bus)
*/
staticvoid of_bus_default_count_cells(struct device_node *dev, int *addrc, int *sizec)
{ if (addrc)
*addrc = of_n_addr_cells(dev); if (sizec)
*sizec = of_n_size_cells(dev);
}
static u64 of_bus_default_map(__be32 *addr, const __be32 *range, int na, int ns, int pna, int fna)
{
u64 cp, s, da;
cp = of_read_number(range + fna, na - fna);
s = of_read_number(range + na + pna, ns);
da = of_read_number(addr + fna, na - fna);
static u64 of_bus_default_flags_map(__be32 *addr, const __be32 *range, int na, int ns, int pna, int fna)
{ /* Check that flags match */ if (*addr != *range) return OF_BAD_ADDR;
if (is_pcie)
pr_warn_once("%pOF: Missing device_type\n", np);
return is_pcie;
}
staticint of_bus_pci_match(struct device_node *np)
{ /* * "pciex" is PCI Express * "vci" is for the /chaos bridge on 1st-gen PCI powermacs * "ht" is hypertransport * * If none of the device_type match, and that the node name is * "pcie", accept the device as PCI (with a warning).
*/ return of_node_is_type(np, "pci") || of_node_is_type(np, "pciex") ||
of_node_is_type(np, "vci") || of_node_is_type(np, "ht") ||
of_node_is_pcie(np);
}
staticvoid of_bus_pci_count_cells(struct device_node *np, int *addrc, int *sizec)
{ if (addrc)
*addrc = 3; if (sizec)
*sizec = 2;
}
static u64 of_bus_pci_map(__be32 *addr, const __be32 *range, int na, int ns, int pna, int fna)
{ unsignedint af, rf;
af = of_bus_pci_get_flags(addr);
rf = of_bus_pci_get_flags(range);
/* Check address type match */ if ((af ^ rf) & (IORESOURCE_MEM | IORESOURCE_IO)) return OF_BAD_ADDR;
/* * of_pci_range_to_resource - Create a resource from an of_pci_range * @range: the PCI range that describes the resource * @np: device node where the range belongs to * @res: pointer to a valid resource that will be updated to * reflect the values contained in the range. * * Returns -EINVAL if the range cannot be converted to resource. * * Note that if the range is an IO range, the resource will be converted * using pci_address_to_pio() which can fail if it is called too early or * if the range cannot be matched to any host bridge IO space (our case here). * To guard against that we try to register the IO range first. * If that fails we know that pci_address_to_pio() will do too.
*/ int of_pci_range_to_resource(conststruct of_pci_range *range, conststruct device_node *np, struct resource *res)
{
u64 start; int err;
res->flags = range->flags;
res->parent = res->child = res->sibling = NULL;
res->name = np->full_name;
/* * of_range_to_resource - Create a resource from a ranges entry * @np: device node where the range belongs to * @index: the 'ranges' index to convert to a resource * @res: pointer to a valid resource that will be updated to * reflect the values contained in the range. * * Returns -ENOENT if the entry is not found or -EOVERFLOW if the range * cannot be converted to resource.
*/ int of_range_to_resource(struct device_node *np, int index, struct resource *res)
{ int ret, i = 0; struct of_range_parser parser; struct of_range range;
ret = of_range_parser_init(&parser, np); if (ret) return ret;
for_each_of_range(&parser, &range) if (i++ == index) return of_pci_range_to_resource(&range, np, res);
staticvoid of_bus_isa_count_cells(struct device_node *child, int *addrc, int *sizec)
{ if (addrc)
*addrc = 2; if (sizec)
*sizec = 1;
}
static u64 of_bus_isa_map(__be32 *addr, const __be32 *range, int na, int ns, int pna, int fna)
{ /* Check address type match */ if ((addr[0] ^ range[0]) & cpu_to_be32(1)) return OF_BAD_ADDR;
if (w & 1)
flags |= IORESOURCE_IO; else
flags |= IORESOURCE_MEM; return flags;
}
staticint of_bus_default_flags_match(struct device_node *np)
{ /* * Check for presence first since of_bus_n_addr_cells() will warn when * walking parent nodes.
*/ return of_property_present(np, "#address-cells") && (of_bus_n_addr_cells(np) == 3);
}
staticint of_bus_default_match(struct device_node *np)
{ /* * Check for presence first since of_bus_n_addr_cells() will warn when * walking parent nodes.
*/ return of_property_present(np, "#address-cells");
}
staticconststruct of_bus *of_match_bus(struct device_node *np)
{ int i;
for (i = 0; i < ARRAY_SIZE(of_busses); i++) if (!of_busses[i].match || of_busses[i].match(np)) return &of_busses[i]; return NULL;
}
staticint of_empty_ranges_quirk(conststruct device_node *np)
{ if (IS_ENABLED(CONFIG_PPC)) { /* To save cycles, we cache the result for global "Mac" setting */ staticint quirk_state = -1;
/* PA-SEMI sdc DT bug */ if (of_device_is_compatible(np, "1682m-sdc")) returntrue;
/* Make quirk cached */ if (quirk_state < 0)
quirk_state =
of_machine_is_compatible("Power Macintosh") ||
of_machine_is_compatible("MacRISC"); return quirk_state;
} returnfalse;
}
staticint of_translate_one(conststruct device_node *parent, conststruct of_bus *bus, conststruct of_bus *pbus, __be32 *addr, int na, int ns, int pna, constchar *rprop)
{ const __be32 *ranges; unsignedint rlen; int rone;
u64 offset = OF_BAD_ADDR;
/* * Normally, an absence of a "ranges" property means we are * crossing a non-translatable boundary, and thus the addresses * below the current cannot be converted to CPU physical ones. * Unfortunately, while this is very clear in the spec, it's not * what Apple understood, and they do have things like /uni-n or * /ht nodes with no "ranges" property and a lot of perfectly * useable mapped devices below them. Thus we treat the absence of * "ranges" as equivalent to an empty "ranges" property which means * a 1:1 translation at that level. It's up to the caller not to try * to translate addresses that aren't supposed to be translated in * the first place. --BenH. * * As far as we know, this damage only exists on Apple machines, so * This code is only enabled on powerpc. --gcl * * This quirk also applies for 'dma-ranges' which frequently exist in * child nodes without 'dma-ranges' in the parent nodes. --RobH
*/
ranges = of_get_property(parent, rprop, &rlen); if (ranges == NULL && !of_empty_ranges_quirk(parent) &&
strcmp(rprop, "dma-ranges")) {
pr_debug("no ranges; cannot translate\n"); return 1;
} if (ranges == NULL || rlen == 0) {
offset = of_read_number(addr, na); /* set address to zero, pass flags through */
memset(addr + pbus->flag_cells, 0, (pna - pbus->flag_cells) * 4);
pr_debug("empty ranges; 1:1 translation\n"); goto finish;
}
pr_debug("walking ranges...\n");
/* Now walk through the ranges */
rlen /= 4;
rone = na + pna + ns; for (; rlen >= rone; rlen -= rone, ranges += rone) {
offset = bus->map(addr, ranges, na, ns, pna, bus->flag_cells); if (offset != OF_BAD_ADDR) break;
} if (offset == OF_BAD_ADDR) {
pr_debug("not found !\n"); return 1;
}
memcpy(addr, ranges + na, 4 * pna);
/* Translate it into parent bus space */ return pbus->translate(addr, offset, pna);
}
/* * Translate an address from the device-tree into a CPU physical address, * this walks up the tree and applies the various bus mappings on the * way. * * Note: We consider that crossing any level with #size-cells == 0 to mean * that translation is impossible (that is we are not dealing with a value * that can be mapped to a cpu physical address). This is not really specified * that way, but this is traditionally the way IBM at least do things * * Whenever the translation fails, the *host pointer will be set to the * device that had registered logical PIO mapping, and the return code is * relative to that node.
*/ static u64 __of_translate_address(struct device_node *node, struct device_node *(*get_parent)(conststruct device_node *), const __be32 *in_addr, constchar *rprop, struct device_node **host)
{ struct device_node *dev __free(device_node) = of_node_get(node); struct device_node *parent __free(device_node) = get_parent(dev); conststruct of_bus *bus, *pbus;
__be32 addr[OF_MAX_ADDR_CELLS]; int na, ns, pna, pns;
pr_debug("** translation for device %pOF **\n", dev);
*host = NULL;
if (parent == NULL) return OF_BAD_ADDR;
bus = of_match_bus(parent); if (!bus) return OF_BAD_ADDR;
/* Count address cells & copy address locally */
bus->count_cells(dev, &na, &ns); if (!OF_CHECK_COUNTS(na, ns)) {
pr_debug("Bad cell count for %pOF\n", dev); return OF_BAD_ADDR;
}
memcpy(addr, in_addr, na * 4);
pr_debug("bus is %s (na=%d, ns=%d) on %pOF\n",
bus->name, na, ns, parent);
of_dump_addr("translating address:", addr, na);
/* Translate */ for (;;) { struct logic_pio_hwaddr *iorange;
/* Switch to parent bus */
of_node_put(dev);
dev = parent;
parent = get_parent(dev);
/* If root, we have finished */ if (parent == NULL) {
pr_debug("reached root node\n"); return of_read_number(addr, na);
}
/* * For indirectIO device which has no ranges property, get * the address from reg directly.
*/
iorange = find_io_range_by_fwnode(&dev->fwnode); if (iorange && (iorange->flags != LOGIC_PIO_CPU_MMIO)) {
u64 result = of_read_number(addr + 1, na - 1);
pr_debug("indirectIO matched(%pOF) 0x%llx\n",
dev, result);
*host = no_free_ptr(dev); return result;
}
/* Get new parent bus and counts */
pbus = of_match_bus(parent); if (!pbus) return OF_BAD_ADDR;
pbus->count_cells(dev, &pna, &pns); if (!OF_CHECK_COUNTS(pna, pns)) {
pr_err("Bad cell count for %pOF\n", dev); return OF_BAD_ADDR;
}
pr_debug("parent bus is %s (na=%d, ns=%d) on %pOF\n",
pbus->name, pna, pns, parent);
/* Apply bus translation */ if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop)) return OF_BAD_ADDR;
/* Complete the move up one level */
na = pna;
ns = pns;
bus = pbus;
/** * of_translate_dma_region - Translate device tree address and size tuple * @dev: device tree node for which to translate * @prop: pointer into array of cells * @start: return value for the start of the DMA range * @length: return value for the length of the DMA range * * Returns a pointer to the cell immediately following the translated DMA region.
*/ const __be32 *of_translate_dma_region(struct device_node *dev, const __be32 *prop,
phys_addr_t *start, size_t *length)
{ struct device_node *parent __free(device_node) = __of_get_dma_parent(dev);
u64 address, size; int na, ns;
if (!parent) return NULL;
na = of_bus_n_addr_cells(parent);
ns = of_bus_n_size_cells(parent);
address = of_translate_dma_address(dev, prop); if (address == OF_BAD_ADDR) return NULL;
size = of_read_number(prop + na, ns);
if (start)
*start = address;
if (length)
*length = size;
return prop + na + ns;
}
EXPORT_SYMBOL(of_translate_dma_region);
const __be32 *__of_get_address(struct device_node *dev, int index, int bar_no,
u64 *size, unsignedint *flags)
{ const __be32 *prop; unsignedint psize; struct device_node *parent __free(device_node) = of_get_parent(dev); conststruct of_bus *bus; int onesize, i, na, ns;
if (parent == NULL) return NULL;
/* match the parent's bus type */
bus = of_match_bus(parent); if (!bus || (strcmp(bus->name, "pci") && (bar_no >= 0))) return NULL;
/* Get "reg" or "assigned-addresses" property */
prop = of_get_property(dev, bus->addresses, &psize); if (prop == NULL) return NULL;
psize /= 4;
bus->count_cells(dev, &na, &ns); if (!OF_CHECK_ADDR_COUNT(na)) return NULL;
onesize = na + ns; for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) {
u32 val = be32_to_cpu(prop[0]); /* PCI bus matches on BAR number instead of index */ if (((bar_no >= 0) && ((val & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0))) ||
((index >= 0) && (i == index))) { if (size)
*size = of_read_number(prop + na, ns); if (flags)
*flags = bus->get_flags(prop); return prop;
}
} return NULL;
}
EXPORT_SYMBOL(__of_get_address);
/** * of_property_read_reg - Retrieve the specified "reg" entry index without translating * @np: device tree node for which to retrieve "reg" from * @idx: "reg" entry index to read * @addr: return value for the untranslated address * @size: return value for the entry size * * Returns -EINVAL if "reg" is not found. Returns 0 on success with addr and * size values filled in.
*/ int of_property_read_reg(struct device_node *np, int idx, u64 *addr, u64 *size)
{ const __be32 *prop = of_get_address(np, idx, size, NULL);
struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser, struct of_pci_range *range)
{ int na = parser->na; int ns = parser->ns; int np = parser->pna + na + ns; int busflag_na = parser->bus->flag_cells;
if (!range) return NULL;
if (!parser->range || parser->range + np > parser->end) return NULL;
/* Now consume following elements while they are contiguous */ while (parser->range + np <= parser->end) {
u32 flags = 0;
u64 bus_addr, cpu_addr, size;
taddr = __of_translate_address(dev, of_get_parent,
in_addr, "ranges", &host); if (host) { /* host-specific port access */
port = logic_pio_trans_hwaddr(&host->fwnode, taddr, size);
of_node_put(host);
} else { /* memory-mapped I/O range */
port = pci_address_to_pio(taddr);
}
if (port == (unsignedlong)-1) return OF_BAD_ADDR;
return port;
}
#ifdef CONFIG_HAS_DMA /** * of_dma_get_range - Get DMA range info and put it into a map array * @np: device node to get DMA range info * @map: dma range structure to return * * Look in bottom up direction for the first "dma-ranges" property * and parse it. Put the information into a DMA offset map array. * * dma-ranges format: * DMA addr (dma_addr) : naddr cells * CPU addr (phys_addr_t) : pna cells * size : nsize cells * * It returns -ENODEV if "dma-ranges" property was not found for this * device in the DT.
*/ int of_dma_get_range(struct device_node *np, conststruct bus_dma_region **map)
{ struct device_node *node __free(device_node) = of_node_get(np); const __be32 *ranges = NULL; bool found_dma_ranges = false; struct of_range_parser parser; struct of_range range; struct bus_dma_region *r; int len, num_ranges = 0;
while (node) {
ranges = of_get_property(node, "dma-ranges", &len);
/* Ignore empty ranges, they imply no translation required */ if (ranges && len > 0) break;
/* Once we find 'dma-ranges', then a missing one is an error */ if (found_dma_ranges && !ranges) return -ENODEV;
found_dma_ranges = true;
node = of_get_next_dma_parent(node);
}
if (!node || !ranges) {
pr_debug("no dma-ranges found for node(%pOF)\n", np); return -ENODEV;
}
of_dma_range_parser_init(&parser, node);
for_each_of_range(&parser, &range) { if (range.cpu_addr == OF_BAD_ADDR) {
pr_err("translation of DMA address(%llx) to CPU address failed node(%pOF)\n",
range.bus_addr, node); continue;
}
num_ranges++;
}
if (!num_ranges) return -EINVAL;
r = kcalloc(num_ranges + 1, sizeof(*r), GFP_KERNEL); if (!r) return -ENOMEM;
/* * Record all info in the generic DMA ranges array for struct device, * returning an error if we don't find any parsable ranges.
*/
*map = r;
of_dma_range_parser_init(&parser, node);
for_each_of_range(&parser, &range) {
pr_debug("dma_addr(%llx) cpu_addr(%llx) size(%llx)\n",
range.bus_addr, range.cpu_addr, range.size); if (range.cpu_addr == OF_BAD_ADDR) continue;
r->cpu_start = range.cpu_addr;
r->dma_start = range.bus_addr;
r->size = range.size;
r++;
} return 0;
} #endif/* CONFIG_HAS_DMA */
/** * of_dma_get_max_cpu_address - Gets highest CPU address suitable for DMA * @np: The node to start searching from or NULL to start from the root * * Gets the highest CPU physical address that is addressable by all DMA masters * in the sub-tree pointed by np, or the whole tree if NULL is passed. If no * DMA constrained device is found, it returns PHYS_ADDR_MAX.
*/
phys_addr_t __init of_dma_get_max_cpu_address(struct device_node *np)
{
phys_addr_t max_cpu_addr = PHYS_ADDR_MAX; struct of_range_parser parser;
phys_addr_t subtree_max_addr; struct device_node *child; struct of_range range; const __be32 *ranges;
u64 cpu_end = 0; int len;
/** * of_dma_is_coherent - Check if device is coherent * @np: device node * * It returns true if "dma-coherent" property was found * for this device in the DT, or if DMA is coherent by * default for OF devices on the current platform and no * "dma-noncoherent" property was found for this device.
*/ bool of_dma_is_coherent(struct device_node *np)
{ struct device_node *node __free(device_node) = of_node_get(np);
while (node) { if (of_property_read_bool(node, "dma-coherent")) returntrue;
if (of_property_read_bool(node, "dma-noncoherent")) returnfalse;
/** * of_address_to_resource - Translate device tree address and return as resource * @dev: Caller's Device Node * @index: Index into the array * @r: Pointer to resource array * * Returns -EINVAL if the range cannot be converted to resource. * * Note that if your address is a PIO address, the conversion will fail if * the physical address can't be internally converted to an IO token with * pci_address_to_pio(), that is because it's either called too early or it * can't be matched to any host bridge IO space
*/ int of_address_to_resource(struct device_node *dev, int index, struct resource *r)
{ return __of_address_to_resource(dev, index, -1, r);
}
EXPORT_SYMBOL_GPL(of_address_to_resource);
int of_pci_address_to_resource(struct device_node *dev, int bar, struct resource *r)
{
if (!IS_ENABLED(CONFIG_PCI)) return -ENOSYS;
return __of_address_to_resource(dev, -1, bar, r);
}
EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
/** * of_iomap - Maps the memory mapped IO for a given device_node * @np: the device whose io range will be mapped * @index: index of the io range * * Returns a pointer to the mapped memory
*/ void __iomem *of_iomap(struct device_node *np, int index)
{ struct resource res;
if (of_address_to_resource(np, index, &res)) return NULL;
/* * of_io_request_and_map - Requests a resource and maps the memory mapped IO * for a given device_node * @device: the device whose io range will be mapped * @index: index of the io range * @name: name "override" for the memory region request or NULL * * Returns a pointer to the requested and mapped memory or an ERR_PTR() encoded * error code on failure. Usage example: * * base = of_io_request_and_map(node, 0, "foo"); * if (IS_ERR(base)) * return PTR_ERR(base);
*/ void __iomem *of_io_request_and_map(struct device_node *np, int index, constchar *name)
{ struct resource res; void __iomem *mem;
if (of_address_to_resource(np, index, &res)) return IOMEM_ERR_PTR(-EINVAL);
if (!name)
name = res.name; if (!request_mem_region(res.start, resource_size(&res), name)) return IOMEM_ERR_PTR(-EBUSY);
if (res.flags & IORESOURCE_MEM_NONPOSTED)
mem = ioremap_np(res.start, resource_size(&res)); else
mem = ioremap(res.start, resource_size(&res));
if (!mem) {
release_mem_region(res.start, resource_size(&res)); return IOMEM_ERR_PTR(-ENOMEM);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.