summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-06-24 14:48:24 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-24 14:48:24 -0700
commitb9d8be7828e974f076717f0da608d052440fe192 (patch)
treed4bc4d3e13f816a76b1a02bde922ee7ad0dbdbd9 /arch
parentd02f40e81e003be6ddba5c176f2e40ea290c3729 (diff)
parent1812fd40725c13cf050c29791a6dd35d593eb8d8 (diff)
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6: (40 commits) [SPARC64]: Update defconfig. [SPARC64]: Make auxio a real driver. [PARPORT] sunbpp: Convert to new SBUS device framework. [Documentation]: Update probing info in sbus_drivers.txt [SCSI] qlogicpti: Convert to new SBUS device framework. [SCSI] esp: Fix bug in esp_remove_common. [NET] sunhme: Kill useless loop over sdevs in quattro_sbus_find(). [NET] myri_sbus: Kill unused next_module struct member. [NET] myri_sbus: Convert to new SBUS device layer. [NET] sunqe: Convert to new SBUS driver layer. [NET] sunbmac: Convert over to new SBUS device framework. [NET] sunlance: Convert to new SBUS driver framework. [NET] sunhme: Convert to new SBUS driver framework. [NET] sunhme: Kill __sparc__ and __sparc_v9__ ifdefs. [SCSI] sparc: Port esp to new SBUS driver layer. [SOUND] sparc: Port amd7930 to new SBUS device layer. [SBUS]: Rewrite and plug into of_device framework. [SPARC]: Port of_device layer and make ebus use it. [SPARC]: Port sparc64 in-kernel device tree code to sparc32. [SPARC64]: Add of_device layer and make ebus/isa use it. ...
Diffstat (limited to 'arch')
-rw-r--r--arch/sparc/kernel/Makefile2
-rw-r--r--arch/sparc/kernel/ebus.c185
-rw-r--r--arch/sparc/kernel/ioport.c131
-rw-r--r--arch/sparc/kernel/of_device.c268
-rw-r--r--arch/sparc/kernel/pcic.c3
-rw-r--r--arch/sparc/kernel/prom.c474
-rw-r--r--arch/sparc/mm/init.c2
-rw-r--r--arch/sparc64/defconfig12
-rw-r--r--arch/sparc64/kernel/Makefile2
-rw-r--r--arch/sparc64/kernel/auxio.c109
-rw-r--r--arch/sparc64/kernel/central.c127
-rw-r--r--arch/sparc64/kernel/chmc.c69
-rw-r--r--arch/sparc64/kernel/devices.c222
-rw-r--r--arch/sparc64/kernel/ebus.c197
-rw-r--r--arch/sparc64/kernel/irq.c19
-rw-r--r--arch/sparc64/kernel/isa.c183
-rw-r--r--arch/sparc64/kernel/of_device.c279
-rw-r--r--arch/sparc64/kernel/pci.c59
-rw-r--r--arch/sparc64/kernel/pci_common.c227
-rw-r--r--arch/sparc64/kernel/pci_impl.h3
-rw-r--r--arch/sparc64/kernel/pci_psycho.c106
-rw-r--r--arch/sparc64/kernel/pci_sabre.c195
-rw-r--r--arch/sparc64/kernel/pci_schizo.c171
-rw-r--r--arch/sparc64/kernel/pci_sun4v.c160
-rw-r--r--arch/sparc64/kernel/power.c113
-rw-r--r--arch/sparc64/kernel/prom.c650
-rw-r--r--arch/sparc64/kernel/sbus.c67
-rw-r--r--arch/sparc64/kernel/setup.c4
-rw-r--r--arch/sparc64/kernel/smp.c41
-rw-r--r--arch/sparc64/kernel/time.c386
-rw-r--r--arch/sparc64/kernel/traps.c18
-rw-r--r--arch/sparc64/kernel/unaligned.c9
-rw-r--r--arch/sparc64/mm/init.c52
-rw-r--r--arch/sparc64/solaris/misc.c34
34 files changed, 3232 insertions, 1347 deletions
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index 1b83e21841b5..6616ee05c313 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -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 of_device.o
obj-$(CONFIG_PCI) += pcic.o
obj-$(CONFIG_SUN4) += sun4setup.o
diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c
index 5c3529ceb5d6..a7a4892956c8 100644
--- a/arch/sparc/kernel/ebus.c
+++ b/arch/sparc/kernel/ebus.c
@@ -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,43 @@ 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))) {
+ 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);
+
+ /* 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 ((dp = dp->child) != NULL) {
dev->children = (struct linux_ebus_child *)
ebus_alloc(sizeof(struct linux_ebus_child));
@@ -236,9 +253,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 +263,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 +314,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 +331,18 @@ void __init ebus_init(void)
*base++ = addr;
}
- nd = prom_getchild(ebusnd);
+ 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 = dp->child;
if (!nd)
goto next_ebus;
@@ -330,7 +355,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 +373,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));
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index f9ff29734848..ae4c667c906f 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -39,6 +39,8 @@
#include <asm/io.h>
#include <asm/vaddrs.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/sbus.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/dma.h>
@@ -224,10 +226,54 @@ static void _sparc_free_io(struct resource *res)
#ifdef CONFIG_SBUS
-void sbus_set_sbus64(struct sbus_dev *sdev, int x) {
+void sbus_set_sbus64(struct sbus_dev *sdev, int x)
+{
printk("sbus_set_sbus64: unsupported\n");
}
+extern unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq);
+void __init sbus_fill_device_irq(struct sbus_dev *sdev)
+{
+ struct linux_prom_irqs irqs[PROMINTR_MAX];
+ int len;
+
+ len = prom_getproperty(sdev->prom_node, "intr",
+ (char *)irqs, sizeof(irqs));
+ if (len != -1) {
+ sdev->num_irqs = len / 8;
+ if (sdev->num_irqs == 0) {
+ sdev->irqs[0] = 0;
+ } else if (sparc_cpu_model == sun4d) {
+ for (len = 0; len < sdev->num_irqs; len++)
+ sdev->irqs[len] =
+ sun4d_build_irq(sdev, irqs[len].pri);
+ } else {
+ for (len = 0; len < sdev->num_irqs; len++)
+ sdev->irqs[len] = irqs[len].pri;
+ }
+ } else {
+ int interrupts[PROMINTR_MAX];
+
+ /* No "intr" node found-- check for "interrupts" node.
+ * This node contains SBus interrupt levels, not IPLs
+ * as in "intr", and no vector values. We convert
+ * SBus interrupt levels to PILs (platform specific).
+ */
+ len = prom_getproperty(sdev->prom_node, "interrupts",
+ (char *)interrupts, sizeof(interrupts));
+ if (len == -1) {
+ sdev->irqs[0] = 0;
+ sdev->num_irqs = 0;
+ } else {
+ sdev->num_irqs = len / sizeof(int);
+ for (len = 0; len < sdev->num_irqs; len++) {
+ sdev->irqs[len] =
+ sbint_to_irq(sdev, interrupts[len]);
+ }
+ }
+ }
+}
+
/*
* Allocate a chunk of memory suitable for DMA.
* Typically devices use them for control blocks.
@@ -414,6 +460,89 @@ void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg,
{
printk("sbus_dma_sync_sg_for_device: not implemented yet\n");
}
+
+/* Support code for sbus_init(). */
+/*
+ * XXX This functions appears to be a distorted version of
+ * prom_sbus_ranges_init(), with all sun4d stuff cut away.
+ * Ask DaveM what is going on here, how is sun4d supposed to work... XXX
+ */
+/* added back sun4d patch from Thomas Bogendoerfer - should be OK (crn) */
+void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus)
+{
+ int parent_node = pn->node;
+
+ if (sparc_cpu_model == sun4d) {
+ struct linux_prom_ranges iounit_ranges[PROMREG_MAX];
+ int num_iounit_ranges, len;
+
+ len = prom_getproperty(parent_node, "ranges",
+ (char *) iounit_ranges,
+ sizeof (iounit_ranges));
+ if (len != -1) {
+ num_iounit_ranges =
+ (len / sizeof(struct linux_prom_ranges));
+ prom_adjust_ranges(sbus->sbus_ranges,
+ sbus->num_sbus_ranges,
+ iounit_ranges, num_iounit_ranges);
+ }
+ }
+}
+
+void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp)
+{
+ struct device_node *parent = dp->parent;
+
+ if (sparc_cpu_model != sun4d &&
+ parent != NULL &&
+ !strcmp(parent->name, "iommu")) {
+ extern void iommu_init(int iommu_node, struct sbus_bus *sbus);
+
+ iommu_init(parent->node, sbus);
+ }
+
+ if (sparc_cpu_model == sun4d) {
+ extern void iounit_init(int sbi_node, int iounit_node,
+ struct sbus_bus *sbus);
+
+ iounit_init(dp->node, parent->node, sbus);
+ }
+}
+
+void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp)
+{
+ if (sparc_cpu_model == sun4d) {
+ struct device_node *parent = dp->parent;
+
+ sbus->devid = of_getintprop_default(parent, "device-id", 0);
+ sbus->board = of_getintprop_default(parent, "board#", 0);
+ }
+}
+
+int __init sbus_arch_preinit(void)
+{
+ extern void register_proc_sparc_ioport(void);
+
+ register_proc_sparc_ioport();
+
+#ifdef CONFIG_SUN4
+ {
+ extern void sun4_dvma_init(void);
+ sun4_dvma_init();
+ }
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+void __init sbus_arch_postinit(void)
+{
+ if (sparc_cpu_model == sun4d) {
+ extern void sun4d_init_sbi_irq(void);
+ sun4d_init_sbi_irq();
+ }
+}
#endif /* CONFIG_SBUS */
#ifdef CONFIG_PCI
diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c
new file mode 100644
index 000000000000..001b8673b4bd
--- /dev/null
+++ b/arch/sparc/kernel/of_device.c
@@ -0,0 +1,268 @@
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/slab.h>
+
+#include <asm/errno.h>
+#include <asm/of_device.h>
+
+/**
+ * of_match_device - Tell if an of_device structure has a matching
+ * of_match structure
+ * @ids: array of of device match structures to search in
+ * @dev: the of device structure to match against
+ *
+ * Used by a driver to check whether an of_device present in the
+ * system is in its list of supported devices.
+ */
+const struct of_device_id *of_match_device(const struct of_device_id *matches,
+ const struct of_device *dev)
+{
+ if (!dev->node)
+ return NULL;
+ while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
+ int match = 1;
+ if (matches->name[0])
+ match &= dev->node->name
+ && !strcmp(matches->name, dev->node->name);
+ if (matches->type[0])
+ match &= dev->node->type
+ && !strcmp(matches->type, dev->node->type);
+ if (matches->compatible[0])
+ match &= of_device_is_compatible(dev->node,
+ matches->compatible);
+ if (match)
+ return matches;
+ matches++;
+ }
+ return NULL;
+}
+
+static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct of_device * of_dev = to_of_device(dev);
+ struct of_platform_driver * of_drv = to_of_platform_driver(drv);
+ const struct of_device_id * matches = of_drv->match_table;
+
+ if (!matches)
+ return 0;
+
+ return of_match_device(matches, of_dev) != NULL;
+}
+
+struct of_device *of_dev_get(struct of_device *dev)
+{
+ struct device *tmp;
+
+ if (!dev)
+ return NULL;
+ tmp = get_device(&dev->dev);
+ if (tmp)
+ return to_of_device(tmp);
+ else
+ return NULL;
+}
+
+void of_dev_put(struct of_device *dev)
+{
+ if (dev)
+ put_device(&dev->dev);
+}
+
+
+static int of_device_probe(struct device *dev)
+{
+ int error = -ENODEV;
+ struct of_platform_driver *drv;
+ struct of_device *of_dev;
+ const struct of_device_id *match;
+
+ drv = to_of_platform_driver(dev->driver);
+ of_dev = to_of_device(dev);
+
+ if (!drv->probe)
+ return error;
+
+ of_dev_get(of_dev);
+
+ match = of_match_device(drv->match_table, of_dev);
+ if (match)
+ error = drv->probe(of_dev, match);
+ if (error)
+ of_dev_put(of_dev);
+
+ return error;
+}
+
+static int of_device_remove(struct device *dev)
+{
+ struct of_device * of_dev = to_of_device(dev);
+ struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
+
+ if (dev->driver && drv->remove)
+ drv->remove(of_dev);
+ return 0;
+}
+
+static int of_device_suspend(struct device *dev, pm_message_t state)
+{
+ struct of_device * of_dev = to_of_device(dev);
+ struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
+ int error = 0;
+
+ if (dev->driver && drv->suspend)
+ error = drv->suspend(of_dev, state);
+ return error;
+}
+
+static int of_device_resume(struct device * dev)
+{
+ struct of_device * of_dev = to_of_device(dev);
+ struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
+ int error = 0;
+
+ if (dev->driver && drv->resume)
+ error = drv->resume(of_dev);
+ return error;
+}
+
+#ifdef CONFIG_PCI
+struct bus_type ebus_bus_type = {
+ .name = "ebus",
+ .match = of_platform_bus_match,
+ .probe = of_device_probe,
+ .remove = of_device_remove,
+ .suspend = of_device_suspend,
+ .resume = of_device_resume,
+};
+#endif
+
+#ifdef CONFIG_SBUS
+struct bus_type sbus_bus_type = {
+ .name = "sbus",
+ .match = of_platform_bus_match,
+ .probe = of_device_probe,
+ .remove = of_device_remove,
+ .suspend = of_device_suspend,
+ .resume = of_device_resume,
+};
+#endif
+
+static int __init of_bus_driver_init(void)
+{
+ int err = 0;
+
+#ifdef CONFIG_PCI
+ if (!err)
+ err = bus_register(&ebus_bus_type);
+#endif
+#ifdef CONFIG_SBUS
+ if (!err)
+ err = bus_register(&sbus_bus_type);
+#endif
+ return 0;
+}
+
+postcore_initcall(of_bus_driver_init);
+
+int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
+{
+ /* initialize common driver fields */
+ drv->driver.name = drv->name;
+ drv->driver.bus = bus;
+
+ /* register with core */
+ return driver_register(&drv->driver);
+}
+
+void of_unregister_driver(struct of_platform_driver *drv)
+{
+ driver_unregister(&drv->driver);
+}
+
+
+static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct of_device *ofdev;
+
+ ofdev = to_of_device(dev);
+ return sprintf(buf, "%s", ofdev->node->full_name);
+}
+
+static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
+
+/**
+ * of_release_dev - free an of device structure when all users of it are finished.
+ * @dev: device that's been disconnected
+ *
+ * Will be called only by the device core when all users of this of device are
+ * done.
+ */
+void of_release_dev(struct device *dev)
+{
+ struct of_device *ofdev;
+
+ ofdev = to_of_device(dev);
+
+ kfree(ofdev);
+}
+
+int of_device_register(struct of_device *ofdev)
+{
+ int rc;
+
+ BUG_ON(ofdev->node == NULL);
+
+ rc = device_register(&ofdev->dev);
+ if (rc)
+ return rc;
+
+ device_create_file(&ofdev->dev, &dev_attr_devspec);
+
+ return 0;
+}
+
+void of_device_unregister(struct of_device *ofdev)
+{
+ device_remove_file(&ofdev->dev, &dev_attr_devspec);
+ device_unregister(&ofdev->dev);
+}
+
+struct of_device* of_platform_device_create(struct device_node *np,
+ const char *bus_id,
+ struct device *parent,
+ struct bus_type *bus)
+{
+ struct of_device *dev;
+
+ dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+ memset(dev, 0, sizeof(*dev));
+
+ dev->dev.parent = parent;
+ dev->dev.bus = bus;
+ dev->dev.release = of_release_dev;
+
+ strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
+
+ if (of_device_register(dev) != 0) {
+ kfree(dev);
+ return NULL;
+ }
+
+ return dev;
+}
+
+EXPORT_SYMBOL(of_match_device);
+EXPORT_SYMBOL(of_register_driver);
+EXPORT_SYMBOL(of_unregister_driver);
+EXPORT_SYMBOL(of_device_register);
+EXPORT_SYMBOL(of_device_unregister);
+EXPORT_SYMBOL(of_dev_get);
+EXPORT_SYMBOL(of_dev_put);
+EXPORT_SYMBOL(of_platform_device_create);
+EXPORT_SYMBOL(of_release_dev);
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index bcdf5ad0f035..bcfdddd0418a 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -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
index 000000000000..63b2b9bd778e
--- /dev/null
+++ b/arch/sparc/kernel/prom.c
@@ -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;
+