[SPARC]: Port sparc64 in-kernel device tree code to sparc32.
authorDavid S. Miller <davem@sunset.davemloft.net>
Fri, 23 Jun 2006 22:53:31 +0000 (15:53 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Sat, 24 Jun 2006 06:15:45 +0000 (23:15 -0700)
Signed-off-by: David S. Miller <davem@davemloft.net>
arch/sparc/kernel/Makefile
arch/sparc/kernel/ebus.c
arch/sparc/kernel/pcic.c
arch/sparc/kernel/prom.c [new file with mode: 0644]
arch/sparc/mm/init.c
drivers/net/sunhme.c
include/asm-sparc/ebus.h
include/asm-sparc/pbm.h
include/asm-sparc/prom.h [new file with mode: 0644]

index 1b83e21841b58adac62ed9f424068f886c5a2345..93e41d0dd8daa46ae5b51db5917942b0fc01b4f7 100644 (file)
@@ -12,7 +12,7 @@ obj-y    := entry.o wof.o wuf.o etrap.o rtrap.o traps.o $(IRQ_OBJS) \
            sys_sparc.o sunos_asm.o systbls.o \
            time.o windows.o cpu.o devices.o sclow.o \
            tadpole.o tick14.o ptrace.o sys_solaris.o \
-           unaligned.o muldiv.o semaphore.o
+           unaligned.o muldiv.o semaphore.o prom.o
 
 obj-$(CONFIG_PCI) += pcic.o
 obj-$(CONFIG_SUN4) += sun4setup.o
index 5c3529ceb5d60151704d1b8f92c381f485d32503..9d461da76399918693c87656b922c526696a97e2 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/ebus.h>
 #include <asm/io.h>
 #include <asm/oplib.h>
+#include <asm/prom.h>
 #include <asm/bpp.h>
 
 struct linux_ebus *ebus_chain = NULL;
@@ -83,79 +84,81 @@ int __init ebus_blacklist_irq(char *name)
        return 0;
 }
 
-void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
-                               struct linux_ebus_child *dev)
+void __init fill_ebus_child(struct device_node *dp,
+                           struct linux_ebus_child *dev)
 {
-       int regs[PROMREG_MAX];
-       int irqs[PROMREG_MAX];
-       char lbuf[128];
+       int *regs;
+       int *irqs;
        int i, len;
 
-       dev->prom_node = node;
-       prom_getstring(node, "name", lbuf, sizeof(lbuf));
-       strcpy(dev->prom_name, lbuf);
-
-       len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
-       if (len == -1) len = 0;
+       dev->prom_node = dp;
+       regs = of_get_property(dp, "reg", &len);
+       if (!regs)
+               len = 0;
        dev->num_addrs = len / sizeof(regs[0]);
 
        for (i = 0; i < dev->num_addrs; i++) {
                if (regs[i] >= dev->parent->num_addrs) {
                        prom_printf("UGH: property for %s was %d, need < %d\n",
-                                   dev->prom_name, len, dev->parent->num_addrs);
+                                   dev->prom_node->name, len,
+                                   dev->parent->num_addrs);
                        panic(__FUNCTION__);
                }
-               dev->resource[i].start = dev->parent->resource[regs[i]].start; /* XXX resource */
+
+               /* XXX resource */
+               dev->resource[i].start =
+                       dev->parent->resource[regs[i]].start;
        }
 
        for (i = 0; i < PROMINTR_MAX; i++)
                dev->irqs[i] = PCI_IRQ_NONE;
 
-       if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_name)) != 0) {
+       if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {
                dev->num_irqs = 1;
-       } else if ((len = prom_getproperty(node, "interrupts",
-           (char *)&irqs, sizeof(irqs))) == -1 || len == 0) {
-               dev->num_irqs = 0;
-               dev->irqs[0] = 0;
-               if (dev->parent->num_irqs != 0) {
-                       dev->num_irqs = 1;
-                       dev->irqs[0] = dev->parent->irqs[0];
-/* P3 */ /* printk("EBUS: dev %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); */
-               }
        } else {
-               dev->num_irqs = len / sizeof(irqs[0]);
-               if (irqs[0] == 0 || irqs[0] >= 8) {
-                       /*
-                        * XXX Zero is a valid pin number...
-                        * This works as long as Ebus is not wired to INTA#.
-                        */
-                       printk("EBUS: %s got bad irq %d from PROM\n",
-                           dev->prom_name, irqs[0]);
+               irqs = of_get_property(dp, "interrupts", &len);
+               if (!irqs) {
                        dev->num_irqs = 0;
                        dev->irqs[0] = 0;
+                       if (dev->parent->num_irqs != 0) {
+                               dev->num_irqs = 1;
+                               dev->irqs[0] = dev->parent->irqs[0];
+                       }
                } else {
-                       dev->irqs[0] = pcic_pin_to_irq(irqs[0], dev->prom_name);
+                       dev->num_irqs = len / sizeof(irqs[0]);
+                       if (irqs[0] == 0 || irqs[0] >= 8) {
+                               /*
+                                * XXX Zero is a valid pin number...
+                                * This works as long as Ebus is not wired
+                                * to INTA#.
+                                */
+                               printk("EBUS: %s got bad irq %d from PROM\n",
+                                      dev->prom_node->name, irqs[0]);
+                               dev->num_irqs = 0;
+                               dev->irqs[0] = 0;
+                       } else {
+                               dev->irqs[0] =
+                                       pcic_pin_to_irq(irqs[0],
+                                                       dev->prom_node->name);
+                       }
                }
        }
 }
 
-void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
+void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
 {
-       struct linux_prom_registers regs[PROMREG_MAX];
+       struct linux_prom_registers *regs;
        struct linux_ebus_child *child;
-       int irqs[PROMINTR_MAX];
-       char lbuf[128];
+       int *irqs;
        int i, n, len;
        unsigned long baseaddr;
 
-       dev->prom_node = node;
-       prom_getstring(node, "name", lbuf, sizeof(lbuf));
-       strcpy(dev->prom_name, lbuf);
+       dev->prom_node = dp;
 
-       len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
+       regs = of_get_property(dp, "reg", &len);
        if (len % sizeof(struct linux_prom_registers)) {
                prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
-                           dev->prom_name, len,
+                           dev->prom_node->name, len,
                            (int)sizeof(struct linux_prom_registers));
                panic(__FUNCTION__);
        }
@@ -197,7 +200,7 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
                        if ((baseaddr = (unsigned long) ioremap(baseaddr,
                            regs[i].reg_size)) == 0) {
                                panic("ebus: unable to remap dev %s",
-                                   dev->prom_name);
+                                     dev->prom_node->name);
                        }
                }
                dev->resource[i].start = baseaddr;      /* XXX Unaligned */
@@ -206,29 +209,33 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
        for (i = 0; i < PROMINTR_MAX; i++)
                dev->irqs[i] = PCI_IRQ_NONE;
 
-       if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_name)) != 0) {
+       if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {
                dev->num_irqs = 1;
-       } else if ((len = prom_getproperty(node, "interrupts",
-           (char *)&irqs, sizeof(irqs))) == -1 || len == 0) {
-               dev->num_irqs = 0;
-               if ((dev->irqs[0] = dev->bus->self->irq) != 0) {
-                        dev->num_irqs = 1;
-/* P3 */ /* printk("EBUS: child %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); */
-               }
        } else {
-               dev->num_irqs = 1;  /* dev->num_irqs = len / sizeof(irqs[0]); */
-               if (irqs[0] == 0 || irqs[0] >= 8) {
-                       /* See above for the parent. XXX */
-                       printk("EBUS: %s got bad irq %d from PROM\n",
-                           dev->prom_name, irqs[0]);
+               irqs = of_get_property(dp, "interrupts", &len);
+               if (!irqs) {
                        dev->num_irqs = 0;
-                       dev->irqs[0] = 0;
+                       if ((dev->irqs[0] = dev->bus->self->irq) != 0) {
+                               dev->num_irqs = 1;
+/* P3 */ /* printk("EBUS: child %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); */
+                       }
                } else {
-                       dev->irqs[0] = pcic_pin_to_irq(irqs[0], dev->prom_name);
+                       dev->num_irqs = 1;  /* dev->num_irqs = len / sizeof(irqs[0]); */
+                       if (irqs[0] == 0 || irqs[0] >= 8) {
+                               /* See above for the parent. XXX */
+                               printk("EBUS: %s got bad irq %d from PROM\n",
+                                      dev->prom_node->name, irqs[0]);
+                               dev->num_irqs = 0;
+                               dev->irqs[0] = 0;
+                       } else {
+                               dev->irqs[0] =
+                                       pcic_pin_to_irq(irqs[0],
+                                                       dev->prom_node->name);
+                       }
                }
        }
 
-       if ((node = prom_getchild(node))) {
+       if ((dp = dp->child) != NULL) {
                dev->children = (struct linux_ebus_child *)
                        ebus_alloc(sizeof(struct linux_ebus_child));
 
@@ -236,9 +243,9 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
                child->next = NULL;
                child->parent = dev;
                child->bus = dev->bus;
-               fill_ebus_child(node, &regs[0], child);
+               fill_ebus_child(dp, child);
 
-               while ((node = prom_getsibling(node)) != 0) {
+               while ((dp = dp->sibling) != NULL) {
                        child->next = (struct linux_ebus_child *)
                                ebus_alloc(sizeof(struct linux_ebus_child));
 
@@ -246,51 +253,49 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
                        child->next = NULL;
                        child->parent = dev;
                        child->bus = dev->bus;
-                       fill_ebus_child(node, &regs[0], child);
+                       fill_ebus_child(dp, child);
                }
        }
 }
 
 void __init ebus_init(void)
 {
-       struct linux_prom_pci_registers regs[PROMREG_MAX];
+       struct linux_prom_pci_registers *regs;
        struct linux_pbm_info *pbm;
        struct linux_ebus_device *dev;
        struct linux_ebus *ebus;
        struct ebus_system_entry *sp;
        struct pci_dev *pdev;
        struct pcidev_cookie *cookie;
-       char lbuf[128];
+       struct device_node *dp;
        unsigned long addr, *base;
        unsigned short pci_command;
-       int nd, len, ebusnd;
-       int reg, nreg;
+       int len, reg, nreg;
        int num_ebus = 0;
 
-       prom_getstring(prom_root_node, "name", lbuf, sizeof(lbuf));
+       dp = of_find_node_by_path("/");
        for (sp = ebus_blacklist; sp->esname != NULL; sp++) {
-               if (strcmp(lbuf, sp->esname) == 0) {
+               if (strcmp(dp->name, sp->esname) == 0) {
                        ebus_blackp = sp->ipt;
                        break;
                }
        }
 
        pdev = pci_get_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, NULL);
-       if (!pdev) {
+       if (!pdev)
                return;
-       }
+
        cookie = pdev->sysdata;
-       ebusnd = cookie->prom_node;
+       dp = cookie->prom_node;
 
        ebus_chain = ebus = (struct linux_ebus *)
                        ebus_alloc(sizeof(struct linux_ebus));
        ebus->next = NULL;
 
-       while (ebusnd) {
+       while (dp) {
+               struct device_node *nd;
 
-               prom_getstring(ebusnd, "name", lbuf, sizeof(lbuf));
-               ebus->prom_node = ebusnd;
-               strcpy(ebus->prom_name, lbuf);
+               ebus->prom_node = dp;
                ebus->self = pdev;
                ebus->parent = pbm = cookie->pbm;
 
@@ -299,9 +304,8 @@ void __init ebus_init(void)
                pci_command |= PCI_COMMAND_MASTER;
                pci_write_config_word(pdev, PCI_COMMAND, pci_command);
 
-               len = prom_getproperty(ebusnd, "reg", (void *)regs,
-                                      sizeof(regs));
-               if (len == 0 || len == -1) {
+               regs = of_get_property(dp, "reg", &len);
+               if (!regs) {
                        prom_printf("%s: can't find reg property\n",
                                    __FUNCTION__);
                        prom_halt();
@@ -317,7 +321,7 @@ void __init ebus_init(void)
                        *base++ = addr;
                }
 
-               nd = prom_getchild(ebusnd);
+               nd = dp->child;
                if (!nd)
                        goto next_ebus;
 
@@ -330,7 +334,7 @@ void __init ebus_init(void)
                dev->bus = ebus;
                fill_ebus_device(nd, dev);
 
-               while ((nd = prom_getsibling(nd)) != 0) {
+               while ((nd = nd->sibling) != NULL) {
                        dev->next = (struct linux_ebus_device *)
                                ebus_alloc(sizeof(struct linux_ebus_device));
 
@@ -348,7 +352,7 @@ void __init ebus_init(void)
                        break;
 
                cookie = pdev->sysdata;
-               ebusnd = cookie->prom_node;
+               dp = cookie->prom_node;
 
                ebus->next = (struct linux_ebus *)
                        ebus_alloc(sizeof(struct linux_ebus));
index bcdf5ad0f035cb545238568b1b56f9e2978e81ea..bcfdddd0418aeda77ab17a87c46e8df5f16287d8 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <asm/irq.h>
 #include <asm/oplib.h>
+#include <asm/prom.h>
 #include <asm/pcic.h>
 #include <asm/timer.h>
 #include <asm/uaccess.h>
@@ -665,7 +666,7 @@ void __init pcibios_fixup_bus(struct pci_bus *bus)
                /* cookies */
                pcp = pci_devcookie_alloc();
                pcp->pbm = &pcic->pbm;
-               pcp->prom_node = node;
+               pcp->prom_node = of_find_node_by_phandle(node);
                dev->sysdata = pcp;
 
                /* fixing I/O to look like memory */
diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c
new file mode 100644 (file)
index 0000000..63b2b9b
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+ * Procedures for creating, accessing and interpreting the device tree.
+ *
+ * Paul Mackerras      August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ * 
+ *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ *    {engebret|bergner}@us.ibm.com 
+ *
+ *  Adapted for sparc32 by David S. Miller davem@davemloft.net
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/module.h>
+
+#include <asm/prom.h>
+#include <asm/oplib.h>
+
+static struct device_node *allnodes;
+
+int of_device_is_compatible(struct device_node *device, const char *compat)
+{
+       const char* cp;
+       int cplen, l;
+
+       cp = (char *) of_get_property(device, "compatible", &cplen);
+       if (cp == NULL)
+               return 0;
+       while (cplen > 0) {
+               if (strncmp(cp, compat, strlen(compat)) == 0)
+                       return 1;
+               l = strlen(cp) + 1;
+               cp += l;
+               cplen -= l;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(of_device_is_compatible);
+
+struct device_node *of_get_parent(const struct device_node *node)
+{
+       struct device_node *np;
+
+       if (!node)
+               return NULL;
+
+       np = node->parent;
+
+       return np;
+}
+EXPORT_SYMBOL(of_get_parent);
+
+struct device_node *of_get_next_child(const struct device_node *node,
+       struct device_node *prev)
+{
+       struct device_node *next;
+
+       next = prev ? prev->sibling : node->child;
+       for (; next != 0; next = next->sibling) {
+               break;
+       }
+
+       return next;
+}
+EXPORT_SYMBOL(of_get_next_child);
+
+struct device_node *of_find_node_by_path(const char *path)
+{
+       struct device_node *np = allnodes;
+
+       for (; np != 0; np = np->allnext) {
+               if (np->full_name != 0 && strcmp(np->full_name, path) == 0)
+                       break;
+       }
+
+       return np;
+}
+EXPORT_SYMBOL(of_find_node_by_path);
+
+struct device_node *of_find_node_by_phandle(phandle handle)
+{
+       struct device_node *np;
+
+       for (np = allnodes; np != 0; np = np->allnext)
+               if (np->node == handle)
+                       break;
+
+       return np;
+}
+EXPORT_SYMBOL(of_find_node_by_phandle);
+
+struct device_node *of_find_node_by_name(struct device_node *from,
+       const char *name)
+{
+       struct device_node *np;
+
+       np = from ? from->allnext : allnodes;
+       for (; np != NULL; np = np->allnext)
+               if (np->name != NULL && strcmp(np->name, name) == 0)
+                       break;
+
+       return np;
+}
+EXPORT_SYMBOL(of_find_node_by_name);
+
+struct device_node *of_find_node_by_type(struct device_node *from,
+       const char *type)
+{
+       struct device_node *np;
+
+       np = from ? from->allnext : allnodes;
+       for (; np != 0; np = np->allnext)
+               if (np->type != 0 && strcmp(np->type, type) == 0)
+                       break;
+
+       return np;
+}
+EXPORT_SYMBOL(of_find_node_by_type);
+
+struct device_node *of_find_compatible_node(struct device_node *from,
+       const char *type, const char *compatible)
+{
+       struct device_node *np;
+
+       np = from ? from->allnext : allnodes;
+       for (; np != 0; np = np->allnext) {
+               if (type != NULL
+                   && !(np->type != 0 && strcmp(np->type, type) == 0))
+                       continue;
+               if (of_device_is_compatible(np, compatible))
+                       break;
+       }
+
+       return np;
+}
+EXPORT_SYMBOL(of_find_compatible_node);
+
+struct property *of_find_property(struct device_node *np, const char *name,
+                                 int *lenp)
+{
+       struct property *pp;
+
+       for (pp = np->properties; pp != 0; pp = pp->next) {
+               if (strcmp(pp->name, name) == 0) {
+                       if (lenp != 0)
+                               *lenp = pp->length;
+                       break;
+               }
+       }
+       return pp;
+}
+EXPORT_SYMBOL(of_find_property);
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+void *of_get_property(struct device_node *np, const char *name, int *lenp)
+{
+       struct property *pp = of_find_property(np,name,lenp);
+       return pp ? pp->value : NULL;
+}
+EXPORT_SYMBOL(of_get_property);
+
+int of_getintprop_default(struct device_node *np, const char *name, int def)
+{
+       struct property *prop;
+       int len;
+
+       prop = of_find_property(np, name, &len);
+       if (!prop || len != 4)
+               return def;
+
+       return *(int *) prop->value;
+}
+EXPORT_SYMBOL(of_getintprop_default);
+
+static unsigned int prom_early_allocated;
+
+static void * __init prom_early_alloc(unsigned long size)
+{
+       void *ret;
+
+       ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL);
+       if (ret != NULL)
+               memset(ret, 0, size);
+
+       prom_early_allocated += size;
+
+       return ret;
+}
+
+static int is_root_node(const struct device_node *dp)
+{
+       if (!dp)
+               return 0;
+
+       return (dp->parent == NULL);
+}
+
+/* The following routines deal with the black magic of fully naming a
+ * node.
+ *
+ * Certain well known named nodes are just the simple name string.
+ *
+ * Actual devices have an address specifier appended to the base name
+ * string, like this "foo@addr".  The "addr" can be in any number of
+ * formats, and the platform plus the type of the node determine the
+ * format and how it is constructed.
+ *
+ * For children of the ROOT node, the naming convention is fixed and
+ * determined by whether this is a sun4u or sun4v system.
+ *
+ * For children of other nodes, it is bus type specific.  So
+ * we walk up the tree until we discover a "device_type" property
+ * we recognize and we go from there.
+ */
+static void __init sparc32_path_component(struct device_node *dp, char *tmp_buf)
+{
+       struct linux_prom_registers *regs;
+       struct property *rprop;
+
+       rprop = of_find_property(dp, "reg", NULL);
+       if (!rprop)
+               return;
+
+       regs = rprop->value;
+       sprintf(tmp_buf, "%s@%x,%x",
+               dp->name,
+               regs->which_io, regs->phys_addr);
+}
+
+/* "name@slot,offset"  */
+static void __init sbus_path_component(struct device_node *dp, char *tmp_buf)
+{
+       struct linux_prom_registers *regs;
+       struct property *prop;
+
+       prop = of_find_property(dp, "reg", NULL);
+       if (!prop)
+               return;
+
+       regs = prop->value;
+       sprintf(tmp_buf, "%s@%x,%x",
+               dp->name,
+               regs->which_io,
+               regs->phys_addr);
+}
+
+/* "name@devnum[,func]" */
+static void __init pci_path_component(struct device_node *dp, char *tmp_buf)
+{
+       struct linux_prom_pci_registers *regs;
+       struct property *prop;
+       unsigned int devfn;
+
+       prop = of_find_property(dp, "reg", NULL);
+       if (!prop)
+               return;
+
+       regs = prop->value;
+       devfn = (regs->phys_hi >> 8) & 0xff;
+       if (devfn & 0x07) {
+               sprintf(tmp_buf, "%s@%x,%x",
+                       dp->name,
+                       devfn >> 3,
+                       devfn & 0x07);
+       } else {
+               sprintf(tmp_buf, "%s@%x",
+                       dp->name,
+                       devfn >> 3);
+       }
+}
+
+/* "name@addrhi,addrlo" */
+static void __init ebus_path_component(struct device_node *dp, char *tmp_buf)
+{
+       struct linux_prom_registers *regs;
+       struct property *prop;
+
+       prop = of_find_property(dp, "reg", NULL);
+       if (!prop)
+               return;
+
+       regs = prop->value;
+
+       sprintf(tmp_buf, "%s@%x,%x",
+               dp->name,
+               regs->which_io, regs->phys_addr);
+}
+
+static void __init __build_path_component(struct device_node *dp, char *tmp_buf)
+{
+       struct device_node *parent = dp->parent;
+
+       if (parent != NULL) {
+               if (!strcmp(parent->type, "pci") ||
+                   !strcmp(parent->type, "pciex"))
+                       return pci_path_component(dp, tmp_buf);
+               if (!strcmp(parent->type, "sbus"))
+                       return sbus_path_component(dp, tmp_buf);
+               if (!strcmp(parent->type, "ebus"))
+                       return ebus_path_component(dp, tmp_buf);
+
+               /* "isa" is handled with platform naming */
+       }
+
+       /* Use platform naming convention.  */
+       return sparc32_path_component(dp, tmp_buf);
+}
+
+static char * __init build_path_component(struct device_node *dp)
+{
+       char tmp_buf[64], *n;
+
+       tmp_buf[0] = '\0';
+       __build_path_component(dp, tmp_buf);
+       if (tmp_buf[0] == '\0')
+               strcpy(tmp_buf, dp->name);
+
+       n = prom_early_alloc(strlen(tmp_buf) + 1);
+       strcpy(n, tmp_buf);
+
+       return n;
+}
+
+static char * __init build_full_name(struct device_node *dp)
+{
+       int len, ourlen, plen;
+       char *n;
+
+       plen = strlen(dp->parent->full_name);
+       ourlen = strlen(dp->path_component_name);
+       len = ourlen + plen + 2;
+
+       n = prom_early_alloc(len);
+       strcpy(n, dp->parent->full_name);
+       if (!is_root_node(dp->parent)) {
+               strcpy(n + plen, "/");
+               plen++;
+       }
+       strcpy(n + plen, dp->path_component_name);
+
+       return n;
+}
+
+static struct property * __init build_one_prop(phandle node, char *prev)
+{
+       static struct property *tmp = NULL;
+       struct property *p;
+       int len;
+
+       if (tmp) {
+               p = tmp;
+               memset(p, 0, sizeof(*p) + 32);
+               tmp = NULL;
+       } else
+               p = prom_early_alloc(sizeof(struct property) + 32);
+
+       p->name = (char *) (p + 1);
+       if (prev == NULL) {
+               prom_firstprop(node, p->name);
+       } else {
+               prom_nextprop(node, prev, p->name);
+       }
+       if (strlen(p->name) == 0) {
+               tmp = p;
+               return NULL;
+       }
+       p->length = prom_getproplen(node, p->name);
+       if (p->length <= 0) {
+               p->length = 0;
+       } else {
+               p->value = prom_early_alloc(p->length);
+               len = prom_getproperty(node, p->name, p->value, p->length);
+       }
+       return p;
+}
+
+static struct property * __init build_prop_list(phandle node)
+{
+       struct property *head, *tail;
+
+       head = tail = build_one_prop(node, NULL);
+       while(tail) {
+               tail->next = build_one_prop(node, tail->name);
+               tail = tail->next;
+       }
+
+       return head;
+}
+
+static char * __init get_one_property(phandle node, char *name)
+{
+       char *buf = "<NULL>";
+       int len;
+
+       len = prom_getproplen(node, name);
+       if (len > 0) {
+               buf = prom_early_alloc(len);
+               len = prom_getproperty(node, name, buf, len);
+       }
+
+       return buf;
+}
+
+static struct device_node * __init create_node(phandle node)
+{
+       struct device_node *dp;
+
+       if (!node)
+               return NULL;
+
+       dp = prom_early_alloc(sizeof(*dp));
+
+       kref_init(&dp->kref);
+
+       dp->name = get_one_property(node, "name");
+       dp->type = get_one_property(node, "device_type");
+       dp->node = node;
+
+       /* Build interrupts later... */
+
+       dp->properties = build_prop_list(node);
+
+       return dp;
+}
+
+static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp)
+{
+       struct device_node *dp;
+
+       dp = create_node(node);
+       if (dp) {
+               *(*nextp) = dp;
+               *nextp = &dp->allnext;
+
+               dp->parent = parent;
+               dp->path_component_name = build_path_component(dp);
+               dp->full_name = build_full_name(dp);
+
+               dp->child = build_tree(dp, prom_getchild(node), nextp);
+
+               dp->sibling = build_tree(parent, prom_getsibling(node), nextp);
+       }
+
+       return dp;
+}
+
+void __init prom_build_devicetree(void)
+{
+       struct device_node **nextp;
+
+       allnodes = create_node(prom_root_node);
+       allnodes->path_component_name = "";
+       allnodes->full_name = "/";
+
+       nextp = &allnodes->allnext;
+       allnodes->child = build_tree(allnodes,
+                                    prom_getchild(allnodes->node),
+                                    &nextp);
+       printk("PROM: Built device tree with %u bytes of memory.\n",
+              prom_early_allocated);
+}
index 898669732466a2a51994efb09557ff75a546918d..cfa7d3456634d34b1bda95a706c8c9c60d9bb3b1 100644 (file)
@@ -31,6 +31,7 @@
 #include <asm/vaddrs.h>
 #include <asm/pgalloc.h>       /* bug in asm-generic/tlb.h: check_pgt_cache */
 #include <asm/tlb.h>
+#include <asm/prom.h>
 
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
@@ -349,6 +350,7 @@ void __init paging_init(void)
        protection_map[14] = PAGE_SHARED;
        protection_map[15] = PAGE_SHARED;
        btfixup();
+       prom_build_devicetree();
        device_scan();
 }
 
index b0d452733c9bfb8d2736002c3a19a00a913f0d54..cfec9e2c09324da4f210a254ba299eda57cc8665 100644 (file)
@@ -45,6 +45,7 @@
 #include <asm/sbus.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
+#include <asm/prom.h>
 #include <asm/auxio.h>
 #ifndef __sparc_v9__
 #include <asm/io-unit.h>
index 2d6a997c5b0c926a4cbccfe313465ec391a16f67..0dc3c01b4b1f5b6d409f521e438f9ef2900bdcc3 100644 (file)
 #include <linux/ioport.h>
 #endif
 #include <asm/oplib.h>
+#include <asm/prom.h>
 
 struct linux_ebus_child {
        struct linux_ebus_child         *next;
        struct linux_ebus_device        *parent;
        struct linux_ebus               *bus;
-       int                              prom_node;
-       char                             prom_name[64];
+       struct device_node              *prom_node;
        struct resource                  resource[PROMREG_MAX];
        int                              num_addrs;
        unsigned int                     irqs[PROMINTR_MAX];
@@ -30,8 +30,7 @@ struct linux_ebus_device {
        struct linux_ebus_device        *next;
        struct linux_ebus_child         *children;
        struct linux_ebus               *bus;
-       int                              prom_node;
-       char                             prom_name[64];
+       struct device_node              *prom_node;
        struct resource                  resource[PROMREG_MAX];
        int                              num_addrs;
        unsigned int                     irqs[PROMINTR_MAX];
@@ -43,10 +42,7 @@ struct linux_ebus {
        struct linux_ebus_device        *devices;
        struct linux_pbm_info           *parent;
        struct pci_dev                  *self;
-       int                              prom_node;
-       char                             prom_name[64];
-       struct linux_prom_ebus_ranges    ebus_ranges[PROMREG_MAX];
-       int                              num_ebus_ranges;
+       struct device_node              *prom_node;
 };
 
 struct linux_ebus_dma {
index 0aba3a82c2eb97d311eb5e8fae2ae95e2864cc51..fedd9c6e875c0cf271a7adaa0ae06ab6a3be06d1 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/pci.h>
 #include <asm/oplib.h>
+#include <asm/prom.h>
 
 struct linux_pbm_info {
        int             prom_node;
@@ -40,7 +41,7 @@ struct linux_pbm_info {
  */
 struct pcidev_cookie {
        struct linux_pbm_info           *pbm;
-       int                             prom_node;
+       struct device_node              *prom_node;
 };
 
 #endif /* !(__SPARC_PBM_H) */
diff --git a/include/asm-sparc/prom.h b/include/asm-sparc/prom.h
new file mode 100644 (file)
index 0000000..c5e3d26
--- /dev/null
@@ -0,0 +1,98 @@
+#ifndef _SPARC_PROM_H
+#define _SPARC_PROM_H
+#ifdef __KERNEL__
+
+
+/*
+ * Definitions for talking to the Open Firmware PROM on
+ * Power Macintosh computers.
+ *
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * Updates for PPC64 by Peter Bergner & David Engebretsen, IBM Corp.
+ * Updates for SPARC32 by David S. Miller
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <asm/atomic.h>
+
+typedef u32 phandle;
+typedef u32 ihandle;
+
+struct interrupt_info {
+       int     line;
+       int     sense;          /* +ve/-ve logic, edge or level, etc. */
+};
+
+struct property {
+       char    *name;
+       int     length;
+       void    *value;
+       struct property *next;
+};
+
+struct device_node {
+       char    *name;
+       char    *type;
+       phandle node;
+       phandle linux_phandle;
+       int     n_intrs;
+       struct  interrupt_info *intrs;
+       char    *path_component_name;
+       char    *full_name;
+
+       struct  property *properties;
+       struct  property *deadprops; /* removed properties */
+       struct  device_node *parent;
+       struct  device_node *child;
+       struct  device_node *sibling;
+       struct  device_node *next;      /* next device of same type */
+       struct  device_node *allnext;   /* next in list of all nodes */
+       struct  proc_dir_entry *pde;    /* this node's proc directory */
+       struct  kref kref;
+       unsigned long _flags;
+       void    *data;
+};
+
+static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
+{
+       dn->pde = de;
+}
+
+extern struct device_node *of_find_node_by_name(struct device_node *from,
+       const char *name);
+#define for_each_node_by_name(dn, name) \
+       for (dn = of_find_node_by_name(NULL, name); dn; \
+            dn = of_find_node_by_name(dn, name))
+extern struct device_node *of_find_node_by_type(struct device_node *from,
+       const char *type);
+#define for_each_node_by_type(dn, type) \
+       for (dn = of_find_node_by_type(NULL, type); dn; \
+            dn = of_find_node_by_type(dn, type))
+extern struct device_node *of_find_compatible_node(struct device_node *from,
+       const char *type, const char *compat);
+extern struct device_node *of_find_node_by_path(const char *path);
+extern struct device_node *of_find_node_by_phandle(phandle handle);
+extern struct device_node *of_get_parent(const struct device_node *node);
+extern struct device_node *of_get_next_child(const struct device_node *node,
+                                            struct device_node *prev);
+extern struct property *of_find_property(struct device_node *np,
+                                        const char *name,
+                                        int *lenp);
+extern int of_device_is_compatible(struct device_node *device, const char *);
+extern void *of_get_property(struct device_node *node, const char *name,
+                            int *lenp);
+extern int of_getintprop_default(struct device_node *np,
+                                const char *name,
+                                int def);
+
+extern void prom_build_devicetree(void);
+
+#endif /* __KERNEL__ */
+#endif /* _SPARC_PROM_H */