]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - arch/sparc64/kernel/prom.c
Consolidate of_get_parent
[karo-tx-linux.git] / arch / sparc64 / kernel / prom.c
index 6625ac8d15fe860dfb8c5f12bf2a3da595680981..2462731ac1a3efec4b006ff0484eee9451e9ed3e 100644 (file)
 #include <asm/irq.h>
 #include <asm/asi.h>
 #include <asm/upa.h>
+#include <asm/smp.h>
 
 static struct device_node *allnodes;
 
-/* use when traversing tree through the allnext, child, sibling,
- * or parent members of struct device_node.
- */
-static DEFINE_RWLOCK(devtree_lock);
-
-int of_device_is_compatible(const struct device_node *device,
-                           const char *compat)
-{
-       const char* cp;
-       int cplen, l;
-
-       cp = 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);
+extern rwlock_t devtree_lock;  /* temporary while merging */
 
 struct device_node *of_get_next_child(const struct device_node *node,
        struct device_node *prev)
@@ -155,35 +119,6 @@ struct device_node *of_find_compatible_node(struct device_node *from,
 }
 EXPORT_SYMBOL(of_find_compatible_node);
 
-struct property *of_find_property(const struct device_node *np,
-                                 const char *name,
-                                 int *lenp)
-{
-       struct property *pp;
-
-       for (pp = np->properties; pp != 0; pp = pp->next) {
-               if (strcasecmp(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.
- */
-const void *of_get_property(const 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;
@@ -197,36 +132,6 @@ int of_getintprop_default(struct device_node *np, const char *name, int def)
 }
 EXPORT_SYMBOL(of_getintprop_default);
 
-int of_n_addr_cells(struct device_node *np)
-{
-       const int* ip;
-       do {
-               if (np->parent)
-                       np = np->parent;
-               ip = of_get_property(np, "#address-cells", NULL);
-               if (ip != NULL)
-                       return *ip;
-       } while (np->parent);
-       /* No #address-cells property for the root node, default to 2 */
-       return 2;
-}
-EXPORT_SYMBOL(of_n_addr_cells);
-
-int of_n_size_cells(struct device_node *np)
-{
-       const int* ip;
-       do {
-               if (np->parent)
-                       np = np->parent;
-               ip = of_get_property(np, "#size-cells", NULL);
-               if (ip != NULL)
-                       return *ip;
-       } while (np->parent);
-       /* No #size-cells property for the root node, default to 1 */
-       return 1;
-}
-EXPORT_SYMBOL(of_n_size_cells);
-
 int of_set_property(struct device_node *dp, const char *name, void *val, int len)
 {
        struct property **prevp;
@@ -396,7 +301,7 @@ static unsigned int psycho_irq_build(struct device_node *dp,
        return build_irq(inofixup, iclr, imap);
 }
 
-static void psycho_irq_trans_init(struct device_node *dp)
+static void __init psycho_irq_trans_init(struct device_node *dp)
 {
        const struct linux_prom64_registers *regs;
 
@@ -636,7 +541,7 @@ static unsigned int sabre_irq_build(struct device_node *dp,
        return virt_irq;
 }
 
-static void sabre_irq_trans_init(struct device_node *dp)
+static void __init sabre_irq_trans_init(struct device_node *dp)
 {
        const struct linux_prom64_registers *regs;
        struct sabre_irq_data *irq_data;
@@ -793,7 +698,8 @@ static unsigned int schizo_irq_build(struct device_node *dp,
        return virt_irq;
 }
 
-static void __schizo_irq_trans_init(struct device_node *dp, int is_tomatillo)
+static void __init __schizo_irq_trans_init(struct device_node *dp,
+                                          int is_tomatillo)
 {
        const struct linux_prom64_registers *regs;
        struct schizo_irq_data *irq_data;
@@ -815,12 +721,12 @@ static void __schizo_irq_trans_init(struct device_node *dp, int is_tomatillo)
        irq_data->chip_version = of_getintprop_default(dp, "version#", 0);
 }
 
-static void schizo_irq_trans_init(struct device_node *dp)
+static void __init schizo_irq_trans_init(struct device_node *dp)
 {
        __schizo_irq_trans_init(dp, 0);
 }
 
-static void tomatillo_irq_trans_init(struct device_node *dp)
+static void __init tomatillo_irq_trans_init(struct device_node *dp)
 {
        __schizo_irq_trans_init(dp, 1);
 }
@@ -834,7 +740,7 @@ static unsigned int pci_sun4v_irq_build(struct device_node *dp,
        return sun4v_build_irq(devhandle, devino);
 }
 
-static void pci_sun4v_irq_trans_init(struct device_node *dp)
+static void __init pci_sun4v_irq_trans_init(struct device_node *dp)
 {
        const struct linux_prom64_registers *regs;
 
@@ -898,7 +804,7 @@ static unsigned int fire_irq_build(struct device_node *dp,
        /* The interrupt map registers do not have an INO field
         * like other chips do.  They return zero in the INO
         * field, and the interrupt controller number is controlled
-        * in bits 6 thru 9.  So in order for build_irq() to get
+        * in bits 6 to 9.  So in order for build_irq() to get
         * the INO right we pass it in as part of the fixup
         * which will get added to the map register zero value
         * read by build_irq().
@@ -908,7 +814,7 @@ static unsigned int fire_irq_build(struct device_node *dp,
        return build_irq(ino, iclr, imap);
 }
 
-static void fire_irq_trans_init(struct device_node *dp)
+static void __init fire_irq_trans_init(struct device_node *dp)
 {
        const struct linux_prom64_registers *regs;
        struct fire_irq_data *irq_data;
@@ -931,29 +837,29 @@ static void fire_irq_trans_init(struct device_node *dp)
  * This should conform to both Sunfire/Wildfire server and Fusion
  * desktop designs.
  */
-#define SYSIO_IMAP_SLOT0       0x2c04UL
-#define SYSIO_IMAP_SLOT1       0x2c0cUL
-#define SYSIO_IMAP_SLOT2       0x2c14UL
-#define SYSIO_IMAP_SLOT3       0x2c1cUL
-#define SYSIO_IMAP_SCSI                0x3004UL
-#define SYSIO_IMAP_ETH         0x300cUL
-#define SYSIO_IMAP_BPP         0x3014UL
-#define SYSIO_IMAP_AUDIO       0x301cUL
-#define SYSIO_IMAP_PFAIL       0x3024UL
-#define SYSIO_IMAP_KMS         0x302cUL
-#define SYSIO_IMAP_FLPY                0x3034UL
-#define SYSIO_IMAP_SHW         0x303cUL
-#define SYSIO_IMAP_KBD         0x3044UL
-#define SYSIO_IMAP_MS          0x304cUL
-#define SYSIO_IMAP_SER         0x3054UL
-#define SYSIO_IMAP_TIM0                0x3064UL
-#define SYSIO_IMAP_TIM1                0x306cUL
-#define SYSIO_IMAP_UE          0x3074UL
-#define SYSIO_IMAP_CE          0x307cUL
-#define SYSIO_IMAP_SBERR       0x3084UL
-#define SYSIO_IMAP_PMGMT       0x308cUL
-#define SYSIO_IMAP_GFX         0x3094UL
-#define SYSIO_IMAP_EUPA                0x309cUL
+#define SYSIO_IMAP_SLOT0       0x2c00UL
+#define SYSIO_IMAP_SLOT1       0x2c08UL
+#define SYSIO_IMAP_SLOT2       0x2c10UL
+#define SYSIO_IMAP_SLOT3       0x2c18UL
+#define SYSIO_IMAP_SCSI                0x3000UL
+#define SYSIO_IMAP_ETH         0x3008UL
+#define SYSIO_IMAP_BPP         0x3010UL
+#define SYSIO_IMAP_AUDIO       0x3018UL
+#define SYSIO_IMAP_PFAIL       0x3020UL
+#define SYSIO_IMAP_KMS         0x3028UL
+#define SYSIO_IMAP_FLPY                0x3030UL
+#define SYSIO_IMAP_SHW         0x3038UL
+#define SYSIO_IMAP_KBD         0x3040UL
+#define SYSIO_IMAP_MS          0x3048UL
+#define SYSIO_IMAP_SER         0x3050UL
+#define SYSIO_IMAP_TIM0                0x3060UL
+#define SYSIO_IMAP_TIM1                0x3068UL
+#define SYSIO_IMAP_UE          0x3070UL
+#define SYSIO_IMAP_CE          0x3078UL
+#define SYSIO_IMAP_SBERR       0x3080UL
+#define SYSIO_IMAP_PMGMT       0x3088UL
+#define SYSIO_IMAP_GFX         0x3090UL
+#define SYSIO_IMAP_EUPA                0x3098UL
 
 #define bogon     ((unsigned long) -1)
 static unsigned long sysio_irq_offsets[] = {
@@ -1004,10 +910,10 @@ static unsigned long sysio_irq_offsets[] = {
  * Interrupt Clear register pointer, SYSIO specific version.
  */
 #define SYSIO_ICLR_UNUSED0     0x3400UL
-#define SYSIO_ICLR_SLOT0       0x340cUL
-#define SYSIO_ICLR_SLOT1       0x344cUL
-#define SYSIO_ICLR_SLOT2       0x348cUL
-#define SYSIO_ICLR_SLOT3       0x34ccUL
+#define SYSIO_ICLR_SLOT0       0x3408UL
+#define SYSIO_ICLR_SLOT1       0x3448UL
+#define SYSIO_ICLR_SLOT2       0x3488UL
+#define SYSIO_ICLR_SLOT3       0x34c8UL
 static unsigned long sysio_imap_to_iclr(unsigned long imap)
 {
        unsigned long diff = SYSIO_ICLR_UNUSED0 - SYSIO_IMAP_SLOT0;
@@ -1071,7 +977,7 @@ static unsigned int sbus_of_build_irq(struct device_node *dp,
        return build_irq(sbus_level, iclr, imap);
 }
 
-static void sbus_irq_trans_init(struct device_node *dp)
+static void __init sbus_irq_trans_init(struct device_node *dp)
 {
        const struct linux_prom64_registers *regs;
 
@@ -1118,7 +1024,7 @@ static unsigned int central_build_irq(struct device_node *dp,
        return build_irq(0, iclr, imap);
 }
 
-static void central_irq_trans_init(struct device_node *dp)
+static void __init central_irq_trans_init(struct device_node *dp)
 {
        dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
        dp->irq_trans->irq_build = central_build_irq;
@@ -1132,7 +1038,7 @@ struct irq_trans {
 };
 
 #ifdef CONFIG_PCI
-static struct irq_trans pci_irq_trans_table[] = {
+static struct irq_trans __initdata pci_irq_trans_table[] = {
        { "SUNW,sabre", sabre_irq_trans_init },
        { "pci108e,a000", sabre_irq_trans_init },
        { "pci108e,a001", sabre_irq_trans_init },
@@ -1158,7 +1064,7 @@ static unsigned int sun4v_vdev_irq_build(struct device_node *dp,
        return sun4v_build_irq(devhandle, devino);
 }
 
-static void sun4v_vdev_irq_trans_init(struct device_node *dp)
+static void __init sun4v_vdev_irq_trans_init(struct device_node *dp)
 {
        const struct linux_prom64_registers *regs;
 
@@ -1170,7 +1076,7 @@ static void sun4v_vdev_irq_trans_init(struct device_node *dp)
                ((regs->phys_addr >> 32UL) & 0x0fffffff);
 }
 
-static void irq_trans_init(struct device_node *dp)
+static void __init irq_trans_init(struct device_node *dp)
 {
 #ifdef CONFIG_PCI
        const char *model;
@@ -1635,10 +1541,21 @@ static struct device_node * __init create_node(phandle node, struct device_node
 
 static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp)
 {
+       struct device_node *ret = NULL, *prev_sibling = NULL;
        struct device_node *dp;
 
-       dp = create_node(node, parent);
-       if (dp) {
+       while (1) {
+               dp = create_node(node, parent);
+               if (!dp)
+                       break;
+
+               if (prev_sibling)
+                       prev_sibling->sibling = dp;
+
+               if (!ret)
+                       ret = dp;
+               prev_sibling = dp;
+
                *(*nextp) = dp;
                *nextp = &dp->allnext;
 
@@ -1647,10 +1564,159 @@ static struct device_node * __init build_tree(struct device_node *parent, phandl
 
                dp->child = build_tree(dp, prom_getchild(node), nextp);
 
-               dp->sibling = build_tree(parent, prom_getsibling(node), nextp);
+               node = prom_getsibling(node);
        }
 
-       return dp;
+       return ret;
+}
+
+static const char *get_mid_prop(void)
+{
+       return (tlb_type == spitfire ? "upa-portid" : "portid");
+}
+
+struct device_node *of_find_node_by_cpuid(int cpuid)
+{
+       struct device_node *dp;
+       const char *mid_prop = get_mid_prop();
+
+       for_each_node_by_type(dp, "cpu") {
+               int id = of_getintprop_default(dp, mid_prop, -1);
+               const char *this_mid_prop = mid_prop;
+
+               if (id < 0) {
+                       this_mid_prop = "cpuid";
+                       id = of_getintprop_default(dp, this_mid_prop, -1);
+               }
+
+               if (id < 0) {
+                       prom_printf("OF: Serious problem, cpu lacks "
+                                   "%s property", this_mid_prop);
+                       prom_halt();
+               }
+               if (cpuid == id)
+                       return dp;
+       }
+       return NULL;
+}
+
+static void __init of_fill_in_cpu_data(void)
+{
+       struct device_node *dp;
+       const char *mid_prop = get_mid_prop();
+
+       ncpus_probed = 0;
+       for_each_node_by_type(dp, "cpu") {
+               int cpuid = of_getintprop_default(dp, mid_prop, -1);
+               const char *this_mid_prop = mid_prop;
+               struct device_node *portid_parent;
+               int portid = -1;
+
+               portid_parent = NULL;
+               if (cpuid < 0) {
+                       this_mid_prop = "cpuid";
+                       cpuid = of_getintprop_default(dp, this_mid_prop, -1);
+                       if (cpuid >= 0) {
+                               int limit = 2;
+
+                               portid_parent = dp;
+                               while (limit--) {
+                                       portid_parent = portid_parent->parent;
+                                       if (!portid_parent)
+                                               break;
+                                       portid = of_getintprop_default(portid_parent,
+                                                                      "portid", -1);
+                                       if (portid >= 0)
+                                               break;
+                               }
+                       }
+               }
+
+               if (cpuid < 0) {
+                       prom_printf("OF: Serious problem, cpu lacks "
+                                   "%s property", this_mid_prop);
+                       prom_halt();
+               }
+
+               ncpus_probed++;
+
+#ifdef CONFIG_SMP
+               if (cpuid >= NR_CPUS)
+                       continue;
+#else
+               /* On uniprocessor we only want the values for the
+                * real physical cpu the kernel booted onto, however
+                * cpu_data() only has one entry at index 0.
+                */
+               if (cpuid != real_hard_smp_processor_id())
+                       continue;
+               cpuid = 0;
+#endif
+
+               cpu_data(cpuid).clock_tick =
+                       of_getintprop_default(dp, "clock-frequency", 0);
+
+               if (portid_parent) {
+                       cpu_data(cpuid).dcache_size =
+                               of_getintprop_default(dp, "l1-dcache-size",
+                                                     16 * 1024);
+                       cpu_data(cpuid).dcache_line_size =
+                               of_getintprop_default(dp, "l1-dcache-line-size",
+                                                     32);
+                       cpu_data(cpuid).icache_size =
+                               of_getintprop_default(dp, "l1-icache-size",
+                                                     8 * 1024);
+                       cpu_data(cpuid).icache_line_size =
+                               of_getintprop_default(dp, "l1-icache-line-size",
+                                                     32);
+                       cpu_data(cpuid).ecache_size =
+                               of_getintprop_default(dp, "l2-cache-size", 0);
+                       cpu_data(cpuid).ecache_line_size =
+                               of_getintprop_default(dp, "l2-cache-line-size", 0);
+                       if (!cpu_data(cpuid).ecache_size ||
+                           !cpu_data(cpuid).ecache_line_size) {
+                               cpu_data(cpuid).ecache_size =
+                                       of_getintprop_default(portid_parent,
+                                                             "l2-cache-size",
+                                                             (4 * 1024 * 1024));
+                               cpu_data(cpuid).ecache_line_size =
+                                       of_getintprop_default(portid_parent,
+                                                             "l2-cache-line-size", 64);
+                       }
+
+                       cpu_data(cpuid).core_id = portid + 1;
+                       cpu_data(cpuid).proc_id = portid;
+#ifdef CONFIG_SMP
+                       sparc64_multi_core = 1;
+#endif
+               } else {
+                       cpu_data(cpuid).dcache_size =
+                               of_getintprop_default(dp, "dcache-size", 16 * 1024);
+                       cpu_data(cpuid).dcache_line_size =
+                               of_getintprop_default(dp, "dcache-line-size", 32);
+
+                       cpu_data(cpuid).icache_size =
+                               of_getintprop_default(dp, "icache-size", 16 * 1024);
+                       cpu_data(cpuid).icache_line_size =
+                               of_getintprop_default(dp, "icache-line-size", 32);
+
+                       cpu_data(cpuid).ecache_size =
+                               of_getintprop_default(dp, "ecache-size",
+                                                     (4 * 1024 * 1024));
+                       cpu_data(cpuid).ecache_line_size =
+                               of_getintprop_default(dp, "ecache-line-size", 64);
+
+                       cpu_data(cpuid).core_id = 0;
+                       cpu_data(cpuid).proc_id = -1;
+               }
+
+#ifdef CONFIG_SMP
+               cpu_set(cpuid, cpu_present_map);
+               cpu_set(cpuid, cpu_possible_map);
+#endif
+       }
+
+       smp_fill_in_sib_core_maps();
 }
 
 void __init prom_build_devicetree(void)
@@ -1667,4 +1733,7 @@ void __init prom_build_devicetree(void)
                                     &nextp);
        printk("PROM: Built device tree with %u bytes of memory.\n",
               prom_early_allocated);
+
+       if (tlb_type != hypervisor)
+               of_fill_in_cpu_data();
 }