summaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/kernel')
-rw-r--r--arch/sparc/kernel/Makefile2
-rw-r--r--arch/sparc/kernel/asm-offsets.c1
-rw-r--r--arch/sparc/kernel/auxio.c1
-rw-r--r--arch/sparc/kernel/cpu.c1
-rw-r--r--arch/sparc/kernel/devices.c1
-rw-r--r--arch/sparc/kernel/ebus.c186
-rw-r--r--arch/sparc/kernel/entry.S1
-rw-r--r--arch/sparc/kernel/head.S1
-rw-r--r--arch/sparc/kernel/idprom.c1
-rw-r--r--arch/sparc/kernel/ioport.c156
-rw-r--r--arch/sparc/kernel/irq.c15
-rw-r--r--arch/sparc/kernel/of_device.c743
-rw-r--r--arch/sparc/kernel/pcic.c16
-rw-r--r--arch/sparc/kernel/process.c1
-rw-r--r--arch/sparc/kernel/prom.c574
-rw-r--r--arch/sparc/kernel/setup.c37
-rw-r--r--arch/sparc/kernel/signal.c1
-rw-r--r--arch/sparc/kernel/smp.c36
-rw-r--r--arch/sparc/kernel/sparc_ksyms.c2
-rw-r--r--arch/sparc/kernel/sun4c_irq.c6
-rw-r--r--arch/sparc/kernel/sun4d_irq.c25
-rw-r--r--arch/sparc/kernel/sun4m_irq.c11
-rw-r--r--arch/sparc/kernel/sun4m_smp.c9
-rw-r--r--arch/sparc/kernel/sys_solaris.c1
-rw-r--r--arch/sparc/kernel/sys_sunos.c2
-rw-r--r--arch/sparc/kernel/systbls.S1
-rw-r--r--arch/sparc/kernel/tick14.c2
-rw-r--r--arch/sparc/kernel/time.c110
-rw-r--r--arch/sparc/kernel/traps.c1
29 files changed, 1697 insertions, 247 deletions
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index 1b83e21841b..6616ee05c31 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/asm-offsets.c b/arch/sparc/kernel/asm-offsets.c
index 1f55231f07d..29d7cfd1c97 100644
--- a/arch/sparc/kernel/asm-offsets.c
+++ b/arch/sparc/kernel/asm-offsets.c
@@ -10,7 +10,6 @@
* On sparc, thread_info data is static and TI_XXX offsets are computed by hand.
*/
-#include <linux/config.h>
#include <linux/sched.h>
// #include <linux/mm.h>
diff --git a/arch/sparc/kernel/auxio.c b/arch/sparc/kernel/auxio.c
index d3b3648362c..118f3eca373 100644
--- a/arch/sparc/kernel/auxio.c
+++ b/arch/sparc/kernel/auxio.c
@@ -5,7 +5,6 @@
#include <linux/stddef.h>
#include <linux/init.h>
-#include <linux/config.h>
#include <linux/spinlock.h>
#include <asm/oplib.h>
#include <asm/io.h>
diff --git a/arch/sparc/kernel/cpu.c b/arch/sparc/kernel/cpu.c
index d7bfc61d287..259a559d4ce 100644
--- a/arch/sparc/kernel/cpu.c
+++ b/arch/sparc/kernel/cpu.c
@@ -4,7 +4,6 @@
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/smp.h>
diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c
index fcb0c049c3f..adba9dfee35 100644
--- a/arch/sparc/kernel/devices.c
+++ b/arch/sparc/kernel/devices.c
@@ -7,7 +7,6 @@
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/threads.h>
#include <linux/string.h>
diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c
index 5c3529ceb5d..81c0cbd96ff 100644
--- a/arch/sparc/kernel/ebus.c
+++ b/arch/sparc/kernel/ebus.c
@@ -7,7 +7,6 @@
* Fixes for different platforms by Pete Zaitcev.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
@@ -20,6 +19,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 +83,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 +199,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 +208,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 +252,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 +262,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 +313,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 +330,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 +354,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 +372,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/entry.S b/arch/sparc/kernel/entry.S
index 887f6a160c5..a4edff4c3be 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -8,7 +8,6 @@
* Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au)
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <asm/head.h>
diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S
index 42d3de59d19..9a219e8b5dd 100644
--- a/arch/sparc/kernel/head.S
+++ b/arch/sparc/kernel/head.S
@@ -11,7 +11,6 @@
*/
#include <linux/version.h>
-#include <linux/config.h>
#include <linux/init.h>
#include <asm/head.h>
diff --git a/arch/sparc/kernel/idprom.c b/arch/sparc/kernel/idprom.c
index 2e1b0f6e99d..3a5bad52539 100644
--- a/arch/sparc/kernel/idprom.c
+++ b/arch/sparc/kernel/idprom.c
@@ -5,7 +5,6 @@
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index f9ff2973484..8654b446ac9 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -26,6 +26,7 @@
*/
#include <linux/config.h>
+#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -39,6 +40,9 @@
#include <asm/io.h>
#include <asm/vaddrs.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
+#include <asm/sbus.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/dma.h>
@@ -141,6 +145,21 @@ void __iomem *sbus_ioremap(struct resource *phyres, unsigned long offset,
phyres->start + offset, size, name);
}
+void __iomem *of_ioremap(struct resource *res, unsigned long offset,
+ unsigned long size, char *name)
+{
+ return _sparc_alloc_io(res->flags & 0xF,
+ res->start + offset,
+ size, name);
+}
+EXPORT_SYMBOL(of_ioremap);
+
+void of_iounmap(void __iomem *base, unsigned long size)
+{
+ iounmap(base);
+}
+EXPORT_SYMBOL(of_iounmap);
+
/*
*/
void sbus_iounmap(volatile void __iomem *addr, unsigned long size)
@@ -206,7 +225,7 @@ _sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz)
pa &= PAGE_MASK;
sparc_mapiorange(bus, pa, res->start, res->end - res->start + 1);
- return (void __iomem *) (res->start + offset);
+ return (void __iomem *)(unsigned long)(res->start + offset);
}
/*
@@ -224,10 +243,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.
@@ -279,7 +342,7 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp)
res->name = sdev->prom_name;
}
- return (void *)res->start;
+ return (void *)(unsigned long)res->start;
err_noiommu:
release_resource(res);
@@ -414,6 +477,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
@@ -690,7 +836,9 @@ _sparc_io_get_info(char *buf, char **start, off_t fpos, int length, int *eof,
if (p + 32 >= e) /* Better than nothing */
break;
if ((nm = r->name) == 0) nm = "???";
- p += sprintf(p, "%08lx-%08lx: %s\n", r->start, r->end, nm);
+ p += sprintf(p, "%016llx-%016llx: %s\n",
+ (unsigned long long)r->start,
+ (unsigned long long)r->end, nm);
}
return p-buf;
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index aac8af5aae5..cde73327ca9 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -11,7 +11,6 @@
* Copyright (C) 1998-2000 Anton Blanchard (anton@samba.org)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/ptrace.h>
@@ -192,11 +191,11 @@ int show_interrupts(struct seq_file *p, void *v)
}
#endif
seq_printf(p, " %c %s",
- (action->flags & SA_INTERRUPT) ? '+' : ' ',
+ (action->flags & IRQF_DISABLED) ? '+' : ' ',
action->name);
for (action=action->next; action; action = action->next) {
seq_printf(p, ",%s %s",
- (action->flags & SA_INTERRUPT) ? " +" : "",
+ (action->flags & IRQF_DISABLED) ? " +" : "",
action->name);
}
seq_putc(p, '\n');
@@ -244,7 +243,7 @@ void free_irq(unsigned int irq, void *dev_id)
printk("Trying to free free shared IRQ%d\n",irq);
goto out_unlock;
}
- } else if (action->flags & SA_SHIRQ) {
+ } else if (action->flags & IRQF_SHARED) {
printk("Trying to free shared IRQ%d with NULL device ID\n", irq);
goto out_unlock;
}
@@ -396,9 +395,9 @@ int request_fast_irq(unsigned int irq,
action = sparc_irq[cpu_irq].action;
if(action) {
- if(action->flags & SA_SHIRQ)
+ if(action->flags & IRQF_SHARED)
panic("Trying to register fast irq when already shared.\n");
- if(irqflags & SA_SHIRQ)
+ if(irqflags & IRQF_SHARED)
panic("Trying to register fast irq as shared.\n");
/* Anyway, someone already owns it so cannot be made fast. */
@@ -498,11 +497,11 @@ int request_irq(unsigned int irq,
actionp = &sparc_irq[cpu_irq].action;
action = *actionp;
if (action) {
- if (!(action->flags & SA_SHIRQ) || !(irqflags & SA_SHIRQ)) {
+ if (!(action->flags & IRQF_SHARED) || !(irqflags & IRQF_SHARED)) {
ret = -EBUSY;
goto out_unlock;
}
- if ((action->flags & SA_INTERRUPT) != (irqflags & SA_INTERRUPT)) {
+ if ((action->flags & IRQF_DISABLED) != (irqflags & IRQF_DISABLED)) {
printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq);
ret = -EBUSY;
goto out_unlock;
diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c
new file mode 100644
index 00000000000..bc956c53037
--- /dev/null
+++ b/arch/sparc/kernel/of_device.c
@@ -0,0 +1,743 @@
+#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;
+}
+
+static int node_match(struct device *dev, void *data)
+{
+ struct of_device *op = to_of_device(dev);
+ struct device_node *dp = data;
+
+ return (op->node == dp);
+}
+
+struct of_device *of_find_device_by_node(struct device_node *dp)
+{
+ struct device *dev = bus_find_device(&of_bus_type, NULL,
+ dp, node_match);
+
+ if (dev)
+ return to_of_device(dev);
+
+ return NULL;
+}
+EXPORT_SYMBOL(of_find_device_by_node);
+
+#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,
+};
+EXPORT_SYMBOL(ebus_bus_type);
+#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,
+};
+EXPORT_SYMBOL(sbus_bus_type);
+#endif
+
+struct bus_type of_bus_type = {
+ .name = "of",
+ .match = of_platform_bus_match,
+ .probe = of_device_probe,
+ .remove = of_device_remove,
+ .suspend = of_device_suspend,
+ .resume = of_device_resume,
+};
+EXPORT_SYMBOL(of_bus_type);
+
+static inline u64 of_read_addr(u32 *cell, int size)
+{
+ u64 r = 0;
+ while (size--)
+ r = (r << 32) | *(cell++);
+ return r;
+}
+
+static void __init get_cells(struct device_node *dp,
+ int *addrc, int *sizec)
+{
+ if (addrc)
+ *addrc = of_n_addr_cells(dp);
+ if (sizec)
+ *sizec = of_n_size_cells(dp);
+}
+
+/* Max address size we deal with */
+#define OF_MAX_ADDR_CELLS 4
+
+struct of_bus {
+ const char *name;
+ const char *addr_prop_name;
+ int (*match)(struct device_node *parent);
+ void (*count_cells)(struct device_node *child,
+ int *addrc, int *sizec);
+ u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna);
+ int (*translate)(u32 *addr, u64 offset, int na);
+ unsigned int (*get_flags)(u32 *addr);
+};
+
+/*
+ * Default translator (generic bus)
+ */
+
+static void of_bus_default_count_cells(struct device_node *dev,
+ int *addrc, int *sizec)
+{
+ get_cells(dev, addrc, sizec);
+}
+
+static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna)
+{
+ u64 cp, s, da;
+
+ cp = of_read_addr(range, na);
+ s = of_read_addr(range + na + pna, ns);
+ da = of_read_addr(addr, na);
+
+ if (da < cp || da >= (cp + s))
+ return OF_BAD_ADDR;
+ return da - cp;
+}
+
+static int of_bus_default_translate(u32 *addr, u64 offset, int na)
+{
+ u64 a = of_read_addr(addr, na);
+ memset(addr, 0, na * 4);
+ a += offset;
+ if (na > 1)
+ addr[na - 2] = a >> 32;
+ addr[na - 1] = a & 0xffffffffu;
+
+ return 0;
+}
+
+static unsigned int of_bus_default_get_flags(u32 *addr)
+{
+ return IORESOURCE_MEM;
+}
+
+
+/*
+ * PCI bus specific translator
+ */
+
+static int of_bus_pci_match(struct device_node *np)
+{
+ return !strcmp(np->type, "pci") || !strcmp(np->type, "pciex");
+}
+
+static void of_bus_pci_count_cells(struct device_node *np,
+ int *addrc, int *sizec)
+{
+ if (addrc)
+ *addrc = 3;
+ if (sizec)
+ *sizec = 2;
+}
+
+static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna)
+{
+ u64 cp, s, da;
+
+ /* Check address type match */
+ if ((addr[0] ^ range[0]) & 0x03000000)
+ return OF_BAD_ADDR;
+
+ /* Read address values, skipping high cell */
+ cp = of_read_addr(range + 1, na - 1);
+ s = of_read_addr(range + na + pna, ns);
+ da = of_read_addr(addr + 1, na - 1);
+
+ if (da < cp || da >= (cp + s))
+ return OF_BAD_ADDR;
+ return da - cp;
+}
+
+static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
+{
+ return of_bus_default_translate(addr + 1, offset, na - 1);
+}
+
+static unsigned int of_bus_pci_get_flags(u32 *addr)
+{
+ unsigned int flags = 0;
+ u32 w = addr[0];
+
+ switch((w >> 24) & 0x03) {
+ case 0x01:
+ flags |= IORESOURCE_IO;
+ case 0x02: /* 32 bits */
+ case 0x03: /* 64 bits */
+ flags |= IORESOURCE_MEM;
+ }
+ if (w & 0x40000000)
+ flags |= IORESOURCE_PREFETCH;
+ return flags;
+}
+
+/*
+ * SBUS bus specific translator
+ */
+
+static int of_bus_sbus_match(struct device_node *np)
+{
+ return !strcmp(np->name, "sbus") ||
+ !strcmp(np->name, "sbi");
+}
+
+static void of_bus_sbus_count_cells(struct device_node *child,
+ int *addrc, int *sizec)
+{
+ if (addrc)
+ *addrc = 2;
+ if (sizec)
+ *sizec = 1;
+}
+
+static u64 of_bus_sbus_map(u32 *addr, u32 *range, int na, int ns, int pna)
+{
+ return of_bus_default_map(addr, range, na, ns, pna);
+}
+
+static int of_bus_sbus_translate(u32 *addr, u64 offset, int na)
+{
+ return of_bus_default_translate(addr, offset, na);
+}
+
+static unsigned int of_bus_sbus_get_flags(u32 *addr)
+{
+ return IORESOURCE_MEM;
+}
+
+
+/*
+ * Array of bus specific translators
+ */
+
+static struct of_bus of_busses[] = {
+ /* PCI */
+ {
+ .name = "pci",
+ .addr_prop_name = "assigned-addresses",
+ .match = of_bus_pci_match,
+ .count_cells = of_bus_pci_count_cells,
+ .map = of_bus_pci_map,
+ .translate = of_bus_pci_translate,
+ .get_flags = of_bus_pci_get_flags,
+ },
+ /* SBUS */
+ {
+ .name = "sbus",
+ .addr_prop_name = "reg",
+ .match = of_bus_sbus_match,
+ .count_cells = of_bus_sbus_count_cells,
+ .map = of_bus_sbus_map,
+ .translate = of_bus_sbus_translate,
+ .get_flags = of_bus_sbus_get_flags,
+ },
+ /* Default */
+ {
+ .name = "default",
+ .addr_prop_name = "reg",
+ .match = NULL,
+ .count_cells = of_bus_default_count_cells,
+ .map = of_bus_default_map,
+ .translate = of_bus_default_translate,
+ .get_flags = of_bus_default_get_flags,
+ },
+};
+
+static struct of_bus *of_match_bus(struct device_node *np)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(of_busses); i ++)
+ if (!of_busses[i].match || of_busses[i].match(np))
+ return &of_busses[i];
+ BUG();
+ return NULL;
+}
+
+static int __init build_one_resource(struct device_node *parent,
+ struct of_bus *bus,
+ struct of_bus *pbus,
+ u32 *addr,
+ int na, int ns, int pna)
+{
+ u32 *ranges;
+ unsigned int rlen;
+ int rone;
+ u64 offset = OF_BAD_ADDR;
+
+ ranges = of_get_property(parent, "ranges", &rlen);
+ if (ranges == NULL || rlen == 0) {
+ offset = of_read_addr(addr, na);
+ memset(addr, 0, pna * 4);
+ goto finish;
+ }
+
+ /* Now walk through the ranges */
+ rlen /= 4;
+ rone = na + pna + ns;
+ for (; rlen >= rone; rlen -= rone, ranges += rone) {
+ offset = bus->map(addr, ranges, na, ns, pna);
+ if (offset != OF_BAD_ADDR)
+ break;
+ }
+ if (offset == OF_BAD_ADDR)
+ return 1;
+
+ memcpy(addr, ranges + na, 4 * pna);
+
+finish:
+ /* Translate it into parent bus space */
+ return pbus->translate(addr, offset, pna);
+}
+
+static void __init build_device_resources(struct of_device *op,
+ struct device *parent)
+{
+ struct of_device *p_op;
+ struct of_bus *bus;
+ int na, ns;
+ int index, num_reg;
+ void *preg;
+
+ if (!parent)
+ return;
+
+ p_op = to_of_device(parent);
+ bus = of_match_bus(p_op->node);
+ bus->count_cells(op->node, &na, &ns);
+
+ preg = of_get_property(op->node, bus->addr_prop_name, &num_reg);
+ if (!preg || num_reg == 0)
+ return;
+
+ /* Convert to num-cells. */
+ num_reg /= 4;
+
+ /* Conver to num-entries. */
+ num_reg /= na + ns;
+
+ for (index = 0; index < num_reg; index++) {
+ struct resource *r = &op->resource[index];
+ u32 addr[OF_MAX_ADDR_CELLS];
+ u32 *reg = (preg + (index * ((na + ns) * 4)));
+ struct device_node *dp = op->node;
+ struct device_node *pp = p_op->node;
+ struct of_bus *pbus;
+ u64 size, result = OF_BAD_ADDR;
+ unsigned long flags;
+ int dna, dns;
+ int pna, pns;
+
+ size = of_read_addr(reg + na, ns);
+ flags = bus->get_flags(reg);
+
+ memcpy(addr, reg, na * 4);
+
+ /* If the immediate parent has no ranges property to apply,
+ * just use a 1<->1 mapping.
+ */
+ if (of_find_property(pp, "ranges", NULL) == NULL) {
+ result = of_read_addr(addr, na);
+ goto build_res;
+ }
+
+ dna = na;
+ dns = ns;
+
+ while (1) {
+ dp = pp;
+ pp = dp->parent;
+ if (!pp) {
+ result = of_read_addr(addr, dna);
+ break;
+ }
+
+ pbus = of_match_bus(pp);
+ pbus->count_cells(dp, &pna, &pns);
+
+ if (build_one_resource(dp, bus, pbus, addr, dna, dns, pna))
+ break;
+
+ dna = pna;
+ dns = pns;
+ bus = pbus;
+ }
+
+ build_res:
+ memset(r, 0, sizeof(*r));
+ if (result != OF_BAD_ADDR) {
+ r->start = result & 0xffffffff;
+ r->end = result + size - 1;
+ r->flags = flags | ((result >> 32ULL) & 0xffUL);
+ } else {
+ r->start = ~0UL;
+ r->end = ~0UL;
+ }
+ r->name = op->node->name;
+ }
+}
+
+static struct of_device * __init scan_one_device(struct device_node *dp,
+ struct device *parent)
+{
+ struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
+ struct linux_prom_irqs *intr;
+ int len, i;
+
+ if (!op)
+ return NULL;
+
+ op->node = dp;
+
+ op->clock_freq = of_getintprop_default(dp, "clock-frequency",
+ (25*1000*1000));
+ op->portid = of_getintprop_default(dp, "upa-portid", -1);
+ if (op->portid == -1)
+ op->portid = of_getintprop_default(dp, "portid", -1);
+
+ intr = of_get_property(dp, "intr", &len);
+ if (intr) {
+ op->num_irqs = len / sizeof(struct linux_prom_irqs);
+ for (i = 0; i < op->num_irqs; i++)
+ op->irqs[i] = intr[i].pri;
+ } else {
+ unsigned int *irq = of_get_property(dp, "interrupts", &len);
+
+ if (irq) {
+ op->num_irqs = len / sizeof(unsigned int);
+ for (i = 0; i < op->num_irqs; i++)
+ op->irqs[i] = irq[i];
+ } else {
+ op->num_irqs = 0;
+ }
+ }
+ if (sparc_cpu_model == sun4d) {
+ static int pil_to_sbus[] = {
+ 0, 0, 1, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 0,
+ };
+ struct device_node *busp = dp->parent;
+ struct linux_prom_registers *regs;
+ int board = of_getintprop_default(busp, "board#", 0);
+ int slot;
+
+ regs = of_get_property(dp, "reg", NULL);
+ slot = regs->which_io;
+
+ for (i = 0; i < op->num_irqs; i++) {
+ int this_irq = op->irqs[i];
+ int sbusl = pil_to_sbus[this_irq];
+
+ if (sbusl)
+ this_irq = (((board + 1) << 5) +
+ (sbusl << 2) +
+ slot);
+
+ op->irqs[i] = this_irq;
+ }
+ }
+
+ build_device_resources(op, parent);
+
+ op->dev.parent = parent;
+ op->dev.bus = &of_bus_type;
+ if (!parent)
+ strcpy(op->dev.bus_id, "root");
+ else
+ strcpy(op->dev.bus_id, dp->path_component_name);
+
+ if (of_device_register(op)) {
+ printk("%s: Could not register of device.\n",
+ dp->full_name);
+ kfree(op);
+ op = NULL;
+ }
+
+ return op;
+}
+
+static void __init scan_tree(struct device_node *dp, struct device *parent)
+{
+ while (dp) {
+ struct of_device *op = scan_one_device(dp, parent);
+
+ if (op)
+ scan_tree(dp->child, &op->dev);
+
+ dp = dp->sibling;
+ }
+}
+
+static void __init scan_of_devices(void)
+{
+ struct device_node *root = of_find_node_by_path("/");
+ struct of_device *parent;
+
+ parent = scan_one_device(root, NULL);
+ if (!parent)
+ return;
+
+ scan_tree(root->child, &parent->dev);
+}
+
+static int __init of_bus_driver_init(void)
+{
+ int err;
+
+ err = bus_register(&of_bus_type);
+#ifdef CONFIG_PCI
+ if (!err)
+ err = bus_register(&ebus_bus_type);
+#endif
+#ifdef CONFIG_SBUS
+ if (!err)
+ err = bus_register(&sbus_bus_type);
+#endif
+
+ if (!err)
+ scan_of_devices();
+
+ return err;
+}
+
+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 42002b742de..bfd31aac2df 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -10,7 +10,6 @@
* CP-1200 by Eric Brower.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
@@ -31,6 +30,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 +665,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 */
@@ -745,7 +745,7 @@ void __init pci_time_init(void)
writel (PCI_COUNTER_IRQ_SET(timer_irq, 0),
pcic->pcic_regs+PCI_COUNTER_IRQ);
irq = request_irq(timer_irq, pcic_timer_handler,
- (SA_INTERRUPT | SA_STATIC_ALLOC), "timer", NULL);
+ (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL);
if (irq) {
prom_printf("time_init: unable to attach IRQ%d\n", timer_irq);
prom_halt();
@@ -859,7 +859,7 @@ char * __init pcibios_setup(char *str)
}
void pcibios_align_resource(void *data, struct resource *res,
- unsigned long size, unsigned long align)
+ resource_size_t size, resource_size_t align)
{
}
@@ -896,13 +896,6 @@ static inline unsigned long get_irqmask(int irq_nr)
return 1 << irq_nr;
}
-static inline char *pcic_irq_itoa(unsigned int irq)
-{
- static char buff[16];
- sprintf(buff, "%d", irq);
- return buff;
-}
-
static void pcic_disable_irq(unsigned int irq_nr)
{
unsigned long mask, flags;
@@ -955,7 +948,6 @@ void __init sun4m_pci_init_IRQ(void)
BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(clear_profile_irq, pcic_clear_profile_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(__irq_itoa, pcic_irq_itoa, BTFIXUPCALL_NORM);
}
int pcibios_assign_resource(struct pci_dev *pdev, int resource)
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 118cac84a0f..89a28cc018c 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -22,7 +22,6 @@
#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
-#include <linux/config.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/reboot.h>
diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c
new file mode 100644
index 00000000000..4b06dcb00eb
--- /dev/null
+++ b/arch/sparc/kernel/prom.c
@@ -0,0 +1,574 @@
+/*
+ * 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;
+
+/* 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(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);
+
+int of_n_addr_cells(struct device_node *np)
+{
+ 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)
+{
+ 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;
+ void *new_val;
+ int err;
+
+ new_val = kmalloc(len, GFP_KERNEL);
+ if (!new_val)
+ return -ENOMEM;
+
+ memcpy(new_val, val, len);
+
+ err = -ENODEV;
+
+ write_lock(&devtree_lock);
+ prevp = &dp->properties;
+ while (*prevp) {
+ struct property *prop = *prevp;
+
+ if (!strcmp(prop->name, name)) {
+ void *old_val = prop->value;
+ int ret;
+
+ ret = prom_setprop(dp->node, name, val, len);
+ err = -EINVAL;
+ if (ret >= 0) {
+ prop->value = new_val;
+ prop->length = len;
+
+ if (OF_IS_DYNAMIC(prop))
+ kfree(old_val);
+
+ OF_MARK_DYNAMIC(prop);
+
+ err = 0;
+ }
+ break;
+ }
+ prevp = &(*prevp)->next;
+ }
+ write_unlock(&devtree_lock);
+
+ /* XXX Upate procfs if necessary... */
+
+ return err;
+}
+EXPORT_SYMBOL(of_set_property);
+
+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 unsigned int unique_id;
+
+static struct property * __init build_one_prop(phandle node, char *prev, char *special_name, void *special_val, int special_len)
+{
+ 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->unique_id = unique_id++;
+ }
+
+ p->name = (char *) (p + 1);
+ if (special_name) {
+ p->length = special_len;
+ p->value = prom_early_alloc(special_len);
+ memcpy(p->value, special_val, special_len);
+ } else {
+ 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 + 1);
+ prom_getproperty(node, p->name, p->value, p->length);
+ ((unsigned char *)p->value)[p->length] = '\0';
+ }
+ }
+ return p;
+}
+
+static struct property * __init build_prop_list(phandle node)
+{
+ struct property *head, *tail;
+
+ head = tail = build_one_prop(node, NULL,
+ ".node", &node, sizeof(node));
+
+ tail->next = build_one_prop(node, NULL, NULL, NULL, 0);
+ tail = tail->next;
+ while(tail) {
+ tail->next = build_one_prop(node, tail->name,
+ NULL, NULL, 0);
+ 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));
+ dp->unique_id = unique_id++;
+
+ 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);
+}
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index 3509e430553..8606ef4e52e 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -19,7 +19,6 @@
#include <linux/a.out.h>
#include <linux/tty.h>
#include <linux/delay.h>
-#include <linux/config.h>
#include <linux/fs.h>
#include <linux/seq_file.h>
#include <linux/syscalls.h>
@@ -31,6 +30,7 @@
#include <linux/console.h>
#include <linux/spinlock.h>
#include <linux/root_dev.h>
+#include <linux/cpu.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -331,7 +331,7 @@ void __init setup_arch(char **cmdline_p)
if (!root_flags)
root_mountflags &= ~MS_RDONLY;
ROOT_DEV = old_decode_dev(root_dev);
-#ifdef CONFIG_BLK_DEV_INITRD
+#ifdef CONFIG_BLK_DEV_RAM
rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0);
rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);
@@ -348,6 +348,8 @@ void __init setup_arch(char **cmdline_p)
init_mm.context = (unsigned long) NO_CONTEXT;
init_task.thread.kregs = &fake_swapper_regs;
+ smp_setup_cpu_possible_map();
+
paging_init();
}
@@ -389,6 +391,8 @@ console_initcall(set_preferred_console);
extern char *sparc_cpu_type;
extern char *sparc_fpu_type;
+static int ncpus_probed;
+
static int show_cpuinfo(struct seq_file *m, void *__unused)
{
seq_printf(m,
@@ -411,7 +415,7 @@ static int show_cpuinfo(struct seq_file *m, void *__unused)
romvec->pv_printrev >> 16,
romvec->pv_printrev & 0xffff,
&cputypval,
- num_possible_cpus(),
+ ncpus_probed,
num_online_cpus()
#ifndef CONFIG_SMP
, cpu_data(0).udelay_val/(500000/HZ),
@@ -471,3 +475,30 @@ void sun_do_break(void)
int serial_console = -1;
int stop_a_enabled = 1;
+
+static int __init topology_init(void)
+{
+ int i, ncpus, err;
+
+ /* Count the number of physically present processors in
+ * the machine, even on uniprocessor, so that /proc/cpuinfo
+ * output is consistent with 2.4.x
+ */
+ ncpus = 0;
+ while (!cpu_find_by_instance(ncpus, NULL, NULL))
+ ncpus++;
+ ncpus_probed = ncpus;
+
+ err = 0;
+ for_each_online_cpu(i) {
+ struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p)
+ err = -ENOMEM;
+ else
+ register_cpu(p, i);
+ }
+
+ return err;
+}
+
+subsys_initcall(topology_init);
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
index 0748d8147bb..c9301b9143c 100644
--- a/arch/sparc/kernel/signal.c
+++ b/arch/sparc/kernel/signal.c
@@ -7,7 +7,6 @@
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
*/
-#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/signal.h>
diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c
index 40b42c88e6a..6135d4faeee 100644
--- a/arch/sparc/kernel/smp.c
+++ b/arch/sparc/kernel/smp.c
@@ -58,7 +58,7 @@ cpumask_t smp_commenced_mask = CPU_MASK_NONE;
/* Used to make bitops atomic */
unsigned char bitops_spinlock = 0;
-void __init smp_store_cpu_info(int id)
+void __cpuinit smp_store_cpu_info(int id)
{
int cpu_node;
@@ -267,22 +267,18 @@ int setup_profiling_timer(unsigned int multiplier)
void __init smp_prepare_cpus(unsigned int max_cpus)
{
extern void smp4m_boot_cpus(void);
- int i, cpuid, ncpus, extra;
+ int i, cpuid, extra;
BUG_ON(sparc_cpu_model != sun4m);
printk("Entering SMP Mode...\n");
- ncpus = 1;
extra = 0;
for (i = 0; !cpu_find_by_instance(i, NULL, &cpuid); i++) {
- if (cpuid == boot_cpu_id)
- continue;
- if (cpuid < NR_CPUS && ncpus++ < max_cpus)
- cpu_set(cpuid, phys_cpu_present_map);
- else
+ if (cpuid >= NR_CPUS)
extra++;
}
- if (max_cpus >= NR_CPUS && extra)
+ /* i = number of cpus */
+ if (extra && max_cpus > i - extra)
printk("Warning: NR_CPUS is too low to start all cpus\n");
smp_store_cpu_info(boot_cpu_id);
@@ -290,7 +286,25 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
smp4m_boot_cpus();
}
-void __devinit smp_prepare_boot_cpu(void)
+/* Set this up early so that things like the scheduler can init
+ * properly. We use the same cpu mask for both the present and
+ * possible cpu map.
+ */
+void __init smp_setup_cpu_possible_map(void)
+{
+ int instance, mid;
+
+ instance = 0;
+ while (!cpu_find_by_instance(instance, NULL, &mid)) {
+ if (mid < NR_CPUS) {
+ cpu_set(mid, phys_cpu_present_map);
+ cpu_set(mid, cpu_present_map);
+ }
+ instance++;
+ }
+}
+
+void __init smp_prepare_boot_cpu(void)
{
int cpuid = hard_smp_processor_id();
@@ -306,7 +320,7 @@ void __devinit smp_prepare_boot_cpu(void)
cpu_set(cpuid, phys_cpu_present_map);
}
-int __devinit __cpu_up(unsigned int cpu)
+int __cpuinit __cpu_up(unsigned int cpu)
{
extern int smp4m_boot_one_cpu(int);
int ret;
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index 4b376fae752..5fb987fc3d6 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -9,7 +9,6 @@
#define EXPORT_SYMTAB_STROPS
#define PROMLIB_INTERNAL
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/smp.h>
@@ -163,7 +162,6 @@ EXPORT_SYMBOL(BTFIXUP_CALL(__hard_smp_processor_id));
#endif
EXPORT_SYMBOL(BTFIXUP_CALL(enable_irq));
EXPORT_SYMBOL(BTFIXUP_CALL(disable_irq));
-EXPORT_SYMBOL(BTFIXUP_CALL(__irq_itoa));
EXPORT_SYMBOL(BTFIXUP_CALL(mmu_unlockarea));
EXPORT_SYMBOL(BTFIXUP_CALL(mmu_lockarea));
EXPORT_SYMBOL(BTFIXUP_CALL(mmu_get_scsi_sgl));
diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c
index 3d6a99073c4..4be2c86ea54 100644
--- a/arch/sparc/kernel/sun4c_irq.c
+++ b/arch/sparc/kernel/sun4c_irq.c
@@ -9,7 +9,6 @@
* Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/linkage.h>
#include <linux/kernel_stat.h>
@@ -180,7 +179,7 @@ static void __init sun4c_init_timers(irqreturn_t (*counter_fn)(int, void *, stru
irq = request_irq(TIMER_IRQ,
counter_fn,
- (SA_INTERRUPT | SA_STATIC_ALLOC),
+ (IRQF_DISABLED | SA_STATIC_ALLOC),
"timer", NULL);
if (irq) {
prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
@@ -198,8 +197,6 @@ static void __init sun4c_init_timers(irqreturn_t (*counter_fn)(int, void *, stru
static void sun4c_nop(void) {}
#endif
-extern char *sun4m_irq_itoa(unsigned int irq);
-
void __init sun4c_init_IRQ(void)
{
struct linux_prom_registers int_regs[2];
@@ -238,7 +235,6 @@ void __init sun4c_init_IRQ(void)
BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(clear_profile_irq, sun4c_clear_profile_irq, BTFIXUPCALL_NOP);
BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP);
- BTFIXUPSET_CALL(__irq_itoa, sun4m_irq_itoa, BTFIXUPCALL_NORM);
sparc_init_timers = sun4c_init_timers;
#ifdef CONFIG_SMP
BTFIXUPSET_CALL(set_cpu_int, sun4c_nop, BTFIXUPCALL_NOP);
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
index ca656d9bd6f..74eed9775ac 100644
--- a/arch/sparc/kernel/sun4d_irq.c
+++ b/arch/sparc/kernel/sun4d_irq.c
@@ -6,7 +6,6 @@
* Heavily based on arch/sparc/kernel/irq.c.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/linkage.h>
#include <linux/kernel_stat.h>
@@ -108,13 +107,13 @@ found_it: seq_printf(p, "%3d: ", i);
kstat_cpu(cpu_logical_map(x)).irqs[i]);
#endif
seq_printf(p, "%c %s",
- (action->flags & SA_INTERRUPT) ? '+' : ' ',
+ (action->flags & IRQF_DISABLED) ? '+' : ' ',
action->name);
action = action->next;
for (;;) {
for (; action; action = action->next) {
seq_printf(p, ",%s %s",
- (action->flags & SA_INTERRUPT) ? " +" : "",
+ (action->flags & IRQF_DISABLED) ? " +" : "",
action->name);
}
if (!sbusl) break;
@@ -161,7 +160,7 @@ void sun4d_free_irq(unsigned int irq, void *dev_id)
printk("Trying to free free shared IRQ%d\n",irq);
goto out_unlock;
}
- } else if (action->flags & SA_SHIRQ) {
+ } else if (action->flags & IRQF_SHARED) {
printk("Trying to free shared IRQ%d with NULL device ID\n", irq);
goto out_unlock;
}
@@ -299,13 +298,13 @@ int sun4d_request_irq(unsigned int irq,
action = *actionp;
if (action) {
- if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
+ if ((action->flags & IRQF_SHARED) && (irqflags & IRQF_SHARED)) {
for (tmp = action; tmp->next; tmp = tmp->next);
} else {
ret = -EBUSY;
goto out_unlock;
}
- if ((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
+ if ((action->flags & IRQF_DISABLED) ^ (irqflags & IRQF_DISABLED)) {
printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq);
ret = -EBUSY;
goto out_unlock;
@@ -491,7 +490,7 @@ static void __init sun4d_init_timers(irqreturn_t (*counter_fn)(int, void *, stru
irq = request_irq(TIMER_IRQ,
counter_fn,
- (SA_INTERRUPT | SA_STATIC_ALLOC),
+ (IRQF_DISABLED | SA_STATIC_ALLOC),
"timer", NULL);
if (irq) {
prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
@@ -560,17 +559,6 @@ void __init sun4d_init_sbi_irq(void)
}
}
-static char *sun4d_irq_itoa(unsigned int irq)
-{
- static char buff[16];
-
- if (irq < (1 << 5))
- sprintf(buff, "%d", irq);
- else
- sprintf(buff, "%d,%x", sbus_to_pil[(irq >> 2) & 7], irq);
- return buff;
-}
-
void __init sun4d_init_IRQ(void)
{
local_irq_disable();
@@ -581,7 +569,6 @@ void __init sun4d_init_IRQ(void)
BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(clear_profile_irq, sun4d_clear_profile_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(__irq_itoa, sun4d_irq_itoa, BTFIXUPCALL_NORM);
sparc_init_timers = sun4d_init_timers;
#ifdef CONFIG_SMP
BTFIXUPSET_CALL(set_cpu_int, sun4d_set_cpu_int, BTFIXUPCALL_NORM);
diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
index 39d712c3c80..7cefa301efe 100644
--- a/arch/sparc/kernel/sun4m_irq.c
+++ b/arch/sparc/kernel/sun4m_irq.c
@@ -9,7 +9,6 @@
* Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/linkage.h>
#include <linux/kernel_stat.h>
@@ -229,13 +228,6 @@ static void sun4m_load_profile_irq(int cpu, unsigned int limit)
sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit;
}
-char *sun4m_irq_itoa(unsigned int irq)
-{
- static char buff[16];
- sprintf(buff, "%d", irq);
- return buff;
-}
-
static void __init sun4m_init_timers(irqreturn_t (*counter_fn)(int, void *, struct pt_regs *))
{
int reg_count, irq, cpu;
@@ -286,7 +278,7 @@ static void __init sun4m_init_timers(irqreturn_t (*counter_fn)(int, void *, stru
irq = request_irq(TIMER_IRQ,
counter_fn,
- (SA_INTERRUPT | SA_STATIC_ALLOC),
+ (IRQF_DISABLED | SA_STATIC_ALLOC),
"timer", NULL);
if (irq) {
prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
@@ -388,7 +380,6 @@ void __init sun4m_init_IRQ(void)
BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(__irq_itoa, sun4m_irq_itoa, BTFIXUPCALL_NORM);
sparc_init_timers = sun4m_init_timers;
#ifdef CONFIG_SMP
BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM);
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index 70b375a4c2c..3b32096134a 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -66,7 +66,7 @@ static inline unsigned long swap(volatile unsigned long *ptr, unsigned long val)
static void smp_setup_percpu_timer(void);
extern void cpu_probe(void);
-void __init smp4m_callin(void)
+void __cpuinit smp4m_callin(void)
{
int cpuid = hard_smp_processor_id();
@@ -112,13 +112,8 @@ void __init smp4m_callin(void)
local_irq_enable();
cpu_set(cpuid, cpu_online_map);
- /* last one in gets all the interrupts (for testing) */
- set_irq_udt(boot_cpu_id);
}
-extern void init_IRQ(void);
-extern void cpu_panic(void);
-
/*
* Cycle through the processors asking the PROM to start each one.
*/
@@ -134,7 +129,7 @@ void __init smp4m_boot_cpus(void)
local_flush_cache_all();
}
-int smp4m_boot_one_cpu(int i)
+int __cpuinit smp4m_boot_one_cpu(int i)
{
extern unsigned long sun4m_cpu_startup;
unsigned long *entry = &sun4m_cpu_startup;
diff --git a/arch/sparc/kernel/sys_solaris.c b/arch/sparc/kernel/sys_solaris.c
index fb7578554c7..c09afd96dd9 100644
--- a/arch/sparc/kernel/sys_solaris.c
+++ b/arch/sparc/kernel/sys_solaris.c
@@ -4,7 +4,6 @@
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
*/
-#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/string.h>
diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c
index 288de276d9f..aa0fb2efb61 100644
--- a/arch/sparc/kernel/sys_sunos.c
+++ b/arch/sparc/kernel/sys_sunos.c
@@ -196,7 +196,7 @@ asmlinkage int sunos_brk(unsigned long brk)
* simple, it hopefully works in most obvious cases.. Easy to
* fool it, but this should catch most mistakes.
*/
- freepages = get_page_cache_size();
+ freepages = global_page_state(NR_FILE_PAGES);
freepages >>= 1;
freepages += nr_free_pages();
freepages += nr_swap_pages;
diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
index 2856551bddf..10df38eeae0 100644
--- a/arch/sparc/kernel/systbls.S
+++ b/arch/sparc/kernel/systbls.S
@@ -9,7 +9,6 @@
* Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
*/
-#include <linux/config.h>
.data
.align 4
diff --git a/arch/sparc/kernel/tick14.c b/arch/sparc/kernel/tick14.c
index 591547af4c6..d3b4daac705 100644
--- a/arch/sparc/kernel/tick14.c
+++ b/arch/sparc/kernel/tick14.c
@@ -74,7 +74,7 @@ void claim_ticker14(irqreturn_t (*handler)(int, void *, struct pt_regs *),
if (!request_irq(irq_nr,
handler,
- (SA_INTERRUPT | SA_STATIC_ALLOC),
+ (IRQF_DISABLED | SA_STATIC_ALLOC),
"counter14",
NULL)) {
install_linux_ticker();
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
index 7dadcdb4ca4..04eb1eab6e3 100644
--- a/arch/sparc/kernel/time.c
+++ b/arch/sparc/kernel/time.c
@@ -15,7 +15,6 @@
* 1997-09-10 Updated NTP code according to technical memorandum Jan '96
* "A Kernel Model for Precision Timekeeping" by Dave Mills
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/sched.h>
@@ -42,6 +41,7 @@
#include <asm/sun4paddr.h>
#include <asm/page.h>
#include <asm/pcic.h>
+#include <asm/of_device.h>
extern unsigned long wall_jiffies;
@@ -273,83 +273,31 @@ static __inline__ void sun4_clock_probe(void)
#endif
}
-/* Probe for the mostek real time clock chip. */
-static __inline__ void clock_probe(void)
+static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
{
- struct linux_prom_registers clk_reg[2];
- char model[128];
- register int node, cpuunit, bootbus;
- struct resource r;
-
- cpuunit = bootbus = 0;
- memset(&r, 0, sizeof(r));
-
- /* Determine the correct starting PROM node for the probe. */
- node = prom_getchild(prom_root_node);
- switch (sparc_cpu_model) {
- case sun4c:
- break;
- case sun4m:
- node = prom_getchild(prom_searchsiblings(node, "obio"));
- break;
- case sun4d:
- node = prom_getchild(bootbus = prom_searchsiblings(prom_getchild(cpuunit = prom_searchsiblings(node, "cpu-unit")), "bootbus"));
- break;
- default:
- prom_printf("CLOCK: Unsupported architecture!\n");
- prom_halt();
- }
+ struct device_node *dp = op->node;
+ char *model = of_get_property(dp, "model", NULL);
- /* Find the PROM node describing the real time clock. */
- sp_clock_typ = MSTK_INVALID;
- node = prom_searchsiblings(node,"eeprom");
- if (!node) {
- prom_printf("CLOCK: No clock found!\n");
- prom_halt();
- }
+ if (!model)
+ return -ENODEV;
- /* Get the model name and setup everything up. */
- model[0] = '\0';
- prom_getstring(node, "model", model, sizeof(model));
- if (strcmp(model, "mk48t02") == 0) {
+ if (!strcmp(model, "mk48t02")) {
sp_clock_typ = MSTK48T02;
- if (prom_getproperty(node, "reg", (char *) clk_reg, sizeof(clk_reg)) == -1) {
- prom_printf("clock_probe: FAILED!\n");
- prom_halt();
- }
- if (sparc_cpu_model == sun4d)
- prom_apply_generic_ranges (bootbus, cpuunit, clk_reg, 1);
- else
- prom_apply_obio_ranges(clk_reg, 1);
+
/* Map the clock register io area read-only */
- r.flags = clk_reg[0].which_io;
- r.start = clk_reg[0].phys_addr;
- mstk48t02_regs = sbus_ioremap(&r, 0,
- sizeof(struct mostek48t02), "mk48t02");
+ mstk48t02_regs = of_ioremap(&op->resource[0], 0,
+ sizeof(struct mostek48t02),
+ "mk48t02");
mstk48t08_regs = NULL; /* To catch weirdness */
- } else if (strcmp(model, "mk48t08") == 0) {
+ } else if (!strcmp(model, "mk48t08")) {
sp_clock_typ = MSTK48T08;
- if(prom_getproperty(node, "reg", (char *) clk_reg,
- sizeof(clk_reg)) == -1) {
- prom_printf("clock_probe: FAILED!\n");
- prom_halt();
- }
- if (sparc_cpu_model == sun4d)
- prom_apply_generic_ranges (bootbus, cpuunit, clk_reg, 1);
- else
- prom_apply_obio_ranges(clk_reg, 1);
- /* Map the clock register io area read-only */
- /* XXX r/o attribute is somewhere in r.flags */
- r.flags = clk_reg[0].which_io;
- r.start = clk_reg[0].phys_addr;
- mstk48t08_regs = sbus_ioremap(&r, 0,
- sizeof(struct mostek48t08), "mk48t08");
+ mstk48t08_regs = of_ioremap(&op->resource[0], 0,
+ sizeof(struct mostek48t08),
+ "mk48t08");
mstk48t02_regs = &mstk48t08_regs->regs;
- } else {
- prom_printf("CLOCK: Unknown model name '%s'\n",model);
- prom_halt();
- }
+ } else
+ return -ENODEV;
/* Report a low battery voltage condition. */
if (has_low_battery())
@@ -358,6 +306,28 @@ static __inline__ void clock_probe(void)
/* Kick start the clock if it is completely stopped. */
if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
kick_start_clock();
+
+ return 0;
+}
+
+static struct of_device_id clock_match[] = {
+ {
+ .name = "eeprom",
+ },
+ {},
+};
+
+static struct of_platform_driver clock_driver = {
+ .name = "clock",
+ .match_table = clock_match,
+ .probe = clock_probe,
+};
+
+
+/* Probe for the mostek real time clock chip. */
+static void clock_init(void)
+{
+ of_register_driver(&clock_driver, &of_bus_type);
}
void __init sbus_time_init(void)
@@ -376,7 +346,7 @@ void __init sbus_time_init(void)
if (ARCH_SUN4)
sun4_clock_probe();
else
- clock_probe();
+ clock_init();
sparc_init_timers(timer_interrupt);
diff --git a/arch/sparc/kernel/traps.c b/arch/sparc/kernel/traps.c
index 41d45c298fb..6a70d215fd0 100644
--- a/arch/sparc/kernel/traps.c
+++ b/arch/sparc/kernel/traps.c
@@ -9,7 +9,6 @@
* I hate traps on the sparc, grrr...
*/
-#include <linux/config.h>
#include <linux/sched.h> /* for jiffies */
#include <linux/kernel.h>
#include <linux/kallsyms.h>