diff options
Diffstat (limited to 'arch/sparc64/kernel/of_device.c')
-rw-r--r-- | arch/sparc64/kernel/of_device.c | 98 |
1 files changed, 61 insertions, 37 deletions
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index d569f60c24b..0f616ae3246 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -55,18 +55,38 @@ struct of_device *of_find_device_by_node(struct device_node *dp) } EXPORT_SYMBOL(of_find_device_by_node); -#ifdef CONFIG_PCI -struct bus_type isa_bus_type; -EXPORT_SYMBOL(isa_bus_type); +unsigned int irq_of_parse_and_map(struct device_node *node, int index) +{ + struct of_device *op = of_find_device_by_node(node); + + if (!op || index >= op->num_irqs) + return 0; + + return op->irqs[index]; +} +EXPORT_SYMBOL(irq_of_parse_and_map); -struct bus_type ebus_bus_type; -EXPORT_SYMBOL(ebus_bus_type); -#endif +/* Take the archdata values for IOMMU, STC, and HOSTDATA found in + * BUS and propagate to all child of_device objects. + */ +void of_propagate_archdata(struct of_device *bus) +{ + struct dev_archdata *bus_sd = &bus->dev.archdata; + struct device_node *bus_dp = bus->node; + struct device_node *dp; + + for (dp = bus_dp->child; dp; dp = dp->sibling) { + struct of_device *op = of_find_device_by_node(dp); -#ifdef CONFIG_SBUS -struct bus_type sbus_bus_type; -EXPORT_SYMBOL(sbus_bus_type); -#endif + op->dev.archdata.iommu = bus_sd->iommu; + op->dev.archdata.stc = bus_sd->stc; + op->dev.archdata.host_controller = bus_sd->host_controller; + op->dev.archdata.numa_node = bus_sd->numa_node; + + if (dp->child) + of_propagate_archdata(op); + } +} struct bus_type of_platform_bus_type; EXPORT_SYMBOL(of_platform_bus_type); @@ -99,7 +119,7 @@ struct of_bus { int *addrc, int *sizec); int (*map)(u32 *addr, const u32 *range, int na, int ns, int pna); - unsigned int (*get_flags)(const u32 *addr); + unsigned long (*get_flags)(const u32 *addr, unsigned long); }; /* @@ -159,8 +179,10 @@ static int of_bus_default_map(u32 *addr, const u32 *range, return 0; } -static unsigned int of_bus_default_get_flags(const u32 *addr) +static unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags) { + if (flags) + return flags; return IORESOURCE_MEM; } @@ -170,7 +192,7 @@ static unsigned int of_bus_default_get_flags(const u32 *addr) static int of_bus_pci_match(struct device_node *np) { - if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) { + if (!strcmp(np->name, "pci")) { const char *model = of_get_property(np, "model", NULL); if (model && !strcmp(model, "SUNW,simba")) @@ -201,7 +223,7 @@ static int of_bus_simba_match(struct device_node *np) /* Treat PCI busses lacking ranges property just like * simba. */ - if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) { + if (!strcmp(np->name, "pci")) { if (!of_find_property(np, "ranges", NULL)) return 1; } @@ -252,17 +274,21 @@ static int of_bus_pci_map(u32 *addr, const u32 *range, return 0; } -static unsigned int of_bus_pci_get_flags(const u32 *addr) +static unsigned long of_bus_pci_get_flags(const u32 *addr, unsigned long flags) { - unsigned int flags = 0; 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; @@ -375,8 +401,7 @@ static int __init build_one_resource(struct device_node *parent, int na, int ns, int pna) { const u32 *ranges; - unsigned int rlen; - int rone; + int rone, rlen; ranges = of_get_property(parent, "ranges", &rlen); if (ranges == NULL || rlen == 0) { @@ -418,15 +443,24 @@ static int __init use_1to1_mapping(struct device_node *pp) /* 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 (!strcmp(pp->name, "dma")) + if (!strcmp(pp->name, "dma") || + !strcmp(pp->name, "espdma") || + !strcmp(pp->name, "ledma") || + !strcmp(pp->name, "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 (!strcmp(pp->type, "pci") || !strcmp(pp->type, "pciex")) + if (!strcmp(pp->name, "pci")) return 0; return 1; @@ -481,10 +515,10 @@ static void __init build_device_resources(struct of_device *op, int pna, pns; size = of_read_addr(reg + na, ns); - flags = bus->get_flags(reg); - 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; @@ -509,6 +543,8 @@ static void __init build_device_resources(struct of_device *op, dna, dns, pna)) break; + flags = pbus->get_flags(addr, flags); + dna = pna; dns = pns; dbus = pbus; @@ -709,8 +745,7 @@ static unsigned int __init build_one_device_irq(struct of_device *op, break; } } else { - if (!strcmp(pp->type, "pci") || - !strcmp(pp->type, "pciex")) { + if (!strcmp(pp->name, "pci")) { unsigned int this_orig_irq = irq; irq = pci_irq_swizzle(dp, pp, irq); @@ -797,9 +832,9 @@ static struct of_device * __init scan_one_device(struct device_node *dp, op->dev.parent = parent; op->dev.bus = &of_platform_bus_type; if (!parent) - strcpy(op->dev.bus_id, "root"); + dev_set_name(&op->dev, "root"); else - sprintf(op->dev.bus_id, "%08x", dp->node); + dev_set_name(&op->dev, "%08x", dp->node); if (of_device_register(op)) { printk("%s: Could not register of device.\n", @@ -840,17 +875,6 @@ static int __init of_bus_driver_init(void) int err; err = of_bus_type_init(&of_platform_bus_type, "of"); -#ifdef CONFIG_PCI - if (!err) - err = of_bus_type_init(&isa_bus_type, "isa"); - if (!err) - err = of_bus_type_init(&ebus_bus_type, "ebus"); -#endif -#ifdef CONFIG_SBUS - if (!err) - err = of_bus_type_init(&sbus_bus_type, "sbus"); -#endif - if (!err) scan_of_devices(); |