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.
This commit is contained in:
Linus Torvalds 2007-05-09 13:08:20 -07:00
commit d84c4124c4
36 changed files with 586 additions and 412 deletions

View File

@ -52,6 +52,9 @@ config GENERIC_IOMAP
config GENERIC_TIME config GENERIC_TIME
def_bool n def_bool n
config GENERIC_CLOCKEVENTS
def_bool n
config SYS_SUPPORTS_APM_EMULATION config SYS_SUPPORTS_APM_EMULATION
bool bool
@ -436,11 +439,11 @@ endmenu
menu "Timer and clock configuration" menu "Timer and clock configuration"
if !GENERIC_TIME
config SH_TMU config SH_TMU
bool "TMU timer support" bool "TMU timer support"
depends on CPU_SH3 || CPU_SH4 depends on CPU_SH3 || CPU_SH4
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
default y default y
help help
This enables the use of the TMU as the system timer. This enables the use of the TMU as the system timer.
@ -459,8 +462,6 @@ config SH_MTU2
help help
This enables the use of the MTU2 as the system timer. This enables the use of the MTU2 as the system timer.
endif
config SH_TIMER_IRQ config SH_TIMER_IRQ
int int
default "28" if CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785 default "28" if CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785
@ -468,24 +469,6 @@ config SH_TIMER_IRQ
default "140" if CPU_SUBTYPE_SH7206 default "140" if CPU_SUBTYPE_SH7206
default "16" 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 config SH_PCLK_FREQ
int "Peripheral clock frequency (in Hz)" int "Peripheral clock frequency (in Hz)"
default "27000000" if CPU_SUBTYPE_SH73180 || CPU_SUBTYPE_SH7343 default "27000000" if CPU_SUBTYPE_SH73180 || CPU_SUBTYPE_SH7343
@ -509,6 +492,8 @@ config SH_CLK_MD
help help
MD2 - MD0 pin setting. MD2 - MD0 pin setting.
source "kernel/time/Kconfig"
endmenu endmenu
menu "CPU Frequency scaling" menu "CPU Frequency scaling"

View File

@ -93,6 +93,7 @@ static void __init landisk_setup(char **cmdline_p)
*/ */
struct sh_machine_vector mv_landisk __initmv = { struct sh_machine_vector mv_landisk __initmv = {
.mv_name = "LANDISK", .mv_name = "LANDISK",
.mv_nr_irqs = 72,
.mv_setup = landisk_setup, .mv_setup = landisk_setup,
.mv_init_irq = init_landisk_IRQ, .mv_init_irq = init_landisk_IRQ,
}; };

View File

@ -2,8 +2,9 @@
# Makefile for the Linux SuperH-specific device drivers. # Makefile for the Linux SuperH-specific device drivers.
# #
obj-y += dma/
obj-$(CONFIG_PCI) += pci/ obj-$(CONFIG_PCI) += pci/
obj-$(CONFIG_SH_DMA) += dma/
obj-$(CONFIG_SUPERHYWAY) += superhyway/ obj-$(CONFIG_SUPERHYWAY) += superhyway/
obj-$(CONFIG_PUSH_SWITCH) += push-switch.o obj-$(CONFIG_PUSH_SWITCH) += push-switch.o
obj-$(CONFIG_HEARTBEAT) += heartbeat.o obj-$(CONFIG_HEARTBEAT) += heartbeat.o

View File

@ -1,12 +1,12 @@
menu "DMA support" menu "DMA support"
config SH_DMA config SH_DMA_API
bool "DMA controller (DMAC) support" bool
help
Selecting this option will provide same API as PC's Direct Memory
Access Controller(8237A) for SuperH DMAC.
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 config NR_ONCHIP_DMA_CHANNELS
depends on SH_DMA 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 in case channel 3 is unavailable. On the SH4, channels 1,2, and 3
are dual-address capable. 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 endmenu

View File

@ -2,8 +2,8 @@
# Makefile for the SuperH DMA specific kernel interface routines under Linux. # 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_ISA_DMA_API) += dma-isa.o
obj-$(CONFIG_SYSFS) += dma-sysfs.o
obj-$(CONFIG_SH_DMA) += dma-sh.o obj-$(CONFIG_SH_DMA) += dma-sh.o
obj-$(CONFIG_SH_DREAMCAST) += dma-pvr2.o dma-g2.o obj-$(CONFIG_SH_DREAMCAST) += dma-pvr2.o dma-g2.o
obj-$(CONFIG_SH_DMABRG) += dmabrg.o

View File

@ -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);

View File

@ -2,9 +2,8 @@
# Makefile for the Linux/SuperH SH-2A backends. # 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/, ex.o entry.o)
common-y += $(addprefix ../sh2/, entry.o)
obj-$(CONFIG_CPU_SUBTYPE_SH7206) += setup-sh7206.o clock-sh7206.o obj-$(CONFIG_CPU_SUBTYPE_SH7206) += setup-sh7206.o clock-sh7206.o

View File

@ -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;
}

View File

@ -18,6 +18,7 @@ int __init detect_cpu_and_cache_system(void)
{ {
/* Just SH7206 for now .. */ /* Just SH7206 for now .. */
current_cpu_data.type = CPU_SH7206; current_cpu_data.type = CPU_SH7206;
current_cpu_data.flags |= CPU_HAS_OP32;
current_cpu_data.dcache.ways = 4; current_cpu_data.dcache.ways = 4;
current_cpu_data.dcache.way_incr = (1 << 11); current_cpu_data.dcache.way_incr = (1 << 11);

View File

@ -1,7 +1,7 @@
/* /*
* arch/sh/kernel/cpu/sh3/ex.S * 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) 1999, 2000, 2002 Niibe Yutaka
* Copyright (C) 2003 - 2006 Paul Mundt * Copyright (C) 2003 - 2006 Paul Mundt
@ -9,7 +9,6 @@
* This file is subject to the terms and conditions of the GNU General Public * 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 * License. See the file "COPYING" in the main directory of this archive
* for more details. * for more details.
*
*/ */
#include <linux/linkage.h> #include <linux/linkage.h>
@ -36,8 +35,12 @@ ENTRY(exception_handling_table)
.long exception_error ! address error load .long exception_error ! address error load
.long exception_error ! address error store /* 100 */ .long exception_error ! address error store /* 100 */
#endif #endif
.long exception_error ! fpu_exception /* 120 */ #if defined(CONFIG_SH_FPU)
.long exception_error /* 140 */ .long do_fpu_error /* 120 */
#else
.long exception_error /* 120 */
#endif
.long exception_error /* 140 */
.long system_call ! Unconditional Trap /* 160 */ .long system_call ! Unconditional Trap /* 160 */
.long exception_error ! reserved_instruction (filled by trap_init) /* 180 */ .long exception_error ! reserved_instruction (filled by trap_init) /* 180 */
.long exception_error ! illegal_slot_instruction (filled by trap_init) /*1A0*/ .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 * away offsets can be manually inserted in to their appropriate
* location via set_exception_table_{evt,vec}(). * location via set_exception_table_{evt,vec}().
*/ */
.balign 4096,0,4096 .balign 4096,0,4096

View File

@ -2,10 +2,10 @@
# Makefile for the Linux/SuperH SH-4 backends. # Makefile for the Linux/SuperH SH-4 backends.
# #
obj-y := ex.o probe.o common.o obj-y := probe.o common.o
common-y += $(addprefix ../sh3/, entry.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 obj-$(CONFIG_SH_STORE_QUEUES) += sq.o
# CPU subtype setup # CPU subtype setup

View File

@ -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

View File

@ -16,6 +16,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/signal.h> #include <linux/signal.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/system.h>
#include <asm/io.h> #include <asm/io.h>
/* The PR (precision) bit in the FP Status Register must be clear when /* 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; nextpc = regs->pr;
finsn = *(unsigned short *) (regs->pc + 2); finsn = *(unsigned short *) (regs->pc + 2);
} else { } else {
nextpc = regs->pc + 2; nextpc = regs->pc + instruction_size(insn);
finsn = insn; finsn = insn;
} }

View File

@ -15,9 +15,12 @@
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <linux/kexec.h> #include <linux/kexec.h>
#include <asm/kdebug.h> #include <linux/kdebug.h>
#include <linux/tick.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <asm/pgalloc.h>
#include <asm/system.h>
#include <asm/ubc.h> #include <asm/ubc.h>
static int hlt_counter; static int hlt_counter;
@ -58,12 +61,15 @@ void cpu_idle(void)
if (!idle) if (!idle)
idle = default_idle; idle = default_idle;
tick_nohz_stop_sched_tick();
while (!need_resched()) while (!need_resched())
idle(); idle();
tick_nohz_restart_sched_tick();
preempt_enable_no_resched(); preempt_enable_no_resched();
schedule(); schedule();
preempt_disable(); 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); struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
/* Rewind */ /* 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) SIGTRAP) == NOTIFY_STOP)
return; return;
@ -514,9 +520,9 @@ asmlinkage void bug_trap_handler(unsigned long r4, unsigned long r5,
struct pt_regs *regs = RELOC_HIDE(&__regs, 0); struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
/* Rewind */ /* 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) SIGTRAP) == NOTIFY_STOP)
return; return;

View File

@ -431,7 +431,7 @@ const char *get_cpu_subtype(struct sh_cpuinfo *c)
/* Symbolic CPU flags, keep in sync with asm/cpu-features.h */ /* Symbolic CPU flags, keep in sync with asm/cpu-features.h */
static const char *cpu_flags[] = { static const char *cpu_flags[] = {
"none", "fpu", "p2flush", "mmuassoc", "dsp", "perfctr", "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) static void show_cpuflags(struct seq_file *m, struct sh_cpuinfo *c)

View File

@ -58,8 +58,6 @@ EXPORT_SYMBOL(__udelay);
EXPORT_SYMBOL(__ndelay); EXPORT_SYMBOL(__ndelay);
EXPORT_SYMBOL(__const_udelay); EXPORT_SYMBOL(__const_udelay);
EXPORT_SYMBOL(__div64_32);
#define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL(name) #define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL(name)
/* These symbols are generated by the compiler itself */ /* These symbols are generated by the compiler itself */

View File

@ -23,7 +23,7 @@
#include <linux/personality.h> #include <linux/personality.h>
#include <linux/binfmts.h> #include <linux/binfmts.h>
#include <linux/freezer.h> #include <linux/freezer.h>
#include <asm/system.h>
#include <asm/ucontext.h> #include <asm/ucontext.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
@ -500,7 +500,9 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
} }
/* fallthrough */ /* fallthrough */
case -ERESTARTNOINTR: case -ERESTARTNOINTR:
regs->pc -= 2; regs->pc -= instruction_size(
ctrl_inw(regs->pc - 4));
break;
} }
} else { } else {
/* gUSA handling */ /* gUSA handling */
@ -516,7 +518,8 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
regs->regs[15] = regs->regs[1]; regs->regs[15] = regs->regs[1];
if (regs->pc < regs->regs[0]) if (regs->pc < regs->regs[0])
/* Go to rewind point #1 */ /* 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 #ifdef CONFIG_PREEMPT
local_irq_restore(flags); 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] == -ERESTARTSYS ||
regs->regs[0] == -ERESTARTNOINTR) { regs->regs[0] == -ERESTARTNOINTR) {
regs->regs[0] = save_r0; regs->regs[0] = save_r0;
regs->pc -= 2; regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
} else if (regs->regs[0] == -ERESTART_RESTARTBLOCK) { } 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; regs->regs[3] = __NR_restart_syscall;
} }
} }

View File

@ -17,7 +17,7 @@
/* /*
* Save stack-backtrace addresses into a stack_trace buffer. * 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; unsigned long *sp = (unsigned long *)current_stack_pointer;

View File

@ -354,3 +354,4 @@ ENTRY(sys_call_table)
.long sys_move_pages .long sys_move_pages
.long sys_getcpu .long sys_getcpu
.long sys_epoll_pwait .long sys_epoll_pwait
.long sys_utimensat /* 320 */

View File

@ -3,7 +3,7 @@
* *
* Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> * 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> * Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org>
* *
* Some code taken from i386 version. * Some code taken from i386 version.
@ -15,6 +15,7 @@
#include <linux/profile.h> #include <linux/profile.h>
#include <linux/timex.h> #include <linux/timex.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/clockchips.h>
#include <asm/clock.h> #include <asm/clock.h>
#include <asm/rtc.h> #include <asm/rtc.h>
#include <asm/timer.h> #include <asm/timer.h>
@ -38,6 +39,14 @@ static int null_rtc_set_time(const time_t secs)
return 0; 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; void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
int (*rtc_sh_set_time)(const time_t) = null_rtc_set_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); EXPORT_SYMBOL(do_settimeofday);
#endif /* !CONFIG_GENERIC_TIME */ #endif /* !CONFIG_GENERIC_TIME */
#ifndef CONFIG_GENERIC_CLOCKEVENTS
/* last time the RTC clock got updated */ /* last time the RTC clock got updated */
static long last_rtc_update; static long last_rtc_update;
@ -138,6 +148,7 @@ void handle_timer_tick(void)
last_rtc_update = xtime.tv_sec - 600; last_rtc_update = xtime.tv_sec - 600;
} }
} }
#endif /* !CONFIG_GENERIC_CLOCKEVENTS */
#ifdef CONFIG_PM #ifdef CONFIG_PM
int timer_suspend(struct sys_device *dev, pm_message_t state) int timer_suspend(struct sys_device *dev, pm_message_t state)
@ -168,108 +179,6 @@ static struct sysdev_class timer_sysclass = {
.resume = timer_resume, .resume = timer_resume,
}; };
#ifdef CONFIG_NO_IDLE_HZ
static int timer_dyn_tick_enable(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);
}
return ret;
}
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;
}
/*
* 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.
*/
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 ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf)
{
return sprintf(buf, "%i\n",
(sys_timer->dyn_tick->state & DYN_TICK_ENABLED) >> 1);
}
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);
if (enable)
timer_dyn_tick_enable();
else
timer_dyn_tick_disable();
return count;
}
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)
{
if (str)
strlcpy(dyntick_str, str, sizeof(dyntick_str));
return 1;
}
__setup("dyntick=", dyntick_setup);
#endif
static int __init timer_init_sysfs(void) static int __init timer_init_sysfs(void)
{ {
int ret = sysdev_class_register(&timer_sysclass); int ret = sysdev_class_register(&timer_sysclass);
@ -277,27 +186,51 @@ static int __init timer_init_sysfs(void)
return ret; return ret;
sys_timer->dev.cls = &timer_sysclass; sys_timer->dev.cls = &timer_sysclass;
ret = sysdev_register(&sys_timer->dev); return 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); device_initcall(timer_init_sysfs);
void (*board_time_init)(void); void (*board_time_init)(void);
/*
* Shamelessly based on the MIPS and Sparc64 work.
*/
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 void __init init_sh_clocksource(void)
{
if (!sh_hpt_frequency || clocksource_sh.read == null_hpt_read)
return;
clocksource_sh.mult = clocksource_hz2mult(sh_hpt_frequency,
clocksource_sh.shift);
timer_ticks_per_nsec_quotient =
clocksource_hz2mult(sh_hpt_frequency, NSEC_PER_CYC_SHIFT);
clocksource_register(&clocksource_sh);
}
#ifdef CONFIG_GENERIC_TIME
unsigned long long sched_clock(void)
{
unsigned long long ticks = clocksource_sh.read();
return (ticks * timer_ticks_per_nsec_quotient) >> NSEC_PER_CYC_SHIFT;
}
#endif
void __init time_init(void) void __init time_init(void)
{ {
if (board_time_init) if (board_time_init)
@ -316,10 +249,15 @@ void __init time_init(void)
sys_timer = get_sys_timer(); sys_timer = get_sys_timer();
printk(KERN_INFO "Using %s for system timer\n", sys_timer->name); printk(KERN_INFO "Using %s for system timer\n", sys_timer->name);
#ifdef CONFIG_NO_IDLE_HZ if (sys_timer->ops->read)
if (sys_timer->dyn_tick) clocksource_sh.read = sys_timer->ops->read;
spin_lock_init(&sys_timer->dyn_tick->lock);
#endif 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) #if defined(CONFIG_SH_KGDB)
/* /*

View File

@ -1,7 +1,7 @@
/* /*
* arch/sh/kernel/timers/timer-tmu.c - TMU Timer Support * 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 * TMU handling code hacked out of arch/sh/kernel/time.c
* *
@ -18,6 +18,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/seqlock.h> #include <linux/seqlock.h>
#include <linux/clockchips.h>
#include <asm/timer.h> #include <asm/timer.h>
#include <asm/rtc.h> #include <asm/rtc.h>
#include <asm/io.h> #include <asm/io.h>
@ -25,56 +26,75 @@
#include <asm/clock.h> #include <asm/clock.h>
#define TMU_TOCR_INIT 0x00 #define TMU_TOCR_INIT 0x00
#define TMU0_TCR_INIT 0x0020 #define TMU_TCR_INIT 0x0020
#define TMU_TSTR_INIT 1
#define TMU0_TCR_CALIB 0x0000 static int tmu_timer_start(void)
static unsigned long tmu_timer_get_offset(void)
{ {
int count; ctrl_outb(ctrl_inb(TMU_TSTR) | 0x3, TMU_TSTR);
static int count_p = 0x7fffffff; /* for the first call after boot */ return 0;
static unsigned long jiffies_p = 0;
/*
* cache volatile jiffies temporarily; we have IRQs turned off.
*/
unsigned long jiffies_t;
/* timer count may underflow right here */
count = ctrl_inl(TMU0_TCNT); /* read the latched count */
jiffies_t = jiffies;
/*
* 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
*/
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 tmu0_timer_set_interval(unsigned long interval, unsigned int reload)
{
ctrl_outl(interval, TMU0_TCNT);
/*
* TCNT reloads from TCOR on underflow, clear it if we don't
* intend to auto-reload
*/
if (reload)
ctrl_outl(interval, TMU0_TCOR);
else
ctrl_outl(0, TMU0_TCOR);
tmu_timer_start();
}
static int tmu_timer_stop(void)
{
ctrl_outb(ctrl_inb(TMU_TSTR) & ~0x3, TMU_TSTR);
return 0;
}
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;
}
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) static irqreturn_t tmu_timer_interrupt(int irq, void *dummy)
{ {
struct clock_event_device *evt = &tmu0_clockevent;
unsigned long timer_status; unsigned long timer_status;
/* Clear UNF bit */ /* Clear UNF bit */
@ -82,72 +102,76 @@ static irqreturn_t tmu_timer_interrupt(int irq, void *dummy)
timer_status &= ~0x100; timer_status &= ~0x100;
ctrl_outw(timer_status, TMU0_TCR); ctrl_outw(timer_status, TMU0_TCR);
/* evt->event_handler(evt);
* 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);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static struct irqaction tmu_irq = { static struct irqaction tmu0_irq = {
.name = "timer", .name = "periodic timer",
.handler = tmu_timer_interrupt, .handler = tmu_timer_interrupt,
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.mask = CPU_MASK_NONE, .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; u8 divisor = TMU_TCR_INIT & 0x7;
ctrl_outw(TMU0_TCR_INIT, TMU0_TCR); ctrl_outw(TMU_TCR_INIT, TMU0_TCR);
clk->rate = clk->parent->rate / (4 << (divisor << 1)); 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; u8 divisor = ctrl_inw(TMU0_TCR) & 0x7;
clk->rate = clk->parent->rate / (4 << (divisor << 1)); clk->rate = clk->parent->rate / (4 << (divisor << 1));
} }
static struct clk_ops tmu_clk_ops = { static struct clk_ops tmu0_clk_ops = {
.init = tmu_clk_init, .init = tmu0_clk_init,
.recalc = tmu_clk_recalc, .recalc = tmu0_clk_recalc,
}; };
static struct clk tmu0_clk = { static struct clk tmu0_clk = {
.name = "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); u8 divisor = TMU_TCR_INIT & 0x7;
return 0; 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); u8 divisor = ctrl_inw(TMU1_TCR) & 0x7;
return 0; 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) static int tmu_timer_init(void)
{ {
unsigned long interval; 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"); tmu0_clk.parent = clk_get(NULL, "module_clk");
tmu1_clk.parent = clk_get(NULL, "module_clk");
/* Start TMU0 */
tmu_timer_stop(); tmu_timer_stop();
#if !defined(CONFIG_CPU_SUBTYPE_SH7300) && \ #if !defined(CONFIG_CPU_SUBTYPE_SH7300) && \
!defined(CONFIG_CPU_SUBTYPE_SH7760) && \ !defined(CONFIG_CPU_SUBTYPE_SH7760) && \
!defined(CONFIG_CPU_SUBTYPE_SH7785) !defined(CONFIG_CPU_SUBTYPE_SH7785)
@ -155,15 +179,29 @@ static int tmu_timer_init(void)
#endif #endif
clk_register(&tmu0_clk); clk_register(&tmu0_clk);
clk_register(&tmu1_clk);
clk_enable(&tmu0_clk); clk_enable(&tmu0_clk);
clk_enable(&tmu1_clk);
interval = (clk_get_rate(&tmu0_clk) + HZ / 2) / HZ; frequency = clk_get_rate(&tmu0_clk);
printk(KERN_INFO "Interval = %ld\n", interval); interval = (frequency + HZ / 2) / HZ;
ctrl_outl(interval, TMU0_TCOR); sh_hpt_frequency = clk_get_rate(&tmu1_clk);
ctrl_outl(interval, TMU0_TCNT); 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; return 0;
} }
@ -172,9 +210,7 @@ struct sys_timer_ops tmu_timer_ops = {
.init = tmu_timer_init, .init = tmu_timer_init,
.start = tmu_timer_start, .start = tmu_timer_start,
.stop = tmu_timer_stop, .stop = tmu_timer_stop,
#ifndef CONFIG_GENERIC_TIME .read = tmu_timer_read,
.get_offset = tmu_timer_get_offset,
#endif
}; };
struct sys_timer tmu_timer = { struct sys_timer tmu_timer = {

View File

@ -20,10 +20,10 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/bug.h> #include <linux/bug.h>
#include <linux/debug_locks.h> #include <linux/debug_locks.h>
#include <linux/kdebug.h>
#include <linux/limits.h> #include <linux/limits.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/kdebug.h>
#ifdef CONFIG_SH_KGDB #ifdef CONFIG_SH_KGDB
#include <asm/kgdb.h> #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); static DEFINE_SPINLOCK(die_lock);
void die(const char * str, struct pt_regs * regs, long err) 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: simple:
ret = handle_unaligned_ins(instruction,regs); ret = handle_unaligned_ins(instruction,regs);
if (ret==0) if (ret==0)
regs->pc += 2; regs->pc += instruction_size(instruction);
return ret; return ret;
} }
#endif /* CONFIG_CPU_SH2A */ #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); err = do_fpu_inst(inst, regs);
if (!err) { if (!err) {
regs->pc += 2; regs->pc += instruction_size(inst);
return; return;
} }
/* not a FPU inst. */ /* not a FPU inst. */

View File

@ -24,9 +24,10 @@ inline void __const_udelay(unsigned long xloops)
__asm__("dmulu.l %0, %2\n\t" __asm__("dmulu.l %0, %2\n\t"
"sts mach, %0" "sts mach, %0"
: "=r" (xloops) : "=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"); : "macl", "mach");
__delay(xloops * HZ); __delay(xloops);
} }
void __udelay(unsigned long usecs) void __udelay(unsigned long usecs)

View File

@ -218,6 +218,9 @@ endmenu
menu "Memory management options" menu "Memory management options"
config QUICKLIST
def_bool y
config MMU config MMU
bool "Support for memory management hardware" bool "Support for memory management hardware"
depends on !CPU_SH2 depends on !CPU_SH2
@ -300,6 +303,10 @@ config NODES_SHIFT
config ARCH_FLATMEM_ENABLE config ARCH_FLATMEM_ENABLE
def_bool y def_bool y
config MAX_ACTIVE_REGIONS
int
default "1"
config ARCH_POPULATES_NODE_MAP config ARCH_POPULATES_NODE_MAP
def_bool y def_bool y

View File

@ -15,7 +15,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/hardirq.h> #include <linux/hardirq.h>
#include <linux/kprobes.h> #include <linux/kprobes.h>
#include <asm/kdebug.h> #include <linux/kdebug.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>

View File

@ -67,6 +67,8 @@ void show_mem(void)
printk("%d slab pages\n", slab); printk("%d slab pages\n", slab);
printk("%d pages shared\n", shared); printk("%d pages shared\n", shared);
printk("%d pages swap cached\n", cached); 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 #ifdef CONFIG_MMU

View File

@ -104,7 +104,7 @@ static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id)
writeb(tmp, rtc->regbase + RCR1); 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); spin_unlock(&rtc->lock);
@ -139,7 +139,7 @@ static irqreturn_t sh_rtc_alarm(int irq, void *dev_id)
rtc->rearm_aie = 1; rtc->rearm_aie = 1;
rtc_update_irq(&rtc->rtc_dev, 1, events); rtc_update_irq(rtc->rtc_dev, 1, events);
} }
spin_unlock(&rtc->lock); spin_unlock(&rtc->lock);
@ -153,7 +153,7 @@ static irqreturn_t sh_rtc_periodic(int irq, void *dev_id)
spin_lock(&rtc->lock); 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); spin_unlock(&rtc->lock);
@ -341,7 +341,7 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
tm->tm_sec--; tm->tm_sec--;
#endif #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", "mday=%d, mon=%d, year=%d, wday=%d\n",
__FUNCTION__, __FUNCTION__,
tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_sec, tm->tm_min, tm->tm_hour,

View File

@ -1,12 +1,12 @@
#ifndef __ASM_SH_BUG_H #ifndef __ASM_SH_BUG_H
#define __ASM_SH_BUG_H #define __ASM_SH_BUG_H
#define TRAPA_BUG_OPCODE 0xc33e /* trapa #0x3e */
#ifdef CONFIG_BUG #ifdef CONFIG_BUG
#define HAVE_ARCH_BUG #define HAVE_ARCH_BUG
#define HAVE_ARCH_WARN_ON #define HAVE_ARCH_WARN_ON
#define TRAPA_BUG_OPCODE 0xc33e /* trapa #0x3e */
/** /**
* _EMIT_BUG_ENTRY * _EMIT_BUG_ENTRY
* %1 - __FILE__ * %1 - __FILE__

View File

@ -20,5 +20,6 @@
#define CPU_HAS_PTEA 0x0020 /* PTEA register */ #define CPU_HAS_PTEA 0x0020 /* PTEA register */
#define CPU_HAS_LLSC 0x0040 /* movli.l/movco.l */ #define CPU_HAS_LLSC 0x0040 /* movli.l/movco.l */
#define CPU_HAS_L2_CACHE 0x0080 /* Secondary cache / URAM */ #define CPU_HAS_L2_CACHE 0x0080 /* Secondary cache / URAM */
#define CPU_HAS_OP32 0x0100 /* 32-bit instruction support */
#endif /* __ASM_SH_CPU_FEATURES_H */ #endif /* __ASM_SH_CPU_FEATURES_H */

23
include/asm-sh/dmabrg.h Normal file
View File

@ -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

View File

@ -2,20 +2,6 @@
#define __ASM_SH_KDEBUG_H #define __ASM_SH_KDEBUG_H
#include <linux/notifier.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. */ /* Grossly misnamed. */
enum die_val { enum die_val {
@ -23,14 +9,7 @@ enum die_val {
DIE_PAGE_FAULT, DIE_PAGE_FAULT,
}; };
static inline int notify_die(enum die_val val, struct pt_regs *regs, int register_page_fault_notifier(struct notifier_block *nb);
int trap, int sig) int unregister_page_fault_notifier(struct notifier_block *nb);
{
struct die_args args = {
.regs = regs,
.trapnr = trap,
};
return atomic_notifier_call_chain(&shdie_chain, val, &args);
}
#endif /* __ASM_SH_KDEBUG_H */ #endif /* __ASM_SH_KDEBUG_H */

View File

@ -1,6 +1,12 @@
#ifndef __ASM_SH_PGALLOC_H #ifndef __ASM_SH_PGALLOC_H
#define __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, static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
pte_t *pte) 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))); 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. * Allocate and free page tables.
*/ */
static inline pgd_t *pgd_alloc(struct mm_struct *mm) static inline pgd_t *pgd_alloc(struct mm_struct *mm)
{ {
pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT); return quicklist_alloc(QUICK_PGD, GFP_KERNEL | __GFP_REPEAT, pgd_ctor);
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;
} }
static inline void pgd_free(pgd_t *pgd) 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, static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
unsigned long address) 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, static inline struct page *pte_alloc_one(struct mm_struct *mm,
unsigned long address) 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) 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) 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)) #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(x) do { } while (0)
#define __pmd_free_tlb(tlb,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 */ #endif /* __ASM_SH_PGALLOC_H */

View File

@ -255,6 +255,15 @@ static inline void *set_exception_table_evt(unsigned int evt, void *handler)
return set_exception_table_vec(evt >> 5, 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 /* XXX
* disable hlt during certain critical i/o operations * disable hlt during certain critical i/o operations
*/ */

View File

@ -2,12 +2,14 @@
#define __ASM_SH_TIMER_H #define __ASM_SH_TIMER_H
#include <linux/sysdev.h> #include <linux/sysdev.h>
#include <linux/clocksource.h>
#include <asm/cpu/timer.h> #include <asm/cpu/timer.h>
struct sys_timer_ops { struct sys_timer_ops {
int (*init)(void); int (*init)(void);
int (*start)(void); int (*start)(void);
int (*stop)(void); int (*stop)(void);
cycle_t (*read)(void);
#ifndef CONFIG_GENERIC_TIME #ifndef CONFIG_GENERIC_TIME
unsigned long (*get_offset)(void); unsigned long (*get_offset)(void);
#endif #endif
@ -18,29 +20,8 @@ struct sys_timer {
struct sys_device dev; struct sys_device dev;
struct sys_timer_ops *ops; 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) #define TICK_SIZE (tick_nsec / 1000)
extern struct sys_timer tmu_timer, cmt_timer, mtu2_timer; 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 */ /* arch/sh/kernel/time.c */
void handle_timer_tick(void); void handle_timer_tick(void);
extern unsigned long sh_hpt_frequency;
extern struct clocksource clocksource_sh;
#endif /* __ASM_SH_TIMER_H */ #endif /* __ASM_SH_TIMER_H */

View File

@ -85,7 +85,7 @@
#define __NR_sigpending 73 #define __NR_sigpending 73
#define __NR_sethostname 74 #define __NR_sethostname 74
#define __NR_setrlimit 75 #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_getrusage 77
#define __NR_gettimeofday 78 #define __NR_gettimeofday 78
#define __NR_settimeofday 79 #define __NR_settimeofday 79
@ -328,8 +328,9 @@
#define __NR_move_pages 317 #define __NR_move_pages 317
#define __NR_getcpu 318 #define __NR_getcpu 318
#define __NR_epoll_pwait 319 #define __NR_epoll_pwait 319
#define __NR_utimensat 320
#define NR_syscalls 320 #define NR_syscalls 321
#ifdef __KERNEL__ #ifdef __KERNEL__

View File

@ -166,5 +166,5 @@ config ZONE_DMA_FLAG
config NR_QUICK config NR_QUICK
int int
depends on QUICKLIST depends on QUICKLIST
default "2" if SUPERH
default "1" default "1"