diff options
Diffstat (limited to 'arch/sparc')
48 files changed, 1751 insertions, 265 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, ®s[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, ®s[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> diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile index fa500694606..5db7e1d8538 100644 --- a/arch/sparc/lib/Makefile +++ b/arch/sparc/lib/Makefile @@ -9,3 +9,5 @@ lib-y := mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \ strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \ copy_user.o locks.o atomic.o atomic32.o bitops.o \ lshrdi3.o ashldi3.o rwsem.o muldi3.o bitext.o + +obj-y += iomap.o diff --git a/arch/sparc/lib/atomic.S b/arch/sparc/lib/atomic.S index f48ad0c4dad..178cbb8ae1b 100644 --- a/arch/sparc/lib/atomic.S +++ b/arch/sparc/lib/atomic.S @@ -3,7 +3,6 @@ * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu) */ -#include <linux/config.h> #include <asm/ptrace.h> #include <asm/psr.h> diff --git a/arch/sparc/lib/bitops.S b/arch/sparc/lib/bitops.S index 3e939976907..cb7fb66a40c 100644 --- a/arch/sparc/lib/bitops.S +++ b/arch/sparc/lib/bitops.S @@ -3,7 +3,6 @@ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) */ -#include <linux/config.h> #include <asm/ptrace.h> #include <asm/psr.h> diff --git a/arch/sparc/lib/iomap.c b/arch/sparc/lib/iomap.c new file mode 100644 index 00000000000..54501c1ca78 --- /dev/null +++ b/arch/sparc/lib/iomap.c @@ -0,0 +1,48 @@ +/* + * Implement the sparc iomap interfaces + */ +#include <linux/pci.h> +#include <linux/module.h> +#include <asm/io.h> + +/* Create a virtual mapping cookie for an IO port range */ +void __iomem *ioport_map(unsigned long port, unsigned int nr) +{ + return (void __iomem *) (unsigned long) port; +} + +void ioport_unmap(void __iomem *addr) +{ + /* Nothing to do */ +} +EXPORT_SYMBOL(ioport_map); +EXPORT_SYMBOL(ioport_unmap); + +/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */ +void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) +{ + unsigned long start = pci_resource_start(dev, bar); + unsigned long len = pci_resource_len(dev, bar); + unsigned long flags = pci_resource_flags(dev, bar); + + if (!len || !start) + return NULL; + if (maxlen && len > maxlen) + len = maxlen; + if (flags & IORESOURCE_IO) + return ioport_map(start, len); + if (flags & IORESOURCE_MEM) { + if (flags & IORESOURCE_CACHEABLE) + return ioremap(start, len); + return ioremap_nocache(start, len); + } + /* What? */ + return NULL; +} + +void pci_iounmap(struct pci_dev *dev, void __iomem * addr) +{ + /* nothing to do */ +} +EXPORT_SYMBOL(pci_iomap); +EXPORT_SYMBOL(pci_iounmap); diff --git a/arch/sparc/lib/rwsem.S b/arch/sparc/lib/rwsem.S index e7578dc600b..20657744c86 100644 --- a/arch/sparc/lib/rwsem.S +++ b/arch/sparc/lib/rwsem.S @@ -4,7 +4,6 @@ * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) */ -#include <linux/config.h> #include <asm/ptrace.h> #include <asm/psr.h> diff --git a/arch/sparc/mm/btfixup.c b/arch/sparc/mm/btfixup.c index f147a44c978..ec4231c2855 100644 --- a/arch/sparc/mm/btfixup.c +++ b/arch/sparc/mm/btfixup.c @@ -6,7 +6,6 @@ * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/init.h> #include <asm/btfixup.h> diff --git a/arch/sparc/mm/extable.c b/arch/sparc/mm/extable.c index c9845c71f42..16cc28935e3 100644 --- a/arch/sparc/mm/extable.c +++ b/arch/sparc/mm/extable.c @@ -2,7 +2,6 @@ * linux/arch/sparc/mm/extable.c */ -#include <linux/config.h> #include <linux/module.h> #include <asm/uaccess.h> diff --git a/arch/sparc/mm/hypersparc.S b/arch/sparc/mm/hypersparc.S index a231cca3721..d29cc24c5bb 100644 --- a/arch/sparc/mm/hypersparc.S +++ b/arch/sparc/mm/hypersparc.S @@ -10,7 +10,6 @@ #include <asm/asi.h> #include <asm/page.h> #include <asm/pgtsrmmu.h> -#include <linux/config.h> #include <linux/init.h> .text diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c index 89866973246..c85ddf31274 100644 --- a/arch/sparc/mm/init.c +++ b/arch/sparc/mm/init.c @@ -7,7 +7,6 @@ * Copyright (C) 2000 Anton Blanchard (anton@samba.org) */ -#include <linux/config.h> #include <linux/module.h> #include <linux/signal.h> #include <linux/sched.h> @@ -31,6 +30,7 @@ #include <asm/vaddrs.h> #include <asm/pgalloc.h> /* bug in asm-generic/tlb.h: check_pgt_cache */ #include <asm/tlb.h> +#include <asm/prom.h> DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); @@ -349,6 +349,7 @@ void __init paging_init(void) protection_map[14] = PAGE_SHARED; protection_map[15] = PAGE_SHARED; btfixup(); + prom_build_devicetree(); device_scan(); } diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c index eefffa1dc5d..42c1c700c0a 100644 --- a/arch/sparc/mm/io-unit.c +++ b/arch/sparc/mm/io-unit.c @@ -4,7 +4,6 @@ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/slab.h> diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c index 77840c80478..be042efd1ba 100644 --- a/arch/sparc/mm/iommu.c +++ b/arch/sparc/mm/iommu.c @@ -7,7 +7,6 @@ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/mm.h> @@ -144,8 +143,9 @@ static void iommu_flush_iotlb(iopte_t *iopte, unsigned int niopte) unsigned long start; unsigned long end; - start = (unsigned long)iopte & PAGE_MASK; + start = (unsigned long)iopte; end = PAGE_ALIGN(start + niopte*sizeof(iopte_t)); + start &= PAGE_MASK; if (viking_mxcc_present) { while(start < end) { viking_mxcc_flush_page(start); diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index 58c65cc8d0d..16e13f663ab 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -8,7 +8,6 @@ * Copyright (C) 1999,2000 Anton Blanchard (anton@samba.org) */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/slab.h> diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c index 49f28c1bdc6..7fdddf3c7e1 100644 --- a/arch/sparc/mm/sun4c.c +++ b/arch/sparc/mm/sun4c.c @@ -10,7 +10,6 @@ #define NR_TASK_BUCKETS 512 -#include <linux/config.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/init.h> diff --git a/arch/sparc/mm/swift.S b/arch/sparc/mm/swift.S index cd90f3fdc4e..9f4cd396a0f 100644 --- a/arch/sparc/mm/swift.S +++ b/arch/sparc/mm/swift.S @@ -4,7 +4,6 @@ * Copyright (C) 1999 David S. Miller (davem@redhat.com) */ -#include <linux/config.h> #include <asm/psr.h> #include <asm/asi.h> #include <asm/page.h> diff --git a/arch/sparc/mm/tsunami.S b/arch/sparc/mm/tsunami.S index 697af617594..4988e6a310b 100644 --- a/arch/sparc/mm/tsunami.S +++ b/arch/sparc/mm/tsunami.S @@ -4,7 +4,6 @@ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) */ -#include <linux/config.h> #include <asm/ptrace.h> #include <asm/asm-offsets.h> #include <asm/psr.h> diff --git a/arch/sparc/mm/viking.S b/arch/sparc/mm/viking.S index 3cbd6de18dd..754c622548a 100644 --- a/arch/sparc/mm/viking.S +++ b/arch/sparc/mm/viking.S @@ -6,7 +6,6 @@ * Copyright (C) 1999 Pavel Semerad (semerad@ss1000.ms.mff.cuni.cz) */ -#include <linux/config.h> #include <asm/ptrace.h> #include <asm/psr.h> #include <asm/asm-offsets.h> diff --git a/arch/sparc/prom/init.c b/arch/sparc/prom/init.c index b83409c8191..50abfb1b880 100644 --- a/arch/sparc/prom/init.c +++ b/arch/sparc/prom/init.c @@ -6,7 +6,6 @@ * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/init.h> diff --git a/arch/sparc/prom/memory.c b/arch/sparc/prom/memory.c index c20e5309f8a..b0c0f9c4fc1 100644 --- a/arch/sparc/prom/memory.c +++ b/arch/sparc/prom/memory.c @@ -6,7 +6,6 @@ * Copyright (C) 1997 Michael A. Griffith (grif@acm.org) */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/init.h> diff --git a/arch/sparc/prom/misc.c b/arch/sparc/prom/misc.c index c840c206234..1942c7c05cb 100644 --- a/arch/sparc/prom/misc.c +++ b/arch/sparc/prom/misc.c @@ -5,7 +5,6 @@ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ -#include <linux/config.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/sched.h> |