diff options
author | Linus Torvalds | 2007-05-09 13:08:20 -0700 |
---|---|---|
committer | Linus Torvalds | 2007-05-09 13:08:20 -0700 |
commit | d84c4124c4b6611301b402e8611b7e36de3bd351 (patch) | |
tree | d83cfaabfb901755d85074815ad948028dc7b03f | |
parent | 932c37c375cca25175f9b6acee4c75d7a96d985f (diff) | |
parent | a3cf4ea8729a5d448742fd5a0a003827c9f25cb6 (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/lethal/sh-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/lethal/sh-2.6:
sh: Fix stacktrace simplification fallout.
sh: SH7760 DMABRG support.
sh: clockevent/clocksource/hrtimers/nohz TMU support.
sh: Truncate MAX_ACTIVE_REGIONS for the common case.
rtc: rtc-sh: Fix rtc_dev pointer for rtc_update_irq().
sh: Convert to common die chain.
sh: Wire up utimensat syscall.
sh: landisk mv_nr_irqs definition.
sh: Fixup ndelay() xloops calculation for alternate HZ.
sh: Add 32-bit opcode feature CPU flag.
sh: Fix PC adjustments for varying opcode length.
sh: Support for SH-2A 32-bit opcodes.
sh: Kill off redundant __div64_32 symbol export.
sh: Share exception vector table for SH-3/4.
sh: Always define TRAPA_BUG_OPCODE.
sh: __GFP_REPEAT for pte allocations, too.
rtc: rtc-sh: Fix up dev_dbg() warnings.
sh: generic quicklist support.
36 files changed, 572 insertions, 398 deletions
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index d74eb120a9c6..038179ecf6a9 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -52,6 +52,9 @@ config GENERIC_IOMAP config GENERIC_TIME def_bool n +config GENERIC_CLOCKEVENTS + def_bool n + config SYS_SUPPORTS_APM_EMULATION bool @@ -436,11 +439,11 @@ endmenu menu "Timer and clock configuration" -if !GENERIC_TIME - config SH_TMU bool "TMU timer support" depends on CPU_SH3 || CPU_SH4 + select GENERIC_TIME + select GENERIC_CLOCKEVENTS default y help This enables the use of the TMU as the system timer. @@ -459,8 +462,6 @@ config SH_MTU2 help This enables the use of the MTU2 as the system timer. -endif - config SH_TIMER_IRQ int default "28" if CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785 @@ -468,24 +469,6 @@ config SH_TIMER_IRQ default "140" if CPU_SUBTYPE_SH7206 default "16" -config NO_IDLE_HZ - bool "Dynamic tick timer" - help - Select this option if you want to disable continuous timer ticks - and have them programmed to occur as required. This option saves - power as the system can remain in idle state for longer. - - By default dynamic tick is disabled during the boot, and can be - manually enabled with: - - echo 1 > /sys/devices/system/timer/timer0/dyn_tick - - Alternatively, if you want dynamic tick automatically enabled - during boot, pass "dyntick=enable" via the kernel command string. - - Please note that dynamic tick may affect the accuracy of - timekeeping on some platforms depending on the implementation. - config SH_PCLK_FREQ int "Peripheral clock frequency (in Hz)" default "27000000" if CPU_SUBTYPE_SH73180 || CPU_SUBTYPE_SH7343 @@ -509,6 +492,8 @@ config SH_CLK_MD help MD2 - MD0 pin setting. +source "kernel/time/Kconfig" + endmenu menu "CPU Frequency scaling" diff --git a/arch/sh/boards/landisk/setup.c b/arch/sh/boards/landisk/setup.c index a83a5d9587bb..4058b4f50d44 100644 --- a/arch/sh/boards/landisk/setup.c +++ b/arch/sh/boards/landisk/setup.c @@ -93,6 +93,7 @@ static void __init landisk_setup(char **cmdline_p) */ struct sh_machine_vector mv_landisk __initmv = { .mv_name = "LANDISK", + .mv_nr_irqs = 72, .mv_setup = landisk_setup, .mv_init_irq = init_landisk_IRQ, }; diff --git a/arch/sh/drivers/Makefile b/arch/sh/drivers/Makefile index 6cb92676c5fc..e13f06bebd92 100644 --- a/arch/sh/drivers/Makefile +++ b/arch/sh/drivers/Makefile @@ -2,8 +2,9 @@ # Makefile for the Linux SuperH-specific device drivers. # +obj-y += dma/ + obj-$(CONFIG_PCI) += pci/ -obj-$(CONFIG_SH_DMA) += dma/ obj-$(CONFIG_SUPERHYWAY) += superhyway/ obj-$(CONFIG_PUSH_SWITCH) += push-switch.o obj-$(CONFIG_HEARTBEAT) += heartbeat.o diff --git a/arch/sh/drivers/dma/Kconfig b/arch/sh/drivers/dma/Kconfig index defc13c37d48..99935f9daf4b 100644 --- a/arch/sh/drivers/dma/Kconfig +++ b/arch/sh/drivers/dma/Kconfig @@ -1,12 +1,12 @@ menu "DMA support" -config SH_DMA - bool "DMA controller (DMAC) support" - help - Selecting this option will provide same API as PC's Direct Memory - Access Controller(8237A) for SuperH DMAC. +config SH_DMA_API + bool - If unsure, say N. +config SH_DMA + bool "SuperH on-chip DMA controller (DMAC) support" + select SH_DMA_API + default n config NR_ONCHIP_DMA_CHANNELS depends on SH_DMA @@ -53,4 +53,12 @@ config DMA_PAGE_OPS_CHANNEL in case channel 3 is unavailable. On the SH4, channels 1,2, and 3 are dual-address capable. +config SH_DMABRG + bool "SH7760 DMABRG support" + depends on CPU_SUBTYPE_SH7760 + help + The DMABRG does data transfers from main memory to Audio/USB units + of the SH7760. + Say Y if you want to use Audio/USB DMA on your SH7760 board. + endmenu diff --git a/arch/sh/drivers/dma/Makefile b/arch/sh/drivers/dma/Makefile index db1295d32268..1ac812d24488 100644 --- a/arch/sh/drivers/dma/Makefile +++ b/arch/sh/drivers/dma/Makefile @@ -2,8 +2,8 @@ # Makefile for the SuperH DMA specific kernel interface routines under Linux. # -obj-y += dma-api.o +obj-$(CONFIG_SH_DMA_API) += dma-api.o dma-sysfs.o obj-$(CONFIG_ISA_DMA_API) += dma-isa.o -obj-$(CONFIG_SYSFS) += dma-sysfs.o obj-$(CONFIG_SH_DMA) += dma-sh.o obj-$(CONFIG_SH_DREAMCAST) += dma-pvr2.o dma-g2.o +obj-$(CONFIG_SH_DMABRG) += dmabrg.o diff --git a/arch/sh/drivers/dma/dmabrg.c b/arch/sh/drivers/dma/dmabrg.c new file mode 100644 index 000000000000..9d0a29370f21 --- /dev/null +++ b/arch/sh/drivers/dma/dmabrg.c @@ -0,0 +1,196 @@ +/* + * SH7760 DMABRG IRQ handling + * + * (c) 2007 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com> + * licensed under the GPLv2. + * + */ + +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <asm/dma.h> +#include <asm/dmabrg.h> +#include <asm/io.h> + +/* + * The DMABRG is a special DMA unit within the SH7760. It does transfers + * from USB-SRAM/Audio units to main memory (and also the LCDC; but that + * part is sensibly placed in the LCDC registers and requires no irqs) + * It has 3 IRQ lines which trigger 10 events, and works independently + * from the traditional SH DMAC (although it blocks usage of DMAC 0) + * + * BRGIRQID | component | dir | meaning | source + * ----------------------------------------------------- + * 0 | USB-DMA | ... | xfer done | DMABRGI1 + * 1 | USB-UAE | ... | USB addr err.| DMABRGI0 + * 2 | HAC0/SSI0 | play| all done | DMABRGI1 + * 3 | HAC0/SSI0 | play| half done | DMABRGI2 + * 4 | HAC0/SSI0 | rec | all done | DMABRGI1 + * 5 | HAC0/SSI0 | rec | half done | DMABRGI2 + * 6 | HAC1/SSI1 | play| all done | DMABRGI1 + * 7 | HAC1/SSI1 | play| half done | DMABRGI2 + * 8 | HAC1/SSI1 | rec | all done | DMABRGI1 + * 9 | HAC1/SSI1 | rec | half done | DMABRGI2 + * + * all can be enabled/disabled in the DMABRGCR register, + * as well as checked if they occured. + * + * DMABRGI0 services USB DMA Address errors, but it still must be + * enabled/acked in the DMABRGCR register. USB-DMA complete indicator + * is grouped together with the audio buffer end indicators, too bad... + * + * DMABRGCR: Bits 31-24: audio-dma ENABLE flags, + * Bits 23-16: audio-dma STATUS flags, + * Bits 9-8: USB error/xfer ENABLE, + * Bits 1-0: USB error/xfer STATUS. + * Ack an IRQ by writing 0 to the STATUS flag. + * Mask IRQ by writing 0 to ENABLE flag. + * + * Usage is almost like with any other IRQ: + * dmabrg_request_irq(BRGIRQID, handler, data) + * dmabrg_free_irq(BRGIRQID) + * + * handler prototype: void brgirqhandler(void *data) + */ + +#define DMARSRA 0xfe090000 +#define DMAOR 0xffa00040 +#define DMACHCR0 0xffa0000c +#define DMABRGCR 0xfe3c0000 + +#define DMAOR_BRG 0x0000c000 +#define DMAOR_DMEN 0x00000001 + +#define DMABRGI0 68 +#define DMABRGI1 69 +#define DMABRGI2 70 + +struct dmabrg_handler { + void (*handler)(void *); + void *data; +} *dmabrg_handlers; + +static inline void dmabrg_call_handler(int i) +{ + dmabrg_handlers[i].handler(dmabrg_handlers[i].data); +} + +/* + * main DMABRG irq handler. It acks irqs and then + * handles every set and unmasked bit sequentially. + * No locking and no validity checks; it should be + * as fast as possible (audio!) + */ +static irqreturn_t dmabrg_irq(int irq, void *data) +{ + unsigned long dcr; + unsigned int i; + + dcr = ctrl_inl(DMABRGCR); + ctrl_outl(dcr & ~0x00ff0003, DMABRGCR); /* ack all */ + dcr &= dcr >> 8; /* ignore masked */ + + /* USB stuff, get it out of the way first */ + if (dcr & 1) + dmabrg_call_handler(DMABRGIRQ_USBDMA); + if (dcr & 2) + dmabrg_call_handler(DMABRGIRQ_USBDMAERR); + + /* Audio */ + dcr >>= 16; + while (dcr) { + i = __ffs(dcr); + dcr &= dcr - 1; + dmabrg_call_handler(i + DMABRGIRQ_A0TXF); + } + return IRQ_HANDLED; +} + +static void dmabrg_disable_irq(unsigned int dmairq) +{ + unsigned long dcr; + dcr = ctrl_inl(DMABRGCR); + dcr &= ~(1 << ((dmairq > 1) ? dmairq + 22 : dmairq + 8)); + ctrl_outl(dcr, DMABRGCR); +} + +static void dmabrg_enable_irq(unsigned int dmairq) +{ + unsigned long dcr; + dcr = ctrl_inl(DMABRGCR); + dcr |= (1 << ((dmairq > 1) ? dmairq + 22 : dmairq + 8)); + ctrl_outl(dcr, DMABRGCR); +} + +int dmabrg_request_irq(unsigned int dmairq, void(*handler)(void*), + void *data) +{ + if ((dmairq > 9) || !handler) + return -ENOENT; + if (dmabrg_handlers[dmairq].handler) + return -EBUSY; + + dmabrg_handlers[dmairq].handler = handler; + dmabrg_handlers[dmairq].data = data; + + dmabrg_enable_irq(dmairq); + return 0; +} +EXPORT_SYMBOL_GPL(dmabrg_request_irq); + +void dmabrg_free_irq(unsigned int dmairq) +{ + if (likely(dmairq < 10)) { + dmabrg_disable_irq(dmairq); + dmabrg_handlers[dmairq].handler = NULL; + dmabrg_handlers[dmairq].data = NULL; + } +} +EXPORT_SYMBOL_GPL(dmabrg_free_irq); + +static int __init dmabrg_init(void) +{ + unsigned long or; + int ret; + + dmabrg_handlers = kzalloc(10 * sizeof(struct dmabrg_handler), + GFP_KERNEL); + if (!dmabrg_handlers) + return -ENOMEM; + +#ifdef CONFIG_SH_DMA + /* request DMAC channel 0 before anyone else can get it */ + ret = request_dma(0, "DMAC 0 (DMABRG)"); + if (ret < 0) + printk(KERN_INFO "DMABRG: DMAC ch0 not reserved!\n"); +#endif + + ctrl_outl(0, DMABRGCR); + ctrl_outl(0, DMACHCR0); + ctrl_outl(0x94000000, DMARSRA); /* enable DMABRG in DMAC 0 */ + + /* enable DMABRG mode, enable the DMAC */ + or = ctrl_inl(DMAOR); + ctrl_outl(or | DMAOR_BRG | DMAOR_DMEN, DMAOR); + + ret = request_irq(DMABRGI0, dmabrg_irq, IRQF_DISABLED, + "DMABRG USB address error", NULL); + if (ret) + goto out0; + + ret = request_irq(DMABRGI1, dmabrg_irq, IRQF_DISABLED, + "DMABRG Transfer End", NULL); + if (ret) + goto out1; + + ret = request_irq(DMABRGI2, dmabrg_irq, IRQF_DISABLED, + "DMABRG Transfer Half", NULL); + if (ret == 0) + return ret; + + free_irq(DMABRGI1, 0); +out1: free_irq(DMABRGI0, 0); +out0: kfree(dmabrg_handlers); + return ret; +} +subsys_initcall(dmabrg_init); diff --git a/arch/sh/kernel/cpu/sh2a/Makefile b/arch/sh/kernel/cpu/sh2a/Makefile index 350972ae9410..965fa2572b23 100644 --- a/arch/sh/kernel/cpu/sh2a/Makefile +++ b/arch/sh/kernel/cpu/sh2a/Makefile @@ -2,9 +2,8 @@ # Makefile for the Linux/SuperH SH-2A backends. # -obj-y := common.o probe.o +obj-y := common.o probe.o opcode_helper.o -common-y += $(addprefix ../sh2/, ex.o) -common-y += $(addprefix ../sh2/, entry.o) +common-y += $(addprefix ../sh2/, ex.o entry.o) obj-$(CONFIG_CPU_SUBTYPE_SH7206) += setup-sh7206.o clock-sh7206.o diff --git a/arch/sh/kernel/cpu/sh2a/opcode_helper.c b/arch/sh/kernel/cpu/sh2a/opcode_helper.c new file mode 100644 index 000000000000..9704b7926d8b --- /dev/null +++ b/arch/sh/kernel/cpu/sh2a/opcode_helper.c @@ -0,0 +1,55 @@ +/* + * arch/sh/kernel/cpu/sh2a/opcode_helper.c + * + * Helper for the SH-2A 32-bit opcodes. + * + * Copyright (C) 2007 Paul Mundt + * + * 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. + */ +#include <linux/kernel.h> +#include <asm/system.h> + +/* + * Instructions on SH are generally fixed at 16-bits, however, SH-2A + * introduces some 32-bit instructions. Since there are no real + * constraints on their use (and they can be mixed and matched), we need + * to check the instruction encoding to work out if it's a true 32-bit + * instruction or not. + * + * Presently, 32-bit opcodes have only slight variations in what the + * actual encoding looks like in the first-half of the instruction, which + * makes it fairly straightforward to differentiate from the 16-bit ones. + * + * First 16-bits of encoding Used by + * + * 0011nnnnmmmm0001 mov.b, mov.w, mov.l, fmov.d, + * fmov.s, movu.b, movu.w + * + * 0011nnnn0iii1001 bclr.b, bld.b, bset.b, bst.b, band.b, + * bandnot.b, bldnot.b, bor.b, bornot.b, + * bxor.b + * + * 0000nnnniiii0000 movi20 + * 0000nnnniiii0001 movi20s + */ +unsigned int instruction_size(unsigned int insn) +{ + /* Look for the common cases */ + switch ((insn & 0xf00f)) { + case 0x0000: /* movi20 */ + case 0x0001: /* movi20s */ + case 0x3001: /* 32-bit mov/fmov/movu variants */ + return 4; + } + + /* And the special cases.. */ + switch ((insn & 0xf08f)) { + case 0x3009: /* 32-bit b*.b bit operations */ + return 4; + } + + return 2; +} diff --git a/arch/sh/kernel/cpu/sh2a/probe.c b/arch/sh/kernel/cpu/sh2a/probe.c index 426f6db01fc6..f455c3509789 100644 --- a/arch/sh/kernel/cpu/sh2a/probe.c +++ b/arch/sh/kernel/cpu/sh2a/probe.c @@ -18,6 +18,7 @@ int __init detect_cpu_and_cache_system(void) { /* Just SH7206 for now .. */ current_cpu_data.type = CPU_SH7206; + current_cpu_data.flags |= CPU_HAS_OP32; current_cpu_data.dcache.ways = 4; current_cpu_data.dcache.way_incr = (1 << 11); diff --git a/arch/sh/kernel/cpu/sh3/ex.S b/arch/sh/kernel/cpu/sh3/ex.S index ba3082d640b5..2b2a9e02fb75 100644 --- a/arch/sh/kernel/cpu/sh3/ex.S +++ b/arch/sh/kernel/cpu/sh3/ex.S @@ -1,7 +1,7 @@ /* * arch/sh/kernel/cpu/sh3/ex.S * - * The SH-3 exception vector table. + * The SH-3 and SH-4 exception vector table. * Copyright (C) 1999, 2000, 2002 Niibe Yutaka * Copyright (C) 2003 - 2006 Paul Mundt @@ -9,7 +9,6 @@ * 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. - * */ #include <linux/linkage.h> @@ -36,8 +35,12 @@ ENTRY(exception_handling_table) .long exception_error ! address error load .long exception_error ! address error store /* 100 */ #endif - .long exception_error ! fpu_exception /* 120 */ - .long exception_error /* 140 */ +#if defined(CONFIG_SH_FPU) + .long do_fpu_error /* 120 */ +#else + .long exception_error /* 120 */ +#endif + .long exception_error /* 140 */ .long system_call ! Unconditional Trap /* 160 */ .long exception_error ! reserved_instruction (filled by trap_init) /* 180 */ .long exception_error ! illegal_slot_instruction (filled by trap_init) /*1A0*/ @@ -55,4 +58,4 @@ ENTRY(user_break_point_trap) * away offsets can be manually inserted in to their appropriate * location via set_exception_table_{evt,vec}(). */ - .balign 4096,0,4096 + .balign 4096,0,4096 diff --git a/arch/sh/kernel/cpu/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile index 19ca68c71884..8add10bd8268 100644 --- a/arch/sh/kernel/cpu/sh4/Makefile +++ b/arch/sh/kernel/cpu/sh4/Makefile @@ -2,10 +2,10 @@ # Makefile for the Linux/SuperH SH-4 backends. # -obj-y := ex.o probe.o common.o -common-y += $(addprefix ../sh3/, entry.o) +obj-y := probe.o common.o +common-y += $(addprefix ../sh3/, entry.o ex.o) -obj-$(CONFIG_SH_FPU) += fpu.o +obj-$(CONFIG_SH_FPU) += fpu.o obj-$(CONFIG_SH_STORE_QUEUES) += sq.o # CPU subtype setup diff --git a/arch/sh/kernel/cpu/sh4/ex.S b/arch/sh/kernel/cpu/sh4/ex.S deleted file mode 100644 index ac8ab57413cc..000000000000 --- a/arch/sh/kernel/cpu/sh4/ex.S +++ /dev/null @@ -1,62 +0,0 @@ -/* - * arch/sh/kernel/cpu/sh4/ex.S - * - * The SH-4 exception vector table. - - * Copyright (C) 1999, 2000, 2002 Niibe Yutaka - * Copyright (C) 2003 - 2006 Paul Mundt - * - * 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. - * - */ -#include <linux/linkage.h> - - .align 2 - .data - -ENTRY(exception_handling_table) - .long exception_error /* 000 */ - .long exception_error -#if defined(CONFIG_MMU) - .long tlb_miss_load /* 040 */ - .long tlb_miss_store - .long initial_page_write - .long tlb_protection_violation_load - .long tlb_protection_violation_store - .long address_error_load - .long address_error_store /* 100 */ -#else - .long exception_error ! tlb miss load /* 040 */ - .long exception_error ! tlb miss store - .long exception_error ! initial page write - .long exception_error ! tlb prot violation load - .long exception_error ! tlb prot violation store - .long exception_error ! address error load - .long exception_error ! address error store /* 100 */ -#endif -#if defined(CONFIG_SH_FPU) - .long do_fpu_error /* 120 */ -#else - .long exception_error /* 120 */ -#endif - .long exception_error /* 140 */ - .long system_call ! Unconditional Trap /* 160 */ - .long exception_error ! reserved_instruction (filled by trap_init) /* 180 */ - .long exception_error ! illegal_slot_instruction (filled by trap_init) /*1A0*/ -ENTRY(nmi_slot) -#if defined (CONFIG_KGDB_NMI) - .long debug_enter /* 1C0 */ ! Allow trap to debugger -#else - .long exception_none /* 1C0 */ ! Not implemented yet -#endif -ENTRY(user_break_point_trap) - .long break_point_trap /* 1E0 */ - - /* - * Pad the remainder of the table out, exceptions residing in far - * away offsets can be manually inserted in to their appropriate - * location via set_exception_table_{evt,vec}(). - */ - .balign 4096,0,4096 diff --git a/arch/sh/kernel/cpu/sh4/fpu.c b/arch/sh/kernel/cpu/sh4/fpu.c index 7624677f6628..d61dd599169f 100644 --- a/arch/sh/kernel/cpu/sh4/fpu.c +++ b/arch/sh/kernel/cpu/sh4/fpu.c @@ -16,6 +16,7 @@ #include <linux/sched.h> #include <linux/signal.h> #include <asm/processor.h> +#include <asm/system.h> #include <asm/io.h> /* The PR (precision) bit in the FP Status Register must be clear when @@ -265,7 +266,7 @@ ieee_fpe_handler (struct pt_regs *regs) nextpc = regs->pr; finsn = *(unsigned short *) (regs->pc + 2); } else { - nextpc = regs->pc + 2; + nextpc = regs->pc + instruction_size(insn); finsn = insn; } diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c index 329b3f3051de..6b4f5748d0be 100644 --- a/arch/sh/kernel/process.c +++ b/arch/sh/kernel/process.c @@ -15,9 +15,12 @@ #include <linux/pm.h> #include <linux/kallsyms.h> #include <linux/kexec.h> -#include <asm/kdebug.h> +#include <linux/kdebug.h> +#include <linux/tick.h> #include <asm/uaccess.h> #include <asm/mmu_context.h> +#include <asm/pgalloc.h> +#include <asm/system.h> #include <asm/ubc.h> static int hlt_counter; @@ -58,12 +61,15 @@ void cpu_idle(void) if (!idle) idle = default_idle; + tick_nohz_stop_sched_tick(); while (!need_resched()) idle(); + tick_nohz_restart_sched_tick(); preempt_enable_no_resched(); schedule(); preempt_disable(); + check_pgt_cache(); } } @@ -495,9 +501,9 @@ asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5, struct pt_regs *regs = RELOC_HIDE(&__regs, 0); /* Rewind */ - regs->pc -= 2; + regs->pc -= instruction_size(ctrl_inw(regs->pc - 4)); - if (notify_die(DIE_TRAP, regs, regs->tra & 0xff, + if (notify_die(DIE_TRAP, "debug trap", regs, 0, regs->tra & 0xff, SIGTRAP) == NOTIFY_STOP) return; @@ -514,9 +520,9 @@ asmlinkage void bug_trap_handler(unsigned long r4, unsigned long r5, struct pt_regs *regs = RELOC_HIDE(&__regs, 0); /* Rewind */ - regs->pc -= 2; + regs->pc -= instruction_size(ctrl_inw(regs->pc - 4)); - if (notify_die(DIE_TRAP, regs, TRAPA_BUG_OPCODE & 0xff, + if (notify_die(DIE_TRAP, "bug trap", regs, 0, TRAPA_BUG_OPCODE & 0xff, SIGTRAP) == NOTIFY_STOP) return; diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 477d2a854fc4..c27729135935 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -431,7 +431,7 @@ const char *get_cpu_subtype(struct sh_cpuinfo *c) /* Symbolic CPU flags, keep in sync with asm/cpu-features.h */ static const char *cpu_flags[] = { "none", "fpu", "p2flush", "mmuassoc", "dsp", "perfctr", - "ptea", "llsc", "l2", NULL + "ptea", "llsc", "l2", "op32", NULL }; static void show_cpuflags(struct seq_file *m, struct sh_cpuinfo *c) diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c index fa91641c1f62..c1cfcb9f047c 100644 --- a/arch/sh/kernel/sh_ksyms.c +++ b/arch/sh/kernel/sh_ksyms.c @@ -58,8 +58,6 @@ EXPORT_SYMBOL(__udelay); EXPORT_SYMBOL(__ndelay); EXPORT_SYMBOL(__const_udelay); -EXPORT_SYMBOL(__div64_32); - #define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL(name) /* These symbols are generated by the compiler itself */ diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c index eb0191c374b6..b32c35a7c0a3 100644 --- a/arch/sh/kernel/signal.c +++ b/arch/sh/kernel/signal.c @@ -23,7 +23,7 @@ #include <linux/personality.h> #include <linux/binfmts.h> #include <linux/freezer.h> - +#include <asm/system.h> #include <asm/ucontext.h> #include <asm/uaccess.h> #include <asm/pgtable.h> @@ -500,7 +500,9 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, } /* fallthrough */ case -ERESTARTNOINTR: - regs->pc -= 2; + regs->pc -= instruction_size( + ctrl_inw(regs->pc - 4)); + break; } } else { /* gUSA handling */ @@ -516,7 +518,8 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, regs->regs[15] = regs->regs[1]; if (regs->pc < regs->regs[0]) /* Go to rewind point #1 */ - regs->pc = regs->regs[0] + offset - 2; + regs->pc = regs->regs[0] + offset - + instruction_size(ctrl_inw(regs->pc-4)); } #ifdef CONFIG_PREEMPT local_irq_restore(flags); @@ -600,9 +603,9 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0) regs->regs[0] == -ERESTARTSYS || regs->regs[0] == -ERESTARTNOINTR) { regs->regs[0] = save_r0; - regs->pc -= 2; + regs->pc -= instruction_size(ctrl_inw(regs->pc - 4)); } else if (regs->regs[0] == -ERESTART_RESTARTBLOCK) { - regs->pc -= 2; + regs->pc -= instruction_size(ctrl_inw(regs->pc - 4)); regs->regs[3] = __NR_restart_syscall; } } diff --git a/arch/sh/kernel/stacktrace.c b/arch/sh/kernel/stacktrace.c index 4bdd2f83535d..d41e561be20e 100644 --- a/arch/sh/kernel/stacktrace.c +++ b/arch/sh/kernel/stacktrace.c @@ -17,7 +17,7 @@ /* * Save stack-backtrace addresses into a stack_trace buffer. */ -void save_stack_trace(struct stack_trace *trace, struct task_struct *task) +void save_stack_trace(struct stack_trace *trace) { unsigned long *sp = (unsigned long *)current_stack_pointer; diff --git a/arch/sh/kernel/syscalls.S b/arch/sh/kernel/syscalls.S index 38fc8cd3ea3a..4357d1a6358f 100644 --- a/arch/sh/kernel/syscalls.S +++ b/arch/sh/kernel/syscalls.S @@ -354,3 +354,4 @@ ENTRY(sys_call_table) .long sys_move_pages .long sys_getcpu .long sys_epoll_pwait + .long sys_utimensat /* 320 */ diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c index d47e775962e9..a3a67d151e52 100644 --- a/arch/sh/kernel/time.c +++ b/arch/sh/kernel/time.c @@ -3,7 +3,7 @@ * * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> - * Copyright (C) 2002 - 2006 Paul Mundt + * Copyright (C) 2002 - 2007 Paul Mundt * Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org> * * Some code taken from i386 version. @@ -15,6 +15,7 @@ #include <linux/profile.h> #include <linux/timex.h> #include <linux/sched.h> +#include <linux/clockchips.h> #include <asm/clock.h> #include <asm/rtc.h> #include <asm/timer.h> @@ -38,6 +39,14 @@ static int null_rtc_set_time(const time_t secs) return 0; } +/* + * Null high precision timer functions for systems lacking one. + */ +static cycle_t null_hpt_read(void) +{ + return 0; +} + void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time; int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time; @@ -101,6 +110,7 @@ int do_settimeofday(struct timespec *tv) EXPORT_SYMBOL(do_settimeofday); #endif /* !CONFIG_GENERIC_TIME */ +#ifndef CONFIG_GENERIC_CLOCKEVENTS /* last time the RTC clock got updated */ static long last_rtc_update; @@ -138,6 +148,7 @@ void handle_timer_tick(void) last_rtc_update = xtime.tv_sec - 600; } } +#endif /* !CONFIG_GENERIC_CLOCKEVENTS */ #ifdef CONFIG_PM int timer_suspend(struct sys_device *dev, pm_message_t state) @@ -168,136 +179,58 @@ static struct sysdev_class timer_sysclass = { .resume = timer_resume, }; -#ifdef CONFIG_NO_IDLE_HZ -static int timer_dyn_tick_enable(void) +static int __init timer_init_sysfs(void) { - struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick; - unsigned long flags; - int ret = -ENODEV; - - if (dyn_tick) { - spin_lock_irqsave(&dyn_tick->lock, flags); - ret = 0; - if (!(dyn_tick->state & DYN_TICK_ENABLED)) { - ret = dyn_tick->enable(); - - if (ret == 0) - dyn_tick->state |= DYN_TICK_ENABLED; - } - spin_unlock_irqrestore(&dyn_tick->lock, flags); - } + int ret = sysdev_class_register(&timer_sysclass); + if (ret != 0) + return ret; - return ret; + sys_timer->dev.cls = &timer_sysclass; + return sysdev_register(&sys_timer->dev); } +device_initcall(timer_init_sysfs); -static int timer_dyn_tick_disable(void) -{ - struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick; - unsigned long flags; - int ret = -ENODEV; - - if (dyn_tick) { - spin_lock_irqsave(&dyn_tick->lock, flags); - ret = 0; - if (dyn_tick->state & DYN_TICK_ENABLED) { - ret = dyn_tick->disable(); - - if (ret == 0) - dyn_tick->state &= ~DYN_TICK_ENABLED; - } - spin_unlock_irqrestore(&dyn_tick->lock, flags); - } - - return ret; -} +void (*board_time_init)(void); /* - * Reprogram the system timer for at least the calculated time interval. - * This function should be called from the idle thread with IRQs disabled, - * immediately before sleeping. + * Shamelessly based on the MIPS and Sparc64 work. */ -void timer_dyn_reprogram(void) -{ - struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick; - unsigned long next, seq, flags; - - if (!dyn_tick) - return; - - spin_lock_irqsave(&dyn_tick->lock, flags); - if (dyn_tick->state & DYN_TICK_ENABLED) { - next = next_timer_interrupt(); - do { - seq = read_seqbegin(&xtime_lock); - dyn_tick->reprogram(next - jiffies); - } while (read_seqretry(&xtime_lock, seq)); - } - spin_unlock_irqrestore(&dyn_tick->lock, flags); -} +static unsigned long timer_ticks_per_nsec_quotient __read_mostly; +unsigned long sh_hpt_frequency = 0; + +#define NSEC_PER_CYC_SHIFT 10 + +struct clocksource clocksource_sh = { + .name = "SuperH", + .rating = 200, + .mask = CLOCKSOURCE_MASK(32), + .read = null_hpt_read, + .shift = 16, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; -static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf) +static void __init init_sh_clocksource(void) { - return sprintf(buf, "%i\n", - (sys_timer->dyn_tick->state & DYN_TICK_ENABLED) >> 1); -} + if (!sh_hpt_frequency || clocksource_sh.read == null_hpt_read) + return; -static ssize_t timer_set_dyn_tick(struct sys_device *dev, const char *buf, - size_t count) -{ - unsigned int enable = simple_strtoul(buf, NULL, 2); + clocksource_sh.mult = clocksource_hz2mult(sh_hpt_frequency, + clocksource_sh.shift); - if (enable) - timer_dyn_tick_enable(); - else - timer_dyn_tick_disable(); + timer_ticks_per_nsec_quotient = + clocksource_hz2mult(sh_hpt_frequency, NSEC_PER_CYC_SHIFT); - return count; + clocksource_register(&clocksource_sh); } -static SYSDEV_ATTR(dyn_tick, 0644, timer_show_dyn_tick, timer_set_dyn_tick); -/* - * dyntick=enable|disable - */ -static char dyntick_str[4] __initdata = ""; - -static int __init dyntick_setup(char *str) +#ifdef CONFIG_GENERIC_TIME +unsigned long long sched_clock(void) { - if (str) - strlcpy(dyntick_str, str, sizeof(dyntick_str)); - return 1; + unsigned long long ticks = clocksource_sh.read(); + return (ticks * timer_ticks_per_nsec_quotient) >> NSEC_PER_CYC_SHIFT; } - -__setup("dyntick=", dyntick_setup); -#endif - -static int __init timer_init_sysfs(void) -{ - int ret = sysdev_class_register(&timer_sysclass); - if (ret != 0) - return ret; - - sys_timer->dev.cls = &timer_sysclass; - ret = sysdev_register(&sys_timer->dev); - -#ifdef CONFIG_NO_IDLE_HZ - if (ret == 0 && sys_timer->dyn_tick) { - ret = sysdev_create_file(&sys_timer->dev, &attr_dyn_tick); - - /* - * Turn on dynamic tick after calibrate delay - * for correct bogomips - */ - if (ret == 0 && dyntick_str[0] == 'e') - ret = timer_dyn_tick_enable(); - } #endif - return ret; -} -device_initcall(timer_init_sysfs); - -void (*board_time_init)(void); - void __init time_init(void) { if (board_time_init) @@ -316,10 +249,15 @@ void __init time_init(void) sys_timer = get_sys_timer(); printk(KERN_INFO "Using %s for system timer\n", sys_timer->name); -#ifdef CONFIG_NO_IDLE_HZ - if (sys_timer->dyn_tick) - spin_lock_init(&sys_timer->dyn_tick->lock); -#endif + if (sys_timer->ops->read) + clocksource_sh.read = sys_timer->ops->read; + + init_sh_clocksource(); + + if (sh_hpt_frequency) + printk("Using %lu.%03lu MHz high precision timer.\n", + ((sh_hpt_frequency + 500) / 1000) / 1000, + ((sh_hpt_frequency + 500) / 1000) % 1000); #if defined(CONFIG_SH_KGDB) /* diff --git a/arch/sh/kernel/timers/timer-tmu.c b/arch/sh/kernel/timers/timer-tmu.c index d9e3151c891e..2d997e2a5b6c 100644 --- a/arch/sh/kernel/timers/timer-tmu.c +++ b/arch/sh/kernel/timers/timer-tmu.c @@ -1,7 +1,7 @@ /* * arch/sh/kernel/timers/timer-tmu.c - TMU Timer Support * - * Copyright (C) 2005 Paul Mundt + * Copyright (C) 2005 - 2007 Paul Mundt * * TMU handling code hacked out of arch/sh/kernel/time.c * @@ -18,6 +18,7 @@ #include <linux/kernel.h> #include <linux/interrupt.h> #include <linux/seqlock.h> +#include <linux/clockchips.h> #include <asm/timer.h> #include <asm/rtc.h> #include <asm/io.h> @@ -25,56 +26,75 @@ #include <asm/clock.h> #define TMU_TOCR_INIT 0x00 -#define TMU0_TCR_INIT 0x0020 -#define TMU_TSTR_INIT 1 +#define TMU_TCR_INIT 0x0020 -#define TMU0_TCR_CALIB 0x0000 +static int tmu_timer_start(void) +{ + ctrl_outb(ctrl_inb(TMU_TSTR) | 0x3, TMU_TSTR); + return 0; +} -static unsigned long tmu_timer_get_offset(void) +static void tmu0_timer_set_interval(unsigned long interval, unsigned int reload) { - int count; - static int count_p = 0x7fffffff; /* for the first call after boot */ - static unsigned long jiffies_p = 0; + ctrl_outl(interval, TMU0_TCNT); /* - * cache volatile jiffies temporarily; we have IRQs turned off. + * TCNT reloads from TCOR on underflow, clear it if we don't + * intend to auto-reload */ - unsigned long jiffies_t; + if (reload) + ctrl_outl(interval, TMU0_TCOR); + else + ctrl_outl(0, TMU0_TCOR); - /* timer count may underflow right here */ - count = ctrl_inl(TMU0_TCNT); /* read the latched count */ + tmu_timer_start(); +} - jiffies_t = jiffies; +static int tmu_timer_stop(void) +{ + ctrl_outb(ctrl_inb(TMU_TSTR) & ~0x3, TMU_TSTR); + return 0; +} - /* - * avoiding timer inconsistencies (they are rare, but they happen)... - * there is one kind of problem that must be avoided here: - * 1. the timer counter underflows - */ +static cycle_t tmu_timer_read(void) +{ + return ~ctrl_inl(TMU1_TCNT); +} + +static int tmu_set_next_event(unsigned long cycles, + struct clock_event_device *evt) +{ + tmu0_timer_set_interval(cycles, 1); + return 0; +} - if (jiffies_t == jiffies_p) { - if (count > count_p) { - /* the nutcase */ - if (ctrl_inw(TMU0_TCR) & 0x100) { /* Check UNF bit */ - count -= LATCH; - } else { - printk("%s (): hardware timer problem?\n", - __FUNCTION__); - } - } - } else - jiffies_p = jiffies_t; - - count_p = count; - - count = ((LATCH-1) - count) * TICK_SIZE; - count = (count + LATCH/2) / LATCH; - - return count; +static void tmu_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + ctrl_outl(ctrl_inl(TMU0_TCNT), TMU0_TCOR); + break; + case CLOCK_EVT_MODE_ONESHOT: + ctrl_outl(0, TMU0_TCOR); + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + break; + } } +static struct clock_event_device tmu0_clockevent = { + .name = "tmu0", + .shift = 32, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = tmu_set_mode, + .set_next_event = tmu_set_next_event, +}; + static irqreturn_t tmu_timer_interrupt(int irq, void *dummy) { + struct clock_event_device *evt = &tmu0_clockevent; unsigned long timer_status; /* Clear UNF bit */ @@ -82,72 +102,76 @@ static irqreturn_t tmu_timer_interrupt(int irq, void *dummy) timer_status &= ~0x100; ctrl_outw(timer_status, TMU0_TCR); - /* - * Here we are in the timer irq handler. We just have irqs locally - * disabled but we don't know if the timer_bh is running on the other - * CPU. We need to avoid to SMP race with it. NOTE: we don' t need - * the irq version of write_lock because as just said we have irq - * locally disabled. -arca - */ - write_seqlock(&xtime_lock); - handle_timer_tick(); - write_sequnlock(&xtime_lock); + evt->event_handler(evt); return IRQ_HANDLED; } -static struct irqaction tmu_irq = { - .name = "timer", +static struct irqaction tmu0_irq = { + .name = "periodic timer", .handler = tmu_timer_interrupt, .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .mask = CPU_MASK_NONE, }; -static void tmu_clk_init(struct clk *clk) +static void tmu0_clk_init(struct clk *clk) { - u8 divisor = TMU0_TCR_INIT & 0x7; - ctrl_outw(TMU0_TCR_INIT, TMU0_TCR); + u8 divisor = TMU_TCR_INIT & 0x7; + ctrl_outw(TMU_TCR_INIT, TMU0_TCR); clk->rate = clk->parent->rate / (4 << (divisor << 1)); } -static void tmu_clk_recalc(struct clk *clk) +static void tmu0_clk_recalc(struct clk *clk) { u8 divisor = ctrl_inw(TMU0_TCR) & 0x7; clk->rate = clk->parent->rate / (4 << (divisor << 1)); } -static struct clk_ops tmu_clk_ops = { - .init = tmu_clk_init, - .recalc = tmu_clk_recalc, +static struct clk_ops tmu0_clk_ops = { + .init = tmu0_clk_init, + .recalc = tmu0_clk_recalc, }; static struct clk tmu0_clk = { .name = "tmu0_clk", - .ops = &tmu_clk_ops, + .ops = &tmu0_clk_ops, }; -static int tmu_timer_start(void) +static void tmu1_clk_init(struct clk *clk) { - ctrl_outb(TMU_TSTR_INIT, TMU_TSTR); - return 0; + u8 divisor = TMU_TCR_INIT & 0x7; + ctrl_outw(divisor, TMU1_TCR); + clk->rate = clk->parent->rate / (4 << (divisor << 1)); } -static int tmu_timer_stop(void) +static void tmu1_clk_recalc(struct clk *clk) { - ctrl_outb(0, TMU_TSTR); - return 0; + u8 divisor = ctrl_inw(TMU1_TCR) & 0x7; + clk->rate = clk->parent->rate / (4 << (divisor << 1)); } +static struct clk_ops tmu1_clk_ops = { + .init = tmu1_clk_init, + .recalc = tmu1_clk_recalc, +}; + +static struct clk tmu1_clk = { + .name = "tmu1_clk", + .ops = &tmu1_clk_ops, +}; + static int tmu_timer_init(void) { unsigned long interval; + unsigned long frequency; - setup_irq(CONFIG_SH_TIMER_IRQ, &tmu_irq); + setup_irq(CONFIG_SH_TIMER_IRQ, &tmu0_irq); tmu0_clk.parent = clk_get(NULL, "module_clk"); + tmu1_clk.parent = clk_get(NULL, "module_clk"); - /* Start TMU0 */ tmu_timer_stop(); + #if !defined(CONFIG_CPU_SUBTYPE_SH7300) && \ !defined(CONFIG_CPU_SUBTYPE_SH7760) && \ !defined(CONFIG_CPU_SUBTYPE_SH7785) @@ -155,15 +179,29 @@ static int tmu_timer_init(void) #endif clk_register(&tmu0_clk); + clk_register(&tmu1_clk); clk_enable(&tmu0_clk); + clk_enable(&tmu1_clk); - interval = (clk_get_rate(&tmu0_clk) + HZ / 2) / HZ; - printk(KERN_INFO "Interval = %ld\n", interval); + frequency = clk_get_rate(&tmu0_clk); + interval = (frequency + HZ / 2) / HZ; - ctrl_outl(interval, TMU0_TCOR); - ctrl_outl(interval, TMU0_TCNT); + sh_hpt_frequency = clk_get_rate(&tmu1_clk); + ctrl_outl(~0, TMU1_TCNT); + ctrl_outl(~0, TMU1_TCOR); - tmu_timer_start(); + tmu0_timer_set_interval(interval, 1); + + tmu0_clockevent.mult = div_sc(frequency, NSEC_PER_SEC, + tmu0_clockevent.shift); + tmu0_clockevent.max_delta_ns = + clockevent_delta2ns(-1, &tmu0_clockevent); + tmu0_clockevent.min_delta_ns = + clockevent_delta2ns(1, &tmu0_clockevent); + + tmu0_clockevent.cpumask = cpumask_of_cpu(0); + + clockevents_register_device(&tmu0_clockevent); return 0; } @@ -172,9 +210,7 @@ struct sys_timer_ops tmu_timer_ops = { .init = tmu_timer_init, .start = tmu_timer_start, .stop = tmu_timer_stop, -#ifndef CONFIG_GENERIC_TIME - .get_offset = tmu_timer_get_offset, -#endif + .read = tmu_timer_read, }; struct sys_timer tmu_timer = { diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c index 7b40f0ff3dfc..3a197649cd83 100644 --- a/arch/sh/kernel/traps.c +++ b/arch/sh/kernel/traps.c @@ -20,10 +20,10 @@ #include <linux/io.h> #include <linux/bug.h> #include <linux/debug_locks.h> +#include <linux/kdebug.h> #include <linux/limits.h> #include <asm/system.h> #include <asm/uaccess.h> -#include <asm/kdebug.h> #ifdef CONFIG_SH_KGDB #include <asm/kgdb.h> @@ -76,20 +76,6 @@ static void dump_mem(const char *str, unsigned long bottom, unsigned long top) } } -ATOMIC_NOTIFIER_HEAD(shdie_chain); - -int register_die_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&shdie_chain, nb); -} -EXPORT_SYMBOL(register_die_notifier); - -int unregister_die_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&shdie_chain, nb); -} -EXPORT_SYMBOL(unregister_die_notifier); - static DEFINE_SPINLOCK(die_lock); void die(const char * str, struct pt_regs * regs, long err) @@ -505,7 +491,7 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) simple: ret = handle_unaligned_ins(instruction,regs); if (ret==0) - regs->pc += 2; + regs->pc += instruction_size(instruction); return ret; } #endif /* CONFIG_CPU_SH2A */ @@ -682,7 +668,7 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5, err = do_fpu_inst(inst, regs); if (!err) { - regs->pc += 2; + regs->pc += instruction_size(inst); return; } /* not a FPU inst. */ diff --git a/arch/sh/lib/delay.c b/arch/sh/lib/delay.c index 351714694d6d..f3ddd2133e6f 100644 --- a/arch/sh/lib/delay.c +++ b/arch/sh/lib/delay.c @@ -24,9 +24,10 @@ inline void __const_udelay(unsigned long xloops) __asm__("dmulu.l %0, %2\n\t" "sts mach, %0" : "=r" (xloops) - : "0" (xloops), "r" (cpu_data[raw_smp_processor_id()].loops_per_jiffy) + : "0" (xloops), + "r" (HZ * cpu_data[raw_smp_processor_id()].loops_per_jiffy) : "macl", "mach"); - __delay(xloops * HZ); + __delay(xloops); } void __udelay(unsigned long usecs) diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig index 12f3d394dc28..253346d7b316 100644 --- a/arch/sh/mm/Kconfig +++ b/arch/sh/mm/Kconfig @@ -218,6 +218,9 @@ endmenu menu "Memory management options" +config QUICKLIST + def_bool y + config MMU bool "Support for memory management hardware" depends on !CPU_SH2 @@ -300,6 +303,10 @@ config NODES_SHIFT config ARCH_FLATMEM_ENABLE def_bool y +config MAX_ACTIVE_REGIONS + int + default "1" + config ARCH_POPULATES_NODE_MAP def_bool y diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c index 0ecc117cade4..9207da67ff8a 100644 --- a/arch/sh/mm/fault.c +++ b/arch/sh/mm/fault.c @@ -15,7 +15,7 @@ #include <linux/mm.h> #include <linux/hardirq.h> #include <linux/kprobes.h> -#include <asm/kdebug.h> +#include <linux/kdebug.h> #include <asm/system.h> #include <asm/mmu_context.h> #include <asm/tlbflush.h> diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 4d030988b368..8fe223a890ed 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -67,6 +67,8 @@ void show_mem(void) printk("%d slab pages\n", slab); printk("%d pages shared\n", shared); printk("%d pages swap cached\n", cached); + printk(KERN_INFO "Total of %ld pages in page table cache\n", + quicklist_total_size()); } #ifdef CONFIG_MMU diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 6abf4811958c..e0f91dfce0f5 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -104,7 +104,7 @@ static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id) writeb(tmp, rtc->regbase + RCR1); - rtc_update_irq(&rtc->rtc_dev, 1, events); + rtc_update_irq(rtc->rtc_dev, 1, events); spin_unlock(&rtc->lock); @@ -139,7 +139,7 @@ static irqreturn_t sh_rtc_alarm(int irq, void *dev_id) rtc->rearm_aie = 1; - rtc_update_irq(&rtc->rtc_dev, 1, events); + rtc_update_irq(rtc->rtc_dev, 1, events); } spin_unlock(&rtc->lock); @@ -153,7 +153,7 @@ static irqreturn_t sh_rtc_periodic(int irq, void *dev_id) spin_lock(&rtc->lock); - rtc_update_irq(&rtc->rtc_dev, 1, RTC_PF | RTC_IRQF); + rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF); spin_unlock(&rtc->lock); @@ -341,7 +341,7 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_sec--; #endif - dev_dbg(&dev, "%s: tm is secs=%d, mins=%d, hours=%d, " + dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__, tm->tm_sec, tm->tm_min, tm->tm_hour, diff --git a/include/asm-sh/bug.h b/include/asm-sh/bug.h index 794c36daf06d..46f925c815ac 100644 --- a/include/asm-sh/bug.h +++ b/include/asm-sh/bug.h @@ -1,12 +1,12 @@ #ifndef __ASM_SH_BUG_H #define __ASM_SH_BUG_H +#define TRAPA_BUG_OPCODE 0xc33e /* trapa #0x3e */ + #ifdef CONFIG_BUG #define HAVE_ARCH_BUG #define HAVE_ARCH_WARN_ON -#define TRAPA_BUG_OPCODE 0xc33e /* trapa #0x3e */ - /** * _EMIT_BUG_ENTRY * %1 - __FILE__ diff --git a/include/asm-sh/cpu-features.h b/include/asm-sh/cpu-features.h index 4bccd7c032f9..86308aa39731 100644 --- a/include/asm-sh/cpu-features.h +++ b/include/asm-sh/cpu-features.h @@ -20,5 +20,6 @@ #define CPU_HAS_PTEA 0x0020 /* PTEA register */ #define CPU_HAS_LLSC 0x0040 /* movli.l/movco.l */ #define CPU_HAS_L2_CACHE 0x0080 /* Secondary cache / URAM */ +#define CPU_HAS_OP32 0x0100 /* 32-bit instruction support */ #endif /* __ASM_SH_CPU_FEATURES_H */ diff --git a/include/asm-sh/dmabrg.h b/include/asm-sh/dmabrg.h new file mode 100644 index 000000000000..c5edba216cf1 --- /dev/null +++ b/include/asm-sh/dmabrg.h @@ -0,0 +1,23 @@ +/* + * SH7760 DMABRG (USB/Audio) support + */ + +#ifndef _DMABRG_H_ +#define _DMABRG_H_ + +/* IRQ sources */ +#define DMABRGIRQ_USBDMA 0 +#define DMABRGIRQ_USBDMAERR 1 +#define DMABRGIRQ_A0TXF 2 +#define DMABRGIRQ_A0TXH 3 +#define DMABRGIRQ_A0RXF 4 +#define DMABRGIRQ_A0RXH 5 +#define DMABRGIRQ_A1TXF 6 +#define DMABRGIRQ_A1TXH 7 +#define DMABRGIRQ_A1RXF 8 +#define DMABRGIRQ_A1RXH 9 + +extern int dmabrg_request_irq(unsigned int, void(*)(void *), void *); +extern void dmabrg_free_irq(unsigned int); + +#endif diff --git a/include/asm-sh/kdebug.h b/include/asm-sh/kdebug.h index 493c20629747..16578b7c9da1 100644 --- a/include/asm-sh/kdebug.h +++ b/include/asm-sh/kdebug.h @@ -2,20 +2,6 @@ #define __ASM_SH_KDEBUG_H #include <linux/notifier.h> -#include <asm-generic/kdebug.h> - -struct pt_regs; - -struct die_args { - struct pt_regs *regs; - int trapnr; -}; - -int register_die_notifier(struct notifier_block *nb); -int unregister_die_notifier(struct notifier_block *nb); -int register_page_fault_notifier(struct notifier_block *nb); -int unregister_page_fault_notifier(struct notifier_block *nb); -extern struct atomic_notifier_head shdie_chain; /* Grossly misnamed. */ enum die_val { @@ -23,14 +9,7 @@ enum die_val { DIE_PAGE_FAULT, }; -static inline int notify_die(enum die_val val, struct pt_regs *regs, - int trap, int sig) -{ - struct die_args args = { - .regs = regs, - .trapnr = trap, - }; +int register_page_fault_notifier(struct notifier_block *nb); +int unregister_page_fault_notifier(struct notifier_block *nb); - return atomic_notifier_call_chain(&shdie_chain, val, &args); -} #endif /* __ASM_SH_KDEBUG_H */ diff --git a/include/asm-sh/pgalloc.h b/include/asm-sh/pgalloc.h index 888e4529e6fe..18b613c57cf5 100644 --- a/include/asm-sh/pgalloc.h +++ b/include/asm-sh/pgalloc.h @@ -1,6 +1,12 @@ #ifndef __ASM_SH_PGALLOC_H #define __ASM_SH_PGALLOC_H +#include <linux/quicklist.h> +#include <asm/page.h> + +#define QUICK_PGD 0 /* We preserve special mappings over free */ +#define QUICK_PT 1 /* Other page table pages that are zero on free */ + static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte) { @@ -13,48 +19,49 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, set_pmd(pmd, __pmd((unsigned long)page_address(pte))); } +static inline void pgd_ctor(void *x) +{ + pgd_t *pgd = x; + + memcpy(pgd + USER_PTRS_PER_PGD, + swapper_pg_dir + USER_PTRS_PER_PGD, + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); +} + /* * Allocate and free page tables. */ static inline pgd_t *pgd_alloc(struct mm_struct *mm) { - pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT); - - if (pgd) { - memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); - memcpy(pgd + USER_PTRS_PER_PGD, - swapper_pg_dir + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); - } - - return pgd; + return quicklist_alloc(QUICK_PGD, GFP_KERNEL | __GFP_REPEAT, pgd_ctor); } static inline void pgd_free(pgd_t *pgd) { - free_page((unsigned long)pgd); + quicklist_free(QUICK_PGD, NULL, pgd); } static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) { - return (pte_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO); + return quicklist_alloc(QUICK_PT, GFP_KERNEL | __GFP_REPEAT, NULL); } static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) { - return alloc_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO); + void *pg = quicklist_alloc(QUICK_PT, GFP_KERNEL | __GFP_REPEAT, NULL); + return pg ? virt_to_page(pg) : NULL; } static inline void pte_free_kernel(pte_t *pte) { - free_page((unsigned long)pte); + quicklist_free(QUICK_PT, NULL, pte); } static inline void pte_free(struct page *pte) { - __free_page(pte); + quicklist_free_page(QUICK_PT, NULL, pte); } #define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) @@ -66,6 +73,11 @@ static inline void pte_free(struct page *pte) #define pmd_free(x) do { } while (0) #define __pmd_free_tlb(tlb,x) do { } while (0) -#define check_pgt_cache() do { } while (0) + +static inline void check_pgt_cache(void) +{ + quicklist_trim(QUICK_PGD, NULL, 25, 16); + quicklist_trim(QUICK_PT, NULL, 25, 16); +} #endif /* __ASM_SH_PGALLOC_H */ diff --git a/include/asm-sh/system.h b/include/asm-sh/system.h index e7e96ee0c8a5..82f3e229e621 100644 --- a/include/asm-sh/system.h +++ b/include/asm-sh/system.h @@ -255,6 +255,15 @@ static inline void *set_exception_table_evt(unsigned int evt, void *handler) return set_exception_table_vec(evt >> 5, handler); } +/* + * SH-2A has both 16 and 32-bit opcodes, do lame encoding checks. + */ +#ifdef CONFIG_CPU_SH2A +extern unsigned int instruction_size(unsigned int insn); +#else +#define instruction_size(insn) (2) +#endif + /* XXX * disable hlt during certain critical i/o operations */ diff --git a/include/asm-sh/timer.h b/include/asm-sh/timer.h index 17b5e76a4c31..701ba84c7049 100644 --- a/include/asm-sh/timer.h +++ b/include/asm-sh/timer.h @@ -2,12 +2,14 @@ #define __ASM_SH_TIMER_H #include <linux/sysdev.h> +#include <linux/clocksource.h> #include <asm/cpu/timer.h> struct sys_timer_ops { int (*init)(void); int (*start)(void); int (*stop)(void); + cycle_t (*read)(void); #ifndef CONFIG_GENERIC_TIME unsigned long (*get_offset)(void); #endif @@ -18,29 +20,8 @@ struct sys_timer { struct sys_device dev; struct sys_timer_ops *ops; - -#ifdef CONFIG_NO_IDLE_HZ - struct dyn_tick_timer *dyn_tick; -#endif }; -#ifdef CONFIG_NO_IDLE_HZ -#define DYN_TICK_ENABLED (1 << 1) - -struct dyn_tick_timer { - spinlock_t lock; - unsigned int state; /* Current state */ - int (*enable)(void); /* Enables dynamic tick */ - int (*disable)(void); /* Disables dynamic tick */ - void (*reprogram)(unsigned long); /* Reprograms the timer */ - int (*handler)(int, void *); -}; - -void timer_dyn_reprogram(void); -#else -#define timer_dyn_reprogram() do { } while (0) -#endif - #define TICK_SIZE (tick_nsec / 1000) extern struct sys_timer tmu_timer, cmt_timer, mtu2_timer; @@ -58,5 +39,7 @@ struct sys_timer *get_sys_timer(void); /* arch/sh/kernel/time.c */ void handle_timer_tick(void); +extern unsigned long sh_hpt_frequency; +extern struct clocksource clocksource_sh; #endif /* __ASM_SH_TIMER_H */ diff --git a/include/asm-sh/unistd.h b/include/asm-sh/unistd.h index 49be50a36b77..af71e379a5ee 100644 --- a/include/asm-sh/unistd.h +++ b/include/asm-sh/unistd.h @@ -85,7 +85,7 @@ #define __NR_sigpending 73 #define __NR_sethostname 74 #define __NR_setrlimit 75 -#define __NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */ +#define __NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */ #define __NR_getrusage 77 #define __NR_gettimeofday 78 #define __NR_settimeofday 79 @@ -328,8 +328,9 @@ #define __NR_move_pages 317 #define __NR_getcpu 318 #define __NR_epoll_pwait 319 +#define __NR_utimensat 320 -#define NR_syscalls 320 +#define NR_syscalls 321 #ifdef __KERNEL__ diff --git a/mm/Kconfig b/mm/Kconfig index 1ac718f636ec..a17da8bafe62 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -166,5 +166,5 @@ config ZONE_DMA_FLAG config NR_QUICK int depends on QUICKLIST + default "2" if SUPERH default "1" - |