aboutsummaryrefslogtreecommitdiff
path: root/arch/sparc/kernel/of_device.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-10-15 13:46:29 +0200
committerIngo Molnar <mingo@elte.hu>2008-10-15 13:46:29 +0200
commitb2aaf8f74cdc84a9182f6cabf198b7763bcb9d40 (patch)
tree53ccb1c2c14751fe69cf93102e76e97021f6df07 /arch/sparc/kernel/of_device.c
parent4f962d4d65923d7b722192e729840cfb79af0a5a (diff)
parent278429cff8809958d25415ba0ed32b59866ab1a8 (diff)
Merge branch 'linus' into stackprotector
Conflicts: arch/x86/kernel/Makefile include/asm-x86/pda.h
Diffstat (limited to 'arch/sparc/kernel/of_device.c')
-rw-r--r--arch/sparc/kernel/of_device.c95
1 files changed, 68 insertions, 27 deletions
diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c
index cc4c235c4f5..0837bd52e28 100644
--- a/arch/sparc/kernel/of_device.c
+++ b/arch/sparc/kernel/of_device.c
@@ -29,15 +29,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 ebus_bus_type;
-EXPORT_SYMBOL(ebus_bus_type);
-#endif
+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);
+
+/* 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);
@@ -70,7 +93,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);
};
/*
@@ -130,8 +153,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;
}
@@ -194,17 +219,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;
@@ -235,7 +264,7 @@ static int of_bus_sbus_map(u32 *addr, const u32 *range, int na, int ns, int pna)
return of_bus_default_map(addr, range, na, ns, pna);
}
-static unsigned int of_bus_sbus_get_flags(const u32 *addr)
+static unsigned long of_bus_sbus_get_flags(const u32 *addr, unsigned long flags)
{
return IORESOURCE_MEM;
}
@@ -321,6 +350,27 @@ static int __init build_one_resource(struct device_node *parent,
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_find_property(pp, "ranges", NULL) != NULL)
+ return 0;
+
+ /* 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") ||
+ !strcmp(pp->name, "espdma") ||
+ !strcmp(pp->name, "ledma") ||
+ !strcmp(pp->name, "lebuffer"))
+ return 0;
+
+ return 1;
+}
+
static int of_resource_verbose;
static void __init build_device_resources(struct of_device *op,
@@ -362,14 +412,12 @@ 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);
- /* If the immediate parent has no ranges property to apply,
- * just use a 1<->1 mapping.
- */
- if (of_find_property(pp, "ranges", NULL) == NULL) {
+ flags = bus->get_flags(reg, 0);
+
+ if (use_1to1_mapping(pp)) {
result = of_read_addr(addr, na);
goto build_res;
}
@@ -393,6 +441,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;
@@ -556,15 +606,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(&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();