diff options
Diffstat (limited to 'arch')
74 files changed, 1362 insertions, 1006 deletions
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 2568d311be21..23348e9561b9 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -247,7 +247,7 @@ not_relocated: mov r0, #0 mov r3, r7 bl decompress_kernel - add r0, r0, #127 + add r0, r0, #127 + 128 @ alignment + stack bic r0, r0, #127 @ align the kernel length /* * r0 = decompressed kernel length @@ -269,6 +269,7 @@ not_relocated: mov r0, #0 stmia r1!, {r9 - r14} cmp r2, r3 blo 1b + add sp, r1, #128 @ relocate the stack bl cache_clean_flush add pc, r5, r0 @ call relocation code @@ -476,6 +477,7 @@ __common_mmu_cache_on: */ .align 5 reloc_start: add r9, r5, r0 + sub r9, r9, #128 @ do not copy the stack debug_reloc_start mov r1, r4 1: @@ -486,6 +488,7 @@ reloc_start: add r9, r5, r0 cmp r5, r9 blo 1b + add sp, r1, #128 @ relocate the stack debug_reloc_end call_kernel: bl cache_clean_flush diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c index 06c9a0507d0d..848efb2a4ebf 100644 --- a/arch/arm/mach-at91/clock.c +++ b/arch/arm/mach-at91/clock.c @@ -364,19 +364,14 @@ static int at91_clk_show(struct seq_file *s, void *unused) { u32 scsr, pcsr, sr; struct clk *clk; - unsigned i; seq_printf(s, "SCSR = %8x\n", scsr = at91_sys_read(AT91_PMC_SCSR)); seq_printf(s, "PCSR = %8x\n", pcsr = at91_sys_read(AT91_PMC_PCSR)); - seq_printf(s, "MOR = %8x\n", at91_sys_read(AT91_CKGR_MOR)); seq_printf(s, "MCFR = %8x\n", at91_sys_read(AT91_CKGR_MCFR)); seq_printf(s, "PLLA = %8x\n", at91_sys_read(AT91_CKGR_PLLAR)); seq_printf(s, "PLLB = %8x\n", at91_sys_read(AT91_CKGR_PLLBR)); - seq_printf(s, "MCKR = %8x\n", at91_sys_read(AT91_PMC_MCKR)); - for (i = 0; i < 4; i++) - seq_printf(s, "PCK%d = %8x\n", i, at91_sys_read(AT91_PMC_PCKR(i))); seq_printf(s, "SR = %8x\n", sr = at91_sys_read(AT91_PMC_SR)); seq_printf(s, "\n"); diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index ff8db29e989e..47ff676aca5f 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -76,12 +76,11 @@ static int at91_pm_verify_clocks(void) pr_debug("AT91: PM - Suspend-to-RAM with USB still active\n"); return 0; } - } else if (cpu_is_at91sam9260()) { -#warning "Check SAM9260 USB clocks" - } else if (cpu_is_at91sam9261()) { -#warning "Check SAM9261 USB clocks" - } else if (cpu_is_at91sam9263()) { -#warning "Check SAM9263 USB clocks" + } else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || cpu_is_at91sam9263()) { + if ((scsr & (AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP)) != 0) { + pr_debug("AT91: PM - Suspend-to-RAM with USB still active\n"); + return 0; + } } #ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS diff --git a/arch/arm/oprofile/op_model_mpcore.c b/arch/arm/oprofile/op_model_mpcore.c index 7791da791f5f..75bae067922d 100644 --- a/arch/arm/oprofile/op_model_mpcore.c +++ b/arch/arm/oprofile/op_model_mpcore.c @@ -200,8 +200,10 @@ static int em_call_function(int (*fn)(void)) data.fn = fn; data.ret = 0; + preempt_disable(); smp_call_function(em_func, &data, 1, 1); em_func(&data); + preempt_enable(); return data.ret; } diff --git a/arch/i386/math-emu/fpu_entry.c b/arch/i386/math-emu/fpu_entry.c index ddf8fa3bbd01..1853524c8b57 100644 --- a/arch/i386/math-emu/fpu_entry.c +++ b/arch/i386/math-emu/fpu_entry.c @@ -754,7 +754,7 @@ int save_i387_soft(void *s387, struct _fpstate __user * buf) return -1; if ( offset ) if (__copy_to_user(d+other, (u_char *)&S387->st_space, offset)) - return -1 + return -1; RE_ENTRANT_CHECK_ON; return 1; diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c index 29d7d61543a1..1ecb3e43b523 100644 --- a/arch/i386/mm/fault.c +++ b/arch/i386/mm/fault.c @@ -458,6 +458,11 @@ bad_area: bad_area_nosemaphore: /* User mode accesses just cause a SIGSEGV */ if (error_code & 4) { + /* + * It's possible to have interrupts off here. + */ + local_irq_enable(); + /* * Valid to do another page fault here because this one came * from user space. diff --git a/arch/m68knommu/platform/5307/timers.c b/arch/m68knommu/platform/5307/timers.c index 92e58070b016..fb66eadd5896 100644 --- a/arch/m68knommu/platform/5307/timers.c +++ b/arch/m68knommu/platform/5307/timers.c @@ -62,10 +62,13 @@ void coldfire_tick(void) /***************************************************************************/ +static int ticks_per_intr; + void coldfire_timer_init(irq_handler_t handler) { __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR)); - __raw_writetrr(((MCF_BUSCLK / 16) / HZ), TA(MCFTIMER_TRR)); + ticks_per_intr = (MCF_BUSCLK / 16) / HZ; + __raw_writetrr(ticks_per_intr - 1, TA(MCFTIMER_TRR)); __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR)); @@ -81,11 +84,10 @@ void coldfire_timer_init(irq_handler_t handler) unsigned long coldfire_timer_offset(void) { - unsigned long trr, tcn, offset; + unsigned long tcn, offset; tcn = __raw_readw(TA(MCFTIMER_TCN)); - trr = __raw_readtrr(TA(MCFTIMER_TRR)); - offset = (tcn * (1000000 / HZ)) / trr; + offset = ((tcn + 1) * (1000000 / HZ)) / ticks_per_intr; /* Check if we just wrapped the counters and maybe missed a tick */ if ((offset < (1000000 / HZ / 2)) && mcf_timerirqpending(1)) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 0f09412e1b7f..9528ee90640a 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -747,9 +747,9 @@ config EARLY_PRINTK to print messages very early in the bootup process. This is useful for kernel debugging when your machine crashes very - early before the console code is initialized. For normal operation - it is not recommended because it looks on some machines ugly and - oesn't cooperate with an X server. You should normally N here, + early before the console code is initialized. For normal operation, + it is not recommended because it looks ugly on some machines and + doesn't cooperate with an X server. You should normally say N here, unless you want to debug such a crash. config SYS_HAS_EARLY_PRINTK diff --git a/arch/mips/emma2rh/markeins/setup.c b/arch/mips/emma2rh/markeins/setup.c index b29a44739230..2f060e1ed36c 100644 --- a/arch/mips/emma2rh/markeins/setup.c +++ b/arch/mips/emma2rh/markeins/setup.c @@ -115,30 +115,6 @@ extern void markeins_irq_setup(void); static void inline __init markeins_sio_setup(void) { -#ifdef CONFIG_KGDB_8250 - struct uart_port emma_port; - - memset(&emma_port, 0, sizeof(emma_port)); - - emma_port.flags = - UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; - emma_port.iotype = UPIO_MEM; - emma_port.regshift = 4; /* I/O addresses are every 8 bytes */ - emma_port.uartclk = 18544000; /* Clock rate of the chip */ - - emma_port.line = 0; - emma_port.mapbase = KSEG1ADDR(EMMA2RH_PFUR0_BASE + 3); - emma_port.membase = (u8*)emma_port.mapbase; - early_serial_setup(&emma_port); - - emma_port.line = 1; - emma_port.mapbase = KSEG1ADDR(EMMA2RH_PFUR1_BASE + 3); - emma_port.membase = (u8*)emma_port.mapbase; - early_serial_setup(&emma_port); - - emma_port.irq = EMMA2RH_IRQ_PFUR1; - kgdb8250_add_port(1, &emma_port); -#endif } void __init plat_mem_setup(void) diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 37849edd0645..06e04da211d5 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -556,6 +556,16 @@ asmlinkage long sys32_sync_file_range(int fd, int __pad, flags); } +asmlinkage long sys32_fadvise64_64(int fd, int __pad, + unsigned long a2, unsigned long a3, + unsigned long a4, unsigned long a5, + int flags) +{ + return sys_fadvise64_64(fd, + merge_64(a2, a3), merge_64(a4, a5), + flags); +} + save_static_function(sys32_clone); __attribute_used__ noinline static int _sys32_clone(nabi_no_regargs struct pt_regs regs) diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index cc566cf12246..06729596812f 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S @@ -174,7 +174,7 @@ LEAF(_init_fpu) or t0, t1 mtc0 t0, CP0_STATUS #endif /* CONFIG_MIPS_MT_SMTC */ - fpu_enable_hazard + enable_fpu_hazard li t1, FPU_DEFAULT ctc1 t1, fcr31 diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 6eac28337423..1631035ffc24 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -299,7 +299,7 @@ EXPORT(sysn32_call_table) PTR sys_ni_syscall /* res. for afs_syscall */ PTR sys_ni_syscall /* res. for security */ PTR sys_gettid - PTR sys32_readahead + PTR sys_readahead PTR sys_setxattr /* 6180 */ PTR sys_lsetxattr PTR sys_fsetxattr diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 7e74b412a782..2aa99426ac1c 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -459,7 +459,7 @@ sys_call_table: PTR sys_remap_file_pages PTR sys_set_tid_address PTR sys_restart_syscall - PTR sys_fadvise64_64 + PTR sys32_fadvise64_64 PTR compat_sys_statfs64 /* 4255 */ PTR compat_sys_fstatfs64 PTR compat_sys_timer_create diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 200de027f354..3f58b6ac1358 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -927,12 +927,6 @@ asmlinkage void do_reserved(struct pt_regs *regs) (regs->cp0_cause & 0x7f) >> 2); } -static asmlinkage void do_default_vi(void) -{ - show_regs(get_irq_regs()); - panic("Caught unexpected vectored interrupt."); -} - /* * Some MIPS CPUs can enable/disable for cache parity detection, but do * it different ways. @@ -1128,6 +1122,12 @@ void mips_srs_free(int set) clear_bit(set, &sr->sr_allocated); } +static asmlinkage void do_default_vi(void) +{ + show_regs(get_irq_regs()); + panic("Caught unexpected vectored interrupt."); +} + static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) { unsigned long handler; diff --git a/arch/mips/mips-boards/atlas/atlas_setup.c b/arch/mips/mips-boards/atlas/atlas_setup.c index 0c6b0ce15028..1cc6ebbedfdd 100644 --- a/arch/mips/mips-boards/atlas/atlas_setup.c +++ b/arch/mips/mips-boards/atlas/atlas_setup.c @@ -48,6 +48,8 @@ const char *get_system_type(void) return "MIPS Atlas"; } +const char display_string[] = " LINUX ON ATLAS "; + void __init plat_mem_setup(void) { mips_pcibios_init(); diff --git a/arch/mips/mips-boards/generic/display.c b/arch/mips/mips-boards/generic/display.c index 548dbe5ce7c8..5d600054090a 100644 --- a/arch/mips/mips-boards/generic/display.c +++ b/arch/mips/mips-boards/generic/display.c @@ -19,9 +19,14 @@ */ #include <linux/compiler.h> +#include <linux/timer.h> #include <asm/io.h> #include <asm/mips-boards/generic.h> +extern const char display_string[]; +static unsigned int display_count; +static unsigned int max_display_count; + void mips_display_message(const char *str) { static unsigned int __iomem *display = NULL; @@ -37,3 +42,22 @@ void mips_display_message(const char *str) writel(' ', display + i); } } + +static void scroll_display_message(unsigned long data); +static DEFINE_TIMER(mips_scroll_timer, scroll_display_message, HZ, 0); + +static void scroll_display_message(unsigned long data) +{ + mips_display_message(&display_string[display_count++]); + if (display_count == max_display_count) + display_count = 0; + + mod_timer(&mips_scroll_timer, jiffies + HZ); +} + +void mips_scroll_message(void) +{ + del_timer_sync(&mips_scroll_timer); + max_display_count = strlen(display_string) + 1 - 8; + mod_timer(&mips_scroll_timer, jiffies + 1); +} diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c index df2a2bd3aa5d..37735bfc3afd 100644 --- a/arch/mips/mips-boards/generic/time.c +++ b/arch/mips/mips-boards/generic/time.c @@ -53,37 +53,11 @@ unsigned long cpu_khz; -#if defined(CONFIG_MIPS_ATLAS) -static char display_string[] = " LINUX ON ATLAS "; -#endif -#if defined(CONFIG_MIPS_MALTA) -#if defined(CONFIG_MIPS_MT_SMTC) -static char display_string[] = " SMTC LINUX ON MALTA "; -#else -static char display_string[] = " LINUX ON MALTA "; -#endif /* CONFIG_MIPS_MT_SMTC */ -#endif -#if defined(CONFIG_MIPS_SEAD) -static char display_string[] = " LINUX ON SEAD "; -#endif -static unsigned int display_count; -#define MAX_DISPLAY_COUNT (sizeof(display_string) - 8) - #define CPUCTR_IMASKBIT (0x100 << MIPSCPU_INT_CPUCTR) -static unsigned int timer_tick_count; static int mips_cpu_timer_irq; extern void smtc_timer_broadcast(int); -static inline void scroll_display_message(void) -{ - if ((timer_tick_count++ % HZ) == 0) { - mips_display_message(&display_string[display_count++]); - if (display_count == MAX_DISPLAY_COUNT) - display_count = 0; - } -} - static void mips_timer_dispatch(void) { do_IRQ(mips_cpu_timer_irq); @@ -143,7 +117,6 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id) if (cpu_data[cpu].vpe_id == 0) { timer_interrupt(irq, NULL); smtc_timer_broadcast(cpu_data[cpu].vpe_id); - scroll_display_message(); } else { write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ)); @@ -167,8 +140,6 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id) /* we keep interrupt disabled all the time */ if (!r2 || (read_c0_cause() & (1 << 30))) timer_interrupt(irq, NULL); - - scroll_display_message(); } else { /* Everyone else needs to reset the timer int here as ll_local_timer_interrupt doesn't */ @@ -262,6 +233,8 @@ void __init mips_time_init(void) (est_freq%1000000)*100/1000000); cpu_khz = est_freq / 1000; + + mips_scroll_message(); } void __init plat_timer_setup(struct irqaction *irq) diff --git a/arch/mips/mips-boards/malta/malta_setup.c b/arch/mips/mips-boards/malta/malta_setup.c index 7873932532a1..c14b7bf89950 100644 --- a/arch/mips/mips-boards/malta/malta_setup.c +++ b/arch/mips/mips-boards/malta/malta_setup.c @@ -56,6 +56,12 @@ const char *get_system_type(void) return "MIPS Malta"; } +#if defined(CONFIG_MIPS_MT_SMTC) +const char display_string[] = " SMTC LINUX ON MALTA "; +#else +const char display_string[] = " LINUX ON MALTA "; +#endif /* CONFIG_MIPS_MT_SMTC */ + #ifdef CONFIG_BLK_DEV_FD void __init fd_activate(void) { diff --git a/arch/mips/mips-boards/sead/sead_setup.c b/arch/mips/mips-boards/sead/sead_setup.c index a189dec7c7bc..811aba100605 100644 --- a/arch/mips/mips-boards/sead/sead_setup.c +++ b/arch/mips/mips-boards/sead/sead_setup.c @@ -43,6 +43,8 @@ const char *get_system_type(void) return "MIPS SEAD"; } +const char display_string[] = " LINUX ON SEAD "; + void __init plat_mem_setup(void) { ioport_resource.end = 0x7fffffff; diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index f0eb29917d9a..76903c727647 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -168,8 +168,9 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, addr = (unsigned long) page_address(sg->page); if (!plat_device_is_coherent(dev) && addr) __dma_sync(addr + sg->offset, sg->length, direction); - sg->dma_address = plat_map_dma_mem_page(dev, sg->page) + - sg->offset; + sg->dma_address = plat_map_dma_mem(dev, + (void *)(addr + sg->offset), + sg->length); } return nents; diff --git a/arch/mips/qemu/q-irq.c b/arch/mips/qemu/q-irq.c index f5ea2fe10f14..89891e984b3b 100644 --- a/arch/mips/qemu/q-irq.c +++ b/arch/mips/qemu/q-irq.c @@ -7,8 +7,6 @@ #include <asm/system.h> #include <asm/time.h> -extern asmlinkage void qemu_handle_int(void); - asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_status() & read_c0_cause(); diff --git a/arch/mips/sni/pcimt.c b/arch/mips/sni/pcimt.c index 9ee208daa8b1..97b234361b4d 100644 --- a/arch/mips/sni/pcimt.c +++ b/arch/mips/sni/pcimt.c @@ -6,7 +6,7 @@ * for more details. * * Copyright (C) 1996, 97, 98, 2000, 03, 04, 06 Ralf Baechle (ralf@linux-mips.org) - * Copyright (C) 2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + * Copyright (C) 2006,2007 Thomas Bogendoerfer (tsbogend@alpha.franken.de) */ #include <linux/init.h> @@ -131,6 +131,19 @@ static struct resource pcimt_io_resources[] = { } }; +static struct resource pcimt_mem_resources[] = { + { + /* + * this region should only be 4 bytes long, + * but it's 16MB on all RM300C I've checked + */ + .start = 0x1a000000, + .end = 0x1affffff, + .name = "PCI INT ACK", + .flags = IORESOURCE_BUSY + } +}; + static struct resource sni_mem_resource = { .start = 0x18000000UL, .end = 0x1fbfffffUL, @@ -145,6 +158,9 @@ static void __init sni_pcimt_resource_init(void) /* request I/O space for devices used on all i[345]86 PCs */ for (i = 0; i < ARRAY_SIZE(pcimt_io_resources); i++) request_resource(&sni_io_resource, pcimt_io_resources + i); + /* request MEM space for devices used on all i[345]86 PCs */ + for (i = 0; i < ARRAY_SIZE(pcimt_mem_resources); i++) + request_resource(&sni_mem_resource, pcimt_mem_resources + i); } extern struct pci_ops sni_pcimt_ops; diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c index 68d7cf609b4f..4fedfbda0c79 100644 --- a/arch/mips/sni/setup.c +++ b/arch/mips/sni/setup.c @@ -6,7 +6,7 @@ * for more details. * * Copyright (C) 1996, 97, 98, 2000, 03, 04, 06 Ralf Baechle (ralf@linux-mips.org) - * Copyright (C) 2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + * Copyright (C) 2006,2007 Thomas Bogendoerfer (tsbogend@alpha.franken.de) */ #include <linux/eisa.h> #include <linux/init.h> @@ -92,3 +92,34 @@ void __init plat_mem_setup(void) sni_display_setup(); } + +#if CONFIG_PCI + +#include <linux/pci.h> +#include <video/vga.h> +#include <video/cirrus.h> + +static void __devinit quirk_cirrus_ram_size(struct pci_dev *dev) +{ + u16 cmd; + + /* + * firmware doesn't set the ram size correct, so we + * need to do it here, otherwise we get screen corruption + * on older Cirrus chips + */ + pci_read_config_word (dev, PCI_COMMAND, &cmd); + if ((cmd & (PCI_COMMAND_IO|PCI_COMMAND_MEMORY)) + == (PCI_COMMAND_IO|PCI_COMMAND_MEMORY)) { + vga_wseq (NULL, CL_SEQR6, 0x12); /* unlock all extension registers */ + vga_wseq (NULL, CL_SEQRF, 0x18); + } +} + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5434_8, + quirk_cirrus_ram_size); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5436, + quirk_cirrus_ram_size); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446, + quirk_cirrus_ram_size); +#endif diff --git a/arch/powerpc/boot/crt0.S b/arch/powerpc/boot/crt0.S index 5a4215c4b014..f1c4dfc635be 100644 --- a/arch/powerpc/boot/crt0.S +++ b/arch/powerpc/boot/crt0.S @@ -13,6 +13,7 @@ .text /* a procedure descriptor used when booting this as a COFF file */ + .globl _zimage_start_opd _zimage_start_opd: .long _zimage_start, 0, 0, 0 diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c index d501c23e5159..d454f61c9c7c 100644 --- a/arch/powerpc/kernel/of_platform.c +++ b/arch/powerpc/kernel/of_platform.c @@ -433,7 +433,7 @@ static int __devinit of_pci_phb_probe(struct of_device *dev, * Note also that we don't do ISA, this will also be fixed with a * more massive rework. */ - pci_setup_phb_io(phb, 0); + pci_setup_phb_io(phb, pci_io_base == 0); /* Init pci_dn data structures */ pci_devs_phb_init_dynamic(phb); diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.c b/arch/powerpc/platforms/cell/cbe_cpufreq.c index f9ac3fe3be97..ac445998d831 100644 --- a/arch/powerpc/platforms/cell/cbe_cpufreq.c +++ b/arch/powerpc/platforms/cell/cbe_cpufreq.c @@ -67,6 +67,7 @@ static u64 MIC_Slow_Next_Timer_table[] = { 0x00003FC000000000ull, }; +static unsigned int pmi_frequency_limit = 0; /* * hardware specific functions */ @@ -164,7 +165,6 @@ static int set_pmode(int cpu, unsigned int slow_mode) { static void cbe_cpufreq_handle_pmi(struct of_device *dev, pmi_message_t pmi_msg) { - struct cpufreq_policy policy; u8 cpu; u8 cbe_pmode_new; @@ -173,15 +173,27 @@ static void cbe_cpufreq_handle_pmi(struct of_device *dev, pmi_message_t pmi_msg) cpu = cbe_node_to_cpu(pmi_msg.data1); cbe_pmode_new = pmi_msg.data2; - cpufreq_get_policy(&policy, cpu); + pmi_frequency_limit = cbe_freqs[cbe_pmode_new].frequency; - policy.max = min(policy.max, cbe_freqs[cbe_pmode_new].frequency); - policy.min = min(policy.min, policy.max); + pr_debug("cbe_handle_pmi: max freq=%d\n", pmi_frequency_limit); +} + +static int pmi_notifier(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct cpufreq_policy *policy = data; - pr_debug("cbe_handle_pmi: new policy.min=%d policy.max=%d\n", policy.min, policy.max); - cpufreq_set_policy(&policy); + if (event != CPUFREQ_INCOMPATIBLE) + return 0; + + cpufreq_verify_within_limits(policy, 0, pmi_frequency_limit); + return 0; } +static struct notifier_block pmi_notifier_block = { + .notifier_call = pmi_notifier, +}; + static struct pmi_handler cbe_pmi_handler = { .type = PMI_TYPE_FREQ_CHANGE, .handle_pmi_message = cbe_cpufreq_handle_pmi, @@ -238,12 +250,21 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy) cpufreq_frequency_table_get_attr(cbe_freqs, policy->cpu); + if (pmi_dev) { + /* frequency might get limited later, initialize limit with max_freq */ + pmi_frequency_limit = max_freq; + cpufreq_register_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER); + } + /* this ensures that policy->cpuinfo_min and policy->cpuinfo_max are set correctly */ return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs); } static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy) { + if (pmi_dev) + cpufreq_unregister_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER); + cpufreq_frequency_table_put_attr(policy->cpu); return 0; } diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index 8654749e317b..7c51cb54bca1 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c @@ -39,7 +39,7 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang) if (spu_init_csa(&ctx->csa)) goto out_free; spin_lock_init(&ctx->mmio_lock); - spin_lock_init(&ctx->mapping_lock); + mutex_init(&ctx->mapping_lock); kref_init(&ctx->kref); mutex_init(&ctx->state_mutex); mutex_init(&ctx->run_mutex); @@ -103,6 +103,7 @@ void spu_forget(struct spu_context *ctx) void spu_unmap_mappings(struct spu_context *ctx) { + mutex_lock(&ctx->mapping_lock); if (ctx->local_store) unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1); if (ctx->mfc) @@ -117,6 +118,7 @@ void spu_unmap_mappings(struct spu_context *ctx) unmap_mapping_range(ctx->mss, 0, 0x1000, 1); if (ctx->psmap) unmap_mapping_range(ctx->psmap, 0, 0x20000, 1); + mutex_unlock(&ctx->mapping_lock); } /** diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 45614c73c784..b1e7e2f8a2e9 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -45,11 +45,11 @@ spufs_mem_open(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); file->private_data = ctx; if (!i->i_openers++) ctx->local_store = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } @@ -59,10 +59,10 @@ spufs_mem_release(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); if (!--i->i_openers) ctx->local_store = NULL; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } @@ -217,6 +217,7 @@ unsigned long spufs_get_unmapped_area(struct file *file, unsigned long addr, static const struct file_operations spufs_mem_fops = { .open = spufs_mem_open, + .release = spufs_mem_release, .read = spufs_mem_read, .write = spufs_mem_write, .llseek = generic_file_llseek, @@ -309,11 +310,11 @@ static int spufs_cntl_open(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); file->private_data = ctx; if (!i->i_openers++) ctx->cntl = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return simple_attr_open(inode, file, spufs_cntl_get, spufs_cntl_set, "0x%08lx"); } @@ -326,10 +327,10 @@ spufs_cntl_release(struct inode *inode, struct file *file) simple_attr_close(inode, file); - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); if (!--i->i_openers) ctx->cntl = NULL; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } @@ -812,11 +813,11 @@ static int spufs_signal1_open(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); file->private_data = ctx; if (!i->i_openers++) ctx->signal1 = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return nonseekable_open(inode, file); } @@ -826,10 +827,10 @@ spufs_signal1_release(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); if (!--i->i_openers) ctx->signal1 = NULL; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } @@ -936,11 +937,11 @@ static int spufs_signal2_open(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); file->private_data = ctx; if (!i->i_openers++) ctx->signal2 = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return nonseekable_open(inode, file); } @@ -950,10 +951,10 @@ spufs_signal2_release(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); if (!--i->i_openers) ctx->signal2 = NULL; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } @@ -1154,10 +1155,10 @@ static int spufs_mss_open(struct inode *inode, struct file *file) file->private_data = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); if (!i->i_openers++) ctx->mss = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return nonseekable_open(inode, file); } @@ -1167,10 +1168,10 @@ spufs_mss_release(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); if (!--i->i_openers) ctx->mss = NULL; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } @@ -1211,11 +1212,11 @@ static int spufs_psmap_open(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); file->private_data = i->i_ctx; if (!i->i_openers++) ctx->psmap = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return nonseekable_open(inode, file); } @@ -1225,10 +1226,10 @@ spufs_psmap_release(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); if (!--i->i_openers) ctx->psmap = NULL; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } @@ -1281,11 +1282,11 @@ static int spufs_mfc_open(struct inode *inode, struct file *file) if (atomic_read(&inode->i_count) != 1) return -EBUSY; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); file->private_data = ctx; if (!i->i_openers++) ctx->mfc = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return nonseekable_open(inode, file); } @@ -1295,10 +1296,10 @@ spufs_mfc_release(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); if (!--i->i_openers) ctx->mfc = NULL; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 7150730e2ff1..9807206e0219 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -177,7 +177,7 @@ static int spufs_rmdir(struct inode *parent, struct dentry *dir) static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files, int mode, struct spu_context *ctx) { - struct dentry *dentry; + struct dentry *dentry, *tmp; int ret; while (files->name && files->name[0]) { @@ -193,7 +193,20 @@ static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files, } return 0; out: - spufs_prune_dir(dir); + /* + * remove all children from dir. dir->inode is not set so don't + * just simply use spufs_prune_dir() and panic afterwards :) + * dput() looks like it will do the right thing: + * - dec parent's ref counter + * - remove child from parent's child list + * - free child's inode if possible + * - free child + */ + list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) { + dput(dentry); + } + + shrink_dcache_parent(dir); return ret; } @@ -274,6 +287,7 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags, goto out; out_free_ctx: + spu_forget(ctx); put_spu_context(ctx); out_iput: iput(inode); @@ -349,37 +363,6 @@ out: return ret; } -static int spufs_rmgang(struct inode *root, struct dentry *dir) -{ - /* FIXME: this fails if the dir is not empty, - which causes a leak of gangs. */ - return simple_rmdir(root, dir); -} - -static int spufs_gang_close(struct inode *inode, struct file *file) -{ - struct inode *parent; - struct dentry *dir; - int ret; - - dir = file->f_path.dentry; - parent = dir->d_parent->d_inode; - - ret = spufs_rmgang(parent, dir); - WARN_ON(ret); - - return dcache_dir_close(inode, file); -} - -const struct file_operations spufs_gang_fops = { - .open = dcache_dir_open, - .release = spufs_gang_close, - .llseek = dcache_dir_lseek, - .read = generic_read_dir, - .readdir = dcache_readdir, - .fsync = simple_sync_file, -}; - static int spufs_mkgang(struct inode *dir, struct dentry *dentry, int mode) { @@ -407,7 +390,6 @@ spufs_mkgang(struct inode *dir, struct dentry *dentry, int mode) inode->i_fop = &simple_dir_operations; d_instantiate(dentry, inode); - dget(dentry); dir->i_nlink++; dentry->d_inode->i_nlink++; return ret; @@ -437,7 +419,7 @@ static int spufs_gang_open(struct dentry *dentry, struct vfsmount *mnt) goto out; } - filp->f_op = &spufs_gang_fops; + filp->f_op = &simple_dir_operations; fd_install(ret, filp); out: return ret; @@ -458,8 +440,10 @@ static int spufs_create_gang(struct inode *inode, * in error path of *_open(). */ ret = spufs_gang_open(dget(dentry), mntget(mnt)); - if (ret < 0) - WARN_ON(spufs_rmgang(inode, dentry)); + if (ret < 0) { + int err = simple_rmdir(inode, dentry); + WARN_ON(err); + } out: mutex_unlock(&inode->i_mutex); @@ -600,6 +584,10 @@ spufs_create_root(struct super_block *sb, void *data) struct inode *inode; int ret; + ret = -ENODEV; + if (!spu_management_ops) + goto out; + ret = -ENOMEM; inode = spufs_new_inode(sb, S_IFDIR | 0775); if (!inode) diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index b6ecb30e7d58..3b831e07f1ed 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -93,43 +93,6 @@ void spu_stop_tick(struct spu_context *ctx) } } -void spu_sched_tick(struct work_struct *work) -{ - struct spu_context *ctx = - container_of(work, struct spu_context, sched_work.work); - struct spu *spu; - int preempted = 0; - - /* - * If this context is being stopped avoid rescheduling from the - * scheduler tick because we would block on the state_mutex. - * The caller will yield the spu later on anyway. - */ - if (test_bit(SPU_SCHED_EXITING, &ctx->sched_flags)) - return; - - mutex_lock(&ctx->state_mutex); - spu = ctx->spu; - if (spu) { - int best = sched_find_first_bit(spu_prio->bitmap); - if (best <= ctx->prio) { - spu_deactivate(ctx); - preempted = 1; - } - } - mutex_unlock(&ctx->state_mutex); - - if (preempted) { - /* - * We need to break out of the wait loop in spu_run manually - * to ensure this context gets put on the runqueue again - * ASAP. - */ - wake_up(&ctx->stop_wq); - } else - spu_start_tick(ctx); -} - /** * spu_add_to_active_list - add spu to active list * @spu: spu to add to the active list @@ -273,34 +236,6 @@ static void spu_prio_wait(struct spu_context *ctx) remove_wait_queue(&ctx->stop_wq, &wait); } -/** - * spu_reschedule - try to find a runnable context for a spu - * @spu: spu available - * - * This function is called whenever a spu becomes idle. It looks for the - * most suitable runnable spu context and schedules it for execution. - */ -static void spu_reschedule(struct spu *spu) -{ - int best; - - spu_free(spu); - - spin_lock(&spu_prio->runq_lock); - best = sched_find_first_bit(spu_prio->bitmap); - if (best < MAX_PRIO) { - struct list_head *rq = &spu_prio->runq[best]; - struct spu_context *ctx; - - BUG_ON(list_empty(rq)); - - ctx = list_entry(rq->next, struct spu_context, rq); - __spu_del_from_rq(ctx); - wake_up(&ctx->stop_wq); - } - spin_unlock(&spu_prio->runq_lock); -} - static struct spu *spu_get_idle(struct spu_context *ctx) { struct spu *spu = NULL; @@ -429,6 +364,51 @@ int spu_activate(struct spu_context *ctx, unsigned long flags) } /** + * grab_runnable_context - try to find a runnable context + * + * Remove the highest priority context on the runqueue and return it + * to the caller. Returns %NULL if no runnable context was found. + */ +static struct spu_context *grab_runnable_context(int prio) +{ + struct spu_context *ctx = NULL; + int best; + + spin_lock(&spu_prio->runq_lock); + best = sched_find_first_bit(spu_prio->bitmap); + if (best < prio) { + struct list_head *rq = &spu_prio->runq[best]; + + BUG_ON(list_empty(rq)); + + ctx = list_entry(rq->next, struct spu_context, rq); + __spu_del_from_rq(ctx); + } + spin_unlock(&spu_prio->runq_lock); + + return ctx; +} + +static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio) +{ + struct spu *spu = ctx->spu; + struct spu_context *new = NULL; + + if (spu) { + new = grab_runnable_context(max_prio); + if (new || force) { + spu_unbind_context(spu, ctx); + spu_free(spu); + if (new) + wake_up(&new->stop_wq); + } + + } + + return new != NULL; +} + +/** * spu_deactivate - unbind a context from it's physical spu * @ctx: spu context to unbind * @@ -437,12 +417,7 @@ int spu_activate(struct spu_context *ctx, unsigned long flags) */ void spu_deactivate(struct spu_context *ctx) { - struct spu *spu = ctx->spu; - - if (spu) { - spu_unbind_context(spu, ctx); - spu_reschedule(spu); - } + __spu_deactivate(ctx, 1, MAX_PRIO); } /** @@ -455,21 +430,43 @@ void spu_deactivate(struct spu_context *ctx) */ void spu_yield(struct spu_context *ctx) { - struct spu *spu; - - if (mutex_trylock(&ctx->state_mutex)) { - if ((spu = ctx->spu) != NULL) { - int best = sched_find_first_bit(spu_prio->bitmap); - if (best < MAX_PRIO) { - pr_debug("%s: yielding SPU %d NODE %d\n", - __FUNCTION__, spu->number, spu->node); - spu_deactivate(ctx); - } - } + if (!(ctx->flags & SPU_CREATE_NOSCHED)) { + mutex_lock(&ctx->state_mutex); + __spu_deactivate(ctx, 0, MAX_PRIO); mutex_unlock(&ctx->state_mutex); } } +void spu_sched_tick(struct work_struct *work) +{ + struct spu_context *ctx = + container_of(work, struct spu_context, sched_work.work); + int preempted; + + /* + * If this context is being stopped avoid rescheduling from the + * scheduler tick because we would block on the state_mutex. + * The caller will yield the spu later on anyway. + */ + if (test_bit(SPU_SCHED_EXITING, &ctx->sched_flags)) + return; + + mutex_lock(&ctx->state_mutex); + preempted = __spu_deactivate(ctx, 0, ctx->prio + 1); + mutex_unlock(&ctx->state_mutex); + + if (preempted) { + /* + * We need to break out of the wait loop in spu_run manually + * to ensure this context gets put on the runqueue again + * ASAP. + */ + wake_up(&ctx->stop_wq); + } else { + spu_start_tick(ctx); + } +} + int __init spu_sched_init(void) { int i; diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 0a947fd7de57..47617e8014a5 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -55,7 +55,7 @@ struct spu_context { struct address_space *signal2; /* 'signal2' area mappings. */ struct address_space *mss; /* 'mss' area mappings. */ struct address_space *psmap; /* 'psmap' area mappings. */ - spinlock_t mapping_lock; + struct mutex mapping_lock; u64 object_id; /* user space pointer for oprofile */ enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state; diff --git a/arch/powerpc/platforms/celleb/Makefile b/arch/powerpc/platforms/celleb/Makefile index f4f82520dc4f..5240046d8671 100644 --- a/arch/powerpc/platforms/celleb/Makefile +++ b/arch/powerpc/platforms/celleb/Makefile @@ -4,5 +4,5 @@ obj-y += interrupt.o iommu.o setup.o \ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_PPC_UDBG_BEAT) += udbg_beat.o -obj-$(CONFIG_HAS_TXX9_SERIAL) += scc_sio.o +obj-$(CONFIG_SERIAL_TXX9) += scc_sio.o obj-$(CONFIG_SPU_BASE) += spu_priv1.o diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c index 95fa6a7d15ee..f33b21b9f5d4 100644 --- a/arch/powerpc/platforms/pasemi/iommu.c +++ b/arch/powerpc/platforms/pasemi/iommu.c @@ -31,8 +31,6 @@ #define IOBMAP_PAGE_SIZE (1 << IOBMAP_PAGE_SHIFT) #define IOBMAP_PAGE_MASK (IOBMAP_PAGE_SIZE - 1) -#define IOBMAP_PAGE_FACTOR (PAGE_SHIFT - IOBMAP_PAGE_SHIFT) - #define IOB_BASE 0xe0000000 #define IOB_SIZE 0x3000 /* Configuration registers */ @@ -97,9 +95,6 @@ static void iobmap_build(struct iommu_table *tbl, long index, bus_addr = (tbl->it_offset + index) << PAGE_SHIFT; - npages <<= IOBMAP_PAGE_FACTOR; - index <<= IOBMAP_PAGE_FACTOR; - ip = ((u32 *)tbl->it_base) + index; while (npages--) { @@ -125,9 +120,6 @@ static void iobmap_free(struct iommu_table *tbl, long index, bus_addr = (tbl->it_offset + index) << PAGE_SHIFT; - npages <<= IOBMAP_PAGE_FACTOR; - index <<= IOBMAP_PAGE_FACTOR; - ip = ((u32 *)tbl->it_base) + index; while (npages--) { diff --git a/arch/ppc/syslib/qspan_pci.c b/arch/ppc/syslib/qspan_pci.c index 85053b2816a9..7a97c7440b30 100644 --- a/arch/ppc/syslib/qspan_pci.c +++ b/arch/ppc/syslib/qspan_pci.c @@ -365,13 +365,13 @@ int qspan_pcibios_find_class(unsigned int class_code, unsigned short index, } void __init -m8xx_pcibios_fixup(void)) +m8xx_pcibios_fixup(void) { /* Lots to do here, all board and configuration specific. */ } void __init -m8xx_setup_pci_ptrs(void)) +m8xx_setup_pci_ptrs(void) { set_config_access_method(qspan); diff --git a/arch/sh/boards/se/73180/setup.c b/arch/sh/boards/se/73180/setup.c index 911ce1cdbd7f..e143017c8975 100644 --- a/arch/sh/boards/se/73180/setup.c +++ b/arch/sh/boards/se/73180/setup.c @@ -38,8 +38,8 @@ static struct platform_device *se73180_devices[] __initdata = { static int __init se73180_devices_setup(void) { - return platform_add_devices(sh7343se_platform_devices, - ARRAY_SIZE(sh7343se_platform_devices)); + return platform_add_devices(se73180_devices, + ARRAY_SIZE(se73180_devices)); } __initcall(se73180_devices_setup); diff --git a/arch/sh/boards/superh/microdev/irq.c b/arch/sh/boards/superh/microdev/irq.c index cc1cb04fa618..4d335077a3ff 100644 --- a/arch/sh/boards/superh/microdev/irq.c +++ b/arch/sh/boards/superh/microdev/irq.c @@ -11,6 +11,7 @@ #include <linux/init.h> #include <linux/irq.h> +#include <linux/interrupt.h> #include <asm/system.h> #include <asm/io.h> #include <asm/microdev.h> diff --git a/arch/sh/cchips/voyagergx/irq.c b/arch/sh/cchips/voyagergx/irq.c index 70f12907647f..d70e5c8461b5 100644 --- a/arch/sh/cchips/voyagergx/irq.c +++ b/arch/sh/cchips/voyagergx/irq.c @@ -28,7 +28,7 @@ static void disable_voyagergx_irq(unsigned int irq) unsigned long val; unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE); - pr_debug("disable_voyagergx_irq(%d): mask=%x\n", irq, mask); + pr_debug("disable_voyagergx_irq(%d): mask=%lx\n", irq, mask); val = readl((void __iomem *)VOYAGER_INT_MASK); val &= ~mask; writel(val, (void __iomem *)VOYAGER_INT_MASK); @@ -39,7 +39,7 @@ static void enable_voyagergx_irq(unsigned int irq) unsigned long val; unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE); - pr_debug("disable_voyagergx_irq(%d): mask=%x\n", irq, mask); + pr_debug("disable_voyagergx_irq(%d): mask=%lx\n", irq, mask); val = readl((void __iomem *)VOYAGER_INT_MASK); val |= mask; writel(val, (void __iomem *)VOYAGER_INT_MASK); @@ -125,11 +125,12 @@ int voyagergx_irq_demux(int irq) i = 17; else printk("Unexpected IRQ irq = %d status = 0x%08lx\n", irq, val); - pr_debug("voyagergx_irq_demux %d \n", i); - if (i < VOYAGER_IRQ_NUM) { + pr_debug("voyagergx_irq_demux %ld \n", i); + if (i < VOYAGER_IRQ_NUM) { irq = VOYAGER_IRQ_BASE + i; - if (voyagergx_demux[i].func != 0) - irq = voyagergx_demux[i].func(irq, voyagergx_demux[i].dev); + if (voyagergx_demux[i].func != 0) + irq = voyagergx_demux[i].func(irq, + voyagergx_demux[i].dev); } } return irq; diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S index 659cc081e5e7..b0b59d4a33ca 100644 --- a/arch/sh/kernel/cpu/sh3/entry.S +++ b/arch/sh/kernel/cpu/sh3/entry.S @@ -320,7 +320,9 @@ skip_restore: .align 2 5: .long 0x00001000 ! DSP +#ifdef CONFIG_KGDB_NMI 6: .long in_nmi +#endif 7: .long 0x30000000 ! common exception handler diff --git a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c index fcb2c41bc34e..a33429463e96 100644 --- a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c +++ b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c @@ -111,7 +111,7 @@ static int shoc_clk_verify_rate(struct clk *clk, unsigned long rate) return 0; } -static int shoc_clk_set_rate(struct clk *clk, unsigned long rate) +static int shoc_clk_set_rate(struct clk *clk, unsigned long rate, int algo_id) { unsigned long frqcr3; unsigned int tmp; diff --git a/arch/sh/mm/ioremap.c b/arch/sh/mm/ioremap.c index be03d74e99cb..0c7b7e33abdc 100644 --- a/arch/sh/mm/ioremap.c +++ b/arch/sh/mm/ioremap.c @@ -22,6 +22,7 @@ #include <asm/addrspace.h> #include <asm/cacheflush.h> #include <asm/tlbflush.h> +#include <asm/mmu.h> /* * Remap an arbitrary physical address space into the kernel virtual diff --git a/arch/sh64/kernel/pci_sh5.c b/arch/sh64/kernel/pci_sh5.c index fb51660847c8..3334f99b5835 100644 --- a/arch/sh64/kernel/pci_sh5.c +++ b/arch/sh64/kernel/pci_sh5.c @@ -521,10 +521,10 @@ void __init pcibios_fixup_bus(struct pci_bus *bus) bus->resource[0]->start = PCIBIOS_MIN_IO; bus->resource[1]->start = PCIBIOS_MIN_MEM; #else - bus->resource[0]->end = 0 - bus->resource[1]->end = 0 - bus->resource[0]->start =0 - bus->resource[1]->start = 0; + bus->resource[0]->end = 0; + bus->resource[1]->end = 0; + bus->resource[0]->start =0; + bus->resource[1]->start = 0; #endif /* Turn off downstream PF memory address range by default */ bus->resource[2]->start = 1024*1024; diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index bd00f89eed1e..89a1b469b93d 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -396,6 +396,15 @@ config SCHED_SMT when dealing with UltraSPARC cpus at a cost of slightly increased overhead in some places. If unsure say N here. +config SCHED_MC + bool "Multi-core scheduler support" + depends on SMP + default y + help + Multi-core scheduler support improves the CPU scheduler's decision + making when dealing with multi-core CPU chips at a cost of slightly + increased overhead in some places. If unsure say N here. + source "kernel/Kconfig.preempt" config CMDLINE_BOOL diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index d8d19093d12f..f964bf28d21a 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.70 2002/02/09 19:49:30 davem Exp $ +# # Makefile for the linux kernel. # @@ -8,7 +8,7 @@ EXTRA_CFLAGS := -Werror extra-y := head.o init_task.o vmlinux.lds obj-y := process.o setup.o cpu.o idprom.o \ - traps.o auxio.o una_asm.o \ + traps.o auxio.o una_asm.o sysfs.o \ irq.o ptrace.o time.o sys_sparc.o signal.o \ unaligned.o central.o pci.o starfire.o semaphore.o \ power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \ diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index ed712e0b3372..7d1a11822a1e 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -2514,9 +2514,9 @@ sun4v_ncs_request: nop .size sun4v_ncs_request, .-sun4v_ncs_request - .globl sun4v_scv_send - .type sun4v_scv_send,#function -sun4v_scv_send: + .globl sun4v_svc_send + .type sun4v_svc_send,#function +sun4v_svc_send: save %sp, -192, %sp mov %i0, %o0 mov %i1, %o1 @@ -2526,11 +2526,11 @@ sun4v_scv_send: stx %o1, [%i3] ret restore - .size sun4v_scv_send, .-sun4v_scv_send + .size sun4v_svc_send, .-sun4v_svc_send - .globl sun4v_scv_recv - .type sun4v_scv_recv,#function -sun4v_scv_recv: + .globl sun4v_svc_recv + .type sun4v_svc_recv,#function +sun4v_svc_recv: save %sp, -192, %sp mov %i0, %o0 mov %i1, %o1 @@ -2540,33 +2540,55 @@ sun4v_scv_recv: stx %o1, [%i3] ret restore - .size sun4v_scv_recv, .-sun4v_scv_recv + .size sun4v_svc_recv, .-sun4v_svc_recv - .globl sun4v_scv_getstatus - .type sun4v_scv_getstatus,#function -sun4v_scv_getstatus: + .globl sun4v_svc_getstatus + .type sun4v_svc_getstatus,#function +sun4v_svc_getstatus: mov HV_FAST_SVC_GETSTATUS, %o5 mov %o1, %o4 ta HV_FAST_TRAP stx %o1, [%o4] retl nop - .size sun4v_scv_getstatus, .-sun4v_scv_getstatus + .size sun4v_svc_getstatus, .-sun4v_svc_getstatus - .globl sun4v_scv_setstatus - .type sun4v_scv_setstatus,#function -sun4v_scv_setstatus: + .globl sun4v_svc_setstatus + .type sun4v_svc_setstatus,#function +sun4v_svc_setstatus: mov HV_FAST_SVC_SETSTATUS, %o5 ta HV_FAST_TRAP retl nop - .size sun4v_scv_setstatus, .-sun4v_scv_setstatus + .size sun4v_svc_setstatus, .-sun4v_svc_setstatus - .globl sun4v_scv_clrstatus - .type sun4v_scv_clrstatus,#function -sun4v_scv_clrstatus: + .globl sun4v_svc_clrstatus + .type sun4v_svc_clrstatus,#function +sun4v_svc_clrstatus: mov HV_FAST_SVC_CLRSTATUS, %o5 ta HV_FAST_TRAP retl nop - .size sun4v_scv_clrstatus, .-sun4v_scv_clrstatus + .size sun4v_svc_clrstatus, .-sun4v_svc_clrstatus + + .globl sun4v_mmustat_conf + .type sun4v_mmustat_conf,#function +sun4v_mmustat_conf: + mov %o1, %o4 + mov HV_FAST_MMUSTAT_CONF, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_mmustat_conf, .-sun4v_mmustat_conf + + .globl sun4v_mmustat_info + .type sun4v_mmustat_info,#function +sun4v_mmustat_info: + mov %o0, %o4 + mov HV_FAST_MMUSTAT_INFO, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_mmustat_info, .-sun4v_mmustat_info diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c index 9246c2cf9574..f0e16045fb16 100644 --- a/arch/sparc64/kernel/mdesc.c +++ b/arch/sparc64/kernel/mdesc.c @@ -473,6 +473,53 @@ static void __init set_core_ids(void) } } +static void __init mark_proc_ids(struct mdesc_node *mp, int proc_id) +{ + int i; + + for (i = 0; i < mp->num_arcs; i++) { + struct mdesc_node *t = mp->arcs[i].arc; + const u64 *id; + + if (strcmp(mp->arcs[i].name, "back")) + continue; + + if (strcmp(t->name, "cpu")) + continue; + + id = md_get_property(t, "id", NULL); + if (*id < NR_CPUS) + cpu_data(*id).proc_id = proc_id; + } +} + +static void __init __set_proc_ids(const char *exec_unit_name) +{ + struct mdesc_node *mp; + int idx; + + idx = 0; + md_for_each_node_by_name(mp, exec_unit_name) { + const char *type; + int len; + + type = md_get_property(mp, "type", &len); + if (!find_in_proplist(type, "int", len) && + !find_in_proplist(type, "integer", len)) + continue; + + mark_proc_ids(mp, idx); + + idx++; + } +} + +static void __init set_proc_ids(void) +{ + __set_proc_ids("exec_unit"); + __set_proc_ids("exec-unit"); +} + static void __init get_one_mondo_bits(const u64 *p, unsigned int *mask, unsigned char def) { u64 val; @@ -574,9 +621,15 @@ static void __init mdesc_fill_in_cpu_data(void) #endif c->core_id = 0; + c->proc_id = -1; } +#ifdef CONFIG_SMP + sparc64_multi_core = 1; +#endif + set_core_ids(); + set_proc_ids(); smp_fill_in_sib_core_maps(); } diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 16cc46a71872..6676b93219dc 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -343,6 +343,15 @@ static int of_bus_simba_match(struct device_node *np) if (model && !strcmp(model, "SUNW,simba")) return 1; + + /* Treat PCI busses lacking ranges property just like + * simba. + */ + if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) { + if (!of_find_property(np, "ranges", NULL)) + return 1; + } + return 0; } @@ -549,8 +558,6 @@ static int __init build_one_resource(struct device_node *parent, static int __init use_1to1_mapping(struct device_node *pp) { - const char *model; - /* If this is on the PMU bus, don't try to translate it even * if a ranges property exists. */ @@ -567,9 +574,11 @@ static int __init use_1to1_mapping(struct device_node *pp) 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")) + /* Similarly for all PCI bridges, if we get this far + * it lacks a ranges property, and this will include + * cases like Simba. + */ + if (!strcmp(pp->type, "pci") || !strcmp(pp->type, "pciex")) return 0; return 1; diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index 38a32bc95d22..81f4a5ea05f7 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -522,6 +522,89 @@ static void pci_resource_adjust(struct resource *res, res->end += root->start; } +/* For PCI bus devices which lack a 'ranges' property we interrogate + * the config space values to set the resources, just like the generic + * Linux PCI probing code does. + */ +static void __devinit pci_cfg_fake_ranges(struct pci_dev *dev, + struct pci_bus *bus, + struct pci_pbm_info *pbm) +{ + struct resource *res; + u8 io_base_lo, io_limit_lo; + u16 mem_base_lo, mem_limit_lo; + unsigned long base, limit; + + pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo); + pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo); + base = (io_base_lo & PCI_IO_RANGE_MASK) << 8; + limit = (io_limit_lo & PCI_IO_RANGE_MASK) << 8; + + if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) { + u16 io_base_hi, io_limit_hi; + + pci_read_config_word(dev, PCI_IO_BASE_UPPER16, &io_base_hi); + pci_read_config_word(dev, PCI_IO_LIMIT_UPPER16, &io_limit_hi); + base |= (io_base_hi << 16); + limit |= (io_limit_hi << 16); + } + + res = bus->resource[0]; + if (base <= limit) { + res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO; + if (!res->start) + res->start = base; + if (!res->end) + res->end = limit + 0xfff; + pci_resource_adjust(res, &pbm->io_space); + } + + pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo); + pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo); + base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16; + limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16; + + res = bus->resource[1]; + if (base <= limit) { + res->flags = ((mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | + IORESOURCE_MEM); + res->start = base; + res->end = limit + 0xfffff; + pci_resource_adjust(res, &pbm->mem_space); + } + + pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo); + pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo); + base = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16; + limit = (mem_limit_lo & PCI_PREF_RANGE_MASK) << 16; + + if ((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) { + u32 mem_base_hi, mem_limit_hi; + + pci_read_config_dword(dev, PCI_PREF_BASE_UPPER32, &mem_base_hi); + pci_read_config_dword(dev, PCI_PREF_LIMIT_UPPER32, &mem_limit_hi); + + /* + * Some bridges set the base > limit by default, and some + * (broken) BIOSes do not initialize them. If we find + * this, just assume they are not being used. + */ + if (mem_base_hi <= mem_limit_hi) { + base |= ((long) mem_base_hi) << 32; + limit |= ((long) mem_limit_hi) << 32; + } + } + + res = bus->resource[2]; + if (base <= limit) { + res->flags = ((mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | + IORESOURCE_MEM | IORESOURCE_PREFETCH); + res->start = base; + res->end = limit + 0xfffff; + pci_resource_adjust(res, &pbm->mem_space); + } +} + /* Cook up fake bus resources for SUNW,simba PCI bridges which lack * a proper 'ranges' property. */ @@ -581,13 +664,8 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, simba = 0; if (ranges == NULL) { const char *model = of_get_property(node, "model", NULL); - if (model && !strcmp(model, "SUNW,simba")) { + if (model && !strcmp(model, "SUNW,simba")) simba = 1; - } else { - printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n", - node->full_name); - return; - } } bus = pci_add_new_bus(dev->bus, dev, busrange[0]); @@ -611,7 +689,10 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, } if (simba) { apb_fake_ranges(dev, bus, pbm); - goto simba_cont; + goto after_ranges; + } else if (ranges == NULL) { + pci_cfg_fake_ranges(dev, bus, pbm); + goto after_ranges; } i = 1; for (; len >= 32; len -= 32, ranges += 8) { @@ -650,7 +731,7 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, */ pci_resource_adjust(res, root); } -simba_cont: +after_ranges: sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), bus->number); if (ofpci_verbose) diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 323d6c278518..22e1be5c7489 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -636,13 +636,18 @@ static void apb_init(struct pci_bus *sabre_bus) static void sabre_scan_bus(struct pci_pbm_info *pbm) { static int once; - struct pci_bus *pbus; /* The APB bridge speaks to the Sabre host PCI bridge * at 66Mhz, but the front side of APB runs at 33Mhz * for both segments. + * + * Hummingbird systems do not use APB, so they run + * at 66MHZ. */ - pbm->is_66mhz_capable = 0; + if (hummingbird_p) + pbm->is_66mhz_capable = 1; + else + pbm->is_66mhz_capable = 0; /* This driver has not been verified to handle * multiple SABREs yet, so trap this. @@ -656,13 +661,13 @@ static void sabre_scan_bus(struct pci_pbm_info *pbm) } once++; - pbus = pci_scan_one_pbm(pbm); - if (!pbus) + pbm->pci_bus = pci_scan_one_pbm(pbm); + if (!pbm->pci_bus) return; - sabre_root_bus = pbus; + sabre_root_bus = pbm->pci_bus; - apb_init(pbus); + apb_init(pbm->pci_bus); sabre_register_error_handlers(pbm); } diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index dad4b3ba705f..61036b346664 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -933,29 +933,29 @@ static void __init fire_irq_trans_init(struct device_node *dp) * This should conform to both Sunfire/Wildfire server and Fusion * desktop designs. */ -#define SYSIO_IMAP_SLOT0 0x2c04UL -#define SYSIO_IMAP_SLOT1 0x2c0cUL -#define SYSIO_IMAP_SLOT2 0x2c14UL -#define SYSIO_IMAP_SLOT3 0x2c1cUL -#define SYSIO_IMAP_SCSI 0x3004UL -#define SYSIO_IMAP_ETH 0x300cUL -#define SYSIO_IMAP_BPP 0x3014UL -#define SYSIO_IMAP_AUDIO 0x301cUL -#define SYSIO_IMAP_PFAIL 0x3024UL -#define SYSIO_IMAP_KMS 0x302cUL -#define SYSIO_IMAP_FLPY 0x3034UL -#define SYSIO_IMAP_SHW 0x303cUL -#define SYSIO_IMAP_KBD 0x3044UL -#define SYSIO_IMAP_MS 0x304cUL -#define SYSIO_IMAP_SER 0x3054UL -#define SYSIO_IMAP_TIM0 0x3064UL -#define SYSIO_IMAP_TIM1 0x306cUL -#define SYSIO_IMAP_UE 0x3074UL -#define SYSIO_IMAP_CE 0x307cUL -#define SYSIO_IMAP_SBERR 0x3084UL -#define SYSIO_IMAP_PMGMT 0x308cUL -#define SYSIO_IMAP_GFX 0x3094UL -#define SYSIO_IMAP_EUPA 0x309cUL +#define SYSIO_IMAP_SLOT0 0x2c00UL +#define SYSIO_IMAP_SLOT1 0x2c08UL +#define SYSIO_IMAP_SLOT2 0x2c10UL +#define SYSIO_IMAP_SLOT3 0x2c18UL +#define SYSIO_IMAP_SCSI 0x3000UL +#define SYSIO_IMAP_ETH 0x3008UL +#define SYSIO_IMAP_BPP 0x3010UL +#define SYSIO_IMAP_AUDIO 0x3018UL +#define SYSIO_IMAP_PFAIL 0x3020UL +#define SYSIO_IMAP_KMS 0x3028UL +#define SYSIO_IMAP_FLPY 0x3030UL +#define SYSIO_IMAP_SHW 0x3038UL +#define SYSIO_IMAP_KBD 0x3040UL +#define SYSIO_IMAP_MS 0x3048UL +#define SYSIO_IMAP_SER 0x3050UL +#define SYSIO_IMAP_TIM0 0x3060UL +#define SYSIO_IMAP_TIM1 0x3068UL +#define SYSIO_IMAP_UE 0x3070UL +#define SYSIO_IMAP_CE 0x3078UL +#define SYSIO_IMAP_SBERR 0x3080UL +#define SYSIO_IMAP_PMGMT 0x3088UL +#define SYSIO_IMAP_GFX 0x3090UL +#define SYSIO_IMAP_EUPA 0x3098UL #define bogon ((unsigned long) -1) static unsigned long sysio_irq_offsets[] = { @@ -1006,10 +1006,10 @@ static unsigned long sysio_irq_offsets[] = { * Interrupt Clear register pointer, SYSIO specific version. */ #define SYSIO_ICLR_UNUSED0 0x3400UL -#define SYSIO_ICLR_SLOT0 0x340cUL -#define SYSIO_ICLR_SLOT1 0x344cUL -#define SYSIO_ICLR_SLOT2 0x348cUL -#define SYSIO_ICLR_SLOT3 0x34ccUL +#define SYSIO_ICLR_SLOT0 0x3408UL +#define SYSIO_ICLR_SLOT1 0x3448UL +#define SYSIO_ICLR_SLOT2 0x3488UL +#define SYSIO_ICLR_SLOT3 0x34c8UL static unsigned long sysio_imap_to_iclr(unsigned long imap) { unsigned long diff = SYSIO_ICLR_UNUSED0 - SYSIO_IMAP_SLOT0; @@ -1781,6 +1781,10 @@ static void __init of_fill_in_cpu_data(void) } cpu_data(cpuid).core_id = portid + 1; + cpu_data(cpuid).proc_id = portid; +#ifdef CONFIG_SMP + sparc64_multi_core = 1; +#endif } else { cpu_data(cpuid).dcache_size = of_getintprop_default(dp, "dcache-size", 16 * 1024); @@ -1799,6 +1803,7 @@ static void __init of_fill_in_cpu_data(void) of_getintprop_default(dp, "ecache-line-size", 64); cpu_data(cpuid).core_id = 0; + cpu_data(cpuid).proc_id = -1; } #ifdef CONFIG_SMP diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index 91f6e2a74ad5..a1fd9bcc0b87 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -629,29 +629,29 @@ void sbus_set_sbus64(struct sbus_dev *sdev, int bursts) * This should conform to both Sunfire/Wildfire server and Fusion * desktop designs. */ -#define SYSIO_IMAP_SLOT0 0x2c04UL -#define SYSIO_IMAP_SLOT1 0x2c0cUL -#define SYSIO_IMAP_SLOT2 0x2c14UL -#define SYSIO_IMAP_SLOT3 0x2c1cUL -#define SYSIO_IMAP_SCSI 0x3004UL -#define SYSIO_IMAP_ETH 0x300cUL -#define SYSIO_IMAP_BPP 0x3014UL -#define SYSIO_IMAP_AUDIO 0x301cUL -#define SYSIO_IMAP_PFAIL 0x3024UL -#define SYSIO_IMAP_KMS 0x302cUL -#define SYSIO_IMAP_FLPY 0x3034UL -#define SYSIO_IMAP_SHW 0x303cUL -#define SYSIO_IMAP_KBD 0x3044UL -#define SYSIO_IMAP_MS 0x304cUL -#define SYSIO_IMAP_SER 0x3054UL -#define SYSIO_IMAP_TIM0 0x3064UL -#define SYSIO_IMAP_TIM1 0x306cUL -#define SYSIO_IMAP_UE 0x3074UL -#define SYSIO_IMAP_CE 0x307cUL -#define SYSIO_IMAP_SBERR 0x3084UL -#define SYSIO_IMAP_PMGMT 0x308cUL -#define SYSIO_IMAP_GFX 0x3094UL -#define SYSIO_IMAP_EUPA 0x309cUL +#define SYSIO_IMAP_SLOT0 0x2c00UL +#define SYSIO_IMAP_SLOT1 0x2c08UL +#define SYSIO_IMAP_SLOT2 0x2c10UL +#define SYSIO_IMAP_SLOT3 0x2c18UL +#define SYSIO_IMAP_SCSI 0x3000UL +#define SYSIO_IMAP_ETH 0x3008UL +#define SYSIO_IMAP_BPP 0x3010UL +#define SYSIO_IMAP_AUDIO 0x3018UL +#define SYSIO_IMAP_PFAIL 0x3020UL +#define SYSIO_IMAP_KMS 0x3028UL +#define SYSIO_IMAP_FLPY 0x3030UL +#define SYSIO_IMAP_SHW 0x3038UL +#define SYSIO_IMAP_KBD 0x3040UL +#define SYSIO_IMAP_MS 0x3048UL +#define SYSIO_IMAP_SER 0x3050UL +#define SYSIO_IMAP_TIM0 0x3060UL +#define SYSIO_IMAP_TIM1 0x3068UL +#define SYSIO_IMAP_UE 0x3070UL +#define SYSIO_IMAP_CE 0x3078UL +#define SYSIO_IMAP_SBERR 0x3080UL +#define SYSIO_IMAP_PMGMT 0x3088UL +#define SYSIO_IMAP_GFX 0x3090UL +#define SYSIO_IMAP_EUPA 0x3098UL #define bogon ((unsigned long) -1) static unsigned long sysio_irq_offsets[] = { @@ -700,10 +700,10 @@ static unsigned long sysio_irq_offsets[] = { * Interrupt Clear register pointer, SYSIO specific version. */ #define SYSIO_ICLR_UNUSED0 0x3400UL -#define SYSIO_ICLR_SLOT0 0x340cUL -#define SYSIO_ICLR_SLOT1 0x344cUL -#define SYSIO_ICLR_SLOT2 0x348cUL -#define SYSIO_ICLR_SLOT3 0x34ccUL +#define SYSIO_ICLR_SLOT0 0x3408UL +#define SYSIO_ICLR_SLOT1 0x3448UL +#define SYSIO_ICLR_SLOT2 0x3488UL +#define SYSIO_ICLR_SLOT3 0x34c8UL static unsigned long sysio_imap_to_iclr(unsigned long imap) { unsigned long diff = SYSIO_ICLR_UNUSED0 - SYSIO_IMAP_SLOT0; diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index de9b4c13f1c7..7490cc670a53 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -513,22 +513,3 @@ void sun_do_break(void) int serial_console = -1; int stop_a_enabled = 1; - -static int __init topology_init(void) -{ - int i, err; - - err = -ENOMEM; - - for_each_possible_cpu(i) { - struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL); - if (p) { - register_cpu(p, i); - err = 0; - } - } - - return err; -} - -subsys_initcall(topology_init); diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index c550bba3490a..4dcd7d0b60f2 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -44,6 +44,8 @@ extern void calibrate_delay(void); +int sparc64_multi_core __read_mostly; + /* Please don't make this stuff initdata!!! --DaveM */ unsigned char boot_cpu_id; @@ -51,6 +53,8 @@ cpumask_t cpu_online_map __read_mostly = CPU_MASK_NONE; cpumask_t phys_cpu_present_map __read_mostly = CPU_MASK_NONE; cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = CPU_MASK_NONE }; +cpumask_t cpu_core_map[NR_CPUS] __read_mostly = + { [0 ... NR_CPUS-1] = CPU_MASK_NONE }; static cpumask_t smp_commenced_mask; static cpumask_t cpu_callout_map; @@ -1217,13 +1221,28 @@ void __devinit smp_fill_in_sib_core_maps(void) unsigned int j; if (cpu_data(i).core_id == 0) { - cpu_set(i, cpu_sibling_map[i]); + cpu_set(i, cpu_core_map[i]); continue; } for_each_possible_cpu(j) { if (cpu_data(i).core_id == cpu_data(j).core_id) + cpu_set(j, cpu_core_map[i]); + } + } + + for_each_possible_cpu(i) { + unsigned int j; + + if (cpu_data(i).proc_id == -1) { + cpu_set(i, cpu_sibling_map[i]); + continue; + } + + for_each_possible_cpu(j) { + if (cpu_data(i).proc_id == + cpu_data(j).proc_id) cpu_set(j, cpu_sibling_map[i]); } } diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index d00f51a5683f..6fa761612899 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -24,6 +24,7 @@ #include <linux/syscalls.h> #include <linux/percpu.h> #include <linux/init.h> +#include <linux/rwsem.h> #include <net/compat.h> #include <asm/oplib.h> @@ -58,7 +59,6 @@ #include <asm/ns87303.h> #include <asm/timer.h> #include <asm/cpudata.h> -#include <asm/rwsem.h> struct poll { int fd; diff --git a/arch/sparc64/kernel/sysfs.c b/arch/sparc64/kernel/sysfs.c new file mode 100644 index 000000000000..cdb1477af89f --- /dev/null +++ b/arch/sparc64/kernel/sysfs.c @@ -0,0 +1,297 @@ +/* sysfs.c: Toplogy sysfs support code for sparc64. + * + * Copyright (C) 2007 David S. Miller <davem@davemloft.net> + */ +#include <linux/sysdev.h> +#include <linux/cpu.h> +#include <linux/smp.h> +#include <linux/percpu.h> +#include <linux/init.h> + +#include <asm/hypervisor.h> +#include <asm/spitfire.h> + +static DEFINE_PER_CPU(struct hv_mmu_statistics, mmu_stats) __attribute__((aligned(64))); + +#define SHOW_MMUSTAT_ULONG(NAME) \ +static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ +{ \ + struct hv_mmu_statistics *p = &per_cpu(mmu_stats, dev->id); \ + return sprintf(buf, "%lu\n", p->NAME); \ +} \ +static SYSDEV_ATTR(NAME, 0444, show_##NAME, NULL) + +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_8k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_8k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_64k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_64k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_4mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_4mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_256mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_256mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_8k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_8k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_64k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_64k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_4mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_4mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_256mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_256mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_8k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_8k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_64k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_64k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_4mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_4mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_256mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_256mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_8k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_8k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_64k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_64k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_4mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_4mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_256mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_256mb_tte); + +static struct attribute *mmu_stat_attrs[] = { + &attr_immu_tsb_hits_ctx0_8k_tte.attr, + &attr_immu_tsb_ticks_ctx0_8k_tte.attr, + &attr_immu_tsb_hits_ctx0_64k_tte.attr, + &attr_immu_tsb_ticks_ctx0_64k_tte.attr, + &attr_immu_tsb_hits_ctx0_4mb_tte.attr, + &attr_immu_tsb_ticks_ctx0_4mb_tte.attr, + &attr_immu_tsb_hits_ctx0_256mb_tte.attr, + &attr_immu_tsb_ticks_ctx0_256mb_tte.attr, + &attr_immu_tsb_hits_ctxnon0_8k_tte.attr, + &attr_immu_tsb_ticks_ctxnon0_8k_tte.attr, + &attr_immu_tsb_hits_ctxnon0_64k_tte.attr, + &attr_immu_tsb_ticks_ctxnon0_64k_tte.attr, + &attr_immu_tsb_hits_ctxnon0_4mb_tte.attr, + &attr_immu_tsb_ticks_ctxnon0_4mb_tte.attr, + &attr_immu_tsb_hits_ctxnon0_256mb_tte.attr, + &attr_immu_tsb_ticks_ctxnon0_256mb_tte.attr, + &attr_dmmu_tsb_hits_ctx0_8k_tte.attr, + &attr_dmmu_tsb_ticks_ctx0_8k_tte.attr, + &attr_dmmu_tsb_hits_ctx0_64k_tte.attr, + &attr_dmmu_tsb_ticks_ctx0_64k_tte.attr, + &attr_dmmu_tsb_hits_ctx0_4mb_tte.attr, + &attr_dmmu_tsb_ticks_ctx0_4mb_tte.attr, + &attr_dmmu_tsb_hits_ctx0_256mb_tte.attr, + &attr_dmmu_tsb_ticks_ctx0_256mb_tte.attr, + &attr_dmmu_tsb_hits_ctxnon0_8k_tte.attr, + &attr_dmmu_tsb_ticks_ctxnon0_8k_tte.attr, + &attr_dmmu_tsb_hits_ctxnon0_64k_tte.attr, + &attr_dmmu_tsb_ticks_ctxnon0_64k_tte.attr, + &attr_dmmu_tsb_hits_ctxnon0_4mb_tte.attr, + &attr_dmmu_tsb_ticks_ctxnon0_4mb_tte.attr, + &attr_dmmu_tsb_hits_ctxnon0_256mb_tte.attr, + &attr_dmmu_tsb_ticks_ctxnon0_256mb_tte.attr, + NULL, +}; + +static struct attribute_group mmu_stat_group = { + .attrs = mmu_stat_attrs, + .name = "mmu_stats", +}; + +/* XXX convert to rusty's on_one_cpu */ +static unsigned long run_on_cpu(unsigned long cpu, + unsigned long (*func)(unsigned long), + unsigned long arg) +{ + cpumask_t old_affinity = current->cpus_allowed; + unsigned long ret; + + /* should return -EINVAL to userspace */ + if (set_cpus_allowed(current, cpumask_of_cpu(cpu))) + return 0; + + ret = func(arg); + + set_cpus_allowed(current, old_affinity); + + return ret; +} + +static unsigned long read_mmustat_enable(unsigned long junk) +{ + unsigned long ra = 0; + + sun4v_mmustat_info(&ra); + + return ra != 0; +} + +static unsigned long write_mmustat_enable(unsigned long val) +{ + unsigned long ra, orig_ra; + + if (val) + ra = __pa(&per_cpu(mmu_stats, smp_processor_id())); + else + ra = 0UL; + + return sun4v_mmustat_conf(ra, &orig_ra); +} + +static ssize_t show_mmustat_enable(struct sys_device *s, char *buf) +{ + unsigned long val = run_on_cpu(s->id, read_mmustat_enable, 0); + return sprintf(buf, "%lx\n", val); +} + +static ssize_t store_mmustat_enable(struct sys_device *s, const char *buf, size_t count) +{ + unsigned long val, err; + int ret = sscanf(buf, "%ld", &val); + + if (ret != 1) + return -EINVAL; + + err = run_on_cpu(s->id, write_mmustat_enable, val); + if (err) + return -EIO; + + return count; +} + +static SYSDEV_ATTR(mmustat_enable, 0644, show_mmustat_enable, store_mmustat_enable); + +static int mmu_stats_supported; + +static int register_mmu_stats(struct sys_device *s) +{ + if (!mmu_stats_supported) + return 0; + sysdev_create_file(s, &attr_mmustat_enable); + return sysfs_create_group(&s->kobj, &mmu_stat_group); +} + +#ifdef CONFIG_HOTPLUG_CPU +static void unregister_mmu_stats(struct sys_device *s) +{ + if (!mmu_stats_supported) + return; + sysfs_remove_group(&s->kobj, &mmu_stat_group); + sysdev_remove_file(s, &attr_mmustat_enable); +} +#endif + +#define SHOW_CPUDATA_ULONG_NAME(NAME, MEMBER) \ +static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ +{ \ + cpuinfo_sparc *c = &cpu_data(dev->id); \ + return sprintf(buf, "%lu\n", c->MEMBER); \ +} + +#define SHOW_CPUDATA_UINT_NAME(NAME, MEMBER) \ +static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ +{ \ + cpuinfo_sparc *c = &cpu_data(dev->id); \ + return sprintf(buf, "%u\n", c->MEMBER); \ +} + +SHOW_CPUDATA_ULONG_NAME(clock_tick, clock_tick); +SHOW_CPUDATA_ULONG_NAME(udelay_val, udelay_val); +SHOW_CPUDATA_UINT_NAME(l1_dcache_size, dcache_size); +SHOW_CPUDATA_UINT_NAME(l1_dcache_line_size, dcache_line_size); +SHOW_CPUDATA_UINT_NAME(l1_icache_size, icache_size); +SHOW_CPUDATA_UINT_NAME(l1_icache_line_size, icache_line_size); +SHOW_CPUDATA_UINT_NAME(l2_cache_size, ecache_size); +SHOW_CPUDATA_UINT_NAME(l2_cache_line_size, ecache_line_size); + +static struct sysdev_attribute cpu_core_attrs[] = { + _SYSDEV_ATTR(clock_tick, 0444, show_clock_tick, NULL), + _SYSDEV_ATTR(udelay_val, 0444, show_udelay_val, NULL), + _SYSDEV_ATTR(l1_dcache_size, 0444, show_l1_dcache_size, NULL), + _SYSDEV_ATTR(l1_dcache_line_size, 0444, show_l1_dcache_line_size, NULL), + _SYSDEV_ATTR(l1_icache_size, 0444, show_l1_icache_size, NULL), + _SYSDEV_ATTR(l1_icache_line_size, 0444, show_l1_icache_line_size, NULL), + _SYSDEV_ATTR(l2_cache_size, 0444, show_l2_cache_size, NULL), + _SYSDEV_ATTR(l2_cache_line_size, 0444, show_l2_cache_line_size, NULL), +}; + +static DEFINE_PER_CPU(struct cpu, cpu_devices); + +static void register_cpu_online(unsigned int cpu) +{ + struct cpu *c = &per_cpu(cpu_devices, cpu); + struct sys_device *s = &c->sysdev; + int i; + + for (i = 0; i < ARRAY_SIZE(cpu_core_attrs); i++) + sysdev_create_file(s, &cpu_core_attrs[i]); + + register_mmu_stats(s); +} + +#ifdef CONFIG_HOTPLUG_CPU +static void unregister_cpu_online(unsigned int cpu) +{ + struct cpu *c = &per_cpu(cpu_devices, cpu); + struct sys_device *s = &c->sysdev; + int i; + + unregister_mmu_stats(s); + for (i = 0; i < ARRAY_SIZE(cpu_core_attrs); i++) + sysdev_remove_file(s, &cpu_core_attrs[i]); +} +#endif + +static int __cpuinit sysfs_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned int)(long)hcpu; + + switch (action) { + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + register_cpu_online(cpu); + break; +#ifdef CONFIG_HOTPLUG_CPU + case CPU_DEAD: + case CPU_DEAD_FROZEN: + unregister_cpu_online(cpu); + break; +#endif + } + return NOTIFY_OK; +} + +static struct notifier_block __cpuinitdata sysfs_cpu_nb = { + .notifier_call = sysfs_cpu_notify, +}; + +static void __init check_mmu_stats(void) +{ + unsigned long dummy1, err; + + if (tlb_type != hypervisor) + return; + + err = sun4v_mmustat_info(&dummy1); + if (!err) + mmu_stats_supported = 1; +} + +static int __init topology_init(void) +{ + int cpu; + + check_mmu_stats(); + + register_cpu_notifier(&sysfs_cpu_nb); + + for_each_possible_cpu(cpu) { + struct cpu *c = &per_cpu(cpu_devices, cpu); + + register_cpu(c, cpu); + if (cpu_online(cpu)) + register_cpu_online(cpu); + } + + return 0; +} + +subsys_initcall(topology_init); diff --git a/arch/um/Kconfig b/arch/um/Kconfig index c504312219b4..e6ff30266542 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -278,6 +278,7 @@ config HIGHMEM config KERNEL_STACK_ORDER int "Kernel stack size order" default 1 if 64BIT + range 1 10 if 64BIT default 0 if !64BIT help This option determines the size of UML kernel stacks. They will diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index ced99106f798..4bd40bb43ec2 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -3,6 +3,7 @@ * Licensed under the GPL */ +#include "linux/kernel.h" #include "linux/sched.h" #include "linux/slab.h" #include "linux/list.h" diff --git a/arch/um/drivers/stderr_console.c b/arch/um/drivers/stderr_console.c index 911539293871..4739dd527b43 100644 --- a/arch/um/drivers/stderr_console.c +++ b/arch/um/drivers/stderr_console.c @@ -1,3 +1,4 @@ +#include <linux/kernel.h> #include <linux/init.h> #include <linux/console.h> diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 70509ddaac03..2e09f162c42f 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -20,6 +20,7 @@ #define MAJOR_NR UBD_MAJOR #define UBD_SHIFT 4 +#include "linux/kernel.h" #include "linux/module.h" #include "linux/blkdev.h" #include "linux/hdreg.h" diff --git a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c index 8b7f2cdedf94..c716b5a6db13 100644 --- a/arch/um/kernel/exitcode.c +++ b/arch/um/kernel/exitcode.c @@ -1,8 +1,9 @@ -/* +/* * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ +#include "linux/kernel.h" #include "linux/init.h" #include "linux/ctype.h" #include "linux/proc_fs.h" @@ -24,11 +25,14 @@ static int read_proc_exitcode(char *page, char **start, off_t off, val = uml_exitcode; len = sprintf(page, "%d\n", val); len -= off; - if(len <= off+count) *eof = 1; + if(len <= off+count) + *eof = 1; *start = page + off; - if(len > count) len = count; - if(len < 0) len = 0; - return(len); + if(len > count) + len = count; + if(len < 0) + len = 0; + return len; } static int write_proc_exitcode(struct file *file, const char __user *buffer, @@ -38,12 +42,14 @@ static int write_proc_exitcode(struct file *file, const char __user *buffer, int tmp; if(copy_from_user(buf, buffer, count)) - return(-EFAULT); + return -EFAULT; + tmp = simple_strtol(buf, &end, 0); if((*end != '\0') && !isspace(*end)) - return(-EINVAL); + return -EINVAL; + uml_exitcode = tmp; - return(count); + return count; } static int make_proc_exitcode(void) @@ -54,24 +60,13 @@ static int make_proc_exitcode(void) if(ent == NULL){ printk(KERN_WARNING "make_proc_exitcode : Failed to register " "/proc/exitcode\n"); - return(0); + return 0; } ent->read_proc = read_proc_exitcode; ent->write_proc = write_proc_exitcode; - - return(0); + + return 0; } __initcall(make_proc_exitcode); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index cb29fb96948d..aac1c0be54c6 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -465,13 +465,14 @@ static unsigned int die_nest_count; unsigned __kprobes long oops_begin(void) { - int cpu = smp_processor_id(); + int cpu; unsigned long flags; oops_enter(); /* racy, but better than risking deadlock. */ local_irq_save(flags); + cpu = smp_processor_id(); if (!spin_trylock(&die_lock)) { if (cpu == die_owner) /* nested oops. should stop eventually */; diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c index bfb62a13d7ee..635e58d443d7 100644 --- a/arch/x86_64/mm/fault.c +++ b/arch/x86_64/mm/fault.c @@ -476,6 +476,12 @@ bad_area: bad_area_nosemaphore: /* User mode accesses just cause a SIGSEGV */ if (error_code & PF_USER) { + + /* + * It's possible to have interrupts off here. + */ + local_irq_enable(); + if (is_prefetch(regs, address, error_code)) return; diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c index 1ad5111aec38..efb6e845114e 100644 --- a/arch/x86_64/mm/init.c +++ b/arch/x86_64/mm/init.c @@ -79,6 +79,8 @@ void show_mem(void) if (unlikely(i % MAX_ORDER_NR_PAGES == 0)) { touch_nmi_watchdog(); } + if (!pfn_valid(pgdat->node_start_pfn + i)) + continue; page = pfn_to_page(pgdat->node_start_pfn + i); total++; if (PageReserved(page)) diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c index 698079b3a336..d0323cd6a2ea 100644 --- a/arch/xtensa/kernel/asm-offsets.c +++ b/arch/xtensa/kernel/asm-offsets.c @@ -39,6 +39,7 @@ int main(void) DEFINE(PT_LEND, offsetof (struct pt_regs, lend)); DEFINE(PT_LCOUNT, offsetof (struct pt_regs, lcount)); DEFINE(PT_SAR, offsetof (struct pt_regs, sar)); + DEFINE(PT_ICOUNTLEVEL, offsetof (struct pt_regs, icountlevel)); DEFINE(PT_SYSCALL, offsetof (struct pt_regs, syscall)); DEFINE(PT_AREG, offsetof (struct pt_regs, areg[0])); DEFINE(PT_AREG0, offsetof (struct pt_regs, areg[0])); diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S index 9e271ba009bf..8dc7a2c26ff9 100644 --- a/arch/xtensa/kernel/entry.S +++ b/arch/xtensa/kernel/entry.S @@ -125,8 +125,9 @@ _user_exception: movi a2, 0 rsr a3, SAR - wsr a2, ICOUNTLEVEL + xsr a2, ICOUNTLEVEL s32i a3, a1, PT_SAR + s32i a2, a1, PT_ICOUNTLEVEL /* Rotate ws so that the current windowbase is at bit0. */ /* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */ @@ -276,8 +277,9 @@ _kernel_exception: movi a2, 0 rsr a3, SAR - wsr a2, ICOUNTLEVEL + xsr a2, ICOUNTLEVEL s32i a3, a1, PT_SAR + s32i a2, a1, PT_ICOUNTLEVEL /* Rotate ws so that the current windowbase is at bit0. */ /* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */ @@ -330,14 +332,16 @@ _kernel_exception: common_exception: - /* Save EXCVADDR, DEBUGCAUSE, and PC, and clear LCOUNT */ + /* Save some registers, disable loops and clear the syscall flag. */ rsr a2, DEBUGCAUSE rsr a3, EPC_1 s32i a2, a1, PT_DEBUGCAUSE s32i a3, a1, PT_PC + movi a2, -1 rsr a3, EXCVADDR + s32i a2, a1, PT_SYSCALL movi a2, 0 s32i a3, a1, PT_EXCVADDR xsr a2, LCOUNT @@ -450,27 +454,8 @@ common_exception_return: /* Restore the state of the task and return from the exception. */ - - /* If we are returning from a user exception, and the process - * to run next has PT_SINGLESTEP set, we want to setup - * ICOUNT and ICOUNTLEVEL to step one instruction. - * PT_SINGLESTEP is set by sys_ptrace (ptrace.c) - */ - 4: /* a2 holds GET_CURRENT(a2,a1) */ - l32i a3, a2, TI_TASK - l32i a3, a3, TASK_PTRACE - bbci.l a3, PT_SINGLESTEP_BIT, 1f # jump if single-step flag is not set - - movi a3, -2 # PT_SINGLESTEP flag is set, - movi a4, 1 # icountlevel of 1 means it won't - wsr a3, ICOUNT # start counting until after rfe - wsr a4, ICOUNTLEVEL # so setup icount & icountlevel. - isync - -1: - #if XCHAL_EXTRA_SA_SIZE /* For user exceptions, restore the extra state from the user's TCB. */ @@ -665,6 +650,13 @@ common_exception_exit: wsr a3, LEND wsr a2, LCOUNT + /* We control single stepping through the ICOUNTLEVEL register. */ + + l32i a2, a1, PT_ICOUNTLEVEL + movi a3, -2 + wsr a2, ICOUNTLEVEL + wsr a3, ICOUNT + /* Check if it was double exception. */ l32i a0, a1, PT_DEPC diff --git a/arch/xtensa/kernel/head.S b/arch/xtensa/kernel/head.S index ea89910efa44..67e69139520b 100644 --- a/arch/xtensa/kernel/head.S +++ b/arch/xtensa/kernel/head.S @@ -19,6 +19,8 @@ #include <asm/page.h> #include <asm/cacheasm.h> +#include <linux/linkage.h> + /* * This module contains the entry code for kernel images. It performs the * minimal setup needed to call the generic C routines. @@ -227,13 +229,14 @@ _startup: should_never_return: j should_never_return - /* Define some common data structures here. We define them - * here in this assembly file due to their unusual alignment - * requirements. - */ - .comm swapper_pg_dir,PAGE_SIZE,PAGE_SIZE - .comm empty_bad_page_table,PAGE_SIZE,PAGE_SIZE - .comm empty_bad_page,PAGE_SIZE,PAGE_SIZE - .comm empty_zero_page,PAGE_SIZE,PAGE_SIZE +/* + * BSS section + */ + +.section ".bss.page_aligned", "w" +ENTRY(swapper_pg_dir) + .fill PAGE_SIZE, 1, 0 +ENTRY(empty_zero_page) + .fill PAGE_SIZE, 1, 0 diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c index 45571ccb72d6..77deae5290f0 100644 --- a/arch/xtensa/kernel/pci.c +++ b/arch/xtensa/kernel/pci.c @@ -401,7 +401,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, * Also, think for a moment about likes of floppy.c that * include architecture specific parts. They may want to redefine ins/outs. * - * We do not use horroble macroses here because we want to + * We do not use horrible macros here because we want to * advance pointer by sizeof(size). */ void outsb(unsigned long addr, const void *src, unsigned long count) { diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c index 1ecf6716c327..2e8d398cf196 100644 --- a/arch/xtensa/kernel/setup.c +++ b/arch/xtensa/kernel/setup.c @@ -41,6 +41,7 @@ #include <asm/platform.h> #include <asm/page.h> #include <asm/setup.h> +#include <asm/param.h> #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) struct screen_info screen_info = { 0, 24, 0, 0, 0, 80, 0, 0, 0, 24, 1, 16}; diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c index 58107672a619..033aae0336d2 100644 --- a/arch/xtensa/kernel/signal.c +++ b/arch/xtensa/kernel/signal.c @@ -1,397 +1,239 @@ -// TODO coprocessor stuff /* - * linux/arch/xtensa/kernel/signal.c + * arch/xtensa/kernel/signal.c * - * Copyright (C) 1991, 1992 Linus Torvalds - * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson - * - * Joe Taylor <joe@tensilica.com> - * Chris Zankel <chris@zankel.net> + * Default platform functions. * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. * + * Copyright (C) 2005, 2006 Tensilica Inc. + * Copyright (C) 1991, 1992 Linus Torvalds + * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson * + * Chris Zankel <chris@zankel.net> + * Joe Taylor <joe@tensilica.com> */ -#include <asm/variant/core.h> -#include <asm/coprocessor.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/kernel.h> #include <linux/signal.h> #include <linux/errno.h> -#include <linux/wait.h> #include <linux/ptrace.h> -#include <linux/unistd.h> -#include <linux/stddef.h> #include <linux/personality.h> +#include <linux/freezer.h> + #include <asm/ucontext.h> #include <asm/uaccess.h> -#include <asm/pgtable.h> #include <asm/cacheflush.h> +#include <asm/coprocessor.h> +#include <asm/unistd.h> #define DEBUG_SIG 0 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, - struct rusage * ru); asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); extern struct task_struct *coproc_owners[]; +extern void release_all_cp (struct task_struct *); -/* - * Atomically swap in the new signal mask, and wait for a signal. +struct rt_sigframe +{ + struct siginfo info; + struct ucontext uc; + cp_state_t cpstate; + unsigned char retcode[6]; + unsigned int window[4]; +}; + +/* + * Flush register windows stored in pt_regs to stack. + * Returns 1 for errors. + * + * Note that windowbase, windowstart, and wmask are not updated! */ -int xtensa_sigsuspend(struct pt_regs *regs) +int +flush_window_regs_user(struct pt_regs *regs) { - old_sigset_t mask = (old_sigset_t) regs->areg[3]; - sigset_t saveset; + const unsigned long ws = regs->windowstart; + const unsigned long wb = regs->windowbase; + unsigned long sp = 0; + unsigned long wm; + int err = 1; + int base; - mask &= _BLOCKABLE; - spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; - siginitset(¤t->blocked, mask); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + /* Return if no other frames. */ - regs->areg[2] = -EINTR; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal(regs, &saveset)) - return -EINTR; - } -} + if (regs->wmask == 1) + return 0; -asmlinkage int -xtensa_rt_sigsuspend(struct pt_regs *regs) -{ - sigset_t *unewset = (sigset_t *) regs->areg[4]; - size_t sigsetsize = (size_t) regs->areg[3]; - sigset_t saveset, newset; - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; + /* Rotate windowmask and skip empty frames. */ - if (copy_from_user(&newset, unewset, sizeof(newset))) - return -EFAULT; - sigdelsetmask(&newset, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; - current->blocked = newset; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + wm = (ws >> wb) | (ws << (XCHAL_NUM_AREGS / 4 - wb)); + base = (XCHAL_NUM_AREGS / 4) - (regs->wmask >> 4); + + /* For call8 or call12 frames, we need the previous stack pointer. */ - regs->areg[2] = -EINTR; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal(regs, &saveset)) - return -EINTR; - } -} + if ((regs->wmask & 2) == 0) + if (__get_user(sp, (int*)(regs->areg[base * 4 + 1] - 12))) + goto errout; -asmlinkage int -xtensa_sigaction(int sig, const struct old_sigaction *act, - struct old_sigaction *oact) -{ - struct k_sigaction new_ka, old_ka; - int ret; + /* Spill frames to stack. */ - if (act) { - old_sigset_t mask; - if (!access_ok(VERIFY_READ, act, sizeof(*act)) || - __get_user(new_ka.sa.sa_handler, &act->sa_handler) || - __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) - return -EFAULT; - __get_user(new_ka.sa.sa_flags, &act->sa_flags); - __get_user(mask, &act->sa_mask); - siginitset(&new_ka.sa.sa_mask, mask); - } + while (base < XCHAL_NUM_AREGS / 4) { - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + int m = (wm >> base); + int inc = 0; - if (!ret && oact) { - if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || - __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) - return -EFAULT; - __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); - } + /* Save registers a4..a7 (call8) or a4...a11 (call12) */ - return ret; -} + if (m & 2) { /* call4 */ + inc = 1; -asmlinkage int -xtensa_sigaltstack(struct pt_regs *regs) -{ - const stack_t *uss = (stack_t *) regs->areg[4]; - stack_t *uoss = (stack_t *) regs->areg[3]; + } else if (m & 4) { /* call8 */ + if (copy_to_user((void*)(sp - 32), + ®s->areg[(base + 1) * 4], 16)) + goto errout; + inc = 2; - if (regs->depc > 64) - panic ("Double exception sys_sigreturn\n"); + } else if (m & 8) { /* call12 */ + if (copy_to_user((void*)(sp - 48), + ®s->areg[(base + 1) * 4], 32)) + goto errout; + inc = 3; + } + /* Save current frame a0..a3 under next SP */ - return do_sigaltstack(uss, uoss, regs->areg[1]); -} + sp = regs->areg[((base + inc) * 4 + 1) % XCHAL_NUM_AREGS]; + if (copy_to_user((void*)(sp - 16), ®s->areg[base * 4], 16)) + goto errout; + + /* Get current stack pointer for next loop iteration. */ + + sp = regs->areg[base * 4 + 1]; + base += inc; + } + + return 0; +errout: + return err; +} /* - * Do a signal return; undo the signal stack. + * Note: We don't copy double exception 'regs', we have to finish double exc. + * first before we return to signal handler! This dbl.exc.handler might cause + * another double exception, but I think we are fine as the situation is the + * same as if we had returned to the signal handerl and got an interrupt + * immediately... */ -struct sigframe -{ - struct sigcontext sc; - struct _cpstate cpstate; - unsigned long extramask[_NSIG_WORDS-1]; - unsigned char retcode[6]; - unsigned int reserved[4]; /* Reserved area for chaining */ - unsigned int window[4]; /* Window of 4 registers for initial context */ -}; - -struct rt_sigframe +static int +setup_sigcontext(struct sigcontext __user *sc, cp_state_t *cpstate, + struct pt_regs *regs, unsigned long mask) { - struct siginfo info; - struct ucontext uc; - struct _cpstate cpstate; - unsigned char retcode[6]; - unsigned int reserved[4]; /* Reserved area for chaining */ - unsigned int window[4]; /* Window of 4 registers for initial context */ -}; + int err = 0; -extern void release_all_cp (struct task_struct *); +#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) + COPY(pc); + COPY(ps); + COPY(lbeg); + COPY(lend); + COPY(lcount); + COPY(sar); +#undef COPY + err |= flush_window_regs_user(regs); + err |= __copy_to_user (sc->sc_a, regs->areg, 16 * 4); -// FIXME restore_cpextra -static inline int -restore_cpextra (struct _cpstate *buf) -{ -#if 0 - /* The signal handler may have used coprocessors in which - * case they are still enabled. We disable them to force a - * reloading of the original task's CP state by the lazy - * context-switching mechanisms of CP exception handling. - * Also, we essentially discard any coprocessor state that the - * signal handler created. */ + // err |= __copy_to_user (sc->sc_a, regs->areg, XCHAL_NUM_AREGS * 4) - struct task_struct *tsk = current; - release_all_cp(tsk); - return __copy_from_user(tsk->thread.cpextra, buf, XTENSA_CP_EXTRA_SIZE); +#if XCHAL_HAVE_CP +# error Coprocessors unsupported + err |= save_cpextra(cpstate); + err |= __put_user(err ? NULL : cpstate, &sc->sc_cpstate); #endif - return 0; -} - -/* Note: We don't copy double exception 'tregs', we have to finish double exc. first before we return to signal handler! This dbl.exc.handler might cause another double exception, but I think we are fine as the situation is the same as if we had returned to the signal handerl and got an interrupt immediately... - */ + /* non-iBCS2 extensions.. */ + err |= __put_user(mask, &sc->oldmask); + return err; +} static int -restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) +restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { - struct thread_struct *thread; unsigned int err = 0; unsigned long ps; - struct _cpstate *buf; #define COPY(x) err |= __get_user(regs->x, &sc->sc_##x) COPY(pc); - COPY(depc); - COPY(wmask); COPY(lbeg); COPY(lend); COPY(lcount); COPY(sar); - COPY(windowbase); - COPY(windowstart); #undef COPY + /* All registers were flushed to stack. Start with a prestine frame. */ + + regs->wmask = 1; + regs->windowbase = 0; + regs->windowstart = 1; + /* For PS, restore only PS.CALLINC. * Assume that all other bits are either the same as for the signal * handler, or the user mode value doesn't matter (e.g. PS.OWB). */ err |= __get_user(ps, &sc->sc_ps); - regs->ps = (regs->ps & ~PS_CALLINC_MASK) - | (ps & PS_CALLINC_MASK); + regs->ps = (regs->ps & ~PS_CALLINC_MASK) | (ps & PS_CALLINC_MASK); /* Additional corruption checks */ - if ((regs->windowbase >= (XCHAL_NUM_AREGS/4)) - || ((regs->windowstart & ~((1<<(XCHAL_NUM_AREGS/4)) - 1)) != 0) ) - err = 1; if ((regs->lcount > 0) - && ((regs->lbeg > TASK_SIZE) || (regs->lend > TASK_SIZE)) ) + && ((regs->lbeg > TASK_SIZE) || (regs->lend > TASK_SIZE)) ) err = 1; - /* Restore extended register state. - * See struct thread_struct in processor.h. - */ - thread = ¤t->thread; - - err |= __copy_from_user (regs->areg, sc->sc_areg, XCHAL_NUM_AREGS*4); - err |= __get_user(buf, &sc->sc_cpstate); - if (buf) { - if (!access_ok(VERIFY_READ, buf, sizeof(*buf))) - goto badframe; - err |= restore_cpextra(buf); - } - - regs->syscall = -1; /* disable syscall checks */ - return err; - -badframe: - return 1; -} - -static inline void -flush_my_cpstate(struct task_struct *tsk) -{ - unsigned long flags; - local_irq_save(flags); - -#if 0 // FIXME - for (i = 0; i < XCHAL_CP_NUM; i++) { - if (tsk == coproc_owners[i]) { - xthal_validate_cp(i); - xthal_save_cpregs(tsk->thread.cpregs_ptr[i], i); + err |= __copy_from_user(regs->areg, sc->sc_a, 16 * 4); - /* Invalidate and "disown" the cp to allow - * callers the chance to reset cp state in the - * task_struct. */ +#if XCHAL_HAVE_CP +# error Coprocessors unsupported + /* The signal handler may have used coprocessors in which + * case they are still enabled. We disable them to force a + * reloading of the original task's CP state by the lazy + * context-switching mechanisms of CP exception handling. + * Also, we essentially discard any coprocessor state that the + * signal handler created. */ - xthal_invalidate_cp(i); - coproc_owners[i] = 0; - } + if (!err) { + struct task_struct *tsk = current; + release_all_cp(tsk); + err |= __copy_from_user(tsk->thread.cpextra, sc->sc_cpstate, + XTENSA_CP_EXTRA_SIZE); } #endif - local_irq_restore(flags); -} - -/* Return codes: - 0: nothing saved - 1: stuff to save, successful - -1: stuff to save, error happened -*/ -static int -save_cpextra (struct _cpstate *buf) -{ -#if XCHAL_CP_NUM == 0 - return 0; -#else - - /* FIXME: If a task has never used a coprocessor, there is - * no need to save and restore anything. Tracking this - * information would allow us to optimize this section. - * Perhaps we can use current->used_math or (current->flags & - * PF_USEDFPU) or define a new field in the thread - * structure. */ - - /* We flush any live, task-owned cp state to the task_struct, - * then copy it all to the sigframe. Then we clear all - * cp/extra state in the task_struct, effectively - * clearing/resetting all cp/extra state for the signal - * handler (cp-exception handling will load these new values - * into the cp/extra registers.) This step is important for - * things like a floating-point cp, where the OS must reset - * the FCR to the default rounding mode. */ - - int err = 0; - struct task_struct *tsk = current; - - flush_my_cpstate(tsk); - /* Note that we just copy everything: 'extra' and 'cp' state together.*/ - err |= __copy_to_user(buf, tsk->thread.cp_save, XTENSA_CP_EXTRA_SIZE); - memset(tsk->thread.cp_save, 0, XTENSA_CP_EXTRA_SIZE); - -#if (XTENSA_CP_EXTRA_SIZE == 0) -#error Sanity check on memset above, cpextra_size should not be zero. -#endif - - return err ? -1 : 1; -#endif -} - -static int -setup_sigcontext(struct sigcontext *sc, struct _cpstate *cpstate, - struct pt_regs *regs, unsigned long mask) -{ - struct thread_struct *thread; - int err = 0; - -//printk("setup_sigcontext\n"); -#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) - COPY(pc); - COPY(ps); - COPY(depc); - COPY(wmask); - COPY(lbeg); - COPY(lend); - COPY(lcount); - COPY(sar); - COPY(windowbase); - COPY(windowstart); -#undef COPY - - /* Save extended register state. - * See struct thread_struct in processor.h. - */ - thread = ¤t->thread; - err |= __copy_to_user (sc->sc_areg, regs->areg, XCHAL_NUM_AREGS * 4); - err |= save_cpextra(cpstate); - err |= __put_user(err ? NULL : cpstate, &sc->sc_cpstate); - /* non-iBCS2 extensions.. */ - err |= __put_user(mask, &sc->oldmask); + regs->syscall = -1; /* disable syscall checks */ return err; } -asmlinkage int xtensa_sigreturn(struct pt_regs *regs) -{ - struct sigframe *frame = (struct sigframe *)regs->areg[1]; - sigset_t set; - if (regs->depc > 64) - panic ("Double exception sys_sigreturn\n"); - - if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) - goto badframe; - - if (__get_user(set.sig[0], &frame->sc.oldmask) - || (_NSIG_WORDS > 1 - && __copy_from_user(&set.sig[1], &frame->extramask, - sizeof(frame->extramask)))) - goto badframe; - - sigdelsetmask(&set, ~_BLOCKABLE); - - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(regs, &frame->sc)) - goto badframe; - return regs->areg[2]; -badframe: - force_sig(SIGSEGV, current); - return 0; -} +/* + * Do a signal return; undo the signal stack. + */ -asmlinkage int xtensa_rt_sigreturn(struct pt_regs *regs) +asmlinkage long xtensa_rt_sigreturn(long a0, long a1, long a2, long a3, + long a4, long a5, struct pt_regs *regs) { - struct rt_sigframe *frame = (struct rt_sigframe *)regs->areg[1]; + struct rt_sigframe __user *frame; sigset_t set; - stack_t st; int ret; + if (regs->depc > 64) - { - printk("!!!!!!! DEPC !!!!!!!\n"); - return 0; - } + panic("rt_sigreturn in double exception!\n"); + + frame = (struct rt_sigframe __user *) regs->areg[1]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; @@ -407,13 +249,11 @@ asmlinkage int xtensa_rt_sigreturn(struct pt_regs *regs) if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) goto badframe; + ret = regs->areg[2]; - if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) + if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->areg[1]) == -EFAULT) goto badframe; - /* It is more difficult to avoid calling this function than to - call it and ignore errors. */ - do_sigaltstack(&st, NULL, regs->areg[1]); return ret; @@ -422,77 +262,50 @@ badframe: return 0; } -/* - * Set up a signal frame. - */ + /* - * Determine which stack to use.. + * Set up a signal frame. */ -static inline void * -get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) -{ - if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp)) - sp = current->sas_ss_sp + current->sas_ss_size; - - return (void *)((sp - frame_size) & -16ul); -} - -#define USE_SIGRETURN 0 -#define USE_RT_SIGRETURN 1 static int -gen_return_code(unsigned char *codemem, unsigned int use_rt_sigreturn) +gen_return_code(unsigned char *codemem) { - unsigned int retcall; int err = 0; -#if 0 - /* Ignoring SA_RESTORER for now; it's supposed to be obsolete, - * and the xtensa glibc doesn't use it. + /* + * The 12-bit immediate is really split up within the 24-bit MOVI + * instruction. As long as the above system call numbers fit within + * 8-bits, the following code works fine. See the Xtensa ISA for + * details. */ - if (ka->sa.sa_flags & SA_RESTORER) { - regs->pr = (unsigned long) ka->sa.sa_restorer; - } else -#endif /* 0 */ - { - -#if (__NR_sigreturn > 255) || (__NR_rt_sigreturn > 255) - -/* The 12-bit immediate is really split up within the 24-bit MOVI - * instruction. As long as the above system call numbers fit within - * 8-bits, the following code works fine. See the Xtensa ISA for - * details. - */ -#error Generating the MOVI instruction below breaks! +#if __NR_rt_sigreturn > 255 +# error Generating the MOVI instruction below breaks! #endif - retcall = use_rt_sigreturn ? __NR_rt_sigreturn : __NR_sigreturn; - #ifdef __XTENSA_EB__ /* Big Endian version */ - /* Generate instruction: MOVI a2, retcall */ - err |= __put_user(0x22, &codemem[0]); - err |= __put_user(0x0a, &codemem[1]); - err |= __put_user(retcall, &codemem[2]); - /* Generate instruction: SYSCALL */ - err |= __put_user(0x00, &codemem[3]); - err |= __put_user(0x05, &codemem[4]); - err |= __put_user(0x00, &codemem[5]); + /* Generate instruction: MOVI a2, __NR_rt_sigreturn */ + err |= __put_user(0x22, &codemem[0]); + err |= __put_user(0x0a, &codemem[1]); + err |= __put_user(__NR_rt_sigreturn, &codemem[2]); + /* Generate instruction: SYSCALL */ + err |= __put_user(0x00, &codemem[3]); + err |= __put_user(0x05, &codemem[4]); + err |= __put_user(0x00, &codemem[5]); #elif defined __XTENSA_EL__ /* Little Endian version */ - /* Generate instruction: MOVI a2, retcall */ - err |= __put_user(0x22, &codemem[0]); - err |= __put_user(0xa0, &codemem[1]); - err |= __put_user(retcall, &codemem[2]); - /* Generate instruction: SYSCALL */ - err |= __put_user(0x00, &codemem[3]); - err |= __put_user(0x50, &codemem[4]); - err |= __put_user(0x00, &codemem[5]); + /* Generate instruction: MOVI a2, __NR_rt_sigreturn */ + err |= __put_user(0x22, &codemem[0]); + err |= __put_user(0xa0, &codemem[1]); + err |= __put_user(__NR_rt_sigreturn, &codemem[2]); + /* Generate instruction: SYSCALL */ + err |= __put_user(0x00, &codemem[3]); + err |= __put_user(0x50, &codemem[4]); + err |= __put_user(0x00, &codemem[5]); #else -#error Must use compiler for Xtensa processors. +# error Must use compiler for Xtensa processors. #endif - } /* Flush generated code out of the data cache */ @@ -504,97 +317,29 @@ gen_return_code(unsigned char *codemem, unsigned int use_rt_sigreturn) return err; } -static void -set_thread_state(struct pt_regs *regs, void *stack, unsigned char *retaddr, - void *handler, unsigned long arg1, void *arg2, void *arg3) -{ - /* Set up registers for signal handler */ - start_thread(regs, (unsigned long) handler, (unsigned long) stack); - - /* Set up a stack frame for a call4 - * Note: PS.CALLINC is set to one by start_thread - */ - regs->areg[4] = (((unsigned long) retaddr) & 0x3fffffff) | 0x40000000; - regs->areg[6] = arg1; - regs->areg[7] = (unsigned long) arg2; - regs->areg[8] = (unsigned long) arg3; -} -static void setup_frame(int sig, struct k_sigaction *ka, +static void setup_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs) { - struct sigframe *frame; + struct rt_sigframe *frame; int err = 0; int signal; + unsigned long sp, ra; - frame = get_sigframe(ka, regs->areg[1], sizeof(*frame)); - if (regs->depc > 64) - { - printk("!!!!!!! DEPC !!!!!!!\n"); - return; - } - - - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - goto give_sigsegv; - - signal = current_thread_info()->exec_domain - && current_thread_info()->exec_domain->signal_invmap - && sig < 32 - ? current_thread_info()->exec_domain->signal_invmap[sig] - : sig; - - err |= setup_sigcontext(&frame->sc, &frame->cpstate, regs, set->sig[0]); + sp = regs->areg[1]; - if (_NSIG_WORDS > 1) { - err |= __copy_to_user(frame->extramask, &set->sig[1], - sizeof(frame->extramask)); + if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp)) { + sp = current->sas_ss_sp + current->sas_ss_size; } - /* Create sys_sigreturn syscall in stack frame */ - err |= gen_return_code(frame->retcode, USE_SIGRETURN); - - if (err) - goto give_sigsegv; - - /* Create signal handler execution context. - * Return context not modified until this point. - */ - set_thread_state(regs, frame, frame->retcode, - ka->sa.sa_handler, signal, &frame->sc, NULL); - - /* Set access mode to USER_DS. Nomenclature is outdated, but - * functionality is used in uaccess.h - */ - set_fs(USER_DS); - - -#if DEBUG_SIG - printk("SIG deliver (%s:%d): signal=%d sp=%p pc=%08x\n", - current->comm, current->pid, signal, frame, regs->pc); -#endif - - return; - -give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); -} - -static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, - sigset_t *set, struct pt_regs *regs) -{ - struct rt_sigframe *frame; - int err = 0; - int signal; + frame = (void *)((sp - sizeof(*frame)) & -16ul); - frame = get_sigframe(ka, regs->areg[1], sizeof(*frame)); if (regs->depc > 64) panic ("Double exception sys_sigreturn\n"); - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) { goto give_sigsegv; + } signal = current_thread_info()->exec_domain && current_thread_info()->exec_domain->signal_invmap @@ -602,9 +347,12 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ? current_thread_info()->exec_domain->signal_invmap[sig] : sig; - err |= copy_siginfo_to_user(&frame->info, info); + if (ka->sa.sa_flags & SA_SIGINFO) { + err |= copy_siginfo_to_user(&frame->info, info); + } + + /* Create the user context. */ - /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); err |= __put_user((void *)current->sas_ss_sp, @@ -617,16 +365,31 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); /* Create sys_rt_sigreturn syscall in stack frame */ - err |= gen_return_code(frame->retcode, USE_RT_SIGRETURN); - if (err) + err |= gen_return_code(frame->retcode); + + if (err) { goto give_sigsegv; + } + - /* Create signal handler execution context. + /* + * Create signal handler execution context. * Return context not modified until this point. */ - set_thread_state(regs, frame, frame->retcode, - ka->sa.sa_handler, signal, &frame->info, &frame->uc); + + /* Set up registers for signal handler */ + start_thread(regs, (unsigned long) ka->sa.sa_handler, + (unsigned long) frame); + + /* Set up a stack frame for a call4 + * Note: PS.CALLINC is set to one by start_thread + */ + ra = (unsigned long) frame->retcode; + regs->areg[4] = (((unsigned long) ra) & 0x3fffffff) | 0x40000000; + regs->areg[6] = (unsigned long) signal; + regs->areg[7] = (unsigned long) &frame->info; + regs->areg[8] = (unsigned long) &frame->uc; /* Set access mode to USER_DS. Nomenclature is outdated, but * functionality is used in uaccess.h @@ -646,6 +409,48 @@ give_sigsegv: force_sig(SIGSEGV, current); } +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ + +asmlinkage long xtensa_rt_sigsuspend(sigset_t __user *unewset, + size_t sigsetsize, + long a2, long a3, long a4, long a5, + struct pt_regs *regs) +{ + sigset_t saveset, newset; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset, unewset, sizeof(newset))) + return -EFAULT; + + sigdelsetmask(&newset, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + regs->areg[2] = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(regs, &saveset)) + return -EINTR; + } +} + +asmlinkage long xtensa_sigaltstack(const stack_t __user *uss, + stack_t __user *uoss, + long a2, long a3, long a4, long a5, + struct pt_regs *regs) +{ + return do_sigaltstack(uss, uoss, regs->areg[1]); +} + /* @@ -663,51 +468,89 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) int signr; struct k_sigaction ka; + if (!user_mode(regs)) + return 0; + + if (try_to_freeze()) + goto no_signal; + if (!oldset) oldset = ¤t->blocked; + task_pt_regs(current)->icountlevel = 0; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); - /* Are we from a system call? */ - if (regs->syscall >= 0) { - /* If so, check system call restarting.. */ - switch (regs->areg[2]) { - case ERESTARTNOHAND: - case ERESTART_RESTARTBLOCK: - regs->areg[2] = -EINTR; - break; + if (signr > 0) { + + /* Are we from a system call? */ + + if ((signed)regs->syscall >= 0) { - case ERESTARTSYS: - if (!(ka.sa.sa_flags & SA_RESTART)) { + /* If so, check system call restarting.. */ + + switch (regs->areg[2]) { + case -ERESTARTNOHAND: + case -ERESTART_RESTARTBLOCK: regs->areg[2] = -EINTR; break; - } - /* fallthrough */ - case ERESTARTNOINTR: - regs->areg[2] = regs->syscall; - regs->pc -= 3; + + case -ERESTARTSYS: + if (!(ka.sa.sa_flags & SA_RESTART)) { + regs->areg[2] = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: + regs->areg[2] = regs->syscall; + regs->pc -= 3; + break; + + default: + /* nothing to do */ + if (regs->areg[2] != 0) + break; + } } - } - if (signr == 0) - return 0; /* no signals delivered */ + /* Whee! Actually deliver the signal. */ + /* Set up the stack frame */ + setup_frame(signr, &ka, &info, oldset, regs); - /* Whee! Actually deliver the signal. */ + if (ka.sa.sa_flags & SA_ONESHOT) + ka.sa.sa_handler = SIG_DFL; - /* Set up the stack frame */ - if (ka.sa.sa_flags & SA_SIGINFO) - setup_rt_frame(signr, &ka, &info, oldset, regs); - else - setup_frame(signr, &ka, oldset, regs); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked, ¤t->blocked, &ka.sa.sa_mask); + if (!(ka.sa.sa_flags & SA_NODEFER)) + sigaddset(¤t->blocked, signr); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + if (current->ptrace & PT_SINGLESTEP) + task_pt_regs(current)->icountlevel = 1; - if (ka.sa.sa_flags & SA_ONESHOT) - ka.sa.sa_handler = SIG_DFL; + return 1; + } - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, &ka.sa.sa_mask); - if (!(ka.sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked, signr); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - return 1; +no_signal: + /* Did we come from a system call? */ + if ((signed) regs->syscall >= 0) { + /* Restart the system call - no handlers present */ + switch (regs->areg[2]) { + case -ERESTARTNOHAND: + case -ERESTARTSYS: + case -ERESTARTNOINTR: + regs->areg[2] = regs->syscall; + regs->pc -= 3; + break; + case -ERESTART_RESTARTBLOCK: + regs->areg[2] = __NR_restart_syscall; + regs->pc -= 3; + break; + } + } + if (current->ptrace & PT_SINGLESTEP) + task_pt_regs(current)->icountlevel = 1; + return 0; } + diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S index 4b7b4ff79973..b0582c3c5f8d 100644 --- a/arch/xtensa/kernel/vmlinux.lds.S +++ b/arch/xtensa/kernel/vmlinux.lds.S @@ -84,9 +84,7 @@ SECTIONS { /* The .head.text section must be the first section! */ *(.head.text) - *(.literal) - TEXT_TEXT - *(.srom.text) + *(.literal .text) VMLINUX_SYMBOL(__sched_text_start) = .; *(.sched.literal .sched.text) VMLINUX_SYMBOL(__sched_text_end) = .; @@ -96,6 +94,7 @@ SECTIONS } _etext = .; + PROVIDE (etext = .); . = ALIGN(16); @@ -103,32 +102,6 @@ SECTIONS /* Relocation table */ - . = ALIGN(16); - __boot_reloc_table_start = ABSOLUTE(.); - - __relocate : { - - RELOCATE_ENTRY(_WindowVectors_text, - .WindowVectors.text); -#if 0 - RELOCATE_ENTRY(_KernelExceptionVector_literal, - .KernelExceptionVector.literal); -#endif - RELOCATE_ENTRY(_KernelExceptionVector_text, - .KernelExceptionVector.text); -#if 0 - RELOCATE_ENTRY(_UserExceptionVector_literal, - .UserExceptionVector.literal); -#endif - RELOCATE_ENTRY(_UserExceptionVector_text, - .UserExceptionVector.text); - RELOCATE_ENTRY(_DoubleExceptionVector_literal, - .DoubleExceptionVector.literal); - RELOCATE_ENTRY(_DoubleExceptionVector_text, - .DoubleExceptionVector.text); - } - __boot_reloc_table_end = ABSOLUTE(.) ; - .fixup : { *(.fixup) } . = ALIGN(16); @@ -145,8 +118,7 @@ SECTIONS _fdata = .; .data : { - DATA_DATA - CONSTRUCTORS + *(.data) CONSTRUCTORS . = ALIGN(XCHAL_ICACHE_LINESIZE); *(.data.cacheline_aligned) } @@ -174,6 +146,22 @@ SECTIONS __tagtable_begin = .; *(.taglist) __tagtable_end = .; + + . = ALIGN(16); + __boot_reloc_table_start = ABSOLUTE(.); + + RELOCATE_ENTRY(_WindowVectors_text, + .WindowVectors.text); + RELOCATE_ENTRY(_KernelExceptionVector_text, + .KernelExceptionVector.text); + RELOCATE_ENTRY(_UserExceptionVector_text, + .UserExceptionVector.text); + RELOCATE_ENTRY(_DoubleExceptionVector_literal, + .DoubleExceptionVector.literal); + RELOCATE_ENTRY(_DoubleExceptionVector_text, + .DoubleExceptionVector.text); + + __boot_reloc_table_end = ABSOLUTE(.) ; } . = ALIGN(XCHAL_ICACHE_LINESIZE); @@ -194,16 +182,6 @@ SECTIONS SECURITY_INIT - . = ALIGN(4); - - __start___ftr_fixup = .; - __ftr_fixup : { *(__ftr_fixup) } - __stop___ftr_fixup = .; - - . = ALIGN(4096); - __per_cpu_start = .; - .data.percpu : { *(.data.percpu) } - __per_cpu_end = .; #ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(4096); @@ -212,6 +190,12 @@ SECTIONS __initramfs_end = .; #endif + . = ALIGN(4096); + __per_cpu_start = .; + .data.percpu : { *(.data.percpu) } + __per_cpu_end = .; + + /* We need this dummy segment here */ . = ALIGN(4); @@ -273,9 +257,9 @@ SECTIONS /* BSS section */ _bss_start = .; - .sbss : { *(.sbss) *(.scommon) } - .bss : { *(COMMON) *(.bss) } + .bss : { *(.bss.page_aligned) *(.bss) } _bss_end = .; + _end = .; /* only used by the boot loader */ @@ -293,16 +277,16 @@ SECTIONS *(.ResetVector.text) } - /* Sections to be discarded */ /DISCARD/ : { - *(.text.exit) - *(.text.exit.literal) - *(.data.exit) + *(.exit.literal .exit.text) + *(.exit.data) *(.exitcall.exit) } + .xt.lit : { *(.xt.lit) } + .xt.prop : { *(.xt.prop) } .debug 0 : { *(.debug) } .line 0 : { *(.line) } diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c index cd7e6a020602..60dbdb43fb4c 100644 --- a/arch/xtensa/kernel/xtensa_ksyms.c +++ b/arch/xtensa/kernel/xtensa_ksyms.c @@ -38,21 +38,10 @@ /* * String functions */ -EXPORT_SYMBOL(memcmp); EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memmove); -EXPORT_SYMBOL(memchr); -EXPORT_SYMBOL(strcat); -EXPORT_SYMBOL(strchr); -EXPORT_SYMBOL(strlen); -EXPORT_SYMBOL(strncat); -EXPORT_SYMBOL(strnlen); -EXPORT_SYMBOL(strrchr); -EXPORT_SYMBOL(strstr); -EXPORT_SYMBOL(enable_irq); -EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(kernel_thread); /* diff --git a/arch/xtensa/lib/strncpy_user.S b/arch/xtensa/lib/strncpy_user.S index a834057bda6b..b2655d94558d 100644 --- a/arch/xtensa/lib/strncpy_user.S +++ b/arch/xtensa/lib/strncpy_user.S @@ -25,18 +25,18 @@ /* * char *__strncpy_user(char *dst, const char *src, size_t len) */ -.text -.begin literal -.align 4 -.Lmask0: - .byte 0xff, 0x00, 0x00, 0x00 -.Lmask1: - .byte 0x00, 0xff, 0x00, 0x00 -.Lmask2: - .byte 0x00, 0x00, 0xff, 0x00 -.Lmask3: - .byte 0x00, 0x00, 0x00, 0xff -.end literal + +#ifdef __XTENSA_EB__ +# define MASK0 0xff000000 +# define MASK1 0x00ff0000 +# define MASK2 0x0000ff00 +# define MASK3 0x000000ff +#else +# define MASK0 0x000000ff +# define MASK1 0x0000ff00 +# define MASK2 0x00ff0000 +# define MASK3 0xff000000 +#endif # Register use # a0/ return address @@ -53,6 +53,7 @@ # a11/ dst # a12/ tmp +.text .align 4 .global __strncpy_user .type __strncpy_user,@function @@ -61,10 +62,10 @@ __strncpy_user: # a2/ dst, a3/ src, a4/ len mov a11, a2 # leave dst in return value register beqz a4, .Lret # if len is zero - l32r a5, .Lmask0 # mask for byte 0 - l32r a6, .Lmask1 # mask for byte 1 - l32r a7, .Lmask2 # mask for byte 2 - l32r a8, .Lmask3 # mask for byte 3 + movi a5, MASK0 # mask for byte 0 + movi a6, MASK1 # mask for byte 1 + movi a7, MASK2 # mask for byte 2 + movi a8, MASK3 # mask for byte 3 bbsi.l a3, 0, .Lsrc1mod2 # if only 8-bit aligned bbsi.l a3, 1, .Lsrc2mod4 # if only 16-bit aligned .Lsrcaligned: # return here when src is word-aligned diff --git a/arch/xtensa/lib/strnlen_user.S b/arch/xtensa/lib/strnlen_user.S index 5e9c1e709b2e..ad3f616322ca 100644 --- a/arch/xtensa/lib/strnlen_user.S +++ b/arch/xtensa/lib/strnlen_user.S @@ -24,18 +24,18 @@ /* * size_t __strnlen_user(const char *s, size_t len) */ -.text -.begin literal -.align 4 -.Lmask0: - .byte 0xff, 0x00, 0x00, 0x00 -.Lmask1: - .byte 0x00, 0xff, 0x00, 0x00 -.Lmask2: - .byte 0x00, 0x00, 0xff, 0x00 -.Lmask3: - .byte 0x00, 0x00, 0x00, 0xff -.end literal + +#ifdef __XTENSA_EB__ +# define MASK0 0xff000000 +# define MASK1 0x00ff0000 +# define MASK2 0x0000ff00 +# define MASK3 0x000000ff +#else +# define MASK0 0x000000ff +# define MASK1 0x0000ff00 +# define MASK2 0x00ff0000 +# define MASK3 0xff000000 +#endif # Register use: # a2/ src @@ -48,6 +48,7 @@ # a9/ tmp # a10/ tmp +.text .align 4 .global __strnlen_user .type __strnlen_user,@function @@ -56,10 +57,10 @@ __strnlen_user: # a2/ s, a3/ len addi a4, a2, -4 # because we overincrement at the end; # we compensate with load offsets of 4 - l32r a5, .Lmask0 # mask for byte 0 - l32r a6, .Lmask1 # mask for byte 1 - l32r a7, .Lmask2 # mask for byte 2 - l32r a8, .Lmask3 # mask for byte 3 + movi a5, MASK0 # mask for byte 0 + movi a6, MASK1 # mask for byte 1 + movi a7, MASK2 # mask for byte 2 + movi a8, MASK3 # mask for byte 3 bbsi.l a2, 0, .L1mod2 # if only 8-bit aligned bbsi.l a2, 1, .L2mod4 # if only 16-bit aligned diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c index e1ec2d1e8189..8415c76f11c2 100644 --- a/arch/xtensa/mm/init.c +++ b/arch/xtensa/mm/init.c @@ -205,7 +205,7 @@ void __init init_mmu (void) /* Writing zeros to the <t>TLBCFG special registers ensure * that valid values exist in the register. For existing * PGSZID<w> fields, zero selects the first element of the - * page-size array. For nonexistant PGSZID<w> fields, zero is + * page-size array. For nonexistent PGSZID<w> fields, zero is * the best value to write. Also, when changing PGSZID<w> * fields, the corresponding TLB must be flushed. */ diff --git a/arch/xtensa/platform-iss/network.c b/arch/xtensa/platform-iss/network.c index 4bfe333be229..f09962fa98c0 100644 --- a/arch/xtensa/platform-iss/network.c +++ b/arch/xtensa/platform-iss/network.c @@ -473,7 +473,7 @@ static int iss_net_open(struct net_device *dev) netif_start_queue(dev); /* clear buffer - it can happen that the host side of the interface - * is full when we gethere. In this case, new data is never queued, + * is full when we get here. In this case, new data is never queued, * SIGIOs never arrive, and the net never works. */ while ((err = iss_net_rx(dev)) > 0) |