mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 17:18:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
23
arch/frv/kernel/Makefile
Normal file
23
arch/frv/kernel/Makefile
Normal file
|
@ -0,0 +1,23 @@
|
|||
#
|
||||
# Makefile for the linux kernel.
|
||||
#
|
||||
|
||||
heads-y := head-uc-fr401.o head-uc-fr451.o head-uc-fr555.o
|
||||
heads-$(CONFIG_MMU) := head-mmu-fr451.o
|
||||
|
||||
extra-y:= head.o vmlinux.lds
|
||||
|
||||
obj-y := $(heads-y) entry.o entry-table.o break.o switch_to.o \
|
||||
process.o traps.o ptrace.o signal.o dma.o \
|
||||
sys_frv.o time.o setup.o frv_ksyms.o \
|
||||
debug-stub.o irq.o sleep.o uaccess.o
|
||||
|
||||
obj-$(CONFIG_GDBSTUB) += gdb-stub.o gdb-io.o
|
||||
|
||||
obj-$(CONFIG_MB93091_VDK) += irq-mb93091.o
|
||||
obj-$(CONFIG_PM) += pm.o cmode.o
|
||||
obj-$(CONFIG_MB93093_PDK) += pm-mb93093.o
|
||||
obj-$(CONFIG_FUJITSU_MB93493) += irq-mb93493.o
|
||||
obj-$(CONFIG_SYSCTL) += sysctl.o
|
||||
obj-$(CONFIG_FUTEX) += futex.o
|
||||
obj-$(CONFIG_MODULES) += module.o
|
108
arch/frv/kernel/asm-offsets.c
Normal file
108
arch/frv/kernel/asm-offsets.c
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Generate definitions needed by assembly language modules.
|
||||
* This code generates raw asm output which is post-processed
|
||||
* to extract and format the required data.
|
||||
*/
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/personality.h>
|
||||
#include <linux/kbuild.h>
|
||||
#include <asm/registers.h>
|
||||
#include <asm/ucontext.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/gdb-stub.h>
|
||||
|
||||
#define DEF_PTREG(sym, reg) \
|
||||
asm volatile("\n->" #sym " %0 offsetof(struct pt_regs, " #reg ")" \
|
||||
: : "i" (offsetof(struct pt_regs, reg)))
|
||||
|
||||
#define DEF_IREG(sym, reg) \
|
||||
asm volatile("\n->" #sym " %0 offsetof(struct user_context, " #reg ")" \
|
||||
: : "i" (offsetof(struct user_context, reg)))
|
||||
|
||||
#define DEF_FREG(sym, reg) \
|
||||
asm volatile("\n->" #sym " %0 offsetof(struct user_context, " #reg ")" \
|
||||
: : "i" (offsetof(struct user_context, reg)))
|
||||
|
||||
#define DEF_0REG(sym, reg) \
|
||||
asm volatile("\n->" #sym " %0 offsetof(struct frv_frame0, " #reg ")" \
|
||||
: : "i" (offsetof(struct frv_frame0, reg)))
|
||||
|
||||
void foo(void)
|
||||
{
|
||||
/* offsets into the thread_info structure */
|
||||
OFFSET(TI_TASK, thread_info, task);
|
||||
OFFSET(TI_EXEC_DOMAIN, thread_info, exec_domain);
|
||||
OFFSET(TI_FLAGS, thread_info, flags);
|
||||
OFFSET(TI_STATUS, thread_info, status);
|
||||
OFFSET(TI_CPU, thread_info, cpu);
|
||||
OFFSET(TI_PREEMPT_COUNT, thread_info, preempt_count);
|
||||
OFFSET(TI_ADDR_LIMIT, thread_info, addr_limit);
|
||||
OFFSET(TI_RESTART_BLOCK, thread_info, restart_block);
|
||||
BLANK();
|
||||
|
||||
/* offsets into register file storage */
|
||||
DEF_PTREG(REG_PSR, psr);
|
||||
DEF_PTREG(REG_ISR, isr);
|
||||
DEF_PTREG(REG_CCR, ccr);
|
||||
DEF_PTREG(REG_CCCR, cccr);
|
||||
DEF_PTREG(REG_LR, lr);
|
||||
DEF_PTREG(REG_LCR, lcr);
|
||||
DEF_PTREG(REG_PC, pc);
|
||||
DEF_PTREG(REG__STATUS, __status);
|
||||
DEF_PTREG(REG_SYSCALLNO, syscallno);
|
||||
DEF_PTREG(REG_ORIG_GR8, orig_gr8);
|
||||
DEF_PTREG(REG_GNER0, gner0);
|
||||
DEF_PTREG(REG_GNER1, gner1);
|
||||
DEF_PTREG(REG_IACC0, iacc0);
|
||||
DEF_PTREG(REG_TBR, tbr);
|
||||
DEF_PTREG(REG_GR0, tbr);
|
||||
DEFINE(REG__END, sizeof(struct pt_regs));
|
||||
BLANK();
|
||||
|
||||
DEF_0REG(REG_DCR, debug.dcr);
|
||||
DEF_0REG(REG_IBAR0, debug.ibar[0]);
|
||||
DEF_0REG(REG_DBAR0, debug.dbar[0]);
|
||||
DEF_0REG(REG_DBDR00, debug.dbdr[0][0]);
|
||||
DEF_0REG(REG_DBMR00, debug.dbmr[0][0]);
|
||||
BLANK();
|
||||
|
||||
DEF_IREG(__INT_GR0, i.gr[0]);
|
||||
DEF_FREG(__USER_FPMEDIA, f);
|
||||
DEF_FREG(__FPMEDIA_FR0, f.fr[0]);
|
||||
DEF_FREG(__FPMEDIA_FNER0, f.fner[0]);
|
||||
DEF_FREG(__FPMEDIA_MSR0, f.msr[0]);
|
||||
DEF_FREG(__FPMEDIA_ACC0, f.acc[0]);
|
||||
DEF_FREG(__FPMEDIA_ACCG0, f.accg[0]);
|
||||
DEF_FREG(__FPMEDIA_FSR0, f.fsr[0]);
|
||||
BLANK();
|
||||
|
||||
DEFINE(NR_PT_REGS, sizeof(struct pt_regs) / 4);
|
||||
DEFINE(NR_USER_INT_REGS, sizeof(struct user_int_regs) / 4);
|
||||
DEFINE(NR_USER_FPMEDIA_REGS, sizeof(struct user_fpmedia_regs) / 4);
|
||||
DEFINE(NR_USER_CONTEXT, sizeof(struct user_context) / 4);
|
||||
DEFINE(FRV_FRAME0_SIZE, sizeof(struct frv_frame0));
|
||||
BLANK();
|
||||
|
||||
/* offsets into thread_struct */
|
||||
OFFSET(__THREAD_FRAME, thread_struct, frame);
|
||||
OFFSET(__THREAD_CURR, thread_struct, curr);
|
||||
OFFSET(__THREAD_SP, thread_struct, sp);
|
||||
OFFSET(__THREAD_FP, thread_struct, fp);
|
||||
OFFSET(__THREAD_LR, thread_struct, lr);
|
||||
OFFSET(__THREAD_PC, thread_struct, pc);
|
||||
OFFSET(__THREAD_GR16, thread_struct, gr[0]);
|
||||
OFFSET(__THREAD_SCHED_LR, thread_struct, sched_lr);
|
||||
OFFSET(__THREAD_FRAME0, thread_struct, frame0);
|
||||
OFFSET(__THREAD_USER, thread_struct, user);
|
||||
BLANK();
|
||||
|
||||
/* offsets into frv_debug_status */
|
||||
OFFSET(DEBUG_BPSR, frv_debug_status, bpsr);
|
||||
OFFSET(DEBUG_DCR, frv_debug_status, dcr);
|
||||
OFFSET(DEBUG_BRR, frv_debug_status, brr);
|
||||
OFFSET(DEBUG_NMAR, frv_debug_status, nmar);
|
||||
BLANK();
|
||||
}
|
792
arch/frv/kernel/break.S
Normal file
792
arch/frv/kernel/break.S
Normal file
|
@ -0,0 +1,792 @@
|
|||
/* break.S: Break interrupt handling (kept separate from entry.S)
|
||||
*
|
||||
* Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/spr-regs.h>
|
||||
|
||||
#include <asm/errno.h>
|
||||
|
||||
#
|
||||
# the break handler has its own stack
|
||||
#
|
||||
.section .bss..stack
|
||||
.globl __break_user_context
|
||||
.balign THREAD_SIZE
|
||||
__break_stack:
|
||||
.space THREAD_SIZE - FRV_FRAME0_SIZE
|
||||
__break_frame_0:
|
||||
.space FRV_FRAME0_SIZE
|
||||
|
||||
#
|
||||
# miscellaneous variables
|
||||
#
|
||||
.section .bss
|
||||
#ifdef CONFIG_MMU
|
||||
.globl __break_tlb_miss_real_return_info
|
||||
__break_tlb_miss_real_return_info:
|
||||
.balign 8
|
||||
.space 2*4 /* saved PCSR, PSR for TLB-miss handler fixup */
|
||||
#endif
|
||||
|
||||
__break_trace_through_exceptions:
|
||||
.space 4
|
||||
|
||||
#define CS2_ECS1 0xe1200000
|
||||
#define CS2_USERLED 0x4
|
||||
|
||||
.macro LEDS val,reg
|
||||
# sethi.p %hi(CS2_ECS1+CS2_USERLED),gr30
|
||||
# setlo %lo(CS2_ECS1+CS2_USERLED),gr30
|
||||
# setlos #~\val,\reg
|
||||
# st \reg,@(gr30,gr0)
|
||||
# setlos #0x5555,\reg
|
||||
# sethi.p %hi(0xffc00100),gr30
|
||||
# setlo %lo(0xffc00100),gr30
|
||||
# sth \reg,@(gr30,gr0)
|
||||
# membar
|
||||
.endm
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# entry point for Break Exceptions/Interrupts
|
||||
#
|
||||
###############################################################################
|
||||
.section .text..break
|
||||
.balign 4
|
||||
.globl __entry_break
|
||||
__entry_break:
|
||||
#ifdef CONFIG_MMU
|
||||
movgs gr31,scr3
|
||||
#endif
|
||||
LEDS 0x1001,gr31
|
||||
|
||||
sethi.p %hi(__break_frame_0),gr31
|
||||
setlo %lo(__break_frame_0),gr31
|
||||
|
||||
stdi gr2,@(gr31,#REG_GR(2))
|
||||
movsg ccr,gr3
|
||||
sti gr3,@(gr31,#REG_CCR)
|
||||
|
||||
# catch the return from a TLB-miss handler that had single-step disabled
|
||||
# traps will be enabled, so we have to do this now
|
||||
#ifdef CONFIG_MMU
|
||||
movsg bpcsr,gr3
|
||||
sethi.p %hi(__break_tlb_miss_return_breaks_here),gr2
|
||||
setlo %lo(__break_tlb_miss_return_breaks_here),gr2
|
||||
subcc gr2,gr3,gr0,icc0
|
||||
beq icc0,#2,__break_return_singlestep_tlbmiss
|
||||
#endif
|
||||
|
||||
# determine whether we have stepped through into an exception
|
||||
# - we need to take special action to suspend h/w single stepping if we've done
|
||||
# that, so that the gdbstub doesn't get bogged down endlessly stepping through
|
||||
# external interrupt handling
|
||||
movsg bpsr,gr3
|
||||
andicc gr3,#BPSR_BET,gr0,icc0
|
||||
bne icc0,#2,__break_maybe_userspace /* jump if PSR.ET was 1 */
|
||||
|
||||
LEDS 0x1003,gr2
|
||||
|
||||
movsg brr,gr3
|
||||
andicc gr3,#BRR_ST,gr0,icc0
|
||||
andicc.p gr3,#BRR_SB,gr0,icc1
|
||||
bne icc0,#2,__break_step /* jump if single-step caused break */
|
||||
beq icc1,#2,__break_continue /* jump if BREAK didn't cause break */
|
||||
|
||||
LEDS 0x1007,gr2
|
||||
|
||||
# handle special breaks
|
||||
movsg bpcsr,gr3
|
||||
|
||||
sethi.p %hi(__entry_return_singlestep_breaks_here),gr2
|
||||
setlo %lo(__entry_return_singlestep_breaks_here),gr2
|
||||
subcc gr2,gr3,gr0,icc0
|
||||
beq icc0,#2,__break_return_singlestep
|
||||
|
||||
bra __break_continue
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# handle BREAK instruction in kernel-mode exception epilogue
|
||||
#
|
||||
###############################################################################
|
||||
__break_return_singlestep:
|
||||
LEDS 0x100f,gr2
|
||||
|
||||
# special break insn requests single-stepping to be turned back on
|
||||
# HERE RETT
|
||||
# PSR.ET 0 0
|
||||
# PSR.PS old PSR.S ?
|
||||
# PSR.S 1 1
|
||||
# BPSR.ET 0 1 (can't have caused orig excep otherwise)
|
||||
# BPSR.BS 1 old PSR.S
|
||||
movsg dcr,gr2
|
||||
sethi.p %hi(DCR_SE),gr3
|
||||
setlo %lo(DCR_SE),gr3
|
||||
or gr2,gr3,gr2
|
||||
movgs gr2,dcr
|
||||
|
||||
movsg psr,gr2
|
||||
andi gr2,#PSR_PS,gr2
|
||||
slli gr2,#11,gr2 /* PSR.PS -> BPSR.BS */
|
||||
ori gr2,#BPSR_BET,gr2 /* 1 -> BPSR.BET */
|
||||
movgs gr2,bpsr
|
||||
|
||||
# return to the invoker of the original kernel exception
|
||||
movsg pcsr,gr2
|
||||
movgs gr2,bpcsr
|
||||
|
||||
LEDS 0x101f,gr2
|
||||
|
||||
ldi @(gr31,#REG_CCR),gr3
|
||||
movgs gr3,ccr
|
||||
lddi.p @(gr31,#REG_GR(2)),gr2
|
||||
xor gr31,gr31,gr31
|
||||
movgs gr0,brr
|
||||
#ifdef CONFIG_MMU
|
||||
movsg scr3,gr31
|
||||
#endif
|
||||
rett #1
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# handle BREAK instruction in TLB-miss handler return path
|
||||
#
|
||||
###############################################################################
|
||||
#ifdef CONFIG_MMU
|
||||
__break_return_singlestep_tlbmiss:
|
||||
LEDS 0x1100,gr2
|
||||
|
||||
sethi.p %hi(__break_tlb_miss_real_return_info),gr3
|
||||
setlo %lo(__break_tlb_miss_real_return_info),gr3
|
||||
lddi @(gr3,#0),gr2
|
||||
movgs gr2,pcsr
|
||||
movgs gr3,psr
|
||||
|
||||
bra __break_return_singlestep
|
||||
#endif
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# handle single stepping into an exception prologue from kernel mode
|
||||
# - we try and catch it whilst it is still in the main vector table
|
||||
# - if we catch it there, we have to jump to the fixup handler
|
||||
# - there is a fixup table that has a pointer for every 16b slot in the trap
|
||||
# table
|
||||
#
|
||||
###############################################################################
|
||||
__break_step:
|
||||
LEDS 0x2003,gr2
|
||||
|
||||
# external interrupts seem to escape from the trap table before single
|
||||
# step catches up with them
|
||||
movsg bpcsr,gr2
|
||||
sethi.p %hi(__entry_kernel_external_interrupt),gr3
|
||||
setlo %lo(__entry_kernel_external_interrupt),gr3
|
||||
subcc.p gr2,gr3,gr0,icc0
|
||||
sethi %hi(__entry_uspace_external_interrupt),gr3
|
||||
setlo.p %lo(__entry_uspace_external_interrupt),gr3
|
||||
beq icc0,#2,__break_step_kernel_external_interrupt
|
||||
subcc.p gr2,gr3,gr0,icc0
|
||||
sethi %hi(__entry_kernel_external_interrupt_virtually_disabled),gr3
|
||||
setlo.p %lo(__entry_kernel_external_interrupt_virtually_disabled),gr3
|
||||
beq icc0,#2,__break_step_uspace_external_interrupt
|
||||
subcc.p gr2,gr3,gr0,icc0
|
||||
sethi %hi(__entry_kernel_external_interrupt_virtual_reenable),gr3
|
||||
setlo.p %lo(__entry_kernel_external_interrupt_virtual_reenable),gr3
|
||||
beq icc0,#2,__break_step_kernel_external_interrupt_virtually_disabled
|
||||
subcc gr2,gr3,gr0,icc0
|
||||
beq icc0,#2,__break_step_kernel_external_interrupt_virtual_reenable
|
||||
|
||||
LEDS 0x2007,gr2
|
||||
|
||||
# the two main vector tables are adjacent on one 8Kb slab
|
||||
movsg bpcsr,gr2
|
||||
setlos #0xffffe000,gr3
|
||||
and gr2,gr3,gr2
|
||||
sethi.p %hi(__trap_tables),gr3
|
||||
setlo %lo(__trap_tables),gr3
|
||||
subcc gr2,gr3,gr0,icc0
|
||||
bne icc0,#2,__break_continue
|
||||
|
||||
LEDS 0x200f,gr2
|
||||
|
||||
# skip workaround if so requested by GDB
|
||||
sethi.p %hi(__break_trace_through_exceptions),gr3
|
||||
setlo %lo(__break_trace_through_exceptions),gr3
|
||||
ld @(gr3,gr0),gr3
|
||||
subcc gr3,gr0,gr0,icc0
|
||||
bne icc0,#0,__break_continue
|
||||
|
||||
LEDS 0x201f,gr2
|
||||
|
||||
# access the fixup table - there's a 1:1 mapping between the slots in the trap tables and
|
||||
# the slots in the trap fixup tables allowing us to simply divide the offset into the
|
||||
# former by 4 to access the latter
|
||||
sethi.p %hi(__trap_tables),gr3
|
||||
setlo %lo(__trap_tables),gr3
|
||||
movsg bpcsr,gr2
|
||||
sub gr2,gr3,gr2
|
||||
srli.p gr2,#2,gr2
|
||||
|
||||
sethi %hi(__trap_fixup_tables),gr3
|
||||
setlo.p %lo(__trap_fixup_tables),gr3
|
||||
andi gr2,#~3,gr2
|
||||
ld @(gr2,gr3),gr2
|
||||
jmpil @(gr2,#0)
|
||||
|
||||
# step through an internal exception from kernel mode
|
||||
.globl __break_step_kernel_softprog_interrupt
|
||||
__break_step_kernel_softprog_interrupt:
|
||||
sethi.p %hi(__entry_kernel_softprog_interrupt_reentry),gr3
|
||||
setlo %lo(__entry_kernel_softprog_interrupt_reentry),gr3
|
||||
bra __break_return_as_kernel_prologue
|
||||
|
||||
# step through an external interrupt from kernel mode
|
||||
.globl __break_step_kernel_external_interrupt
|
||||
__break_step_kernel_external_interrupt:
|
||||
# deal with virtual interrupt disablement
|
||||
beq icc2,#0,__break_step_kernel_external_interrupt_virtually_disabled
|
||||
|
||||
sethi.p %hi(__entry_kernel_external_interrupt_reentry),gr3
|
||||
setlo %lo(__entry_kernel_external_interrupt_reentry),gr3
|
||||
|
||||
__break_return_as_kernel_prologue:
|
||||
LEDS 0x203f,gr2
|
||||
|
||||
movgs gr3,bpcsr
|
||||
|
||||
# do the bit we had to skip
|
||||
#ifdef CONFIG_MMU
|
||||
movsg ear0,gr2 /* EAR0 can get clobbered by gdb-stub (ICI/ICEI) */
|
||||
movgs gr2,scr2
|
||||
#endif
|
||||
|
||||
or.p sp,gr0,gr2 /* set up the stack pointer */
|
||||
subi sp,#REG__END,sp
|
||||
sti.p gr2,@(sp,#REG_SP)
|
||||
|
||||
setlos #REG__STATUS_STEP,gr2
|
||||
sti gr2,@(sp,#REG__STATUS) /* record single step status */
|
||||
|
||||
# cancel single-stepping mode
|
||||
movsg dcr,gr2
|
||||
sethi.p %hi(~DCR_SE),gr3
|
||||
setlo %lo(~DCR_SE),gr3
|
||||
and gr2,gr3,gr2
|
||||
movgs gr2,dcr
|
||||
|
||||
LEDS 0x207f,gr2
|
||||
|
||||
ldi @(gr31,#REG_CCR),gr3
|
||||
movgs gr3,ccr
|
||||
lddi.p @(gr31,#REG_GR(2)),gr2
|
||||
xor gr31,gr31,gr31
|
||||
movgs gr0,brr
|
||||
#ifdef CONFIG_MMU
|
||||
movsg scr3,gr31
|
||||
#endif
|
||||
rett #1
|
||||
|
||||
# we single-stepped into an interrupt handler whilst interrupts were merely virtually disabled
|
||||
# need to really disable interrupts, set flag, fix up and return
|
||||
__break_step_kernel_external_interrupt_virtually_disabled:
|
||||
movsg psr,gr2
|
||||
andi gr2,#~PSR_PIL,gr2
|
||||
ori gr2,#PSR_PIL_14,gr2 /* debugging interrupts only */
|
||||
movgs gr2,psr
|
||||
|
||||
ldi @(gr31,#REG_CCR),gr3
|
||||
movgs gr3,ccr
|
||||
subcc.p gr0,gr0,gr0,icc2 /* leave Z set, clear C */
|
||||
|
||||
# exceptions must've been enabled and we must've been in supervisor mode
|
||||
setlos BPSR_BET|BPSR_BS,gr3
|
||||
movgs gr3,bpsr
|
||||
|
||||
# return to where the interrupt happened
|
||||
movsg pcsr,gr2
|
||||
movgs gr2,bpcsr
|
||||
|
||||
lddi.p @(gr31,#REG_GR(2)),gr2
|
||||
|
||||
xor gr31,gr31,gr31
|
||||
movgs gr0,brr
|
||||
#ifdef CONFIG_MMU
|
||||
movsg scr3,gr31
|
||||
#endif
|
||||
rett #1
|
||||
|
||||
# we stepped through into the virtual interrupt reenablement trap
|
||||
#
|
||||
# we also want to single step anyway, but after fixing up so that we get an event on the
|
||||
# instruction after the broken-into exception returns
|
||||
.globl __break_step_kernel_external_interrupt_virtual_reenable
|
||||
__break_step_kernel_external_interrupt_virtual_reenable:
|
||||
movsg psr,gr2
|
||||
andi gr2,#~PSR_PIL,gr2
|
||||
movgs gr2,psr
|
||||
|
||||
ldi @(gr31,#REG_CCR),gr3
|
||||
movgs gr3,ccr
|
||||
subicc gr0,#1,gr0,icc2 /* clear Z, set C */
|
||||
|
||||
# save the adjusted ICC2
|
||||
movsg ccr,gr3
|
||||
sti gr3,@(gr31,#REG_CCR)
|
||||
|
||||
# exceptions must've been enabled and we must've been in supervisor mode
|
||||
setlos BPSR_BET|BPSR_BS,gr3
|
||||
movgs gr3,bpsr
|
||||
|
||||
# return to where the trap happened
|
||||
movsg pcsr,gr2
|
||||
movgs gr2,bpcsr
|
||||
|
||||
# and then process the single step
|
||||
bra __break_continue
|
||||
|
||||
# step through an internal exception from uspace mode
|
||||
.globl __break_step_uspace_softprog_interrupt
|
||||
__break_step_uspace_softprog_interrupt:
|
||||
sethi.p %hi(__entry_uspace_softprog_interrupt_reentry),gr3
|
||||
setlo %lo(__entry_uspace_softprog_interrupt_reentry),gr3
|
||||
bra __break_return_as_uspace_prologue
|
||||
|
||||
# step through an external interrupt from kernel mode
|
||||
.globl __break_step_uspace_external_interrupt
|
||||
__break_step_uspace_external_interrupt:
|
||||
sethi.p %hi(__entry_uspace_external_interrupt_reentry),gr3
|
||||
setlo %lo(__entry_uspace_external_interrupt_reentry),gr3
|
||||
|
||||
__break_return_as_uspace_prologue:
|
||||
LEDS 0x20ff,gr2
|
||||
|
||||
movgs gr3,bpcsr
|
||||
|
||||
# do the bit we had to skip
|
||||
sethi.p %hi(__kernel_frame0_ptr),gr28
|
||||
setlo %lo(__kernel_frame0_ptr),gr28
|
||||
ldi.p @(gr28,#0),gr28
|
||||
|
||||
setlos #REG__STATUS_STEP,gr2
|
||||
sti gr2,@(gr28,#REG__STATUS) /* record single step status */
|
||||
|
||||
# cancel single-stepping mode
|
||||
movsg dcr,gr2
|
||||
sethi.p %hi(~DCR_SE),gr3
|
||||
setlo %lo(~DCR_SE),gr3
|
||||
and gr2,gr3,gr2
|
||||
movgs gr2,dcr
|
||||
|
||||
LEDS 0x20fe,gr2
|
||||
|
||||
ldi @(gr31,#REG_CCR),gr3
|
||||
movgs gr3,ccr
|
||||
lddi.p @(gr31,#REG_GR(2)),gr2
|
||||
xor gr31,gr31,gr31
|
||||
movgs gr0,brr
|
||||
#ifdef CONFIG_MMU
|
||||
movsg scr3,gr31
|
||||
#endif
|
||||
rett #1
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
# step through an ITLB-miss handler from user mode
|
||||
.globl __break_user_insn_tlb_miss
|
||||
__break_user_insn_tlb_miss:
|
||||
# we'll want to try the trap stub again
|
||||
sethi.p %hi(__trap_user_insn_tlb_miss),gr2
|
||||
setlo %lo(__trap_user_insn_tlb_miss),gr2
|
||||
movgs gr2,bpcsr
|
||||
|
||||
__break_tlb_miss_common:
|
||||
LEDS 0x2101,gr2
|
||||
|
||||
# cancel single-stepping mode
|
||||
movsg dcr,gr2
|
||||
sethi.p %hi(~DCR_SE),gr3
|
||||
setlo %lo(~DCR_SE),gr3
|
||||
and gr2,gr3,gr2
|
||||
movgs gr2,dcr
|
||||
|
||||
# we'll swap the real return address for one with a BREAK insn so that we can re-enable
|
||||
# single stepping on return
|
||||
movsg pcsr,gr2
|
||||
sethi.p %hi(__break_tlb_miss_real_return_info),gr3
|
||||
setlo %lo(__break_tlb_miss_real_return_info),gr3
|
||||
sti gr2,@(gr3,#0)
|
||||
|
||||
sethi.p %hi(__break_tlb_miss_return_break),gr2
|
||||
setlo %lo(__break_tlb_miss_return_break),gr2
|
||||
movgs gr2,pcsr
|
||||
|
||||
# we also have to fudge PSR because the return BREAK is in kernel space and we want
|
||||
# to get a BREAK fault not an access violation should the return be to userspace
|
||||
movsg psr,gr2
|
||||
sti.p gr2,@(gr3,#4)
|
||||
ori gr2,#PSR_PS,gr2
|
||||
movgs gr2,psr
|
||||
|
||||
LEDS 0x2102,gr2
|
||||
|
||||
ldi @(gr31,#REG_CCR),gr3
|
||||
movgs gr3,ccr
|
||||
lddi @(gr31,#REG_GR(2)),gr2
|
||||
movsg scr3,gr31
|
||||
movgs gr0,brr
|
||||
rett #1
|
||||
|
||||
# step through a DTLB-miss handler from user mode
|
||||
.globl __break_user_data_tlb_miss
|
||||
__break_user_data_tlb_miss:
|
||||
# we'll want to try the trap stub again
|
||||
sethi.p %hi(__trap_user_data_tlb_miss),gr2
|
||||
setlo %lo(__trap_user_data_tlb_miss),gr2
|
||||
movgs gr2,bpcsr
|
||||
bra __break_tlb_miss_common
|
||||
|
||||
# step through an ITLB-miss handler from kernel mode
|
||||
.globl __break_kernel_insn_tlb_miss
|
||||
__break_kernel_insn_tlb_miss:
|
||||
# we'll want to try the trap stub again
|
||||
sethi.p %hi(__trap_kernel_insn_tlb_miss),gr2
|
||||
setlo %lo(__trap_kernel_insn_tlb_miss),gr2
|
||||
movgs gr2,bpcsr
|
||||
bra __break_tlb_miss_common
|
||||
|
||||
# step through a DTLB-miss handler from kernel mode
|
||||
.globl __break_kernel_data_tlb_miss
|
||||
__break_kernel_data_tlb_miss:
|
||||
# we'll want to try the trap stub again
|
||||
sethi.p %hi(__trap_kernel_data_tlb_miss),gr2
|
||||
setlo %lo(__trap_kernel_data_tlb_miss),gr2
|
||||
movgs gr2,bpcsr
|
||||
bra __break_tlb_miss_common
|
||||
#endif
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# handle debug events originating with userspace
|
||||
#
|
||||
###############################################################################
|
||||
__break_maybe_userspace:
|
||||
LEDS 0x3003,gr2
|
||||
|
||||
setlos #BPSR_BS,gr2
|
||||
andcc gr3,gr2,gr0,icc0
|
||||
bne icc0,#0,__break_continue /* skip if PSR.S was 1 */
|
||||
|
||||
movsg brr,gr2
|
||||
andicc gr2,#BRR_ST|BRR_SB,gr0,icc0
|
||||
beq icc0,#0,__break_continue /* jump if not BREAK or single-step */
|
||||
|
||||
LEDS 0x3007,gr2
|
||||
|
||||
# do the first part of the exception prologue here
|
||||
sethi.p %hi(__kernel_frame0_ptr),gr28
|
||||
setlo %lo(__kernel_frame0_ptr),gr28
|
||||
ldi @(gr28,#0),gr28
|
||||
andi gr28,#~7,gr28
|
||||
|
||||
# set up the kernel stack pointer
|
||||
sti sp ,@(gr28,#REG_SP)
|
||||
ori gr28,0,sp
|
||||
sti gr0 ,@(gr28,#REG_GR(28))
|
||||
|
||||
stdi gr20,@(gr28,#REG_GR(20))
|
||||
stdi gr22,@(gr28,#REG_GR(22))
|
||||
|
||||
movsg tbr,gr20
|
||||
movsg bpcsr,gr21
|
||||
movsg psr,gr22
|
||||
|
||||
# determine the exception type and cancel single-stepping mode
|
||||
or gr0,gr0,gr23
|
||||
|
||||
movsg dcr,gr2
|
||||
sethi.p %hi(DCR_SE),gr3
|
||||
setlo %lo(DCR_SE),gr3
|
||||
andcc gr2,gr3,gr0,icc0
|
||||
beq icc0,#0,__break_no_user_sstep /* must have been a BREAK insn */
|
||||
|
||||
not gr3,gr3
|
||||
and gr2,gr3,gr2
|
||||
movgs gr2,dcr
|
||||
ori gr23,#REG__STATUS_STEP,gr23
|
||||
|
||||
__break_no_user_sstep:
|
||||
LEDS 0x300f,gr2
|
||||
|
||||
movsg brr,gr2
|
||||
andi gr2,#BRR_ST|BRR_SB,gr2
|
||||
slli gr2,#1,gr2
|
||||
or gr23,gr2,gr23
|
||||
sti.p gr23,@(gr28,#REG__STATUS) /* record single step status */
|
||||
|
||||
# adjust the value acquired from TBR - this indicates the exception
|
||||
setlos #~TBR_TT,gr2
|
||||
and.p gr20,gr2,gr20
|
||||
setlos #TBR_TT_BREAK,gr2
|
||||
or.p gr20,gr2,gr20
|
||||
|
||||
# fudge PSR.PS and BPSR.BS to return to kernel mode through the trap
|
||||
# table as trap 126
|
||||
andi gr22,#~PSR_PS,gr22 /* PSR.PS should be 0 */
|
||||
movgs gr22,psr
|
||||
|
||||
setlos #BPSR_BS,gr2 /* BPSR.BS should be 1 and BPSR.BET 0 */
|
||||
movgs gr2,bpsr
|
||||
|
||||
# return through remainder of the exception prologue
|
||||
# - need to load gr23 with return handler address
|
||||
sethi.p %hi(__entry_return_from_user_exception),gr23
|
||||
setlo %lo(__entry_return_from_user_exception),gr23
|
||||
sethi.p %hi(__entry_common),gr3
|
||||
setlo %lo(__entry_common),gr3
|
||||
movgs gr3,bpcsr
|
||||
|
||||
LEDS 0x301f,gr2
|
||||
|
||||
ldi @(gr31,#REG_CCR),gr3
|
||||
movgs gr3,ccr
|
||||
lddi.p @(gr31,#REG_GR(2)),gr2
|
||||
xor gr31,gr31,gr31
|
||||
movgs gr0,brr
|
||||
#ifdef CONFIG_MMU
|
||||
movsg scr3,gr31
|
||||
#endif
|
||||
rett #1
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# resume normal debug-mode entry
|
||||
#
|
||||
###############################################################################
|
||||
__break_continue:
|
||||
LEDS 0x4003,gr2
|
||||
|
||||
# set up the kernel stack pointer
|
||||
sti sp,@(gr31,#REG_SP)
|
||||
|
||||
sethi.p %hi(__break_frame_0),sp
|
||||
setlo %lo(__break_frame_0),sp
|
||||
|
||||
# finish building the exception frame
|
||||
stdi gr4 ,@(gr31,#REG_GR(4))
|
||||
stdi gr6 ,@(gr31,#REG_GR(6))
|
||||
stdi gr8 ,@(gr31,#REG_GR(8))
|
||||
stdi gr10,@(gr31,#REG_GR(10))
|
||||
stdi gr12,@(gr31,#REG_GR(12))
|
||||
stdi gr14,@(gr31,#REG_GR(14))
|
||||
stdi gr16,@(gr31,#REG_GR(16))
|
||||
stdi gr18,@(gr31,#REG_GR(18))
|
||||
stdi gr20,@(gr31,#REG_GR(20))
|
||||
stdi gr22,@(gr31,#REG_GR(22))
|
||||
stdi gr24,@(gr31,#REG_GR(24))
|
||||
stdi gr26,@(gr31,#REG_GR(26))
|
||||
sti gr0 ,@(gr31,#REG_GR(28)) /* NULL frame pointer */
|
||||
sti gr29,@(gr31,#REG_GR(29))
|
||||
sti gr30,@(gr31,#REG_GR(30))
|
||||
sti gr8 ,@(gr31,#REG_ORIG_GR8)
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
movsg scr3,gr19
|
||||
sti gr19,@(gr31,#REG_GR(31))
|
||||
#endif
|
||||
|
||||
movsg bpsr ,gr19
|
||||
movsg tbr ,gr20
|
||||
movsg bpcsr,gr21
|
||||
movsg psr ,gr22
|
||||
movsg isr ,gr23
|
||||
movsg cccr ,gr25
|
||||
movsg lr ,gr26
|
||||
movsg lcr ,gr27
|
||||
|
||||
andi.p gr22,#~(PSR_S|PSR_ET),gr5 /* rebuild PSR */
|
||||
andi gr19,#PSR_ET,gr4
|
||||
or.p gr4,gr5,gr5
|
||||
srli gr19,#10,gr4
|
||||
andi gr4,#PSR_S,gr4
|
||||
or.p gr4,gr5,gr5
|
||||
|
||||
setlos #-1,gr6
|
||||
sti gr20,@(gr31,#REG_TBR)
|
||||
sti gr21,@(gr31,#REG_PC)
|
||||
sti gr5 ,@(gr31,#REG_PSR)
|
||||
sti gr23,@(gr31,#REG_ISR)
|
||||
sti gr25,@(gr31,#REG_CCCR)
|
||||
stdi gr26,@(gr31,#REG_LR)
|
||||
sti gr6 ,@(gr31,#REG_SYSCALLNO)
|
||||
|
||||
# store CPU-specific regs
|
||||
movsg iacc0h,gr4
|
||||
movsg iacc0l,gr5
|
||||
stdi gr4,@(gr31,#REG_IACC0)
|
||||
|
||||
movsg gner0,gr4
|
||||
movsg gner1,gr5
|
||||
stdi gr4,@(gr31,#REG_GNER0)
|
||||
|
||||
# build the debug register frame
|
||||
movsg brr,gr4
|
||||
movgs gr0,brr
|
||||
movsg nmar,gr5
|
||||
movsg dcr,gr6
|
||||
|
||||
sethi.p %hi(__debug_status),gr7
|
||||
setlo %lo(__debug_status),gr7
|
||||
|
||||
stdi gr4 ,@(gr7,#DEBUG_BRR)
|
||||
sti gr19,@(gr7,#DEBUG_BPSR)
|
||||
sti.p gr6 ,@(gr7,#DEBUG_DCR)
|
||||
|
||||
# trap exceptions during break handling and disable h/w breakpoints/watchpoints
|
||||
sethi %hi(DCR_EBE),gr5
|
||||
setlo.p %lo(DCR_EBE),gr5
|
||||
sethi %hi(__entry_breaktrap_table),gr4
|
||||
setlo %lo(__entry_breaktrap_table),gr4
|
||||
movgs gr5,dcr
|
||||
movgs gr4,tbr
|
||||
|
||||
# set up kernel global registers
|
||||
sethi.p %hi(__kernel_current_task),gr5
|
||||
setlo %lo(__kernel_current_task),gr5
|
||||
ld @(gr5,gr0),gr29
|
||||
ldi.p @(gr29,#4),gr15 ; __current_thread_info = current->thread_info
|
||||
|
||||
sethi %hi(_gp),gr16
|
||||
setlo.p %lo(_gp),gr16
|
||||
|
||||
# make sure we (the kernel) get div-zero and misalignment exceptions
|
||||
setlos #ISR_EDE|ISR_DTT_DIVBYZERO|ISR_EMAM_EXCEPTION,gr5
|
||||
movgs gr5,isr
|
||||
|
||||
# enter the GDB stub
|
||||
LEDS 0x4007,gr2
|
||||
|
||||
or.p gr0,gr0,fp
|
||||
call debug_stub
|
||||
|
||||
LEDS 0x403f,gr2
|
||||
|
||||
# return from break
|
||||
lddi @(gr31,#REG_IACC0),gr4
|
||||
movgs gr4,iacc0h
|
||||
movgs gr5,iacc0l
|
||||
|
||||
lddi @(gr31,#REG_GNER0),gr4
|
||||
movgs gr4,gner0
|
||||
movgs gr5,gner1
|
||||
|
||||
lddi @(gr31,#REG_LR) ,gr26
|
||||
lddi @(gr31,#REG_CCR) ,gr24
|
||||
lddi @(gr31,#REG_PSR) ,gr22
|
||||
ldi @(gr31,#REG_PC) ,gr21
|
||||
ldi @(gr31,#REG_TBR) ,gr20
|
||||
|
||||
sethi.p %hi(__debug_status),gr6
|
||||
setlo %lo(__debug_status),gr6
|
||||
ldi.p @(gr6,#DEBUG_DCR) ,gr6
|
||||
|
||||
andi gr22,#PSR_S,gr19 /* rebuild BPSR */
|
||||
andi.p gr22,#PSR_ET,gr5
|
||||
slli gr19,#10,gr19
|
||||
or gr5,gr19,gr19
|
||||
|
||||
movgs gr6 ,dcr
|
||||
movgs gr19,bpsr
|
||||
movgs gr20,tbr
|
||||
movgs gr21,bpcsr
|
||||
movgs gr23,isr
|
||||
movgs gr24,ccr
|
||||
movgs gr25,cccr
|
||||
movgs gr26,lr
|
||||
movgs gr27,lcr
|
||||
|
||||
LEDS 0x407f,gr2
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
ldi @(gr31,#REG_GR(31)),gr2
|
||||
movgs gr2,scr3
|
||||
#endif
|
||||
|
||||
ldi @(gr31,#REG_GR(30)),gr30
|
||||
ldi @(gr31,#REG_GR(29)),gr29
|
||||
lddi @(gr31,#REG_GR(26)),gr26
|
||||
lddi @(gr31,#REG_GR(24)),gr24
|
||||
lddi @(gr31,#REG_GR(22)),gr22
|
||||
lddi @(gr31,#REG_GR(20)),gr20
|
||||
lddi @(gr31,#REG_GR(18)),gr18
|
||||
lddi @(gr31,#REG_GR(16)),gr16
|
||||
lddi @(gr31,#REG_GR(14)),gr14
|
||||
lddi @(gr31,#REG_GR(12)),gr12
|
||||
lddi @(gr31,#REG_GR(10)),gr10
|
||||
lddi @(gr31,#REG_GR(8)) ,gr8
|
||||
lddi @(gr31,#REG_GR(6)) ,gr6
|
||||
lddi @(gr31,#REG_GR(4)) ,gr4
|
||||
lddi @(gr31,#REG_GR(2)) ,gr2
|
||||
ldi.p @(gr31,#REG_SP) ,sp
|
||||
|
||||
xor gr31,gr31,gr31
|
||||
movgs gr0,brr
|
||||
#ifdef CONFIG_MMU
|
||||
movsg scr3,gr31
|
||||
#endif
|
||||
rett #1
|
||||
|
||||
###################################################################################################
|
||||
#
|
||||
# GDB stub "system calls"
|
||||
#
|
||||
###################################################################################################
|
||||
|
||||
#ifdef CONFIG_GDBSTUB
|
||||
# void gdbstub_console_write(struct console *con, const char *p, unsigned n)
|
||||
.globl gdbstub_console_write
|
||||
gdbstub_console_write:
|
||||
break
|
||||
bralr
|
||||
#endif
|
||||
|
||||
# GDB stub BUG() trap
|
||||
# GR8 is the proposed signal number
|
||||
.globl __debug_bug_trap
|
||||
__debug_bug_trap:
|
||||
break
|
||||
bralr
|
||||
|
||||
# transfer kernel exeception to GDB for handling
|
||||
.globl __break_hijack_kernel_event
|
||||
__break_hijack_kernel_event:
|
||||
break
|
||||
.globl __break_hijack_kernel_event_breaks_here
|
||||
__break_hijack_kernel_event_breaks_here:
|
||||
nop
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
# handle a return from TLB-miss that requires single-step reactivation
|
||||
.globl __break_tlb_miss_return_break
|
||||
__break_tlb_miss_return_break:
|
||||
break
|
||||
__break_tlb_miss_return_breaks_here:
|
||||
nop
|
||||
#endif
|
||||
|
||||
# guard the first .text label in the next file from confusion
|
||||
nop
|
189
arch/frv/kernel/cmode.S
Normal file
189
arch/frv/kernel/cmode.S
Normal file
|
@ -0,0 +1,189 @@
|
|||
/* cmode.S: clock mode management
|
||||
*
|
||||
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Woodhouse (dwmw2@infradead.org)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/sys.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/cache.h>
|
||||
#include <asm/spr-regs.h>
|
||||
|
||||
#define __addr_MASK 0xfeff9820 /* interrupt controller mask */
|
||||
|
||||
#define __addr_SDRAMC 0xfe000400 /* SDRAM controller regs */
|
||||
#define SDRAMC_DSTS 0x28 /* SDRAM status */
|
||||
#define SDRAMC_DSTS_SSI 0x00000001 /* indicates that the SDRAM is in self-refresh mode */
|
||||
#define SDRAMC_DRCN 0x30 /* SDRAM refresh control */
|
||||
#define SDRAMC_DRCN_SR 0x00000001 /* transition SDRAM into self-refresh mode */
|
||||
#define __addr_CLKC 0xfeff9a00
|
||||
#define CLKC_SWCMODE 0x00000008
|
||||
#define __addr_LEDS 0xe1200004
|
||||
|
||||
.macro li v r
|
||||
sethi.p %hi(\v),\r
|
||||
setlo %lo(\v),\r
|
||||
.endm
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Change CMODE
|
||||
# - void frv_change_cmode(int cmode)
|
||||
#
|
||||
###############################################################################
|
||||
.globl frv_change_cmode
|
||||
.type frv_change_cmode,@function
|
||||
|
||||
.macro LEDS v
|
||||
#ifdef DEBUG_CMODE
|
||||
setlos #~\v,gr10
|
||||
sti gr10,@(gr11,#0)
|
||||
membar
|
||||
#endif
|
||||
.endm
|
||||
|
||||
frv_change_cmode:
|
||||
movsg lr,gr9
|
||||
#ifdef DEBUG_CMODE
|
||||
li __addr_LEDS,gr11
|
||||
#endif
|
||||
dcef @(gr0,gr0),#1
|
||||
|
||||
# Shift argument left by 24 bits to fit in SWCMODE register later.
|
||||
slli gr8,#24,gr8
|
||||
|
||||
# (1) Set '0' in the PSR.ET bit, and prohibit interrupts.
|
||||
movsg psr,gr14
|
||||
andi gr14,#~PSR_ET,gr3
|
||||
movgs gr3,psr
|
||||
|
||||
#if 0 // Fujitsu recommend to skip this and will update docs.
|
||||
# (2) Set '0' to all bits of the MASK register of the interrupt
|
||||
# controller, and mask interrupts.
|
||||
li __addr_MASK,gr12
|
||||
ldi @(gr12,#0),gr13
|
||||
li 0xffff0000,gr4
|
||||
sti gr4,@(gr12,#0)
|
||||
#endif
|
||||
|
||||
# (3) Stop the transfer function of DMAC. Stop all the bus masters
|
||||
# to access SDRAM and the internal resources.
|
||||
|
||||
# (already done by caller)
|
||||
|
||||
# (4) Preload a series of following instructions to the instruction
|
||||
# cache.
|
||||
li #__cmode_icache_lock_start,gr3
|
||||
li #__cmode_icache_lock_end,gr4
|
||||
|
||||
1: icpl gr3,gr0,#1
|
||||
addi gr3,#L1_CACHE_BYTES,gr3
|
||||
cmp gr4,gr3,icc0
|
||||
bhi icc0,#0,1b
|
||||
|
||||
# Set up addresses in regs for later steps.
|
||||
setlos SDRAMC_DRCN_SR,gr3
|
||||
li __addr_SDRAMC,gr4
|
||||
li __addr_CLKC,gr5
|
||||
ldi @(gr5,#0),gr6
|
||||
li #0x80000000,gr7
|
||||
or gr6,gr7,gr6
|
||||
|
||||
bra __cmode_icache_lock_start
|
||||
|
||||
.balign L1_CACHE_BYTES
|
||||
__cmode_icache_lock_start:
|
||||
|
||||
# (5) Flush the content of all caches by the DCEF instruction.
|
||||
dcef @(gr0,gr0),#1
|
||||
|
||||
# (6) Execute loading the dummy for SDRAM.
|
||||
ldi @(gr9,#0),gr0
|
||||
|
||||
# (7) Set '1' to the DRCN.SR bit, and change SDRAM to the
|
||||
# self-refresh mode. Execute the dummy load to all memory
|
||||
# devices set to cacheable on the external bus side in parallel
|
||||
# with this.
|
||||
sti gr3,@(gr4,#SDRAMC_DRCN)
|
||||
|
||||
# (8) Execute memory barrier instruction (MEMBAR).
|
||||
membar
|
||||
|
||||
# (9) Read the DSTS register repeatedly until '1' stands in the
|
||||
# DSTS.SSI field.
|
||||
1: ldi @(gr4,#SDRAMC_DSTS),gr3
|
||||
andicc gr3,#SDRAMC_DSTS_SSI,gr3,icc0
|
||||
beq icc0,#0,1b
|
||||
|
||||
# (10) Execute memory barrier instruction (MEMBAR).
|
||||
membar
|
||||
|
||||
#if 1
|
||||
# (11) Set the value of CMODE that you want to change to
|
||||
# SWCMODE.SWCM[3:0].
|
||||
sti gr8,@(gr5,#CLKC_SWCMODE)
|
||||
|
||||
# (12) Set '1' to the CLKC.SWEN bit. In that case, do not change
|
||||
# fields other than SWEN of the CLKC register.
|
||||
sti gr6,@(gr5,#0)
|
||||
#endif
|
||||
# (13) Execute the instruction just after the memory barrier
|
||||
# instruction that executes the self-loop 256 times. (Meanwhile,
|
||||
# the CMODE switch is done.)
|
||||
membar
|
||||
setlos #256,gr7
|
||||
2: subicc gr7,#1,gr7,icc0
|
||||
bne icc0,#2,2b
|
||||
|
||||
LEDS 0x36
|
||||
|
||||
# (14) Release the self-refresh of SDRAM.
|
||||
sti gr0,@(gr4,#SDRAMC_DRCN)
|
||||
|
||||
# Wait for it...
|
||||
3: ldi @(gr4,#SDRAMC_DSTS),gr3
|
||||
andicc gr3,#SDRAMC_DSTS_SSI,gr3,icc0
|
||||
bne icc0,#2,3b
|
||||
|
||||
#if 0
|
||||
li 0x0100000,gr10
|
||||
4: subicc gr10,#1,gr10,icc0
|
||||
|
||||
bne icc0,#0,4b
|
||||
#endif
|
||||
|
||||
__cmode_icache_lock_end:
|
||||
|
||||
li #__cmode_icache_lock_start,gr3
|
||||
li #__cmode_icache_lock_end,gr4
|
||||
|
||||
4: icul gr3
|
||||
addi gr3,#L1_CACHE_BYTES,gr3
|
||||
cmp gr4,gr3,icc0
|
||||
bhi icc0,#0,4b
|
||||
|
||||
#if 0 // Fujitsu recommend to skip this and will update docs.
|
||||
# (15) Release the interrupt mask setting of the MASK register of
|
||||
# the interrupt controller if necessary.
|
||||
sti gr13,@(gr12,#0)
|
||||
#endif
|
||||
# (16) Set 1' in the PSR.ET bit, and permit interrupt.
|
||||
movgs gr14,psr
|
||||
|
||||
bralr
|
||||
|
||||
.size frv_change_cmode, .-frv_change_cmode
|
258
arch/frv/kernel/debug-stub.c
Normal file
258
arch/frv/kernel/debug-stub.c
Normal file
|
@ -0,0 +1,258 @@
|
|||
/* debug-stub.c: debug-mode stub
|
||||
*
|
||||
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/start_kernel.h>
|
||||
|
||||
#include <asm/serial-regs.h>
|
||||
#include <asm/timer-regs.h>
|
||||
#include <asm/irc-regs.h>
|
||||
#include <asm/gdb-stub.h>
|
||||
#include "gdb-io.h"
|
||||
|
||||
/* CPU board CON5 */
|
||||
#define __UART0(X) (*(volatile uint8_t *)(UART0_BASE + (UART_##X)))
|
||||
|
||||
#define LSR_WAIT_FOR0(STATE) \
|
||||
do { \
|
||||
} while (!(__UART0(LSR) & UART_LSR_##STATE))
|
||||
|
||||
#define FLOWCTL_QUERY0(LINE) ({ __UART0(MSR) & UART_MSR_##LINE; })
|
||||
#define FLOWCTL_CLEAR0(LINE) do { __UART0(MCR) &= ~UART_MCR_##LINE; } while (0)
|
||||
#define FLOWCTL_SET0(LINE) do { __UART0(MCR) |= UART_MCR_##LINE; } while (0)
|
||||
|
||||
#define FLOWCTL_WAIT_FOR0(LINE) \
|
||||
do { \
|
||||
gdbstub_do_rx(); \
|
||||
} while(!FLOWCTL_QUERY(LINE))
|
||||
|
||||
struct frv_debug_status __debug_status;
|
||||
|
||||
static void __init debug_stub_init(void);
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* debug mode handler stub
|
||||
* - we come here with the CPU in debug mode and with exceptions disabled
|
||||
* - handle debugging services for userspace
|
||||
*/
|
||||
asmlinkage void debug_stub(void)
|
||||
{
|
||||
unsigned long hsr0;
|
||||
int type = 0;
|
||||
|
||||
static u8 inited = 0;
|
||||
if (!inited) {
|
||||
debug_stub_init();
|
||||
type = -1;
|
||||
inited = 1;
|
||||
}
|
||||
|
||||
hsr0 = __get_HSR(0);
|
||||
if (hsr0 & HSR0_ETMD)
|
||||
__set_HSR(0, hsr0 & ~HSR0_ETMD);
|
||||
|
||||
/* disable single stepping */
|
||||
__debug_status.dcr &= ~DCR_SE;
|
||||
|
||||
/* kernel mode can propose an exception be handled in debug mode by jumping to a special
|
||||
* location */
|
||||
if (__debug_frame->pc == (unsigned long) __break_hijack_kernel_event_breaks_here) {
|
||||
/* replace the debug frame with the kernel frame and discard
|
||||
* the top kernel context */
|
||||
*__debug_frame = *__frame;
|
||||
__frame = __debug_frame->next_frame;
|
||||
__debug_status.brr = (__debug_frame->tbr & TBR_TT) << 12;
|
||||
__debug_status.brr |= BRR_EB;
|
||||
}
|
||||
|
||||
if (__debug_frame->pc == (unsigned long) __debug_bug_trap + 4) {
|
||||
__debug_frame->pc = __debug_frame->lr;
|
||||
type = __debug_frame->gr8;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GDBSTUB
|
||||
gdbstub(type);
|
||||
#endif
|
||||
|
||||
if (hsr0 & HSR0_ETMD)
|
||||
__set_HSR(0, __get_HSR(0) | HSR0_ETMD);
|
||||
|
||||
} /* end debug_stub() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* debug stub initialisation
|
||||
*/
|
||||
static void __init debug_stub_init(void)
|
||||
{
|
||||
__set_IRR(6, 0xff000000); /* map ERRs to NMI */
|
||||
__set_IITMR(1, 0x20000000); /* ERR0/1, UART0/1 IRQ detect levels */
|
||||
|
||||
asm volatile(" movgs gr0,ibar0 \n"
|
||||
" movgs gr0,ibar1 \n"
|
||||
" movgs gr0,ibar2 \n"
|
||||
" movgs gr0,ibar3 \n"
|
||||
" movgs gr0,dbar0 \n"
|
||||
" movgs gr0,dbmr00 \n"
|
||||
" movgs gr0,dbmr01 \n"
|
||||
" movgs gr0,dbdr00 \n"
|
||||
" movgs gr0,dbdr01 \n"
|
||||
" movgs gr0,dbar1 \n"
|
||||
" movgs gr0,dbmr10 \n"
|
||||
" movgs gr0,dbmr11 \n"
|
||||
" movgs gr0,dbdr10 \n"
|
||||
" movgs gr0,dbdr11 \n"
|
||||
);
|
||||
|
||||
/* deal with debugging stub initialisation and initial pause */
|
||||
if (__debug_frame->pc == (unsigned long) __debug_stub_init_break)
|
||||
__debug_frame->pc = (unsigned long) start_kernel;
|
||||
|
||||
/* enable the debug events we want to trap */
|
||||
__debug_status.dcr = DCR_EBE;
|
||||
|
||||
#ifdef CONFIG_GDBSTUB
|
||||
gdbstub_init();
|
||||
#endif
|
||||
|
||||
__clr_MASK_all();
|
||||
__clr_MASK(15);
|
||||
__clr_RC(15);
|
||||
|
||||
} /* end debug_stub_init() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* kernel "exit" trap for gdb stub
|
||||
*/
|
||||
void debug_stub_exit(int status)
|
||||
{
|
||||
|
||||
#ifdef CONFIG_GDBSTUB
|
||||
gdbstub_exit(status);
|
||||
#endif
|
||||
|
||||
} /* end debug_stub_exit() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* send string to serial port
|
||||
*/
|
||||
void debug_to_serial(const char *p, int n)
|
||||
{
|
||||
char ch;
|
||||
|
||||
for (; n > 0; n--) {
|
||||
ch = *p++;
|
||||
FLOWCTL_SET0(DTR);
|
||||
LSR_WAIT_FOR0(THRE);
|
||||
// FLOWCTL_WAIT_FOR(CTS);
|
||||
|
||||
if (ch == 0x0a) {
|
||||
__UART0(TX) = 0x0d;
|
||||
mb();
|
||||
LSR_WAIT_FOR0(THRE);
|
||||
// FLOWCTL_WAIT_FOR(CTS);
|
||||
}
|
||||
__UART0(TX) = ch;
|
||||
mb();
|
||||
|
||||
FLOWCTL_CLEAR0(DTR);
|
||||
}
|
||||
|
||||
} /* end debug_to_serial() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* send string to serial port
|
||||
*/
|
||||
void debug_to_serial2(const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
char buf[64];
|
||||
int n;
|
||||
|
||||
va_start(va, fmt);
|
||||
n = vsprintf(buf, fmt, va);
|
||||
va_end(va);
|
||||
|
||||
debug_to_serial(buf, n);
|
||||
|
||||
} /* end debug_to_serial2() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* set up the ttyS0 serial port baud rate timers
|
||||
*/
|
||||
void __init console_set_baud(unsigned baud)
|
||||
{
|
||||
unsigned value, high, low;
|
||||
u8 lcr;
|
||||
|
||||
/* work out the divisor to give us the nearest higher baud rate */
|
||||
value = __serial_clock_speed_HZ / 16 / baud;
|
||||
|
||||
/* determine the baud rate range */
|
||||
high = __serial_clock_speed_HZ / 16 / value;
|
||||
low = __serial_clock_speed_HZ / 16 / (value + 1);
|
||||
|
||||
/* pick the nearest bound */
|
||||
if (low + (high - low) / 2 > baud)
|
||||
value++;
|
||||
|
||||
lcr = __UART0(LCR);
|
||||
__UART0(LCR) |= UART_LCR_DLAB;
|
||||
mb();
|
||||
__UART0(DLL) = value & 0xff;
|
||||
__UART0(DLM) = (value >> 8) & 0xff;
|
||||
mb();
|
||||
__UART0(LCR) = lcr;
|
||||
mb();
|
||||
|
||||
} /* end console_set_baud() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
*
|
||||
*/
|
||||
int __init console_get_baud(void)
|
||||
{
|
||||
unsigned value;
|
||||
u8 lcr;
|
||||
|
||||
lcr = __UART0(LCR);
|
||||
__UART0(LCR) |= UART_LCR_DLAB;
|
||||
mb();
|
||||
value = __UART0(DLM) << 8;
|
||||
value |= __UART0(DLL);
|
||||
__UART0(LCR) = lcr;
|
||||
mb();
|
||||
|
||||
return value;
|
||||
} /* end console_get_baud() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* display BUG() info
|
||||
*/
|
||||
#ifndef CONFIG_NO_KERNEL_MSG
|
||||
void __debug_bug_printk(const char *file, unsigned line)
|
||||
{
|
||||
printk("kernel BUG at %s:%d!\n", file, line);
|
||||
|
||||
} /* end __debug_bug_printk() */
|
||||
#endif
|
463
arch/frv/kernel/dma.c
Normal file
463
arch/frv/kernel/dma.c
Normal file
|
@ -0,0 +1,463 @@
|
|||
/* dma.c: DMA controller management on FR401 and the like
|
||||
*
|
||||
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/gpio-regs.h>
|
||||
#include <asm/irc-regs.h>
|
||||
#include <asm/cpu-irqs.h>
|
||||
|
||||
struct frv_dma_channel {
|
||||
uint8_t flags;
|
||||
#define FRV_DMA_FLAGS_RESERVED 0x01
|
||||
#define FRV_DMA_FLAGS_INUSE 0x02
|
||||
#define FRV_DMA_FLAGS_PAUSED 0x04
|
||||
uint8_t cap; /* capabilities available */
|
||||
int irq; /* completion IRQ */
|
||||
uint32_t dreqbit;
|
||||
uint32_t dackbit;
|
||||
uint32_t donebit;
|
||||
const unsigned long ioaddr; /* DMA controller regs addr */
|
||||
const char *devname;
|
||||
dma_irq_handler_t handler;
|
||||
void *data;
|
||||
};
|
||||
|
||||
|
||||
#define __get_DMAC(IO,X) ({ *(volatile unsigned long *)((IO) + DMAC_##X##x); })
|
||||
|
||||
#define __set_DMAC(IO,X,V) \
|
||||
do { \
|
||||
*(volatile unsigned long *)((IO) + DMAC_##X##x) = (V); \
|
||||
mb(); \
|
||||
} while(0)
|
||||
|
||||
#define ___set_DMAC(IO,X,V) \
|
||||
do { \
|
||||
*(volatile unsigned long *)((IO) + DMAC_##X##x) = (V); \
|
||||
} while(0)
|
||||
|
||||
|
||||
static struct frv_dma_channel frv_dma_channels[FRV_DMA_NCHANS] = {
|
||||
[0] = {
|
||||
.cap = FRV_DMA_CAP_DREQ | FRV_DMA_CAP_DACK | FRV_DMA_CAP_DONE,
|
||||
.irq = IRQ_CPU_DMA0,
|
||||
.dreqbit = SIR_DREQ0_INPUT,
|
||||
.dackbit = SOR_DACK0_OUTPUT,
|
||||
.donebit = SOR_DONE0_OUTPUT,
|
||||
.ioaddr = 0xfe000900,
|
||||
},
|
||||
[1] = {
|
||||
.cap = FRV_DMA_CAP_DREQ | FRV_DMA_CAP_DACK | FRV_DMA_CAP_DONE,
|
||||
.irq = IRQ_CPU_DMA1,
|
||||
.dreqbit = SIR_DREQ1_INPUT,
|
||||
.dackbit = SOR_DACK1_OUTPUT,
|
||||
.donebit = SOR_DONE1_OUTPUT,
|
||||
.ioaddr = 0xfe000980,
|
||||
},
|
||||
[2] = {
|
||||
.cap = FRV_DMA_CAP_DREQ | FRV_DMA_CAP_DACK,
|
||||
.irq = IRQ_CPU_DMA2,
|
||||
.dreqbit = SIR_DREQ2_INPUT,
|
||||
.dackbit = SOR_DACK2_OUTPUT,
|
||||
.ioaddr = 0xfe000a00,
|
||||
},
|
||||
[3] = {
|
||||
.cap = FRV_DMA_CAP_DREQ | FRV_DMA_CAP_DACK,
|
||||
.irq = IRQ_CPU_DMA3,
|
||||
.dreqbit = SIR_DREQ3_INPUT,
|
||||
.dackbit = SOR_DACK3_OUTPUT,
|
||||
.ioaddr = 0xfe000a80,
|
||||
},
|
||||
[4] = {
|
||||
.cap = FRV_DMA_CAP_DREQ,
|
||||
.irq = IRQ_CPU_DMA4,
|
||||
.dreqbit = SIR_DREQ4_INPUT,
|
||||
.ioaddr = 0xfe001000,
|
||||
},
|
||||
[5] = {
|
||||
.cap = FRV_DMA_CAP_DREQ,
|
||||
.irq = IRQ_CPU_DMA5,
|
||||
.dreqbit = SIR_DREQ5_INPUT,
|
||||
.ioaddr = 0xfe001080,
|
||||
},
|
||||
[6] = {
|
||||
.cap = FRV_DMA_CAP_DREQ,
|
||||
.irq = IRQ_CPU_DMA6,
|
||||
.dreqbit = SIR_DREQ6_INPUT,
|
||||
.ioaddr = 0xfe001100,
|
||||
},
|
||||
[7] = {
|
||||
.cap = FRV_DMA_CAP_DREQ,
|
||||
.irq = IRQ_CPU_DMA7,
|
||||
.dreqbit = SIR_DREQ7_INPUT,
|
||||
.ioaddr = 0xfe001180,
|
||||
},
|
||||
};
|
||||
|
||||
static DEFINE_RWLOCK(frv_dma_channels_lock);
|
||||
|
||||
unsigned long frv_dma_inprogress;
|
||||
|
||||
#define frv_clear_dma_inprogress(channel) \
|
||||
atomic_clear_mask(1 << (channel), &frv_dma_inprogress);
|
||||
|
||||
#define frv_set_dma_inprogress(channel) \
|
||||
atomic_set_mask(1 << (channel), &frv_dma_inprogress);
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* DMA irq handler - determine channel involved, grab status and call real handler
|
||||
*/
|
||||
static irqreturn_t dma_irq_handler(int irq, void *_channel)
|
||||
{
|
||||
struct frv_dma_channel *channel = _channel;
|
||||
|
||||
frv_clear_dma_inprogress(channel - frv_dma_channels);
|
||||
return channel->handler(channel - frv_dma_channels,
|
||||
__get_DMAC(channel->ioaddr, CSTR),
|
||||
channel->data);
|
||||
|
||||
} /* end dma_irq_handler() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* Determine which DMA controllers are present on this CPU
|
||||
*/
|
||||
void __init frv_dma_init(void)
|
||||
{
|
||||
unsigned long psr = __get_PSR();
|
||||
int num_dma, i;
|
||||
|
||||
/* First, determine how many DMA channels are available */
|
||||
switch (PSR_IMPLE(psr)) {
|
||||
case PSR_IMPLE_FR405:
|
||||
case PSR_IMPLE_FR451:
|
||||
case PSR_IMPLE_FR501:
|
||||
case PSR_IMPLE_FR551:
|
||||
num_dma = FRV_DMA_8CHANS;
|
||||
break;
|
||||
|
||||
case PSR_IMPLE_FR401:
|
||||
default:
|
||||
num_dma = FRV_DMA_4CHANS;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Now mark all of the non-existent channels as reserved */
|
||||
for(i = num_dma; i < FRV_DMA_NCHANS; i++)
|
||||
frv_dma_channels[i].flags = FRV_DMA_FLAGS_RESERVED;
|
||||
|
||||
} /* end frv_dma_init() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* allocate a DMA controller channel and the IRQ associated with it
|
||||
*/
|
||||
int frv_dma_open(const char *devname,
|
||||
unsigned long dmamask,
|
||||
int dmacap,
|
||||
dma_irq_handler_t handler,
|
||||
unsigned long irq_flags,
|
||||
void *data)
|
||||
{
|
||||
struct frv_dma_channel *channel;
|
||||
int dma, ret;
|
||||
uint32_t val;
|
||||
|
||||
write_lock(&frv_dma_channels_lock);
|
||||
|
||||
ret = -ENOSPC;
|
||||
|
||||
for (dma = FRV_DMA_NCHANS - 1; dma >= 0; dma--) {
|
||||
channel = &frv_dma_channels[dma];
|
||||
|
||||
if (!test_bit(dma, &dmamask))
|
||||
continue;
|
||||
|
||||
if ((channel->cap & dmacap) != dmacap)
|
||||
continue;
|
||||
|
||||
if (!frv_dma_channels[dma].flags)
|
||||
goto found;
|
||||
}
|
||||
|
||||
goto out;
|
||||
|
||||
found:
|
||||
ret = request_irq(channel->irq, dma_irq_handler, irq_flags, devname, channel);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* okay, we've allocated all the resources */
|
||||
channel = &frv_dma_channels[dma];
|
||||
|
||||
channel->flags |= FRV_DMA_FLAGS_INUSE;
|
||||
channel->devname = devname;
|
||||
channel->handler = handler;
|
||||
channel->data = data;
|
||||
|
||||
/* Now make sure we are set up for DMA and not GPIO */
|
||||
/* SIR bit must be set for DMA to work */
|
||||
__set_SIR(channel->dreqbit | __get_SIR());
|
||||
/* SOR bits depend on what the caller requests */
|
||||
val = __get_SOR();
|
||||
if(dmacap & FRV_DMA_CAP_DACK)
|
||||
val |= channel->dackbit;
|
||||
else
|
||||
val &= ~channel->dackbit;
|
||||
if(dmacap & FRV_DMA_CAP_DONE)
|
||||
val |= channel->donebit;
|
||||
else
|
||||
val &= ~channel->donebit;
|
||||
__set_SOR(val);
|
||||
|
||||
ret = dma;
|
||||
out:
|
||||
write_unlock(&frv_dma_channels_lock);
|
||||
return ret;
|
||||
} /* end frv_dma_open() */
|
||||
|
||||
EXPORT_SYMBOL(frv_dma_open);
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* close a DMA channel and its associated interrupt
|
||||
*/
|
||||
void frv_dma_close(int dma)
|
||||
{
|
||||
struct frv_dma_channel *channel = &frv_dma_channels[dma];
|
||||
unsigned long flags;
|
||||
|
||||
write_lock_irqsave(&frv_dma_channels_lock, flags);
|
||||
|
||||
free_irq(channel->irq, channel);
|
||||
frv_dma_stop(dma);
|
||||
|
||||
channel->flags &= ~FRV_DMA_FLAGS_INUSE;
|
||||
|
||||
write_unlock_irqrestore(&frv_dma_channels_lock, flags);
|
||||
} /* end frv_dma_close() */
|
||||
|
||||
EXPORT_SYMBOL(frv_dma_close);
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* set static configuration on a DMA channel
|
||||
*/
|
||||
void frv_dma_config(int dma, unsigned long ccfr, unsigned long cctr, unsigned long apr)
|
||||
{
|
||||
unsigned long ioaddr = frv_dma_channels[dma].ioaddr;
|
||||
|
||||
___set_DMAC(ioaddr, CCFR, ccfr);
|
||||
___set_DMAC(ioaddr, CCTR, cctr);
|
||||
___set_DMAC(ioaddr, APR, apr);
|
||||
mb();
|
||||
|
||||
} /* end frv_dma_config() */
|
||||
|
||||
EXPORT_SYMBOL(frv_dma_config);
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* start a DMA channel
|
||||
*/
|
||||
void frv_dma_start(int dma,
|
||||
unsigned long sba, unsigned long dba,
|
||||
unsigned long pix, unsigned long six, unsigned long bcl)
|
||||
{
|
||||
unsigned long ioaddr = frv_dma_channels[dma].ioaddr;
|
||||
|
||||
___set_DMAC(ioaddr, SBA, sba);
|
||||
___set_DMAC(ioaddr, DBA, dba);
|
||||
___set_DMAC(ioaddr, PIX, pix);
|
||||
___set_DMAC(ioaddr, SIX, six);
|
||||
___set_DMAC(ioaddr, BCL, bcl);
|
||||
___set_DMAC(ioaddr, CSTR, 0);
|
||||
mb();
|
||||
|
||||
__set_DMAC(ioaddr, CCTR, __get_DMAC(ioaddr, CCTR) | DMAC_CCTRx_ACT);
|
||||
frv_set_dma_inprogress(dma);
|
||||
|
||||
} /* end frv_dma_start() */
|
||||
|
||||
EXPORT_SYMBOL(frv_dma_start);
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* restart a DMA channel that's been stopped in circular addressing mode by comparison-end
|
||||
*/
|
||||
void frv_dma_restart_circular(int dma, unsigned long six)
|
||||
{
|
||||
unsigned long ioaddr = frv_dma_channels[dma].ioaddr;
|
||||
|
||||
___set_DMAC(ioaddr, SIX, six);
|
||||
___set_DMAC(ioaddr, CSTR, __get_DMAC(ioaddr, CSTR) & ~DMAC_CSTRx_CE);
|
||||
mb();
|
||||
|
||||
__set_DMAC(ioaddr, CCTR, __get_DMAC(ioaddr, CCTR) | DMAC_CCTRx_ACT);
|
||||
frv_set_dma_inprogress(dma);
|
||||
|
||||
} /* end frv_dma_restart_circular() */
|
||||
|
||||
EXPORT_SYMBOL(frv_dma_restart_circular);
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* stop a DMA channel
|
||||
*/
|
||||
void frv_dma_stop(int dma)
|
||||
{
|
||||
unsigned long ioaddr = frv_dma_channels[dma].ioaddr;
|
||||
uint32_t cctr;
|
||||
|
||||
___set_DMAC(ioaddr, CSTR, 0);
|
||||
cctr = __get_DMAC(ioaddr, CCTR);
|
||||
cctr &= ~(DMAC_CCTRx_IE | DMAC_CCTRx_ACT);
|
||||
cctr |= DMAC_CCTRx_FC; /* fifo clear */
|
||||
__set_DMAC(ioaddr, CCTR, cctr);
|
||||
__set_DMAC(ioaddr, BCL, 0);
|
||||
frv_clear_dma_inprogress(dma);
|
||||
} /* end frv_dma_stop() */
|
||||
|
||||
EXPORT_SYMBOL(frv_dma_stop);
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* test interrupt status of DMA channel
|
||||
*/
|
||||
int is_frv_dma_interrupting(int dma)
|
||||
{
|
||||
unsigned long ioaddr = frv_dma_channels[dma].ioaddr;
|
||||
|
||||
return __get_DMAC(ioaddr, CSTR) & (1 << 23);
|
||||
|
||||
} /* end is_frv_dma_interrupting() */
|
||||
|
||||
EXPORT_SYMBOL(is_frv_dma_interrupting);
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* dump data about a DMA channel
|
||||
*/
|
||||
void frv_dma_dump(int dma)
|
||||
{
|
||||
unsigned long ioaddr = frv_dma_channels[dma].ioaddr;
|
||||
unsigned long cstr, pix, six, bcl;
|
||||
|
||||
cstr = __get_DMAC(ioaddr, CSTR);
|
||||
pix = __get_DMAC(ioaddr, PIX);
|
||||
six = __get_DMAC(ioaddr, SIX);
|
||||
bcl = __get_DMAC(ioaddr, BCL);
|
||||
|
||||
printk("DMA[%d] cstr=%lx pix=%lx six=%lx bcl=%lx\n", dma, cstr, pix, six, bcl);
|
||||
|
||||
} /* end frv_dma_dump() */
|
||||
|
||||
EXPORT_SYMBOL(frv_dma_dump);
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* pause all DMA controllers
|
||||
* - called by clock mangling routines
|
||||
* - caller must be holding interrupts disabled
|
||||
*/
|
||||
void frv_dma_pause_all(void)
|
||||
{
|
||||
struct frv_dma_channel *channel;
|
||||
unsigned long ioaddr;
|
||||
unsigned long cstr, cctr;
|
||||
int dma;
|
||||
|
||||
write_lock(&frv_dma_channels_lock);
|
||||
|
||||
for (dma = FRV_DMA_NCHANS - 1; dma >= 0; dma--) {
|
||||
channel = &frv_dma_channels[dma];
|
||||
|
||||
if (!(channel->flags & FRV_DMA_FLAGS_INUSE))
|
||||
continue;
|
||||
|
||||
ioaddr = channel->ioaddr;
|
||||
cctr = __get_DMAC(ioaddr, CCTR);
|
||||
if (cctr & DMAC_CCTRx_ACT) {
|
||||
cctr &= ~DMAC_CCTRx_ACT;
|
||||
__set_DMAC(ioaddr, CCTR, cctr);
|
||||
|
||||
do {
|
||||
cstr = __get_DMAC(ioaddr, CSTR);
|
||||
} while (cstr & DMAC_CSTRx_BUSY);
|
||||
|
||||
if (cstr & DMAC_CSTRx_FED)
|
||||
channel->flags |= FRV_DMA_FLAGS_PAUSED;
|
||||
frv_clear_dma_inprogress(dma);
|
||||
}
|
||||
}
|
||||
|
||||
} /* end frv_dma_pause_all() */
|
||||
|
||||
EXPORT_SYMBOL(frv_dma_pause_all);
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* resume paused DMA controllers
|
||||
* - called by clock mangling routines
|
||||
* - caller must be holding interrupts disabled
|
||||
*/
|
||||
void frv_dma_resume_all(void)
|
||||
{
|
||||
struct frv_dma_channel *channel;
|
||||
unsigned long ioaddr;
|
||||
unsigned long cstr, cctr;
|
||||
int dma;
|
||||
|
||||
for (dma = FRV_DMA_NCHANS - 1; dma >= 0; dma--) {
|
||||
channel = &frv_dma_channels[dma];
|
||||
|
||||
if (!(channel->flags & FRV_DMA_FLAGS_PAUSED))
|
||||
continue;
|
||||
|
||||
ioaddr = channel->ioaddr;
|
||||
cstr = __get_DMAC(ioaddr, CSTR);
|
||||
cstr &= ~(DMAC_CSTRx_FED | DMAC_CSTRx_INT);
|
||||
__set_DMAC(ioaddr, CSTR, cstr);
|
||||
|
||||
cctr = __get_DMAC(ioaddr, CCTR);
|
||||
cctr |= DMAC_CCTRx_ACT;
|
||||
__set_DMAC(ioaddr, CCTR, cctr);
|
||||
|
||||
channel->flags &= ~FRV_DMA_FLAGS_PAUSED;
|
||||
frv_set_dma_inprogress(dma);
|
||||
}
|
||||
|
||||
write_unlock(&frv_dma_channels_lock);
|
||||
|
||||
} /* end frv_dma_resume_all() */
|
||||
|
||||
EXPORT_SYMBOL(frv_dma_resume_all);
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* dma status clear
|
||||
*/
|
||||
void frv_dma_status_clear(int dma)
|
||||
{
|
||||
unsigned long ioaddr = frv_dma_channels[dma].ioaddr;
|
||||
uint32_t cctr;
|
||||
___set_DMAC(ioaddr, CSTR, 0);
|
||||
|
||||
cctr = __get_DMAC(ioaddr, CCTR);
|
||||
} /* end frv_dma_status_clear() */
|
||||
|
||||
EXPORT_SYMBOL(frv_dma_status_clear);
|
329
arch/frv/kernel/entry-table.S
Normal file
329
arch/frv/kernel/entry-table.S
Normal file
|
@ -0,0 +1,329 @@
|
|||
/* entry-table.S: main trap vector tables and exception jump table
|
||||
*
|
||||
* Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/sys.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/spr-regs.h>
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Declare the main trap and vector tables
|
||||
#
|
||||
# There are six tables:
|
||||
#
|
||||
# (1) The trap table for debug mode
|
||||
# (2) The trap table for kernel mode
|
||||
# (3) The trap table for user mode
|
||||
#
|
||||
# The CPU jumps to an appropriate slot in the appropriate table to perform
|
||||
# exception processing. We have three different tables for the three
|
||||
# different CPU modes because there is no hardware differentiation between
|
||||
# stack pointers for these three modes, and so we have to invent one when
|
||||
# crossing mode boundaries.
|
||||
#
|
||||
# (4) The exception handler vector table
|
||||
#
|
||||
# The user and kernel trap tables use the same prologue for normal
|
||||
# exception processing. The prologue then jumps to the handler in this
|
||||
# table, as indexed by the exception ID from the TBR.
|
||||
#
|
||||
# (5) The fixup table for kernel-trap single-step
|
||||
# (6) The fixup table for user-trap single-step
|
||||
#
|
||||
# Due to the way single-stepping works on this CPU (single-step is not
|
||||
# disabled when crossing exception boundaries, only when in debug mode),
|
||||
# we have to catch the single-step event in break.S and jump to the fixup
|
||||
# routine pointed to by this table.
|
||||
#
|
||||
# The linker script places the user mode and kernel mode trap tables on to
|
||||
# the same 8Kb page, so that break.S can be more efficient when performing
|
||||
# single-step bypass management
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
# trap table for entry from debug mode
|
||||
.section .trap.break,"ax"
|
||||
.balign 256*16
|
||||
.globl __entry_breaktrap_table
|
||||
__entry_breaktrap_table:
|
||||
|
||||
# trap table for entry from user mode
|
||||
.section .trap.user,"ax"
|
||||
.balign 256*16
|
||||
.globl __entry_usertrap_table
|
||||
__entry_usertrap_table:
|
||||
|
||||
# trap table for entry from kernel mode
|
||||
.section .trap.kernel,"ax"
|
||||
.balign 256*16
|
||||
.globl __entry_kerneltrap_table
|
||||
__entry_kerneltrap_table:
|
||||
|
||||
# exception handler jump table
|
||||
.section .trap.vector,"ax"
|
||||
.balign 256*4
|
||||
.globl __entry_vector_table
|
||||
__entry_vector_table:
|
||||
|
||||
# trap fixup table for single-stepping in user mode
|
||||
.section .trap.fixup.user,"a"
|
||||
.balign 256*4
|
||||
.globl __break_usertrap_fixup_table
|
||||
__break_usertrap_fixup_table:
|
||||
|
||||
# trap fixup table for single-stepping in user mode
|
||||
.section .trap.fixup.kernel,"a"
|
||||
.balign 256*4
|
||||
.globl __break_kerneltrap_fixup_table
|
||||
__break_kerneltrap_fixup_table:
|
||||
|
||||
# handler declaration for a software or program interrupt
|
||||
.macro VECTOR_SOFTPROG tbr_tt, vec
|
||||
.section .trap.user
|
||||
.org \tbr_tt
|
||||
bra __entry_uspace_softprog_interrupt
|
||||
.section .trap.fixup.user
|
||||
.org \tbr_tt >> 2
|
||||
.long __break_step_uspace_softprog_interrupt
|
||||
.section .trap.kernel
|
||||
.org \tbr_tt
|
||||
bra __entry_kernel_softprog_interrupt
|
||||
.section .trap.fixup.kernel
|
||||
.org \tbr_tt >> 2
|
||||
.long __break_step_kernel_softprog_interrupt
|
||||
.section .trap.vector
|
||||
.org \tbr_tt >> 2
|
||||
.long \vec
|
||||
.endm
|
||||
|
||||
# handler declaration for a maskable external interrupt
|
||||
.macro VECTOR_IRQ tbr_tt, vec
|
||||
.section .trap.user
|
||||
.org \tbr_tt
|
||||
bra __entry_uspace_external_interrupt
|
||||
.section .trap.fixup.user
|
||||
.org \tbr_tt >> 2
|
||||
.long __break_step_uspace_external_interrupt
|
||||
.section .trap.kernel
|
||||
.org \tbr_tt
|
||||
# deal with virtual interrupt disablement
|
||||
beq icc2,#0,__entry_kernel_external_interrupt_virtually_disabled
|
||||
bra __entry_kernel_external_interrupt
|
||||
.section .trap.fixup.kernel
|
||||
.org \tbr_tt >> 2
|
||||
.long __break_step_kernel_external_interrupt
|
||||
.section .trap.vector
|
||||
.org \tbr_tt >> 2
|
||||
.long \vec
|
||||
.endm
|
||||
|
||||
# handler declaration for an NMI external interrupt
|
||||
.macro VECTOR_NMI tbr_tt, vec
|
||||
.section .trap.user
|
||||
.org \tbr_tt
|
||||
break
|
||||
break
|
||||
break
|
||||
break
|
||||
.section .trap.kernel
|
||||
.org \tbr_tt
|
||||
break
|
||||
break
|
||||
break
|
||||
break
|
||||
.section .trap.vector
|
||||
.org \tbr_tt >> 2
|
||||
.long \vec
|
||||
.endm
|
||||
|
||||
# handler declaration for an MMU only software or program interrupt
|
||||
.macro VECTOR_SP_MMU tbr_tt, vec
|
||||
#ifdef CONFIG_MMU
|
||||
VECTOR_SOFTPROG \tbr_tt, \vec
|
||||
#else
|
||||
VECTOR_NMI \tbr_tt, 0
|
||||
#endif
|
||||
.endm
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# specification of the vectors
|
||||
# - note: each macro inserts code into multiple sections
|
||||
#
|
||||
###############################################################################
|
||||
VECTOR_SP_MMU TBR_TT_INSTR_MMU_MISS, __entry_insn_mmu_miss
|
||||
VECTOR_SOFTPROG TBR_TT_INSTR_ACC_ERROR, __entry_insn_access_error
|
||||
VECTOR_SOFTPROG TBR_TT_INSTR_ACC_EXCEP, __entry_insn_access_exception
|
||||
VECTOR_SOFTPROG TBR_TT_PRIV_INSTR, __entry_privileged_instruction
|
||||
VECTOR_SOFTPROG TBR_TT_ILLEGAL_INSTR, __entry_illegal_instruction
|
||||
VECTOR_SOFTPROG TBR_TT_FP_EXCEPTION, __entry_media_exception
|
||||
VECTOR_SOFTPROG TBR_TT_MP_EXCEPTION, __entry_media_exception
|
||||
VECTOR_SOFTPROG TBR_TT_DATA_ACC_ERROR, __entry_data_access_error
|
||||
VECTOR_SP_MMU TBR_TT_DATA_MMU_MISS, __entry_data_mmu_miss
|
||||
VECTOR_SOFTPROG TBR_TT_DATA_ACC_EXCEP, __entry_data_access_exception
|
||||
VECTOR_SOFTPROG TBR_TT_DATA_STR_ERROR, __entry_data_store_error
|
||||
VECTOR_SOFTPROG TBR_TT_DIVISION_EXCEP, __entry_division_exception
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
.section .trap.user
|
||||
.org TBR_TT_INSTR_TLB_MISS
|
||||
.globl __trap_user_insn_tlb_miss
|
||||
__trap_user_insn_tlb_miss:
|
||||
movsg ear0,gr28 /* faulting address */
|
||||
movsg scr0,gr31 /* get mapped PTD coverage start address */
|
||||
xor.p gr28,gr31,gr31 /* compare addresses */
|
||||
bra __entry_user_insn_tlb_miss
|
||||
|
||||
.org TBR_TT_DATA_TLB_MISS
|
||||
.globl __trap_user_data_tlb_miss
|
||||
__trap_user_data_tlb_miss:
|
||||
movsg ear0,gr28 /* faulting address */
|
||||
movsg scr1,gr31 /* get mapped PTD coverage start address */
|
||||
xor.p gr28,gr31,gr31 /* compare addresses */
|
||||
bra __entry_user_data_tlb_miss
|
||||
|
||||
.section .trap.kernel
|
||||
.org TBR_TT_INSTR_TLB_MISS
|
||||
.globl __trap_kernel_insn_tlb_miss
|
||||
__trap_kernel_insn_tlb_miss:
|
||||
movsg ear0,gr29 /* faulting address */
|
||||
movsg scr0,gr31 /* get mapped PTD coverage start address */
|
||||
xor.p gr29,gr31,gr31 /* compare addresses */
|
||||
bra __entry_kernel_insn_tlb_miss
|
||||
|
||||
.org TBR_TT_DATA_TLB_MISS
|
||||
.globl __trap_kernel_data_tlb_miss
|
||||
__trap_kernel_data_tlb_miss:
|
||||
movsg ear0,gr29 /* faulting address */
|
||||
movsg scr1,gr31 /* get mapped PTD coverage start address */
|
||||
xor.p gr29,gr31,gr31 /* compare addresses */
|
||||
bra __entry_kernel_data_tlb_miss
|
||||
|
||||
.section .trap.fixup.user
|
||||
.org TBR_TT_INSTR_TLB_MISS >> 2
|
||||
.globl __trap_fixup_user_insn_tlb_miss
|
||||
__trap_fixup_user_insn_tlb_miss:
|
||||
.long __break_user_insn_tlb_miss
|
||||
.org TBR_TT_DATA_TLB_MISS >> 2
|
||||
.globl __trap_fixup_user_data_tlb_miss
|
||||
__trap_fixup_user_data_tlb_miss:
|
||||
.long __break_user_data_tlb_miss
|
||||
|
||||
.section .trap.fixup.kernel
|
||||
.org TBR_TT_INSTR_TLB_MISS >> 2
|
||||
.globl __trap_fixup_kernel_insn_tlb_miss
|
||||
__trap_fixup_kernel_insn_tlb_miss:
|
||||
.long __break_kernel_insn_tlb_miss
|
||||
.org TBR_TT_DATA_TLB_MISS >> 2
|
||||
.globl __trap_fixup_kernel_data_tlb_miss
|
||||
__trap_fixup_kernel_data_tlb_miss:
|
||||
.long __break_kernel_data_tlb_miss
|
||||
|
||||
.section .trap.vector
|
||||
.org TBR_TT_INSTR_TLB_MISS >> 2
|
||||
.long __entry_insn_mmu_fault
|
||||
.org TBR_TT_DATA_TLB_MISS >> 2
|
||||
.long __entry_data_mmu_fault
|
||||
#endif
|
||||
|
||||
VECTOR_SP_MMU TBR_TT_DATA_DAT_EXCEP, __entry_data_dat_fault
|
||||
VECTOR_NMI TBR_TT_DECREMENT_TIMER, __entry_do_NMI
|
||||
VECTOR_SOFTPROG TBR_TT_COMPOUND_EXCEP, __entry_compound_exception
|
||||
VECTOR_IRQ TBR_TT_INTERRUPT_1, __entry_do_IRQ
|
||||
VECTOR_IRQ TBR_TT_INTERRUPT_2, __entry_do_IRQ
|
||||
VECTOR_IRQ TBR_TT_INTERRUPT_3, __entry_do_IRQ
|
||||
VECTOR_IRQ TBR_TT_INTERRUPT_4, __entry_do_IRQ
|
||||
VECTOR_IRQ TBR_TT_INTERRUPT_5, __entry_do_IRQ
|
||||
VECTOR_IRQ TBR_TT_INTERRUPT_6, __entry_do_IRQ
|
||||
VECTOR_IRQ TBR_TT_INTERRUPT_7, __entry_do_IRQ
|
||||
VECTOR_IRQ TBR_TT_INTERRUPT_8, __entry_do_IRQ
|
||||
VECTOR_IRQ TBR_TT_INTERRUPT_9, __entry_do_IRQ
|
||||
VECTOR_IRQ TBR_TT_INTERRUPT_10, __entry_do_IRQ
|
||||
VECTOR_IRQ TBR_TT_INTERRUPT_11, __entry_do_IRQ
|
||||
VECTOR_IRQ TBR_TT_INTERRUPT_12, __entry_do_IRQ
|
||||
VECTOR_IRQ TBR_TT_INTERRUPT_13, __entry_do_IRQ
|
||||
VECTOR_IRQ TBR_TT_INTERRUPT_14, __entry_do_IRQ
|
||||
VECTOR_NMI TBR_TT_INTERRUPT_15, __entry_do_NMI
|
||||
|
||||
# miscellaneous user mode entry points
|
||||
.section .trap.user
|
||||
.org TBR_TT_TRAP0
|
||||
.rept 127
|
||||
bra __entry_uspace_softprog_interrupt
|
||||
.long 0,0,0
|
||||
.endr
|
||||
.org TBR_TT_BREAK
|
||||
bra __entry_break
|
||||
.long 0,0,0
|
||||
|
||||
.section .trap.fixup.user
|
||||
.org TBR_TT_TRAP0 >> 2
|
||||
.rept 127
|
||||
.long __break_step_uspace_softprog_interrupt
|
||||
.endr
|
||||
.org TBR_TT_BREAK >> 2
|
||||
.long 0
|
||||
|
||||
# miscellaneous kernel mode entry points
|
||||
.section .trap.kernel
|
||||
.org TBR_TT_TRAP0
|
||||
bra __entry_kernel_softprog_interrupt
|
||||
.org TBR_TT_TRAP1
|
||||
bra __entry_kernel_softprog_interrupt
|
||||
|
||||
# trap #2 in kernel - reenable interrupts
|
||||
.org TBR_TT_TRAP2
|
||||
bra __entry_kernel_external_interrupt_virtual_reenable
|
||||
|
||||
# miscellaneous kernel traps
|
||||
.org TBR_TT_TRAP3
|
||||
.rept 124
|
||||
bra __entry_kernel_softprog_interrupt
|
||||
.long 0,0,0
|
||||
.endr
|
||||
.org TBR_TT_BREAK
|
||||
bra __entry_break
|
||||
.long 0,0,0
|
||||
|
||||
.section .trap.fixup.kernel
|
||||
.org TBR_TT_TRAP0 >> 2
|
||||
.long __break_step_kernel_softprog_interrupt
|
||||
.long __break_step_kernel_softprog_interrupt
|
||||
.long __break_step_kernel_external_interrupt_virtual_reenable
|
||||
.rept 124
|
||||
.long __break_step_kernel_softprog_interrupt
|
||||
.endr
|
||||
.org TBR_TT_BREAK >> 2
|
||||
.long 0
|
||||
|
||||
# miscellaneous debug mode entry points
|
||||
.section .trap.break
|
||||
.org TBR_TT_BREAK
|
||||
movsg bpcsr,gr30
|
||||
jmpl @(gr30,gr0)
|
||||
|
||||
# miscellaneous vectors
|
||||
.section .trap.vector
|
||||
.org TBR_TT_TRAP0 >> 2
|
||||
.long system_call
|
||||
.rept 119
|
||||
.long __entry_unsupported_trap
|
||||
.endr
|
||||
|
||||
# userspace atomic op emulation, traps 120-126
|
||||
.rept 7
|
||||
.long __entry_atomic_op
|
||||
.endr
|
||||
|
||||
.org TBR_TT_BREAK >> 2
|
||||
.long __entry_debug_exception
|
1519
arch/frv/kernel/entry.S
Normal file
1519
arch/frv/kernel/entry.S
Normal file
File diff suppressed because it is too large
Load diff
113
arch/frv/kernel/frv_ksyms.c
Normal file
113
arch/frv/kernel/frv_ksyms.c
Normal file
|
@ -0,0 +1,113 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/user.h>
|
||||
#include <linux/elfcore.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <asm/setup.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/checksum.h>
|
||||
#include <asm/hardirq.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
extern long __memcpy_user(void *dst, const void *src, size_t count);
|
||||
extern long __memset_user(void *dst, const void *src, size_t count);
|
||||
|
||||
/* platform dependent support */
|
||||
|
||||
EXPORT_SYMBOL(__ioremap);
|
||||
EXPORT_SYMBOL(iounmap);
|
||||
|
||||
EXPORT_SYMBOL(ip_fast_csum);
|
||||
|
||||
#if 0
|
||||
EXPORT_SYMBOL(local_irq_count);
|
||||
EXPORT_SYMBOL(local_bh_count);
|
||||
#endif
|
||||
|
||||
EXPORT_SYMBOL(__res_bus_clock_speed_HZ);
|
||||
EXPORT_SYMBOL(__page_offset);
|
||||
EXPORT_SYMBOL(__memcpy_user);
|
||||
EXPORT_SYMBOL(__memset_user);
|
||||
EXPORT_SYMBOL(frv_dcache_writeback);
|
||||
EXPORT_SYMBOL(frv_cache_invalidate);
|
||||
EXPORT_SYMBOL(frv_icache_invalidate);
|
||||
EXPORT_SYMBOL(frv_cache_wback_inv);
|
||||
|
||||
#ifndef CONFIG_MMU
|
||||
EXPORT_SYMBOL(memory_start);
|
||||
EXPORT_SYMBOL(memory_end);
|
||||
#endif
|
||||
|
||||
EXPORT_SYMBOL(__debug_bug_trap);
|
||||
|
||||
/* The following are special because they're not called
|
||||
explicitly (the C compiler generates them). Fortunately,
|
||||
their interface isn't gonna change any time soon now, so
|
||||
it's OK to leave it out of version control. */
|
||||
EXPORT_SYMBOL(memcpy);
|
||||
EXPORT_SYMBOL(memset);
|
||||
|
||||
EXPORT_SYMBOL(__outsl_ns);
|
||||
EXPORT_SYMBOL(__insl_ns);
|
||||
|
||||
#ifdef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS
|
||||
EXPORT_SYMBOL(atomic_test_and_ANDNOT_mask);
|
||||
EXPORT_SYMBOL(atomic_test_and_OR_mask);
|
||||
EXPORT_SYMBOL(atomic_test_and_XOR_mask);
|
||||
EXPORT_SYMBOL(atomic_add_return);
|
||||
EXPORT_SYMBOL(atomic_sub_return);
|
||||
EXPORT_SYMBOL(__xchg_32);
|
||||
EXPORT_SYMBOL(__cmpxchg_32);
|
||||
#endif
|
||||
EXPORT_SYMBOL(atomic64_add_return);
|
||||
EXPORT_SYMBOL(atomic64_sub_return);
|
||||
EXPORT_SYMBOL(__xchg_64);
|
||||
EXPORT_SYMBOL(__cmpxchg_64);
|
||||
|
||||
EXPORT_SYMBOL(__debug_bug_printk);
|
||||
EXPORT_SYMBOL(__delay_loops_MHz);
|
||||
|
||||
/*
|
||||
* libgcc functions - functions that are used internally by the
|
||||
* compiler... (prototypes are not correct though, but that
|
||||
* doesn't really matter since they're not versioned).
|
||||
*/
|
||||
extern void __gcc_bcmp(void);
|
||||
extern void __ashldi3(void);
|
||||
extern void __ashrdi3(void);
|
||||
extern void __cmpdi2(void);
|
||||
extern void __divdi3(void);
|
||||
extern void __lshrdi3(void);
|
||||
extern void __moddi3(void);
|
||||
extern void __muldi3(void);
|
||||
extern void __mulll(void);
|
||||
extern void __umulll(void);
|
||||
extern void __negdi2(void);
|
||||
extern void __ucmpdi2(void);
|
||||
extern void __udivdi3(void);
|
||||
extern void __udivmoddi4(void);
|
||||
extern void __umoddi3(void);
|
||||
|
||||
/* gcc lib functions */
|
||||
//EXPORT_SYMBOL(__gcc_bcmp);
|
||||
EXPORT_SYMBOL(__ashldi3);
|
||||
EXPORT_SYMBOL(__ashrdi3);
|
||||
//EXPORT_SYMBOL(__cmpdi2);
|
||||
//EXPORT_SYMBOL(__divdi3);
|
||||
EXPORT_SYMBOL(__lshrdi3);
|
||||
//EXPORT_SYMBOL(__moddi3);
|
||||
EXPORT_SYMBOL(__muldi3);
|
||||
EXPORT_SYMBOL(__mulll);
|
||||
EXPORT_SYMBOL(__umulll);
|
||||
EXPORT_SYMBOL(__negdi2);
|
||||
EXPORT_SYMBOL(__ucmpdi2);
|
||||
//EXPORT_SYMBOL(__udivdi3);
|
||||
//EXPORT_SYMBOL(__udivmoddi4);
|
||||
//EXPORT_SYMBOL(__umoddi3);
|
242
arch/frv/kernel/futex.c
Normal file
242
arch/frv/kernel/futex.c
Normal file
|
@ -0,0 +1,242 @@
|
|||
/* futex.c: futex operations
|
||||
*
|
||||
* Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/futex.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/futex.h>
|
||||
#include <asm/errno.h>
|
||||
|
||||
/*
|
||||
* the various futex operations; MMU fault checking is ignored under no-MMU
|
||||
* conditions
|
||||
*/
|
||||
static inline int atomic_futex_op_xchg_set(int oparg, u32 __user *uaddr, int *_oldval)
|
||||
{
|
||||
int oldval, ret;
|
||||
|
||||
asm("0: \n"
|
||||
" orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */
|
||||
" ckeq icc3,cc7 \n"
|
||||
"1: ld.p %M0,%1 \n" /* LD.P/ORCR must be atomic */
|
||||
" orcr cc7,cc7,cc3 \n" /* set CC3 to true */
|
||||
"2: cst.p %3,%M0 ,cc3,#1 \n"
|
||||
" corcc gr29,gr29,gr0 ,cc3,#1 \n" /* clear ICC3.Z if store happens */
|
||||
" beq icc3,#0,0b \n"
|
||||
" setlos 0,%2 \n"
|
||||
"3: \n"
|
||||
".subsection 2 \n"
|
||||
"4: setlos %5,%2 \n"
|
||||
" bra 3b \n"
|
||||
".previous \n"
|
||||
".section __ex_table,\"a\" \n"
|
||||
" .balign 8 \n"
|
||||
" .long 1b,4b \n"
|
||||
" .long 2b,4b \n"
|
||||
".previous"
|
||||
: "+U"(*uaddr), "=&r"(oldval), "=&r"(ret), "=r"(oparg)
|
||||
: "3"(oparg), "i"(-EFAULT)
|
||||
: "memory", "cc7", "cc3", "icc3"
|
||||
);
|
||||
|
||||
*_oldval = oldval;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int atomic_futex_op_xchg_add(int oparg, u32 __user *uaddr, int *_oldval)
|
||||
{
|
||||
int oldval, ret;
|
||||
|
||||
asm("0: \n"
|
||||
" orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */
|
||||
" ckeq icc3,cc7 \n"
|
||||
"1: ld.p %M0,%1 \n" /* LD.P/ORCR must be atomic */
|
||||
" orcr cc7,cc7,cc3 \n" /* set CC3 to true */
|
||||
" add %1,%3,%3 \n"
|
||||
"2: cst.p %3,%M0 ,cc3,#1 \n"
|
||||
" corcc gr29,gr29,gr0 ,cc3,#1 \n" /* clear ICC3.Z if store happens */
|
||||
" beq icc3,#0,0b \n"
|
||||
" setlos 0,%2 \n"
|
||||
"3: \n"
|
||||
".subsection 2 \n"
|
||||
"4: setlos %5,%2 \n"
|
||||
" bra 3b \n"
|
||||
".previous \n"
|
||||
".section __ex_table,\"a\" \n"
|
||||
" .balign 8 \n"
|
||||
" .long 1b,4b \n"
|
||||
" .long 2b,4b \n"
|
||||
".previous"
|
||||
: "+U"(*uaddr), "=&r"(oldval), "=&r"(ret), "=r"(oparg)
|
||||
: "3"(oparg), "i"(-EFAULT)
|
||||
: "memory", "cc7", "cc3", "icc3"
|
||||
);
|
||||
|
||||
*_oldval = oldval;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int atomic_futex_op_xchg_or(int oparg, u32 __user *uaddr, int *_oldval)
|
||||
{
|
||||
int oldval, ret;
|
||||
|
||||
asm("0: \n"
|
||||
" orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */
|
||||
" ckeq icc3,cc7 \n"
|
||||
"1: ld.p %M0,%1 \n" /* LD.P/ORCR must be atomic */
|
||||
" orcr cc7,cc7,cc3 \n" /* set CC3 to true */
|
||||
" or %1,%3,%3 \n"
|
||||
"2: cst.p %3,%M0 ,cc3,#1 \n"
|
||||
" corcc gr29,gr29,gr0 ,cc3,#1 \n" /* clear ICC3.Z if store happens */
|
||||
" beq icc3,#0,0b \n"
|
||||
" setlos 0,%2 \n"
|
||||
"3: \n"
|
||||
".subsection 2 \n"
|
||||
"4: setlos %5,%2 \n"
|
||||
" bra 3b \n"
|
||||
".previous \n"
|
||||
".section __ex_table,\"a\" \n"
|
||||
" .balign 8 \n"
|
||||
" .long 1b,4b \n"
|
||||
" .long 2b,4b \n"
|
||||
".previous"
|
||||
: "+U"(*uaddr), "=&r"(oldval), "=&r"(ret), "=r"(oparg)
|
||||
: "3"(oparg), "i"(-EFAULT)
|
||||
: "memory", "cc7", "cc3", "icc3"
|
||||
);
|
||||
|
||||
*_oldval = oldval;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int atomic_futex_op_xchg_and(int oparg, u32 __user *uaddr, int *_oldval)
|
||||
{
|
||||
int oldval, ret;
|
||||
|
||||
asm("0: \n"
|
||||
" orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */
|
||||
" ckeq icc3,cc7 \n"
|
||||
"1: ld.p %M0,%1 \n" /* LD.P/ORCR must be atomic */
|
||||
" orcr cc7,cc7,cc3 \n" /* set CC3 to true */
|
||||
" and %1,%3,%3 \n"
|
||||
"2: cst.p %3,%M0 ,cc3,#1 \n"
|
||||
" corcc gr29,gr29,gr0 ,cc3,#1 \n" /* clear ICC3.Z if store happens */
|
||||
" beq icc3,#0,0b \n"
|
||||
" setlos 0,%2 \n"
|
||||
"3: \n"
|
||||
".subsection 2 \n"
|
||||
"4: setlos %5,%2 \n"
|
||||
" bra 3b \n"
|
||||
".previous \n"
|
||||
".section __ex_table,\"a\" \n"
|
||||
" .balign 8 \n"
|
||||
" .long 1b,4b \n"
|
||||
" .long 2b,4b \n"
|
||||
".previous"
|
||||
: "+U"(*uaddr), "=&r"(oldval), "=&r"(ret), "=r"(oparg)
|
||||
: "3"(oparg), "i"(-EFAULT)
|
||||
: "memory", "cc7", "cc3", "icc3"
|
||||
);
|
||||
|
||||
*_oldval = oldval;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int atomic_futex_op_xchg_xor(int oparg, u32 __user *uaddr, int *_oldval)
|
||||
{
|
||||
int oldval, ret;
|
||||
|
||||
asm("0: \n"
|
||||
" orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */
|
||||
" ckeq icc3,cc7 \n"
|
||||
"1: ld.p %M0,%1 \n" /* LD.P/ORCR must be atomic */
|
||||
" orcr cc7,cc7,cc3 \n" /* set CC3 to true */
|
||||
" xor %1,%3,%3 \n"
|
||||
"2: cst.p %3,%M0 ,cc3,#1 \n"
|
||||
" corcc gr29,gr29,gr0 ,cc3,#1 \n" /* clear ICC3.Z if store happens */
|
||||
" beq icc3,#0,0b \n"
|
||||
" setlos 0,%2 \n"
|
||||
"3: \n"
|
||||
".subsection 2 \n"
|
||||
"4: setlos %5,%2 \n"
|
||||
" bra 3b \n"
|
||||
".previous \n"
|
||||
".section __ex_table,\"a\" \n"
|
||||
" .balign 8 \n"
|
||||
" .long 1b,4b \n"
|
||||
" .long 2b,4b \n"
|
||||
".previous"
|
||||
: "+U"(*uaddr), "=&r"(oldval), "=&r"(ret), "=r"(oparg)
|
||||
: "3"(oparg), "i"(-EFAULT)
|
||||
: "memory", "cc7", "cc3", "icc3"
|
||||
);
|
||||
|
||||
*_oldval = oldval;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* do the futex operations
|
||||
*/
|
||||
int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
||||
{
|
||||
int op = (encoded_op >> 28) & 7;
|
||||
int cmp = (encoded_op >> 24) & 15;
|
||||
int oparg = (encoded_op << 8) >> 20;
|
||||
int cmparg = (encoded_op << 20) >> 20;
|
||||
int oldval = 0, ret;
|
||||
|
||||
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
||||
oparg = 1 << oparg;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
|
||||
return -EFAULT;
|
||||
|
||||
pagefault_disable();
|
||||
|
||||
switch (op) {
|
||||
case FUTEX_OP_SET:
|
||||
ret = atomic_futex_op_xchg_set(oparg, uaddr, &oldval);
|
||||
break;
|
||||
case FUTEX_OP_ADD:
|
||||
ret = atomic_futex_op_xchg_add(oparg, uaddr, &oldval);
|
||||
break;
|
||||
case FUTEX_OP_OR:
|
||||
ret = atomic_futex_op_xchg_or(oparg, uaddr, &oldval);
|
||||
break;
|
||||
case FUTEX_OP_ANDN:
|
||||
ret = atomic_futex_op_xchg_and(~oparg, uaddr, &oldval);
|
||||
break;
|
||||
case FUTEX_OP_XOR:
|
||||
ret = atomic_futex_op_xchg_xor(oparg, uaddr, &oldval);
|
||||
break;
|
||||
default:
|
||||
ret = -ENOSYS;
|
||||
break;
|
||||
}
|
||||
|
||||
pagefault_enable();
|
||||
|
||||
if (!ret) {
|
||||
switch (cmp) {
|
||||
case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
|
||||
case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
|
||||
case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
|
||||
case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
|
||||
case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
|
||||
case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
|
||||
default: ret = -ENOSYS; break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
} /* end futex_atomic_op_inuser() */
|
215
arch/frv/kernel/gdb-io.c
Normal file
215
arch/frv/kernel/gdb-io.c
Normal file
|
@ -0,0 +1,215 @@
|
|||
/* gdb-io.c: FR403 GDB stub I/O
|
||||
*
|
||||
* Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/serial_reg.h>
|
||||
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/irc-regs.h>
|
||||
#include <asm/timer-regs.h>
|
||||
#include <asm/gdb-stub.h>
|
||||
#include "gdb-io.h"
|
||||
|
||||
#ifdef CONFIG_GDBSTUB_UART0
|
||||
#define __UART(X) (*(volatile uint8_t *)(UART0_BASE + (UART_##X)))
|
||||
#define __UART_IRR_NMI 0xff0f0000
|
||||
#else /* CONFIG_GDBSTUB_UART1 */
|
||||
#define __UART(X) (*(volatile uint8_t *)(UART1_BASE + (UART_##X)))
|
||||
#define __UART_IRR_NMI 0xfff00000
|
||||
#endif
|
||||
|
||||
#define LSR_WAIT_FOR(STATE) \
|
||||
do { \
|
||||
gdbstub_do_rx(); \
|
||||
} while (!(__UART(LSR) & UART_LSR_##STATE))
|
||||
|
||||
#define FLOWCTL_QUERY(LINE) ({ __UART(MSR) & UART_MSR_##LINE; })
|
||||
#define FLOWCTL_CLEAR(LINE) do { __UART(MCR) &= ~UART_MCR_##LINE; mb(); } while (0)
|
||||
#define FLOWCTL_SET(LINE) do { __UART(MCR) |= UART_MCR_##LINE; mb(); } while (0)
|
||||
|
||||
#define FLOWCTL_WAIT_FOR(LINE) \
|
||||
do { \
|
||||
gdbstub_do_rx(); \
|
||||
} while(!FLOWCTL_QUERY(LINE))
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* initialise the GDB stub
|
||||
* - called with PSR.ET==0, so can't incur external interrupts
|
||||
*/
|
||||
void gdbstub_io_init(void)
|
||||
{
|
||||
/* set up the serial port */
|
||||
__UART(LCR) = UART_LCR_WLEN8; /* 1N8 */
|
||||
__UART(FCR) =
|
||||
UART_FCR_ENABLE_FIFO |
|
||||
UART_FCR_CLEAR_RCVR |
|
||||
UART_FCR_CLEAR_XMIT |
|
||||
UART_FCR_TRIGGER_1;
|
||||
|
||||
FLOWCTL_CLEAR(DTR);
|
||||
FLOWCTL_SET(RTS);
|
||||
|
||||
// gdbstub_set_baud(115200);
|
||||
|
||||
/* we want to get serial receive interrupts */
|
||||
__UART(IER) = UART_IER_RDI | UART_IER_RLSI;
|
||||
mb();
|
||||
|
||||
__set_IRR(6, __UART_IRR_NMI); /* map ERRs and UARTx to NMI */
|
||||
|
||||
} /* end gdbstub_io_init() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* set up the GDB stub serial port baud rate timers
|
||||
*/
|
||||
void gdbstub_set_baud(unsigned baud)
|
||||
{
|
||||
unsigned value, high, low;
|
||||
u8 lcr;
|
||||
|
||||
/* work out the divisor to give us the nearest higher baud rate */
|
||||
value = __serial_clock_speed_HZ / 16 / baud;
|
||||
|
||||
/* determine the baud rate range */
|
||||
high = __serial_clock_speed_HZ / 16 / value;
|
||||
low = __serial_clock_speed_HZ / 16 / (value + 1);
|
||||
|
||||
/* pick the nearest bound */
|
||||
if (low + (high - low) / 2 > baud)
|
||||
value++;
|
||||
|
||||
lcr = __UART(LCR);
|
||||
__UART(LCR) |= UART_LCR_DLAB;
|
||||
mb();
|
||||
__UART(DLL) = value & 0xff;
|
||||
__UART(DLM) = (value >> 8) & 0xff;
|
||||
mb();
|
||||
__UART(LCR) = lcr;
|
||||
mb();
|
||||
|
||||
} /* end gdbstub_set_baud() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* receive characters into the receive FIFO
|
||||
*/
|
||||
void gdbstub_do_rx(void)
|
||||
{
|
||||
unsigned ix, nix;
|
||||
|
||||
ix = gdbstub_rx_inp;
|
||||
|
||||
while (__UART(LSR) & UART_LSR_DR) {
|
||||
nix = (ix + 2) & 0xfff;
|
||||
if (nix == gdbstub_rx_outp)
|
||||
break;
|
||||
|
||||
gdbstub_rx_buffer[ix++] = __UART(LSR);
|
||||
gdbstub_rx_buffer[ix++] = __UART(RX);
|
||||
ix = nix;
|
||||
}
|
||||
|
||||
gdbstub_rx_inp = ix;
|
||||
|
||||
__clr_RC(15);
|
||||
__clr_IRL();
|
||||
|
||||
} /* end gdbstub_do_rx() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* wait for a character to come from the debugger
|
||||
*/
|
||||
int gdbstub_rx_char(unsigned char *_ch, int nonblock)
|
||||
{
|
||||
unsigned ix;
|
||||
u8 ch, st;
|
||||
|
||||
*_ch = 0xff;
|
||||
|
||||
if (gdbstub_rx_unget) {
|
||||
*_ch = gdbstub_rx_unget;
|
||||
gdbstub_rx_unget = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
try_again:
|
||||
gdbstub_do_rx();
|
||||
|
||||
/* pull chars out of the buffer */
|
||||
ix = gdbstub_rx_outp;
|
||||
if (ix == gdbstub_rx_inp) {
|
||||
if (nonblock)
|
||||
return -EAGAIN;
|
||||
//watchdog_alert_counter = 0;
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
st = gdbstub_rx_buffer[ix++];
|
||||
ch = gdbstub_rx_buffer[ix++];
|
||||
gdbstub_rx_outp = ix & 0x00000fff;
|
||||
|
||||
if (st & UART_LSR_BI) {
|
||||
gdbstub_proto("### GDB Rx Break Detected ###\n");
|
||||
return -EINTR;
|
||||
}
|
||||
else if (st & (UART_LSR_FE|UART_LSR_OE|UART_LSR_PE)) {
|
||||
gdbstub_io("### GDB Rx Error (st=%02x) ###\n",st);
|
||||
return -EIO;
|
||||
}
|
||||
else {
|
||||
gdbstub_io("### GDB Rx %02x (st=%02x) ###\n",ch,st);
|
||||
*_ch = ch & 0x7f;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} /* end gdbstub_rx_char() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* send a character to the debugger
|
||||
*/
|
||||
void gdbstub_tx_char(unsigned char ch)
|
||||
{
|
||||
FLOWCTL_SET(DTR);
|
||||
LSR_WAIT_FOR(THRE);
|
||||
// FLOWCTL_WAIT_FOR(CTS);
|
||||
|
||||
if (ch == 0x0a) {
|
||||
__UART(TX) = 0x0d;
|
||||
mb();
|
||||
LSR_WAIT_FOR(THRE);
|
||||
// FLOWCTL_WAIT_FOR(CTS);
|
||||
}
|
||||
__UART(TX) = ch;
|
||||
mb();
|
||||
|
||||
FLOWCTL_CLEAR(DTR);
|
||||
} /* end gdbstub_tx_char() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* send a character to the debugger
|
||||
*/
|
||||
void gdbstub_tx_flush(void)
|
||||
{
|
||||
LSR_WAIT_FOR(TEMT);
|
||||
LSR_WAIT_FOR(THRE);
|
||||
FLOWCTL_CLEAR(DTR);
|
||||
} /* end gdbstub_tx_flush() */
|
55
arch/frv/kernel/gdb-io.h
Normal file
55
arch/frv/kernel/gdb-io.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
/* gdb-io.h: FR403 GDB I/O port defs
|
||||
*
|
||||
* Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _GDB_IO_H
|
||||
#define _GDB_IO_H
|
||||
|
||||
#include <asm/serial-regs.h>
|
||||
|
||||
#undef UART_RX
|
||||
#undef UART_TX
|
||||
#undef UART_DLL
|
||||
#undef UART_DLM
|
||||
#undef UART_IER
|
||||
#undef UART_IIR
|
||||
#undef UART_FCR
|
||||
#undef UART_LCR
|
||||
#undef UART_MCR
|
||||
#undef UART_LSR
|
||||
#undef UART_MSR
|
||||
#undef UART_SCR
|
||||
|
||||
#define UART_RX 0*8 /* In: Receive buffer (DLAB=0) */
|
||||
#define UART_TX 0*8 /* Out: Transmit buffer (DLAB=0) */
|
||||
#define UART_DLL 0*8 /* Out: Divisor Latch Low (DLAB=1) */
|
||||
#define UART_DLM 1*8 /* Out: Divisor Latch High (DLAB=1) */
|
||||
#define UART_IER 1*8 /* Out: Interrupt Enable Register */
|
||||
#define UART_IIR 2*8 /* In: Interrupt ID Register */
|
||||
#define UART_FCR 2*8 /* Out: FIFO Control Register */
|
||||
#define UART_LCR 3*8 /* Out: Line Control Register */
|
||||
#define UART_MCR 4*8 /* Out: Modem Control Register */
|
||||
#define UART_LSR 5*8 /* In: Line Status Register */
|
||||
#define UART_MSR 6*8 /* In: Modem Status Register */
|
||||
#define UART_SCR 7*8 /* I/O: Scratch Register */
|
||||
|
||||
#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
|
||||
#define UART_LCR_SBC 0x40 /* Set break control */
|
||||
#define UART_LCR_SPAR 0x20 /* Stick parity (?) */
|
||||
#define UART_LCR_EPAR 0x10 /* Even parity select */
|
||||
#define UART_LCR_PARITY 0x08 /* Parity Enable */
|
||||
#define UART_LCR_STOP 0x04 /* Stop bits: 0=1 stop bit, 1= 2 stop bits */
|
||||
#define UART_LCR_WLEN5 0x00 /* Wordlength: 5 bits */
|
||||
#define UART_LCR_WLEN6 0x01 /* Wordlength: 6 bits */
|
||||
#define UART_LCR_WLEN7 0x02 /* Wordlength: 7 bits */
|
||||
#define UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */
|
||||
|
||||
|
||||
#endif /* _GDB_IO_H */
|
2149
arch/frv/kernel/gdb-stub.c
Normal file
2149
arch/frv/kernel/gdb-stub.c
Normal file
File diff suppressed because it is too large
Load diff
374
arch/frv/kernel/head-mmu-fr451.S
Normal file
374
arch/frv/kernel/head-mmu-fr451.S
Normal file
|
@ -0,0 +1,374 @@
|
|||
/* head-mmu-fr451.S: FR451 mmu-linux specific bits of initialisation
|
||||
*
|
||||
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/threads.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/mem-layout.h>
|
||||
#include <asm/spr-regs.h>
|
||||
#include <asm/mb86943a.h>
|
||||
#include "head.inc"
|
||||
|
||||
|
||||
#define __400_DBR0 0xfe000e00
|
||||
#define __400_DBR1 0xfe000e08
|
||||
#define __400_DBR2 0xfe000e10
|
||||
#define __400_DBR3 0xfe000e18
|
||||
#define __400_DAM0 0xfe000f00
|
||||
#define __400_DAM1 0xfe000f08
|
||||
#define __400_DAM2 0xfe000f10
|
||||
#define __400_DAM3 0xfe000f18
|
||||
#define __400_LGCR 0xfe000010
|
||||
#define __400_LCR 0xfe000100
|
||||
#define __400_LSBR 0xfe000c00
|
||||
|
||||
__INIT
|
||||
.balign 4
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# describe the position and layout of the SDRAM controller registers
|
||||
#
|
||||
# ENTRY: EXIT:
|
||||
# GR5 - cacheline size
|
||||
# GR11 - displacement of 2nd SDRAM addr reg from GR14
|
||||
# GR12 - displacement of 3rd SDRAM addr reg from GR14
|
||||
# GR13 - displacement of 4th SDRAM addr reg from GR14
|
||||
# GR14 - address of 1st SDRAM addr reg
|
||||
# GR15 - amount to shift address by to match SDRAM addr reg
|
||||
# GR26 &__head_reference [saved]
|
||||
# GR30 LED address [saved]
|
||||
# CC0 - T if DBR0 is present
|
||||
# CC1 - T if DBR1 is present
|
||||
# CC2 - T if DBR2 is present
|
||||
# CC3 - T if DBR3 is present
|
||||
#
|
||||
###############################################################################
|
||||
.globl __head_fr451_describe_sdram
|
||||
__head_fr451_describe_sdram:
|
||||
sethi.p %hi(__400_DBR0),gr14
|
||||
setlo %lo(__400_DBR0),gr14
|
||||
setlos.p #__400_DBR1-__400_DBR0,gr11
|
||||
setlos #__400_DBR2-__400_DBR0,gr12
|
||||
setlos.p #__400_DBR3-__400_DBR0,gr13
|
||||
setlos #32,gr5 ; cacheline size
|
||||
setlos.p #0,gr15 ; amount to shift addr reg by
|
||||
setlos #0x00ff,gr4
|
||||
movgs gr4,cccr ; extant DARS/DAMK regs
|
||||
bralr
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# rearrange the bus controller registers
|
||||
#
|
||||
# ENTRY: EXIT:
|
||||
# GR26 &__head_reference [saved]
|
||||
# GR30 LED address revised LED address
|
||||
#
|
||||
###############################################################################
|
||||
.globl __head_fr451_set_busctl
|
||||
__head_fr451_set_busctl:
|
||||
sethi.p %hi(__400_LGCR),gr4
|
||||
setlo %lo(__400_LGCR),gr4
|
||||
sethi.p %hi(__400_LSBR),gr10
|
||||
setlo %lo(__400_LSBR),gr10
|
||||
sethi.p %hi(__400_LCR),gr11
|
||||
setlo %lo(__400_LCR),gr11
|
||||
|
||||
# set the bus controller
|
||||
ldi @(gr4,#0),gr5
|
||||
ori gr5,#0xff,gr5 ; make sure all chip-selects are enabled
|
||||
sti gr5,@(gr4,#0)
|
||||
|
||||
sethi.p %hi(__region_CS1),gr4
|
||||
setlo %lo(__region_CS1),gr4
|
||||
sethi.p %hi(__region_CS1_M),gr5
|
||||
setlo %lo(__region_CS1_M),gr5
|
||||
sethi.p %hi(__region_CS1_C),gr6
|
||||
setlo %lo(__region_CS1_C),gr6
|
||||
sti gr4,@(gr10,#1*0x08)
|
||||
sti gr5,@(gr10,#1*0x08+0x100)
|
||||
sti gr6,@(gr11,#1*0x08)
|
||||
sethi.p %hi(__region_CS2),gr4
|
||||
setlo %lo(__region_CS2),gr4
|
||||
sethi.p %hi(__region_CS2_M),gr5
|
||||
setlo %lo(__region_CS2_M),gr5
|
||||
sethi.p %hi(__region_CS2_C),gr6
|
||||
setlo %lo(__region_CS2_C),gr6
|
||||
sti gr4,@(gr10,#2*0x08)
|
||||
sti gr5,@(gr10,#2*0x08+0x100)
|
||||
sti gr6,@(gr11,#2*0x08)
|
||||
sethi.p %hi(__region_CS3),gr4
|
||||
setlo %lo(__region_CS3),gr4
|
||||
sethi.p %hi(__region_CS3_M),gr5
|
||||
setlo %lo(__region_CS3_M),gr5
|
||||
sethi.p %hi(__region_CS3_C),gr6
|
||||
setlo %lo(__region_CS3_C),gr6
|
||||
sti gr4,@(gr10,#3*0x08)
|
||||
sti gr5,@(gr10,#3*0x08+0x100)
|
||||
sti gr6,@(gr11,#3*0x08)
|
||||
sethi.p %hi(__region_CS4),gr4
|
||||
setlo %lo(__region_CS4),gr4
|
||||
sethi.p %hi(__region_CS4_M),gr5
|
||||
setlo %lo(__region_CS4_M),gr5
|
||||
sethi.p %hi(__region_CS4_C),gr6
|
||||
setlo %lo(__region_CS4_C),gr6
|
||||
sti gr4,@(gr10,#4*0x08)
|
||||
sti gr5,@(gr10,#4*0x08+0x100)
|
||||
sti gr6,@(gr11,#4*0x08)
|
||||
sethi.p %hi(__region_CS5),gr4
|
||||
setlo %lo(__region_CS5),gr4
|
||||
sethi.p %hi(__region_CS5_M),gr5
|
||||
setlo %lo(__region_CS5_M),gr5
|
||||
sethi.p %hi(__region_CS5_C),gr6
|
||||
setlo %lo(__region_CS5_C),gr6
|
||||
sti gr4,@(gr10,#5*0x08)
|
||||
sti gr5,@(gr10,#5*0x08+0x100)
|
||||
sti gr6,@(gr11,#5*0x08)
|
||||
sethi.p %hi(__region_CS6),gr4
|
||||
setlo %lo(__region_CS6),gr4
|
||||
sethi.p %hi(__region_CS6_M),gr5
|
||||
setlo %lo(__region_CS6_M),gr5
|
||||
sethi.p %hi(__region_CS6_C),gr6
|
||||
setlo %lo(__region_CS6_C),gr6
|
||||
sti gr4,@(gr10,#6*0x08)
|
||||
sti gr5,@(gr10,#6*0x08+0x100)
|
||||
sti gr6,@(gr11,#6*0x08)
|
||||
sethi.p %hi(__region_CS7),gr4
|
||||
setlo %lo(__region_CS7),gr4
|
||||
sethi.p %hi(__region_CS7_M),gr5
|
||||
setlo %lo(__region_CS7_M),gr5
|
||||
sethi.p %hi(__region_CS7_C),gr6
|
||||
setlo %lo(__region_CS7_C),gr6
|
||||
sti gr4,@(gr10,#7*0x08)
|
||||
sti gr5,@(gr10,#7*0x08+0x100)
|
||||
sti gr6,@(gr11,#7*0x08)
|
||||
membar
|
||||
bar
|
||||
|
||||
# adjust LED bank address
|
||||
#ifdef CONFIG_MB93091_VDK
|
||||
sethi.p %hi(__region_CS2 + 0x01200004),gr30
|
||||
setlo %lo(__region_CS2 + 0x01200004),gr30
|
||||
#endif
|
||||
bralr
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# determine the total SDRAM size
|
||||
#
|
||||
# ENTRY: EXIT:
|
||||
# GR25 - SDRAM size
|
||||
# GR26 &__head_reference [saved]
|
||||
# GR30 LED address [saved]
|
||||
#
|
||||
###############################################################################
|
||||
.globl __head_fr451_survey_sdram
|
||||
__head_fr451_survey_sdram:
|
||||
sethi.p %hi(__400_DAM0),gr11
|
||||
setlo %lo(__400_DAM0),gr11
|
||||
sethi.p %hi(__400_DBR0),gr12
|
||||
setlo %lo(__400_DBR0),gr12
|
||||
|
||||
sethi.p %hi(0xfe000000),gr17 ; unused SDRAM DBR value
|
||||
setlo %lo(0xfe000000),gr17
|
||||
setlos #0,gr25
|
||||
|
||||
ldi @(gr12,#0x00),gr4 ; DAR0
|
||||
subcc gr4,gr17,gr0,icc0
|
||||
beq icc0,#0,__head_no_DCS0
|
||||
ldi @(gr11,#0x00),gr6 ; DAM0: bits 31:20 match addr 31:20
|
||||
add gr25,gr6,gr25
|
||||
addi gr25,#1,gr25
|
||||
__head_no_DCS0:
|
||||
|
||||
ldi @(gr12,#0x08),gr4 ; DAR1
|
||||
subcc gr4,gr17,gr0,icc0
|
||||
beq icc0,#0,__head_no_DCS1
|
||||
ldi @(gr11,#0x08),gr6 ; DAM1: bits 31:20 match addr 31:20
|
||||
add gr25,gr6,gr25
|
||||
addi gr25,#1,gr25
|
||||
__head_no_DCS1:
|
||||
|
||||
ldi @(gr12,#0x10),gr4 ; DAR2
|
||||
subcc gr4,gr17,gr0,icc0
|
||||
beq icc0,#0,__head_no_DCS2
|
||||
ldi @(gr11,#0x10),gr6 ; DAM2: bits 31:20 match addr 31:20
|
||||
add gr25,gr6,gr25
|
||||
addi gr25,#1,gr25
|
||||
__head_no_DCS2:
|
||||
|
||||
ldi @(gr12,#0x18),gr4 ; DAR3
|
||||
subcc gr4,gr17,gr0,icc0
|
||||
beq icc0,#0,__head_no_DCS3
|
||||
ldi @(gr11,#0x18),gr6 ; DAM3: bits 31:20 match addr 31:20
|
||||
add gr25,gr6,gr25
|
||||
addi gr25,#1,gr25
|
||||
__head_no_DCS3:
|
||||
bralr
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# set the protection map with the I/DAMPR registers
|
||||
#
|
||||
# ENTRY: EXIT:
|
||||
# GR25 SDRAM size [saved]
|
||||
# GR26 &__head_reference [saved]
|
||||
# GR30 LED address [saved]
|
||||
#
|
||||
#
|
||||
# Using this map:
|
||||
# REGISTERS ADDRESS RANGE VIEW
|
||||
# =============== ====================== ===============================
|
||||
# IAMPR0/DAMPR0 0xC0000000-0xCFFFFFFF Cached kernel RAM Window
|
||||
# DAMPR11 0xE0000000-0xFFFFFFFF Uncached I/O
|
||||
#
|
||||
###############################################################################
|
||||
.globl __head_fr451_set_protection
|
||||
__head_fr451_set_protection:
|
||||
movsg lr,gr27
|
||||
|
||||
# set the I/O region protection registers for FR451 in MMU mode
|
||||
#define PGPROT_IO xAMPRx_L|xAMPRx_M|xAMPRx_S_KERNEL|xAMPRx_C|xAMPRx_V
|
||||
|
||||
sethi.p %hi(__region_IO),gr5
|
||||
setlo %lo(__region_IO),gr5
|
||||
setlos #PGPROT_IO|xAMPRx_SS_512Mb,gr4
|
||||
or gr4,gr5,gr4
|
||||
movgs gr5,damlr11 ; General I/O tile
|
||||
movgs gr4,dampr11
|
||||
|
||||
# need to open a window onto at least part of the RAM for the kernel's use
|
||||
sethi.p %hi(__sdram_base),gr8
|
||||
setlo %lo(__sdram_base),gr8 ; physical address
|
||||
sethi.p %hi(__page_offset),gr9
|
||||
setlo %lo(__page_offset),gr9 ; virtual address
|
||||
|
||||
setlos #xAMPRx_L|xAMPRx_M|xAMPRx_SS_256Mb|xAMPRx_S_KERNEL|xAMPRx_V,gr11
|
||||
or gr8,gr11,gr8
|
||||
|
||||
movgs gr9,iamlr0 ; mapped from real address 0
|
||||
movgs gr8,iampr0 ; cached kernel memory at 0xC0000000
|
||||
movgs gr9,damlr0
|
||||
movgs gr8,dampr0
|
||||
|
||||
# set a temporary mapping for the kernel running at address 0 until we've turned on the MMU
|
||||
sethi.p %hi(__sdram_base),gr9
|
||||
setlo %lo(__sdram_base),gr9 ; virtual address
|
||||
|
||||
and.p gr4,gr11,gr4
|
||||
and gr5,gr11,gr5
|
||||
or.p gr4,gr11,gr4
|
||||
or gr5,gr11,gr5
|
||||
|
||||
movgs gr9,iamlr1 ; mapped from real address 0
|
||||
movgs gr8,iampr1 ; cached kernel memory at 0x00000000
|
||||
movgs gr9,damlr1
|
||||
movgs gr8,dampr1
|
||||
|
||||
# we use DAMR2-10 for kmap_atomic(), cache flush and TLB management
|
||||
# since the DAMLR regs are not going to change, we can set them now
|
||||
# also set up IAMLR2 to the same as DAMLR5
|
||||
sethi.p %hi(KMAP_ATOMIC_PRIMARY_FRAME),gr4
|
||||
setlo %lo(KMAP_ATOMIC_PRIMARY_FRAME),gr4
|
||||
sethi.p %hi(PAGE_SIZE),gr5
|
||||
setlo %lo(PAGE_SIZE),gr5
|
||||
|
||||
movgs gr4,damlr2
|
||||
movgs gr4,iamlr2
|
||||
add gr4,gr5,gr4
|
||||
movgs gr4,damlr3
|
||||
add gr4,gr5,gr4
|
||||
movgs gr4,damlr4
|
||||
add gr4,gr5,gr4
|
||||
movgs gr4,damlr5
|
||||
add gr4,gr5,gr4
|
||||
movgs gr4,damlr6
|
||||
add gr4,gr5,gr4
|
||||
movgs gr4,damlr7
|
||||
add gr4,gr5,gr4
|
||||
movgs gr4,damlr8
|
||||
add gr4,gr5,gr4
|
||||
movgs gr4,damlr9
|
||||
add gr4,gr5,gr4
|
||||
movgs gr4,damlr10
|
||||
|
||||
movgs gr0,dampr2
|
||||
movgs gr0,dampr4
|
||||
movgs gr0,dampr5
|
||||
movgs gr0,dampr6
|
||||
movgs gr0,dampr7
|
||||
movgs gr0,dampr8
|
||||
movgs gr0,dampr9
|
||||
movgs gr0,dampr10
|
||||
|
||||
movgs gr0,iamlr3
|
||||
movgs gr0,iamlr4
|
||||
movgs gr0,iamlr5
|
||||
movgs gr0,iamlr6
|
||||
movgs gr0,iamlr7
|
||||
|
||||
movgs gr0,iampr2
|
||||
movgs gr0,iampr3
|
||||
movgs gr0,iampr4
|
||||
movgs gr0,iampr5
|
||||
movgs gr0,iampr6
|
||||
movgs gr0,iampr7
|
||||
|
||||
# start in TLB context 0 with the swapper's page tables
|
||||
movgs gr0,cxnr
|
||||
|
||||
sethi.p %hi(swapper_pg_dir),gr4
|
||||
setlo %lo(swapper_pg_dir),gr4
|
||||
sethi.p %hi(__page_offset),gr5
|
||||
setlo %lo(__page_offset),gr5
|
||||
sub gr4,gr5,gr4
|
||||
movgs gr4,ttbr
|
||||
setlos #xAMPRx_L|xAMPRx_M|xAMPRx_SS_16Kb|xAMPRx_S|xAMPRx_C|xAMPRx_V,gr5
|
||||
or gr4,gr5,gr4
|
||||
movgs gr4,dampr3
|
||||
|
||||
# the FR451 also has an extra trap base register
|
||||
movsg tbr,gr4
|
||||
movgs gr4,btbr
|
||||
|
||||
LEDS 0x3300
|
||||
jmpl @(gr27,gr0)
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# finish setting up the protection registers
|
||||
#
|
||||
###############################################################################
|
||||
.globl __head_fr451_finalise_protection
|
||||
__head_fr451_finalise_protection:
|
||||
# turn on the timers as appropriate
|
||||
movgs gr0,timerh
|
||||
movgs gr0,timerl
|
||||
movgs gr0,timerd
|
||||
movsg hsr0,gr4
|
||||
sethi.p %hi(HSR0_ETMI),gr5
|
||||
setlo %lo(HSR0_ETMI),gr5
|
||||
or gr4,gr5,gr4
|
||||
movgs gr4,hsr0
|
||||
|
||||
# clear the TLB entry cache
|
||||
movgs gr0,iamlr1
|
||||
movgs gr0,iampr1
|
||||
movgs gr0,damlr1
|
||||
movgs gr0,dampr1
|
||||
|
||||
# clear the PGE cache
|
||||
sethi.p %hi(__flush_tlb_all),gr4
|
||||
setlo %lo(__flush_tlb_all),gr4
|
||||
jmpl @(gr4,gr0)
|
311
arch/frv/kernel/head-uc-fr401.S
Normal file
311
arch/frv/kernel/head-uc-fr401.S
Normal file
|
@ -0,0 +1,311 @@
|
|||
/* head-uc-fr401.S: FR401/3/5 uc-linux specific bits of initialisation
|
||||
*
|
||||
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/threads.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/spr-regs.h>
|
||||
#include <asm/mb86943a.h>
|
||||
#include "head.inc"
|
||||
|
||||
|
||||
#define __400_DBR0 0xfe000e00
|
||||
#define __400_DBR1 0xfe000e08
|
||||
#define __400_DBR2 0xfe000e10 /* not on FR401 */
|
||||
#define __400_DBR3 0xfe000e18 /* not on FR401 */
|
||||
#define __400_DAM0 0xfe000f00
|
||||
#define __400_DAM1 0xfe000f08
|
||||
#define __400_DAM2 0xfe000f10 /* not on FR401 */
|
||||
#define __400_DAM3 0xfe000f18 /* not on FR401 */
|
||||
#define __400_LGCR 0xfe000010
|
||||
#define __400_LCR 0xfe000100
|
||||
#define __400_LSBR 0xfe000c00
|
||||
|
||||
__INIT
|
||||
.balign 4
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# describe the position and layout of the SDRAM controller registers
|
||||
#
|
||||
# ENTRY: EXIT:
|
||||
# GR5 - cacheline size
|
||||
# GR11 - displacement of 2nd SDRAM addr reg from GR14
|
||||
# GR12 - displacement of 3rd SDRAM addr reg from GR14
|
||||
# GR13 - displacement of 4th SDRAM addr reg from GR14
|
||||
# GR14 - address of 1st SDRAM addr reg
|
||||
# GR15 - amount to shift address by to match SDRAM addr reg
|
||||
# GR26 &__head_reference [saved]
|
||||
# GR30 LED address [saved]
|
||||
# CC0 - T if DBR0 is present
|
||||
# CC1 - T if DBR1 is present
|
||||
# CC2 - T if DBR2 is present (not FR401/FR401A)
|
||||
# CC3 - T if DBR3 is present (not FR401/FR401A)
|
||||
#
|
||||
###############################################################################
|
||||
.globl __head_fr401_describe_sdram
|
||||
__head_fr401_describe_sdram:
|
||||
sethi.p %hi(__400_DBR0),gr14
|
||||
setlo %lo(__400_DBR0),gr14
|
||||
setlos.p #__400_DBR1-__400_DBR0,gr11
|
||||
setlos #__400_DBR2-__400_DBR0,gr12
|
||||
setlos.p #__400_DBR3-__400_DBR0,gr13
|
||||
setlos #32,gr5 ; cacheline size
|
||||
setlos.p #0,gr15 ; amount to shift addr reg by
|
||||
|
||||
# specify which DBR regs are present
|
||||
setlos #0x00ff,gr4
|
||||
movgs gr4,cccr
|
||||
movsg psr,gr3 ; check for FR401/FR401A
|
||||
srli gr3,#25,gr3
|
||||
subicc gr3,#0x20>>1,gr0,icc0
|
||||
bnelr icc0,#1
|
||||
setlos #0x000f,gr4
|
||||
movgs gr4,cccr
|
||||
bralr
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# rearrange the bus controller registers
|
||||
#
|
||||
# ENTRY: EXIT:
|
||||
# GR26 &__head_reference [saved]
|
||||
# GR30 LED address revised LED address
|
||||
#
|
||||
###############################################################################
|
||||
.globl __head_fr401_set_busctl
|
||||
__head_fr401_set_busctl:
|
||||
sethi.p %hi(__400_LGCR),gr4
|
||||
setlo %lo(__400_LGCR),gr4
|
||||
sethi.p %hi(__400_LSBR),gr10
|
||||
setlo %lo(__400_LSBR),gr10
|
||||
sethi.p %hi(__400_LCR),gr11
|
||||
setlo %lo(__400_LCR),gr11
|
||||
|
||||
# set the bus controller
|
||||
ldi @(gr4,#0),gr5
|
||||
ori gr5,#0xff,gr5 ; make sure all chip-selects are enabled
|
||||
sti gr5,@(gr4,#0)
|
||||
|
||||
sethi.p %hi(__region_CS1),gr4
|
||||
setlo %lo(__region_CS1),gr4
|
||||
sethi.p %hi(__region_CS1_M),gr5
|
||||
setlo %lo(__region_CS1_M),gr5
|
||||
sethi.p %hi(__region_CS1_C),gr6
|
||||
setlo %lo(__region_CS1_C),gr6
|
||||
sti gr4,@(gr10,#1*0x08)
|
||||
sti gr5,@(gr10,#1*0x08+0x100)
|
||||
sti gr6,@(gr11,#1*0x08)
|
||||
sethi.p %hi(__region_CS2),gr4
|
||||
setlo %lo(__region_CS2),gr4
|
||||
sethi.p %hi(__region_CS2_M),gr5
|
||||
setlo %lo(__region_CS2_M),gr5
|
||||
sethi.p %hi(__region_CS2_C),gr6
|
||||
setlo %lo(__region_CS2_C),gr6
|
||||
sti gr4,@(gr10,#2*0x08)
|
||||
sti gr5,@(gr10,#2*0x08+0x100)
|
||||
sti gr6,@(gr11,#2*0x08)
|
||||
sethi.p %hi(__region_CS3),gr4
|
||||
setlo %lo(__region_CS3),gr4
|
||||
sethi.p %hi(__region_CS3_M),gr5
|
||||
setlo %lo(__region_CS3_M),gr5
|
||||
sethi.p %hi(__region_CS3_C),gr6
|
||||
setlo %lo(__region_CS3_C),gr6
|
||||
sti gr4,@(gr10,#3*0x08)
|
||||
sti gr5,@(gr10,#3*0x08+0x100)
|
||||
sti gr6,@(gr11,#3*0x08)
|
||||
sethi.p %hi(__region_CS4),gr4
|
||||
setlo %lo(__region_CS4),gr4
|
||||
sethi.p %hi(__region_CS4_M),gr5
|
||||
setlo %lo(__region_CS4_M),gr5
|
||||
sethi.p %hi(__region_CS4_C),gr6
|
||||
setlo %lo(__region_CS4_C),gr6
|
||||
sti gr4,@(gr10,#4*0x08)
|
||||
sti gr5,@(gr10,#4*0x08+0x100)
|
||||
sti gr6,@(gr11,#4*0x08)
|
||||
sethi.p %hi(__region_CS5),gr4
|
||||
setlo %lo(__region_CS5),gr4
|
||||
sethi.p %hi(__region_CS5_M),gr5
|
||||
setlo %lo(__region_CS5_M),gr5
|
||||
sethi.p %hi(__region_CS5_C),gr6
|
||||
setlo %lo(__region_CS5_C),gr6
|
||||
sti gr4,@(gr10,#5*0x08)
|
||||
sti gr5,@(gr10,#5*0x08+0x100)
|
||||
sti gr6,@(gr11,#5*0x08)
|
||||
sethi.p %hi(__region_CS6),gr4
|
||||
setlo %lo(__region_CS6),gr4
|
||||
sethi.p %hi(__region_CS6_M),gr5
|
||||
setlo %lo(__region_CS6_M),gr5
|
||||
sethi.p %hi(__region_CS6_C),gr6
|
||||
setlo %lo(__region_CS6_C),gr6
|
||||
sti gr4,@(gr10,#6*0x08)
|
||||
sti gr5,@(gr10,#6*0x08+0x100)
|
||||
sti gr6,@(gr11,#6*0x08)
|
||||
sethi.p %hi(__region_CS7),gr4
|
||||
setlo %lo(__region_CS7),gr4
|
||||
sethi.p %hi(__region_CS7_M),gr5
|
||||
setlo %lo(__region_CS7_M),gr5
|
||||
sethi.p %hi(__region_CS7_C),gr6
|
||||
setlo %lo(__region_CS7_C),gr6
|
||||
sti gr4,@(gr10,#7*0x08)
|
||||
sti gr5,@(gr10,#7*0x08+0x100)
|
||||
sti gr6,@(gr11,#7*0x08)
|
||||
membar
|
||||
bar
|
||||
|
||||
# adjust LED bank address
|
||||
sethi.p %hi(LED_ADDR - 0x20000000 +__region_CS2),gr30
|
||||
setlo %lo(LED_ADDR - 0x20000000 +__region_CS2),gr30
|
||||
bralr
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# determine the total SDRAM size
|
||||
#
|
||||
# ENTRY: EXIT:
|
||||
# GR25 - SDRAM size
|
||||
# GR26 &__head_reference [saved]
|
||||
# GR30 LED address [saved]
|
||||
#
|
||||
###############################################################################
|
||||
.globl __head_fr401_survey_sdram
|
||||
__head_fr401_survey_sdram:
|
||||
sethi.p %hi(__400_DAM0),gr11
|
||||
setlo %lo(__400_DAM0),gr11
|
||||
sethi.p %hi(__400_DBR0),gr12
|
||||
setlo %lo(__400_DBR0),gr12
|
||||
|
||||
sethi.p %hi(0xfe000000),gr17 ; unused SDRAM DBR value
|
||||
setlo %lo(0xfe000000),gr17
|
||||
setlos #0,gr25
|
||||
|
||||
ldi @(gr12,#0x00),gr4 ; DAR0
|
||||
subcc gr4,gr17,gr0,icc0
|
||||
beq icc0,#0,__head_no_DCS0
|
||||
ldi @(gr11,#0x00),gr6 ; DAM0: bits 31:20 match addr 31:20
|
||||
add gr25,gr6,gr25
|
||||
addi gr25,#1,gr25
|
||||
__head_no_DCS0:
|
||||
|
||||
ldi @(gr12,#0x08),gr4 ; DAR1
|
||||
subcc gr4,gr17,gr0,icc0
|
||||
beq icc0,#0,__head_no_DCS1
|
||||
ldi @(gr11,#0x08),gr6 ; DAM1: bits 31:20 match addr 31:20
|
||||
add gr25,gr6,gr25
|
||||
addi gr25,#1,gr25
|
||||
__head_no_DCS1:
|
||||
|
||||
# FR401/FR401A does not have DCS2/3
|
||||
movsg psr,gr3
|
||||
srli gr3,#25,gr3
|
||||
subicc gr3,#0x20>>1,gr0,icc0
|
||||
beq icc0,#0,__head_no_DCS3
|
||||
|
||||
ldi @(gr12,#0x10),gr4 ; DAR2
|
||||
subcc gr4,gr17,gr0,icc0
|
||||
beq icc0,#0,__head_no_DCS2
|
||||
ldi @(gr11,#0x10),gr6 ; DAM2: bits 31:20 match addr 31:20
|
||||
add gr25,gr6,gr25
|
||||
addi gr25,#1,gr25
|
||||
__head_no_DCS2:
|
||||
|
||||
ldi @(gr12,#0x18),gr4 ; DAR3
|
||||
subcc gr4,gr17,gr0,icc0
|
||||
beq icc0,#0,__head_no_DCS3
|
||||
ldi @(gr11,#0x18),gr6 ; DAM3: bits 31:20 match addr 31:20
|
||||
add gr25,gr6,gr25
|
||||
addi gr25,#1,gr25
|
||||
__head_no_DCS3:
|
||||
bralr
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# set the protection map with the I/DAMPR registers
|
||||
#
|
||||
# ENTRY: EXIT:
|
||||
# GR25 SDRAM size [saved]
|
||||
# GR26 &__head_reference [saved]
|
||||
# GR30 LED address [saved]
|
||||
#
|
||||
###############################################################################
|
||||
.globl __head_fr401_set_protection
|
||||
__head_fr401_set_protection:
|
||||
movsg lr,gr27
|
||||
|
||||
# set the I/O region protection registers for FR401/3/5
|
||||
sethi.p %hi(__region_IO),gr5
|
||||
setlo %lo(__region_IO),gr5
|
||||
ori gr5,#xAMPRx_SS_512Mb|xAMPRx_S_KERNEL|xAMPRx_C|xAMPRx_V,gr5
|
||||
movgs gr0,iampr7
|
||||
movgs gr5,dampr7 ; General I/O tile
|
||||
|
||||
# need to tile the remaining IAMPR/DAMPR registers to cover as much of the RAM as possible
|
||||
# - start with the highest numbered registers
|
||||
sethi.p %hi(__kernel_image_end),gr8
|
||||
setlo %lo(__kernel_image_end),gr8
|
||||
sethi.p %hi(32768),gr4 ; allow for a maximal allocator bitmap
|
||||
setlo %lo(32768),gr4
|
||||
add gr8,gr4,gr8
|
||||
sethi.p %hi(1024*2048-1),gr4 ; round up to nearest 2MiB
|
||||
setlo %lo(1024*2048-1),gr4
|
||||
add.p gr8,gr4,gr8
|
||||
not gr4,gr4
|
||||
and gr8,gr4,gr8
|
||||
|
||||
sethi.p %hi(__page_offset),gr9
|
||||
setlo %lo(__page_offset),gr9
|
||||
add gr9,gr25,gr9
|
||||
|
||||
# GR8 = base of uncovered RAM
|
||||
# GR9 = top of uncovered RAM
|
||||
|
||||
#ifdef CONFIG_MB93093_PDK
|
||||
sethi.p %hi(__region_CS2),gr4
|
||||
setlo %lo(__region_CS2),gr4
|
||||
ori gr4,#xAMPRx_SS_1Mb|xAMPRx_S_KERNEL|xAMPRx_C|xAMPRx_V,gr4
|
||||
movgs gr4,dampr6
|
||||
movgs gr0,iampr6
|
||||
#else
|
||||
call __head_split_region
|
||||
movgs gr4,iampr6
|
||||
movgs gr5,dampr6
|
||||
#endif
|
||||
call __head_split_region
|
||||
movgs gr4,iampr5
|
||||
movgs gr5,dampr5
|
||||
call __head_split_region
|
||||
movgs gr4,iampr4
|
||||
movgs gr5,dampr4
|
||||
call __head_split_region
|
||||
movgs gr4,iampr3
|
||||
movgs gr5,dampr3
|
||||
call __head_split_region
|
||||
movgs gr4,iampr2
|
||||
movgs gr5,dampr2
|
||||
call __head_split_region
|
||||
movgs gr4,iampr1
|
||||
movgs gr5,dampr1
|
||||
|
||||
# cover kernel core image with kernel-only segment
|
||||
sethi.p %hi(__page_offset),gr8
|
||||
setlo %lo(__page_offset),gr8
|
||||
call __head_split_region
|
||||
|
||||
#ifdef CONFIG_PROTECT_KERNEL
|
||||
ori.p gr4,#xAMPRx_S_KERNEL,gr4
|
||||
ori gr5,#xAMPRx_S_KERNEL,gr5
|
||||
#endif
|
||||
|
||||
movgs gr4,iampr0
|
||||
movgs gr5,dampr0
|
||||
jmpl @(gr27,gr0)
|
174
arch/frv/kernel/head-uc-fr451.S
Normal file
174
arch/frv/kernel/head-uc-fr451.S
Normal file
|
@ -0,0 +1,174 @@
|
|||
/* head-uc-fr451.S: FR451 uc-linux specific bits of initialisation
|
||||
*
|
||||
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/threads.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/spr-regs.h>
|
||||
#include <asm/mb86943a.h>
|
||||
#include "head.inc"
|
||||
|
||||
|
||||
#define __400_DBR0 0xfe000e00
|
||||
#define __400_DBR1 0xfe000e08
|
||||
#define __400_DBR2 0xfe000e10
|
||||
#define __400_DBR3 0xfe000e18
|
||||
#define __400_DAM0 0xfe000f00
|
||||
#define __400_DAM1 0xfe000f08
|
||||
#define __400_DAM2 0xfe000f10
|
||||
#define __400_DAM3 0xfe000f18
|
||||
#define __400_LGCR 0xfe000010
|
||||
#define __400_LCR 0xfe000100
|
||||
#define __400_LSBR 0xfe000c00
|
||||
|
||||
__INIT
|
||||
.balign 4
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# set the protection map with the I/DAMPR registers
|
||||
#
|
||||
# ENTRY: EXIT:
|
||||
# GR25 SDRAM size [saved]
|
||||
# GR26 &__head_reference [saved]
|
||||
# GR30 LED address [saved]
|
||||
#
|
||||
###############################################################################
|
||||
.globl __head_fr451_set_protection
|
||||
__head_fr451_set_protection:
|
||||
movsg lr,gr27
|
||||
|
||||
movgs gr0,dampr10
|
||||
movgs gr0,damlr10
|
||||
movgs gr0,dampr9
|
||||
movgs gr0,damlr9
|
||||
movgs gr0,dampr8
|
||||
movgs gr0,damlr8
|
||||
|
||||
# set the I/O region protection registers for FR401/3/5
|
||||
sethi.p %hi(__region_IO),gr5
|
||||
setlo %lo(__region_IO),gr5
|
||||
sethi.p %hi(0x1fffffff),gr7
|
||||
setlo %lo(0x1fffffff),gr7
|
||||
ori gr5,#xAMPRx_SS_512Mb|xAMPRx_S_KERNEL|xAMPRx_C|xAMPRx_V,gr5
|
||||
movgs gr5,dampr11 ; General I/O tile
|
||||
movgs gr7,damlr11
|
||||
|
||||
# need to tile the remaining IAMPR/DAMPR registers to cover as much of the RAM as possible
|
||||
# - start with the highest numbered registers
|
||||
sethi.p %hi(__kernel_image_end),gr8
|
||||
setlo %lo(__kernel_image_end),gr8
|
||||
sethi.p %hi(32768),gr4 ; allow for a maximal allocator bitmap
|
||||
setlo %lo(32768),gr4
|
||||
add gr8,gr4,gr8
|
||||
sethi.p %hi(1024*2048-1),gr4 ; round up to nearest 2MiB
|
||||
setlo %lo(1024*2048-1),gr4
|
||||
add.p gr8,gr4,gr8
|
||||
not gr4,gr4
|
||||
and gr8,gr4,gr8
|
||||
|
||||
sethi.p %hi(__page_offset),gr9
|
||||
setlo %lo(__page_offset),gr9
|
||||
add gr9,gr25,gr9
|
||||
|
||||
sethi.p %hi(0xffffc000),gr11
|
||||
setlo %lo(0xffffc000),gr11
|
||||
|
||||
# GR8 = base of uncovered RAM
|
||||
# GR9 = top of uncovered RAM
|
||||
# GR11 = xAMLR mask
|
||||
LEDS 0x3317
|
||||
call __head_split_region
|
||||
movgs gr4,iampr7
|
||||
movgs gr6,iamlr7
|
||||
movgs gr5,dampr7
|
||||
movgs gr7,damlr7
|
||||
|
||||
LEDS 0x3316
|
||||
call __head_split_region
|
||||
movgs gr4,iampr6
|
||||
movgs gr6,iamlr6
|
||||
movgs gr5,dampr6
|
||||
movgs gr7,damlr6
|
||||
|
||||
LEDS 0x3315
|
||||
call __head_split_region
|
||||
movgs gr4,iampr5
|
||||
movgs gr6,iamlr5
|
||||
movgs gr5,dampr5
|
||||
movgs gr7,damlr5
|
||||
|
||||
LEDS 0x3314
|
||||
call __head_split_region
|
||||
movgs gr4,iampr4
|
||||
movgs gr6,iamlr4
|
||||
movgs gr5,dampr4
|
||||
movgs gr7,damlr4
|
||||
|
||||
LEDS 0x3313
|
||||
call __head_split_region
|
||||
movgs gr4,iampr3
|
||||
movgs gr6,iamlr3
|
||||
movgs gr5,dampr3
|
||||
movgs gr7,damlr3
|
||||
|
||||
LEDS 0x3312
|
||||
call __head_split_region
|
||||
movgs gr4,iampr2
|
||||
movgs gr6,iamlr2
|
||||
movgs gr5,dampr2
|
||||
movgs gr7,damlr2
|
||||
|
||||
LEDS 0x3311
|
||||
call __head_split_region
|
||||
movgs gr4,iampr1
|
||||
movgs gr6,iamlr1
|
||||
movgs gr5,dampr1
|
||||
movgs gr7,damlr1
|
||||
|
||||
# cover kernel core image with kernel-only segment
|
||||
LEDS 0x3310
|
||||
sethi.p %hi(__page_offset),gr8
|
||||
setlo %lo(__page_offset),gr8
|
||||
call __head_split_region
|
||||
|
||||
#ifdef CONFIG_PROTECT_KERNEL
|
||||
ori.p gr4,#xAMPRx_S_KERNEL,gr4
|
||||
ori gr5,#xAMPRx_S_KERNEL,gr5
|
||||
#endif
|
||||
|
||||
movgs gr4,iampr0
|
||||
movgs gr6,iamlr0
|
||||
movgs gr5,dampr0
|
||||
movgs gr7,damlr0
|
||||
|
||||
# start in TLB context 0 with no page tables
|
||||
movgs gr0,cxnr
|
||||
movgs gr0,ttbr
|
||||
|
||||
# the FR451 also has an extra trap base register
|
||||
movsg tbr,gr4
|
||||
movgs gr4,btbr
|
||||
|
||||
# turn on the timers as appropriate
|
||||
movgs gr0,timerh
|
||||
movgs gr0,timerl
|
||||
movgs gr0,timerd
|
||||
movsg hsr0,gr4
|
||||
sethi.p %hi(HSR0_ETMI),gr5
|
||||
setlo %lo(HSR0_ETMI),gr5
|
||||
or gr4,gr5,gr4
|
||||
movgs gr4,hsr0
|
||||
|
||||
LEDS 0x3300
|
||||
jmpl @(gr27,gr0)
|
347
arch/frv/kernel/head-uc-fr555.S
Normal file
347
arch/frv/kernel/head-uc-fr555.S
Normal file
|
@ -0,0 +1,347 @@
|
|||
/* head-uc-fr555.S: FR555 uc-linux specific bits of initialisation
|
||||
*
|
||||
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/threads.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/spr-regs.h>
|
||||
#include <asm/mb86943a.h>
|
||||
#include "head.inc"
|
||||
|
||||
|
||||
#define __551_DARS0 0xfeff0100
|
||||
#define __551_DARS1 0xfeff0104
|
||||
#define __551_DARS2 0xfeff0108
|
||||
#define __551_DARS3 0xfeff010c
|
||||
#define __551_DAMK0 0xfeff0110
|
||||
#define __551_DAMK1 0xfeff0114
|
||||
#define __551_DAMK2 0xfeff0118
|
||||
#define __551_DAMK3 0xfeff011c
|
||||
#define __551_LCR 0xfeff1100
|
||||
#define __551_LSBR 0xfeff1c00
|
||||
|
||||
__INIT
|
||||
.balign 4
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# describe the position and layout of the SDRAM controller registers
|
||||
#
|
||||
# ENTRY: EXIT:
|
||||
# GR5 - cacheline size
|
||||
# GR11 - displacement of 2nd SDRAM addr reg from GR14
|
||||
# GR12 - displacement of 3rd SDRAM addr reg from GR14
|
||||
# GR13 - displacement of 4th SDRAM addr reg from GR14
|
||||
# GR14 - address of 1st SDRAM addr reg
|
||||
# GR15 - amount to shift address by to match SDRAM addr reg
|
||||
# GR26 &__head_reference [saved]
|
||||
# GR30 LED address [saved]
|
||||
# CC0 - T if DARS0 is present
|
||||
# CC1 - T if DARS1 is present
|
||||
# CC2 - T if DARS2 is present
|
||||
# CC3 - T if DARS3 is present
|
||||
#
|
||||
###############################################################################
|
||||
.globl __head_fr555_describe_sdram
|
||||
__head_fr555_describe_sdram:
|
||||
sethi.p %hi(__551_DARS0),gr14
|
||||
setlo %lo(__551_DARS0),gr14
|
||||
setlos.p #__551_DARS1-__551_DARS0,gr11
|
||||
setlos #__551_DARS2-__551_DARS0,gr12
|
||||
setlos.p #__551_DARS3-__551_DARS0,gr13
|
||||
setlos #64,gr5 ; cacheline size
|
||||
setlos #20,gr15 ; amount to shift addr by
|
||||
setlos #0x00ff,gr4
|
||||
movgs gr4,cccr ; extant DARS/DAMK regs
|
||||
bralr
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# rearrange the bus controller registers
|
||||
#
|
||||
# ENTRY: EXIT:
|
||||
# GR26 &__head_reference [saved]
|
||||
# GR30 LED address revised LED address
|
||||
#
|
||||
###############################################################################
|
||||
.globl __head_fr555_set_busctl
|
||||
__head_fr555_set_busctl:
|
||||
LEDS 0x100f
|
||||
sethi.p %hi(__551_LSBR),gr10
|
||||
setlo %lo(__551_LSBR),gr10
|
||||
sethi.p %hi(__551_LCR),gr11
|
||||
setlo %lo(__551_LCR),gr11
|
||||
|
||||
# set the bus controller
|
||||
sethi.p %hi(__region_CS1),gr4
|
||||
setlo %lo(__region_CS1),gr4
|
||||
sethi.p %hi(__region_CS1_M),gr5
|
||||
setlo %lo(__region_CS1_M),gr5
|
||||
sethi.p %hi(__region_CS1_C),gr6
|
||||
setlo %lo(__region_CS1_C),gr6
|
||||
sti gr4,@(gr10,#1*0x08)
|
||||
sti gr5,@(gr10,#1*0x08+0x100)
|
||||
sti gr6,@(gr11,#1*0x08)
|
||||
sethi.p %hi(__region_CS2),gr4
|
||||
setlo %lo(__region_CS2),gr4
|
||||
sethi.p %hi(__region_CS2_M),gr5
|
||||
setlo %lo(__region_CS2_M),gr5
|
||||
sethi.p %hi(__region_CS2_C),gr6
|
||||
setlo %lo(__region_CS2_C),gr6
|
||||
sti gr4,@(gr10,#2*0x08)
|
||||
sti gr5,@(gr10,#2*0x08+0x100)
|
||||
sti gr6,@(gr11,#2*0x08)
|
||||
sethi.p %hi(__region_CS3),gr4
|
||||
setlo %lo(__region_CS3),gr4
|
||||
sethi.p %hi(__region_CS3_M),gr5
|
||||
setlo %lo(__region_CS3_M),gr5
|
||||
sethi.p %hi(__region_CS3_C),gr6
|
||||
setlo %lo(__region_CS3_C),gr6
|
||||
sti gr4,@(gr10,#3*0x08)
|
||||
sti gr5,@(gr10,#3*0x08+0x100)
|
||||
sti gr6,@(gr11,#3*0x08)
|
||||
sethi.p %hi(__region_CS4),gr4
|
||||
setlo %lo(__region_CS4),gr4
|
||||
sethi.p %hi(__region_CS4_M),gr5
|
||||
setlo %lo(__region_CS4_M),gr5
|
||||
sethi.p %hi(__region_CS4_C),gr6
|
||||
setlo %lo(__region_CS4_C),gr6
|
||||
sti gr4,@(gr10,#4*0x08)
|
||||
sti gr5,@(gr10,#4*0x08+0x100)
|
||||
sti gr6,@(gr11,#4*0x08)
|
||||
sethi.p %hi(__region_CS5),gr4
|
||||
setlo %lo(__region_CS5),gr4
|
||||
sethi.p %hi(__region_CS5_M),gr5
|
||||
setlo %lo(__region_CS5_M),gr5
|
||||
sethi.p %hi(__region_CS5_C),gr6
|
||||
setlo %lo(__region_CS5_C),gr6
|
||||
sti gr4,@(gr10,#5*0x08)
|
||||
sti gr5,@(gr10,#5*0x08+0x100)
|
||||
sti gr6,@(gr11,#5*0x08)
|
||||
sethi.p %hi(__region_CS6),gr4
|
||||
setlo %lo(__region_CS6),gr4
|
||||
sethi.p %hi(__region_CS6_M),gr5
|
||||
setlo %lo(__region_CS6_M),gr5
|
||||
sethi.p %hi(__region_CS6_C),gr6
|
||||
setlo %lo(__region_CS6_C),gr6
|
||||
sti gr4,@(gr10,#6*0x08)
|
||||
sti gr5,@(gr10,#6*0x08+0x100)
|
||||
sti gr6,@(gr11,#6*0x08)
|
||||
sethi.p %hi(__region_CS7),gr4
|
||||
setlo %lo(__region_CS7),gr4
|
||||
sethi.p %hi(__region_CS7_M),gr5
|
||||
setlo %lo(__region_CS7_M),gr5
|
||||
sethi.p %hi(__region_CS7_C),gr6
|
||||
setlo %lo(__region_CS7_C),gr6
|
||||
sti gr4,@(gr10,#7*0x08)
|
||||
sti gr5,@(gr10,#7*0x08+0x100)
|
||||
sti gr6,@(gr11,#7*0x08)
|
||||
membar
|
||||
bar
|
||||
|
||||
# adjust LED bank address
|
||||
#ifdef CONFIG_MB93091_VDK
|
||||
sethi.p %hi(LED_ADDR - 0x20000000 +__region_CS2),gr30
|
||||
setlo %lo(LED_ADDR - 0x20000000 +__region_CS2),gr30
|
||||
#endif
|
||||
bralr
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# determine the total SDRAM size
|
||||
#
|
||||
# ENTRY: EXIT:
|
||||
# GR25 - SDRAM size
|
||||
# GR26 &__head_reference [saved]
|
||||
# GR30 LED address [saved]
|
||||
#
|
||||
###############################################################################
|
||||
.globl __head_fr555_survey_sdram
|
||||
__head_fr555_survey_sdram:
|
||||
sethi.p %hi(__551_DAMK0),gr11
|
||||
setlo %lo(__551_DAMK0),gr11
|
||||
sethi.p %hi(__551_DARS0),gr12
|
||||
setlo %lo(__551_DARS0),gr12
|
||||
|
||||
sethi.p %hi(0xfff),gr17 ; unused SDRAM AMK value
|
||||
setlo %lo(0xfff),gr17
|
||||
setlos #0,gr25
|
||||
|
||||
ldi @(gr11,#0x00),gr6 ; DAMK0: bits 11:0 match addr 11:0
|
||||
subcc gr6,gr17,gr0,icc0
|
||||
beq icc0,#0,__head_no_DCS0
|
||||
ldi @(gr12,#0x00),gr4 ; DARS0
|
||||
add gr25,gr6,gr25
|
||||
addi gr25,#1,gr25
|
||||
__head_no_DCS0:
|
||||
|
||||
ldi @(gr11,#0x04),gr6 ; DAMK1: bits 11:0 match addr 11:0
|
||||
subcc gr6,gr17,gr0,icc0
|
||||
beq icc0,#0,__head_no_DCS1
|
||||
ldi @(gr12,#0x04),gr4 ; DARS1
|
||||
add gr25,gr6,gr25
|
||||
addi gr25,#1,gr25
|
||||
__head_no_DCS1:
|
||||
|
||||
ldi @(gr11,#0x8),gr6 ; DAMK2: bits 11:0 match addr 11:0
|
||||
subcc gr6,gr17,gr0,icc0
|
||||
beq icc0,#0,__head_no_DCS2
|
||||
ldi @(gr12,#0x8),gr4 ; DARS2
|
||||
add gr25,gr6,gr25
|
||||
addi gr25,#1,gr25
|
||||
__head_no_DCS2:
|
||||
|
||||
ldi @(gr11,#0xc),gr6 ; DAMK3: bits 11:0 match addr 11:0
|
||||
subcc gr6,gr17,gr0,icc0
|
||||
beq icc0,#0,__head_no_DCS3
|
||||
ldi @(gr12,#0xc),gr4 ; DARS3
|
||||
add gr25,gr6,gr25
|
||||
addi gr25,#1,gr25
|
||||
__head_no_DCS3:
|
||||
|
||||
slli gr25,#20,gr25 ; shift [11:0] -> [31:20]
|
||||
bralr
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# set the protection map with the I/DAMPR registers
|
||||
#
|
||||
# ENTRY: EXIT:
|
||||
# GR25 SDRAM size saved
|
||||
# GR30 LED address saved
|
||||
#
|
||||
###############################################################################
|
||||
.globl __head_fr555_set_protection
|
||||
__head_fr555_set_protection:
|
||||
movsg lr,gr27
|
||||
|
||||
sethi.p %hi(0xfff00000),gr11
|
||||
setlo %lo(0xfff00000),gr11
|
||||
|
||||
# set the I/O region protection registers for FR555
|
||||
sethi.p %hi(__region_IO),gr7
|
||||
setlo %lo(__region_IO),gr7
|
||||
ori gr7,#xAMPRx_SS_512Mb|xAMPRx_S_KERNEL|xAMPRx_C|xAMPRx_V,gr5
|
||||
movgs gr0,iampr15
|
||||
movgs gr0,iamlr15
|
||||
movgs gr5,dampr15
|
||||
movgs gr7,damlr15
|
||||
|
||||
# need to tile the remaining IAMPR/DAMPR registers to cover as much of the RAM as possible
|
||||
# - start with the highest numbered registers
|
||||
sethi.p %hi(__kernel_image_end),gr8
|
||||
setlo %lo(__kernel_image_end),gr8
|
||||
sethi.p %hi(32768),gr4 ; allow for a maximal allocator bitmap
|
||||
setlo %lo(32768),gr4
|
||||
add gr8,gr4,gr8
|
||||
sethi.p %hi(1024*2048-1),gr4 ; round up to nearest 2MiB
|
||||
setlo %lo(1024*2048-1),gr4
|
||||
add.p gr8,gr4,gr8
|
||||
not gr4,gr4
|
||||
and gr8,gr4,gr8
|
||||
|
||||
sethi.p %hi(__page_offset),gr9
|
||||
setlo %lo(__page_offset),gr9
|
||||
add gr9,gr25,gr9
|
||||
|
||||
# GR8 = base of uncovered RAM
|
||||
# GR9 = top of uncovered RAM
|
||||
# GR11 - mask for DAMLR/IAMLR regs
|
||||
#
|
||||
call __head_split_region
|
||||
movgs gr4,iampr14
|
||||
movgs gr6,iamlr14
|
||||
movgs gr5,dampr14
|
||||
movgs gr7,damlr14
|
||||
call __head_split_region
|
||||
movgs gr4,iampr13
|
||||
movgs gr6,iamlr13
|
||||
movgs gr5,dampr13
|
||||
movgs gr7,damlr13
|
||||
call __head_split_region
|
||||
movgs gr4,iampr12
|
||||
movgs gr6,iamlr12
|
||||
movgs gr5,dampr12
|
||||
movgs gr7,damlr12
|
||||
call __head_split_region
|
||||
movgs gr4,iampr11
|
||||
movgs gr6,iamlr11
|
||||
movgs gr5,dampr11
|
||||
movgs gr7,damlr11
|
||||
call __head_split_region
|
||||
movgs gr4,iampr10
|
||||
movgs gr6,iamlr10
|
||||
movgs gr5,dampr10
|
||||
movgs gr7,damlr10
|
||||
call __head_split_region
|
||||
movgs gr4,iampr9
|
||||
movgs gr6,iamlr9
|
||||
movgs gr5,dampr9
|
||||
movgs gr7,damlr9
|
||||
call __head_split_region
|
||||
movgs gr4,iampr8
|
||||
movgs gr6,iamlr8
|
||||
movgs gr5,dampr8
|
||||
movgs gr7,damlr8
|
||||
|
||||
call __head_split_region
|
||||
movgs gr4,iampr7
|
||||
movgs gr6,iamlr7
|
||||
movgs gr5,dampr7
|
||||
movgs gr7,damlr7
|
||||
call __head_split_region
|
||||
movgs gr4,iampr6
|
||||
movgs gr6,iamlr6
|
||||
movgs gr5,dampr6
|
||||
movgs gr7,damlr6
|
||||
call __head_split_region
|
||||
movgs gr4,iampr5
|
||||
movgs gr6,iamlr5
|
||||
movgs gr5,dampr5
|
||||
movgs gr7,damlr5
|
||||
call __head_split_region
|
||||
movgs gr4,iampr4
|
||||
movgs gr6,iamlr4
|
||||
movgs gr5,dampr4
|
||||
movgs gr7,damlr4
|
||||
call __head_split_region
|
||||
movgs gr4,iampr3
|
||||
movgs gr6,iamlr3
|
||||
movgs gr5,dampr3
|
||||
movgs gr7,damlr3
|
||||
call __head_split_region
|
||||
movgs gr4,iampr2
|
||||
movgs gr6,iamlr2
|
||||
movgs gr5,dampr2
|
||||
movgs gr7,damlr2
|
||||
call __head_split_region
|
||||
movgs gr4,iampr1
|
||||
movgs gr6,iamlr1
|
||||
movgs gr5,dampr1
|
||||
movgs gr7,damlr1
|
||||
|
||||
# cover kernel core image with kernel-only segment
|
||||
sethi.p %hi(__page_offset),gr8
|
||||
setlo %lo(__page_offset),gr8
|
||||
call __head_split_region
|
||||
|
||||
#ifdef CONFIG_PROTECT_KERNEL
|
||||
ori.p gr4,#xAMPRx_S_KERNEL,gr4
|
||||
ori gr5,#xAMPRx_S_KERNEL,gr5
|
||||
#endif
|
||||
|
||||
movgs gr4,iampr0
|
||||
movgs gr6,iamlr0
|
||||
movgs gr5,dampr0
|
||||
movgs gr7,damlr0
|
||||
jmpl @(gr27,gr0)
|
638
arch/frv/kernel/head.S
Normal file
638
arch/frv/kernel/head.S
Normal file
|
@ -0,0 +1,638 @@
|
|||
/* head.S: kernel entry point for FR-V kernel
|
||||
*
|
||||
* Copyright (C) 2003, 2004 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/threads.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/spr-regs.h>
|
||||
#include <asm/mb86943a.h>
|
||||
#include <asm/cache.h>
|
||||
#include "head.inc"
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# void _boot(unsigned long magic, char *command_line) __attribute__((noreturn))
|
||||
#
|
||||
# - if magic is 0xdead1eaf, then command_line is assumed to point to the kernel
|
||||
# command line string
|
||||
#
|
||||
###############################################################################
|
||||
__HEAD
|
||||
.balign 4
|
||||
|
||||
.globl _boot, __head_reference
|
||||
.type _boot,@function
|
||||
_boot:
|
||||
__head_reference:
|
||||
sethi.p %hi(LED_ADDR),gr30
|
||||
setlo %lo(LED_ADDR),gr30
|
||||
|
||||
LEDS 0x0000
|
||||
|
||||
# calculate reference address for PC-relative stuff
|
||||
call 0f
|
||||
0: movsg lr,gr26
|
||||
addi gr26,#__head_reference-0b,gr26
|
||||
|
||||
# invalidate and disable both of the caches and turn off the memory access checking
|
||||
dcef @(gr0,gr0),1
|
||||
bar
|
||||
|
||||
sethi.p %hi(~(HSR0_ICE|HSR0_DCE|HSR0_CBM|HSR0_EIMMU|HSR0_EDMMU)),gr4
|
||||
setlo %lo(~(HSR0_ICE|HSR0_DCE|HSR0_CBM|HSR0_EIMMU|HSR0_EDMMU)),gr4
|
||||
movsg hsr0,gr5
|
||||
and gr4,gr5,gr5
|
||||
movgs gr5,hsr0
|
||||
movsg hsr0,gr5
|
||||
|
||||
LEDS 0x0001
|
||||
|
||||
icei @(gr0,gr0),1
|
||||
dcei @(gr0,gr0),1
|
||||
bar
|
||||
|
||||
# turn the instruction cache back on
|
||||
sethi.p %hi(HSR0_ICE),gr4
|
||||
setlo %lo(HSR0_ICE),gr4
|
||||
movsg hsr0,gr5
|
||||
or gr4,gr5,gr5
|
||||
movgs gr5,hsr0
|
||||
movsg hsr0,gr5
|
||||
|
||||
bar
|
||||
|
||||
LEDS 0x0002
|
||||
|
||||
# retrieve the parameters (including command line) before we overwrite them
|
||||
sethi.p %hi(0xdead1eaf),gr7
|
||||
setlo %lo(0xdead1eaf),gr7
|
||||
subcc gr7,gr8,gr0,icc0
|
||||
bne icc0,#0,__head_no_parameters
|
||||
|
||||
sethi.p %hi(redboot_command_line-1),gr6
|
||||
setlo %lo(redboot_command_line-1),gr6
|
||||
sethi.p %hi(__head_reference),gr4
|
||||
setlo %lo(__head_reference),gr4
|
||||
sub gr6,gr4,gr6
|
||||
add.p gr6,gr26,gr6
|
||||
subi gr9,#1,gr9
|
||||
setlos.p #511,gr4
|
||||
setlos #1,gr5
|
||||
|
||||
__head_copy_cmdline:
|
||||
ldubu.p @(gr9,gr5),gr16
|
||||
subicc gr4,#1,gr4,icc0
|
||||
stbu.p gr16,@(gr6,gr5)
|
||||
subicc gr16,#0,gr0,icc1
|
||||
bls icc0,#0,__head_end_cmdline
|
||||
bne icc1,#1,__head_copy_cmdline
|
||||
__head_end_cmdline:
|
||||
stbu gr0,@(gr6,gr5)
|
||||
__head_no_parameters:
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# we need to relocate the SDRAM to 0x00000000 (linux) or 0xC0000000 (uClinux)
|
||||
# - note that we're going to have to run entirely out of the icache whilst
|
||||
# fiddling with the SDRAM controller registers
|
||||
#
|
||||
###############################################################################
|
||||
#ifdef CONFIG_MMU
|
||||
call __head_fr451_describe_sdram
|
||||
|
||||
#else
|
||||
movsg psr,gr5
|
||||
srli gr5,#28,gr5
|
||||
subicc gr5,#3,gr0,icc0
|
||||
beq icc0,#0,__head_fr551_sdram
|
||||
|
||||
call __head_fr401_describe_sdram
|
||||
bra __head_do_sdram
|
||||
|
||||
__head_fr551_sdram:
|
||||
call __head_fr555_describe_sdram
|
||||
LEDS 0x000d
|
||||
|
||||
__head_do_sdram:
|
||||
#endif
|
||||
|
||||
# preload the registers with invalid values in case any DBR/DARS are marked not present
|
||||
sethi.p %hi(0xfe000000),gr17 ; unused SDRAM DBR value
|
||||
setlo %lo(0xfe000000),gr17
|
||||
or.p gr17,gr0,gr20
|
||||
or gr17,gr0,gr21
|
||||
or.p gr17,gr0,gr22
|
||||
or gr17,gr0,gr23
|
||||
|
||||
# consult the SDRAM controller CS address registers
|
||||
cld @(gr14,gr0 ),gr20, cc0,#1 ; DBR0 / DARS0
|
||||
cld @(gr14,gr11),gr21, cc1,#1 ; DBR1 / DARS1
|
||||
cld @(gr14,gr12),gr22, cc2,#1 ; DBR2 / DARS2
|
||||
cld.p @(gr14,gr13),gr23, cc3,#1 ; DBR3 / DARS3
|
||||
|
||||
sll gr20,gr15,gr20 ; shift values up for FR551
|
||||
sll gr21,gr15,gr21
|
||||
sll gr22,gr15,gr22
|
||||
sll gr23,gr15,gr23
|
||||
|
||||
LEDS 0x0003
|
||||
|
||||
# assume the lowest valid CS line to be the SDRAM base and get its address
|
||||
subcc gr20,gr17,gr0,icc0
|
||||
subcc.p gr21,gr17,gr0,icc1
|
||||
subcc gr22,gr17,gr0,icc2
|
||||
subcc.p gr23,gr17,gr0,icc3
|
||||
ckne icc0,cc4 ; T if DBR0 != 0xfe000000
|
||||
ckne icc1,cc5
|
||||
ckne icc2,cc6
|
||||
ckne icc3,cc7
|
||||
cor gr23,gr0,gr24, cc7,#1 ; GR24 = SDRAM base
|
||||
cor gr22,gr0,gr24, cc6,#1
|
||||
cor gr21,gr0,gr24, cc5,#1
|
||||
cor gr20,gr0,gr24, cc4,#1
|
||||
|
||||
# calculate the displacement required to get the SDRAM into the right place in memory
|
||||
sethi.p %hi(__sdram_base),gr16
|
||||
setlo %lo(__sdram_base),gr16
|
||||
sub gr16,gr24,gr16 ; delta = __sdram_base - DBRx
|
||||
|
||||
# calculate the new values to go in the controller regs
|
||||
cadd.p gr20,gr16,gr20, cc4,#1 ; DCS#0 (new) = DCS#0 (old) + delta
|
||||
cadd gr21,gr16,gr21, cc5,#1
|
||||
cadd.p gr22,gr16,gr22, cc6,#1
|
||||
cadd gr23,gr16,gr23, cc7,#1
|
||||
|
||||
srl gr20,gr15,gr20 ; shift values down for FR551
|
||||
srl gr21,gr15,gr21
|
||||
srl gr22,gr15,gr22
|
||||
srl gr23,gr15,gr23
|
||||
|
||||
# work out the address at which the reg updater resides and lock it into icache
|
||||
# also work out the address the updater will jump to when finished
|
||||
sethi.p %hi(__head_move_sdram-__head_reference),gr18
|
||||
setlo %lo(__head_move_sdram-__head_reference),gr18
|
||||
sethi.p %hi(__head_sdram_moved-__head_reference),gr19
|
||||
setlo %lo(__head_sdram_moved-__head_reference),gr19
|
||||
add.p gr18,gr26,gr18
|
||||
add gr19,gr26,gr19
|
||||
add.p gr19,gr16,gr19 ; moved = addr + (__sdram_base - DBRx)
|
||||
add gr18,gr5,gr4 ; two cachelines probably required
|
||||
|
||||
icpl gr18,gr0,#1 ; load and lock the cachelines
|
||||
icpl gr4,gr0,#1
|
||||
LEDS 0x0004
|
||||
membar
|
||||
bar
|
||||
jmpl @(gr18,gr0)
|
||||
|
||||
.balign L1_CACHE_BYTES
|
||||
__head_move_sdram:
|
||||
cst gr20,@(gr14,gr0 ), cc4,#1
|
||||
cst gr21,@(gr14,gr11), cc5,#1
|
||||
cst gr22,@(gr14,gr12), cc6,#1
|
||||
cst gr23,@(gr14,gr13), cc7,#1
|
||||
cld @(gr14,gr0 ),gr20, cc4,#1
|
||||
cld @(gr14,gr11),gr21, cc5,#1
|
||||
cld @(gr14,gr12),gr22, cc4,#1
|
||||
cld @(gr14,gr13),gr23, cc7,#1
|
||||
bar
|
||||
membar
|
||||
jmpl @(gr19,gr0)
|
||||
|
||||
.balign L1_CACHE_BYTES
|
||||
__head_sdram_moved:
|
||||
icul gr18
|
||||
add gr18,gr5,gr4
|
||||
icul gr4
|
||||
icei @(gr0,gr0),1
|
||||
dcei @(gr0,gr0),1
|
||||
|
||||
LEDS 0x0005
|
||||
|
||||
# recalculate reference address
|
||||
call 0f
|
||||
0: movsg lr,gr26
|
||||
addi gr26,#__head_reference-0b,gr26
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# move the kernel image down to the bottom of the SDRAM
|
||||
#
|
||||
###############################################################################
|
||||
sethi.p %hi(__kernel_image_size_no_bss+15),gr4
|
||||
setlo %lo(__kernel_image_size_no_bss+15),gr4
|
||||
srli.p gr4,#4,gr4 ; count
|
||||
or gr26,gr26,gr16 ; source
|
||||
|
||||
sethi.p %hi(__sdram_base),gr17 ; destination
|
||||
setlo %lo(__sdram_base),gr17
|
||||
|
||||
setlos #8,gr5
|
||||
sub.p gr16,gr5,gr16 ; adjust src for LDDU
|
||||
sub gr17,gr5,gr17 ; adjust dst for LDDU
|
||||
|
||||
sethi.p %hi(__head_move_kernel-__head_reference),gr18
|
||||
setlo %lo(__head_move_kernel-__head_reference),gr18
|
||||
sethi.p %hi(__head_kernel_moved-__head_reference+__sdram_base),gr19
|
||||
setlo %lo(__head_kernel_moved-__head_reference+__sdram_base),gr19
|
||||
add gr18,gr26,gr18
|
||||
icpl gr18,gr0,#1
|
||||
jmpl @(gr18,gr0)
|
||||
|
||||
.balign 32
|
||||
__head_move_kernel:
|
||||
lddu @(gr16,gr5),gr10
|
||||
lddu @(gr16,gr5),gr12
|
||||
stdu.p gr10,@(gr17,gr5)
|
||||
subicc gr4,#1,gr4,icc0
|
||||
stdu.p gr12,@(gr17,gr5)
|
||||
bhi icc0,#0,__head_move_kernel
|
||||
jmpl @(gr19,gr0)
|
||||
|
||||
.balign 32
|
||||
__head_kernel_moved:
|
||||
icul gr18
|
||||
icei @(gr0,gr0),1
|
||||
dcei @(gr0,gr0),1
|
||||
|
||||
LEDS 0x0006
|
||||
|
||||
# recalculate reference address
|
||||
call 0f
|
||||
0: movsg lr,gr26
|
||||
addi gr26,#__head_reference-0b,gr26
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# rearrange the iomem map and set the protection registers
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
LEDS 0x3301
|
||||
call __head_fr451_set_busctl
|
||||
LEDS 0x3303
|
||||
call __head_fr451_survey_sdram
|
||||
LEDS 0x3305
|
||||
call __head_fr451_set_protection
|
||||
|
||||
#else
|
||||
movsg psr,gr5
|
||||
srli gr5,#PSR_IMPLE_SHIFT,gr5
|
||||
subicc gr5,#PSR_IMPLE_FR551,gr0,icc0
|
||||
beq icc0,#0,__head_fr555_memmap
|
||||
subicc gr5,#PSR_IMPLE_FR451,gr0,icc0
|
||||
beq icc0,#0,__head_fr451_memmap
|
||||
|
||||
LEDS 0x3101
|
||||
call __head_fr401_set_busctl
|
||||
LEDS 0x3103
|
||||
call __head_fr401_survey_sdram
|
||||
LEDS 0x3105
|
||||
call __head_fr401_set_protection
|
||||
bra __head_done_memmap
|
||||
|
||||
__head_fr451_memmap:
|
||||
LEDS 0x3301
|
||||
call __head_fr401_set_busctl
|
||||
LEDS 0x3303
|
||||
call __head_fr401_survey_sdram
|
||||
LEDS 0x3305
|
||||
call __head_fr451_set_protection
|
||||
bra __head_done_memmap
|
||||
|
||||
__head_fr555_memmap:
|
||||
LEDS 0x3501
|
||||
call __head_fr555_set_busctl
|
||||
LEDS 0x3503
|
||||
call __head_fr555_survey_sdram
|
||||
LEDS 0x3505
|
||||
call __head_fr555_set_protection
|
||||
|
||||
__head_done_memmap:
|
||||
#endif
|
||||
LEDS 0x0007
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# turn the data cache and MMU on
|
||||
# - for the FR451 this'll mean that the window through which the kernel is
|
||||
# viewed will change
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
#define MMUMODE HSR0_EIMMU|HSR0_EDMMU|HSR0_EXMMU|HSR0_EDAT|HSR0_XEDAT
|
||||
#else
|
||||
#define MMUMODE HSR0_EIMMU|HSR0_EDMMU
|
||||
#endif
|
||||
|
||||
movsg hsr0,gr5
|
||||
|
||||
sethi.p %hi(MMUMODE),gr4
|
||||
setlo %lo(MMUMODE),gr4
|
||||
or gr4,gr5,gr5
|
||||
|
||||
#if defined(CONFIG_FRV_DEFL_CACHE_WTHRU)
|
||||
sethi.p %hi(HSR0_DCE|HSR0_CBM_WRITE_THRU),gr4
|
||||
setlo %lo(HSR0_DCE|HSR0_CBM_WRITE_THRU),gr4
|
||||
#elif defined(CONFIG_FRV_DEFL_CACHE_WBACK)
|
||||
sethi.p %hi(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
|
||||
setlo %lo(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
|
||||
#elif defined(CONFIG_FRV_DEFL_CACHE_WBEHIND)
|
||||
sethi.p %hi(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
|
||||
setlo %lo(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
|
||||
|
||||
movsg psr,gr6
|
||||
srli gr6,#24,gr6
|
||||
cmpi gr6,#0x50,icc0 // FR451
|
||||
beq icc0,#0,0f
|
||||
cmpi gr6,#0x40,icc0 // FR405
|
||||
bne icc0,#0,1f
|
||||
0:
|
||||
# turn off write-allocate
|
||||
sethi.p %hi(HSR0_NWA),gr6
|
||||
setlo %lo(HSR0_NWA),gr6
|
||||
or gr4,gr6,gr4
|
||||
1:
|
||||
|
||||
#else
|
||||
#error No default cache configuration set
|
||||
#endif
|
||||
|
||||
or gr4,gr5,gr5
|
||||
movgs gr5,hsr0
|
||||
bar
|
||||
|
||||
LEDS 0x0008
|
||||
|
||||
sethi.p %hi(__head_mmu_enabled),gr19
|
||||
setlo %lo(__head_mmu_enabled),gr19
|
||||
jmpl @(gr19,gr0)
|
||||
|
||||
__head_mmu_enabled:
|
||||
icei @(gr0,gr0),#1
|
||||
dcei @(gr0,gr0),#1
|
||||
|
||||
LEDS 0x0009
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
call __head_fr451_finalise_protection
|
||||
#endif
|
||||
|
||||
LEDS 0x000a
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# set up the runtime environment
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
# clear the BSS area
|
||||
sethi.p %hi(__bss_start),gr4
|
||||
setlo %lo(__bss_start),gr4
|
||||
sethi.p %hi(_end),gr5
|
||||
setlo %lo(_end),gr5
|
||||
or.p gr0,gr0,gr18
|
||||
or gr0,gr0,gr19
|
||||
|
||||
0:
|
||||
stdi gr18,@(gr4,#0)
|
||||
stdi gr18,@(gr4,#8)
|
||||
stdi gr18,@(gr4,#16)
|
||||
stdi.p gr18,@(gr4,#24)
|
||||
addi gr4,#24,gr4
|
||||
subcc gr5,gr4,gr0,icc0
|
||||
bhi icc0,#2,0b
|
||||
|
||||
LEDS 0x000b
|
||||
|
||||
# save the SDRAM details
|
||||
sethi.p %hi(__sdram_old_base),gr4
|
||||
setlo %lo(__sdram_old_base),gr4
|
||||
st gr24,@(gr4,gr0)
|
||||
|
||||
sethi.p %hi(__sdram_base),gr5
|
||||
setlo %lo(__sdram_base),gr5
|
||||
sethi.p %hi(memory_start),gr4
|
||||
setlo %lo(memory_start),gr4
|
||||
st gr5,@(gr4,gr0)
|
||||
|
||||
add gr25,gr5,gr25
|
||||
sethi.p %hi(memory_end),gr4
|
||||
setlo %lo(memory_end),gr4
|
||||
st gr25,@(gr4,gr0)
|
||||
|
||||
# point the TBR at the kernel trap table
|
||||
sethi.p %hi(__entry_kerneltrap_table),gr4
|
||||
setlo %lo(__entry_kerneltrap_table),gr4
|
||||
movgs gr4,tbr
|
||||
|
||||
# set up the exception frame for init
|
||||
sethi.p %hi(__kernel_frame0_ptr),gr28
|
||||
setlo %lo(__kernel_frame0_ptr),gr28
|
||||
sethi.p %hi(_gp),gr16
|
||||
setlo %lo(_gp),gr16
|
||||
sethi.p %hi(__entry_usertrap_table),gr4
|
||||
setlo %lo(__entry_usertrap_table),gr4
|
||||
|
||||
lddi @(gr28,#0),gr28 ; load __frame & current
|
||||
ldi.p @(gr29,#4),gr15 ; set current_thread
|
||||
|
||||
or gr0,gr0,fp
|
||||
or gr28,gr0,sp
|
||||
|
||||
sti.p gr4,@(gr28,REG_TBR)
|
||||
setlos #ISR_EDE|ISR_DTT_DIVBYZERO|ISR_EMAM_EXCEPTION,gr5
|
||||
movgs gr5,isr
|
||||
|
||||
# turn on and off various CPU services
|
||||
movsg psr,gr22
|
||||
sethi.p %hi(#PSR_EM|PSR_EF|PSR_CM|PSR_NEM),gr4
|
||||
setlo %lo(#PSR_EM|PSR_EF|PSR_CM|PSR_NEM),gr4
|
||||
or gr22,gr4,gr22
|
||||
movgs gr22,psr
|
||||
|
||||
andi gr22,#~(PSR_PIL|PSR_PS|PSR_S),gr22
|
||||
ori gr22,#PSR_ET,gr22
|
||||
sti gr22,@(gr28,REG_PSR)
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# set up the registers and jump into the kernel
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
LEDS 0x000c
|
||||
|
||||
sethi.p #0xe5e5,gr3
|
||||
setlo #0xe5e5,gr3
|
||||
or.p gr3,gr0,gr4
|
||||
or gr3,gr0,gr5
|
||||
or.p gr3,gr0,gr6
|
||||
or gr3,gr0,gr7
|
||||
or.p gr3,gr0,gr8
|
||||
or gr3,gr0,gr9
|
||||
or.p gr3,gr0,gr10
|
||||
or gr3,gr0,gr11
|
||||
or.p gr3,gr0,gr12
|
||||
or gr3,gr0,gr13
|
||||
or.p gr3,gr0,gr14
|
||||
or gr3,gr0,gr17
|
||||
or.p gr3,gr0,gr18
|
||||
or gr3,gr0,gr19
|
||||
or.p gr3,gr0,gr20
|
||||
or gr3,gr0,gr21
|
||||
or.p gr3,gr0,gr23
|
||||
or gr3,gr0,gr24
|
||||
or.p gr3,gr0,gr25
|
||||
or gr3,gr0,gr26
|
||||
or.p gr3,gr0,gr27
|
||||
# or gr3,gr0,gr30
|
||||
or gr3,gr0,gr31
|
||||
movgs gr0,lr
|
||||
movgs gr0,lcr
|
||||
movgs gr0,ccr
|
||||
movgs gr0,cccr
|
||||
|
||||
# initialise the virtual interrupt handling
|
||||
subcc gr0,gr0,gr0,icc2 /* set Z, clear C */
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
movgs gr3,scr2
|
||||
movgs gr3,scr3
|
||||
#endif
|
||||
|
||||
LEDS 0x0fff
|
||||
|
||||
# invoke the debugging stub if present
|
||||
# - arch/frv/kernel/debug-stub.c will shift control directly to init/main.c
|
||||
# (it will not return here)
|
||||
break
|
||||
.globl __debug_stub_init_break
|
||||
__debug_stub_init_break:
|
||||
|
||||
# however, if you need to use an ICE, and don't care about using any userspace
|
||||
# debugging tools (such as the ptrace syscall), you can just step over the break
|
||||
# above and get to the kernel this way
|
||||
# look at arch/frv/kernel/debug-stub.c: debug_stub_init() to see what you've missed
|
||||
call start_kernel
|
||||
|
||||
.globl __head_end
|
||||
__head_end:
|
||||
.size _boot, .-_boot
|
||||
|
||||
# provide a point for GDB to place a break
|
||||
.section .text..start,"ax"
|
||||
.globl _start
|
||||
.balign 4
|
||||
_start:
|
||||
call _boot
|
||||
|
||||
.previous
|
||||
###############################################################################
|
||||
#
|
||||
# split a tile off of the region defined by GR8-GR9
|
||||
#
|
||||
# ENTRY: EXIT:
|
||||
# GR4 - IAMPR value representing tile
|
||||
# GR5 - DAMPR value representing tile
|
||||
# GR6 - IAMLR value representing tile
|
||||
# GR7 - DAMLR value representing tile
|
||||
# GR8 region base pointer [saved]
|
||||
# GR9 region top pointer updated to exclude new tile
|
||||
# GR11 xAMLR mask [saved]
|
||||
# GR25 SDRAM size [saved]
|
||||
# GR30 LED address [saved]
|
||||
#
|
||||
# - GR8 and GR9 should be rounded up/down to the nearest megabyte before calling
|
||||
#
|
||||
###############################################################################
|
||||
.globl __head_split_region
|
||||
.type __head_split_region,@function
|
||||
__head_split_region:
|
||||
subcc.p gr9,gr8,gr4,icc0
|
||||
setlos #31,gr5
|
||||
scan.p gr4,gr0,gr6
|
||||
beq icc0,#0,__head_region_empty
|
||||
sub.p gr5,gr6,gr6 ; bit number of highest set bit (1MB=>20)
|
||||
setlos #1,gr4
|
||||
sll.p gr4,gr6,gr4 ; size of region (1 << bitno)
|
||||
subi gr6,#17,gr6 ; 1MB => 0x03
|
||||
slli.p gr6,#4,gr6 ; 1MB => 0x30
|
||||
sub gr9,gr4,gr9 ; move uncovered top down
|
||||
|
||||
or gr9,gr6,gr4
|
||||
ori gr4,#xAMPRx_S_USER|xAMPRx_C_CACHED|xAMPRx_V,gr4
|
||||
or.p gr4,gr0,gr5
|
||||
|
||||
and gr4,gr11,gr6
|
||||
and.p gr5,gr11,gr7
|
||||
bralr
|
||||
|
||||
__head_region_empty:
|
||||
or.p gr0,gr0,gr4
|
||||
or gr0,gr0,gr5
|
||||
or.p gr0,gr0,gr6
|
||||
or gr0,gr0,gr7
|
||||
bralr
|
||||
.size __head_split_region, .-__head_split_region
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# write the 32-bit hex number in GR8 to ttyS0
|
||||
#
|
||||
###############################################################################
|
||||
#if 0
|
||||
.globl __head_write_to_ttyS0
|
||||
.type __head_write_to_ttyS0,@function
|
||||
__head_write_to_ttyS0:
|
||||
sethi.p %hi(0xfeff9c00),gr31
|
||||
setlo %lo(0xfeff9c00),gr31
|
||||
setlos #8,gr20
|
||||
|
||||
0: ldubi @(gr31,#5*8),gr21
|
||||
andi gr21,#0x60,gr21
|
||||
subicc gr21,#0x60,gr21,icc0
|
||||
bne icc0,#0,0b
|
||||
|
||||
1: srli gr8,#28,gr21
|
||||
slli gr8,#4,gr8
|
||||
|
||||
addi gr21,#'0',gr21
|
||||
subicc gr21,#'9',gr0,icc0
|
||||
bls icc0,#2,2f
|
||||
addi gr21,#'A'-'0'-10,gr21
|
||||
2:
|
||||
stbi gr21,@(gr31,#0*8)
|
||||
subicc gr20,#1,gr20,icc0
|
||||
bhi icc0,#2,1b
|
||||
|
||||
setlos #'\r',gr21
|
||||
stbi gr21,@(gr31,#0*8)
|
||||
|
||||
setlos #'\n',gr21
|
||||
stbi gr21,@(gr31,#0*8)
|
||||
|
||||
3: ldubi @(gr31,#5*8),gr21
|
||||
andi gr21,#0x60,gr21
|
||||
subicc gr21,#0x60,gr21,icc0
|
||||
bne icc0,#0,3b
|
||||
bralr
|
||||
|
||||
.size __head_write_to_ttyS0, .-__head_write_to_ttyS0
|
||||
#endif
|
50
arch/frv/kernel/head.inc
Normal file
50
arch/frv/kernel/head.inc
Normal file
|
@ -0,0 +1,50 @@
|
|||
/* head.inc: head common definitions -*- asm -*-
|
||||
*
|
||||
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
|
||||
#if defined(CONFIG_MB93090_MB00)
|
||||
#define LED_ADDR (0x21200000+4)
|
||||
|
||||
.macro LEDS val
|
||||
sethi.p %hi(0xFFC00030),gr3
|
||||
setlo %lo(0xFFC00030),gr3
|
||||
lduh @(gr3,gr0),gr3
|
||||
andicc gr3,#0x100,gr0,icc0
|
||||
bne icc0,0,999f
|
||||
|
||||
setlos #~\val,gr3
|
||||
st gr3,@(gr30,gr0)
|
||||
membar
|
||||
dcf @(gr30,gr0)
|
||||
999:
|
||||
.endm
|
||||
|
||||
#elif defined(CONFIG_MB93093_PDK)
|
||||
#define LED_ADDR (0x20000023)
|
||||
|
||||
.macro LEDS val
|
||||
setlos #\val,gr3
|
||||
stb gr3,@(gr30,gr0)
|
||||
membar
|
||||
.endm
|
||||
|
||||
#else
|
||||
#define LED_ADDR 0
|
||||
|
||||
.macro LEDS val
|
||||
.endm
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
__sdram_base = 0x00000000 /* base address to which SDRAM relocated */
|
||||
#else
|
||||
__sdram_base = __page_offset /* base address to which SDRAM relocated */
|
||||
#endif
|
157
arch/frv/kernel/irq-mb93091.c
Normal file
157
arch/frv/kernel/irq-mb93091.c
Normal file
|
@ -0,0 +1,157 @@
|
|||
/* irq-mb93091.c: MB93091 FPGA interrupt handling
|
||||
*
|
||||
* Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/delay.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/irc-regs.h>
|
||||
|
||||
#define __reg16(ADDR) (*(volatile unsigned short *)(ADDR))
|
||||
|
||||
#define __get_IMR() ({ __reg16(0xffc00004); })
|
||||
#define __set_IMR(M) do { __reg16(0xffc00004) = (M); wmb(); } while(0)
|
||||
#define __get_IFR() ({ __reg16(0xffc0000c); })
|
||||
#define __clr_IFR(M) do { __reg16(0xffc0000c) = ~(M); wmb(); } while(0)
|
||||
|
||||
|
||||
/*
|
||||
* on-motherboard FPGA PIC operations
|
||||
*/
|
||||
static void frv_fpga_mask(struct irq_data *d)
|
||||
{
|
||||
uint16_t imr = __get_IMR();
|
||||
|
||||
imr |= 1 << (d->irq - IRQ_BASE_FPGA);
|
||||
|
||||
__set_IMR(imr);
|
||||
}
|
||||
|
||||
static void frv_fpga_ack(struct irq_data *d)
|
||||
{
|
||||
__clr_IFR(1 << (d->irq - IRQ_BASE_FPGA));
|
||||
}
|
||||
|
||||
static void frv_fpga_mask_ack(struct irq_data *d)
|
||||
{
|
||||
uint16_t imr = __get_IMR();
|
||||
|
||||
imr |= 1 << (d->irq - IRQ_BASE_FPGA);
|
||||
__set_IMR(imr);
|
||||
|
||||
__clr_IFR(1 << (d->irq - IRQ_BASE_FPGA));
|
||||
}
|
||||
|
||||
static void frv_fpga_unmask(struct irq_data *d)
|
||||
{
|
||||
uint16_t imr = __get_IMR();
|
||||
|
||||
imr &= ~(1 << (d->irq - IRQ_BASE_FPGA));
|
||||
|
||||
__set_IMR(imr);
|
||||
}
|
||||
|
||||
static struct irq_chip frv_fpga_pic = {
|
||||
.name = "mb93091",
|
||||
.irq_ack = frv_fpga_ack,
|
||||
.irq_mask = frv_fpga_mask,
|
||||
.irq_mask_ack = frv_fpga_mask_ack,
|
||||
.irq_unmask = frv_fpga_unmask,
|
||||
};
|
||||
|
||||
/*
|
||||
* FPGA PIC interrupt handler
|
||||
*/
|
||||
static irqreturn_t fpga_interrupt(int irq, void *_mask)
|
||||
{
|
||||
uint16_t imr, mask = (unsigned long) _mask;
|
||||
|
||||
imr = __get_IMR();
|
||||
mask = mask & ~imr & __get_IFR();
|
||||
|
||||
/* poll all the triggered IRQs */
|
||||
while (mask) {
|
||||
int irq;
|
||||
|
||||
asm("scan %1,gr0,%0" : "=r"(irq) : "r"(mask));
|
||||
irq = 31 - irq;
|
||||
mask &= ~(1 << irq);
|
||||
|
||||
generic_handle_irq(IRQ_BASE_FPGA + irq);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* define an interrupt action for each FPGA PIC output
|
||||
* - use dev_id to indicate the FPGA PIC input to output mappings
|
||||
*/
|
||||
static struct irqaction fpga_irq[4] = {
|
||||
[0] = {
|
||||
.handler = fpga_interrupt,
|
||||
.flags = IRQF_SHARED,
|
||||
.name = "fpga.0",
|
||||
.dev_id = (void *) 0x0028UL,
|
||||
},
|
||||
[1] = {
|
||||
.handler = fpga_interrupt,
|
||||
.flags = IRQF_SHARED,
|
||||
.name = "fpga.1",
|
||||
.dev_id = (void *) 0x0050UL,
|
||||
},
|
||||
[2] = {
|
||||
.handler = fpga_interrupt,
|
||||
.flags = IRQF_SHARED,
|
||||
.name = "fpga.2",
|
||||
.dev_id = (void *) 0x1c00UL,
|
||||
},
|
||||
[3] = {
|
||||
.handler = fpga_interrupt,
|
||||
.flags = IRQF_SHARED,
|
||||
.name = "fpga.3",
|
||||
.dev_id = (void *) 0x6386UL,
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* initialise the motherboard FPGA's PIC
|
||||
*/
|
||||
void __init fpga_init(void)
|
||||
{
|
||||
int irq;
|
||||
|
||||
/* all PIC inputs are all set to be low-level driven, apart from the
|
||||
* NMI button (15) which is fixed at falling-edge
|
||||
*/
|
||||
__set_IMR(0x7ffe);
|
||||
__clr_IFR(0x0000);
|
||||
|
||||
for (irq = IRQ_BASE_FPGA + 1; irq <= IRQ_BASE_FPGA + 14; irq++)
|
||||
irq_set_chip_and_handler(irq, &frv_fpga_pic, handle_level_irq);
|
||||
|
||||
irq_set_chip_and_handler(IRQ_FPGA_NMI, &frv_fpga_pic, handle_edge_irq);
|
||||
|
||||
/* the FPGA drives the first four external IRQ inputs on the CPU PIC */
|
||||
setup_irq(IRQ_CPU_EXTERNAL0, &fpga_irq[0]);
|
||||
setup_irq(IRQ_CPU_EXTERNAL1, &fpga_irq[1]);
|
||||
setup_irq(IRQ_CPU_EXTERNAL2, &fpga_irq[2]);
|
||||
setup_irq(IRQ_CPU_EXTERNAL3, &fpga_irq[3]);
|
||||
}
|
129
arch/frv/kernel/irq-mb93093.c
Normal file
129
arch/frv/kernel/irq-mb93093.c
Normal file
|
@ -0,0 +1,129 @@
|
|||
/* irq-mb93093.c: MB93093 FPGA interrupt handling
|
||||
*
|
||||
* Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/delay.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/irc-regs.h>
|
||||
|
||||
#define __reg16(ADDR) (*(volatile unsigned short *)(__region_CS2 + (ADDR)))
|
||||
|
||||
#define __get_IMR() ({ __reg16(0x0a); })
|
||||
#define __set_IMR(M) do { __reg16(0x0a) = (M); wmb(); } while(0)
|
||||
#define __get_IFR() ({ __reg16(0x02); })
|
||||
#define __clr_IFR(M) do { __reg16(0x02) = ~(M); wmb(); } while(0)
|
||||
|
||||
/*
|
||||
* off-CPU FPGA PIC operations
|
||||
*/
|
||||
static void frv_fpga_mask(struct irq_data *d)
|
||||
{
|
||||
uint16_t imr = __get_IMR();
|
||||
|
||||
imr |= 1 << (d->irq - IRQ_BASE_FPGA);
|
||||
__set_IMR(imr);
|
||||
}
|
||||
|
||||
static void frv_fpga_ack(struct irq_data *d)
|
||||
{
|
||||
__clr_IFR(1 << (d->irq - IRQ_BASE_FPGA));
|
||||
}
|
||||
|
||||
static void frv_fpga_mask_ack(struct irq_data *d)
|
||||
{
|
||||
uint16_t imr = __get_IMR();
|
||||
|
||||
imr |= 1 << (d->irq - IRQ_BASE_FPGA);
|
||||
__set_IMR(imr);
|
||||
|
||||
__clr_IFR(1 << (d->irq - IRQ_BASE_FPGA));
|
||||
}
|
||||
|
||||
static void frv_fpga_unmask(struct irq_data *d)
|
||||
{
|
||||
uint16_t imr = __get_IMR();
|
||||
|
||||
imr &= ~(1 << (d->irq - IRQ_BASE_FPGA));
|
||||
|
||||
__set_IMR(imr);
|
||||
}
|
||||
|
||||
static struct irq_chip frv_fpga_pic = {
|
||||
.name = "mb93093",
|
||||
.irq_ack = frv_fpga_ack,
|
||||
.irq_mask = frv_fpga_mask,
|
||||
.irq_mask_ack = frv_fpga_mask_ack,
|
||||
.irq_unmask = frv_fpga_unmask,
|
||||
};
|
||||
|
||||
/*
|
||||
* FPGA PIC interrupt handler
|
||||
*/
|
||||
static irqreturn_t fpga_interrupt(int irq, void *_mask)
|
||||
{
|
||||
uint16_t imr, mask = (unsigned long) _mask;
|
||||
|
||||
imr = __get_IMR();
|
||||
mask = mask & ~imr & __get_IFR();
|
||||
|
||||
/* poll all the triggered IRQs */
|
||||
while (mask) {
|
||||
int irq;
|
||||
|
||||
asm("scan %1,gr0,%0" : "=r"(irq) : "r"(mask));
|
||||
irq = 31 - irq;
|
||||
mask &= ~(1 << irq);
|
||||
|
||||
generic_handle_irq(IRQ_BASE_FPGA + irq);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* define an interrupt action for each FPGA PIC output
|
||||
* - use dev_id to indicate the FPGA PIC input to output mappings
|
||||
*/
|
||||
static struct irqaction fpga_irq[1] = {
|
||||
[0] = {
|
||||
.handler = fpga_interrupt,
|
||||
.name = "fpga.0",
|
||||
.dev_id = (void *) 0x0700UL,
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* initialise the motherboard FPGA's PIC
|
||||
*/
|
||||
void __init fpga_init(void)
|
||||
{
|
||||
int irq;
|
||||
|
||||
/* all PIC inputs are all set to be edge triggered */
|
||||
__set_IMR(0x0700);
|
||||
__clr_IFR(0x0000);
|
||||
|
||||
for (irq = IRQ_BASE_FPGA + 8; irq <= IRQ_BASE_FPGA + 10; irq++)
|
||||
irq_set_chip_and_handler(irq, &frv_fpga_pic, handle_edge_irq);
|
||||
|
||||
/* the FPGA drives external IRQ input #2 on the CPU PIC */
|
||||
setup_irq(IRQ_CPU_EXTERNAL2, &fpga_irq[0]);
|
||||
}
|
147
arch/frv/kernel/irq-mb93493.c
Normal file
147
arch/frv/kernel/irq-mb93493.c
Normal file
|
@ -0,0 +1,147 @@
|
|||
/* irq-mb93493.c: MB93493 companion chip interrupt handler
|
||||
*
|
||||
* Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/delay.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/irc-regs.h>
|
||||
#include <asm/mb93493-irqs.h>
|
||||
#include <asm/mb93493-regs.h>
|
||||
|
||||
#define IRQ_ROUTE_ONE(X) (X##_ROUTE << (X - IRQ_BASE_MB93493))
|
||||
|
||||
#define IRQ_ROUTING \
|
||||
(IRQ_ROUTE_ONE(IRQ_MB93493_VDC) | \
|
||||
IRQ_ROUTE_ONE(IRQ_MB93493_VCC) | \
|
||||
IRQ_ROUTE_ONE(IRQ_MB93493_AUDIO_OUT) | \
|
||||
IRQ_ROUTE_ONE(IRQ_MB93493_I2C_0) | \
|
||||
IRQ_ROUTE_ONE(IRQ_MB93493_I2C_1) | \
|
||||
IRQ_ROUTE_ONE(IRQ_MB93493_USB) | \
|
||||
IRQ_ROUTE_ONE(IRQ_MB93493_LOCAL_BUS) | \
|
||||
IRQ_ROUTE_ONE(IRQ_MB93493_PCMCIA) | \
|
||||
IRQ_ROUTE_ONE(IRQ_MB93493_GPIO) | \
|
||||
IRQ_ROUTE_ONE(IRQ_MB93493_AUDIO_IN))
|
||||
|
||||
/*
|
||||
* daughter board PIC operations
|
||||
* - there is no way to ACK interrupts in the MB93493 chip
|
||||
*/
|
||||
static void frv_mb93493_mask(struct irq_data *d)
|
||||
{
|
||||
uint32_t iqsr;
|
||||
volatile void *piqsr;
|
||||
|
||||
if (IRQ_ROUTING & (1 << (d->irq - IRQ_BASE_MB93493)))
|
||||
piqsr = __addr_MB93493_IQSR(1);
|
||||
else
|
||||
piqsr = __addr_MB93493_IQSR(0);
|
||||
|
||||
iqsr = readl(piqsr);
|
||||
iqsr &= ~(1 << (d->irq - IRQ_BASE_MB93493 + 16));
|
||||
writel(iqsr, piqsr);
|
||||
}
|
||||
|
||||
static void frv_mb93493_ack(struct irq_data *d)
|
||||
{
|
||||
}
|
||||
|
||||
static void frv_mb93493_unmask(struct irq_data *d)
|
||||
{
|
||||
uint32_t iqsr;
|
||||
volatile void *piqsr;
|
||||
|
||||
if (IRQ_ROUTING & (1 << (d->irq - IRQ_BASE_MB93493)))
|
||||
piqsr = __addr_MB93493_IQSR(1);
|
||||
else
|
||||
piqsr = __addr_MB93493_IQSR(0);
|
||||
|
||||
iqsr = readl(piqsr);
|
||||
iqsr |= 1 << (d->irq - IRQ_BASE_MB93493 + 16);
|
||||
writel(iqsr, piqsr);
|
||||
}
|
||||
|
||||
static struct irq_chip frv_mb93493_pic = {
|
||||
.name = "mb93093",
|
||||
.irq_ack = frv_mb93493_ack,
|
||||
.irq_mask = frv_mb93493_mask,
|
||||
.irq_mask_ack = frv_mb93493_mask,
|
||||
.irq_unmask = frv_mb93493_unmask,
|
||||
};
|
||||
|
||||
/*
|
||||
* MB93493 PIC interrupt handler
|
||||
*/
|
||||
static irqreturn_t mb93493_interrupt(int irq, void *_piqsr)
|
||||
{
|
||||
volatile void *piqsr = _piqsr;
|
||||
uint32_t iqsr;
|
||||
|
||||
iqsr = readl(piqsr);
|
||||
iqsr = iqsr & (iqsr >> 16) & 0xffff;
|
||||
|
||||
/* poll all the triggered IRQs */
|
||||
while (iqsr) {
|
||||
int irq;
|
||||
|
||||
asm("scan %1,gr0,%0" : "=r"(irq) : "r"(iqsr));
|
||||
irq = 31 - irq;
|
||||
iqsr &= ~(1 << irq);
|
||||
|
||||
generic_handle_irq(IRQ_BASE_MB93493 + irq);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* define an interrupt action for each MB93493 PIC output
|
||||
* - use dev_id to indicate the MB93493 PIC input to output mappings
|
||||
*/
|
||||
static struct irqaction mb93493_irq[2] = {
|
||||
[0] = {
|
||||
.handler = mb93493_interrupt,
|
||||
.flags = IRQF_SHARED,
|
||||
.name = "mb93493.0",
|
||||
.dev_id = (void *) __addr_MB93493_IQSR(0),
|
||||
},
|
||||
[1] = {
|
||||
.handler = mb93493_interrupt,
|
||||
.flags = IRQF_SHARED,
|
||||
.name = "mb93493.1",
|
||||
.dev_id = (void *) __addr_MB93493_IQSR(1),
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* initialise the motherboard MB93493's PIC
|
||||
*/
|
||||
void __init mb93493_init(void)
|
||||
{
|
||||
int irq;
|
||||
|
||||
for (irq = IRQ_BASE_MB93493 + 0; irq <= IRQ_BASE_MB93493 + 10; irq++)
|
||||
irq_set_chip_and_handler(irq, &frv_mb93493_pic,
|
||||
handle_edge_irq);
|
||||
|
||||
/* the MB93493 drives external IRQ inputs on the CPU PIC */
|
||||
setup_irq(IRQ_CPU_MB93493_0, &mb93493_irq[0]);
|
||||
setup_irq(IRQ_CPU_MB93493_1, &mb93493_irq[1]);
|
||||
}
|
159
arch/frv/kernel/irq.c
Normal file
159
arch/frv/kernel/irq.c
Normal file
|
@ -0,0 +1,159 @@
|
|||
/* irq.c: FRV IRQ handling
|
||||
*
|
||||
* Copyright (C) 2003, 2004, 2006 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/timex.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/smp.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/delay.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/irc-regs.h>
|
||||
#include <asm/gdb-stub.h>
|
||||
|
||||
#define set_IRR(N,A,B,C,D) __set_IRR(N, (A << 28) | (B << 24) | (C << 20) | (D << 16))
|
||||
|
||||
extern void __init fpga_init(void);
|
||||
#ifdef CONFIG_FUJITSU_MB93493
|
||||
extern void __init mb93493_init(void);
|
||||
#endif
|
||||
|
||||
#define __reg16(ADDR) (*(volatile unsigned short *)(ADDR))
|
||||
|
||||
atomic_t irq_err_count;
|
||||
|
||||
int arch_show_interrupts(struct seq_file *p, int prec)
|
||||
{
|
||||
seq_printf(p, "%*s: ", prec, "ERR");
|
||||
seq_printf(p, "%10u\n", atomic_read(&irq_err_count));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* on-CPU PIC operations
|
||||
*/
|
||||
static void frv_cpupic_ack(struct irq_data *d)
|
||||
{
|
||||
__clr_RC(d->irq);
|
||||
__clr_IRL();
|
||||
}
|
||||
|
||||
static void frv_cpupic_mask(struct irq_data *d)
|
||||
{
|
||||
__set_MASK(d->irq);
|
||||
}
|
||||
|
||||
static void frv_cpupic_mask_ack(struct irq_data *d)
|
||||
{
|
||||
__set_MASK(d->irq);
|
||||
__clr_RC(d->irq);
|
||||
__clr_IRL();
|
||||
}
|
||||
|
||||
static void frv_cpupic_unmask(struct irq_data *d)
|
||||
{
|
||||
__clr_MASK(d->irq);
|
||||
}
|
||||
|
||||
static struct irq_chip frv_cpu_pic = {
|
||||
.name = "cpu",
|
||||
.irq_ack = frv_cpupic_ack,
|
||||
.irq_mask = frv_cpupic_mask,
|
||||
.irq_mask_ack = frv_cpupic_mask_ack,
|
||||
.irq_unmask = frv_cpupic_unmask,
|
||||
};
|
||||
|
||||
/*
|
||||
* handles all normal device IRQs
|
||||
* - registers are referred to by the __frame variable (GR28)
|
||||
* - IRQ distribution is complicated in this arch because of the many PICs, the
|
||||
* way they work and the way they cascade
|
||||
*/
|
||||
asmlinkage void do_IRQ(void)
|
||||
{
|
||||
irq_enter();
|
||||
generic_handle_irq(__get_IRL());
|
||||
irq_exit();
|
||||
}
|
||||
|
||||
/*
|
||||
* handles all NMIs when not co-opted by the debugger
|
||||
* - registers are referred to by the __frame variable (GR28)
|
||||
*/
|
||||
asmlinkage void do_NMI(void)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* initialise the interrupt system
|
||||
*/
|
||||
void __init init_IRQ(void)
|
||||
{
|
||||
int level;
|
||||
|
||||
for (level = 1; level <= 14; level++)
|
||||
irq_set_chip_and_handler(level, &frv_cpu_pic,
|
||||
handle_level_irq);
|
||||
|
||||
irq_set_handler(IRQ_CPU_TIMER0, handle_edge_irq);
|
||||
|
||||
/* set the trigger levels for internal interrupt sources
|
||||
* - timers all falling-edge
|
||||
* - ERR0 is rising-edge
|
||||
* - all others are high-level
|
||||
*/
|
||||
__set_IITMR(0, 0x003f0000); /* DMA0-3, TIMER0-2 */
|
||||
__set_IITMR(1, 0x20000000); /* ERR0-1, UART0-1, DMA4-7 */
|
||||
|
||||
/* route internal interrupts */
|
||||
set_IRR(4, IRQ_DMA3_LEVEL, IRQ_DMA2_LEVEL, IRQ_DMA1_LEVEL,
|
||||
IRQ_DMA0_LEVEL);
|
||||
set_IRR(5, 0, IRQ_TIMER2_LEVEL, IRQ_TIMER1_LEVEL, IRQ_TIMER0_LEVEL);
|
||||
set_IRR(6, IRQ_GDBSTUB_LEVEL, IRQ_GDBSTUB_LEVEL,
|
||||
IRQ_UART1_LEVEL, IRQ_UART0_LEVEL);
|
||||
set_IRR(7, IRQ_DMA7_LEVEL, IRQ_DMA6_LEVEL, IRQ_DMA5_LEVEL,
|
||||
IRQ_DMA4_LEVEL);
|
||||
|
||||
/* route external interrupts */
|
||||
set_IRR(2, IRQ_XIRQ7_LEVEL, IRQ_XIRQ6_LEVEL, IRQ_XIRQ5_LEVEL,
|
||||
IRQ_XIRQ4_LEVEL);
|
||||
set_IRR(3, IRQ_XIRQ3_LEVEL, IRQ_XIRQ2_LEVEL, IRQ_XIRQ1_LEVEL,
|
||||
IRQ_XIRQ0_LEVEL);
|
||||
|
||||
#if defined(CONFIG_MB93091_VDK)
|
||||
__set_TM1(0x55550000); /* XIRQ7-0 all active low */
|
||||
#elif defined(CONFIG_MB93093_PDK)
|
||||
__set_TM1(0x15550000); /* XIRQ7 active high, 6-0 all active low */
|
||||
#else
|
||||
#error dont know external IRQ trigger levels for this setup
|
||||
#endif
|
||||
|
||||
fpga_init();
|
||||
#ifdef CONFIG_FUJITSU_MB93493
|
||||
mb93493_init();
|
||||
#endif
|
||||
}
|
59
arch/frv/kernel/local.h
Normal file
59
arch/frv/kernel/local.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/* local.h: local definitions
|
||||
*
|
||||
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _FRV_LOCAL_H
|
||||
#define _FRV_LOCAL_H
|
||||
|
||||
#include <asm/sections.h>
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
/* dma.c */
|
||||
extern unsigned long frv_dma_inprogress;
|
||||
|
||||
extern void frv_dma_pause_all(void);
|
||||
extern void frv_dma_resume_all(void);
|
||||
|
||||
/* sleep.S */
|
||||
extern asmlinkage void frv_cpu_suspend(unsigned long);
|
||||
extern asmlinkage void frv_cpu_core_sleep(void);
|
||||
|
||||
/* setup.c */
|
||||
extern unsigned long __nongprelbss pdm_suspend_mode;
|
||||
extern void determine_clocks(int verbose);
|
||||
extern int __nongprelbss clock_p0_current;
|
||||
extern int __nongprelbss clock_cm_current;
|
||||
extern int __nongprelbss clock_cmode_current;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
extern int __nongprelbss clock_cmodes_permitted;
|
||||
extern unsigned long __nongprelbss clock_bits_settable;
|
||||
#define CLOCK_BIT_CM 0x0000000f
|
||||
#define CLOCK_BIT_CM_H 0x00000001 /* CLKC.CM can be set to 0 */
|
||||
#define CLOCK_BIT_CM_M 0x00000002 /* CLKC.CM can be set to 1 */
|
||||
#define CLOCK_BIT_CM_L 0x00000004 /* CLKC.CM can be set to 2 */
|
||||
#define CLOCK_BIT_P0 0x00000010 /* CLKC.P0 can be changed */
|
||||
#define CLOCK_BIT_CMODE 0x00000020 /* CLKC.CMODE can be changed */
|
||||
|
||||
extern void (*__power_switch_wake_setup)(void);
|
||||
extern int (*__power_switch_wake_check)(void);
|
||||
extern void (*__power_switch_wake_cleanup)(void);
|
||||
#endif
|
||||
|
||||
/* time.c */
|
||||
extern void time_divisor_init(void);
|
||||
|
||||
/* cmode.S */
|
||||
extern asmlinkage void frv_change_cmode(int);
|
||||
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* _FRV_LOCAL_H */
|
1
arch/frv/kernel/local64.h
Normal file
1
arch/frv/kernel/local64.h
Normal file
|
@ -0,0 +1 @@
|
|||
#include <asm-generic/local64.h>
|
27
arch/frv/kernel/module.c
Normal file
27
arch/frv/kernel/module.c
Normal file
|
@ -0,0 +1,27 @@
|
|||
/* module.c: FRV specific module loading bits
|
||||
*
|
||||
* Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
* - Derived from arch/i386/kernel/module.c, Copyright (C) 2001 Rusty Russell.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
#include <linux/moduleloader.h>
|
||||
#include <linux/elf.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#if 0
|
||||
#define DEBUGP printk
|
||||
#else
|
||||
#define DEBUGP(fmt...)
|
||||
#endif
|
||||
|
||||
/* TODO: At least one of apply_relocate or apply_relocate_add must be
|
||||
* implemented in order to get working module support.
|
||||
*/
|
65
arch/frv/kernel/pm-mb93093.c
Normal file
65
arch/frv/kernel/pm-mb93093.c
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* FR-V MB93093 Power Management Routines
|
||||
*
|
||||
* Copyright (c) 2004 Red Hat, Inc.
|
||||
*
|
||||
* Written by: msalter@redhat.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include <asm/mb86943a.h>
|
||||
|
||||
#include "local.h"
|
||||
|
||||
static unsigned long imask;
|
||||
/*
|
||||
* Setup interrupt masks, etc to enable wakeup by power switch
|
||||
*/
|
||||
static void mb93093_power_switch_setup(void)
|
||||
{
|
||||
/* mask all but FPGA interrupt sources. */
|
||||
imask = *(volatile unsigned long *)0xfeff9820;
|
||||
*(volatile unsigned long *)0xfeff9820 = ~(1 << (IRQ_XIRQ2_LEVEL + 16)) & 0xfffe0000;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup interrupt masks, etc after wakeup by power switch
|
||||
*/
|
||||
static void mb93093_power_switch_cleanup(void)
|
||||
{
|
||||
*(volatile unsigned long *)0xfeff9820 = imask;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return non-zero if wakeup irq was caused by power switch
|
||||
*/
|
||||
static int mb93093_power_switch_check(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize power interface
|
||||
*/
|
||||
static int __init mb93093_pm_init(void)
|
||||
{
|
||||
__power_switch_wake_setup = mb93093_power_switch_setup;
|
||||
__power_switch_wake_check = mb93093_power_switch_check;
|
||||
__power_switch_wake_cleanup = mb93093_power_switch_cleanup;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__initcall(mb93093_pm_init);
|
||||
|
352
arch/frv/kernel/pm.c
Normal file
352
arch/frv/kernel/pm.c
Normal file
|
@ -0,0 +1,352 @@
|
|||
/*
|
||||
* FR-V Power Management Routines
|
||||
*
|
||||
* Copyright (c) 2004 Red Hat, Inc.
|
||||
*
|
||||
* Based on SA1100 version:
|
||||
* Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include <asm/mb86943a.h>
|
||||
|
||||
#include "local.h"
|
||||
|
||||
/*
|
||||
* Debug macros
|
||||
*/
|
||||
#define DEBUG
|
||||
|
||||
int pm_do_suspend(void)
|
||||
{
|
||||
local_irq_disable();
|
||||
|
||||
__set_LEDS(0xb1);
|
||||
|
||||
/* go zzz */
|
||||
frv_cpu_suspend(pdm_suspend_mode);
|
||||
|
||||
__set_LEDS(0xb2);
|
||||
|
||||
local_irq_enable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long __irq_mask;
|
||||
|
||||
/*
|
||||
* Setup interrupt masks, etc to enable wakeup by power switch
|
||||
*/
|
||||
static void __default_power_switch_setup(void)
|
||||
{
|
||||
/* default is to mask all interrupt sources. */
|
||||
__irq_mask = *(unsigned long *)0xfeff9820;
|
||||
*(unsigned long *)0xfeff9820 = 0xfffe0000;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup interrupt masks, etc after wakeup by power switch
|
||||
*/
|
||||
static void __default_power_switch_cleanup(void)
|
||||
{
|
||||
*(unsigned long *)0xfeff9820 = __irq_mask;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return non-zero if wakeup irq was caused by power switch
|
||||
*/
|
||||
static int __default_power_switch_check(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void (*__power_switch_wake_setup)(void) = __default_power_switch_setup;
|
||||
int (*__power_switch_wake_check)(void) = __default_power_switch_check;
|
||||
void (*__power_switch_wake_cleanup)(void) = __default_power_switch_cleanup;
|
||||
|
||||
int pm_do_bus_sleep(void)
|
||||
{
|
||||
local_irq_disable();
|
||||
|
||||
/*
|
||||
* Here is where we need some platform-dependent setup
|
||||
* of the interrupt state so that appropriate wakeup
|
||||
* sources are allowed and all others are masked.
|
||||
*/
|
||||
__power_switch_wake_setup();
|
||||
|
||||
__set_LEDS(0xa1);
|
||||
|
||||
/* go zzz
|
||||
*
|
||||
* This is in a loop in case power switch shares an irq with other
|
||||
* devices. The wake_check() tells us if we need to finish waking
|
||||
* or go back to sleep.
|
||||
*/
|
||||
do {
|
||||
frv_cpu_suspend(HSR0_PDM_BUS_SLEEP);
|
||||
} while (__power_switch_wake_check && !__power_switch_wake_check());
|
||||
|
||||
__set_LEDS(0xa2);
|
||||
|
||||
/*
|
||||
* Here is where we need some platform-dependent restore
|
||||
* of the interrupt state prior to being called.
|
||||
*/
|
||||
__power_switch_wake_cleanup();
|
||||
|
||||
local_irq_enable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long sleep_phys_sp(void *sp)
|
||||
{
|
||||
return virt_to_phys(sp);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
/*
|
||||
* Use a temporary sysctl number. Horrid, but will be cleaned up in 2.6
|
||||
* when all the PM interfaces exist nicely.
|
||||
*/
|
||||
#define CTL_PM_SUSPEND 1
|
||||
#define CTL_PM_CMODE 2
|
||||
#define CTL_PM_P0 4
|
||||
#define CTL_PM_CM 5
|
||||
|
||||
static int user_atoi(char __user *ubuf, size_t len)
|
||||
{
|
||||
char buf[16];
|
||||
unsigned long ret;
|
||||
|
||||
if (len > 15)
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(buf, ubuf, len))
|
||||
return -EFAULT;
|
||||
|
||||
buf[len] = 0;
|
||||
ret = simple_strtoul(buf, NULL, 0);
|
||||
if (ret > INT_MAX)
|
||||
return -ERANGE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send us to sleep.
|
||||
*/
|
||||
static int sysctl_pm_do_suspend(struct ctl_table *ctl, int write,
|
||||
void __user *buffer, size_t *lenp, loff_t *fpos)
|
||||
{
|
||||
int mode;
|
||||
|
||||
if (*lenp <= 0)
|
||||
return -EIO;
|
||||
|
||||
mode = user_atoi(buffer, *lenp);
|
||||
switch (mode) {
|
||||
case 1:
|
||||
return pm_do_suspend();
|
||||
|
||||
case 5:
|
||||
return pm_do_bus_sleep();
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int try_set_cmode(int new_cmode)
|
||||
{
|
||||
if (new_cmode > 15)
|
||||
return -EINVAL;
|
||||
if (!(clock_cmodes_permitted & (1<<new_cmode)))
|
||||
return -EINVAL;
|
||||
|
||||
/* now change cmode */
|
||||
local_irq_disable();
|
||||
frv_dma_pause_all();
|
||||
|
||||
frv_change_cmode(new_cmode);
|
||||
|
||||
determine_clocks(0);
|
||||
time_divisor_init();
|
||||
|
||||
#ifdef DEBUG
|
||||
determine_clocks(1);
|
||||
#endif
|
||||
frv_dma_resume_all();
|
||||
local_irq_enable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int cmode_procctl(struct ctl_table *ctl, int write,
|
||||
void __user *buffer, size_t *lenp, loff_t *fpos)
|
||||
{
|
||||
int new_cmode;
|
||||
|
||||
if (!write)
|
||||
return proc_dointvec(ctl, write, buffer, lenp, fpos);
|
||||
|
||||
new_cmode = user_atoi(buffer, *lenp);
|
||||
|
||||
return try_set_cmode(new_cmode)?:*lenp;
|
||||
}
|
||||
|
||||
static int try_set_p0(int new_p0)
|
||||
{
|
||||
unsigned long flags, clkc;
|
||||
|
||||
if (new_p0 < 0 || new_p0 > 1)
|
||||
return -EINVAL;
|
||||
|
||||
local_irq_save(flags);
|
||||
__set_PSR(flags & ~PSR_ET);
|
||||
|
||||
frv_dma_pause_all();
|
||||
|
||||
clkc = __get_CLKC();
|
||||
if (new_p0)
|
||||
clkc |= CLKC_P0;
|
||||
else
|
||||
clkc &= ~CLKC_P0;
|
||||
__set_CLKC(clkc);
|
||||
|
||||
determine_clocks(0);
|
||||
time_divisor_init();
|
||||
|
||||
#ifdef DEBUG
|
||||
determine_clocks(1);
|
||||
#endif
|
||||
frv_dma_resume_all();
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int try_set_cm(int new_cm)
|
||||
{
|
||||
unsigned long flags, clkc;
|
||||
|
||||
if (new_cm < 0 || new_cm > 1)
|
||||
return -EINVAL;
|
||||
|
||||
local_irq_save(flags);
|
||||
__set_PSR(flags & ~PSR_ET);
|
||||
|
||||
frv_dma_pause_all();
|
||||
|
||||
clkc = __get_CLKC();
|
||||
clkc &= ~CLKC_CM;
|
||||
clkc |= new_cm;
|
||||
__set_CLKC(clkc);
|
||||
|
||||
determine_clocks(0);
|
||||
time_divisor_init();
|
||||
|
||||
#if 1 //def DEBUG
|
||||
determine_clocks(1);
|
||||
#endif
|
||||
|
||||
frv_dma_resume_all();
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p0_procctl(struct ctl_table *ctl, int write,
|
||||
void __user *buffer, size_t *lenp, loff_t *fpos)
|
||||
{
|
||||
int new_p0;
|
||||
|
||||
if (!write)
|
||||
return proc_dointvec(ctl, write, buffer, lenp, fpos);
|
||||
|
||||
new_p0 = user_atoi(buffer, *lenp);
|
||||
|
||||
return try_set_p0(new_p0)?:*lenp;
|
||||
}
|
||||
|
||||
static int cm_procctl(struct ctl_table *ctl, int write,
|
||||
void __user *buffer, size_t *lenp, loff_t *fpos)
|
||||
{
|
||||
int new_cm;
|
||||
|
||||
if (!write)
|
||||
return proc_dointvec(ctl, write, buffer, lenp, fpos);
|
||||
|
||||
new_cm = user_atoi(buffer, *lenp);
|
||||
|
||||
return try_set_cm(new_cm)?:*lenp;
|
||||
}
|
||||
|
||||
static struct ctl_table pm_table[] =
|
||||
{
|
||||
{
|
||||
.procname = "suspend",
|
||||
.data = NULL,
|
||||
.maxlen = 0,
|
||||
.mode = 0200,
|
||||
.proc_handler = sysctl_pm_do_suspend,
|
||||
},
|
||||
{
|
||||
.procname = "cmode",
|
||||
.data = &clock_cmode_current,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = cmode_procctl,
|
||||
},
|
||||
{
|
||||
.procname = "p0",
|
||||
.data = &clock_p0_current,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = p0_procctl,
|
||||
},
|
||||
{
|
||||
.procname = "cm",
|
||||
.data = &clock_cm_current,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = cm_procctl,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct ctl_table pm_dir_table[] =
|
||||
{
|
||||
{
|
||||
.procname = "pm",
|
||||
.mode = 0555,
|
||||
.child = pm_table,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize power interface
|
||||
*/
|
||||
static int __init pm_init(void)
|
||||
{
|
||||
register_sysctl_table(pm_dir_table);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__initcall(pm_init);
|
||||
|
||||
#endif
|
281
arch/frv/kernel/process.c
Normal file
281
arch/frv/kernel/process.c
Normal file
|
@ -0,0 +1,281 @@
|
|||
/* process.c: FRV specific parts of process handling
|
||||
*
|
||||
* Copyright (C) 2003-5 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
* - Derived from arch/m68k/kernel/process.c
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/user.h>
|
||||
#include <linux/elf.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/rcupdate.h>
|
||||
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/tlb.h>
|
||||
#include <asm/gdb-stub.h>
|
||||
#include <asm/mb-regs.h>
|
||||
|
||||
#include "local.h"
|
||||
|
||||
asmlinkage void ret_from_fork(void);
|
||||
asmlinkage void ret_from_kernel_thread(void);
|
||||
|
||||
#include <asm/pgalloc.h>
|
||||
|
||||
void (*pm_power_off)(void);
|
||||
EXPORT_SYMBOL(pm_power_off);
|
||||
|
||||
static void core_sleep_idle(void)
|
||||
{
|
||||
#ifdef LED_DEBUG_SLEEP
|
||||
/* Show that we're sleeping... */
|
||||
__set_LEDS(0x55aa);
|
||||
#endif
|
||||
frv_cpu_core_sleep();
|
||||
#ifdef LED_DEBUG_SLEEP
|
||||
/* ... and that we woke up */
|
||||
__set_LEDS(0);
|
||||
#endif
|
||||
mb();
|
||||
}
|
||||
|
||||
void arch_cpu_idle(void)
|
||||
{
|
||||
if (!frv_dma_inprogress)
|
||||
core_sleep_idle();
|
||||
else
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
void machine_restart(char * __unused)
|
||||
{
|
||||
unsigned long reset_addr;
|
||||
#ifdef CONFIG_GDBSTUB
|
||||
gdbstub_exit(0);
|
||||
#endif
|
||||
|
||||
if (PSR_IMPLE(__get_PSR()) == PSR_IMPLE_FR551)
|
||||
reset_addr = 0xfefff500;
|
||||
else
|
||||
reset_addr = 0xfeff0500;
|
||||
|
||||
/* Software reset. */
|
||||
asm volatile(" dcef @(gr0,gr0),1 ! membar !"
|
||||
" sti %1,@(%0,0) !"
|
||||
" nop ! nop ! nop ! nop ! nop ! "
|
||||
" nop ! nop ! nop ! nop ! nop ! "
|
||||
" nop ! nop ! nop ! nop ! nop ! "
|
||||
" nop ! nop ! nop ! nop ! nop ! "
|
||||
: : "r" (reset_addr), "r" (1) );
|
||||
|
||||
for (;;)
|
||||
;
|
||||
}
|
||||
|
||||
void machine_halt(void)
|
||||
{
|
||||
#ifdef CONFIG_GDBSTUB
|
||||
gdbstub_exit(0);
|
||||
#endif
|
||||
|
||||
for (;;);
|
||||
}
|
||||
|
||||
void machine_power_off(void)
|
||||
{
|
||||
#ifdef CONFIG_GDBSTUB
|
||||
gdbstub_exit(0);
|
||||
#endif
|
||||
|
||||
for (;;);
|
||||
}
|
||||
|
||||
void flush_thread(void)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
inline unsigned long user_stack(const struct pt_regs *regs)
|
||||
{
|
||||
while (regs->next_frame)
|
||||
regs = regs->next_frame;
|
||||
return user_mode(regs) ? regs->sp : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* set up the kernel stack and exception frames for a new process
|
||||
*/
|
||||
int copy_thread(unsigned long clone_flags,
|
||||
unsigned long usp, unsigned long arg,
|
||||
struct task_struct *p)
|
||||
{
|
||||
struct pt_regs *childregs;
|
||||
|
||||
childregs = (struct pt_regs *)
|
||||
(task_stack_page(p) + THREAD_SIZE - FRV_FRAME0_SIZE);
|
||||
|
||||
/* set up the userspace frame (the only place that the USP is stored) */
|
||||
*childregs = *current_pt_regs();
|
||||
|
||||
p->thread.frame = childregs;
|
||||
p->thread.curr = p;
|
||||
p->thread.sp = (unsigned long) childregs;
|
||||
p->thread.fp = 0;
|
||||
p->thread.lr = 0;
|
||||
p->thread.frame0 = childregs;
|
||||
|
||||
if (unlikely(p->flags & PF_KTHREAD)) {
|
||||
childregs->gr9 = usp; /* function */
|
||||
childregs->gr8 = arg;
|
||||
p->thread.pc = (unsigned long) ret_from_kernel_thread;
|
||||
save_user_regs(p->thread.user);
|
||||
return 0;
|
||||
}
|
||||
if (usp)
|
||||
childregs->sp = usp;
|
||||
childregs->next_frame = NULL;
|
||||
|
||||
p->thread.pc = (unsigned long) ret_from_fork;
|
||||
|
||||
/* the new TLS pointer is passed in as arg #5 to sys_clone() */
|
||||
if (clone_flags & CLONE_SETTLS)
|
||||
childregs->gr29 = childregs->gr12;
|
||||
|
||||
save_user_regs(p->thread.user);
|
||||
|
||||
return 0;
|
||||
} /* end copy_thread() */
|
||||
|
||||
unsigned long get_wchan(struct task_struct *p)
|
||||
{
|
||||
struct pt_regs *regs0;
|
||||
unsigned long fp, pc;
|
||||
unsigned long stack_limit;
|
||||
int count = 0;
|
||||
if (!p || p == current || p->state == TASK_RUNNING)
|
||||
return 0;
|
||||
|
||||
stack_limit = (unsigned long) (p + 1);
|
||||
fp = p->thread.fp;
|
||||
regs0 = p->thread.frame0;
|
||||
|
||||
do {
|
||||
if (fp < stack_limit || fp >= (unsigned long) regs0 || fp & 3)
|
||||
return 0;
|
||||
|
||||
pc = ((unsigned long *) fp)[2];
|
||||
|
||||
/* FIXME: This depends on the order of these functions. */
|
||||
if (!in_sched_functions(pc))
|
||||
return pc;
|
||||
|
||||
fp = *(unsigned long *) fp;
|
||||
} while (count++ < 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long thread_saved_pc(struct task_struct *tsk)
|
||||
{
|
||||
/* Check whether the thread is blocked in resume() */
|
||||
if (in_sched_functions(tsk->thread.pc))
|
||||
return ((unsigned long *)tsk->thread.fp)[2];
|
||||
else
|
||||
return tsk->thread.pc;
|
||||
}
|
||||
|
||||
int elf_check_arch(const struct elf32_hdr *hdr)
|
||||
{
|
||||
unsigned long hsr0 = __get_HSR(0);
|
||||
unsigned long psr = __get_PSR();
|
||||
|
||||
if (hdr->e_machine != EM_FRV)
|
||||
return 0;
|
||||
|
||||
switch (hdr->e_flags & EF_FRV_GPR_MASK) {
|
||||
case EF_FRV_GPR64:
|
||||
if ((hsr0 & HSR0_GRN) == HSR0_GRN_32)
|
||||
return 0;
|
||||
case EF_FRV_GPR32:
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (hdr->e_flags & EF_FRV_FPR_MASK) {
|
||||
case EF_FRV_FPR64:
|
||||
if ((hsr0 & HSR0_FRN) == HSR0_FRN_32)
|
||||
return 0;
|
||||
case EF_FRV_FPR32:
|
||||
case EF_FRV_FPR_NONE:
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((hdr->e_flags & EF_FRV_MULADD) == EF_FRV_MULADD)
|
||||
if (PSR_IMPLE(psr) != PSR_IMPLE_FR405 &&
|
||||
PSR_IMPLE(psr) != PSR_IMPLE_FR451)
|
||||
return 0;
|
||||
|
||||
switch (hdr->e_flags & EF_FRV_CPU_MASK) {
|
||||
case EF_FRV_CPU_GENERIC:
|
||||
break;
|
||||
case EF_FRV_CPU_FR300:
|
||||
case EF_FRV_CPU_SIMPLE:
|
||||
case EF_FRV_CPU_TOMCAT:
|
||||
default:
|
||||
return 0;
|
||||
case EF_FRV_CPU_FR400:
|
||||
if (PSR_IMPLE(psr) != PSR_IMPLE_FR401 &&
|
||||
PSR_IMPLE(psr) != PSR_IMPLE_FR405 &&
|
||||
PSR_IMPLE(psr) != PSR_IMPLE_FR451 &&
|
||||
PSR_IMPLE(psr) != PSR_IMPLE_FR551)
|
||||
return 0;
|
||||
break;
|
||||
case EF_FRV_CPU_FR450:
|
||||
if (PSR_IMPLE(psr) != PSR_IMPLE_FR451)
|
||||
return 0;
|
||||
break;
|
||||
case EF_FRV_CPU_FR500:
|
||||
if (PSR_IMPLE(psr) != PSR_IMPLE_FR501)
|
||||
return 0;
|
||||
break;
|
||||
case EF_FRV_CPU_FR550:
|
||||
if (PSR_IMPLE(psr) != PSR_IMPLE_FR551)
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
|
||||
{
|
||||
memcpy(fpregs,
|
||||
¤t->thread.user->f,
|
||||
sizeof(current->thread.user->f));
|
||||
return 1;
|
||||
}
|
377
arch/frv/kernel/ptrace.c
Normal file
377
arch/frv/kernel/ptrace.c
Normal file
|
@ -0,0 +1,377 @@
|
|||
/* ptrace.c: FRV specific parts of process tracing
|
||||
*
|
||||
* Copyright (C) 2003-5 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
* - Derived from arch/m68k/kernel/ptrace.c
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/user.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/regset.h>
|
||||
#include <linux/elf.h>
|
||||
#include <linux/tracehook.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
/*
|
||||
* does not yet catch signals sent when the child dies.
|
||||
* in exit.c or in signal.c.
|
||||
*/
|
||||
|
||||
/*
|
||||
* retrieve the contents of FRV userspace general registers
|
||||
*/
|
||||
static int genregs_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
{
|
||||
const struct user_int_regs *iregs = &target->thread.user->i;
|
||||
int ret;
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
iregs, 0, sizeof(*iregs));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
sizeof(*iregs), -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* update the contents of the FRV userspace general registers
|
||||
*/
|
||||
static int genregs_set(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf)
|
||||
{
|
||||
struct user_int_regs *iregs = &target->thread.user->i;
|
||||
unsigned int offs_gr0, offs_gr1;
|
||||
int ret;
|
||||
|
||||
/* not allowed to set PSR or __status */
|
||||
if (pos < offsetof(struct user_int_regs, psr) + sizeof(long) &&
|
||||
pos + count > offsetof(struct user_int_regs, psr))
|
||||
return -EIO;
|
||||
|
||||
if (pos < offsetof(struct user_int_regs, __status) + sizeof(long) &&
|
||||
pos + count > offsetof(struct user_int_regs, __status))
|
||||
return -EIO;
|
||||
|
||||
/* set the control regs */
|
||||
offs_gr0 = offsetof(struct user_int_regs, gr[0]);
|
||||
offs_gr1 = offsetof(struct user_int_regs, gr[1]);
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
iregs, 0, offs_gr0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* skip GR0/TBR */
|
||||
ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
|
||||
offs_gr0, offs_gr1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* set the general regs */
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
&iregs->gr[1], offs_gr1, sizeof(*iregs));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
|
||||
sizeof(*iregs), -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* retrieve the contents of FRV userspace FP/Media registers
|
||||
*/
|
||||
static int fpmregs_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
{
|
||||
const struct user_fpmedia_regs *fpregs = &target->thread.user->f;
|
||||
int ret;
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
fpregs, 0, sizeof(*fpregs));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
sizeof(*fpregs), -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* update the contents of the FRV userspace FP/Media registers
|
||||
*/
|
||||
static int fpmregs_set(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf)
|
||||
{
|
||||
struct user_fpmedia_regs *fpregs = &target->thread.user->f;
|
||||
int ret;
|
||||
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
fpregs, 0, sizeof(*fpregs));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
|
||||
sizeof(*fpregs), -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* determine if the FP/Media registers have actually been used
|
||||
*/
|
||||
static int fpmregs_active(struct task_struct *target,
|
||||
const struct user_regset *regset)
|
||||
{
|
||||
return tsk_used_math(target) ? regset->n : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Define the register sets available on the FRV under Linux
|
||||
*/
|
||||
enum frv_regset {
|
||||
REGSET_GENERAL,
|
||||
REGSET_FPMEDIA,
|
||||
};
|
||||
|
||||
static const struct user_regset frv_regsets[] = {
|
||||
/*
|
||||
* General register format is:
|
||||
* PSR, ISR, CCR, CCCR, LR, LCR, PC, (STATUS), SYSCALLNO, ORIG_G8
|
||||
* GNER0-1, IACC0, TBR, GR1-63
|
||||
*/
|
||||
[REGSET_GENERAL] = {
|
||||
.core_note_type = NT_PRSTATUS,
|
||||
.n = ELF_NGREG,
|
||||
.size = sizeof(long),
|
||||
.align = sizeof(long),
|
||||
.get = genregs_get,
|
||||
.set = genregs_set,
|
||||
},
|
||||
/*
|
||||
* FPU/Media register format is:
|
||||
* FR0-63, FNER0-1, MSR0-1, ACC0-7, ACCG0-8, FSR
|
||||
*/
|
||||
[REGSET_FPMEDIA] = {
|
||||
.core_note_type = NT_PRFPREG,
|
||||
.n = sizeof(struct user_fpmedia_regs) / sizeof(long),
|
||||
.size = sizeof(long),
|
||||
.align = sizeof(long),
|
||||
.get = fpmregs_get,
|
||||
.set = fpmregs_set,
|
||||
.active = fpmregs_active,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct user_regset_view user_frv_native_view = {
|
||||
.name = "frv",
|
||||
.e_machine = EM_FRV,
|
||||
.regsets = frv_regsets,
|
||||
.n = ARRAY_SIZE(frv_regsets),
|
||||
};
|
||||
|
||||
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
|
||||
{
|
||||
return &user_frv_native_view;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get contents of register REGNO in task TASK.
|
||||
*/
|
||||
static inline long get_reg(struct task_struct *task, int regno)
|
||||
{
|
||||
struct user_context *user = task->thread.user;
|
||||
|
||||
if (regno < 0 || regno >= PT__END)
|
||||
return 0;
|
||||
|
||||
return ((unsigned long *) user)[regno];
|
||||
}
|
||||
|
||||
/*
|
||||
* Write contents of register REGNO in task TASK.
|
||||
*/
|
||||
static inline int put_reg(struct task_struct *task, int regno,
|
||||
unsigned long data)
|
||||
{
|
||||
struct user_context *user = task->thread.user;
|
||||
|
||||
if (regno < 0 || regno >= PT__END)
|
||||
return -EIO;
|
||||
|
||||
switch (regno) {
|
||||
case PT_GR(0):
|
||||
return 0;
|
||||
case PT_PSR:
|
||||
case PT__STATUS:
|
||||
return -EIO;
|
||||
default:
|
||||
((unsigned long *) user)[regno] = data;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Called by kernel/ptrace.c when detaching..
|
||||
*
|
||||
* Control h/w single stepping
|
||||
*/
|
||||
void user_enable_single_step(struct task_struct *child)
|
||||
{
|
||||
child->thread.frame0->__status |= REG__STATUS_STEP;
|
||||
}
|
||||
|
||||
void user_disable_single_step(struct task_struct *child)
|
||||
{
|
||||
child->thread.frame0->__status &= ~REG__STATUS_STEP;
|
||||
}
|
||||
|
||||
void ptrace_disable(struct task_struct *child)
|
||||
{
|
||||
user_disable_single_step(child);
|
||||
}
|
||||
|
||||
long arch_ptrace(struct task_struct *child, long request,
|
||||
unsigned long addr, unsigned long data)
|
||||
{
|
||||
unsigned long tmp;
|
||||
int ret;
|
||||
int regno = addr >> 2;
|
||||
unsigned long __user *datap = (unsigned long __user *) data;
|
||||
|
||||
switch (request) {
|
||||
/* read the word at location addr in the USER area. */
|
||||
case PTRACE_PEEKUSR: {
|
||||
tmp = 0;
|
||||
ret = -EIO;
|
||||
if (addr & 3)
|
||||
break;
|
||||
|
||||
ret = 0;
|
||||
switch (regno) {
|
||||
case 0 ... PT__END - 1:
|
||||
tmp = get_reg(child, regno);
|
||||
break;
|
||||
|
||||
case PT__END + 0:
|
||||
tmp = child->mm->end_code - child->mm->start_code;
|
||||
break;
|
||||
|
||||
case PT__END + 1:
|
||||
tmp = child->mm->end_data - child->mm->start_data;
|
||||
break;
|
||||
|
||||
case PT__END + 2:
|
||||
tmp = child->mm->start_stack - child->mm->start_brk;
|
||||
break;
|
||||
|
||||
case PT__END + 3:
|
||||
tmp = child->mm->start_code;
|
||||
break;
|
||||
|
||||
case PT__END + 4:
|
||||
tmp = child->mm->start_stack;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
ret = put_user(tmp, datap);
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
|
||||
ret = -EIO;
|
||||
if (addr & 3)
|
||||
break;
|
||||
|
||||
switch (regno) {
|
||||
case 0 ... PT__END - 1:
|
||||
ret = put_reg(child, regno, data);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case PTRACE_GETREGS: /* Get all integer regs from the child. */
|
||||
return copy_regset_to_user(child, &user_frv_native_view,
|
||||
REGSET_GENERAL,
|
||||
0, sizeof(child->thread.user->i),
|
||||
datap);
|
||||
|
||||
case PTRACE_SETREGS: /* Set all integer regs in the child. */
|
||||
return copy_regset_from_user(child, &user_frv_native_view,
|
||||
REGSET_GENERAL,
|
||||
0, sizeof(child->thread.user->i),
|
||||
datap);
|
||||
|
||||
case PTRACE_GETFPREGS: /* Get the child FP/Media state. */
|
||||
return copy_regset_to_user(child, &user_frv_native_view,
|
||||
REGSET_FPMEDIA,
|
||||
0, sizeof(child->thread.user->f),
|
||||
datap);
|
||||
|
||||
case PTRACE_SETFPREGS: /* Set the child FP/Media state. */
|
||||
return copy_regset_from_user(child, &user_frv_native_view,
|
||||
REGSET_FPMEDIA,
|
||||
0, sizeof(child->thread.user->f),
|
||||
datap);
|
||||
|
||||
default:
|
||||
ret = ptrace_request(child, request, addr, data);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* handle tracing of system call entry
|
||||
* - return the revised system call number or ULONG_MAX to cause ENOSYS
|
||||
*/
|
||||
asmlinkage unsigned long syscall_trace_entry(void)
|
||||
{
|
||||
__frame->__status |= REG__STATUS_SYSC_ENTRY;
|
||||
if (tracehook_report_syscall_entry(__frame)) {
|
||||
/* tracing decided this syscall should not happen, so
|
||||
* We'll return a bogus call number to get an ENOSYS
|
||||
* error, but leave the original number in
|
||||
* __frame->syscallno
|
||||
*/
|
||||
return ULONG_MAX;
|
||||
}
|
||||
|
||||
return __frame->syscallno;
|
||||
}
|
||||
|
||||
/*
|
||||
* handle tracing of system call exit
|
||||
*/
|
||||
asmlinkage void syscall_trace_exit(void)
|
||||
{
|
||||
__frame->__status |= REG__STATUS_SYSC_EXIT;
|
||||
tracehook_report_syscall_exit(__frame, 0);
|
||||
}
|
1178
arch/frv/kernel/setup.c
Normal file
1178
arch/frv/kernel/setup.c
Normal file
File diff suppressed because it is too large
Load diff
442
arch/frv/kernel/signal.c
Normal file
442
arch/frv/kernel/signal.c
Normal file
|
@ -0,0 +1,442 @@
|
|||
/* signal.c: FRV specific bits of signal handling
|
||||
*
|
||||
* Copyright (C) 2003-5 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
* - Derived from arch/m68k/kernel/signal.c
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <linux/personality.h>
|
||||
#include <linux/tracehook.h>
|
||||
#include <asm/ucontext.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
#define DEBUG_SIG 0
|
||||
|
||||
struct fdpic_func_descriptor {
|
||||
unsigned long text;
|
||||
unsigned long GOT;
|
||||
};
|
||||
|
||||
/*
|
||||
* Do a signal return; undo the signal stack.
|
||||
*/
|
||||
|
||||
struct sigframe
|
||||
{
|
||||
__sigrestore_t pretcode;
|
||||
int sig;
|
||||
struct sigcontext sc;
|
||||
unsigned long extramask[_NSIG_WORDS-1];
|
||||
uint32_t retcode[2];
|
||||
};
|
||||
|
||||
struct rt_sigframe
|
||||
{
|
||||
__sigrestore_t pretcode;
|
||||
int sig;
|
||||
struct siginfo __user *pinfo;
|
||||
void __user *puc;
|
||||
struct siginfo info;
|
||||
struct ucontext uc;
|
||||
uint32_t retcode[2];
|
||||
};
|
||||
|
||||
static int restore_sigcontext(struct sigcontext __user *sc, int *_gr8)
|
||||
{
|
||||
struct user_context *user = current->thread.user;
|
||||
unsigned long tbr, psr;
|
||||
|
||||
/* Always make any pending restarted system calls return -EINTR */
|
||||
current_thread_info()->restart_block.fn = do_no_restart_syscall;
|
||||
|
||||
tbr = user->i.tbr;
|
||||
psr = user->i.psr;
|
||||
if (copy_from_user(user, &sc->sc_context, sizeof(sc->sc_context)))
|
||||
goto badframe;
|
||||
user->i.tbr = tbr;
|
||||
user->i.psr = psr;
|
||||
|
||||
restore_user_regs(user);
|
||||
|
||||
user->i.syscallno = -1; /* disable syscall checks */
|
||||
|
||||
*_gr8 = user->i.gr[8];
|
||||
return 0;
|
||||
|
||||
badframe:
|
||||
return 1;
|
||||
}
|
||||
|
||||
asmlinkage int sys_sigreturn(void)
|
||||
{
|
||||
struct sigframe __user *frame = (struct sigframe __user *) __frame->sp;
|
||||
sigset_t set;
|
||||
int gr8;
|
||||
|
||||
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
|
||||
goto badframe;
|
||||
if (__get_user(set.sig[0], &frame->sc.sc_oldmask))
|
||||
goto badframe;
|
||||
|
||||
if (_NSIG_WORDS > 1 &&
|
||||
__copy_from_user(&set.sig[1], &frame->extramask, sizeof(frame->extramask)))
|
||||
goto badframe;
|
||||
|
||||
set_current_blocked(&set);
|
||||
|
||||
if (restore_sigcontext(&frame->sc, &gr8))
|
||||
goto badframe;
|
||||
return gr8;
|
||||
|
||||
badframe:
|
||||
force_sig(SIGSEGV, current);
|
||||
return 0;
|
||||
}
|
||||
|
||||
asmlinkage int sys_rt_sigreturn(void)
|
||||
{
|
||||
struct rt_sigframe __user *frame = (struct rt_sigframe __user *) __frame->sp;
|
||||
sigset_t set;
|
||||
int gr8;
|
||||
|
||||
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
|
||||
goto badframe;
|
||||
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
|
||||
goto badframe;
|
||||
|
||||
set_current_blocked(&set);
|
||||
|
||||
if (restore_sigcontext(&frame->uc.uc_mcontext, &gr8))
|
||||
goto badframe;
|
||||
|
||||
if (restore_altstack(&frame->uc.uc_stack))
|
||||
goto badframe;
|
||||
|
||||
return gr8;
|
||||
|
||||
badframe:
|
||||
force_sig(SIGSEGV, current);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up a signal frame
|
||||
*/
|
||||
static int setup_sigcontext(struct sigcontext __user *sc, unsigned long mask)
|
||||
{
|
||||
save_user_regs(current->thread.user);
|
||||
|
||||
if (copy_to_user(&sc->sc_context, current->thread.user, sizeof(sc->sc_context)) != 0)
|
||||
goto badframe;
|
||||
|
||||
/* non-iBCS2 extensions.. */
|
||||
if (__put_user(mask, &sc->sc_oldmask) < 0)
|
||||
goto badframe;
|
||||
|
||||
return 0;
|
||||
|
||||
badframe:
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* Determine which stack to use..
|
||||
*/
|
||||
static inline void __user *get_sigframe(struct ksignal *ksig,
|
||||
size_t frame_size)
|
||||
{
|
||||
unsigned long sp = sigsp(__frame->sp, ksig);
|
||||
|
||||
return (void __user *) ((sp - frame_size) & ~7UL);
|
||||
|
||||
} /* end get_sigframe() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static int setup_frame(struct ksignal *ksig, sigset_t *set)
|
||||
{
|
||||
struct sigframe __user *frame;
|
||||
int rsig, sig = ksig->sig;
|
||||
|
||||
set_fs(USER_DS);
|
||||
|
||||
frame = get_sigframe(ksig, sizeof(*frame));
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
||||
return -EFAULT;
|
||||
|
||||
rsig = sig;
|
||||
if (sig < 32 &&
|
||||
__current_thread_info->exec_domain &&
|
||||
__current_thread_info->exec_domain->signal_invmap)
|
||||
rsig = __current_thread_info->exec_domain->signal_invmap[sig];
|
||||
|
||||
if (__put_user(rsig, &frame->sig) < 0)
|
||||
return -EFAULT;
|
||||
|
||||
if (setup_sigcontext(&frame->sc, set->sig[0]))
|
||||
return -EFAULT;
|
||||
|
||||
if (_NSIG_WORDS > 1) {
|
||||
if (__copy_to_user(frame->extramask, &set->sig[1],
|
||||
sizeof(frame->extramask)))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* Set up to return from userspace. If provided, use a stub
|
||||
* already in userspace. */
|
||||
if (ksig->ka.sa.sa_flags & SA_RESTORER) {
|
||||
if (__put_user(ksig->ka.sa.sa_restorer, &frame->pretcode) < 0)
|
||||
return -EFAULT;
|
||||
}
|
||||
else {
|
||||
/* Set up the following code on the stack:
|
||||
* setlos #__NR_sigreturn,gr7
|
||||
* tira gr0,0
|
||||
*/
|
||||
if (__put_user((__sigrestore_t)frame->retcode, &frame->pretcode) ||
|
||||
__put_user(0x8efc0000|__NR_sigreturn, &frame->retcode[0]) ||
|
||||
__put_user(0xc0700000, &frame->retcode[1]))
|
||||
return -EFAULT;
|
||||
|
||||
flush_icache_range((unsigned long) frame->retcode,
|
||||
(unsigned long) (frame->retcode + 2));
|
||||
}
|
||||
|
||||
/* Set up registers for the signal handler */
|
||||
if (current->personality & FDPIC_FUNCPTRS) {
|
||||
struct fdpic_func_descriptor __user *funcptr =
|
||||
(struct fdpic_func_descriptor __user *) ksig->ka.sa.sa_handler;
|
||||
struct fdpic_func_descriptor desc;
|
||||
if (copy_from_user(&desc, funcptr, sizeof(desc)))
|
||||
return -EFAULT;
|
||||
__frame->pc = desc.text;
|
||||
__frame->gr15 = desc.GOT;
|
||||
} else {
|
||||
__frame->pc = (unsigned long) ksig->ka.sa.sa_handler;
|
||||
__frame->gr15 = 0;
|
||||
}
|
||||
|
||||
__frame->sp = (unsigned long) frame;
|
||||
__frame->lr = (unsigned long) &frame->retcode;
|
||||
__frame->gr8 = sig;
|
||||
|
||||
#if DEBUG_SIG
|
||||
printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n",
|
||||
sig, current->comm, current->pid, frame, __frame->pc,
|
||||
frame->pretcode);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
} /* end setup_frame() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static int setup_rt_frame(struct ksignal *ksig, sigset_t *set)
|
||||
{
|
||||
struct rt_sigframe __user *frame;
|
||||
int rsig, sig = ksig->sig;
|
||||
|
||||
set_fs(USER_DS);
|
||||
|
||||
frame = get_sigframe(ksig, sizeof(*frame));
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
||||
return -EFAULT;
|
||||
|
||||
rsig = sig;
|
||||
if (sig < 32 &&
|
||||
__current_thread_info->exec_domain &&
|
||||
__current_thread_info->exec_domain->signal_invmap)
|
||||
rsig = __current_thread_info->exec_domain->signal_invmap[sig];
|
||||
|
||||
if (__put_user(rsig, &frame->sig) ||
|
||||
__put_user(&frame->info, &frame->pinfo) ||
|
||||
__put_user(&frame->uc, &frame->puc))
|
||||
return -EFAULT;
|
||||
|
||||
if (copy_siginfo_to_user(&frame->info, &ksig->info))
|
||||
return -EFAULT;
|
||||
|
||||
/* Create the ucontext. */
|
||||
if (__put_user(0, &frame->uc.uc_flags) ||
|
||||
__put_user(NULL, &frame->uc.uc_link) ||
|
||||
__save_altstack(&frame->uc.uc_stack, __frame->sp))
|
||||
return -EFAULT;
|
||||
|
||||
if (setup_sigcontext(&frame->uc.uc_mcontext, set->sig[0]))
|
||||
return -EFAULT;
|
||||
|
||||
if (__copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)))
|
||||
return -EFAULT;
|
||||
|
||||
/* Set up to return from userspace. If provided, use a stub
|
||||
* already in userspace. */
|
||||
if (ksig->ka.sa.sa_flags & SA_RESTORER) {
|
||||
if (__put_user(ksig->ka.sa.sa_restorer, &frame->pretcode))
|
||||
return -EFAULT;
|
||||
}
|
||||
else {
|
||||
/* Set up the following code on the stack:
|
||||
* setlos #__NR_sigreturn,gr7
|
||||
* tira gr0,0
|
||||
*/
|
||||
if (__put_user((__sigrestore_t)frame->retcode, &frame->pretcode) ||
|
||||
__put_user(0x8efc0000|__NR_rt_sigreturn, &frame->retcode[0]) ||
|
||||
__put_user(0xc0700000, &frame->retcode[1]))
|
||||
return -EFAULT;
|
||||
|
||||
flush_icache_range((unsigned long) frame->retcode,
|
||||
(unsigned long) (frame->retcode + 2));
|
||||
}
|
||||
|
||||
/* Set up registers for signal handler */
|
||||
if (current->personality & FDPIC_FUNCPTRS) {
|
||||
struct fdpic_func_descriptor __user *funcptr =
|
||||
(struct fdpic_func_descriptor __user *) ksig->ka.sa.sa_handler;
|
||||
struct fdpic_func_descriptor desc;
|
||||
if (copy_from_user(&desc, funcptr, sizeof(desc)))
|
||||
return -EFAULT;
|
||||
__frame->pc = desc.text;
|
||||
__frame->gr15 = desc.GOT;
|
||||
} else {
|
||||
__frame->pc = (unsigned long) ksig->ka.sa.sa_handler;
|
||||
__frame->gr15 = 0;
|
||||
}
|
||||
|
||||
__frame->sp = (unsigned long) frame;
|
||||
__frame->lr = (unsigned long) &frame->retcode;
|
||||
__frame->gr8 = sig;
|
||||
__frame->gr9 = (unsigned long) &frame->info;
|
||||
|
||||
#if DEBUG_SIG
|
||||
printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n",
|
||||
sig, current->comm, current->pid, frame, __frame->pc,
|
||||
frame->pretcode);
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
} /* end setup_rt_frame() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* OK, we're invoking a handler
|
||||
*/
|
||||
static void handle_signal(struct ksignal *ksig)
|
||||
{
|
||||
sigset_t *oldset = sigmask_to_save();
|
||||
int ret;
|
||||
|
||||
/* Are we from a system call? */
|
||||
if (__frame->syscallno != -1) {
|
||||
/* If so, check system call restarting.. */
|
||||
switch (__frame->gr8) {
|
||||
case -ERESTART_RESTARTBLOCK:
|
||||
case -ERESTARTNOHAND:
|
||||
__frame->gr8 = -EINTR;
|
||||
break;
|
||||
|
||||
case -ERESTARTSYS:
|
||||
if (!(ksig->ka.sa.sa_flags & SA_RESTART)) {
|
||||
__frame->gr8 = -EINTR;
|
||||
break;
|
||||
}
|
||||
|
||||
/* fallthrough */
|
||||
case -ERESTARTNOINTR:
|
||||
__frame->gr8 = __frame->orig_gr8;
|
||||
__frame->pc -= 4;
|
||||
}
|
||||
__frame->syscallno = -1;
|
||||
}
|
||||
|
||||
/* Set up the stack frame */
|
||||
if (ksig->ka.sa.sa_flags & SA_SIGINFO)
|
||||
ret = setup_rt_frame(ksig, oldset);
|
||||
else
|
||||
ret = setup_frame(ksig, oldset);
|
||||
|
||||
signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLESTEP));
|
||||
} /* end handle_signal() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* Note that 'init' is a special process: it doesn't get signals it doesn't
|
||||
* want to handle. Thus you cannot kill init even with a SIGKILL even by
|
||||
* mistake.
|
||||
*/
|
||||
static void do_signal(void)
|
||||
{
|
||||
struct ksignal ksig;
|
||||
|
||||
if (get_signal(&ksig)) {
|
||||
handle_signal(&ksig);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Did we come from a system call? */
|
||||
if (__frame->syscallno != -1) {
|
||||
/* Restart the system call - no handlers present */
|
||||
switch (__frame->gr8) {
|
||||
case -ERESTARTNOHAND:
|
||||
case -ERESTARTSYS:
|
||||
case -ERESTARTNOINTR:
|
||||
__frame->gr8 = __frame->orig_gr8;
|
||||
__frame->pc -= 4;
|
||||
break;
|
||||
|
||||
case -ERESTART_RESTARTBLOCK:
|
||||
__frame->gr7 = __NR_restart_syscall;
|
||||
__frame->pc -= 4;
|
||||
break;
|
||||
}
|
||||
__frame->syscallno = -1;
|
||||
}
|
||||
|
||||
/* if there's no signal to deliver, we just put the saved sigmask
|
||||
* back */
|
||||
restore_saved_sigmask();
|
||||
} /* end do_signal() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* notification of userspace execution resumption
|
||||
* - triggered by the TIF_WORK_MASK flags
|
||||
*/
|
||||
asmlinkage void do_notify_resume(__u32 thread_info_flags)
|
||||
{
|
||||
/* pending single-step? */
|
||||
if (thread_info_flags & _TIF_SINGLESTEP)
|
||||
clear_thread_flag(TIF_SINGLESTEP);
|
||||
|
||||
/* deal with pending signal delivery */
|
||||
if (thread_info_flags & _TIF_SIGPENDING)
|
||||
do_signal();
|
||||
|
||||
/* deal with notification on about to resume userspace execution */
|
||||
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
|
||||
clear_thread_flag(TIF_NOTIFY_RESUME);
|
||||
tracehook_notify_resume(__frame);
|
||||
}
|
||||
|
||||
} /* end do_notify_resume() */
|
373
arch/frv/kernel/sleep.S
Normal file
373
arch/frv/kernel/sleep.S
Normal file
|
@ -0,0 +1,373 @@
|
|||
/* sleep.S: power saving mode entry
|
||||
*
|
||||
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Woodhouse (dwmw2@infradead.org)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/sys.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/cache.h>
|
||||
#include <asm/spr-regs.h>
|
||||
|
||||
#define __addr_MASK 0xfeff9820 /* interrupt controller mask */
|
||||
|
||||
#define __addr_FR55X_DRCN 0xfeff0218 /* Address of DRCN register */
|
||||
#define FR55X_DSTS_OFFSET -4 /* Offset from DRCN to DSTS */
|
||||
#define FR55X_SDRAMC_DSTS_SSI 0x00000002 /* indicates that the SDRAM is in self-refresh mode */
|
||||
|
||||
#define __addr_FR4XX_DRCN 0xfe000430 /* Address of DRCN register */
|
||||
#define FR4XX_DSTS_OFFSET -8 /* Offset from DRCN to DSTS */
|
||||
#define FR4XX_SDRAMC_DSTS_SSI 0x00000001 /* indicates that the SDRAM is in self-refresh mode */
|
||||
|
||||
#define SDRAMC_DRCN_SR 0x00000001 /* transition SDRAM into self-refresh mode */
|
||||
|
||||
.section .bss
|
||||
.balign 8
|
||||
.globl __sleep_save_area
|
||||
__sleep_save_area:
|
||||
.space 16
|
||||
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
|
||||
.macro li v r
|
||||
sethi.p %hi(\v),\r
|
||||
setlo %lo(\v),\r
|
||||
.endm
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
###############################################################################
|
||||
#
|
||||
# CPU suspension routine
|
||||
# - void frv_cpu_suspend(unsigned long pdm_mode)
|
||||
#
|
||||
###############################################################################
|
||||
.globl frv_cpu_suspend
|
||||
.type frv_cpu_suspend,@function
|
||||
frv_cpu_suspend:
|
||||
|
||||
#----------------------------------------------------
|
||||
# save hsr0, psr, isr, and lr for resume code
|
||||
#----------------------------------------------------
|
||||
li __sleep_save_area,gr11
|
||||
|
||||
movsg hsr0,gr4
|
||||
movsg psr,gr5
|
||||
movsg isr,gr6
|
||||
movsg lr,gr7
|
||||
stdi gr4,@(gr11,#0)
|
||||
stdi gr6,@(gr11,#8)
|
||||
|
||||
# store the return address from sleep in GR14, and its complement in GR13 as a check
|
||||
li __ramboot_resume,gr14
|
||||
#ifdef CONFIG_MMU
|
||||
# Resume via RAMBOOT# will turn MMU off, so bootloader needs a physical address.
|
||||
sethi.p %hi(__page_offset),gr13
|
||||
setlo %lo(__page_offset),gr13
|
||||
sub gr14,gr13,gr14
|
||||
#endif
|
||||
not gr14,gr13
|
||||
|
||||
#----------------------------------------------------
|
||||
# preload and lock into icache that code which may have to run
|
||||
# when dram is in self-refresh state.
|
||||
#----------------------------------------------------
|
||||
movsg hsr0, gr3
|
||||
li HSR0_ICE,gr4
|
||||
or gr3,gr4,gr3
|
||||
movgs gr3,hsr0
|
||||
or gr3,gr8,gr7 // add the sleep bits for later
|
||||
|
||||
li #__icache_lock_start,gr3
|
||||
li #__icache_lock_end,gr4
|
||||
1: icpl gr3,gr0,#1
|
||||
addi gr3,#L1_CACHE_BYTES,gr3
|
||||
cmp gr4,gr3,icc0
|
||||
bhi icc0,#0,1b
|
||||
|
||||
# disable exceptions
|
||||
movsg psr,gr8
|
||||
andi.p gr8,#~PSR_PIL,gr8
|
||||
andi gr8,~PSR_ET,gr8
|
||||
movgs gr8,psr
|
||||
ori gr8,#PSR_ET,gr8
|
||||
|
||||
srli gr8,#28,gr4
|
||||
subicc gr4,#3,gr0,icc0
|
||||
beq icc0,#0,1f
|
||||
# FR4xx
|
||||
li __addr_FR4XX_DRCN,gr4
|
||||
li FR4XX_SDRAMC_DSTS_SSI,gr5
|
||||
li FR4XX_DSTS_OFFSET,gr6
|
||||
bra __icache_lock_start
|
||||
1:
|
||||
# FR5xx
|
||||
li __addr_FR55X_DRCN,gr4
|
||||
li FR55X_SDRAMC_DSTS_SSI,gr5
|
||||
li FR55X_DSTS_OFFSET,gr6
|
||||
bra __icache_lock_start
|
||||
|
||||
.size frv_cpu_suspend, .-frv_cpu_suspend
|
||||
|
||||
#
|
||||
# the final part of the sleep sequence...
|
||||
# - we want it to be be cacheline aligned so we can lock it into the icache easily
|
||||
# On entry: gr7 holds desired hsr0 sleep value
|
||||
# gr8 holds desired psr sleep value
|
||||
#
|
||||
.balign L1_CACHE_BYTES
|
||||
.type __icache_lock_start,@function
|
||||
__icache_lock_start:
|
||||
|
||||
#----------------------------------------------------
|
||||
# put SDRAM in self-refresh mode
|
||||
#----------------------------------------------------
|
||||
|
||||
# Flush all data in the cache using the DCEF instruction.
|
||||
dcef @(gr0,gr0),#1
|
||||
|
||||
# Stop DMAC transfer
|
||||
|
||||
# Execute dummy load from SDRAM
|
||||
ldi @(gr11,#0),gr11
|
||||
|
||||
# put the SDRAM into self-refresh mode
|
||||
ld @(gr4,gr0),gr11
|
||||
ori gr11,#SDRAMC_DRCN_SR,gr11
|
||||
st gr11,@(gr4,gr0)
|
||||
membar
|
||||
|
||||
# wait for SDRAM to reach self-refresh mode
|
||||
1: ld @(gr4,gr6),gr11
|
||||
andcc gr11,gr5,gr11,icc0
|
||||
beq icc0,#0,1b
|
||||
|
||||
# Set the GPIO register so that the IRQ[3:0] pins become valid, as required.
|
||||
# Set the clock mode (CLKC register) as required.
|
||||
# - At this time, also set the CLKC register P0 bit.
|
||||
|
||||
# Set the HSR0 register PDM field.
|
||||
movgs gr7,hsr0
|
||||
|
||||
# Execute NOP 32 times.
|
||||
.rept 32
|
||||
nop
|
||||
.endr
|
||||
|
||||
#if 0 // Fujitsu recommend to skip this and will update docs.
|
||||
# Release the interrupt mask setting of the MASK register of the
|
||||
# interrupt controller if necessary.
|
||||
sti gr10,@(gr9,#0)
|
||||
membar
|
||||
#endif
|
||||
|
||||
# Set the PSR register ET bit to 1 to enable interrupts.
|
||||
movgs gr8,psr
|
||||
|
||||
###################################################
|
||||
# this is only reached if waking up via interrupt
|
||||
###################################################
|
||||
|
||||
# Execute NOP 32 times.
|
||||
.rept 32
|
||||
nop
|
||||
.endr
|
||||
|
||||
#----------------------------------------------------
|
||||
# wake SDRAM from self-refresh mode
|
||||
#----------------------------------------------------
|
||||
ld @(gr4,gr0),gr11
|
||||
andi gr11,#~SDRAMC_DRCN_SR,gr11
|
||||
st gr11,@(gr4,gr0)
|
||||
membar
|
||||
2:
|
||||
ld @(gr4,gr6),gr11 // Wait for it to come back...
|
||||
andcc gr11,gr5,gr0,icc0
|
||||
bne icc0,0,2b
|
||||
|
||||
# wait for the SDRAM to stabilise
|
||||
li 0x0100000,gr3
|
||||
3: subicc gr3,#1,gr3,icc0
|
||||
bne icc0,#0,3b
|
||||
|
||||
# now that DRAM is back, this is the end of the code which gets
|
||||
# locked in icache.
|
||||
__icache_lock_end:
|
||||
.size __icache_lock_start, .-__icache_lock_start
|
||||
|
||||
# Fall-through to the RAMBOOT# wakeup path
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# resume from suspend re-entry point reached via RAMBOOT# and bootloader
|
||||
#
|
||||
###############################################################################
|
||||
__ramboot_resume:
|
||||
|
||||
#----------------------------------------------------
|
||||
# restore hsr0, psr, isr, and leave saved lr in gr7
|
||||
#----------------------------------------------------
|
||||
li __sleep_save_area,gr11
|
||||
#ifdef CONFIG_MMU
|
||||
movsg hsr0,gr4
|
||||
sethi.p %hi(HSR0_EXMMU),gr3
|
||||
setlo %lo(HSR0_EXMMU),gr3
|
||||
andcc gr3,gr4,gr0,icc0
|
||||
bne icc0,#0,2f
|
||||
|
||||
# need to use physical address
|
||||
sethi.p %hi(__page_offset),gr3
|
||||
setlo %lo(__page_offset),gr3
|
||||
sub gr11,gr3,gr11
|
||||
|
||||
# flush all tlb entries
|
||||
setlos #64,gr4
|
||||
setlos.p #PAGE_SIZE,gr5
|
||||
setlos #0,gr6
|
||||
1:
|
||||
tlbpr gr6,gr0,#6,#0
|
||||
subicc.p gr4,#1,gr4,icc0
|
||||
add gr6,gr5,gr6
|
||||
bne icc0,#2,1b
|
||||
|
||||
# need a temporary mapping for the current physical address we are
|
||||
# using between time MMU is enabled and jump to virtual address is
|
||||
# made.
|
||||
sethi.p %hi(0x00000000),gr4
|
||||
setlo %lo(0x00000000),gr4 ; physical address
|
||||
setlos #xAMPRx_L|xAMPRx_M|xAMPRx_SS_256Mb|xAMPRx_S_KERNEL|xAMPRx_V,gr5
|
||||
or gr4,gr5,gr5
|
||||
|
||||
movsg cxnr,gr13
|
||||
or gr4,gr13,gr4
|
||||
|
||||
movgs gr4,iamlr1 ; mapped from real address 0
|
||||
movgs gr5,iampr1 ; cached kernel memory at 0x00000000
|
||||
2:
|
||||
#endif
|
||||
|
||||
lddi @(gr11,#0),gr4 ; hsr0, psr
|
||||
lddi @(gr11,#8),gr6 ; isr, lr
|
||||
movgs gr4,hsr0
|
||||
bar
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
sethi.p %hi(1f),gr11
|
||||
setlo %lo(1f),gr11
|
||||
jmpl @(gr11,gr0)
|
||||
1:
|
||||
movgs gr0,iampr1 ; get rid of temporary mapping
|
||||
#endif
|
||||
movgs gr5,psr
|
||||
movgs gr6,isr
|
||||
|
||||
#----------------------------------------------------
|
||||
# unlock the icache which was locked before going to sleep
|
||||
#----------------------------------------------------
|
||||
li __icache_lock_start,gr3
|
||||
li __icache_lock_end,gr4
|
||||
1: icul gr3
|
||||
addi gr3,#L1_CACHE_BYTES,gr3
|
||||
cmp gr4,gr3,icc0
|
||||
bhi icc0,#0,1b
|
||||
|
||||
#----------------------------------------------------
|
||||
# back to business as usual
|
||||
#----------------------------------------------------
|
||||
jmpl @(gr7,gr0) ;
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# CPU core sleep mode routine
|
||||
#
|
||||
###############################################################################
|
||||
.globl frv_cpu_core_sleep
|
||||
.type frv_cpu_core_sleep,@function
|
||||
frv_cpu_core_sleep:
|
||||
|
||||
# Preload into icache.
|
||||
li #__core_sleep_icache_lock_start,gr3
|
||||
li #__core_sleep_icache_lock_end,gr4
|
||||
|
||||
1: icpl gr3,gr0,#1
|
||||
addi gr3,#L1_CACHE_BYTES,gr3
|
||||
cmp gr4,gr3,icc0
|
||||
bhi icc0,#0,1b
|
||||
|
||||
bra __core_sleep_icache_lock_start
|
||||
|
||||
.balign L1_CACHE_BYTES
|
||||
__core_sleep_icache_lock_start:
|
||||
|
||||
# (1) Set the PSR register ET bit to 0 to disable interrupts.
|
||||
movsg psr,gr8
|
||||
andi.p gr8,#~(PSR_PIL),gr8
|
||||
andi gr8,#~(PSR_ET),gr4
|
||||
movgs gr4,psr
|
||||
|
||||
#if 0 // Fujitsu recommend to skip this and will update docs.
|
||||
# (2) Set '1' to all bits in the MASK register of the interrupt
|
||||
# controller and mask interrupts.
|
||||
sethi.p %hi(__addr_MASK),gr9
|
||||
setlo %lo(__addr_MASK),gr9
|
||||
sethi.p %hi(0xffff0000),gr4
|
||||
setlo %lo(0xffff0000),gr4
|
||||
ldi @(gr9,#0),gr10
|
||||
sti gr4,@(gr9,#0)
|
||||
#endif
|
||||
# (3) Flush all data in the cache using the DCEF instruction.
|
||||
dcef @(gr0,gr0),#1
|
||||
|
||||
# (4) Execute the memory barrier instruction
|
||||
membar
|
||||
|
||||
# (5) Set the GPIO register so that the IRQ[3:0] pins become valid, as required.
|
||||
# (6) Set the clock mode (CLKC register) as required.
|
||||
# - At this time, also set the CLKC register P0 bit.
|
||||
# (7) Set the HSR0 register PDM field to 001 .
|
||||
movsg hsr0,gr4
|
||||
ori gr4,HSR0_PDM_CORE_SLEEP,gr4
|
||||
movgs gr4,hsr0
|
||||
|
||||
# (8) Execute NOP 32 times.
|
||||
.rept 32
|
||||
nop
|
||||
.endr
|
||||
|
||||
#if 0 // Fujitsu recommend to skip this and will update docs.
|
||||
# (9) Release the interrupt mask setting of the MASK register of the
|
||||
# interrupt controller if necessary.
|
||||
sti gr10,@(gr9,#0)
|
||||
membar
|
||||
#endif
|
||||
|
||||
# (10) Set the PSR register ET bit to 1 to enable interrupts.
|
||||
movgs gr8,psr
|
||||
|
||||
__core_sleep_icache_lock_end:
|
||||
|
||||
# Unlock from icache
|
||||
li __core_sleep_icache_lock_start,gr3
|
||||
li __core_sleep_icache_lock_end,gr4
|
||||
1: icul gr3
|
||||
addi gr3,#L1_CACHE_BYTES,gr3
|
||||
cmp gr4,gr3,icc0
|
||||
bhi icc0,#0,1b
|
||||
|
||||
bralr
|
||||
|
||||
.size frv_cpu_core_sleep, .-frv_cpu_core_sleep
|
489
arch/frv/kernel/switch_to.S
Normal file
489
arch/frv/kernel/switch_to.S
Normal file
|
@ -0,0 +1,489 @@
|
|||
###############################################################################
|
||||
#
|
||||
# switch_to.S: context switch operation
|
||||
#
|
||||
# Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
|
||||
# Written by David Howells (dhowells@redhat.com)
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version
|
||||
# 2 of the License, or (at your option) any later version.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/registers.h>
|
||||
#include <asm/spr-regs.h>
|
||||
|
||||
.macro LEDS val
|
||||
setlos #~\val,gr27
|
||||
st gr27,@(gr30,gr0)
|
||||
membar
|
||||
dcf @(gr30,gr0)
|
||||
.endm
|
||||
|
||||
.section .sdata
|
||||
.balign 8
|
||||
|
||||
# address of frame 0 (userspace) on current kernel stack
|
||||
.globl __kernel_frame0_ptr
|
||||
__kernel_frame0_ptr:
|
||||
.long init_thread_union + THREAD_SIZE - FRV_FRAME0_SIZE
|
||||
|
||||
# address of current task
|
||||
.globl __kernel_current_task
|
||||
__kernel_current_task:
|
||||
.long init_task
|
||||
|
||||
.section .text
|
||||
.balign 4
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# struct task_struct *__switch_to(struct thread_struct *prev_thread,
|
||||
# struct thread_struct *next_thread,
|
||||
# struct task_struct *prev)
|
||||
#
|
||||
###############################################################################
|
||||
.globl __switch_to
|
||||
__switch_to:
|
||||
# save outgoing process's context
|
||||
sethi.p %hi(__switch_back),gr13
|
||||
setlo %lo(__switch_back),gr13
|
||||
movsg lr,gr12
|
||||
|
||||
stdi gr28,@(gr8,#__THREAD_FRAME)
|
||||
sti sp ,@(gr8,#__THREAD_SP)
|
||||
sti fp ,@(gr8,#__THREAD_FP)
|
||||
stdi gr12,@(gr8,#__THREAD_LR)
|
||||
stdi gr16,@(gr8,#__THREAD_GR(16))
|
||||
stdi gr18,@(gr8,#__THREAD_GR(18))
|
||||
stdi gr20,@(gr8,#__THREAD_GR(20))
|
||||
stdi gr22,@(gr8,#__THREAD_GR(22))
|
||||
stdi gr24,@(gr8,#__THREAD_GR(24))
|
||||
stdi.p gr26,@(gr8,#__THREAD_GR(26))
|
||||
|
||||
or gr8,gr8,gr22
|
||||
ldi.p @(gr8,#__THREAD_USER),gr8
|
||||
call save_user_regs
|
||||
or gr22,gr22,gr8
|
||||
|
||||
# retrieve the new context
|
||||
sethi.p %hi(__kernel_frame0_ptr),gr6
|
||||
setlo %lo(__kernel_frame0_ptr),gr6
|
||||
movsg psr,gr4
|
||||
|
||||
lddi.p @(gr9,#__THREAD_FRAME),gr10
|
||||
or gr10,gr10,gr27 ; save prev for the return value
|
||||
|
||||
ldi @(gr11,#4),gr19 ; get new_current->thread_info
|
||||
|
||||
lddi @(gr9,#__THREAD_SP),gr12
|
||||
ldi @(gr9,#__THREAD_LR),gr14
|
||||
ldi @(gr9,#__THREAD_PC),gr18
|
||||
ldi.p @(gr9,#__THREAD_FRAME0),gr7
|
||||
|
||||
# actually switch kernel contexts with ordinary exceptions disabled
|
||||
andi gr4,#~PSR_ET,gr5
|
||||
movgs gr5,psr
|
||||
|
||||
or.p gr10,gr0,gr28 ; set __frame
|
||||
or gr11,gr0,gr29 ; set __current
|
||||
or.p gr12,gr0,sp
|
||||
or gr13,gr0,fp
|
||||
or gr19,gr0,gr15 ; set __current_thread_info
|
||||
|
||||
sti gr7,@(gr6,#0) ; set __kernel_frame0_ptr
|
||||
sti gr29,@(gr6,#4) ; set __kernel_current_task
|
||||
|
||||
movgs gr14,lr
|
||||
bar
|
||||
|
||||
# jump to __switch_back or ret_from_fork as appropriate
|
||||
# - move prev to GR8
|
||||
movgs gr4,psr
|
||||
jmpl.p @(gr18,gr0)
|
||||
or gr27,gr27,gr8
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# restore incoming process's context
|
||||
# - on entry:
|
||||
# - SP, FP, LR, GR15, GR28 and GR29 will have been set up appropriately
|
||||
# - GR8 will point to the outgoing task_struct
|
||||
# - GR9 will point to the incoming thread_struct
|
||||
#
|
||||
###############################################################################
|
||||
__switch_back:
|
||||
lddi @(gr9,#__THREAD_GR(16)),gr16
|
||||
lddi @(gr9,#__THREAD_GR(18)),gr18
|
||||
lddi @(gr9,#__THREAD_GR(20)),gr20
|
||||
lddi @(gr9,#__THREAD_GR(22)),gr22
|
||||
lddi @(gr9,#__THREAD_GR(24)),gr24
|
||||
lddi @(gr9,#__THREAD_GR(26)),gr26
|
||||
|
||||
# fall through into restore_user_regs()
|
||||
ldi.p @(gr9,#__THREAD_USER),gr8
|
||||
or gr8,gr8,gr9
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# restore extra general regs and FP/Media regs
|
||||
# - void *restore_user_regs(const struct user_context *target, void *retval)
|
||||
# - on entry:
|
||||
# - GR8 will point to the user context to swap in
|
||||
# - GR9 will contain the value to be returned in GR8 (prev task on context switch)
|
||||
#
|
||||
###############################################################################
|
||||
.globl restore_user_regs
|
||||
restore_user_regs:
|
||||
movsg hsr0,gr6
|
||||
ori gr6,#HSR0_GRHE|HSR0_FRLE|HSR0_FRHE,gr6
|
||||
movgs gr6,hsr0
|
||||
movsg hsr0,gr6
|
||||
|
||||
movsg psr,gr7
|
||||
ori gr7,#PSR_EF|PSR_EM,gr7
|
||||
movgs gr7,psr
|
||||
movsg psr,gr7
|
||||
srli gr7,#24,gr7
|
||||
bar
|
||||
|
||||
lddi @(gr8,#__FPMEDIA_MSR(0)),gr4
|
||||
|
||||
movgs gr4,msr0
|
||||
movgs gr5,msr1
|
||||
|
||||
lddfi @(gr8,#__FPMEDIA_ACC(0)),fr16
|
||||
lddfi @(gr8,#__FPMEDIA_ACC(2)),fr18
|
||||
ldbfi @(gr8,#__FPMEDIA_ACCG(0)),fr20
|
||||
ldbfi @(gr8,#__FPMEDIA_ACCG(1)),fr21
|
||||
ldbfi @(gr8,#__FPMEDIA_ACCG(2)),fr22
|
||||
ldbfi @(gr8,#__FPMEDIA_ACCG(3)),fr23
|
||||
|
||||
mwtacc fr16,acc0
|
||||
mwtacc fr17,acc1
|
||||
mwtacc fr18,acc2
|
||||
mwtacc fr19,acc3
|
||||
mwtaccg fr20,accg0
|
||||
mwtaccg fr21,accg1
|
||||
mwtaccg fr22,accg2
|
||||
mwtaccg fr23,accg3
|
||||
|
||||
# some CPUs have extra ACCx and ACCGx regs and maybe FSRx regs
|
||||
subicc.p gr7,#0x50,gr0,icc0
|
||||
subicc gr7,#0x31,gr0,icc1
|
||||
beq icc0,#0,__restore_acc_fr451
|
||||
beq icc1,#0,__restore_acc_fr555
|
||||
__restore_acc_cont:
|
||||
|
||||
# some CPU's have GR32-GR63
|
||||
setlos #HSR0_FRHE,gr4
|
||||
andcc gr6,gr4,gr0,icc0
|
||||
beq icc0,#1,__restore_skip_gr32_gr63
|
||||
|
||||
lddi @(gr8,#__INT_GR(32)),gr32
|
||||
lddi @(gr8,#__INT_GR(34)),gr34
|
||||
lddi @(gr8,#__INT_GR(36)),gr36
|
||||
lddi @(gr8,#__INT_GR(38)),gr38
|
||||
lddi @(gr8,#__INT_GR(40)),gr40
|
||||
lddi @(gr8,#__INT_GR(42)),gr42
|
||||
lddi @(gr8,#__INT_GR(44)),gr44
|
||||
lddi @(gr8,#__INT_GR(46)),gr46
|
||||
lddi @(gr8,#__INT_GR(48)),gr48
|
||||
lddi @(gr8,#__INT_GR(50)),gr50
|
||||
lddi @(gr8,#__INT_GR(52)),gr52
|
||||
lddi @(gr8,#__INT_GR(54)),gr54
|
||||
lddi @(gr8,#__INT_GR(56)),gr56
|
||||
lddi @(gr8,#__INT_GR(58)),gr58
|
||||
lddi @(gr8,#__INT_GR(60)),gr60
|
||||
lddi @(gr8,#__INT_GR(62)),gr62
|
||||
__restore_skip_gr32_gr63:
|
||||
|
||||
# all CPU's have FR0-FR31
|
||||
lddfi @(gr8,#__FPMEDIA_FR( 0)),fr0
|
||||
lddfi @(gr8,#__FPMEDIA_FR( 2)),fr2
|
||||
lddfi @(gr8,#__FPMEDIA_FR( 4)),fr4
|
||||
lddfi @(gr8,#__FPMEDIA_FR( 6)),fr6
|
||||
lddfi @(gr8,#__FPMEDIA_FR( 8)),fr8
|
||||
lddfi @(gr8,#__FPMEDIA_FR(10)),fr10
|
||||
lddfi @(gr8,#__FPMEDIA_FR(12)),fr12
|
||||
lddfi @(gr8,#__FPMEDIA_FR(14)),fr14
|
||||
lddfi @(gr8,#__FPMEDIA_FR(16)),fr16
|
||||
lddfi @(gr8,#__FPMEDIA_FR(18)),fr18
|
||||
lddfi @(gr8,#__FPMEDIA_FR(20)),fr20
|
||||
lddfi @(gr8,#__FPMEDIA_FR(22)),fr22
|
||||
lddfi @(gr8,#__FPMEDIA_FR(24)),fr24
|
||||
lddfi @(gr8,#__FPMEDIA_FR(26)),fr26
|
||||
lddfi @(gr8,#__FPMEDIA_FR(28)),fr28
|
||||
lddfi.p @(gr8,#__FPMEDIA_FR(30)),fr30
|
||||
|
||||
# some CPU's have FR32-FR63
|
||||
setlos #HSR0_FRHE,gr4
|
||||
andcc gr6,gr4,gr0,icc0
|
||||
beq icc0,#1,__restore_skip_fr32_fr63
|
||||
|
||||
lddfi @(gr8,#__FPMEDIA_FR(32)),fr32
|
||||
lddfi @(gr8,#__FPMEDIA_FR(34)),fr34
|
||||
lddfi @(gr8,#__FPMEDIA_FR(36)),fr36
|
||||
lddfi @(gr8,#__FPMEDIA_FR(38)),fr38
|
||||
lddfi @(gr8,#__FPMEDIA_FR(40)),fr40
|
||||
lddfi @(gr8,#__FPMEDIA_FR(42)),fr42
|
||||
lddfi @(gr8,#__FPMEDIA_FR(44)),fr44
|
||||
lddfi @(gr8,#__FPMEDIA_FR(46)),fr46
|
||||
lddfi @(gr8,#__FPMEDIA_FR(48)),fr48
|
||||
lddfi @(gr8,#__FPMEDIA_FR(50)),fr50
|
||||
lddfi @(gr8,#__FPMEDIA_FR(52)),fr52
|
||||
lddfi @(gr8,#__FPMEDIA_FR(54)),fr54
|
||||
lddfi @(gr8,#__FPMEDIA_FR(56)),fr56
|
||||
lddfi @(gr8,#__FPMEDIA_FR(58)),fr58
|
||||
lddfi @(gr8,#__FPMEDIA_FR(60)),fr60
|
||||
lddfi @(gr8,#__FPMEDIA_FR(62)),fr62
|
||||
__restore_skip_fr32_fr63:
|
||||
|
||||
lddi @(gr8,#__FPMEDIA_FNER(0)),gr4
|
||||
movsg fner0,gr4
|
||||
movsg fner1,gr5
|
||||
or.p gr9,gr9,gr8
|
||||
bralr
|
||||
|
||||
# the FR451 also has ACC8-11/ACCG8-11 regs (but not 4-7...)
|
||||
__restore_acc_fr451:
|
||||
lddfi @(gr8,#__FPMEDIA_ACC(4)),fr16
|
||||
lddfi @(gr8,#__FPMEDIA_ACC(6)),fr18
|
||||
ldbfi @(gr8,#__FPMEDIA_ACCG(4)),fr20
|
||||
ldbfi @(gr8,#__FPMEDIA_ACCG(5)),fr21
|
||||
ldbfi @(gr8,#__FPMEDIA_ACCG(6)),fr22
|
||||
ldbfi @(gr8,#__FPMEDIA_ACCG(7)),fr23
|
||||
|
||||
mwtacc fr16,acc8
|
||||
mwtacc fr17,acc9
|
||||
mwtacc fr18,acc10
|
||||
mwtacc fr19,acc11
|
||||
mwtaccg fr20,accg8
|
||||
mwtaccg fr21,accg9
|
||||
mwtaccg fr22,accg10
|
||||
mwtaccg fr23,accg11
|
||||
bra __restore_acc_cont
|
||||
|
||||
# the FR555 also has ACC4-7/ACCG4-7 regs and an FSR0 reg
|
||||
__restore_acc_fr555:
|
||||
lddfi @(gr8,#__FPMEDIA_ACC(4)),fr16
|
||||
lddfi @(gr8,#__FPMEDIA_ACC(6)),fr18
|
||||
ldbfi @(gr8,#__FPMEDIA_ACCG(4)),fr20
|
||||
ldbfi @(gr8,#__FPMEDIA_ACCG(5)),fr21
|
||||
ldbfi @(gr8,#__FPMEDIA_ACCG(6)),fr22
|
||||
ldbfi @(gr8,#__FPMEDIA_ACCG(7)),fr23
|
||||
|
||||
mnop.p
|
||||
mwtacc fr16,acc4
|
||||
mnop.p
|
||||
mwtacc fr17,acc5
|
||||
mnop.p
|
||||
mwtacc fr18,acc6
|
||||
mnop.p
|
||||
mwtacc fr19,acc7
|
||||
mnop.p
|
||||
mwtaccg fr20,accg4
|
||||
mnop.p
|
||||
mwtaccg fr21,accg5
|
||||
mnop.p
|
||||
mwtaccg fr22,accg6
|
||||
mnop.p
|
||||
mwtaccg fr23,accg7
|
||||
|
||||
ldi @(gr8,#__FPMEDIA_FSR(0)),gr4
|
||||
movgs gr4,fsr0
|
||||
|
||||
bra __restore_acc_cont
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# save extra general regs and FP/Media regs
|
||||
# - void save_user_regs(struct user_context *target)
|
||||
#
|
||||
###############################################################################
|
||||
.globl save_user_regs
|
||||
save_user_regs:
|
||||
movsg hsr0,gr6
|
||||
ori gr6,#HSR0_GRHE|HSR0_FRLE|HSR0_FRHE,gr6
|
||||
movgs gr6,hsr0
|
||||
movsg hsr0,gr6
|
||||
|
||||
movsg psr,gr7
|
||||
ori gr7,#PSR_EF|PSR_EM,gr7
|
||||
movgs gr7,psr
|
||||
movsg psr,gr7
|
||||
srli gr7,#24,gr7
|
||||
bar
|
||||
|
||||
movsg fner0,gr4
|
||||
movsg fner1,gr5
|
||||
stdi.p gr4,@(gr8,#__FPMEDIA_FNER(0))
|
||||
|
||||
# some CPU's have GR32-GR63
|
||||
setlos #HSR0_GRHE,gr4
|
||||
andcc gr6,gr4,gr0,icc0
|
||||
beq icc0,#1,__save_skip_gr32_gr63
|
||||
|
||||
stdi gr32,@(gr8,#__INT_GR(32))
|
||||
stdi gr34,@(gr8,#__INT_GR(34))
|
||||
stdi gr36,@(gr8,#__INT_GR(36))
|
||||
stdi gr38,@(gr8,#__INT_GR(38))
|
||||
stdi gr40,@(gr8,#__INT_GR(40))
|
||||
stdi gr42,@(gr8,#__INT_GR(42))
|
||||
stdi gr44,@(gr8,#__INT_GR(44))
|
||||
stdi gr46,@(gr8,#__INT_GR(46))
|
||||
stdi gr48,@(gr8,#__INT_GR(48))
|
||||
stdi gr50,@(gr8,#__INT_GR(50))
|
||||
stdi gr52,@(gr8,#__INT_GR(52))
|
||||
stdi gr54,@(gr8,#__INT_GR(54))
|
||||
stdi gr56,@(gr8,#__INT_GR(56))
|
||||
stdi gr58,@(gr8,#__INT_GR(58))
|
||||
stdi gr60,@(gr8,#__INT_GR(60))
|
||||
stdi gr62,@(gr8,#__INT_GR(62))
|
||||
__save_skip_gr32_gr63:
|
||||
|
||||
# all CPU's have FR0-FR31
|
||||
stdfi fr0 ,@(gr8,#__FPMEDIA_FR( 0))
|
||||
stdfi fr2 ,@(gr8,#__FPMEDIA_FR( 2))
|
||||
stdfi fr4 ,@(gr8,#__FPMEDIA_FR( 4))
|
||||
stdfi fr6 ,@(gr8,#__FPMEDIA_FR( 6))
|
||||
stdfi fr8 ,@(gr8,#__FPMEDIA_FR( 8))
|
||||
stdfi fr10,@(gr8,#__FPMEDIA_FR(10))
|
||||
stdfi fr12,@(gr8,#__FPMEDIA_FR(12))
|
||||
stdfi fr14,@(gr8,#__FPMEDIA_FR(14))
|
||||
stdfi fr16,@(gr8,#__FPMEDIA_FR(16))
|
||||
stdfi fr18,@(gr8,#__FPMEDIA_FR(18))
|
||||
stdfi fr20,@(gr8,#__FPMEDIA_FR(20))
|
||||
stdfi fr22,@(gr8,#__FPMEDIA_FR(22))
|
||||
stdfi fr24,@(gr8,#__FPMEDIA_FR(24))
|
||||
stdfi fr26,@(gr8,#__FPMEDIA_FR(26))
|
||||
stdfi fr28,@(gr8,#__FPMEDIA_FR(28))
|
||||
stdfi.p fr30,@(gr8,#__FPMEDIA_FR(30))
|
||||
|
||||
# some CPU's have FR32-FR63
|
||||
setlos #HSR0_FRHE,gr4
|
||||
andcc gr6,gr4,gr0,icc0
|
||||
beq icc0,#1,__save_skip_fr32_fr63
|
||||
|
||||
stdfi fr32,@(gr8,#__FPMEDIA_FR(32))
|
||||
stdfi fr34,@(gr8,#__FPMEDIA_FR(34))
|
||||
stdfi fr36,@(gr8,#__FPMEDIA_FR(36))
|
||||
stdfi fr38,@(gr8,#__FPMEDIA_FR(38))
|
||||
stdfi fr40,@(gr8,#__FPMEDIA_FR(40))
|
||||
stdfi fr42,@(gr8,#__FPMEDIA_FR(42))
|
||||
stdfi fr44,@(gr8,#__FPMEDIA_FR(44))
|
||||
stdfi fr46,@(gr8,#__FPMEDIA_FR(46))
|
||||
stdfi fr48,@(gr8,#__FPMEDIA_FR(48))
|
||||
stdfi fr50,@(gr8,#__FPMEDIA_FR(50))
|
||||
stdfi fr52,@(gr8,#__FPMEDIA_FR(52))
|
||||
stdfi fr54,@(gr8,#__FPMEDIA_FR(54))
|
||||
stdfi fr56,@(gr8,#__FPMEDIA_FR(56))
|
||||
stdfi fr58,@(gr8,#__FPMEDIA_FR(58))
|
||||
stdfi fr60,@(gr8,#__FPMEDIA_FR(60))
|
||||
stdfi fr62,@(gr8,#__FPMEDIA_FR(62))
|
||||
__save_skip_fr32_fr63:
|
||||
|
||||
mrdacc acc0 ,fr4
|
||||
mrdacc acc1 ,fr5
|
||||
|
||||
stdfi.p fr4 ,@(gr8,#__FPMEDIA_ACC(0))
|
||||
|
||||
mrdacc acc2 ,fr6
|
||||
mrdacc acc3 ,fr7
|
||||
|
||||
stdfi.p fr6 ,@(gr8,#__FPMEDIA_ACC(2))
|
||||
|
||||
mrdaccg accg0,fr4
|
||||
stbfi.p fr4 ,@(gr8,#__FPMEDIA_ACCG(0))
|
||||
|
||||
mrdaccg accg1,fr5
|
||||
stbfi.p fr5 ,@(gr8,#__FPMEDIA_ACCG(1))
|
||||
|
||||
mrdaccg accg2,fr6
|
||||
stbfi.p fr6 ,@(gr8,#__FPMEDIA_ACCG(2))
|
||||
|
||||
mrdaccg accg3,fr7
|
||||
stbfi fr7 ,@(gr8,#__FPMEDIA_ACCG(3))
|
||||
|
||||
movsg msr0 ,gr4
|
||||
movsg msr1 ,gr5
|
||||
|
||||
stdi gr4 ,@(gr8,#__FPMEDIA_MSR(0))
|
||||
|
||||
# some CPUs have extra ACCx and ACCGx regs and maybe FSRx regs
|
||||
subicc.p gr7,#0x50,gr0,icc0
|
||||
subicc gr7,#0x31,gr0,icc1
|
||||
beq icc0,#0,__save_acc_fr451
|
||||
beq icc1,#0,__save_acc_fr555
|
||||
__save_acc_cont:
|
||||
|
||||
lddfi @(gr8,#__FPMEDIA_FR(4)),fr4
|
||||
lddfi.p @(gr8,#__FPMEDIA_FR(6)),fr6
|
||||
bralr
|
||||
|
||||
# the FR451 also has ACC8-11/ACCG8-11 regs (but not 4-7...)
|
||||
__save_acc_fr451:
|
||||
mrdacc acc8 ,fr4
|
||||
mrdacc acc9 ,fr5
|
||||
|
||||
stdfi.p fr4 ,@(gr8,#__FPMEDIA_ACC(4))
|
||||
|
||||
mrdacc acc10,fr6
|
||||
mrdacc acc11,fr7
|
||||
|
||||
stdfi.p fr6 ,@(gr8,#__FPMEDIA_ACC(6))
|
||||
|
||||
mrdaccg accg8,fr4
|
||||
stbfi.p fr4 ,@(gr8,#__FPMEDIA_ACCG(4))
|
||||
|
||||
mrdaccg accg9,fr5
|
||||
stbfi.p fr5 ,@(gr8,#__FPMEDIA_ACCG(5))
|
||||
|
||||
mrdaccg accg10,fr6
|
||||
stbfi.p fr6 ,@(gr8,#__FPMEDIA_ACCG(6))
|
||||
|
||||
mrdaccg accg11,fr7
|
||||
stbfi fr7 ,@(gr8,#__FPMEDIA_ACCG(7))
|
||||
bra __save_acc_cont
|
||||
|
||||
# the FR555 also has ACC4-7/ACCG4-7 regs and an FSR0 reg
|
||||
__save_acc_fr555:
|
||||
mnop.p
|
||||
mrdacc acc4 ,fr4
|
||||
mnop.p
|
||||
mrdacc acc5 ,fr5
|
||||
|
||||
stdfi fr4 ,@(gr8,#__FPMEDIA_ACC(4))
|
||||
|
||||
mnop.p
|
||||
mrdacc acc6 ,fr6
|
||||
mnop.p
|
||||
mrdacc acc7 ,fr7
|
||||
|
||||
stdfi fr6 ,@(gr8,#__FPMEDIA_ACC(6))
|
||||
|
||||
mnop.p
|
||||
mrdaccg accg4,fr4
|
||||
stbfi fr4 ,@(gr8,#__FPMEDIA_ACCG(4))
|
||||
|
||||
mnop.p
|
||||
mrdaccg accg5,fr5
|
||||
stbfi fr5 ,@(gr8,#__FPMEDIA_ACCG(5))
|
||||
|
||||
mnop.p
|
||||
mrdaccg accg6,fr6
|
||||
stbfi fr6 ,@(gr8,#__FPMEDIA_ACCG(6))
|
||||
|
||||
mnop.p
|
||||
mrdaccg accg7,fr7
|
||||
stbfi fr7 ,@(gr8,#__FPMEDIA_ACCG(7))
|
||||
|
||||
movsg fsr0 ,gr4
|
||||
sti gr4 ,@(gr8,#__FPMEDIA_FSR(0))
|
||||
bra __save_acc_cont
|
44
arch/frv/kernel/sys_frv.c
Normal file
44
arch/frv/kernel/sys_frv.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
/* sys_frv.c: FRV arch-specific syscall wrappers
|
||||
*
|
||||
* Copyright (C) 2003-5 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
* - Derived from arch/m68k/kernel/sys_m68k.c
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/sem.h>
|
||||
#include <linux/msg.h>
|
||||
#include <linux/shm.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/mman.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/ipc.h>
|
||||
|
||||
#include <asm/setup.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
|
||||
unsigned long prot, unsigned long flags,
|
||||
unsigned long fd, unsigned long pgoff)
|
||||
{
|
||||
/* As with sparc32, make sure the shift for mmap2 is constant
|
||||
(12), no matter what PAGE_SIZE we have.... */
|
||||
|
||||
/* But unlike sparc32, don't just silently break if we're
|
||||
trying to map something we can't */
|
||||
if (pgoff & ((1 << (PAGE_SHIFT - 12)) - 1))
|
||||
return -EINVAL;
|
||||
|
||||
return sys_mmap_pgoff(addr, len, prot, flags, fd,
|
||||
pgoff >> (PAGE_SHIFT - 12));
|
||||
}
|
221
arch/frv/kernel/sysctl.c
Normal file
221
arch/frv/kernel/sysctl.c
Normal file
|
@ -0,0 +1,221 @@
|
|||
/* sysctl.c: implementation of /proc/sys files relating to FRV specifically
|
||||
*
|
||||
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
static const char frv_cache_wback[] = "wback";
|
||||
static const char frv_cache_wthru[] = "wthru";
|
||||
|
||||
static void frv_change_dcache_mode(unsigned long newmode)
|
||||
{
|
||||
unsigned long flags, hsr0;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
hsr0 = __get_HSR(0);
|
||||
hsr0 &= ~HSR0_DCE;
|
||||
__set_HSR(0, hsr0);
|
||||
|
||||
asm volatile(" dcef @(gr0,gr0),#1 \n"
|
||||
" membar \n"
|
||||
: : : "memory"
|
||||
);
|
||||
|
||||
hsr0 = (hsr0 & ~HSR0_CBM) | newmode;
|
||||
__set_HSR(0, hsr0);
|
||||
hsr0 |= HSR0_DCE;
|
||||
__set_HSR(0, hsr0);
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
//printk("HSR0 now %08lx\n", hsr0);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* handle requests to dynamically switch the write caching mode delivered by /proc
|
||||
*/
|
||||
static int procctl_frv_cachemode(struct ctl_table *table, int write,
|
||||
void __user *buffer, size_t *lenp,
|
||||
loff_t *ppos)
|
||||
{
|
||||
unsigned long hsr0;
|
||||
char buff[8];
|
||||
int len;
|
||||
|
||||
len = *lenp;
|
||||
|
||||
if (write) {
|
||||
/* potential state change */
|
||||
if (len <= 1 || len > sizeof(buff) - 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(buff, buffer, len) != 0)
|
||||
return -EFAULT;
|
||||
|
||||
if (buff[len - 1] == '\n')
|
||||
buff[len - 1] = '\0';
|
||||
else
|
||||
buff[len] = '\0';
|
||||
|
||||
if (strcmp(buff, frv_cache_wback) == 0) {
|
||||
/* switch dcache into write-back mode */
|
||||
frv_change_dcache_mode(HSR0_CBM_COPY_BACK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(buff, frv_cache_wthru) == 0) {
|
||||
/* switch dcache into write-through mode */
|
||||
frv_change_dcache_mode(HSR0_CBM_WRITE_THRU);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* read the state */
|
||||
if (*ppos > 0) {
|
||||
*lenp = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
hsr0 = __get_HSR(0);
|
||||
switch (hsr0 & HSR0_CBM) {
|
||||
case HSR0_CBM_WRITE_THRU:
|
||||
memcpy(buff, frv_cache_wthru, sizeof(frv_cache_wthru) - 1);
|
||||
buff[sizeof(frv_cache_wthru) - 1] = '\n';
|
||||
len = sizeof(frv_cache_wthru);
|
||||
break;
|
||||
default:
|
||||
memcpy(buff, frv_cache_wback, sizeof(frv_cache_wback) - 1);
|
||||
buff[sizeof(frv_cache_wback) - 1] = '\n';
|
||||
len = sizeof(frv_cache_wback);
|
||||
break;
|
||||
}
|
||||
|
||||
if (len > *lenp)
|
||||
len = *lenp;
|
||||
|
||||
if (copy_to_user(buffer, buff, len) != 0)
|
||||
return -EFAULT;
|
||||
|
||||
*lenp = len;
|
||||
*ppos = len;
|
||||
return 0;
|
||||
|
||||
} /* end procctl_frv_cachemode() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* permit the mm_struct the nominated process is using have its MMU context ID pinned
|
||||
*/
|
||||
#ifdef CONFIG_MMU
|
||||
static int procctl_frv_pin_cxnr(struct ctl_table *table, int write,
|
||||
void __user *buffer, size_t *lenp,
|
||||
loff_t *ppos)
|
||||
{
|
||||
pid_t pid;
|
||||
char buff[16], *p;
|
||||
int len;
|
||||
|
||||
len = *lenp;
|
||||
|
||||
if (write) {
|
||||
/* potential state change */
|
||||
if (len <= 1 || len > sizeof(buff) - 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(buff, buffer, len) != 0)
|
||||
return -EFAULT;
|
||||
|
||||
if (buff[len - 1] == '\n')
|
||||
buff[len - 1] = '\0';
|
||||
else
|
||||
buff[len] = '\0';
|
||||
|
||||
pid = simple_strtoul(buff, &p, 10);
|
||||
if (*p)
|
||||
return -EINVAL;
|
||||
|
||||
return cxn_pin_by_pid(pid);
|
||||
}
|
||||
|
||||
/* read the currently pinned CXN */
|
||||
if (*ppos > 0) {
|
||||
*lenp = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = snprintf(buff, sizeof(buff), "%d\n", cxn_pinned);
|
||||
if (len > *lenp)
|
||||
len = *lenp;
|
||||
|
||||
if (copy_to_user(buffer, buff, len) != 0)
|
||||
return -EFAULT;
|
||||
|
||||
*lenp = len;
|
||||
*ppos = len;
|
||||
return 0;
|
||||
|
||||
} /* end procctl_frv_pin_cxnr() */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* FR-V specific sysctls
|
||||
*/
|
||||
static struct ctl_table frv_table[] =
|
||||
{
|
||||
{
|
||||
.procname = "cache-mode",
|
||||
.data = NULL,
|
||||
.maxlen = 0,
|
||||
.mode = 0644,
|
||||
.proc_handler = procctl_frv_cachemode,
|
||||
},
|
||||
#ifdef CONFIG_MMU
|
||||
{
|
||||
.procname = "pin-cxnr",
|
||||
.data = NULL,
|
||||
.maxlen = 0,
|
||||
.mode = 0644,
|
||||
.proc_handler = procctl_frv_pin_cxnr
|
||||
},
|
||||
#endif
|
||||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
* Use a temporary sysctl number. Horrid, but will be cleaned up in 2.6
|
||||
* when all the PM interfaces exist nicely.
|
||||
*/
|
||||
static struct ctl_table frv_dir_table[] =
|
||||
{
|
||||
{
|
||||
.procname = "frv",
|
||||
.mode = 0555,
|
||||
.child = frv_table
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize power interface
|
||||
*/
|
||||
static int __init frv_sysctl_init(void)
|
||||
{
|
||||
register_sysctl_table(frv_dir_table);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__initcall(frv_sysctl_init);
|
122
arch/frv/kernel/time.c
Normal file
122
arch/frv/kernel/time.c
Normal file
|
@ -0,0 +1,122 @@
|
|||
/* time.c: FRV arch-specific time handling
|
||||
*
|
||||
* Copyright (C) 2003-5 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
* - Derived from arch/m68k/kernel/time.c
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/param.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/profile.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/timer-regs.h>
|
||||
#include <asm/mb-regs.h>
|
||||
#include <asm/mb86943a.h>
|
||||
|
||||
#include <linux/timex.h>
|
||||
|
||||
#define TICK_SIZE (tick_nsec / 1000)
|
||||
|
||||
unsigned long __nongprelbss __clkin_clock_speed_HZ;
|
||||
unsigned long __nongprelbss __ext_bus_clock_speed_HZ;
|
||||
unsigned long __nongprelbss __res_bus_clock_speed_HZ;
|
||||
unsigned long __nongprelbss __sdram_clock_speed_HZ;
|
||||
unsigned long __nongprelbss __core_bus_clock_speed_HZ;
|
||||
unsigned long __nongprelbss __core_clock_speed_HZ;
|
||||
unsigned long __nongprelbss __dsu_clock_speed_HZ;
|
||||
unsigned long __nongprelbss __serial_clock_speed_HZ;
|
||||
unsigned long __delay_loops_MHz;
|
||||
|
||||
static irqreturn_t timer_interrupt(int irq, void *dummy);
|
||||
|
||||
static struct irqaction timer_irq = {
|
||||
.handler = timer_interrupt,
|
||||
.name = "timer",
|
||||
};
|
||||
|
||||
/*
|
||||
* timer_interrupt() needs to keep up the real-time clock,
|
||||
* as well as call the "xtime_update()" routine every clocktick
|
||||
*/
|
||||
static irqreturn_t timer_interrupt(int irq, void *dummy)
|
||||
{
|
||||
profile_tick(CPU_PROFILING);
|
||||
|
||||
xtime_update(1);
|
||||
|
||||
#ifdef CONFIG_HEARTBEAT
|
||||
static unsigned short n;
|
||||
n++;
|
||||
__set_LEDS(n);
|
||||
#endif /* CONFIG_HEARTBEAT */
|
||||
|
||||
update_process_times(user_mode(get_irq_regs()));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
void time_divisor_init(void)
|
||||
{
|
||||
unsigned short base, pre, prediv;
|
||||
|
||||
/* set the scheduling timer going */
|
||||
pre = 1;
|
||||
prediv = 4;
|
||||
base = __res_bus_clock_speed_HZ / pre / HZ / (1 << prediv);
|
||||
|
||||
__set_TPRV(pre);
|
||||
__set_TxCKSL_DATA(0, prediv);
|
||||
__set_TCTR(TCTR_SC_CTR0 | TCTR_RL_RW_LH8 | TCTR_MODE_2);
|
||||
__set_TCSR_DATA(0, base & 0xff);
|
||||
__set_TCSR_DATA(0, base >> 8);
|
||||
}
|
||||
|
||||
|
||||
void read_persistent_clock(struct timespec *ts)
|
||||
{
|
||||
unsigned int year, mon, day, hour, min, sec;
|
||||
|
||||
extern void arch_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec);
|
||||
|
||||
/* FIX by dqg : Set to zero for platforms that don't have tod */
|
||||
/* without this time is undefined and can overflow time_t, causing */
|
||||
/* very strange errors */
|
||||
year = 1980;
|
||||
mon = day = 1;
|
||||
hour = min = sec = 0;
|
||||
arch_gettod (&year, &mon, &day, &hour, &min, &sec);
|
||||
|
||||
if ((year += 1900) < 1970)
|
||||
year += 100;
|
||||
ts->tv_sec = mktime(year, mon, day, hour, min, sec);
|
||||
ts->tv_nsec = 0;
|
||||
}
|
||||
|
||||
void time_init(void)
|
||||
{
|
||||
/* install scheduling interrupt handler */
|
||||
setup_irq(IRQ_CPU_TIMER0, &timer_irq);
|
||||
|
||||
time_divisor_init();
|
||||
}
|
||||
|
||||
/*
|
||||
* Scheduler clock - returns current time in nanosec units.
|
||||
*/
|
||||
unsigned long long sched_clock(void)
|
||||
{
|
||||
return jiffies_64 * (1000000000 / HZ);
|
||||
}
|
646
arch/frv/kernel/traps.c
Normal file
646
arch/frv/kernel/traps.c
Normal file
|
@ -0,0 +1,646 @@
|
|||
/* traps.c: high-level exception handler for FR-V
|
||||
*
|
||||
* Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/user.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/fpu.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/siginfo.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
void show_backtrace(struct pt_regs *, unsigned long);
|
||||
|
||||
extern asmlinkage void __break_hijack_kernel_event(void);
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* instruction access error
|
||||
*/
|
||||
asmlinkage void insn_access_error(unsigned long esfr1, unsigned long epcr0, unsigned long esr0)
|
||||
{
|
||||
siginfo_t info;
|
||||
|
||||
die_if_kernel("-- Insn Access Error --\n"
|
||||
"EPCR0 : %08lx\n"
|
||||
"ESR0 : %08lx\n",
|
||||
epcr0, esr0);
|
||||
|
||||
info.si_signo = SIGSEGV;
|
||||
info.si_code = SEGV_ACCERR;
|
||||
info.si_errno = 0;
|
||||
info.si_addr = (void __user *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc);
|
||||
|
||||
force_sig_info(info.si_signo, &info, current);
|
||||
} /* end insn_access_error() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* handler for:
|
||||
* - illegal instruction
|
||||
* - privileged instruction
|
||||
* - unsupported trap
|
||||
* - debug exceptions
|
||||
*/
|
||||
asmlinkage void illegal_instruction(unsigned long esfr1, unsigned long epcr0, unsigned long esr0)
|
||||
{
|
||||
siginfo_t info;
|
||||
|
||||
die_if_kernel("-- Illegal Instruction --\n"
|
||||
"EPCR0 : %08lx\n"
|
||||
"ESR0 : %08lx\n"
|
||||
"ESFR1 : %08lx\n",
|
||||
epcr0, esr0, esfr1);
|
||||
|
||||
info.si_errno = 0;
|
||||
info.si_addr = (void __user *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc);
|
||||
|
||||
switch (__frame->tbr & TBR_TT) {
|
||||
case TBR_TT_ILLEGAL_INSTR:
|
||||
info.si_signo = SIGILL;
|
||||
info.si_code = ILL_ILLOPC;
|
||||
break;
|
||||
case TBR_TT_PRIV_INSTR:
|
||||
info.si_signo = SIGILL;
|
||||
info.si_code = ILL_PRVOPC;
|
||||
break;
|
||||
case TBR_TT_TRAP2 ... TBR_TT_TRAP126:
|
||||
info.si_signo = SIGILL;
|
||||
info.si_code = ILL_ILLTRP;
|
||||
break;
|
||||
/* GDB uses "tira gr0, #1" as a breakpoint instruction. */
|
||||
case TBR_TT_TRAP1:
|
||||
case TBR_TT_BREAK:
|
||||
info.si_signo = SIGTRAP;
|
||||
info.si_code =
|
||||
(__frame->__status & REG__STATUS_STEPPED) ? TRAP_TRACE : TRAP_BRKPT;
|
||||
break;
|
||||
}
|
||||
|
||||
force_sig_info(info.si_signo, &info, current);
|
||||
} /* end illegal_instruction() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* handle atomic operations with errors
|
||||
* - arguments in gr8, gr9, gr10
|
||||
* - original memory value placed in gr5
|
||||
* - replacement memory value placed in gr9
|
||||
*/
|
||||
asmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0,
|
||||
unsigned long esr0)
|
||||
{
|
||||
static DEFINE_SPINLOCK(atomic_op_lock);
|
||||
unsigned long x, y, z;
|
||||
unsigned long __user *p;
|
||||
mm_segment_t oldfs;
|
||||
siginfo_t info;
|
||||
int ret;
|
||||
|
||||
y = 0;
|
||||
z = 0;
|
||||
|
||||
oldfs = get_fs();
|
||||
if (!user_mode(__frame))
|
||||
set_fs(KERNEL_DS);
|
||||
|
||||
switch (__frame->tbr & TBR_TT) {
|
||||
/* TIRA gr0,#120
|
||||
* u32 __atomic_user_cmpxchg32(u32 *ptr, u32 test, u32 new)
|
||||
*/
|
||||
case TBR_TT_ATOMIC_CMPXCHG32:
|
||||
p = (unsigned long __user *) __frame->gr8;
|
||||
x = __frame->gr9;
|
||||
y = __frame->gr10;
|
||||
|
||||
for (;;) {
|
||||
ret = get_user(z, p);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
if (z != x)
|
||||
goto done;
|
||||
|
||||
spin_lock_irq(&atomic_op_lock);
|
||||
|
||||
if (__get_user(z, p) == 0) {
|
||||
if (z != x)
|
||||
goto done2;
|
||||
|
||||
if (__put_user(y, p) == 0)
|
||||
goto done2;
|
||||
goto error2;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&atomic_op_lock);
|
||||
}
|
||||
|
||||
/* TIRA gr0,#121
|
||||
* u32 __atomic_kernel_xchg32(void *v, u32 new)
|
||||
*/
|
||||
case TBR_TT_ATOMIC_XCHG32:
|
||||
p = (unsigned long __user *) __frame->gr8;
|
||||
y = __frame->gr9;
|
||||
|
||||
for (;;) {
|
||||
ret = get_user(z, p);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
spin_lock_irq(&atomic_op_lock);
|
||||
|
||||
if (__get_user(z, p) == 0) {
|
||||
if (__put_user(y, p) == 0)
|
||||
goto done2;
|
||||
goto error2;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&atomic_op_lock);
|
||||
}
|
||||
|
||||
/* TIRA gr0,#122
|
||||
* ulong __atomic_kernel_XOR_return(ulong i, ulong *v)
|
||||
*/
|
||||
case TBR_TT_ATOMIC_XOR:
|
||||
p = (unsigned long __user *) __frame->gr8;
|
||||
x = __frame->gr9;
|
||||
|
||||
for (;;) {
|
||||
ret = get_user(z, p);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
spin_lock_irq(&atomic_op_lock);
|
||||
|
||||
if (__get_user(z, p) == 0) {
|
||||
y = x ^ z;
|
||||
if (__put_user(y, p) == 0)
|
||||
goto done2;
|
||||
goto error2;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&atomic_op_lock);
|
||||
}
|
||||
|
||||
/* TIRA gr0,#123
|
||||
* ulong __atomic_kernel_OR_return(ulong i, ulong *v)
|
||||
*/
|
||||
case TBR_TT_ATOMIC_OR:
|
||||
p = (unsigned long __user *) __frame->gr8;
|
||||
x = __frame->gr9;
|
||||
|
||||
for (;;) {
|
||||
ret = get_user(z, p);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
spin_lock_irq(&atomic_op_lock);
|
||||
|
||||
if (__get_user(z, p) == 0) {
|
||||
y = x ^ z;
|
||||
if (__put_user(y, p) == 0)
|
||||
goto done2;
|
||||
goto error2;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&atomic_op_lock);
|
||||
}
|
||||
|
||||
/* TIRA gr0,#124
|
||||
* ulong __atomic_kernel_AND_return(ulong i, ulong *v)
|
||||
*/
|
||||
case TBR_TT_ATOMIC_AND:
|
||||
p = (unsigned long __user *) __frame->gr8;
|
||||
x = __frame->gr9;
|
||||
|
||||
for (;;) {
|
||||
ret = get_user(z, p);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
spin_lock_irq(&atomic_op_lock);
|
||||
|
||||
if (__get_user(z, p) == 0) {
|
||||
y = x & z;
|
||||
if (__put_user(y, p) == 0)
|
||||
goto done2;
|
||||
goto error2;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&atomic_op_lock);
|
||||
}
|
||||
|
||||
/* TIRA gr0,#125
|
||||
* int __atomic_user_sub_return(atomic_t *v, int i)
|
||||
*/
|
||||
case TBR_TT_ATOMIC_SUB:
|
||||
p = (unsigned long __user *) __frame->gr8;
|
||||
x = __frame->gr9;
|
||||
|
||||
for (;;) {
|
||||
ret = get_user(z, p);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
spin_lock_irq(&atomic_op_lock);
|
||||
|
||||
if (__get_user(z, p) == 0) {
|
||||
y = z - x;
|
||||
if (__put_user(y, p) == 0)
|
||||
goto done2;
|
||||
goto error2;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&atomic_op_lock);
|
||||
}
|
||||
|
||||
/* TIRA gr0,#126
|
||||
* int __atomic_user_add_return(atomic_t *v, int i)
|
||||
*/
|
||||
case TBR_TT_ATOMIC_ADD:
|
||||
p = (unsigned long __user *) __frame->gr8;
|
||||
x = __frame->gr9;
|
||||
|
||||
for (;;) {
|
||||
ret = get_user(z, p);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
spin_lock_irq(&atomic_op_lock);
|
||||
|
||||
if (__get_user(z, p) == 0) {
|
||||
y = z + x;
|
||||
if (__put_user(y, p) == 0)
|
||||
goto done2;
|
||||
goto error2;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&atomic_op_lock);
|
||||
}
|
||||
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
done2:
|
||||
spin_unlock_irq(&atomic_op_lock);
|
||||
done:
|
||||
if (!user_mode(__frame))
|
||||
set_fs(oldfs);
|
||||
__frame->gr5 = z;
|
||||
__frame->gr9 = y;
|
||||
return;
|
||||
|
||||
error2:
|
||||
spin_unlock_irq(&atomic_op_lock);
|
||||
error:
|
||||
if (!user_mode(__frame))
|
||||
set_fs(oldfs);
|
||||
__frame->pc -= 4;
|
||||
|
||||
die_if_kernel("-- Atomic Op Error --\n");
|
||||
|
||||
info.si_signo = SIGSEGV;
|
||||
info.si_code = SEGV_ACCERR;
|
||||
info.si_errno = 0;
|
||||
info.si_addr = (void __user *) __frame->pc;
|
||||
|
||||
force_sig_info(info.si_signo, &info, current);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
*
|
||||
*/
|
||||
asmlinkage void media_exception(unsigned long msr0, unsigned long msr1)
|
||||
{
|
||||
siginfo_t info;
|
||||
|
||||
die_if_kernel("-- Media Exception --\n"
|
||||
"MSR0 : %08lx\n"
|
||||
"MSR1 : %08lx\n",
|
||||
msr0, msr1);
|
||||
|
||||
info.si_signo = SIGFPE;
|
||||
info.si_code = FPE_MDAOVF;
|
||||
info.si_errno = 0;
|
||||
info.si_addr = (void __user *) __frame->pc;
|
||||
|
||||
force_sig_info(info.si_signo, &info, current);
|
||||
} /* end media_exception() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* instruction or data access exception
|
||||
*/
|
||||
asmlinkage void memory_access_exception(unsigned long esr0,
|
||||
unsigned long ear0,
|
||||
unsigned long epcr0)
|
||||
{
|
||||
siginfo_t info;
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
unsigned long fixup;
|
||||
|
||||
fixup = search_exception_table(__frame->pc);
|
||||
if (fixup) {
|
||||
__frame->pc = fixup;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
die_if_kernel("-- Memory Access Exception --\n"
|
||||
"ESR0 : %08lx\n"
|
||||
"EAR0 : %08lx\n"
|
||||
"EPCR0 : %08lx\n",
|
||||
esr0, ear0, epcr0);
|
||||
|
||||
info.si_signo = SIGSEGV;
|
||||
info.si_code = SEGV_ACCERR;
|
||||
info.si_errno = 0;
|
||||
info.si_addr = NULL;
|
||||
|
||||
if ((esr0 & (ESRx_VALID | ESR0_EAV)) == (ESRx_VALID | ESR0_EAV))
|
||||
info.si_addr = (void __user *) ear0;
|
||||
|
||||
force_sig_info(info.si_signo, &info, current);
|
||||
|
||||
} /* end memory_access_exception() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* data access error
|
||||
* - double-word data load from CPU control area (0xFExxxxxx)
|
||||
* - read performed on inactive or self-refreshing SDRAM
|
||||
* - error notification from slave device
|
||||
* - misaligned address
|
||||
* - access to out of bounds memory region
|
||||
* - user mode accessing privileged memory region
|
||||
* - write to R/O memory region
|
||||
*/
|
||||
asmlinkage void data_access_error(unsigned long esfr1, unsigned long esr15, unsigned long ear15)
|
||||
{
|
||||
siginfo_t info;
|
||||
|
||||
die_if_kernel("-- Data Access Error --\n"
|
||||
"ESR15 : %08lx\n"
|
||||
"EAR15 : %08lx\n",
|
||||
esr15, ear15);
|
||||
|
||||
info.si_signo = SIGSEGV;
|
||||
info.si_code = SEGV_ACCERR;
|
||||
info.si_errno = 0;
|
||||
info.si_addr = (void __user *)
|
||||
(((esr15 & (ESRx_VALID|ESR15_EAV)) == (ESRx_VALID|ESR15_EAV)) ? ear15 : 0);
|
||||
|
||||
force_sig_info(info.si_signo, &info, current);
|
||||
} /* end data_access_error() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* data store error - should only happen if accessing inactive or self-refreshing SDRAM
|
||||
*/
|
||||
asmlinkage void data_store_error(unsigned long esfr1, unsigned long esr15)
|
||||
{
|
||||
die_if_kernel("-- Data Store Error --\n"
|
||||
"ESR15 : %08lx\n",
|
||||
esr15);
|
||||
BUG();
|
||||
} /* end data_store_error() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
*
|
||||
*/
|
||||
asmlinkage void division_exception(unsigned long esfr1, unsigned long esr0, unsigned long isr)
|
||||
{
|
||||
siginfo_t info;
|
||||
|
||||
die_if_kernel("-- Division Exception --\n"
|
||||
"ESR0 : %08lx\n"
|
||||
"ISR : %08lx\n",
|
||||
esr0, isr);
|
||||
|
||||
info.si_signo = SIGFPE;
|
||||
info.si_code = FPE_INTDIV;
|
||||
info.si_errno = 0;
|
||||
info.si_addr = (void __user *) __frame->pc;
|
||||
|
||||
force_sig_info(info.si_signo, &info, current);
|
||||
} /* end division_exception() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
*
|
||||
*/
|
||||
asmlinkage void compound_exception(unsigned long esfr1,
|
||||
unsigned long esr0, unsigned long esr14, unsigned long esr15,
|
||||
unsigned long msr0, unsigned long msr1)
|
||||
{
|
||||
die_if_kernel("-- Compound Exception --\n"
|
||||
"ESR0 : %08lx\n"
|
||||
"ESR15 : %08lx\n"
|
||||
"ESR15 : %08lx\n"
|
||||
"MSR0 : %08lx\n"
|
||||
"MSR1 : %08lx\n",
|
||||
esr0, esr14, esr15, msr0, msr1);
|
||||
BUG();
|
||||
} /* end compound_exception() */
|
||||
|
||||
void show_stack(struct task_struct *task, unsigned long *sp)
|
||||
{
|
||||
}
|
||||
|
||||
void show_trace_task(struct task_struct *tsk)
|
||||
{
|
||||
printk("CONTEXT: stack=0x%lx frame=0x%p LR=0x%lx RET=0x%lx\n",
|
||||
tsk->thread.sp, tsk->thread.frame, tsk->thread.lr, tsk->thread.sched_lr);
|
||||
}
|
||||
|
||||
static const char *regnames[] = {
|
||||
"PSR ", "ISR ", "CCR ", "CCCR",
|
||||
"LR ", "LCR ", "PC ", "_stt",
|
||||
"sys ", "GR8*", "GNE0", "GNE1",
|
||||
"IACH", "IACL",
|
||||
"TBR ", "SP ", "FP ", "GR3 ",
|
||||
"GR4 ", "GR5 ", "GR6 ", "GR7 ",
|
||||
"GR8 ", "GR9 ", "GR10", "GR11",
|
||||
"GR12", "GR13", "GR14", "GR15",
|
||||
"GR16", "GR17", "GR18", "GR19",
|
||||
"GR20", "GR21", "GR22", "GR23",
|
||||
"GR24", "GR25", "GR26", "GR27",
|
||||
"EFRM", "CURR", "GR30", "BFRM"
|
||||
};
|
||||
|
||||
void show_regs(struct pt_regs *regs)
|
||||
{
|
||||
unsigned long *reg;
|
||||
int loop;
|
||||
|
||||
printk("\n");
|
||||
show_regs_print_info(KERN_DEFAULT);
|
||||
|
||||
printk("Frame: @%08lx [%s]\n",
|
||||
(unsigned long) regs,
|
||||
regs->psr & PSR_S ? "kernel" : "user");
|
||||
|
||||
reg = (unsigned long *) regs;
|
||||
for (loop = 0; loop < NR_PT_REGS; loop++) {
|
||||
printk("%s %08lx", regnames[loop + 0], reg[loop + 0]);
|
||||
|
||||
if (loop == NR_PT_REGS - 1 || loop % 5 == 4)
|
||||
printk("\n");
|
||||
else
|
||||
printk(" | ");
|
||||
}
|
||||
}
|
||||
|
||||
void die_if_kernel(const char *str, ...)
|
||||
{
|
||||
char buffer[256];
|
||||
va_list va;
|
||||
|
||||
if (user_mode(__frame))
|
||||
return;
|
||||
|
||||
va_start(va, str);
|
||||
vsnprintf(buffer, sizeof(buffer), str, va);
|
||||
va_end(va);
|
||||
|
||||
console_verbose();
|
||||
printk("\n===================================\n");
|
||||
printk("%s\n", buffer);
|
||||
show_backtrace(__frame, 0);
|
||||
|
||||
__break_hijack_kernel_event();
|
||||
do_exit(SIGSEGV);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* dump the contents of an exception frame
|
||||
*/
|
||||
static void show_backtrace_regs(struct pt_regs *frame)
|
||||
{
|
||||
unsigned long *reg;
|
||||
int loop;
|
||||
|
||||
/* print the registers for this frame */
|
||||
printk("<-- %s Frame: @%p -->\n",
|
||||
frame->psr & PSR_S ? "Kernel Mode" : "User Mode",
|
||||
frame);
|
||||
|
||||
reg = (unsigned long *) frame;
|
||||
for (loop = 0; loop < NR_PT_REGS; loop++) {
|
||||
printk("%s %08lx", regnames[loop + 0], reg[loop + 0]);
|
||||
|
||||
if (loop == NR_PT_REGS - 1 || loop % 5 == 4)
|
||||
printk("\n");
|
||||
else
|
||||
printk(" | ");
|
||||
}
|
||||
|
||||
printk("--------\n");
|
||||
} /* end show_backtrace_regs() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* generate a backtrace of the kernel stack
|
||||
*/
|
||||
void show_backtrace(struct pt_regs *frame, unsigned long sp)
|
||||
{
|
||||
struct pt_regs *frame0;
|
||||
unsigned long tos = 0, stop = 0, base;
|
||||
int format;
|
||||
|
||||
base = ((((unsigned long) frame) + 8191) & ~8191) - sizeof(struct user_context);
|
||||
frame0 = (struct pt_regs *) base;
|
||||
|
||||
if (sp) {
|
||||
tos = sp;
|
||||
stop = (unsigned long) frame;
|
||||
}
|
||||
|
||||
printk("\nProcess %s (pid: %d)\n\n", current->comm, current->pid);
|
||||
|
||||
for (;;) {
|
||||
/* dump stack segment between frames */
|
||||
//printk("%08lx -> %08lx\n", tos, stop);
|
||||
format = 0;
|
||||
while (tos < stop) {
|
||||
if (format == 0)
|
||||
printk(" %04lx :", tos & 0xffff);
|
||||
|
||||
printk(" %08lx", *(unsigned long *) tos);
|
||||
|
||||
tos += 4;
|
||||
format++;
|
||||
if (format == 8) {
|
||||
printk("\n");
|
||||
format = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (format > 0)
|
||||
printk("\n");
|
||||
|
||||
/* dump frame 0 outside of the loop */
|
||||
if (frame == frame0)
|
||||
break;
|
||||
|
||||
tos = frame->sp;
|
||||
if (((unsigned long) frame) + sizeof(*frame) != tos) {
|
||||
printk("-- TOS %08lx does not follow frame %p --\n",
|
||||
tos, frame);
|
||||
break;
|
||||
}
|
||||
|
||||
show_backtrace_regs(frame);
|
||||
|
||||
/* dump the stack between this frame and the next */
|
||||
stop = (unsigned long) frame->next_frame;
|
||||
if (stop != base &&
|
||||
(stop < tos ||
|
||||
stop > base ||
|
||||
(stop < base && stop + sizeof(*frame) > base) ||
|
||||
stop & 3)) {
|
||||
printk("-- next_frame %08lx is invalid (range %08lx-%08lx) --\n",
|
||||
stop, tos, base);
|
||||
break;
|
||||
}
|
||||
|
||||
/* move to next frame */
|
||||
frame = frame->next_frame;
|
||||
}
|
||||
|
||||
/* we can always dump frame 0, even if the rest of the stack is corrupt */
|
||||
show_backtrace_regs(frame0);
|
||||
|
||||
} /* end show_backtrace() */
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* initialise traps
|
||||
*/
|
||||
void __init trap_init (void)
|
||||
{
|
||||
} /* end trap_init() */
|
100
arch/frv/kernel/uaccess.c
Normal file
100
arch/frv/kernel/uaccess.c
Normal file
|
@ -0,0 +1,100 @@
|
|||
/* uaccess.c: userspace access functions
|
||||
*
|
||||
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* copy a null terminated string from userspace
|
||||
*/
|
||||
long strncpy_from_user(char *dst, const char __user *src, long count)
|
||||
{
|
||||
unsigned long max;
|
||||
char *p, ch;
|
||||
long err = -EFAULT;
|
||||
|
||||
BUG_ON(count < 0);
|
||||
|
||||
p = dst;
|
||||
|
||||
#ifndef CONFIG_MMU
|
||||
if ((unsigned long) src < memory_start)
|
||||
goto error;
|
||||
#endif
|
||||
|
||||
if ((unsigned long) src >= get_addr_limit())
|
||||
goto error;
|
||||
|
||||
max = get_addr_limit() - (unsigned long) src;
|
||||
if ((unsigned long) count > max) {
|
||||
memset(dst + max, 0, count - max);
|
||||
count = max;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
for (; count > 0; count--, p++, src++) {
|
||||
__get_user_asm(err, ch, src, "ub", "=r");
|
||||
if (err < 0)
|
||||
goto error;
|
||||
if (!ch)
|
||||
break;
|
||||
*p = ch;
|
||||
}
|
||||
|
||||
err = p - dst; /* return length excluding NUL */
|
||||
|
||||
error:
|
||||
if (count > 0)
|
||||
memset(p, 0, count); /* clear remainder of buffer [security] */
|
||||
|
||||
return err;
|
||||
|
||||
} /* end strncpy_from_user() */
|
||||
|
||||
EXPORT_SYMBOL(strncpy_from_user);
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* Return the size of a string (including the ending 0)
|
||||
*
|
||||
* Return 0 on exception, a value greater than N if too long
|
||||
*/
|
||||
long strnlen_user(const char __user *src, long count)
|
||||
{
|
||||
const char __user *p;
|
||||
long err = 0;
|
||||
char ch;
|
||||
|
||||
BUG_ON(count < 0);
|
||||
|
||||
#ifndef CONFIG_MMU
|
||||
if ((unsigned long) src < memory_start)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
if ((unsigned long) src >= get_addr_limit())
|
||||
return 0;
|
||||
|
||||
for (p = src; count > 0; count--, p++) {
|
||||
__get_user_asm(err, ch, p, "ub", "=r");
|
||||
if (err < 0)
|
||||
return 0;
|
||||
if (!ch)
|
||||
break;
|
||||
}
|
||||
|
||||
return p - src + 1; /* return length including NUL */
|
||||
|
||||
} /* end strnlen_user() */
|
||||
|
||||
EXPORT_SYMBOL(strnlen_user);
|
132
arch/frv/kernel/vmlinux.lds.S
Normal file
132
arch/frv/kernel/vmlinux.lds.S
Normal file
|
@ -0,0 +1,132 @@
|
|||
/* ld script to make FRV Linux kernel
|
||||
* Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
|
||||
*/
|
||||
OUTPUT_FORMAT("elf32-frv", "elf32-frv", "elf32-frv")
|
||||
OUTPUT_ARCH(frv)
|
||||
ENTRY(_start)
|
||||
|
||||
#include <asm-generic/vmlinux.lds.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/cache.h>
|
||||
#include <asm/thread_info.h>
|
||||
|
||||
jiffies = jiffies_64 + 4;
|
||||
|
||||
__page_offset = CONFIG_PAGE_OFFSET; /* start of area covered by struct pages */
|
||||
__kernel_image_start = __page_offset; /* address at which kernel image resides */
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = __kernel_image_start;
|
||||
|
||||
/* discardable initialisation code and data */
|
||||
. = ALIGN(PAGE_SIZE); /* Init code and data */
|
||||
__init_begin = .;
|
||||
|
||||
_sinittext = .;
|
||||
.init.text : {
|
||||
HEAD_TEXT
|
||||
#ifndef CONFIG_DEBUG_INFO
|
||||
INIT_TEXT
|
||||
EXIT_TEXT
|
||||
EXIT_DATA
|
||||
*(.exitcall.exit)
|
||||
#endif
|
||||
}
|
||||
_einittext = .;
|
||||
|
||||
INIT_DATA_SECTION(8)
|
||||
PERCPU_SECTION(L1_CACHE_BYTES)
|
||||
|
||||
. = ALIGN(PAGE_SIZE);
|
||||
__init_end = .;
|
||||
|
||||
.trap : {
|
||||
/* trap table management - read entry-table.S before modifying */
|
||||
. = ALIGN(8192);
|
||||
__trap_tables = .;
|
||||
*(.trap.user)
|
||||
*(.trap.kernel)
|
||||
. = ALIGN(4096);
|
||||
*(.trap.break)
|
||||
}
|
||||
|
||||
/* Text and read-only data */
|
||||
. = ALIGN(4);
|
||||
_text = .;
|
||||
_stext = .;
|
||||
.text : {
|
||||
*(.text..start)
|
||||
*(.text..entry)
|
||||
*(.text..break)
|
||||
*(.text..tlbmiss)
|
||||
TEXT_TEXT
|
||||
SCHED_TEXT
|
||||
LOCK_TEXT
|
||||
#ifdef CONFIG_DEBUG_INFO
|
||||
INIT_TEXT
|
||||
EXIT_TEXT
|
||||
*(.exitcall.exit)
|
||||
#endif
|
||||
*(.fixup)
|
||||
*(.gnu.warning)
|
||||
*(.exitcall.exit)
|
||||
} = 0x9090
|
||||
|
||||
_etext = .; /* End of text section */
|
||||
|
||||
RODATA
|
||||
|
||||
.rodata : {
|
||||
*(.trap.vector)
|
||||
|
||||
/* this clause must not be modified - the ordering and adjacency are imperative */
|
||||
__trap_fixup_tables = .;
|
||||
*(.trap.fixup.user .trap.fixup.kernel)
|
||||
|
||||
}
|
||||
|
||||
EXCEPTION_TABLE(8)
|
||||
|
||||
_sdata = .;
|
||||
.data : { /* Data */
|
||||
INIT_TASK_DATA(THREAD_SIZE)
|
||||
CACHELINE_ALIGNED_DATA(L1_CACHE_BYTES)
|
||||
DATA_DATA
|
||||
*(.data.*)
|
||||
EXIT_DATA
|
||||
CONSTRUCTORS
|
||||
}
|
||||
|
||||
_edata = .; /* End of data section */
|
||||
|
||||
/* GP section */
|
||||
. = ALIGN(L1_CACHE_BYTES);
|
||||
_gp = . + 2048;
|
||||
PROVIDE (gp = _gp);
|
||||
|
||||
.sdata : { *(.sdata .sdata.*) }
|
||||
|
||||
/* BSS */
|
||||
. = ALIGN(L1_CACHE_BYTES);
|
||||
__bss_start = .;
|
||||
|
||||
.sbss : { *(.sbss .sbss.*) }
|
||||
.bss : { *(.bss .bss.*) }
|
||||
.bss..stack : { *(.bss) }
|
||||
|
||||
__bss_stop = .;
|
||||
_end = . ;
|
||||
. = ALIGN(PAGE_SIZE);
|
||||
__kernel_image_end = .;
|
||||
|
||||
STABS_DEBUG
|
||||
DWARF_DEBUG
|
||||
|
||||
.comment 0 : { *(.comment) }
|
||||
|
||||
DISCARDS
|
||||
}
|
||||
|
||||
__kernel_image_size_no_bss = __bss_start - __kernel_image_start;
|
Loading…
Add table
Add a link
Reference in a new issue