Merge tag 'csky-for-linus-4.21' of git://github.com/c-sky/csky-linux

Pull arch/csky updates from Guo Ren:
 "Here are three main features (cpu_hotplug, basic ftrace, basic perf)
  and some bugfixes:

  Features:
   - Add CPU-hotplug support for SMP
   - Add ftrace with function trace and function graph trace
   - Add Perf support
   - Add EM_CSKY_OLD 39
   - optimize kernel panic print.
   - remove syscall_exit_work

  Bugfixes:
   - fix abiv2 mmap(... O_SYNC) failure
   - fix gdb coredump error
   - remove vdsp implement for kernel
   - fix qemu failure to bootup sometimes
   - fix ftrace call-graph panic
   - fix device tree node reference leak
   - remove meaningless header-y
   - fix save hi,lo,dspcr regs in switch_stack
   - remove unused members in processor.h"

* tag 'csky-for-linus-4.21' of git://github.com/c-sky/csky-linux:
  csky: Add perf support for C-SKY
  csky: Add EM_CSKY_OLD 39
  clocksource/drivers/c-sky: fixup ftrace call-graph panic
  csky: ftrace call graph supported.
  csky: basic ftrace supported
  csky: remove unused members in processor.h
  csky: optimize kernel panic print.
  csky: stacktrace supported.
  csky: CPU-hotplug supported for SMP
  clocksource/drivers/c-sky: fixup qemu fail to bootup sometimes.
  csky: fixup save hi,lo,dspcr regs in switch_stack.
  csky: remove syscall_exit_work
  csky: fixup remove vdsp implement for kernel.
  csky: bugfix gdb coredump error.
  csky: fixup abiv2 mmap(... O_SYNC) failed.
  csky: define syscall_get_arch()
  elf-em.h: add EM_CSKY
  csky: remove meaningless header-y
  csky: Don't leak device tree node reference
This commit is contained in:
Linus Torvalds
2019-01-05 09:50:07 -08:00
當前提交 9ee3b3f4a5
共有 36 個文件被更改,包括 1555 次插入222 次删除

查看文件

@@ -6,3 +6,10 @@ obj-y += process.o cpu-probe.o ptrace.o dumpstack.o
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_CSKY_PMU_V1) += perf_event.o
ifdef CONFIG_FUNCTION_TRACER
CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
endif

查看文件

@@ -20,12 +20,9 @@ int main(void)
/* offsets into the thread struct */
DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
DEFINE(THREAD_SR, offsetof(struct thread_struct, sr));
DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0));
DEFINE(THREAD_FESR, offsetof(struct thread_struct, user_fp.fesr));
DEFINE(THREAD_FCR, offsetof(struct thread_struct, user_fp.fcr));
DEFINE(THREAD_FPREG, offsetof(struct thread_struct, user_fp.vr));
DEFINE(THREAD_DSPHI, offsetof(struct thread_struct, hi));
DEFINE(THREAD_DSPLO, offsetof(struct thread_struct, lo));
/* offsets into the thread_info struct */
DEFINE(TINFO_FLAGS, offsetof(struct thread_info, flags));

查看文件

@@ -7,60 +7,39 @@ int kstack_depth_to_print = 48;
void show_trace(unsigned long *stack)
{
unsigned long *endstack;
unsigned long *stack_end;
unsigned long *stack_start;
unsigned long *fp;
unsigned long addr;
int i;
pr_info("Call Trace:\n");
addr = (unsigned long)stack + THREAD_SIZE - 1;
endstack = (unsigned long *)(addr & -THREAD_SIZE);
i = 0;
while (stack + 1 <= endstack) {
addr = *stack++;
/*
* If the address is either in the text segment of the
* kernel, or in the region which contains vmalloc'ed
* memory, it *may* be the address of a calling
* routine; if so, print it so that someone tracing
* down the cause of the crash will be able to figure
* out the call path that was taken.
*/
if (__kernel_text_address(addr)) {
#ifndef CONFIG_KALLSYMS
if (i % 5 == 0)
pr_cont("\n ");
addr = (unsigned long) stack & THREAD_MASK;
stack_start = (unsigned long *) addr;
stack_end = (unsigned long *) (addr + THREAD_SIZE);
fp = stack;
pr_info("\nCall Trace:");
while (fp > stack_start && fp < stack_end) {
#ifdef CONFIG_STACKTRACE
addr = fp[1];
fp = (unsigned long *) fp[0];
#else
addr = *fp++;
#endif
pr_cont(" [<%08lx>] %pS\n", addr, (void *)addr);
i++;
}
if (__kernel_text_address(addr))
pr_cont("\n[<%08lx>] %pS", addr, (void *)addr);
}
pr_cont("\n");
}
void show_stack(struct task_struct *task, unsigned long *stack)
{
unsigned long *p;
unsigned long *endstack;
int i;
if (!stack) {
if (task)
stack = (unsigned long *)task->thread.esp0;
stack = (unsigned long *)thread_saved_fp(task);
else
stack = (unsigned long *)&stack;
}
endstack = (unsigned long *)
(((unsigned long)stack + THREAD_SIZE - 1) & -THREAD_SIZE);
pr_info("Stack from %08lx:", (unsigned long)stack);
p = stack;
for (i = 0; i < kstack_depth_to_print; i++) {
if (p + 1 > endstack)
break;
if (i % 8 == 0)
pr_cont("\n ");
pr_cont(" %08lx", *p++);
}
pr_cont("\n");
show_trace(stack);
}

查看文件

@@ -122,16 +122,6 @@ ENTRY(csky_systemcall)
psrset ee, ie
/* Stack frame for syscall, origin call set_esp0 */
mov r12, sp
bmaski r11, 13
andn r12, r11
bgeni r11, 9
addi r11, 32
addu r12, r11
st sp, (r12, 0)
lrw r11, __NR_syscalls
cmphs syscallid, r11 /* Check nr of syscall */
bt ret_from_exception
@@ -183,18 +173,10 @@ ENTRY(csky_systemcall)
#endif
stw a0, (sp, LSAVE_A0) /* Save return value */
movi a0, 1 /* leave system call */
mov a1, sp /* sp = pt_regs pointer */
jbsr syscall_trace
syscall_exit_work:
ld syscallid, (sp, LSAVE_PSR)
btsti syscallid, 31
bt 2f
jmpi resume_userspace
2: RESTORE_ALL
movi a0, 1 /* leave system call */
mov a1, sp /* right now, sp --> pt_regs */
jbsr syscall_trace
br ret_from_exception
ENTRY(ret_from_kernel_thread)
jbsr schedule_tail
@@ -238,8 +220,6 @@ resume_userspace:
1: RESTORE_ALL
exit_work:
mov a0, sp /* Stack address is arg[0] */
jbsr set_esp0 /* Call C level */
btsti r8, TIF_NEED_RESCHED
bt work_resched
/* If thread_info->flag is empty, RESTORE_ALL */
@@ -354,34 +334,12 @@ ENTRY(__switch_to)
stw sp, (a3, THREAD_KSP)
#ifdef CONFIG_CPU_HAS_HILO
lrw r10, THREAD_DSPHI
add r10, a3
mfhi r6
mflo r7
stw r6, (r10, 0) /* THREAD_DSPHI */
stw r7, (r10, 4) /* THREAD_DSPLO */
mfcr r6, cr14
stw r6, (r10, 8) /* THREAD_DSPCSR */
#endif
/* Set up next process to run */
lrw a3, TASK_THREAD
addu a3, a1
ldw sp, (a3, THREAD_KSP) /* Set next kernel sp */
#ifdef CONFIG_CPU_HAS_HILO
lrw r10, THREAD_DSPHI
add r10, a3
ldw r6, (r10, 8) /* THREAD_DSPCSR */
mtcr r6, cr14
ldw r6, (r10, 0) /* THREAD_DSPHI */
ldw r7, (r10, 4) /* THREAD_DSPLO */
mthi r6
mtlo r7
#endif
ldw a2, (a3, THREAD_SR) /* Set next PSR */
mtcr a2, psr

50
arch/csky/kernel/ftrace.c Normal file
查看文件

@@ -0,0 +1,50 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
#include <linux/ftrace.h>
#include <linux/uaccess.h>
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
unsigned long frame_pointer)
{
unsigned long return_hooker = (unsigned long)&return_to_handler;
unsigned long old;
if (unlikely(atomic_read(&current->tracing_graph_pause)))
return;
old = *parent;
if (!function_graph_enter(old, self_addr,
*(unsigned long *)frame_pointer, parent)) {
/*
* For csky-gcc function has sub-call:
* subi sp, sp, 8
* stw r8, (sp, 0)
* mov r8, sp
* st.w r15, (sp, 0x4)
* push r15
* jl _mcount
* We only need set *parent for resume
*
* For csky-gcc function has no sub-call:
* subi sp, sp, 4
* stw r8, (sp, 0)
* mov r8, sp
* push r15
* jl _mcount
* We need set *parent and *(frame_pointer + 4) for resume,
* because lr is resumed twice.
*/
*parent = return_hooker;
frame_pointer += 4;
if (*(unsigned long *)frame_pointer == old)
*(unsigned long *)frame_pointer = return_hooker;
}
}
#endif
/* _mcount is defined in abi's mcount.S */
extern void _mcount(void);
EXPORT_SYMBOL(_mcount);

文件差異過大導致無法顯示 Load Diff

查看文件

@@ -93,26 +93,31 @@ int dump_task_regs(struct task_struct *tsk, elf_gregset_t *pr_regs)
unsigned long get_wchan(struct task_struct *p)
{
unsigned long esp, pc;
unsigned long stack_page;
unsigned long lr;
unsigned long *fp, *stack_start, *stack_end;
int count = 0;
if (!p || p == current || p->state == TASK_RUNNING)
return 0;
stack_page = (unsigned long)p;
esp = p->thread.esp0;
stack_start = (unsigned long *)end_of_stack(p);
stack_end = (unsigned long *)(task_stack_page(p) + THREAD_SIZE);
fp = (unsigned long *) thread_saved_fp(p);
do {
if (esp < stack_page+sizeof(struct task_struct) ||
esp >= 8184+stack_page)
if (fp < stack_start || fp > stack_end)
return 0;
/*FIXME: There's may be error here!*/
pc = ((unsigned long *)esp)[1];
/* FIXME: This depends on the order of these functions. */
if (!in_sched_functions(pc))
return pc;
esp = *(unsigned long *) esp;
#ifdef CONFIG_STACKTRACE
lr = fp[1];
fp = (unsigned long *)fp[0];
#else
lr = *fp++;
#endif
if (!in_sched_functions(lr) &&
__kernel_text_address(lr))
return lr;
} while (count++ < 16);
return 0;
}
EXPORT_SYMBOL(get_wchan);

查看文件

@@ -50,15 +50,11 @@ static void singlestep_enable(struct task_struct *tsk)
*/
void user_enable_single_step(struct task_struct *child)
{
if (child->thread.esp0 == 0)
return;
singlestep_enable(child);
}
void user_disable_single_step(struct task_struct *child)
{
if (child->thread.esp0 == 0)
return;
singlestep_disable(child);
}
@@ -95,7 +91,9 @@ static int gpr_set(struct task_struct *target,
return ret;
regs.sr = task_pt_regs(target)->sr;
#ifdef CONFIG_CPU_HAS_HILO
regs.dcsr = task_pt_regs(target)->dcsr;
#endif
task_thread_info(target)->tp_value = regs.tls;
*task_pt_regs(target) = regs;
@@ -239,6 +237,7 @@ asmlinkage void syscall_trace(int why, struct pt_regs *regs)
regs->regs[SYSTRACE_SAVENUM] = saved_why;
}
extern void show_stack(struct task_struct *task, unsigned long *stack);
void show_regs(struct pt_regs *fp)
{
unsigned long *sp;
@@ -261,35 +260,37 @@ void show_regs(struct pt_regs *fp)
(int) (((unsigned long) current) + 2 * PAGE_SIZE));
}
pr_info("PC: 0x%08lx\n", (long)fp->pc);
pr_info("PC: 0x%08lx (%pS)\n", (long)fp->pc, (void *)fp->pc);
pr_info("LR: 0x%08lx (%pS)\n", (long)fp->lr, (void *)fp->lr);
pr_info("SP: 0x%08lx\n", (long)fp);
pr_info("orig_a0: 0x%08lx\n", fp->orig_a0);
pr_info("PSR: 0x%08lx\n", (long)fp->sr);
pr_info("a0: 0x%08lx a1: 0x%08lx a2: 0x%08lx a3: 0x%08lx\n",
fp->a0, fp->a1, fp->a2, fp->a3);
pr_info(" a0: 0x%08lx a1: 0x%08lx a2: 0x%08lx a3: 0x%08lx\n",
fp->a0, fp->a1, fp->a2, fp->a3);
#if defined(__CSKYABIV2__)
pr_info("r4: 0x%08lx r5: 0x%08lx r6: 0x%08lx r7: 0x%08lx\n",
pr_info(" r4: 0x%08lx r5: 0x%08lx r6: 0x%08lx r7: 0x%08lx\n",
fp->regs[0], fp->regs[1], fp->regs[2], fp->regs[3]);
pr_info("r8: 0x%08lx r9: 0x%08lx r10: 0x%08lx r11: 0x%08lx\n",
pr_info(" r8: 0x%08lx r9: 0x%08lx r10: 0x%08lx r11: 0x%08lx\n",
fp->regs[4], fp->regs[5], fp->regs[6], fp->regs[7]);
pr_info("r12 0x%08lx r13: 0x%08lx r15: 0x%08lx\n",
pr_info("r12: 0x%08lx r13: 0x%08lx r15: 0x%08lx\n",
fp->regs[8], fp->regs[9], fp->lr);
pr_info("r16:0x%08lx r17: 0x%08lx r18: 0x%08lx r19: 0x%08lx\n",
pr_info("r16: 0x%08lx r17: 0x%08lx r18: 0x%08lx r19: 0x%08lx\n",
fp->exregs[0], fp->exregs[1], fp->exregs[2], fp->exregs[3]);
pr_info("r20 0x%08lx r21: 0x%08lx r22: 0x%08lx r23: 0x%08lx\n",
pr_info("r20: 0x%08lx r21: 0x%08lx r22: 0x%08lx r23: 0x%08lx\n",
fp->exregs[4], fp->exregs[5], fp->exregs[6], fp->exregs[7]);
pr_info("r24 0x%08lx r25: 0x%08lx r26: 0x%08lx r27: 0x%08lx\n",
pr_info("r24: 0x%08lx r25: 0x%08lx r26: 0x%08lx r27: 0x%08lx\n",
fp->exregs[8], fp->exregs[9], fp->exregs[10], fp->exregs[11]);
pr_info("r28 0x%08lx r29: 0x%08lx r30: 0x%08lx tls: 0x%08lx\n",
pr_info("r28: 0x%08lx r29: 0x%08lx r30: 0x%08lx tls: 0x%08lx\n",
fp->exregs[12], fp->exregs[13], fp->exregs[14], fp->tls);
pr_info("hi 0x%08lx lo: 0x%08lx\n",
pr_info(" hi: 0x%08lx lo: 0x%08lx\n",
fp->rhi, fp->rlo);
#else
pr_info("r6: 0x%08lx r7: 0x%08lx r8: 0x%08lx r9: 0x%08lx\n",
pr_info(" r6: 0x%08lx r7: 0x%08lx r8: 0x%08lx r9: 0x%08lx\n",
fp->regs[0], fp->regs[1], fp->regs[2], fp->regs[3]);
pr_info("r10: 0x%08lx r11: 0x%08lx r12: 0x%08lx r13: 0x%08lx\n",
pr_info("r10: 0x%08lx r11: 0x%08lx r12: 0x%08lx r13: 0x%08lx\n",
fp->regs[4], fp->regs[5], fp->regs[6], fp->regs[7]);
pr_info("r14 0x%08lx r1: 0x%08lx r15: 0x%08lx\n",
pr_info("r14: 0x%08lx r1: 0x%08lx r15: 0x%08lx\n",
fp->regs[8], fp->regs[9], fp->lr);
#endif
@@ -311,4 +312,7 @@ void show_regs(struct pt_regs *fp)
pr_cont("%08x ", (int) *sp++);
}
pr_cont("\n");
show_stack(NULL, (unsigned long *)fp->regs[4]);
return;
}

查看文件

@@ -238,8 +238,6 @@ static void do_signal(struct pt_regs *regs, int syscall)
if (!user_mode(regs))
return;
current->thread.esp0 = (unsigned long)regs;
/*
* If we were from a system call, check for system call restarting...
*/

查看文件

@@ -16,6 +16,7 @@
#include <linux/of.h>
#include <linux/sched/task_stack.h>
#include <linux/sched/mm.h>
#include <linux/sched/hotplug.h>
#include <asm/irq.h>
#include <asm/traps.h>
#include <asm/sections.h>
@@ -112,12 +113,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
{
}
static void __init enable_smp_ipi(void)
{
enable_percpu_irq(ipi_irq, 0);
}
static int ipi_dummy_dev;
void __init setup_smp_ipi(void)
{
int rc;
@@ -130,7 +127,7 @@ void __init setup_smp_ipi(void)
if (rc)
panic("%s IRQ request failed\n", __func__);
enable_smp_ipi();
enable_percpu_irq(ipi_irq, 0);
}
void __init setup_smp(void)
@@ -138,7 +135,7 @@ void __init setup_smp(void)
struct device_node *node = NULL;
int cpu;
while ((node = of_find_node_by_type(node, "cpu"))) {
for_each_of_cpu_node(node) {
if (!of_device_is_available(node))
continue;
@@ -161,12 +158,10 @@ volatile unsigned int secondary_stack;
int __cpu_up(unsigned int cpu, struct task_struct *tidle)
{
unsigned int tmp;
secondary_stack = (unsigned int)tidle->stack + THREAD_SIZE;
unsigned long mask = 1 << cpu;
secondary_stack = (unsigned int)tidle->stack + THREAD_SIZE - 8;
secondary_hint = mfcr("cr31");
secondary_ccr = mfcr("cr18");
/*
@@ -176,10 +171,13 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle)
*/
mtcr("cr17", 0x22);
/* Enable cpu in SMP reset ctrl reg */
tmp = mfcr("cr<29, 0>");
tmp |= 1 << cpu;
mtcr("cr<29, 0>", tmp);
if (mask & mfcr("cr<29, 0>")) {
send_arch_ipi(cpumask_of(cpu));
} else {
/* Enable cpu in SMP reset ctrl reg */
mask |= mfcr("cr<29, 0>");
mtcr("cr<29, 0>", mask);
}
/* Wait for the cpu online */
while (!cpu_online(cpu));
@@ -219,7 +217,7 @@ void csky_start_secondary(void)
init_fpu();
#endif
enable_smp_ipi();
enable_percpu_irq(ipi_irq, 0);
mmget(mm);
mmgrab(mm);
@@ -235,3 +233,46 @@ void csky_start_secondary(void)
preempt_disable();
cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
}
#ifdef CONFIG_HOTPLUG_CPU
int __cpu_disable(void)
{
unsigned int cpu = smp_processor_id();
set_cpu_online(cpu, false);
irq_migrate_all_off_this_cpu();
clear_tasks_mm_cpumask(cpu);
return 0;
}
void __cpu_die(unsigned int cpu)
{
if (!cpu_wait_death(cpu, 5)) {
pr_crit("CPU%u: shutdown failed\n", cpu);
return;
}
pr_notice("CPU%u: shutdown\n", cpu);
}
void arch_cpu_idle_dead(void)
{
idle_task_exit();
cpu_report_death();
while (!secondary_stack)
arch_cpu_idle();
local_irq_disable();
asm volatile(
"mov sp, %0\n"
"mov r8, %0\n"
"jmpi csky_start_secondary"
:
: "r" (secondary_stack));
}
#endif

查看文件

@@ -0,0 +1,57 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. */
#include <linux/sched/debug.h>
#include <linux/sched/task_stack.h>
#include <linux/stacktrace.h>
#include <linux/ftrace.h>
void save_stack_trace(struct stack_trace *trace)
{
save_stack_trace_tsk(current, trace);
}
EXPORT_SYMBOL_GPL(save_stack_trace);
void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
{
unsigned long *fp, *stack_start, *stack_end;
unsigned long addr;
int skip = trace->skip;
int savesched;
int graph_idx = 0;
if (tsk == current) {
asm volatile("mov %0, r8\n":"=r"(fp));
savesched = 1;
} else {
fp = (unsigned long *)thread_saved_fp(tsk);
savesched = 0;
}
addr = (unsigned long) fp & THREAD_MASK;
stack_start = (unsigned long *) addr;
stack_end = (unsigned long *) (addr + THREAD_SIZE);
while (fp > stack_start && fp < stack_end) {
unsigned long lpp, fpp;
fpp = fp[0];
lpp = fp[1];
if (!__kernel_text_address(lpp))
break;
else
lpp = ftrace_graph_ret_addr(tsk, &graph_idx, lpp, NULL);
if (savesched || !in_sched_functions(lpp)) {
if (skip) {
skip--;
} else {
trace->entries[trace->nr_entries++] = lpp;
if (trace->nr_entries >= trace->max_entries)
break;
}
}
fp = (unsigned long *)fpp;
}
}
EXPORT_SYMBOL_GPL(save_stack_trace_tsk);

查看文件

@@ -106,7 +106,6 @@ void buserr(struct pt_regs *regs)
pr_err("User mode Bus Error\n");
show_regs(regs);
current->thread.esp0 = (unsigned long) regs;
force_sig_fault(SIGSEGV, 0, (void __user *)regs->pc, current);
}
@@ -162,8 +161,3 @@ asmlinkage void trap_c(struct pt_regs *regs)
}
send_sig(sig, current, 0);
}
asmlinkage void set_esp0(unsigned long ssp)
{
current->thread.esp0 = ssp;
}