Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
David S. Miller | 2819 | 90.99% | 38 | 49.35% |
Grant C. Likely | 97 | 3.13% | 6 | 7.79% |
Robert Reif | 61 | 1.97% | 2 | 2.60% |
Linus Torvalds (pre-git) | 33 | 1.07% | 11 | 14.29% |
Christoph Hellwig | 27 | 0.87% | 1 | 1.30% |
Rob Herring | 23 | 0.74% | 5 | 6.49% |
Stephen Rothwell | 14 | 0.45% | 2 | 2.60% |
Greg Kroah-Hartman | 5 | 0.16% | 2 | 2.60% |
Motohiro Kosaki | 4 | 0.13% | 1 | 1.30% |
Paul Gortmaker | 4 | 0.13% | 2 | 2.60% |
Linus Torvalds | 4 | 0.13% | 2 | 2.60% |
Simon Arlott | 2 | 0.06% | 1 | 1.30% |
Dawei Li | 2 | 0.06% | 1 | 1.30% |
Björn Helgaas | 1 | 0.03% | 1 | 1.30% |
Lucas De Marchi | 1 | 0.03% | 1 | 1.30% |
Rusty Russell | 1 | 0.03% | 1 | 1.30% |
Total | 3098 | 77 |
// SPDX-License-Identifier: GPL-2.0 #include <linux/string.h> #include <linux/kernel.h> #include <linux/dma-mapping.h> #include <linux/init.h> #include <linux/export.h> #include <linux/mod_devicetable.h> #include <linux/slab.h> #include <linux/errno.h> #include <linux/irq.h> #include <linux/of.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <asm/spitfire.h> #include "of_device_common.h" void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name) { unsigned long ret = res->start + offset; struct resource *r; if (res->flags & IORESOURCE_MEM) r = request_mem_region(ret, size, name); else r = request_region(ret, size, name); if (!r) ret = 0; return (void __iomem *) ret; } EXPORT_SYMBOL(of_ioremap); void of_iounmap(struct resource *res, void __iomem *base, unsigned long size) { if (res->flags & IORESOURCE_MEM) release_mem_region((unsigned long) base, size); else release_region((unsigned long) base, size); } EXPORT_SYMBOL(of_iounmap); /* * PCI bus specific translator */ static int of_bus_pci_match(struct device_node *np) { if (of_node_name_eq(np, "pci")) { const char *model = of_get_property(np, "model", NULL); if (model && !strcmp(model, "SUNW,simba")) return 0; /* Do not do PCI specific frobbing if the * PCI bridge lacks a ranges property. We * want to pass it through up to the next * parent as-is, not with the PCI translate * method which chops off the top address cell. */ if (!of_property_present(np, "ranges")) return 0; return 1; } return 0; } static int of_bus_simba_match(struct device_node *np) { const char *model = of_get_property(np, "model", NULL); if (model && !strcmp(model, "SUNW,simba")) return 1; /* Treat PCI busses lacking ranges property just like * simba. */ if (of_node_name_eq(np, "pci")) { if (!of_property_present(np, "ranges")) return 1; } return 0; } static int of_bus_simba_map(u32 *addr, const u32 *range, int na, int ns, int pna) { return 0; } static void of_bus_pci_count_cells(struct device_node *np, int *addrc, int *sizec) { if (addrc) *addrc = 3; if (sizec) *sizec = 2; } static int of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna) { u32 result[OF_MAX_ADDR_CELLS]; int i; /* Check address type match */ if (!((addr[0] ^ range[0]) & 0x03000000)) goto type_match; /* Special exception, we can map a 64-bit address into * a 32-bit range. */ if ((addr[0] & 0x03000000) == 0x03000000 && (range[0] & 0x03000000) == 0x02000000) goto type_match; return -EINVAL; type_match: if (of_out_of_range(addr + 1, range + 1, range + na + pna, na - 1, ns)) return -EINVAL; /* Start with the parent range base. */ memcpy(result, range + na, pna * 4); /* Add in the child address offset, skipping high cell. */ for (i = 0; i < na - 1; i++) result[pna - 1 - i] += (addr[na - 1 - i] - range[na - 1 - i]); memcpy(addr, result, pna * 4); return 0; } static unsigned long of_bus_pci_get_flags(const u32 *addr, unsigned long flags) { u32 w = addr[0]; /* For PCI, we override whatever child busses may have used. */ flags = 0; switch((w >> 24) & 0x03) { case 0x01: flags |= IORESOURCE_IO; break; case 0x02: /* 32 bits */ case 0x03: /* 64 bits */ flags |= IORESOURCE_MEM; break; } if (w & 0x40000000) flags |= IORESOURCE_PREFETCH; return flags; } /* * FHC/Central bus specific translator. * * This is just needed to hard-code the address and size cell * counts. 'fhc' and 'central' nodes lack the #address-cells and * #size-cells properties, and if you walk to the root on such * Enterprise boxes all you'll get is a #size-cells of 2 which is * not what we want to use. */ static int of_bus_fhc_match(struct device_node *np) { return of_node_name_eq(np, "fhc") || of_node_name_eq(np, "central"); } #define of_bus_fhc_count_cells of_bus_sbus_count_cells /* * Array of bus specific translators */ static struct of_bus of_busses[] = { /* PCI */ { .name = "pci", .addr_prop_name = "assigned-addresses", .match = of_bus_pci_match, .count_cells = of_bus_pci_count_cells, .map = of_bus_pci_map, .get_flags = of_bus_pci_get_flags, }, /* SIMBA */ { .name = "simba", .addr_prop_name = "assigned-addresses", .match = of_bus_simba_match, .count_cells = of_bus_pci_count_cells, .map = of_bus_simba_map, .get_flags = of_bus_pci_get_flags, }, /* SBUS */ { .name = "sbus", .addr_prop_name = "reg", .match = of_bus_sbus_match, .count_cells = of_bus_sbus_count_cells, .map = of_bus_default_map, .get_flags = of_bus_default_get_flags, }, /* FHC */ { .name = "fhc", .addr_prop_name = "reg", .match = of_bus_fhc_match, .count_cells = of_bus_fhc_count_cells, .map = of_bus_default_map, .get_flags = of_bus_default_get_flags, }, /* Default */ { .name = "default", .addr_prop_name = "reg", .match = NULL, .count_cells = of_bus_default_count_cells, .map = of_bus_default_map, .get_flags = of_bus_default_get_flags, }, }; static struct 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]; BUG(); return NULL; } static int __init build_one_resource(struct device_node *parent, struct of_bus *bus, struct of_bus *pbus, u32 *addr, int na, int ns, int pna) { const u32 *ranges; int rone, rlen; ranges = of_get_property(parent, "ranges", &rlen); if (ranges == NULL || rlen == 0) { u32 result[OF_MAX_ADDR_CELLS]; int i; memset(result, 0, pna * 4); for (i = 0; i < na; i++) result[pna - 1 - i] = addr[na - 1 - i]; memcpy(addr, result, pna * 4); return 0; } /* Now walk through the ranges */ rlen /= 4; rone = na + pna + ns; for (; rlen >= rone; rlen -= rone, ranges += rone) { if (!bus->map(addr, ranges, na, ns, pna)) return 0; } /* When we miss an I/O space match on PCI, just pass it up * to the next PCI bridge and/or controller. */ if (!strcmp(bus->name, "pci") && (addr[0] & 0x03000000) == 0x01000000) return 0; return 1; } static int __init use_1to1_mapping(struct device_node *pp) { /* If we have a ranges property in the parent, use it. */ if (of_property_present(pp, "ranges")) return 0; /* If the parent is the dma node of an ISA bus, pass * the translation up to the root. * * Some SBUS devices use intermediate nodes to express * hierarchy within the device itself. These aren't * real bus nodes, and don't have a 'ranges' property. * But, we should still pass the translation work up * to the SBUS itself. */ if (of_node_name_eq(pp, "dma") || of_node_name_eq(pp, "espdma") || of_node_name_eq(pp, "ledma") || of_node_name_eq(pp, "lebuffer")) return 0; /* Similarly for all PCI bridges, if we get this far * it lacks a ranges property, and this will include * cases like Simba. */ if (of_node_name_eq(pp, "pci")) return 0; return 1; } static int of_resource_verbose; static void __init build_device_resources(struct platform_device *op, struct device *parent) { struct platform_device *p_op; struct of_bus *bus; int na, ns; int index, num_reg; const void *preg; if (!parent) return; p_op = to_platform_device(parent); bus = of_match_bus(p_op->dev.of_node); bus->count_cells(op->dev.of_node, &na, &ns); preg = of_get_property(op->dev.of_node, bus->addr_prop_name, &num_reg); if (!preg || num_reg == 0) return; /* Convert to num-cells. */ num_reg /= 4; /* Convert to num-entries. */ num_reg /= na + ns; /* Prevent overrunning the op->resources[] array. */ if (num_reg > PROMREG_MAX) { printk(KERN_WARNING "%pOF: Too many regs (%d), " "limiting to %d.\n", op->dev.of_node, num_reg, PROMREG_MAX); num_reg = PROMREG_MAX; } op->resource = op->archdata.resource; op->num_resources = num_reg; for (index = 0; index < num_reg; index++) { struct resource *r = &op->resource[index]; u32 addr[OF_MAX_ADDR_CELLS]; const u32 *reg = (preg + (index * ((na + ns) * 4))); struct device_node *dp = op->dev.of_node; struct device_node *pp = p_op->dev.of_node; struct of_bus *pbus, *dbus; u64 size, result = OF_BAD_ADDR; unsigned long flags; int dna, dns; int pna, pns; size = of_read_addr(reg + na, ns); memcpy(addr, reg, na * 4); flags = bus->get_flags(addr, 0); if (use_1to1_mapping(pp)) { result = of_read_addr(addr, na); goto build_res; } dna = na; dns = ns; dbus = bus; while (1) { dp = pp; pp = dp->parent; if (!pp) { result = of_read_addr(addr, dna); break; } pbus = of_match_bus(pp); pbus->count_cells(dp, &pna, &pns); if (build_one_resource(dp, dbus, pbus, addr, dna, dns, pna)) break; flags = pbus->get_flags(addr, flags); dna = pna; dns = pns; dbus = pbus; } build_res: memset(r, 0, sizeof(*r)); if (of_resource_verbose) printk("%pOF reg[%d] -> %llx\n", op->dev.of_node, index, result); if (result != OF_BAD_ADDR) { if (tlb_type == hypervisor) result &= 0x0fffffffffffffffUL; r->start = result; r->end = result + size - 1; r->flags = flags; } r->name = op->dev.of_node->full_name; } } static struct device_node * __init apply_interrupt_map(struct device_node *dp, struct device_node *pp, const u32 *imap, int imlen, const u32 *imask, unsigned int *irq_p) { struct device_node *cp; unsigned int irq = *irq_p; struct of_bus *bus; phandle handle; const u32 *reg; int na, num_reg, i; bus = of_match_bus(pp); bus->count_cells(dp, &na, NULL); reg = of_get_property(dp, "reg", &num_reg); if (!reg || !num_reg) return NULL; imlen /= ((na + 3) * 4); handle = 0; for (i = 0; i < imlen; i++) { int j; for (j = 0; j < na; j++) { if ((reg[j] & imask[j]) != imap[j]) goto next; } if (imap[na] == irq) { handle = imap[na + 1]; irq = imap[na + 2]; break; } next: imap += (na + 3); } if (i == imlen) { /* Psycho and Sabre PCI controllers can have 'interrupt-map' * properties that do not include the on-board device * interrupts. Instead, the device's 'interrupts' property * is already a fully specified INO value. * * Handle this by deciding that, if we didn't get a * match in the parent's 'interrupt-map', and the * parent is an IRQ translator, then use the parent as * our IRQ controller. */ if (pp->irq_trans) return pp; return NULL; } *irq_p = irq; cp = of_find_node_by_phandle(handle); return cp; } static unsigned int __init pci_irq_swizzle(struct device_node *dp, struct device_node *pp, unsigned int irq) { const struct linux_prom_pci_registers *regs; unsigned int bus, devfn, slot, ret; if (irq < 1 || irq > 4) return irq; regs = of_get_property(dp, "reg", NULL); if (!regs) return irq; bus = (regs->phys_hi >> 16) & 0xff; devfn = (regs->phys_hi >> 8) & 0xff; slot = (devfn >> 3) & 0x1f; if (pp->irq_trans) { /* Derived from Table 8-3, U2P User's Manual. This branch * is handling a PCI controller that lacks a proper set of * interrupt-map and interrupt-map-mask properties. The * Ultra-E450 is one example. * * The bit layout is BSSLL, where: * B: 0 on bus A, 1 on bus B * D: 2-bit slot number, derived from PCI device number as * (dev - 1) for bus A, or (dev - 2) for bus B * L: 2-bit line number */ if (bus & 0x80) { /* PBM-A */ bus = 0x00; slot = (slot - 1) << 2; } else { /* PBM-B */ bus = 0x10; slot = (slot - 2) << 2; } irq -= 1; ret = (bus | slot | irq); } else { /* Going through a PCI-PCI bridge that lacks a set of * interrupt-map and interrupt-map-mask properties. */ ret = ((irq - 1 + (slot & 3)) & 3) + 1; } return ret; } static int of_irq_verbose; static unsigned int __init build_one_device_irq(struct platform_device *op, struct device *parent, unsigned int irq) { struct device_node *dp = op->dev.of_node; struct device_node *pp, *ip; unsigned int orig_irq = irq; int nid; if (irq == 0xffffffff) return irq; if (dp->irq_trans) { irq = dp->irq_trans->irq_build(dp, irq, dp->irq_trans->data); if (of_irq_verbose) printk("%pOF: direct translate %x --> %x\n", dp, orig_irq, irq); goto out; } /* Something more complicated. Walk up to the root, applying * interrupt-map or bus specific translations, until we hit * an IRQ translator. * * If we hit a bus type or situation we cannot handle, we * stop and assume that the original IRQ number was in a * format which has special meaning to its immediate parent. */ pp = dp->parent; ip = NULL; while (pp) { const void *imap, *imsk; int imlen; imap = of_get_property(pp, "interrupt-map", &imlen); imsk = of_get_property(pp, "interrupt-map-mask", NULL); if (imap && imsk) { struct device_node *iret; int this_orig_irq = irq; iret = apply_interrupt_map(dp, pp, imap, imlen, imsk, &irq); if (of_irq_verbose) printk("%pOF: Apply [%pOF:%x] imap --> [%pOF:%x]\n", op->dev.of_node, pp, this_orig_irq, iret, irq); if (!iret) break; if (iret->irq_trans) { ip = iret; break; } } else { if (of_node_name_eq(pp, "pci")) { unsigned int this_orig_irq = irq; irq = pci_irq_swizzle(dp, pp, irq); if (of_irq_verbose) printk("%pOF: PCI swizzle [%pOF] " "%x --> %x\n", op->dev.of_node, pp, this_orig_irq, irq); } if (pp->irq_trans) { ip = pp; break; } } dp = pp; pp = pp->parent; } if (!ip) return orig_irq; irq = ip->irq_trans->irq_build(op->dev.of_node, irq, ip->irq_trans->data); if (of_irq_verbose) printk("%pOF: Apply IRQ trans [%pOF] %x --> %x\n", op->dev.of_node, ip, orig_irq, irq); out: nid = of_node_to_nid(dp); if (nid != -1) { irq_set_affinity(irq, cpumask_of_node(nid)); } return irq; } static struct platform_device * __init scan_one_device(struct device_node *dp, struct device *parent) { struct platform_device *op = kzalloc(sizeof(*op), GFP_KERNEL); const unsigned int *irq; struct dev_archdata *sd; int len, i; if (!op) return NULL; sd = &op->dev.archdata; sd->op = op; op->dev.of_node = dp; irq = of_get_property(dp, "interrupts", &len); if (irq) { op->archdata.num_irqs = len / 4; /* Prevent overrunning the op->irqs[] array. */ if (op->archdata.num_irqs > PROMINTR_MAX) { printk(KERN_WARNING "%pOF: Too many irqs (%d), " "limiting to %d.\n", dp, op->archdata.num_irqs, PROMINTR_MAX); op->archdata.num_irqs = PROMINTR_MAX; } memcpy(op->archdata.irqs, irq, op->archdata.num_irqs * 4); } else { op->archdata.num_irqs = 0; } build_device_resources(op, parent); for (i = 0; i < op->archdata.num_irqs; i++) op->archdata.irqs[i] = build_one_device_irq(op, parent, op->archdata.irqs[i]); op->dev.parent = parent; op->dev.bus = &platform_bus_type; if (!parent) dev_set_name(&op->dev, "root"); else dev_set_name(&op->dev, "%08x", dp->phandle); op->dev.coherent_dma_mask = DMA_BIT_MASK(32); op->dev.dma_mask = &op->dev.coherent_dma_mask; if (of_device_register(op)) { printk("%pOF: Could not register of device.\n", dp); kfree(op); op = NULL; } return op; } static void __init scan_tree(struct device_node *dp, struct device *parent) { while (dp) { struct platform_device *op = scan_one_device(dp, parent); if (op) scan_tree(dp->child, &op->dev); dp = dp->sibling; } } static int __init scan_of_devices(void) { struct device_node *root = of_find_node_by_path("/"); struct platform_device *parent; parent = scan_one_device(root, NULL); if (!parent) return 0; scan_tree(root->child, &parent->dev); return 0; } postcore_initcall(scan_of_devices); static int __init of_debug(char *str) { int val = 0; get_option(&str, &val); if (val & 1) of_resource_verbose = 1; if (val & 2) of_irq_verbose = 1; return 1; } __setup("of_debug=", of_debug);
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1