Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / arch / sparc64 / kernel / ebus.c
index c69504a..8a9b470 100644 (file)
@@ -5,7 +5,6 @@
  * Copyright (C) 1999  David S. Miller (davem@redhat.com)
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
@@ -20,6 +19,8 @@
 #include <asm/pbm.h>
 #include <asm/ebus.h>
 #include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
 #include <asm/bpp.h>
 #include <asm/irq.h>
 
@@ -139,7 +140,7 @@ int ebus_dma_irq_enable(struct ebus_dma_info *p, int on)
 
        if (on) {
                if (p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) {
-                       if (request_irq(p->irq, ebus_dma_irq, SA_SHIRQ, p->name, p))
+                       if (request_irq(p->irq, ebus_dma_irq, IRQF_SHARED, p->name, p))
                                return -EBUSY;
                }
 
@@ -269,10 +270,6 @@ EXPORT_SYMBOL(ebus_dma_enable);
 
 struct linux_ebus *ebus_chain = NULL;
 
-#ifdef CONFIG_SUN_AUXIO
-extern void auxio_probe(void);
-#endif
-
 static inline void *ebus_alloc(size_t size)
 {
        void *mem;
@@ -283,77 +280,22 @@ static inline void *ebus_alloc(size_t size)
        return mem;
 }
 
-static void __init ebus_ranges_init(struct linux_ebus *ebus)
-{
-       int success;
-
-       ebus->num_ebus_ranges = 0;
-       success = prom_getproperty(ebus->prom_node, "ranges",
-                                  (char *)ebus->ebus_ranges,
-                                  sizeof(ebus->ebus_ranges));
-       if (success != -1)
-               ebus->num_ebus_ranges = (success/sizeof(struct linux_prom_ebus_ranges));
-}
-
-static void __init ebus_intmap_init(struct linux_ebus *ebus)
-{
-       int success;
-
-       ebus->num_ebus_intmap = 0;
-       success = prom_getproperty(ebus->prom_node, "interrupt-map",
-                                  (char *)ebus->ebus_intmap,
-                                  sizeof(ebus->ebus_intmap));
-       if (success == -1)
-               return;
-
-       ebus->num_ebus_intmap = (success/sizeof(struct linux_prom_ebus_intmap));
-
-       success = prom_getproperty(ebus->prom_node, "interrupt-map-mask",
-                                  (char *)&ebus->ebus_intmask,
-                                  sizeof(ebus->ebus_intmask));
-       if (success == -1) {
-               prom_printf("%s: can't get interrupt-map-mask\n", __FUNCTION__);
-               prom_halt();
-       }
-}
-
-int __init ebus_intmap_match(struct linux_ebus *ebus,
-                            struct linux_prom_registers *reg,
-                            int *interrupt)
+static void __init fill_ebus_child(struct device_node *dp,
+                                  struct linux_ebus_child *dev,
+                                  int non_standard_regs)
 {
-       unsigned int hi, lo, irq;
-       int i;
-
-       if (!ebus->num_ebus_intmap)
-               return 0;
-
-       hi = reg->which_io & ebus->ebus_intmask.phys_hi;
-       lo = reg->phys_addr & ebus->ebus_intmask.phys_lo;
-       irq = *interrupt & ebus->ebus_intmask.interrupt;
-       for (i = 0; i < ebus->num_ebus_intmap; i++) {
-               if ((ebus->ebus_intmap[i].phys_hi == hi) &&
-                   (ebus->ebus_intmap[i].phys_lo == lo) &&
-                   (ebus->ebus_intmap[i].interrupt == irq)) {
-                       *interrupt = ebus->ebus_intmap[i].cinterrupt;
-                       return 0;
-               }
-       }
-       return -1;
-}
-
-void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
-                           struct linux_ebus_child *dev, int non_standard_regs)
-{
-       int regs[PROMREG_MAX];
-       int irqs[PROMREG_MAX];
+       struct of_device *op;
+       int *regs;
        int i, len;
 
-       dev->prom_node = node;
-       prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name));
-       printk(" (%s)", dev->prom_name);
+       dev->prom_node = dp;
+       printk(" (%s)", dp->name);
 
-       len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
-       dev->num_addrs = len / sizeof(regs[0]);
+       regs = of_get_property(dp, "reg", &len);
+       if (!regs)
+               dev->num_addrs = 0;
+       else
+               dev->num_addrs = len / sizeof(regs[0]);
 
        if (non_standard_regs) {
                /* This is to handle reg properties which are not
@@ -370,30 +312,34 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
                        int rnum = regs[i];
                        if (rnum >= dev->parent->num_addrs) {
                                prom_printf("UGH: property for %s was %d, need < %d\n",
-                                           dev->prom_name, len, dev->parent->num_addrs);
-                               panic(__FUNCTION__);
+                                           dp->name, len, dev->parent->num_addrs);
+                               prom_halt();
                        }
                        dev->resource[i].start = dev->parent->resource[i].start;
                        dev->resource[i].end = dev->parent->resource[i].end;
                        dev->resource[i].flags = IORESOURCE_MEM;
-                       dev->resource[i].name = dev->prom_name;
+                       dev->resource[i].name = dp->name;
                }
        }
 
-       for (i = 0; i < PROMINTR_MAX; i++)
-               dev->irqs[i] = PCI_IRQ_NONE;
-
-       len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
-       if ((len == -1) || (len == 0)) {
+       op = of_find_device_by_node(dp);
+       if (!op) {
                dev->num_irqs = 0;
+       } else {
+               dev->num_irqs = op->num_irqs;
+               for (i = 0; i < dev->num_irqs; i++)
+                       dev->irqs[i] = op->irqs[i];
+       }
+
+       if (!dev->num_irqs) {
                /*
                 * Oh, well, some PROMs don't export interrupts
                 * property to children of EBus devices...
                 *
                 * Be smart about PS/2 keyboard and mouse.
                 */
-               if (!strcmp(dev->parent->prom_name, "8042")) {
-                       if (!strcmp(dev->prom_name, "kb_ps2")) {
+               if (!strcmp(dev->parent->prom_node->name, "8042")) {
+                       if (!strcmp(dev->prom_node->name, "kb_ps2")) {
                                dev->num_irqs = 1;
                                dev->irqs[0] = dev->parent->irqs[0];
                        } else {
@@ -401,103 +347,57 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
                                dev->irqs[0] = dev->parent->irqs[1];
                        }
                }
-       } else {
-               dev->num_irqs = len / sizeof(irqs[0]);
-               for (i = 0; i < dev->num_irqs; i++) {
-                       struct pci_pbm_info *pbm = dev->bus->parent;
-                       struct pci_controller_info *p = pbm->parent;
-
-                       if (ebus_intmap_match(dev->bus, preg, &irqs[i]) != -1) {
-                               dev->irqs[i] = p->irq_build(pbm,
-                                                           dev->bus->self,
-                                                           irqs[i]);
-                       } else {
-                               /* If we get a bogus interrupt property, just
-                                * record the raw value instead of punting.
-                                */
-                               dev->irqs[i] = irqs[i];
-                       }
-               }
        }
 }
 
 static int __init child_regs_nonstandard(struct linux_ebus_device *dev)
 {
-       if (!strcmp(dev->prom_name, "i2c") ||
-           !strcmp(dev->prom_name, "SUNW,lombus"))
+       if (!strcmp(dev->prom_node->name, "i2c") ||
+           !strcmp(dev->prom_node->name, "SUNW,lombus"))
                return 1;
        return 0;
 }
 
-void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
+static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
 {
-       struct linux_prom_registers regs[PROMREG_MAX];
        struct linux_ebus_child *child;
-       int irqs[PROMINTR_MAX];
-       int i, n, len;
+       struct of_device *op;
+       int i, len;
 
-       dev->prom_node = node;
-       prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name));
-       printk(" [%s", dev->prom_name);
+       dev->prom_node = dp;
 
-       len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
-       if (len == -1) {
+       printk(" [%s", dp->name);
+
+       op = of_find_device_by_node(dp);
+       if (!op) {
                dev->num_addrs = 0;
-               goto probe_interrupts;
-       }
+               dev->num_irqs = 0;
+       } else {
+               (void) of_get_property(dp, "reg", &len);
+               dev->num_addrs = len / sizeof(struct linux_prom_registers);
 
-       if (len % sizeof(struct linux_prom_registers)) {
-               prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
-                           dev->prom_name, len,
-                           (int)sizeof(struct linux_prom_registers));
-               prom_halt();
-       }
-       dev->num_addrs = len / sizeof(struct linux_prom_registers);
-
-       for (i = 0; i < dev->num_addrs; i++) {
-               /* XXX Learn how to interpret ebus ranges... -DaveM */
-               if (regs[i].which_io >= 0x10)
-                       n = (regs[i].which_io - 0x10) >> 2;
-               else
-                       n = regs[i].which_io;
-
-               dev->resource[i].start  = dev->bus->self->resource[n].start;
-               dev->resource[i].start += (unsigned long)regs[i].phys_addr;
-               dev->resource[i].end    =
-                       (dev->resource[i].start + (unsigned long)regs[i].reg_size - 1UL);
-               dev->resource[i].flags  = IORESOURCE_MEM;
-               dev->resource[i].name   = dev->prom_name;
-               request_resource(&dev->bus->self->resource[n],
-                                &dev->resource[i]);
+               for (i = 0; i < dev->num_addrs; i++)
+                       memcpy(&dev->resource[i],
+                              &op->resource[i],
+                              sizeof(struct resource));
+
+               dev->num_irqs = op->num_irqs;
+               for (i = 0; i < dev->num_irqs; i++)
+                       dev->irqs[i] = op->irqs[i];
        }
 
-probe_interrupts:
-       for (i = 0; i < PROMINTR_MAX; i++)
-               dev->irqs[i] = PCI_IRQ_NONE;
+       dev->ofdev.node = dp;
+       dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
+       dev->ofdev.dev.bus = &ebus_bus_type;
+       strcpy(dev->ofdev.dev.bus_id, dp->path_component_name);
 
-       len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
-       if ((len == -1) || (len == 0)) {
-               dev->num_irqs = 0;
-       } else {
-               dev->num_irqs = len / sizeof(irqs[0]);
-               for (i = 0; i < dev->num_irqs; i++) {
-                       struct pci_pbm_info *pbm = dev->bus->parent;
-                       struct pci_controller_info *p = pbm->parent;
-
-                       if (ebus_intmap_match(dev->bus, &regs[0], &irqs[i]) != -1) {
-                               dev->irqs[i] = p->irq_build(pbm,
-                                                           dev->bus->self,
-                                                           irqs[i]);
-                       } else {
-                               /* If we get a bogus interrupt property, just
-                                * record the raw value instead of punting.
-                                */
-                               dev->irqs[i] = irqs[i];
-                       }
-               }
-       }
+       /* Register with core */
+       if (of_device_register(&dev->ofdev) != 0)
+               printk(KERN_DEBUG "ebus: device registration error for %s!\n",
+                      dev->ofdev.dev.bus_id);
 
-       if ((node = prom_getchild(node))) {
+       dp = dp->child;
+       if (dp) {
                printk(" ->");
                dev->children = ebus_alloc(sizeof(struct linux_ebus_child));
 
@@ -505,18 +405,18 @@ probe_interrupts:
                child->next = NULL;
                child->parent = dev;
                child->bus = dev->bus;
-               fill_ebus_child(node, &regs[0],
-                               child, child_regs_nonstandard(dev));
+               fill_ebus_child(dp, child,
+                               child_regs_nonstandard(dev));
 
-               while ((node = prom_getsibling(node)) != 0) {
+               while ((dp = dp->sibling) != NULL) {
                        child->next = ebus_alloc(sizeof(struct linux_ebus_child));
 
                        child = child->next;
                        child->next = NULL;
                        child->parent = dev;
                        child->bus = dev->bus;
-                       fill_ebus_child(node, &regs[0],
-                                       child, child_regs_nonstandard(dev));
+                       fill_ebus_child(dp, child,
+                                       child_regs_nonstandard(dev));
                }
        }
        printk("]");
@@ -543,7 +443,8 @@ void __init ebus_init(void)
        struct linux_ebus *ebus;
        struct pci_dev *pdev;
        struct pcidev_cookie *cookie;
-       int nd, ebusnd, is_rio;
+       struct device_node *dp;
+       int is_rio;
        int num_ebus = 0;
 
        pdev = find_next_ebus(NULL, &is_rio);
@@ -553,20 +454,22 @@ void __init ebus_init(void)
        }
 
        cookie = pdev->sysdata;
-       ebusnd = cookie->prom_node;
+       dp = cookie->prom_node;
 
        ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus));
        ebus->next = NULL;
        ebus->is_rio = is_rio;
 
-       while (ebusnd) {
+       while (dp) {
+               struct device_node *child;
+
                /* SUNW,pci-qfe uses four empty ebuses on it.
                   I think we should not consider them here,
                   as they have half of the properties this
                   code expects and once we do PCI hot-plug,
                   we'd have to tweak with the ebus_chain
                   in the runtime after initialization. -jj */
-               if (!prom_getchild (ebusnd)) {
+               if (!dp->child) {
                        pdev = find_next_ebus(pdev, &is_rio);
                        if (!pdev) {
                                if (ebus == ebus_chain) {
@@ -578,22 +481,29 @@ void __init ebus_init(void)
                        }
                        ebus->is_rio = is_rio;
                        cookie = pdev->sysdata;
-                       ebusnd = cookie->prom_node;
+                       dp = cookie->prom_node;
                        continue;
                }
                printk("ebus%d:", num_ebus);
 
-               prom_getstring(ebusnd, "name", ebus->prom_name, sizeof(ebus->prom_name));
                ebus->index = num_ebus;
-               ebus->prom_node = ebusnd;
+               ebus->prom_node = dp;
                ebus->self = pdev;
                ebus->parent = pbm = cookie->pbm;
 
-               ebus_ranges_init(ebus);
-               ebus_intmap_init(ebus);
+               ebus->ofdev.node = dp;
+               ebus->ofdev.dev.parent = &pdev->dev;
+               ebus->ofdev.dev.bus = &ebus_bus_type;
+               strcpy(ebus->ofdev.dev.bus_id, dp->path_component_name);
+
+               /* Register with core */
+               if (of_device_register(&ebus->ofdev) != 0)
+                       printk(KERN_DEBUG "ebus: device registration error for %s!\n",
+                              ebus->ofdev.dev.bus_id);
 
-               nd = prom_getchild(ebusnd);
-               if (!nd)
+
+               child = dp->child;
+               if (!child)
                        goto next_ebus;
 
                ebus->devices = ebus_alloc(sizeof(struct linux_ebus_device));
@@ -602,16 +512,16 @@ void __init ebus_init(void)
                dev->next = NULL;
                dev->children = NULL;
                dev->bus = ebus;
-               fill_ebus_device(nd, dev);
+               fill_ebus_device(child, dev);
 
-               while ((nd = prom_getsibling(nd)) != 0) {
+               while ((child = child->sibling) != NULL) {
                        dev->next = ebus_alloc(sizeof(struct linux_ebus_device));
 
                        dev = dev->next;
                        dev->next = NULL;
                        dev->children = NULL;
                        dev->bus = ebus;
-                       fill_ebus_device(nd, dev);
+                       fill_ebus_device(child, dev);
                }
 
        next_ebus:
@@ -622,7 +532,7 @@ void __init ebus_init(void)
                        break;
 
                cookie = pdev->sysdata;
-               ebusnd = cookie->prom_node;
+               dp = cookie->prom_node;
 
                ebus->next = ebus_alloc(sizeof(struct linux_ebus));
                ebus = ebus->next;
@@ -631,8 +541,4 @@ void __init ebus_init(void)
                ++num_ebus;
        }
        pci_dev_put(pdev); /* XXX for the case, when ebusnd is 0, is it OK? */
-
-#ifdef CONFIG_SUN_AUXIO
-       auxio_probe();
-#endif
 }