diff options
Diffstat (limited to 'arch/sparc64')
-rw-r--r-- | arch/sparc64/Kconfig | 2 | ||||
-rw-r--r-- | arch/sparc64/defconfig | 41 | ||||
-rw-r--r-- | arch/sparc64/kernel/devices.c | 3 | ||||
-rw-r--r-- | arch/sparc64/kernel/head.S | 13 | ||||
-rw-r--r-- | arch/sparc64/kernel/of_device.c | 348 | ||||
-rw-r--r-- | arch/sparc64/kernel/pci_psycho.c | 6 | ||||
-rw-r--r-- | arch/sparc64/kernel/prom.c | 63 | ||||
-rw-r--r-- | arch/sparc64/kernel/setup.c | 2 | ||||
-rw-r--r-- | arch/sparc64/kernel/sparc64_ksyms.c | 1 | ||||
-rw-r--r-- | arch/sparc64/kernel/sys_sparc.c | 18 | ||||
-rw-r--r-- | arch/sparc64/kernel/time.c | 2 | ||||
-rw-r--r-- | arch/sparc64/mm/fault.c | 3 | ||||
-rw-r--r-- | arch/sparc64/prom/tree.c | 85 |
13 files changed, 308 insertions, 279 deletions
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index a7a111db25b..8a36ba8868d 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -334,7 +334,7 @@ config COMPAT default y config BINFMT_ELF32 - tristate "Kernel support for 32-bit ELF binaries" + bool "Kernel support for 32-bit ELF binaries" depends on SPARC32_COMPAT help This allows you to run 32-bit Linux/ELF binaries on your Ultra. diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index b2f41147d0e..43d9229fca0 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.17 -# Fri Jun 23 23:17:09 2006 +# Linux kernel version: 2.6.18-rc2 +# Fri Jul 21 14:19:24 2006 # CONFIG_SPARC=y CONFIG_SPARC64=y @@ -18,6 +18,7 @@ CONFIG_SECCOMP=y CONFIG_HZ_250=y # CONFIG_HZ_1000 is not set CONFIG_HZ=250 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # # Code maturity level options @@ -35,6 +36,7 @@ CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set @@ -51,10 +53,12 @@ CONFIG_PRINTK=y CONFIG_BUG=y CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y +CONFIG_RT_MUTEXES=y CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_SHMEM=y CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 # CONFIG_SLOB is not set @@ -127,8 +131,8 @@ CONFIG_SPARSEMEM=y CONFIG_HAVE_MEMORY_PRESENT=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPARSEMEM_EXTREME=y -CONFIG_MEMORY_HOTPLUG=y CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_RESOURCES_64BIT=y CONFIG_GENERIC_ISA_DMA=y CONFIG_SBUS=y CONFIG_SBUSCHAR=y @@ -203,7 +207,6 @@ CONFIG_TCP_CONG_VEGAS=m CONFIG_TCP_CONG_SCALABLE=m CONFIG_TCP_CONG_LP=m CONFIG_TCP_CONG_VENO=m -CONFIG_TCP_CONG_COMPOUND=m CONFIG_IPV6=m CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_ROUTER_PREF=y @@ -461,9 +464,8 @@ CONFIG_MD_LINEAR=m CONFIG_MD_RAID0=m CONFIG_MD_RAID1=m CONFIG_MD_RAID10=m -CONFIG_MD_RAID5=m +CONFIG_MD_RAID456=m # CONFIG_MD_RAID5_RESHAPE is not set -CONFIG_MD_RAID6=m CONFIG_MD_MULTIPATH=m # CONFIG_MD_FAULTY is not set CONFIG_BLK_DEV_DM=m @@ -663,6 +665,7 @@ CONFIG_SERIO_RAW=m CONFIG_VT=y CONFIG_VT_CONSOLE=y CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set # CONFIG_SERIAL_NONSTANDARD is not set # @@ -693,6 +696,7 @@ CONFIG_UNIX98_PTYS=y # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_HW_RANDOM is not set CONFIG_RTC=y # CONFIG_DTLK is not set # CONFIG_R3964 is not set @@ -839,12 +843,13 @@ CONFIG_VIDEO_V4L2=y # # Graphics support # +# CONFIG_FIRMWARE_EDID is not set CONFIG_FB=y CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_IMAGEBLIT=y # CONFIG_FB_MACMODES is not set -# CONFIG_FB_FIRMWARE_EDID is not set +# CONFIG_FB_BACKLIGHT is not set CONFIG_FB_MODE_HELPERS=y CONFIG_FB_TILEBLITTING=y # CONFIG_FB_CIRRUS is not set @@ -954,6 +959,18 @@ CONFIG_SND_ALI5451=m # CONFIG_SND_CMIPCI is not set # CONFIG_SND_CS4281 is not set # CONFIG_SND_CS46XX is not set +# CONFIG_SND_DARLA20 is not set +# CONFIG_SND_GINA20 is not set +# CONFIG_SND_LAYLA20 is not set +# CONFIG_SND_DARLA24 is not set +# CONFIG_SND_GINA24 is not set +# CONFIG_SND_LAYLA24 is not set +# CONFIG_SND_MONA is not set +# CONFIG_SND_MIA is not set +# CONFIG_SND_ECHO3G is not set +# CONFIG_SND_INDIGO is not set +# CONFIG_SND_INDIGOIO is not set +# CONFIG_SND_INDIGODJ is not set # CONFIG_SND_EMU10K1 is not set # CONFIG_SND_EMU10K1X is not set # CONFIG_SND_ENS1370 is not set @@ -1104,7 +1121,7 @@ CONFIG_USB_HIDDEV=y # CONFIG_USB_LEGOTOWER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_LED is not set -# CONFIG_USB_CY7C63 is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set # CONFIG_USB_CYTHERM is not set # CONFIG_USB_PHIDGETKIT is not set # CONFIG_USB_PHIDGETSERVO is not set @@ -1331,14 +1348,19 @@ CONFIG_KPROBES=y # CONFIG_PRINTK_TIME=y CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set CONFIG_DEBUG_KERNEL=y CONFIG_LOG_BUF_SHIFT=18 CONFIG_DETECT_SOFTLOCKUP=y CONFIG_SCHEDSTATS=y # CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set # CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_RWSEMS is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set # CONFIG_DEBUG_KOBJECT is not set CONFIG_DEBUG_BUGVERBOSE=y # CONFIG_DEBUG_INFO is not set @@ -1402,3 +1424,4 @@ CONFIG_CRC32=y CONFIG_LIBCRC32C=m CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y +CONFIG_PLIST=y diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c index f8ef2f2b9b3..ec10f7edcf8 100644 --- a/arch/sparc64/kernel/devices.c +++ b/arch/sparc64/kernel/devices.c @@ -66,9 +66,6 @@ static int check_cpu_node(struct device_node *dp, int *cur_inst, void *compare_arg, struct device_node **dev_node, int *mid) { - if (strcmp(dp->type, "cpu")) - return -ENODEV; - if (!compare(dp, *cur_inst, compare_arg)) { if (dev_node) *dev_node = dp; diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S index 75684b56767..c8e9dc9d68a 100644 --- a/arch/sparc64/kernel/head.S +++ b/arch/sparc64/kernel/head.S @@ -551,9 +551,10 @@ setup_trap_table: save %sp, -192, %sp /* Force interrupts to be disabled. */ - rdpr %pstate, %o1 - andn %o1, PSTATE_IE, %o1 + rdpr %pstate, %l0 + andn %l0, PSTATE_IE, %o1 wrpr %o1, 0x0, %pstate + rdpr %pil, %l1 wrpr %g0, 15, %pil /* Make the firmware call to jump over to the Linux trap table. */ @@ -622,11 +623,9 @@ setup_trap_table: call init_irqwork_curcpu nop - /* Now we can turn interrupts back on. */ - rdpr %pstate, %o1 - or %o1, PSTATE_IE, %o1 - wrpr %o1, 0, %pstate - wrpr %g0, 0x0, %pil + /* Now we can restore interrupt state. */ + wrpr %l0, 0, %pstate + wrpr %l1, 0x0, %pil ret restore diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 169b017eec0..238bbf6de07 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -210,7 +210,7 @@ struct bus_type of_bus_type = { }; EXPORT_SYMBOL(of_bus_type); -static inline u64 of_read_addr(u32 *cell, int size) +static inline u64 of_read_addr(const u32 *cell, int size) { u64 r = 0; while (size--) @@ -236,8 +236,8 @@ struct of_bus { 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); + int (*map)(u32 *addr, const u32 *range, + int na, int ns, int pna); unsigned int (*get_flags)(u32 *addr); }; @@ -251,27 +251,49 @@ static void of_bus_default_count_cells(struct device_node *dev, get_cells(dev, addrc, sizec); } -static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna) +/* Make sure the least significant 64-bits are in-range. Even + * for 3 or 4 cell values it is a good enough approximation. + */ +static int of_out_of_range(const u32 *addr, const u32 *base, + const u32 *size, int na, int ns) { - u64 cp, s, da; + u64 a = of_read_addr(addr, na); + u64 b = of_read_addr(base, na); + + if (a < b) + return 1; - cp = of_read_addr(range, na); - s = of_read_addr(range + na + pna, ns); - da = of_read_addr(addr, na); + b += of_read_addr(size, ns); + if (a >= b) + return 1; - if (da < cp || da >= (cp + s)) - return OF_BAD_ADDR; - return da - cp; + return 0; } -static int of_bus_default_translate(u32 *addr, u64 offset, int na) +static int of_bus_default_map(u32 *addr, const u32 *range, + int na, int ns, int pna) { - 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; + u32 result[OF_MAX_ADDR_CELLS]; + int i; + + if (ns > 2) { + printk("of_device: Cannot handle size cells (%d) > 2.", ns); + return -EINVAL; + } + + if (of_out_of_range(addr, range, range + na + pna, na, ns)) + return -EINVAL; + + /* Start with the parent range base. */ + memcpy(result, range + na, pna * 4); + + /* Add in the child address offset. */ + for (i = 0; i < na; i++) + result[pna - 1 - i] += + (addr[na - 1 - i] - + range[na - 1 - i]); + + memcpy(addr, result, pna * 4); return 0; } @@ -287,7 +309,20 @@ static unsigned int of_bus_default_get_flags(u32 *addr) static int of_bus_pci_match(struct device_node *np) { - return !strcmp(np->type, "pci") || !strcmp(np->type, "pciex"); + if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) { + /* Do not do PCI specific frobbing if the + * PCI bridge lacks a ranges property. We + * want to pass it through up to the next + * parent as-is, not with the PCI translate + * method which chops off the top address cell. + */ + if (!of_find_property(np, "ranges", NULL)) + return 0; + + return 1; + } + + return 0; } static void of_bus_pci_count_cells(struct device_node *np, @@ -299,27 +334,32 @@ static void of_bus_pci_count_cells(struct device_node *np, *sizec = 2; } -static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna) +static int of_bus_pci_map(u32 *addr, const u32 *range, + int na, int ns, int pna) { - u64 cp, s, da; + u32 result[OF_MAX_ADDR_CELLS]; + int i; /* Check address type match */ if ((addr[0] ^ range[0]) & 0x03000000) - return OF_BAD_ADDR; + return -EINVAL; - /* 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 (of_out_of_range(addr + 1, range + 1, range + na + pna, + na - 1, ns)) + return -EINVAL; - if (da < cp || da >= (cp + s)) - return OF_BAD_ADDR; - return da - cp; -} + /* Start with the parent range base. */ + memcpy(result, range + na, pna * 4); -static int of_bus_pci_translate(u32 *addr, u64 offset, int na) -{ - return of_bus_default_translate(addr + 1, offset, na - 1); + /* Add in the child address offset, skipping high cell. */ + for (i = 0; i < na - 1; i++) + result[pna - 1 - i] += + (addr[na - 1 - i] - + range[na - 1 - i]); + + memcpy(addr, result, pna * 4); + + return 0; } static unsigned int of_bus_pci_get_flags(u32 *addr) @@ -340,59 +380,6 @@ static unsigned int of_bus_pci_get_flags(u32 *addr) } /* - * ISA bus specific translator - */ - -static int of_bus_isa_match(struct device_node *np) -{ - return !strcmp(np->name, "isa"); -} - -static void of_bus_isa_count_cells(struct device_node *child, - int *addrc, int *sizec) -{ - if (addrc) - *addrc = 2; - if (sizec) - *sizec = 1; -} - -static u64 of_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna) -{ - u64 cp, s, da; - - /* Check address type match */ - if ((addr[0] ^ range[0]) & 0x00000001) - 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_isa_translate(u32 *addr, u64 offset, int na) -{ - return of_bus_default_translate(addr + 1, offset, na - 1); -} - -static unsigned int of_bus_isa_get_flags(u32 *addr) -{ - unsigned int flags = 0; - u32 w = addr[0]; - - if (w & 1) - flags |= IORESOURCE_IO; - else - flags |= IORESOURCE_MEM; - return flags; -} - -/* * SBUS bus specific translator */ @@ -411,16 +398,11 @@ static void of_bus_sbus_count_cells(struct device_node *child, *sizec = 1; } -static u64 of_bus_sbus_map(u32 *addr, u32 *range, int na, int ns, int pna) +static int of_bus_sbus_map(u32 *addr, const 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; @@ -439,19 +421,8 @@ static struct of_bus of_busses[] = { .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, }, - /* ISA */ - { - .name = "isa", - .addr_prop_name = "reg", - .match = of_bus_isa_match, - .count_cells = of_bus_isa_count_cells, - .map = of_bus_isa_map, - .translate = of_bus_isa_translate, - .get_flags = of_bus_isa_get_flags, - }, /* SBUS */ { .name = "sbus", @@ -459,7 +430,6 @@ static struct of_bus of_busses[] = { .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 */ @@ -469,7 +439,6 @@ static struct of_bus of_busses[] = { .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, }, }; @@ -494,33 +463,62 @@ static int __init build_one_resource(struct device_node *parent, 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; + u32 result[OF_MAX_ADDR_CELLS]; + int i; + + memset(result, 0, pna * 4); + for (i = 0; i < na; i++) + result[pna - 1 - i] = + addr[na - 1 - i]; + + memcpy(addr, result, pna * 4); + return 0; } /* 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 (!bus->map(addr, ranges, na, ns, pna)) + return 0; } - if (offset == OF_BAD_ADDR) + + return 1; +} + +static int __init use_1to1_mapping(struct device_node *pp) +{ + char *model; + + /* If this is on the PMU bus, don't try to translate it even + * if a ranges property exists. + */ + if (!strcmp(pp->name, "pmu")) return 1; - memcpy(addr, ranges + na, 4 * pna); + /* If we have a ranges property in the parent, use it. */ + if (of_find_property(pp, "ranges", NULL) != NULL) + return 0; + + /* If the parent is the dma node of an ISA bus, pass + * the translation up to the root. + */ + if (!strcmp(pp->name, "dma")) + return 0; + + /* Similarly for Simba PCI bridges. */ + model = of_get_property(pp, "model", NULL); + if (model && !strcmp(model, "SUNW,simba")) + return 0; -finish: - /* Translate it into parent bus space */ - return pbus->translate(addr, offset, pna); + return 1; } +static int of_resource_verbose; + static void __init build_device_resources(struct of_device *op, struct device *parent) { @@ -544,9 +542,17 @@ static void __init build_device_resources(struct of_device *op, /* Convert to num-cells. */ num_reg /= 4; - /* Conver to num-entries. */ + /* Convert to num-entries. */ num_reg /= na + ns; + /* Prevent overruning the op->resources[] array. */ + if (num_reg > PROMREG_MAX) { + printk(KERN_WARNING "%s: Too many regs (%d), " + "limiting to %d.\n", + op->node->full_name, num_reg, PROMREG_MAX); + num_reg = PROMREG_MAX; + } + for (index = 0; index < num_reg; index++) { struct resource *r = &op->resource[index]; u32 addr[OF_MAX_ADDR_CELLS]; @@ -564,15 +570,7 @@ static void __init build_device_resources(struct of_device *op, memcpy(addr, reg, na * 4); - /* If the immediate parent has no ranges property to apply, - * just use a 1<->1 mapping. Unless it is the 'dma' child - * of an isa bus, which must be passed up towards the root. - * - * Also, don't try to translate PMU bus device registers. - */ - if ((of_find_property(pp, "ranges", NULL) == NULL && - strcmp(pp->name, "dma") != 0) || - !strcmp(pp->name, "pmu")) { + if (use_1to1_mapping(pp)) { result = of_read_addr(addr, na); goto build_res; } @@ -591,7 +589,8 @@ static void __init build_device_resources(struct of_device *op, pbus = of_match_bus(pp); pbus->count_cells(dp, &pna, &pns); - if (build_one_resource(dp, bus, pbus, addr, dna, dns, pna)) + if (build_one_resource(dp, bus, pbus, addr, + dna, dns, pna)) break; dna = pna; @@ -601,6 +600,12 @@ static void __init build_device_resources(struct of_device *op, build_res: memset(r, 0, sizeof(*r)); + + if (of_resource_verbose) + printk("%s reg[%d] -> %lx\n", + op->node->full_name, index, + result); + if (result != OF_BAD_ADDR) { if (tlb_type == hypervisor) result &= 0x0fffffffffffffffUL; @@ -653,8 +658,22 @@ apply_interrupt_map(struct device_node *dp, struct device_node *pp, next: imap += (na + 3); } - if (i == imlen) + if (i == imlen) { + /* Psycho and Sabre PCI controllers can have 'interrupt-map' + * properties that do not include the on-board device + * interrupts. Instead, the device's 'interrupts' property + * is already a fully specified INO value. + * + * Handle this by deciding that, if we didn't get a + * match in the parent's 'interrupt-map', and the + * parent is an IRQ translater, then use the parent as + * our IRQ controller. + */ + if (pp->irq_trans) + return pp; + return NULL; + } *irq_p = irq; cp = of_find_node_by_phandle(handle); @@ -684,6 +703,8 @@ static unsigned int __init pci_irq_swizzle(struct device_node *dp, return ret; } +static int of_irq_verbose; + static unsigned int __init build_one_device_irq(struct of_device *op, struct device *parent, unsigned int irq) @@ -698,10 +719,11 @@ static unsigned int __init build_one_device_irq(struct of_device *op, if (dp->irq_trans) { irq = dp->irq_trans->irq_build(dp, irq, dp->irq_trans->data); -#if 1 - printk("%s: direct translate %x --> %x\n", - dp->full_name, orig_irq, irq); -#endif + + if (of_irq_verbose) + printk("%s: direct translate %x --> %x\n", + dp->full_name, orig_irq, irq); + return irq; } @@ -728,12 +750,13 @@ static unsigned int __init build_one_device_irq(struct of_device *op, iret = apply_interrupt_map(dp, pp, imap, imlen, imsk, &irq); -#if 1 - printk("%s: Apply [%s:%x] imap --> [%s:%x]\n", - op->node->full_name, - pp->full_name, this_orig_irq, - (iret ? iret->full_name : "NULL"), irq); -#endif + + if (of_irq_verbose) + printk("%s: Apply [%s:%x] imap --> [%s:%x]\n", + op->node->full_name, + pp->full_name, this_orig_irq, + (iret ? iret->full_name : "NULL"), irq); + if (!iret) break; @@ -747,11 +770,13 @@ static unsigned int __init build_one_device_irq(struct of_device *op, unsigned int this_orig_irq = irq; irq = pci_irq_swizzle(dp, pp, irq); -#if 1 - printk("%s: PCI swizzle [%s] %x --> %x\n", - op->node->full_name, - pp->full_name, this_orig_irq, irq); -#endif + if (of_irq_verbose) + printk("%s: PCI swizzle [%s] " + "%x --> %x\n", + op->node->full_name, + pp->full_name, this_orig_irq, + irq); + } if (pp->irq_trans) { @@ -767,10 +792,9 @@ static unsigned int __init build_one_device_irq(struct of_device *op, irq = ip->irq_trans->irq_build(op->node, irq, ip->irq_trans->data); -#if 1 - printk("%s: Apply IRQ trans [%s] %x --> %x\n", - op->node->full_name, ip->full_name, orig_irq, irq); -#endif + if (of_irq_verbose) + printk("%s: Apply IRQ trans [%s] %x --> %x\n", + op->node->full_name, ip->full_name, orig_irq, irq); return irq; } @@ -801,6 +825,14 @@ static struct of_device * __init scan_one_device(struct device_node *dp, op->num_irqs = 0; } + /* Prevent overruning the op->irqs[] array. */ + if (op->num_irqs > PROMINTR_MAX) { + printk(KERN_WARNING "%s: Too many irqs (%d), " + "limiting to %d.\n", + dp->full_name, op->num_irqs, PROMINTR_MAX); + op->num_irqs = PROMINTR_MAX; + } + build_device_resources(op, parent); for (i = 0; i < op->num_irqs; i++) op->irqs[i] = build_one_device_irq(op, parent, op->irqs[i]); @@ -870,6 +902,20 @@ static int __init of_bus_driver_init(void) postcore_initcall(of_bus_driver_init); +static int __init of_debug(char *str) +{ + int val = 0; + + get_option(&str, &val); + if (val & 1) + of_resource_verbose = 1; + if (val & 2) + of_irq_verbose = 1; + return 1; +} + +__setup("of_debug=", of_debug); + int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus) { /* initialize common driver fields */ @@ -922,9 +968,11 @@ int of_device_register(struct of_device *ofdev) if (rc) return rc; - device_create_file(&ofdev->dev, &dev_attr_devspec); + rc = device_create_file(&ofdev->dev, &dev_attr_devspec); + if (rc) + device_unregister(&ofdev->dev); - return 0; + return rc; } void of_device_unregister(struct of_device *ofdev) diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 197a7ffd57e..1ec0aab68c0 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -1099,9 +1099,6 @@ static void pbm_register_toplevel_resources(struct pci_controller_info *p, { char *name = pbm->name; - sprintf(name, "PSYCHO%d PBM%c", - p->index, - (pbm == &p->pbm_A ? 'A' : 'B')); pbm->io_space.name = pbm->mem_space.name = name; request_resource(&ioport_resource, &pbm->io_space); @@ -1203,12 +1200,13 @@ static void psycho_pbm_init(struct pci_controller_info *p, pbm->io_space.flags = IORESOURCE_IO; pbm->mem_space.end = pbm->mem_space.start + PSYCHO_MEMSPACE_SIZE; pbm->mem_space.flags = IORESOURCE_MEM; - pbm_register_toplevel_resources(p, pbm); pbm->parent = p; pbm->prom_node = dp; pbm->name = dp->full_name; + pbm_register_toplevel_resources(p, pbm); + printk("%s: PSYCHO PCI Bus Module ver[%x:%x]\n", pbm->name, pbm->chip_version, pbm->chip_revision); diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index 99daeee4209..5cc5ab63293 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -344,10 +344,12 @@ static unsigned long __psycho_onboard_imap_off[] = { /*0x2f*/ PSYCHO_IMAP_CE, /*0x30*/ PSYCHO_IMAP_A_ERR, /*0x31*/ PSYCHO_IMAP_B_ERR, -/*0x32*/ PSYCHO_IMAP_PMGMT +/*0x32*/ PSYCHO_IMAP_PMGMT, +/*0x33*/ PSYCHO_IMAP_GFX, +/*0x34*/ PSYCHO_IMAP_EUPA, }; #define PSYCHO_ONBOARD_IRQ_BASE 0x20 -#define PSYCHO_ONBOARD_IRQ_LAST 0x32 +#define PSYCHO_ONBOARD_IRQ_LAST 0x34 #define psycho_onboard_imap_offset(__ino) \ __psycho_onboard_imap_off[(__ino) - PSYCHO_ONBOARD_IRQ_BASE] @@ -529,6 +531,10 @@ static unsigned long __sabre_onboard_imap_off[] = { /*0x2e*/ SABRE_IMAP_UE, /*0x2f*/ SABRE_IMAP_CE, /*0x30*/ SABRE_IMAP_PCIERR, +/*0x31*/ 0 /* reserved */, +/*0x32*/ 0 /* reserved */, +/*0x33*/ SABRE_IMAP_GFX, +/*0x34*/ SABRE_IMAP_EUPA, }; #define SABRE_ONBOARD_IRQ_BASE 0x20 #define SABRE_ONBOARD_IRQ_LAST 0x30 @@ -539,6 +545,45 @@ static unsigned long __sabre_onboard_imap_off[] = { ((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ (SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) +static int sabre_device_needs_wsync(struct device_node *dp) +{ + struct device_node *parent = dp->parent; + char *parent_model, *parent_compat; + + /* This traversal up towards the root is meant to + * handle two cases: + * + * 1) non-PCI bus sitting under PCI, such as 'ebus' + * 2) the PCI controller interrupts themselves, which + * will use the sabre_irq_build but do not need + * the DMA synchronization handling + */ + while (parent) { + if (!strcmp(parent->type, "pci")) + break; + parent = parent->parent; + } + + if (!parent) + return 0; + + parent_model = of_get_property(parent, + "model", NULL); + if (parent_model && + (!strcmp(parent_model, "SUNW,sabre") || + !strcmp(parent_model, "SUNW,simba"))) + return 0; + + parent_compat = of_get_property(parent, + "compatible", NULL); + if (parent_compat && + (!strcmp(parent_compat, "pci108e,a000") || + !strcmp(parent_compat, "pci108e,a001"))) + return 0; + + return 1; +} + static unsigned int sabre_irq_build(struct device_node *dp, unsigned int ino, void *_data) @@ -577,15 +622,17 @@ static unsigned int sabre_irq_build(struct device_node *dp, virt_irq = build_irq(inofixup, iclr, imap); + /* If the parent device is a PCI<->PCI bridge other than + * APB, we have to install a pre-handler to ensure that + * all pending DMA is drained before the interrupt handler + * is run. + */ regs = of_get_property(dp, "reg", NULL); - if (regs && - ((regs->phys_hi >> 16) & 0xff) != irq_data->pci_first_busno) { + if (regs && sabre_device_needs_wsync(dp)) { irq_install_pre_handler(virt_irq, sabre_wsync_handler, (void *) (long) regs->phys_hi, - (void *) - controller_regs + - SABRE_WRSYNC); + (void *) irq_data); } return virt_irq; @@ -854,6 +901,8 @@ static unsigned long sysio_irq_offsets[] = { SYSIO_IMAP_CE, SYSIO_IMAP_SBERR, SYSIO_IMAP_PMGMT, + SYSIO_IMAP_GFX, + SYSIO_IMAP_EUPA, }; #undef bogon diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index a73140466e0..958287448cf 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -16,7 +16,7 @@ #include <asm/smp.h> #include <linux/user.h> #include <linux/a.out.h> -#include <linux/tty.h> +#include <linux/screen_info.h> #include <linux/delay.h> #include <linux/fs.h> #include <linux/seq_file.h> diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 237524d87ca..beffc82a1e8 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -254,7 +254,6 @@ EXPORT_SYMBOL(prom_getproperty); EXPORT_SYMBOL(prom_node_has_property); EXPORT_SYMBOL(prom_setprop); EXPORT_SYMBOL(saved_command_line); -EXPORT_SYMBOL(prom_getname); EXPORT_SYMBOL(prom_finddevice); EXPORT_SYMBOL(prom_feval); EXPORT_SYMBOL(prom_getbool); diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index 51c056df528..054d0abdb7e 100644 --- a/arch/sparc64/kernel/sys_sparc.c +++ b/arch/sparc64/kernel/sys_sparc.c @@ -701,21 +701,21 @@ extern void check_pending(int signum); asmlinkage long sys_getdomainname(char __user *name, int len) { - int nlen; - int err = -EFAULT; + int nlen, err; + + if (len < 0 || len > __NEW_UTS_LEN) + return -EINVAL; down_read(&uts_sem); nlen = strlen(system_utsname.domainname) + 1; - if (nlen < len) len = nlen; - if (len > __NEW_UTS_LEN) - goto done; - if (copy_to_user(name, system_utsname.domainname, len)) - goto done; - err = 0; -done: + + err = -EFAULT; + if (!copy_to_user(name, system_utsname.domainname, len)) + err = 0; + up_read(&uts_sem); return err; } diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index b43de647ba7..094d3e35be1 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -928,8 +928,6 @@ static void sparc64_start_timers(void) __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : /* no outputs */ : "r" (pstate)); - - local_irq_enable(); } struct freq_table { diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c index 1605967cce9..55ae802dc0a 100644 --- a/arch/sparc64/mm/fault.c +++ b/arch/sparc64/mm/fault.c @@ -19,6 +19,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/kprobes.h> +#include <linux/kallsyms.h> #include <asm/page.h> #include <asm/pgtable.h> @@ -132,6 +133,8 @@ static void bad_kernel_pc(struct pt_regs *regs, unsigned long vaddr) printk(KERN_CRIT "OOPS: Bogus kernel PC [%016lx] in fault handler\n", regs->tpc); + printk(KERN_CRIT "OOPS: RPC [%016lx]\n", regs->u_regs[15]); + print_symbol("RPC: <%s>\n", regs->u_regs[15]); printk(KERN_CRIT "OOPS: Fault was to vaddr[%lx]\n", vaddr); __asm__("mov %%sp, %0" : "=r" (ksp)); show_stack(current, ksp); diff --git a/arch/sparc64/prom/tree.c b/arch/sparc64/prom/tree.c index 49075abd7cb..500f05e2cfc 100644 --- a/arch/sparc64/prom/tree.c +++ b/arch/sparc64/prom/tree.c @@ -193,91 +193,6 @@ prom_searchsiblings(int node_start, const char *nodename) return 0; } -/* Gets name in the {name@x,yyyyy|name (if no reg)} form */ -int -prom_getname (int node, char *buffer, int len) -{ - int i, sbus = 0; - int pci = 0, ebus = 0, ide = 0; - struct linux_prom_registers *reg; - struct linux_prom64_registers reg64[PROMREG_MAX]; - - for (sbus = prom_getparent (node); sbus; sbus = prom_getparent (sbus)) { - i = prom_getproperty (sbus, "name", buffer, len); - if (i > 0) { - buffer [i] = 0; - if (!strcmp (buffer, "sbus")) - goto getit; - } - } - if ((pci = prom_getparent (node))) { - i = prom_getproperty (pci, "name", buffer, len); - if (i > 0) { - buffer [i] = 0; - if (!strcmp (buffer, "pci")) - goto getit; - } - pci = 0; - } - if ((ebus = prom_getparent (node))) { - i = prom_getproperty (ebus, "name", buffer, len); - if (i > 0) { - buffer[i] = 0; - if (!strcmp (buffer, "ebus")) - goto getit; - } - ebus = 0; - } - if ((ide = prom_getparent (node))) { - i = prom_getproperty (ide, "name", buffer, len); - if (i > 0) { - buffer [i] = 0; - if (!strcmp (buffer, "ide")) - goto getit; - } - ide = 0; - } -getit: - i = prom_getproperty (node, "name", buffer, len); - if (i <= 0) { - buffer [0] = 0; - return -1; - } - buffer [i] = 0; - len -= i; - i = prom_getproperty (node, "reg", (char *)reg64, sizeof (reg64)); - if (i <= 0) return 0; - if (len < 16) return -1; - buffer = strchr (buffer, 0); - if (sbus) { - reg = (struct linux_prom_registers *)reg64; - sprintf (buffer, "@%x,%x", reg[0].which_io, (uint)reg[0].phys_addr); - } else if (pci) { - int dev, fn; - reg = (struct linux_prom_registers *)reg64; - fn = (reg[0].which_io >> 8) & 0x07; - dev = (reg[0].which_io >> 11) & 0x1f; - if (fn) - sprintf (buffer, "@%x,%x", dev, fn); - else - sprintf (buffer, "@%x", dev); - } else if (ebus) { - reg = (struct linux_prom_registers *)reg64; - sprintf (buffer, "@%x,%x", reg[0].which_io, reg[0].phys_addr); - } else if (ide) { - reg = (struct linux_prom_registers *)reg64; - sprintf (buffer, "@%x,%x", reg[0].which_io, reg[0].phys_addr); - } else if (i == 4) { /* Happens on 8042's children on Ultra/PCI. */ - reg = (struct linux_prom_registers *)reg64; - sprintf (buffer, "@%x", reg[0].which_io); - } else { - sprintf (buffer, "@%x,%x", - (unsigned int)(reg64[0].phys_addr >> 36), - (unsigned int)(reg64[0].phys_addr)); - } - return 0; -} - /* Return the first property type for node 'node'. * buffer should be at least 32B in length */ |