Merge master.kernel.org:/pub/scm/linux/kernel/git/herbert/crypto-2.6
[linux-drm-fsl-dcu.git] / arch / sparc64 / kernel / prom.c
index 5cc5ab63293fa912188053b8d7a9a360e60fd3e5..c54d4d8af0142530d861074fe6afdb8b9081d207 100644 (file)
@@ -15,7 +15,6 @@
  *      2 of the License, or (at your option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/string.h>
@@ -37,12 +36,13 @@ static struct device_node *allnodes;
  */
 static DEFINE_RWLOCK(devtree_lock);
 
-int of_device_is_compatible(struct device_node *device, const char *compat)
+int of_device_is_compatible(const struct device_node *device,
+                           const char *compat)
 {
        const char* cp;
        int cplen, l;
 
-       cp = (char *) of_get_property(device, "compatible", &cplen);
+       cp = of_get_property(device, "compatible", &cplen);
        if (cp == NULL)
                return 0;
        while (cplen > 0) {
@@ -155,13 +155,14 @@ struct device_node *of_find_compatible_node(struct device_node *from,
 }
 EXPORT_SYMBOL(of_find_compatible_node);
 
-struct property *of_find_property(struct device_node *np, const char *name,
+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 (strcmp(pp->name, name) == 0) {
+               if (strcasecmp(pp->name, name) == 0) {
                        if (lenp != 0)
                                *lenp = pp->length;
                        break;
@@ -175,7 +176,8 @@ 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)
+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;
@@ -197,7 +199,7 @@ EXPORT_SYMBOL(of_getintprop_default);
 
 int of_n_addr_cells(struct device_node *np)
 {
-       int* ip;
+       const int* ip;
        do {
                if (np->parent)
                        np = np->parent;
@@ -212,7 +214,7 @@ EXPORT_SYMBOL(of_n_addr_cells);
 
 int of_n_size_cells(struct device_node *np)
 {
-       int* ip;
+       const int* ip;
        do {
                if (np->parent)
                        np = np->parent;
@@ -244,7 +246,7 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len
        while (*prevp) {
                struct property *prop = *prevp;
 
-               if (!strcmp(prop->name, name)) {
+               if (!strcasecmp(prop->name, name)) {
                        void *old_val = prop->value;
                        int ret;
 
@@ -384,11 +386,9 @@ static unsigned int psycho_irq_build(struct device_node *dp,
 
        /* Now build the IRQ bucket. */
        imap = controller_regs + imap_off;
-       imap += 4;
 
        iclr_off = psycho_iclr_offset(ino);
        iclr = controller_regs + iclr_off;
-       iclr += 4;
 
        if ((ino & 0x20) == 0)
                inofixup = ino & 0x03;
@@ -396,9 +396,9 @@ 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)
 {
-       struct linux_prom64_registers *regs;
+       const struct linux_prom64_registers *regs;
 
        dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
        dp->irq_trans->irq_build = psycho_irq_build;
@@ -548,7 +548,7 @@ static unsigned long __sabre_onboard_imap_off[] = {
 static int sabre_device_needs_wsync(struct device_node *dp)
 {
        struct device_node *parent = dp->parent;
-       char *parent_model, *parent_compat;
+       const char *parent_model, *parent_compat;
 
        /* This traversal up towards the root is meant to
         * handle two cases:
@@ -590,7 +590,7 @@ static unsigned int sabre_irq_build(struct device_node *dp,
 {
        struct sabre_irq_data *irq_data = _data;
        unsigned long controller_regs = irq_data->controller_regs;
-       struct linux_prom_pci_registers *regs;
+       const struct linux_prom_pci_registers *regs;
        unsigned long imap, iclr;
        unsigned long imap_off, iclr_off;
        int inofixup = 0;
@@ -611,11 +611,9 @@ static unsigned int sabre_irq_build(struct device_node *dp,
 
        /* Now build the IRQ bucket. */
        imap = controller_regs + imap_off;
-       imap += 4;
 
        iclr_off = sabre_iclr_offset(ino);
        iclr = controller_regs + iclr_off;
-       iclr += 4;
 
        if ((ino & 0x20) == 0)
                inofixup = ino & 0x03;
@@ -638,11 +636,11 @@ 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)
 {
-       struct linux_prom64_registers *regs;
+       const struct linux_prom64_registers *regs;
        struct sabre_irq_data *irq_data;
-       u32 *busrange;
+       const u32 *busrange;
 
        dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
        dp->irq_trans->irq_build = sabre_irq_build;
@@ -677,13 +675,14 @@ static unsigned long schizo_iclr_offset(unsigned long ino)
 static unsigned long schizo_ino_to_iclr(unsigned long pbm_regs,
                                        unsigned int ino)
 {
-       return pbm_regs + schizo_iclr_offset(ino) + 4;
+
+       return pbm_regs + schizo_iclr_offset(ino);
 }
 
 static unsigned long schizo_ino_to_imap(unsigned long pbm_regs,
                                        unsigned int ino)
 {
-       return pbm_regs + schizo_imap_offset(ino) + 4;
+       return pbm_regs + schizo_imap_offset(ino);
 }
 
 #define schizo_read(__reg) \
@@ -794,9 +793,10 @@ static unsigned int schizo_irq_build(struct device_node *dp,
        return virt_irq;
 }
 
-static void schizo_irq_trans_init(struct device_node *dp)
+static void __init __schizo_irq_trans_init(struct device_node *dp,
+                                          int is_tomatillo)
 {
-       struct linux_prom64_registers *regs;
+       const struct linux_prom64_registers *regs;
        struct schizo_irq_data *irq_data;
 
        dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
@@ -808,11 +808,24 @@ static void schizo_irq_trans_init(struct device_node *dp)
        dp->irq_trans->data = irq_data;
 
        irq_data->pbm_regs = regs[0].phys_addr;
-       irq_data->sync_reg = regs[3].phys_addr + 0x1a18UL;
+       if (is_tomatillo)
+               irq_data->sync_reg = regs[3].phys_addr + 0x1a18UL;
+       else
+               irq_data->sync_reg = 0UL;
        irq_data->portid = of_getintprop_default(dp, "portid", 0);
        irq_data->chip_version = of_getintprop_default(dp, "version#", 0);
 }
 
+static void __init schizo_irq_trans_init(struct device_node *dp)
+{
+       __schizo_irq_trans_init(dp, 0);
+}
+
+static void __init tomatillo_irq_trans_init(struct device_node *dp)
+{
+       __schizo_irq_trans_init(dp, 1);
+}
+
 static unsigned int pci_sun4v_irq_build(struct device_node *dp,
                                        unsigned int devino,
                                        void *_data)
@@ -822,9 +835,9 @@ 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)
 {
-       struct linux_prom64_registers *regs;
+       const struct linux_prom64_registers *regs;
 
        dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
        dp->irq_trans->irq_build = pci_sun4v_irq_build;
@@ -833,6 +846,85 @@ static void pci_sun4v_irq_trans_init(struct device_node *dp)
        dp->irq_trans->data = (void *) (unsigned long)
                ((regs->phys_addr >> 32UL) & 0x0fffffff);
 }
+
+struct fire_irq_data {
+       unsigned long pbm_regs;
+       u32 portid;
+};
+
+#define FIRE_IMAP_BASE 0x001000
+#define FIRE_ICLR_BASE 0x001400
+
+static unsigned long fire_imap_offset(unsigned long ino)
+{
+       return FIRE_IMAP_BASE + (ino * 8UL);
+}
+
+static unsigned long fire_iclr_offset(unsigned long ino)
+{
+       return FIRE_ICLR_BASE + (ino * 8UL);
+}
+
+static unsigned long fire_ino_to_iclr(unsigned long pbm_regs,
+                                           unsigned int ino)
+{
+       return pbm_regs + fire_iclr_offset(ino);
+}
+
+static unsigned long fire_ino_to_imap(unsigned long pbm_regs,
+                                           unsigned int ino)
+{
+       return pbm_regs + fire_imap_offset(ino);
+}
+
+static unsigned int fire_irq_build(struct device_node *dp,
+                                        unsigned int ino,
+                                        void *_data)
+{
+       struct fire_irq_data *irq_data = _data;
+       unsigned long pbm_regs = irq_data->pbm_regs;
+       unsigned long imap, iclr;
+       unsigned long int_ctrlr;
+
+       ino &= 0x3f;
+
+       /* Now build the IRQ bucket. */
+       imap = fire_ino_to_imap(pbm_regs, ino);
+       iclr = fire_ino_to_iclr(pbm_regs, ino);
+
+       /* Set the interrupt controller number.  */
+       int_ctrlr = 1 << 6;
+       upa_writeq(int_ctrlr, imap);
+
+       /* 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
+        * 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().
+        */
+       ino |= (irq_data->portid << 6);
+       ino -= int_ctrlr;
+       return build_irq(ino, iclr, imap);
+}
+
+static void __init fire_irq_trans_init(struct device_node *dp)
+{
+       const struct linux_prom64_registers *regs;
+       struct fire_irq_data *irq_data;
+
+       dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
+       dp->irq_trans->irq_build = fire_irq_build;
+
+       irq_data = prom_early_alloc(sizeof(struct fire_irq_data));
+
+       regs = of_get_property(dp, "reg", NULL);
+       dp->irq_trans->data = irq_data;
+
+       irq_data->pbm_regs = regs[0].phys_addr;
+       irq_data->portid = of_getintprop_default(dp, "portid", 0);
+}
 #endif /* CONFIG_PCI */
 
 #ifdef CONFIG_SBUS
@@ -928,7 +1020,7 @@ static unsigned int sbus_of_build_irq(struct device_node *dp,
                                      void *_data)
 {
        unsigned long reg_base = (unsigned long) _data;
-       struct linux_prom_registers *regs;
+       const struct linux_prom_registers *regs;
        unsigned long imap, iclr;
        int sbus_slot = 0;
        int sbus_level = 0;
@@ -980,9 +1072,9 @@ 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)
 {
-       struct linux_prom64_registers *regs;
+       const struct linux_prom64_registers *regs;
 
        dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
        dp->irq_trans->irq_build = sbus_of_build_irq;
@@ -1027,7 +1119,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;
@@ -1041,7 +1133,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 },
@@ -1051,9 +1143,10 @@ static struct irq_trans pci_irq_trans_table[] = {
        { "pci108e,8001", schizo_irq_trans_init },
        { "SUNW,schizo+", schizo_irq_trans_init },
        { "pci108e,8002", schizo_irq_trans_init },
-       { "SUNW,tomatillo", schizo_irq_trans_init },
-       { "pci108e,a801", schizo_irq_trans_init },
+       { "SUNW,tomatillo", tomatillo_irq_trans_init },
+       { "pci108e,a801", tomatillo_irq_trans_init },
        { "SUNW,sun4v-pci", pci_sun4v_irq_trans_init },
+       { "pciex108e,80f0", fire_irq_trans_init },
 };
 #endif
 
@@ -1066,9 +1159,9 @@ 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)
 {
-       struct linux_prom64_registers *regs;
+       const struct linux_prom64_registers *regs;
 
        dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
        dp->irq_trans->irq_build = sun4v_vdev_irq_build;
@@ -1078,25 +1171,24 @@ 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)
 {
-       const char *model;
 #ifdef CONFIG_PCI
+       const char *model;
        int i;
 #endif
 
+#ifdef CONFIG_PCI
        model = of_get_property(dp, "model", NULL);
        if (!model)
                model = of_get_property(dp, "compatible", NULL);
-       if (!model)
-               return;
-
-#ifdef CONFIG_PCI
-       for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) {
-               struct irq_trans *t = &pci_irq_trans_table[i];
+       if (model) {
+               for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) {
+                       struct irq_trans *t = &pci_irq_trans_table[i];
 
-               if (!strcmp(model, t->name))
-                       return t->init(dp);
+                       if (!strcmp(model, t->name))
+                               return t->init(dp);
+               }
        }
 #endif
 #ifdef CONFIG_SBUS
@@ -1104,8 +1196,9 @@ static void irq_trans_init(struct device_node *dp)
            !strcmp(dp->name, "sbi"))
                return sbus_irq_trans_init(dp);
 #endif
-       if (!strcmp(dp->name, "central"))
-               return central_irq_trans_init(dp->child);
+       if (!strcmp(dp->name, "fhc") &&
+           !strcmp(dp->parent->name, "central"))
+               return central_irq_trans_init(dp);
        if (!strcmp(dp->name, "virtual-devices"))
                return sun4v_vdev_irq_trans_init(dp);
 }
@@ -1517,7 +1610,7 @@ static char * __init get_one_property(phandle node, const char *name)
        return buf;
 }
 
-static struct device_node * __init create_node(phandle node)
+static struct device_node * __init create_node(phandle node, struct device_node *parent)
 {
        struct device_node *dp;
 
@@ -1526,6 +1619,7 @@ static struct device_node * __init create_node(phandle node)
 
        dp = prom_early_alloc(sizeof(*dp));
        dp->unique_id = unique_id++;
+       dp->parent = parent;
 
        kref_init(&dp->kref);
 
@@ -1544,12 +1638,11 @@ static struct device_node * __init build_tree(struct device_node *parent, phandl
 {
        struct device_node *dp;
 
-       dp = create_node(node);
+       dp = create_node(node, parent);
        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);
 
@@ -1565,7 +1658,7 @@ void __init prom_build_devicetree(void)
 {
        struct device_node **nextp;
 
-       allnodes = create_node(prom_root_node);
+       allnodes = create_node(prom_root_node, NULL);
        allnodes->path_component_name = "";
        allnodes->full_name = "/";