mirror of
https://github.com/genesi/linux-legacy.git
synced 2026-05-19 13:06:19 +00:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/kyle/parisc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/kyle/parisc-2.6: (23 commits) parisc: move dereference_function_descriptor to process.c parisc: Move kernel Elf_Fdesc define to <asm/elf.h> parisc: fix build when ARCH_HAS_KMAP parisc: fix "make tar-pkg" parisc: drivers: fix warnings parisc: select BUG always parisc: asm/pdc.h should include asm/page.h parisc: led: remove proc_dir_entry::owner parisc: fix macro expansion in atomic.h parisc: iosapic: fix build breakage parisc: oops_enter()/oops_exit() in die() parisc: document light weight syscall ABI parisc: blink all or loadavg LEDs on oops parisc: add ftrace (function and graph tracer) functionality parisc: simplify sys_clone() parisc: add LATENCYTOP_SUPPORT and CONFIG_STACKTRACE_SUPPORT parisc: allow to build with 16k default kernel page size parisc: expose 32/64-bit capabilities in cpuinfo parisc: use constants instead of numbers in assembly parisc: fix usage of 32bit PTE page table entries on 32bit kernels ...
This commit is contained in:
@@ -11,10 +11,25 @@ obj-y := cache.o pacache.o setup.o traps.o time.o irq.o \
|
||||
process.o processor.o pdc_cons.o pdc_chassis.o unwind.o \
|
||||
topology.o
|
||||
|
||||
ifdef CONFIG_FUNCTION_TRACER
|
||||
# Do not profile debug and lowlevel utilities
|
||||
CFLAGS_REMOVE_ftrace.o = -pg
|
||||
CFLAGS_REMOVE_cache.o = -pg
|
||||
CFLAGS_REMOVE_irq.o = -pg
|
||||
CFLAGS_REMOVE_pacache.o = -pg
|
||||
CFLAGS_REMOVE_perf.o = -pg
|
||||
CFLAGS_REMOVE_traps.o = -pg
|
||||
CFLAGS_REMOVE_unaligned.o = -pg
|
||||
CFLAGS_REMOVE_unwind.o = -pg
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_SMP) += smp.o
|
||||
obj-$(CONFIG_PA11) += pci-dma.o
|
||||
obj-$(CONFIG_PCI) += pci.o
|
||||
obj-$(CONFIG_MODULES) += module.o
|
||||
obj-$(CONFIG_64BIT) += binfmt_elf32.o sys_parisc32.o signal32.o
|
||||
obj-$(CONFIG_STACKTRACE)+= stacktrace.o
|
||||
# only supported for PCX-W/U in 64-bit mode at the moment
|
||||
obj-$(CONFIG_64BIT) += perf.o perf_asm.o
|
||||
obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o
|
||||
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
|
||||
|
||||
@@ -505,6 +505,18 @@
|
||||
STREG \pte,0(\ptep)
|
||||
.endm
|
||||
|
||||
/* bitshift difference between a PFN (based on kernel's PAGE_SIZE)
|
||||
* to a CPU TLB 4k PFN (4k => 12 bits to shift) */
|
||||
#define PAGE_ADD_SHIFT (PAGE_SHIFT-12)
|
||||
|
||||
/* Drop prot bits and convert to page addr for iitlbt and idtlbt */
|
||||
.macro convert_for_tlb_insert20 pte
|
||||
extrd,u \pte,(63-ASM_PFN_PTE_SHIFT)+(63-58)+PAGE_ADD_SHIFT,\
|
||||
64-PAGE_SHIFT-PAGE_ADD_SHIFT,\pte
|
||||
depdi _PAGE_SIZE_ENCODING_DEFAULT,63,\
|
||||
(63-58)+PAGE_ADD_SHIFT,\pte
|
||||
.endm
|
||||
|
||||
/* Convert the pte and prot to tlb insertion values. How
|
||||
* this happens is quite subtle, read below */
|
||||
.macro make_insert_tlb spc,pte,prot
|
||||
@@ -544,8 +556,7 @@
|
||||
depi 1,12,1,\prot
|
||||
|
||||
/* Drop prot bits and convert to page addr for iitlbt and idtlbt */
|
||||
extrd,u \pte,(63-ASM_PFN_PTE_SHIFT)+(63-58),64-PAGE_SHIFT,\pte
|
||||
depdi _PAGE_SIZE_ENCODING_DEFAULT,63,63-58,\pte
|
||||
convert_for_tlb_insert20 \pte
|
||||
.endm
|
||||
|
||||
/* Identical macro to make_insert_tlb above, except it
|
||||
@@ -563,8 +574,8 @@
|
||||
|
||||
/* Get rid of prot bits and convert to page addr for iitlba */
|
||||
|
||||
depi _PAGE_SIZE_ENCODING_DEFAULT,31,ASM_PFN_PTE_SHIFT,\pte
|
||||
extru \pte,24,25,\pte
|
||||
depi 0,31,ASM_PFN_PTE_SHIFT,\pte
|
||||
SHRREG \pte,(ASM_PFN_PTE_SHIFT-(31-26)),\pte
|
||||
.endm
|
||||
|
||||
/* This is for ILP32 PA2.0 only. The TLB insertion needs
|
||||
@@ -1244,10 +1255,9 @@ nadtlb_check_flush_20w:
|
||||
depdi,z 7,7,3,prot
|
||||
depdi 1,10,1,prot
|
||||
|
||||
/* Get rid of prot bits and convert to page addr for idtlbt */
|
||||
/* Drop prot bits from pte and convert to page addr for idtlbt */
|
||||
convert_for_tlb_insert20 pte
|
||||
|
||||
depdi 0,63,12,pte
|
||||
extrd,u pte,56,52,pte
|
||||
idtlbt pte,prot
|
||||
|
||||
rfir
|
||||
@@ -1337,8 +1347,8 @@ nadtlb_check_flush_11:
|
||||
|
||||
/* Get rid of prot bits and convert to page addr for idtlba */
|
||||
|
||||
depi 0,31,12,pte
|
||||
extru pte,24,25,pte
|
||||
depi 0,31,ASM_PFN_PTE_SHIFT,pte
|
||||
SHRREG pte,(ASM_PFN_PTE_SHIFT-(31-26)),pte
|
||||
|
||||
mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
|
||||
mtsp spc,%sr1
|
||||
@@ -1403,10 +1413,9 @@ nadtlb_check_flush_20:
|
||||
depdi,z 7,7,3,prot
|
||||
depdi 1,10,1,prot
|
||||
|
||||
/* Get rid of prot bits and convert to page addr for idtlbt */
|
||||
/* Drop prot bits from pte and convert to page addr for idtlbt */
|
||||
convert_for_tlb_insert20 pte
|
||||
|
||||
depdi 0,63,12,pte
|
||||
extrd,u pte,56,32,pte
|
||||
idtlbt pte,prot
|
||||
|
||||
rfir
|
||||
@@ -2176,6 +2185,33 @@ syscall_do_resched:
|
||||
ENDPROC(syscall_exit)
|
||||
|
||||
|
||||
#ifdef CONFIG_FUNCTION_TRACER
|
||||
.import ftrace_function_trampoline,code
|
||||
ENTRY(_mcount)
|
||||
copy %r3, %arg2
|
||||
b ftrace_function_trampoline
|
||||
nop
|
||||
ENDPROC(_mcount)
|
||||
|
||||
ENTRY(return_to_handler)
|
||||
load32 return_trampoline, %rp
|
||||
copy %ret0, %arg0
|
||||
copy %ret1, %arg1
|
||||
b ftrace_return_to_handler
|
||||
nop
|
||||
return_trampoline:
|
||||
copy %ret0, %rp
|
||||
copy %r23, %ret0
|
||||
copy %r24, %ret1
|
||||
|
||||
.globl ftrace_stub
|
||||
ftrace_stub:
|
||||
bv %r0(%rp)
|
||||
nop
|
||||
ENDPROC(return_to_handler)
|
||||
#endif /* CONFIG_FUNCTION_TRACER */
|
||||
|
||||
|
||||
get_register:
|
||||
/*
|
||||
* get_register is used by the non access tlb miss handlers to
|
||||
|
||||
@@ -527,7 +527,11 @@ int pdc_model_capabilities(unsigned long *capabilities)
|
||||
pdc_result[0] = 0; /* preset zero (call may not be implemented!) */
|
||||
retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_CAPABILITIES, __pa(pdc_result), 0);
|
||||
convert_to_wide(pdc_result);
|
||||
*capabilities = pdc_result[0];
|
||||
if (retval == PDC_OK) {
|
||||
*capabilities = pdc_result[0];
|
||||
} else {
|
||||
*capabilities = PDC_MODEL_OS32;
|
||||
}
|
||||
spin_unlock_irqrestore(&pdc_lock, flags);
|
||||
|
||||
return retval;
|
||||
|
||||
185
arch/parisc/kernel/ftrace.c
Normal file
185
arch/parisc/kernel/ftrace.c
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Code for tracing calls in Linux kernel.
|
||||
* Copyright (C) 2009 Helge Deller <deller@gmx.de>
|
||||
*
|
||||
* based on code for x86 which is:
|
||||
* Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
|
||||
*
|
||||
* future possible enhancements:
|
||||
* - add CONFIG_DYNAMIC_FTRACE
|
||||
* - add CONFIG_STACK_TRACER
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/ftrace.h>
|
||||
|
||||
#include <asm/sections.h>
|
||||
#include <asm/ftrace.h>
|
||||
|
||||
|
||||
|
||||
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||
|
||||
/* Add a function return address to the trace stack on thread info.*/
|
||||
static int push_return_trace(unsigned long ret, unsigned long long time,
|
||||
unsigned long func, int *depth)
|
||||
{
|
||||
int index;
|
||||
|
||||
if (!current->ret_stack)
|
||||
return -EBUSY;
|
||||
|
||||
/* The return trace stack is full */
|
||||
if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) {
|
||||
atomic_inc(¤t->trace_overrun);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
index = ++current->curr_ret_stack;
|
||||
barrier();
|
||||
current->ret_stack[index].ret = ret;
|
||||
current->ret_stack[index].func = func;
|
||||
current->ret_stack[index].calltime = time;
|
||||
*depth = index;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Retrieve a function return address to the trace stack on thread info.*/
|
||||
static void pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret)
|
||||
{
|
||||
int index;
|
||||
|
||||
index = current->curr_ret_stack;
|
||||
|
||||
if (unlikely(index < 0)) {
|
||||
ftrace_graph_stop();
|
||||
WARN_ON(1);
|
||||
/* Might as well panic, otherwise we have no where to go */
|
||||
*ret = (unsigned long)
|
||||
dereference_function_descriptor(&panic);
|
||||
return;
|
||||
}
|
||||
|
||||
*ret = current->ret_stack[index].ret;
|
||||
trace->func = current->ret_stack[index].func;
|
||||
trace->calltime = current->ret_stack[index].calltime;
|
||||
trace->overrun = atomic_read(¤t->trace_overrun);
|
||||
trace->depth = index;
|
||||
barrier();
|
||||
current->curr_ret_stack--;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Send the trace to the ring-buffer.
|
||||
* @return the original return address.
|
||||
*/
|
||||
unsigned long ftrace_return_to_handler(unsigned long retval0,
|
||||
unsigned long retval1)
|
||||
{
|
||||
struct ftrace_graph_ret trace;
|
||||
unsigned long ret;
|
||||
|
||||
pop_return_trace(&trace, &ret);
|
||||
trace.rettime = cpu_clock(raw_smp_processor_id());
|
||||
ftrace_graph_return(&trace);
|
||||
|
||||
if (unlikely(!ret)) {
|
||||
ftrace_graph_stop();
|
||||
WARN_ON(1);
|
||||
/* Might as well panic. What else to do? */
|
||||
ret = (unsigned long)
|
||||
dereference_function_descriptor(&panic);
|
||||
}
|
||||
|
||||
/* HACK: we hand over the old functions' return values
|
||||
in %r23 and %r24. Assembly in entry.S will take care
|
||||
and move those to their final registers %ret0 and %ret1 */
|
||||
asm( "copy %0, %%r23 \n\t"
|
||||
"copy %1, %%r24 \n" : : "r" (retval0), "r" (retval1) );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hook the return address and push it in the stack of return addrs
|
||||
* in current thread info.
|
||||
*/
|
||||
void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
|
||||
{
|
||||
unsigned long old;
|
||||
unsigned long long calltime;
|
||||
struct ftrace_graph_ent trace;
|
||||
|
||||
if (unlikely(atomic_read(¤t->tracing_graph_pause)))
|
||||
return;
|
||||
|
||||
old = *parent;
|
||||
*parent = (unsigned long)
|
||||
dereference_function_descriptor(&return_to_handler);
|
||||
|
||||
if (unlikely(!__kernel_text_address(old))) {
|
||||
ftrace_graph_stop();
|
||||
*parent = old;
|
||||
WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
|
||||
calltime = cpu_clock(raw_smp_processor_id());
|
||||
|
||||
if (push_return_trace(old, calltime,
|
||||
self_addr, &trace.depth) == -EBUSY) {
|
||||
*parent = old;
|
||||
return;
|
||||
}
|
||||
|
||||
trace.func = self_addr;
|
||||
|
||||
/* Only trace if the calling function expects to */
|
||||
if (!ftrace_graph_entry(&trace)) {
|
||||
current->curr_ret_stack--;
|
||||
*parent = old;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
|
||||
|
||||
|
||||
void ftrace_function_trampoline(unsigned long parent,
|
||||
unsigned long self_addr,
|
||||
unsigned long org_sp_gr3)
|
||||
{
|
||||
extern ftrace_func_t ftrace_trace_function;
|
||||
|
||||
if (function_trace_stop)
|
||||
return;
|
||||
|
||||
if (ftrace_trace_function != ftrace_stub) {
|
||||
ftrace_trace_function(parent, self_addr);
|
||||
return;
|
||||
}
|
||||
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||
if (ftrace_graph_entry && ftrace_graph_return) {
|
||||
unsigned long sp;
|
||||
unsigned long *parent_rp;
|
||||
|
||||
asm volatile ("copy %%r30, %0" : "=r"(sp));
|
||||
/* sanity check: is stack pointer which we got from
|
||||
assembler function in entry.S in a reasonable
|
||||
range compared to current stack pointer? */
|
||||
if ((sp - org_sp_gr3) > 0x400)
|
||||
return;
|
||||
|
||||
/* calculate pointer to %rp in stack */
|
||||
parent_rp = (unsigned long *) org_sp_gr3 - 0x10;
|
||||
/* sanity check: parent_rp should hold parent */
|
||||
if (*parent_rp != parent)
|
||||
return;
|
||||
|
||||
prepare_ftrace_return(parent_rp, self_addr);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -311,12 +311,12 @@ unsigned long txn_alloc_addr(unsigned int virt_irq)
|
||||
next_cpu++; /* assign to "next" CPU we want this bugger on */
|
||||
|
||||
/* validate entry */
|
||||
while ((next_cpu < NR_CPUS) &&
|
||||
while ((next_cpu < nr_cpu_ids) &&
|
||||
(!per_cpu(cpu_data, next_cpu).txn_addr ||
|
||||
!cpu_online(next_cpu)))
|
||||
next_cpu++;
|
||||
|
||||
if (next_cpu >= NR_CPUS)
|
||||
if (next_cpu >= nr_cpu_ids)
|
||||
next_cpu = 0; /* nothing else, assign monarch */
|
||||
|
||||
return txn_affinity_addr(virt_irq, next_cpu);
|
||||
|
||||
@@ -61,9 +61,7 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/sections.h>
|
||||
#include <asm/unwind.h>
|
||||
|
||||
#if 0
|
||||
@@ -115,8 +113,6 @@ struct got_entry {
|
||||
Elf32_Addr addr;
|
||||
};
|
||||
|
||||
#define Elf_Fdesc Elf32_Fdesc
|
||||
|
||||
struct stub_entry {
|
||||
Elf32_Word insns[2]; /* each stub entry has two insns */
|
||||
};
|
||||
@@ -125,8 +121,6 @@ struct got_entry {
|
||||
Elf64_Addr addr;
|
||||
};
|
||||
|
||||
#define Elf_Fdesc Elf64_Fdesc
|
||||
|
||||
struct stub_entry {
|
||||
Elf64_Word insns[4]; /* each stub entry has four insns */
|
||||
};
|
||||
@@ -916,15 +910,3 @@ void module_arch_cleanup(struct module *mod)
|
||||
deregister_unwind_table(mod);
|
||||
module_bug_cleanup(mod);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
void *dereference_function_descriptor(void *ptr)
|
||||
{
|
||||
Elf64_Fdesc *desc = ptr;
|
||||
void *p;
|
||||
|
||||
if (!probe_kernel_address(&desc->addr, p))
|
||||
ptr = p;
|
||||
return ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -153,5 +153,10 @@ EXPORT_SYMBOL(node_data);
|
||||
EXPORT_SYMBOL(pfnnid_map);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FUNCTION_TRACER
|
||||
extern void _mcount(void);
|
||||
EXPORT_SYMBOL(_mcount);
|
||||
#endif
|
||||
|
||||
/* from pacache.S -- needed for copy_page */
|
||||
EXPORT_SYMBOL(copy_user_page_asm);
|
||||
|
||||
@@ -46,14 +46,15 @@
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/pdc.h>
|
||||
#include <asm/pdc_chassis.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/unwind.h>
|
||||
#include <asm/sections.h>
|
||||
|
||||
/*
|
||||
* The idle thread. There's no useful work to be
|
||||
@@ -231,8 +232,8 @@ sys_clone(unsigned long clone_flags, unsigned long usp,
|
||||
|
||||
However, these last 3 args are only examined
|
||||
if the proper flags are set. */
|
||||
int __user *child_tidptr;
|
||||
int __user *parent_tidptr;
|
||||
int __user *parent_tidptr = (int __user *)regs->gr[24];
|
||||
int __user *child_tidptr = (int __user *)regs->gr[22];
|
||||
|
||||
/* usp must be word aligned. This also prevents users from
|
||||
* passing in the value 1 (which is the signal for a special
|
||||
@@ -243,16 +244,6 @@ sys_clone(unsigned long clone_flags, unsigned long usp,
|
||||
if (usp == 0)
|
||||
usp = regs->gr[30];
|
||||
|
||||
if (clone_flags & CLONE_PARENT_SETTID)
|
||||
parent_tidptr = (int __user *)regs->gr[24];
|
||||
else
|
||||
parent_tidptr = NULL;
|
||||
|
||||
if (clone_flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID))
|
||||
child_tidptr = (int __user *)regs->gr[22];
|
||||
else
|
||||
child_tidptr = NULL;
|
||||
|
||||
return do_fork(clone_flags, usp, regs, 0, parent_tidptr, child_tidptr);
|
||||
}
|
||||
|
||||
@@ -400,3 +391,15 @@ get_wchan(struct task_struct *p)
|
||||
} while (count++ < 16);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
void *dereference_function_descriptor(void *ptr)
|
||||
{
|
||||
Elf64_Fdesc *desc = ptr;
|
||||
void *p;
|
||||
|
||||
if (!probe_kernel_address(&desc->addr, p))
|
||||
ptr = p;
|
||||
return ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -100,8 +100,8 @@ static int __cpuinit processor_probe(struct parisc_device *dev)
|
||||
struct cpuinfo_parisc *p;
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
if (num_online_cpus() >= NR_CPUS) {
|
||||
printk(KERN_INFO "num_online_cpus() >= NR_CPUS\n");
|
||||
if (num_online_cpus() >= nr_cpu_ids) {
|
||||
printk(KERN_INFO "num_online_cpus() >= nr_cpu_ids\n");
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
@@ -214,7 +214,7 @@ static int __cpuinit processor_probe(struct parisc_device *dev)
|
||||
*/
|
||||
#ifdef CONFIG_SMP
|
||||
if (cpuid) {
|
||||
cpu_set(cpuid, cpu_present_map);
|
||||
set_cpu_present(cpuid, true);
|
||||
cpu_up(cpuid);
|
||||
}
|
||||
#endif
|
||||
@@ -364,6 +364,13 @@ show_cpuinfo (struct seq_file *m, void *v)
|
||||
boot_cpu_data.cpu_hz / 1000000,
|
||||
boot_cpu_data.cpu_hz % 1000000 );
|
||||
|
||||
seq_printf(m, "capabilities\t:");
|
||||
if (boot_cpu_data.pdc.capabilities & PDC_MODEL_OS32)
|
||||
seq_printf(m, " os32");
|
||||
if (boot_cpu_data.pdc.capabilities & PDC_MODEL_OS64)
|
||||
seq_printf(m, " os64");
|
||||
seq_printf(m, "\n");
|
||||
|
||||
seq_printf(m, "model\t\t: %s\n"
|
||||
"model name\t: %s\n",
|
||||
boot_cpu_data.pdc.sys_model_name,
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/ftrace.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/atomic.h>
|
||||
@@ -113,14 +114,14 @@ halt_processor(void)
|
||||
{
|
||||
/* REVISIT : redirect I/O Interrupts to another CPU? */
|
||||
/* REVISIT : does PM *know* this CPU isn't available? */
|
||||
cpu_clear(smp_processor_id(), cpu_online_map);
|
||||
set_cpu_online(smp_processor_id(), false);
|
||||
local_irq_disable();
|
||||
for (;;)
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
irqreturn_t
|
||||
irqreturn_t __irq_entry
|
||||
ipi_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
int this_cpu = smp_processor_id();
|
||||
@@ -214,11 +215,11 @@ ipi_send(int cpu, enum ipi_message_type op)
|
||||
}
|
||||
|
||||
static void
|
||||
send_IPI_mask(cpumask_t mask, enum ipi_message_type op)
|
||||
send_IPI_mask(const struct cpumask *mask, enum ipi_message_type op)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
for_each_cpu_mask(cpu, mask)
|
||||
for_each_cpu(cpu, mask)
|
||||
ipi_send(cpu, op);
|
||||
}
|
||||
|
||||
@@ -257,7 +258,7 @@ smp_send_all_nop(void)
|
||||
send_IPI_allbutself(IPI_NOP);
|
||||
}
|
||||
|
||||
void arch_send_call_function_ipi(cpumask_t mask)
|
||||
void arch_send_call_function_ipi_mask(const struct cpumask *mask)
|
||||
{
|
||||
send_IPI_mask(mask, IPI_CALL_FUNC);
|
||||
}
|
||||
@@ -296,13 +297,14 @@ smp_cpu_init(int cpunum)
|
||||
mb();
|
||||
|
||||
/* Well, support 2.4 linux scheme as well. */
|
||||
if (cpu_test_and_set(cpunum, cpu_online_map))
|
||||
if (cpu_isset(cpunum, cpu_online_map))
|
||||
{
|
||||
extern void machine_halt(void); /* arch/parisc.../process.c */
|
||||
|
||||
printk(KERN_CRIT "CPU#%d already initialized!\n", cpunum);
|
||||
machine_halt();
|
||||
}
|
||||
set_cpu_online(cpunum, true);
|
||||
|
||||
/* Initialise the idle task for this CPU */
|
||||
atomic_inc(&init_mm.mm_count);
|
||||
@@ -424,8 +426,8 @@ void __init smp_prepare_boot_cpu(void)
|
||||
/* Setup BSP mappings */
|
||||
printk(KERN_INFO "SMP: bootstrap CPU ID is %d\n", bootstrap_processor);
|
||||
|
||||
cpu_set(bootstrap_processor, cpu_online_map);
|
||||
cpu_set(bootstrap_processor, cpu_present_map);
|
||||
set_cpu_online(bootstrap_processor, true);
|
||||
set_cpu_present(bootstrap_processor, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -436,8 +438,7 @@ void __init smp_prepare_boot_cpu(void)
|
||||
*/
|
||||
void __init smp_prepare_cpus(unsigned int max_cpus)
|
||||
{
|
||||
cpus_clear(cpu_present_map);
|
||||
cpu_set(0, cpu_present_map);
|
||||
init_cpu_present(cpumask_of(0));
|
||||
|
||||
parisc_max_cpus = max_cpus;
|
||||
if (!max_cpus)
|
||||
|
||||
63
arch/parisc/kernel/stacktrace.c
Normal file
63
arch/parisc/kernel/stacktrace.c
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Stack trace management functions
|
||||
*
|
||||
* Copyright (C) 2009 Helge Deller <deller@gmx.de>
|
||||
* based on arch/x86/kernel/stacktrace.c by Ingo Molnar <mingo@redhat.com>
|
||||
* and parisc unwind functions by Randolph Chung <tausq@debian.org>
|
||||
*
|
||||
* TODO: Userspace stacktrace (CONFIG_USER_STACKTRACE_SUPPORT)
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/stacktrace.h>
|
||||
|
||||
#include <asm/unwind.h>
|
||||
|
||||
static void dump_trace(struct task_struct *task, struct stack_trace *trace)
|
||||
{
|
||||
struct unwind_frame_info info;
|
||||
|
||||
/* initialize unwind info */
|
||||
if (task == current) {
|
||||
unsigned long sp;
|
||||
struct pt_regs r;
|
||||
HERE:
|
||||
asm volatile ("copy %%r30, %0" : "=r"(sp));
|
||||
memset(&r, 0, sizeof(struct pt_regs));
|
||||
r.iaoq[0] = (unsigned long)&&HERE;
|
||||
r.gr[2] = (unsigned long)__builtin_return_address(0);
|
||||
r.gr[30] = sp;
|
||||
unwind_frame_init(&info, task, &r);
|
||||
} else {
|
||||
unwind_frame_init_from_blocked_task(&info, task);
|
||||
}
|
||||
|
||||
/* unwind stack and save entries in stack_trace struct */
|
||||
trace->nr_entries = 0;
|
||||
while (trace->nr_entries < trace->max_entries) {
|
||||
if (unwind_once(&info) < 0 || info.ip == 0)
|
||||
break;
|
||||
|
||||
if (__kernel_text_address(info.ip))
|
||||
trace->entries[trace->nr_entries++] = info.ip;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Save stack-backtrace addresses into a stack_trace buffer.
|
||||
*/
|
||||
void save_stack_trace(struct stack_trace *trace)
|
||||
{
|
||||
dump_trace(current, trace);
|
||||
if (trace->nr_entries < trace->max_entries)
|
||||
trace->entries[trace->nr_entries++] = ULONG_MAX;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(save_stack_trace);
|
||||
|
||||
void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
|
||||
{
|
||||
dump_trace(tsk, trace);
|
||||
if (trace->nr_entries < trace->max_entries)
|
||||
trace->entries[trace->nr_entries++] = ULONG_MAX;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
|
||||
@@ -365,17 +365,51 @@ tracesys_sigexit:
|
||||
|
||||
|
||||
/*********************************************************
|
||||
Light-weight-syscall code
|
||||
32/64-bit Light-Weight-Syscall ABI
|
||||
|
||||
r20 - lws number
|
||||
r26,r25,r24,r23,r22 - Input registers
|
||||
r28 - Function return register
|
||||
r21 - Error code.
|
||||
* - Indicates a hint for userspace inline asm
|
||||
implementations.
|
||||
|
||||
Scracth: Any of the above that aren't being
|
||||
currently used, including r1.
|
||||
Syscall number (caller-saves)
|
||||
- %r20
|
||||
* In asm clobber.
|
||||
|
||||
Return pointer: r31 (Not usable)
|
||||
Argument registers (caller-saves)
|
||||
- %r26, %r25, %r24, %r23, %r22
|
||||
* In asm input.
|
||||
|
||||
Return registers (caller-saves)
|
||||
- %r28 (return), %r21 (errno)
|
||||
* In asm output.
|
||||
|
||||
Caller-saves registers
|
||||
- %r1, %r27, %r29
|
||||
- %r2 (return pointer)
|
||||
- %r31 (ble link register)
|
||||
* In asm clobber.
|
||||
|
||||
Callee-saves registers
|
||||
- %r3-%r18
|
||||
- %r30 (stack pointer)
|
||||
* Not in asm clobber.
|
||||
|
||||
If userspace is 32-bit:
|
||||
Callee-saves registers
|
||||
- %r19 (32-bit PIC register)
|
||||
|
||||
Differences from 32-bit calling convention:
|
||||
- Syscall number in %r20
|
||||
- Additional argument register %r22 (arg4)
|
||||
- Callee-saves %r19.
|
||||
|
||||
If userspace is 64-bit:
|
||||
Callee-saves registers
|
||||
- %r27 (64-bit PIC register)
|
||||
|
||||
Differences from 64-bit calling convention:
|
||||
- Syscall number in %r20
|
||||
- Additional argument register %r22 (arg4)
|
||||
- Callee-saves %r27.
|
||||
|
||||
Error codes returned by entry path:
|
||||
|
||||
@@ -473,7 +507,8 @@ lws_compare_and_swap64:
|
||||
b,n lws_compare_and_swap
|
||||
#else
|
||||
/* If we are not a 64-bit kernel, then we don't
|
||||
* implement having 64-bit input registers
|
||||
* have 64-bit input registers, and calling
|
||||
* the 64-bit LWS CAS returns ENOSYS.
|
||||
*/
|
||||
b,n lws_exit_nosys
|
||||
#endif
|
||||
@@ -635,12 +670,15 @@ END(sys_call_table64)
|
||||
/*
|
||||
All light-weight-syscall atomic operations
|
||||
will use this set of locks
|
||||
|
||||
NOTE: The lws_lock_start symbol must be
|
||||
at least 16-byte aligned for safe use
|
||||
with ldcw.
|
||||
*/
|
||||
.section .data
|
||||
.align PAGE_SIZE
|
||||
ENTRY(lws_lock_start)
|
||||
/* lws locks */
|
||||
.align 16
|
||||
.rept 16
|
||||
/* Keep locks aligned at 16-bytes */
|
||||
.word 1
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <linux/profile.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/ftrace.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/io.h>
|
||||
@@ -53,7 +54,7 @@ static unsigned long clocktick __read_mostly; /* timer cycles per tick */
|
||||
* held off for an arbitrarily long period of time by interrupts being
|
||||
* disabled, so we may miss one or more ticks.
|
||||
*/
|
||||
irqreturn_t timer_interrupt(int irq, void *dev_id)
|
||||
irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
unsigned long now;
|
||||
unsigned long next_tick;
|
||||
|
||||
@@ -247,6 +247,8 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
|
||||
|
||||
oops_in_progress = 1;
|
||||
|
||||
oops_enter();
|
||||
|
||||
/* Amuse the user in a SPARC fashion */
|
||||
if (err) printk(
|
||||
KERN_CRIT " _______________________________ \n"
|
||||
@@ -293,6 +295,7 @@ KERN_CRIT " || ||\n");
|
||||
panic("Fatal exception");
|
||||
}
|
||||
|
||||
oops_exit();
|
||||
do_exit(SIGSEGV);
|
||||
}
|
||||
|
||||
@@ -494,7 +497,7 @@ void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long o
|
||||
panic(msg);
|
||||
}
|
||||
|
||||
void handle_interruption(int code, struct pt_regs *regs)
|
||||
void notrace handle_interruption(int code, struct pt_regs *regs)
|
||||
{
|
||||
unsigned long fault_address = 0;
|
||||
unsigned long fault_space = 0;
|
||||
|
||||
@@ -54,6 +54,8 @@ SECTIONS
|
||||
TEXT_TEXT
|
||||
SCHED_TEXT
|
||||
LOCK_TEXT
|
||||
KPROBES_TEXT
|
||||
IRQENTRY_TEXT
|
||||
*(.text.do_softirq)
|
||||
*(.text.sys_exit)
|
||||
*(.text.do_sigaltstack)
|
||||
|
||||
Reference in New Issue
Block a user