prom_parse.c
来自「linux 内核源代码」· C语言 代码 · 共 1,070 行 · 第 1/2 页
C
1,070 行
break; } DBG("OF: parent bus is %s (na=%d, ns=%d) on %s\n", pbus->name, pna, pns, parent->full_name); /* Apply bus translation */ if (of_translate_one(dev, bus, pbus, addr, na, ns, pna)) break; /* Complete the move up one level */ na = pna; ns = pns; bus = pbus; of_dump_addr("OF: one level translation:", addr, na); } bail: of_node_put(parent); of_node_put(dev); return result;}EXPORT_SYMBOL(of_translate_address);const u32 *of_get_address(struct device_node *dev, int index, u64 *size, unsigned int *flags){ const u32 *prop; unsigned int psize; struct device_node *parent; struct of_bus *bus; int onesize, i, na, ns; /* Get parent & match bus type */ parent = of_get_parent(dev); if (parent == NULL) return NULL; bus = of_match_bus(parent); bus->count_cells(dev, &na, &ns); of_node_put(parent); if (!OF_CHECK_COUNTS(na, ns)) return NULL; /* Get "reg" or "assigned-addresses" property */ prop = of_get_property(dev, bus->addresses, &psize); if (prop == NULL) return NULL; psize /= 4; onesize = na + ns; for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) if (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);static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, u64 size, unsigned int flags, struct resource *r){ u64 taddr; if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0) return -EINVAL; taddr = of_translate_address(dev, addrp); if (taddr == OF_BAD_ADDR) return -EINVAL; memset(r, 0, sizeof(struct resource)); if (flags & IORESOURCE_IO) { unsigned long port; port = pci_address_to_pio(taddr); if (port == (unsigned long)-1) return -EINVAL; r->start = port; r->end = port + size - 1; } else { r->start = taddr; r->end = taddr + size - 1; } r->flags = flags; r->name = dev->name; return 0;}int of_address_to_resource(struct device_node *dev, int index, struct resource *r){ const u32 *addrp; u64 size; unsigned int flags; addrp = of_get_address(dev, index, &size, &flags); if (addrp == NULL) return -EINVAL; return __of_address_to_resource(dev, addrp, size, flags, r);}EXPORT_SYMBOL_GPL(of_address_to_resource);void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, unsigned long *busno, unsigned long *phys, unsigned long *size){ const u32 *dma_window; u32 cells; const unsigned char *prop; dma_window = dma_window_prop; /* busno is always one cell */ *busno = *(dma_window++); prop = of_get_property(dn, "ibm,#dma-address-cells", NULL); if (!prop) prop = of_get_property(dn, "#address-cells", NULL); cells = prop ? *(u32 *)prop : of_n_addr_cells(dn); *phys = of_read_number(dma_window, cells); dma_window += cells; prop = of_get_property(dn, "ibm,#dma-size-cells", NULL); cells = prop ? *(u32 *)prop : of_n_size_cells(dn); *size = of_read_number(dma_window, cells);}/* * Interrupt remapper */static unsigned int of_irq_workarounds;static struct device_node *of_irq_dflt_pic;static struct device_node *of_irq_find_parent(struct device_node *child){ struct device_node *p; const phandle *parp; if (!of_node_get(child)) return NULL; do { parp = of_get_property(child, "interrupt-parent", NULL); if (parp == NULL) p = of_get_parent(child); else { if (of_irq_workarounds & OF_IMAP_NO_PHANDLE) p = of_node_get(of_irq_dflt_pic); else p = of_find_node_by_phandle(*parp); } of_node_put(child); child = p; } while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL); return p;}/* This doesn't need to be called if you don't have any special workaround * flags to pass */void of_irq_map_init(unsigned int flags){ of_irq_workarounds = flags; /* OldWorld, don't bother looking at other things */ if (flags & OF_IMAP_OLDWORLD_MAC) return; /* If we don't have phandles, let's try to locate a default interrupt * controller (happens when booting with BootX). We do a first match * here, hopefully, that only ever happens on machines with one * controller. */ if (flags & OF_IMAP_NO_PHANDLE) { struct device_node *np; for(np = NULL; (np = of_find_all_nodes(np)) != NULL;) { if (of_get_property(np, "interrupt-controller", NULL) == NULL) continue; /* Skip /chosen/interrupt-controller */ if (strcmp(np->name, "chosen") == 0) continue; /* It seems like at least one person on this planet wants * to use BootX on a machine with an AppleKiwi controller * which happens to pretend to be an interrupt * controller too. */ if (strcmp(np->name, "AppleKiwi") == 0) continue; /* I think we found one ! */ of_irq_dflt_pic = np; break; } }}int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize, const u32 *addr, struct of_irq *out_irq){ struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL; const u32 *tmp, *imap, *imask; u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0; int imaplen, match, i; DBG("of_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n", parent->full_name, intspec[0], intspec[1], ointsize); ipar = of_node_get(parent); /* First get the #interrupt-cells property of the current cursor * that tells us how to interpret the passed-in intspec. If there * is none, we are nice and just walk up the tree */ do { tmp = of_get_property(ipar, "#interrupt-cells", NULL); if (tmp != NULL) { intsize = *tmp; break; } tnode = ipar; ipar = of_irq_find_parent(ipar); of_node_put(tnode); } while (ipar); if (ipar == NULL) { DBG(" -> no parent found !\n"); goto fail; } DBG("of_irq_map_raw: ipar=%s, size=%d\n", ipar->full_name, intsize); if (ointsize != intsize) return -EINVAL; /* Look for this #address-cells. We have to implement the old linux * trick of looking for the parent here as some device-trees rely on it */ old = of_node_get(ipar); do { tmp = of_get_property(old, "#address-cells", NULL); tnode = of_get_parent(old); of_node_put(old); old = tnode; } while(old && tmp == NULL); of_node_put(old); old = NULL; addrsize = (tmp == NULL) ? 2 : *tmp; DBG(" -> addrsize=%d\n", addrsize); /* Now start the actual "proper" walk of the interrupt tree */ while (ipar != NULL) { /* Now check if cursor is an interrupt-controller and if it is * then we are done */ if (of_get_property(ipar, "interrupt-controller", NULL) != NULL) { DBG(" -> got it !\n"); memcpy(out_irq->specifier, intspec, intsize * sizeof(u32)); out_irq->size = intsize; out_irq->controller = ipar; of_node_put(old); return 0; } /* Now look for an interrupt-map */ imap = of_get_property(ipar, "interrupt-map", &imaplen); /* No interrupt map, check for an interrupt parent */ if (imap == NULL) { DBG(" -> no map, getting parent\n"); newpar = of_irq_find_parent(ipar); goto skiplevel; } imaplen /= sizeof(u32); /* Look for a mask */ imask = of_get_property(ipar, "interrupt-map-mask", NULL); /* If we were passed no "reg" property and we attempt to parse * an interrupt-map, then #address-cells must be 0. * Fail if it's not. */ if (addr == NULL && addrsize != 0) { DBG(" -> no reg passed in when needed !\n"); goto fail; } /* Parse interrupt-map */ match = 0; while (imaplen > (addrsize + intsize + 1) && !match) { /* Compare specifiers */ match = 1; for (i = 0; i < addrsize && match; ++i) { u32 mask = imask ? imask[i] : 0xffffffffu; match = ((addr[i] ^ imap[i]) & mask) == 0; } for (; i < (addrsize + intsize) && match; ++i) { u32 mask = imask ? imask[i] : 0xffffffffu; match = ((intspec[i-addrsize] ^ imap[i]) & mask) == 0; } imap += addrsize + intsize; imaplen -= addrsize + intsize; DBG(" -> match=%d (imaplen=%d)\n", match, imaplen); /* Get the interrupt parent */ if (of_irq_workarounds & OF_IMAP_NO_PHANDLE) newpar = of_node_get(of_irq_dflt_pic); else newpar = of_find_node_by_phandle((phandle)*imap); imap++; --imaplen; /* Check if not found */ if (newpar == NULL) { DBG(" -> imap parent not found !\n"); goto fail; } /* Get #interrupt-cells and #address-cells of new * parent */ tmp = of_get_property(newpar, "#interrupt-cells", NULL); if (tmp == NULL) { DBG(" -> parent lacks #interrupt-cells !\n"); goto fail; } newintsize = *tmp; tmp = of_get_property(newpar, "#address-cells", NULL); newaddrsize = (tmp == NULL) ? 0 : *tmp; DBG(" -> newintsize=%d, newaddrsize=%d\n", newintsize, newaddrsize); /* Check for malformed properties */ if (imaplen < (newaddrsize + newintsize)) goto fail; imap += newaddrsize + newintsize; imaplen -= newaddrsize + newintsize; DBG(" -> imaplen=%d\n", imaplen); } if (!match) goto fail; of_node_put(old); old = of_node_get(newpar); addrsize = newaddrsize; intsize = newintsize; intspec = imap - intsize; addr = intspec - addrsize; skiplevel: /* Iterate again with new parent */ DBG(" -> new parent: %s\n", newpar ? newpar->full_name : "<>"); of_node_put(ipar); ipar = newpar; newpar = NULL; } fail: of_node_put(ipar); of_node_put(old); of_node_put(newpar); return -EINVAL;}EXPORT_SYMBOL_GPL(of_irq_map_raw);#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)static int of_irq_map_oldworld(struct device_node *device, int index, struct of_irq *out_irq){ const u32 *ints = NULL; int intlen; /* * Old machines just have a list of interrupt numbers * and no interrupt-controller nodes. We also have dodgy * cases where the APPL,interrupts property is completely * missing behind pci-pci bridges and we have to get it * from the parent (the bridge itself, as apple just wired * everything together on these) */ while (device) { ints = of_get_property(device, "AAPL,interrupts", &intlen); if (ints != NULL) break; device = device->parent; if (device && strcmp(device->type, "pci") != 0) break; } if (ints == NULL) return -EINVAL; intlen /= sizeof(u32); if (index >= intlen) return -EINVAL; out_irq->controller = NULL; out_irq->specifier[0] = ints[index]; out_irq->size = 1; return 0;}#else /* defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32) */static int of_irq_map_oldworld(struct device_node *device, int index, struct of_irq *out_irq){ return -EINVAL;}#endif /* !(defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)) */int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq){ struct device_node *p; const u32 *intspec, *tmp, *addr; u32 intsize, intlen; int res; DBG("of_irq_map_one: dev=%s, index=%d\n", device->full_name, index); /* OldWorld mac stuff is "special", handle out of line */ if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC) return of_irq_map_oldworld(device, index, out_irq); /* Get the interrupts property */ intspec = of_get_property(device, "interrupts", &intlen); if (intspec == NULL) return -EINVAL; intlen /= sizeof(u32); /* Get the reg property (if any) */ addr = of_get_property(device, "reg", NULL); /* Look for the interrupt parent. */ p = of_irq_find_parent(device); if (p == NULL) return -EINVAL; /* Get size of interrupt specifier */ tmp = of_get_property(p, "#interrupt-cells", NULL); if (tmp == NULL) { of_node_put(p); return -EINVAL; } intsize = *tmp; DBG(" intsize=%d intlen=%d\n", intsize, intlen); /* Check index */ if ((index + 1) * intsize > intlen) return -EINVAL; /* Get new specifier and map it */ res = of_irq_map_raw(p, intspec + index * intsize, intsize, addr, out_irq); of_node_put(p); return res;}EXPORT_SYMBOL_GPL(of_irq_map_one);/** * Search the device tree for the best MAC address to use. 'mac-address' is * checked first, because that is supposed to contain to "most recent" MAC * address. If that isn't set, then 'local-mac-address' is checked next, * because that is the default address. If that isn't set, then the obsolete * 'address' is checked, just in case we're using an old device tree. * * Note that the 'address' property is supposed to contain a virtual address of * the register set, but some DTS files have redefined that property to be the * MAC address. * * All-zero MAC addresses are rejected, because those could be properties that * exist in the device tree, but were not set by U-Boot. For example, the * DTS could define 'mac-address' and 'local-mac-address', with zero MAC * addresses. Some older U-Boots only initialized 'local-mac-address'. In * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists * but is all zeros.*/const void *of_get_mac_address(struct device_node *np){ struct property *pp; pp = of_find_property(np, "mac-address", NULL); if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) return pp->value; pp = of_find_property(np, "local-mac-address", NULL); if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) return pp->value; pp = of_find_property(np, "address", NULL); if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) return pp->value; return NULL;}EXPORT_SYMBOL(of_get_mac_address);int of_irq_to_resource(struct device_node *dev, int index, struct resource *r){ int irq = irq_of_parse_and_map(dev, index); /* Only dereference the resource if both the * resource and the irq are valid. */ if (r && irq != NO_IRQ) { r->start = r->end = irq; r->flags = IORESOURCE_IRQ; } return irq;}EXPORT_SYMBOL_GPL(of_irq_to_resource);void __iomem *of_iomap(struct device_node *np, int index){ struct resource res; if (of_address_to_resource(np, index, &res)) return NULL; return ioremap(res.start, 1 + res.end - res.start);}EXPORT_SYMBOL(of_iomap);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?