Skip to content

Commit

Permalink
ARC: Process-creation/scheduling/idle-loop
Browse files Browse the repository at this point in the history
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>
  • Loading branch information
Vineet Gupta committed Feb 11, 2013
1 parent 4adeefe commit bf90e1e
Show file tree
Hide file tree
Showing 10 changed files with 484 additions and 8 deletions.
2 changes: 2 additions & 0 deletions arch/arc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ config ARC
select GENERIC_FIND_FIRST_BIT
# for now, we don't need GENERIC_IRQ_PROBE, CONFIG_GENERIC_IRQ_CHIP
select GENERIC_IRQ_SHOW
select GENERIC_KERNEL_EXECVE
select GENERIC_KERNEL_THREAD
select GENERIC_PENDING_IRQ if SMP
select GENERIC_SMP_IDLE_THREAD
select HAVE_GENERIC_HARDIRQS
Expand Down
20 changes: 20 additions & 0 deletions arch/arc/include/asm/arcregs.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@
#define AUX_ITRIGGER 0x40d
#define AUX_IPULSE 0x415

/*
* Floating Pt Registers
* Status regs are read-only (build-time) so need not be saved/restored
*/
#define ARC_AUX_FP_STAT 0x300
#define ARC_AUX_DPFP_1L 0x301
#define ARC_AUX_DPFP_1H 0x302
#define ARC_AUX_DPFP_2L 0x303
#define ARC_AUX_DPFP_2H 0x304
#define ARC_AUX_DPFP_STAT 0x305

#ifndef __ASSEMBLY__

/*
Expand Down Expand Up @@ -110,6 +121,15 @@

#endif

#ifdef CONFIG_ARC_FPU_SAVE_RESTORE
/* These DPFP regs need to be saved/restored across ctx-sw */
struct arc_fpu {
struct {
unsigned int l, h;
} aux_dpfp[2];
};
#endif

#endif /* __ASEMBLY__ */

#endif /* __KERNEL__ */
Expand Down
9 changes: 3 additions & 6 deletions arch/arc/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ struct thread_struct {
unsigned long callee_reg; /* pointer to callee regs */
unsigned long fault_address; /* dbls as brkpt holder as well */
unsigned long cause_code; /* Exception Cause Code (ECR) */
#ifdef CONFIG_ARC_FPU_SAVE_RESTORE
struct arc_fpu fpu;
#endif
};

#define INIT_THREAD { \
Expand All @@ -54,12 +57,6 @@ unsigned long thread_saved_pc(struct task_struct *t);

#define cpu_relax() do { } while (0)

/*
* Create a new kernel thread
*/

extern int kernel_thread(int (*fn) (void *), void *arg, unsigned long flags);

#define copy_segments(tsk, mm) do { } while (0)
#define release_segments(mm) do { } while (0)

Expand Down
8 changes: 8 additions & 0 deletions arch/arc/include/asm/ptrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ struct callee_regs {
#define in_syscall(regs) (((regs->orig_r8) >= 0 && \
(regs->orig_r8 <= NR_syscalls)) ? 1 : 0)

#define current_pt_regs() \
({ \
/* open-coded current_thread_info() */ \
register unsigned long sp asm ("sp"); \
unsigned long pg_start = (sp & ~(THREAD_SIZE - 1)); \
(struct pt_regs *)(pg_start + THREAD_SIZE - 4) - 1; \
})

#endif /* !__ASSEMBLY__ */

#endif /* __KERNEL__ */
Expand Down
41 changes: 41 additions & 0 deletions arch/arc/include/asm/switch_to.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/

#ifndef _ASM_ARC_SWITCH_TO_H
#define _ASM_ARC_SWITCH_TO_H

#ifndef __ASSEMBLY__

#include <linux/sched.h>

#ifdef CONFIG_ARC_FPU_SAVE_RESTORE

extern void fpu_save_restore(struct task_struct *p, struct task_struct *n);
#define ARC_FPU_PREV(p, n) fpu_save_restore(p, n)
#define ARC_FPU_NEXT(t)

#else

#define ARC_FPU_PREV(p, n)
#define ARC_FPU_NEXT(n)

#endif /* !CONFIG_ARC_FPU_SAVE_RESTORE */

struct task_struct *__switch_to(struct task_struct *p, struct task_struct *n);

#define switch_to(prev, next, last) \
do { \
ARC_FPU_PREV(prev, next); \
last = __switch_to(prev, next);\
ARC_FPU_NEXT(next); \
mb(); \
} while (0)

#endif

#endif
91 changes: 91 additions & 0 deletions arch/arc/kernel/ctx_sw.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Vineetg: Aug 2009
* -"C" version of lowest level context switch asm macro called by schedular
* gcc doesn't generate the dward CFI info for hand written asm, hence can't
* backtrace out of it (e.g. tasks sleeping in kernel).
* So we cheat a bit by writing almost similar code in inline-asm.
* -This is a hacky way of doing things, but there is no other simple way.
* I don't want/intend to extend unwinding code to understand raw asm
*/

#include <asm/asm-offsets.h>
#include <linux/sched.h>

struct task_struct *__sched
__switch_to(struct task_struct *prev_task, struct task_struct *next_task)
{
unsigned int tmp;
unsigned int prev = (unsigned int)prev_task;
unsigned int next = (unsigned int)next_task;
int num_words_to_skip = 1;

__asm__ __volatile__(
/* FP/BLINK save generated by gcc (standard function prologue */
"st.a r13, [sp, -4] \n\t"
"st.a r14, [sp, -4] \n\t"
"st.a r15, [sp, -4] \n\t"
"st.a r16, [sp, -4] \n\t"
"st.a r17, [sp, -4] \n\t"
"st.a r18, [sp, -4] \n\t"
"st.a r19, [sp, -4] \n\t"
"st.a r20, [sp, -4] \n\t"
"st.a r21, [sp, -4] \n\t"
"st.a r22, [sp, -4] \n\t"
"st.a r23, [sp, -4] \n\t"
"st.a r24, [sp, -4] \n\t"
"st.a r25, [sp, -4] \n\t"
"sub sp, sp, %4 \n\t" /* create gutter at top */

/* set ksp of outgoing task in tsk->thread.ksp */
"st.as sp, [%3, %1] \n\t"

"sync \n\t"

/*
* setup _current_task with incoming tsk.
* optionally, set r25 to that as well
* For SMP extra work to get to &_current_task[cpu]
* (open coded SET_CURR_TASK_ON_CPU)
*/
"st %2, [@_current_task] \n\t"

/* get ksp of incoming task from tsk->thread.ksp */
"ld.as sp, [%2, %1] \n\t"

/* start loading it's CALLEE reg file */

"add sp, sp, %4 \n\t" /* skip gutter at top */

"ld.ab r25, [sp, 4] \n\t"
"ld.ab r24, [sp, 4] \n\t"
"ld.ab r23, [sp, 4] \n\t"
"ld.ab r22, [sp, 4] \n\t"
"ld.ab r21, [sp, 4] \n\t"
"ld.ab r20, [sp, 4] \n\t"
"ld.ab r19, [sp, 4] \n\t"
"ld.ab r18, [sp, 4] \n\t"
"ld.ab r17, [sp, 4] \n\t"
"ld.ab r16, [sp, 4] \n\t"
"ld.ab r15, [sp, 4] \n\t"
"ld.ab r14, [sp, 4] \n\t"
"ld.ab r13, [sp, 4] \n\t"

/* last (ret value) = prev : although for ARC it mov r0, r0 */
"mov %0, %3 \n\t"

/* FP/BLINK restore generated by gcc (standard func epilogue */

: "=r"(tmp)
: "n"((TASK_THREAD + THREAD_KSP) / 4), "r"(next), "r"(prev),
"n"(num_words_to_skip * 4)
: "blink"
);

return (struct task_struct *)tmp;
}
58 changes: 58 additions & 0 deletions arch/arc/kernel/ctx_sw_asm.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Vineetg: Aug 2009
* -Moved core context switch macro out of entry.S into this file.
* -This is the more "natural" hand written assembler
*/

#include <asm/entry.h> /* For the SAVE_* macros */
#include <asm/asm-offsets.h>
#include <asm/linkage.h>

;################### Low Level Context Switch ##########################

.section .sched.text,"ax",@progbits
.align 4
.global __switch_to
.type __switch_to, @function
__switch_to:

/* Save regs on kernel mode stack of task */
st.a blink, [sp, -4]
st.a fp, [sp, -4]
SAVE_CALLEE_SAVED_KERNEL

/* Save the now KSP in task->thread.ksp */
st.as sp, [r0, (TASK_THREAD + THREAD_KSP)/4]

/*
* Return last task in r0 (return reg)
* On ARC, Return reg = First Arg reg = r0.
* Since we already have last task in r0,
* don't need to do anything special to return it
*/

/* hardware memory barrier */
sync

/*
* switch to new task, contained in r1
* Temp reg r3 is required to get the ptr to store val
*/
SET_CURR_TASK_ON_CPU r1, r3

/* reload SP with kernel mode stack pointer in task->thread.ksp */
ld.as sp, [r1, (TASK_THREAD + THREAD_KSP)/4]

/* restore the registers */
RESTORE_CALLEE_SAVED_KERNEL
ld.ab fp, [sp, 4]
ld.ab blink, [sp, 4]
j [blink]

ARC_EXIT __switch_to
15 changes: 13 additions & 2 deletions arch/arc/kernel/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -566,8 +566,19 @@ ARC_ENTRY ret_from_fork
; when the forked child comes here from the __switch_to function
; r0 has the last task pointer.
; put last task in scheduler queue
bl @schedule_tail
b @ret_from_exception
bl @schedule_tail

; If kernel thread, jump to it's entry-point
ld r9, [sp, PT_status32]
brne r9, 0, 1f

jl.d [r14]
mov r0, r13 ; arg to payload

1:
; special case of kernel_thread entry point returning back due to
; kernel_execve() - pretend return from syscall to ret to userland
b ret_from_exception
ARC_EXIT ret_from_fork

;################### Special Sys Call Wrappers ##########################
Expand Down
55 changes: 55 additions & 0 deletions arch/arc/kernel/fpu.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* fpu.c - save/restore of Floating Point Unit Registers on task switch
*
* Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/

#include <linux/sched.h>
#include <asm/switch_to.h>

/*
* To save/restore FPU regs, simplest scheme would use LR/SR insns.
* However since SR serializes the pipeline, an alternate "hack" can be used
* which uses the FPU Exchange insn (DEXCL) to r/w FPU regs.
*
* Store to 64bit dpfp1 reg from a pair of core regs:
* dexcl1 0, r1, r0 ; where r1:r0 is the 64 bit val
*
* Read from dpfp1 into pair of core regs (w/o clobbering dpfp1)
* mov_s r3, 0
* daddh11 r1, r3, r3 ; get "hi" into r1 (dpfp1 unchanged)
* dexcl1 r0, r1, r3 ; get "low" into r0 (dpfp1 low clobbered)
* dexcl1 0, r1, r0 ; restore dpfp1 to orig value
*
* However we can tweak the read, so that read-out of outgoing task's FPU regs
* and write of incoming task's regs happen in one shot. So all the work is
* done before context switch
*/

void fpu_save_restore(struct task_struct *prev, struct task_struct *next)
{
unsigned int *saveto = &prev->thread.fpu.aux_dpfp[0].l;
unsigned int *readfrom = &next->thread.fpu.aux_dpfp[0].l;

const unsigned int zero = 0;

__asm__ __volatile__(
"daddh11 %0, %2, %2\n"
"dexcl1 %1, %3, %4\n"
: "=&r" (*(saveto + 1)), /* early clobber must here */
"=&r" (*(saveto))
: "r" (zero), "r" (*(readfrom + 1)), "r" (*(readfrom))
);

__asm__ __volatile__(
"daddh22 %0, %2, %2\n"
"dexcl2 %1, %3, %4\n"
: "=&r"(*(saveto + 3)), /* early clobber must here */
"=&r"(*(saveto + 2))
: "r" (zero), "r" (*(readfrom + 3)), "r" (*(readfrom + 2))
);
}
Loading

0 comments on commit bf90e1e

Please sign in to comment.