Commit 8d19f15a authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390 update (1/27): arch.

s390 arch file changes for 2.5.39.
parent 7570df54
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
EXTRA_TARGETS := head.o init_task.o EXTRA_TARGETS := head.o init_task.o
EXTRA_AFLAGS := -traditional EXTRA_AFLAGS := -traditional
export-objs := debug.o ebcdic.o irq.o s390_ext.o smp.o s390_ksyms.o export-objs := debug.o ebcdic.o s390_ext.o smp.o s390_ksyms.o
obj-y := entry.o bitmap.o traps.o time.o process.o irq.o \ obj-y := entry.o bitmap.o traps.o time.o process.o \
setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
semaphore.o s390fpu.o reipl.o s390_ext.o debug.o semaphore.o s390fpu.o reipl.o s390_ext.o debug.o
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include <asm/cache.h> #include <asm/cache.h>
#include <asm/lowcore.h> #include <asm/lowcore.h>
#include <asm/errno.h> #include <asm/errno.h>
#include <asm/smp.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/thread_info.h> #include <asm/thread_info.h>
......
...@@ -653,5 +653,5 @@ _stext: basr %r13,0 # get base ...@@ -653,5 +653,5 @@ _stext: basr %r13,0 # get base
.Lstart: .long start_kernel .Lstart: .long start_kernel
.Lbss_bgn: .long __bss_start .Lbss_bgn: .long __bss_start
.Lbss_end: .long _end .Lbss_end: .long _end
.Laregs: .long 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0 .Laregs: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
static struct fs_struct init_fs = INIT_FS; static struct fs_struct init_fs = INIT_FS;
static struct files_struct init_files = INIT_FILES; static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS; static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
struct mm_struct init_mm = INIT_MM(init_mm); struct mm_struct init_mm = INIT_MM(init_mm);
/* /*
......
/*
* arch/s390/kernel/irq.c
*
* S390 version
* Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Ingo Adlung (adlung@de.ibm.com)
*
* Derived from "arch/i386/kernel/irq.c"
* Copyright (C) 1992, 1999 Linus Torvalds, Ingo Molnar
*
* S/390 I/O interrupt processing and I/O request processing is
* implemented in arch/s390/kernel/s390io.c
*/
#include <linux/module.h>
#include <linux/config.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/kernel_stat.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/random.h>
#include <linux/smp.h>
#include <linux/threads.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/seq_file.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bitops.h>
#include <asm/smp.h>
#include <asm/pgtable.h>
#include <asm/delay.h>
#include <asm/lowcore.h>
void s390_init_IRQ ( void );
void s390_free_irq ( unsigned int irq, void *dev_id);
int s390_request_irq( unsigned int irq,
void (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags,
const char *devname,
void *dev_id);
#if 0
/*
* The following vectors are part of the Linux architecture, there
* is no hardware IRQ pin equivalent for them, they are triggered
* through the ICC by us (IPIs), via smp_message_pass():
*/
BUILD_SMP_INTERRUPT(reschedule_interrupt)
BUILD_SMP_INTERRUPT(invalidate_interrupt)
BUILD_SMP_INTERRUPT(stop_cpu_interrupt)
BUILD_SMP_INTERRUPT(mtrr_interrupt)
BUILD_SMP_INTERRUPT(spurious_interrupt)
#endif
int show_interrupts(struct seq_file *p, void *v)
{
int i, j;
seq_puts(p, " ");
for (j=0; j<smp_num_cpus; j++)
seq_printf(p, "CPU%d ",j);
seq_putc(p, '\n');
for (i = 0 ; i < NR_IRQS ; i++) {
if (ioinfo[i] == INVALID_STORAGE_AREA)
continue;
seq_printf(p, "%3d: ",i);
seq_printf(p, " %s", ioinfo[i]->irq_desc.name);
seq_putc(p, '\n');
} /* endfor */
return 0;
}
/*
* Global interrupt locks for SMP. Allow interrupts to come in on any
* CPU, yet make cli/sti act globally to protect critical regions..
*/
#ifdef CONFIG_SMP
atomic_t global_irq_holder = ATOMIC_INIT(NO_PROC_ID);
atomic_t global_irq_lock = ATOMIC_INIT(0);
atomic_t global_irq_count = ATOMIC_INIT(0);
atomic_t global_bh_count;
/*
* "global_cli()" is a special case, in that it can hold the
* interrupts disabled for a longish time, and also because
* we may be doing TLB invalidates when holding the global
* IRQ lock for historical reasons. Thus we may need to check
* SMP invalidate events specially by hand here (but not in
* any normal spinlocks)
*
* Thankfully we don't need this as we can deliver flush tlbs with
* interrupts disabled DJB :-)
*/
#define check_smp_invalidate(cpu)
extern void show_stack(unsigned long* esp);
static void show(char * str)
{
int cpu = smp_processor_id();
printk("\n%s, CPU %d:\n", str, cpu);
printk("irq: %d [%d]\n",
atomic_read(&global_irq_count),local_irq_count(smp_processor_id()));
printk("bh: %d [%d]\n",
atomic_read(&global_bh_count),local_bh_count(smp_processor_id()));
show_stack(NULL);
}
#define MAXCOUNT 100000000
static inline void wait_on_bh(void)
{
int count = MAXCOUNT;
do {
if (!--count) {
show("wait_on_bh");
count = ~0;
}
/* nothing .. wait for the other bh's to go away */
} while (atomic_read(&global_bh_count) != 0);
}
static inline void wait_on_irq(int cpu)
{
int count = MAXCOUNT;
for (;;) {
/*
* Wait until all interrupts are gone. Wait
* for bottom half handlers unless we're
* already executing in one..
*/
if (!atomic_read(&global_irq_count)) {
if (local_bh_count(cpu)||
!atomic_read(&global_bh_count))
break;
}
/* Duh, we have to loop. Release the lock to avoid deadlocks */
atomic_set(&global_irq_lock, 0);
for (;;) {
if (!--count) {
show("wait_on_irq");
count = ~0;
}
local_irq_enable();
SYNC_OTHER_CORES(cpu);
local_irq_disable();
check_smp_invalidate(cpu);
if (atomic_read(&global_irq_count))
continue;
if (atomic_read(&global_irq_lock))
continue;
if (!local_bh_count(cpu)
&& atomic_read(&global_bh_count))
continue;
if (!atomic_compare_and_swap(0, 1, &global_irq_lock))
break;
}
}
}
/*
* This is called when we want to synchronize with
* bottom half handlers. We need to wait until
* no other CPU is executing any bottom half handler.
*
* Don't wait if we're already running in an interrupt
* context or are inside a bh handler.
*/
void synchronize_bh(void)
{
if (atomic_read(&global_bh_count) && !in_interrupt())
wait_on_bh();
}
/*
* This is called when we want to synchronize with
* interrupts. We may for example tell a device to
* stop sending interrupts: but to make sure there
* are no interrupts that are executing on another
* CPU we need to call this function.
*/
void synchronize_irq(void)
{
if (atomic_read(&global_irq_count)) {
/* Stupid approach */
cli();
sti();
}
}
static inline void get_irqlock(int cpu)
{
if (atomic_compare_and_swap(0, 1, &global_irq_lock) != 0) {
/* do we already hold the lock? */
if ( cpu == atomic_read(&global_irq_holder))
return;
/* Uhhuh.. Somebody else got it. Wait.. */
do {
check_smp_invalidate(cpu);
} while (atomic_compare_and_swap(0, 1, &global_irq_lock) != 0);
}
/*
* We also to make sure that nobody else is running
* in an interrupt context.
*/
wait_on_irq(cpu);
/*
* Ok, finally..
*/
atomic_set(&global_irq_holder,cpu);
}
#define EFLAGS_I_SHIFT 25
/*
* A global "cli()" while in an interrupt context
* turns into just a local cli(). Interrupts
* should use spinlocks for the (very unlikely)
* case that they ever want to protect against
* each other.
*
* If we already have local interrupts disabled,
* this will not turn a local disable into a
* global one (problems with spinlocks: this makes
* save_flags+cli+sti usable inside a spinlock).
*/
void __global_cli(void)
{
unsigned long flags;
local_save_flags(flags);
if (flags & (1 << EFLAGS_I_SHIFT)) {
int cpu = smp_processor_id();
local_irq_disable();
if (!in_irq())
get_irqlock(cpu);
}
}
void __global_sti(void)
{
if (!in_irq())
release_irqlock(smp_processor_id());
local_irq_enable();
}
/*
* SMP flags value to restore to:
* 0 - global cli
* 1 - global sti
* 2 - local cli
* 3 - local sti
*/
unsigned long __global_save_flags(void)
{
int retval;
int local_enabled;
unsigned long flags;
local_save_flags(flags);
local_enabled = (flags >> EFLAGS_I_SHIFT) & 1;
/* default to local */
retval = 2 + local_enabled;
/* check for global flags if we're not in an interrupt */
if (!in_irq())
{
if (local_enabled)
retval = 1;
if (atomic_read(&global_irq_holder)== smp_processor_id())
retval = 0;
}
return retval;
}
void __global_restore_flags(unsigned long flags)
{
switch (flags) {
case 0:
__global_cli();
break;
case 1:
__global_sti();
break;
case 2:
local_irq_disable();
break;
case 3:
local_irq_enable();
break;
default:
printk("global_restore_flags: %08lx (%08lx)\n",
flags, (&flags)[-1]);
}
}
#endif
void __init init_IRQ(void)
{
s390_init_IRQ();
}
void free_irq(unsigned int irq, void *dev_id)
{
s390_free_irq( irq, dev_id);
}
int request_irq( unsigned int irq,
void (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags,
const char *devname,
void *dev_id)
{
return( s390_request_irq( irq, handler, irqflags, devname, dev_id ) );
}
void init_irq_proc(void)
{
/* For now, nothing... */
}
#ifdef CONFIG_SMP
EXPORT_SYMBOL(__global_cli);
EXPORT_SYMBOL(__global_sti);
EXPORT_SYMBOL(__global_save_flags);
EXPORT_SYMBOL(__global_restore_flags);
EXPORT_SYMBOL(global_irq_holder);
EXPORT_SYMBOL(global_irq_lock);
EXPORT_SYMBOL(global_irq_count);
EXPORT_SYMBOL(global_bh_count);
#endif
EXPORT_SYMBOL(global_bh_lock);
...@@ -15,9 +15,6 @@ ...@@ -15,9 +15,6 @@
* This file handles the architecture-dependent parts of process handling.. * This file handles the architecture-dependent parts of process handling..
*/ */
#define __KERNEL_SYSCALLS__
#include <stdarg.h>
#include <linux/config.h> #include <linux/config.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/sched.h> #include <linux/sched.h>
...@@ -121,31 +118,35 @@ void show_regs(struct pt_regs *regs) ...@@ -121,31 +118,35 @@ void show_regs(struct pt_regs *regs)
show_trace((unsigned long *) regs->gprs[15]); show_trace((unsigned long *) regs->gprs[15]);
} }
extern void kernel_thread_starter(void);
__asm__(".align 4\n"
"kernel_thread_starter:\n"
" l 15,0(8)\n"
" sr 15,7\n"
" stosm 24(15),3\n"
" lr 2,10\n"
" basr 14,9\n"
" sr 2,2\n"
" br 11\n");
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{ {
int clone_arg = flags | CLONE_VM; struct task_struct *p;
int retval; struct pt_regs regs;
__asm__ __volatile__( memset(&regs, 0, sizeof(regs));
" sr 2,2\n" regs.psw.mask = _SVC_PSW_MASK;
" lr 3,%1\n" regs.psw.addr = (__u32) kernel_thread_starter | _ADDR_31;
" l 4,%6\n" /* load kernel stack ptr of parent */ regs.gprs[7] = STACK_FRAME_OVERHEAD;
" svc %b2\n" /* Linux system call*/ regs.gprs[8] = __LC_KERNEL_STACK;
" cl 4,%6\n" /* compare ksp's: child or parent ? */ regs.gprs[9] = (unsigned long) fn;
" je 0f\n" /* parent - jump*/ regs.gprs[10] = (unsigned long) arg;
" l 15,%6\n" /* fix kernel stack pointer*/ regs.gprs[11] = (unsigned long) do_exit;
" ahi 15,%7\n" regs.orig_gpr2 = -1;
" xc 0(96,15),0(15)\n" /* clear save area */
" lr 2,%4\n" /* load argument*/ /* Ok, create the new process.. */
" lr 14,%5\n" /* get fn-pointer*/ p = do_fork(flags | CLONE_VM, 0, &regs, 0, NULL);
" basr 14,14\n" /* call fn*/ return IS_ERR(p) ? PTR_ERR(p) : p->pid;
" svc %b3\n" /* Linux system call*/
"0: lr %0,2"
: "=a" (retval)
: "d" (clone_arg), "i" (__NR_clone), "i" (__NR_exit),
"d" (arg), "d" (fn), "i" (__LC_KERNEL_STACK) , "i" (-STACK_FRAME_OVERHEAD)
: "2", "3", "4" );
return retval;
} }
/* /*
...@@ -186,12 +187,13 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp, ...@@ -186,12 +187,13 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
frame = ((struct stack_frame *) frame = ((struct stack_frame *)
(THREAD_SIZE + (unsigned long) p->thread_info)) - 1; (THREAD_SIZE + (unsigned long) p->thread_info)) - 1;
p->thread.ksp = (unsigned long) frame; p->thread.ksp = (unsigned long) frame;
memcpy(&frame->childregs,regs,sizeof(struct pt_regs)); frame->childregs = *regs;
frame->childregs.gprs[2] = 0; /* child returns 0 on fork. */
frame->childregs.gprs[15] = new_stackp; frame->childregs.gprs[15] = new_stackp;
frame->back_chain = frame->eos = 0; frame->back_chain = frame->eos = 0;
/* new return point is ret_from_sys_call */ /* new return point is ret_from_fork */
frame->gprs[8] = ((unsigned long) &ret_from_fork) | 0x80000000; frame->gprs[8] = (unsigned long) ret_from_fork;
/* start disabled because of schedule_tick and rq->lock being held */ /* start disabled because of schedule_tick and rq->lock being held */
frame->childregs.psw.mask &= ~0x03000000; frame->childregs.psw.mask &= ~0x03000000;
...@@ -200,6 +202,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp, ...@@ -200,6 +202,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
/* save fprs, if used in last task */ /* save fprs, if used in last task */
save_fp_regs(&p->thread.fp_regs); save_fp_regs(&p->thread.fp_regs);
p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _SEGMENT_TABLE; p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _SEGMENT_TABLE;
/* start process with ar4 pointing to the correct address space */
p->thread.ar4 = get_fs().ar4;
/* Don't copy debug registers */ /* Don't copy debug registers */
memset(&p->thread.per_info,0,sizeof(p->thread.per_info)); memset(&p->thread.per_info,0,sizeof(p->thread.per_info));
return 0; return 0;
...@@ -208,7 +212,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp, ...@@ -208,7 +212,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
asmlinkage int sys_fork(struct pt_regs regs) asmlinkage int sys_fork(struct pt_regs regs)
{ {
struct task_struct *p; struct task_struct *p;
p = do_fork(SIGCHLD, regs.gprs[15], &regs, 0); p = do_fork(SIGCHLD, regs.gprs[15], &regs, 0, NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid; return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
...@@ -217,12 +221,14 @@ asmlinkage int sys_clone(struct pt_regs regs) ...@@ -217,12 +221,14 @@ asmlinkage int sys_clone(struct pt_regs regs)
unsigned long clone_flags; unsigned long clone_flags;
unsigned long newsp; unsigned long newsp;
struct task_struct *p; struct task_struct *p;
int *user_tid;
clone_flags = regs.gprs[3]; clone_flags = regs.gprs[3];
newsp = regs.orig_gpr2; newsp = regs.orig_gpr2;
user_tid = (int *) regs.gprs[4];
if (!newsp) if (!newsp)
newsp = regs.gprs[15]; newsp = regs.gprs[15];
p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0); p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0, user_tid);
return IS_ERR(p) ? PTR_ERR(p) : p->pid; return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
...@@ -239,7 +245,8 @@ asmlinkage int sys_clone(struct pt_regs regs) ...@@ -239,7 +245,8 @@ asmlinkage int sys_clone(struct pt_regs regs)
asmlinkage int sys_vfork(struct pt_regs regs) asmlinkage int sys_vfork(struct pt_regs regs)
{ {
struct task_struct *p; struct task_struct *p;
p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.gprs[15], &regs, 0); p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
regs.gprs[15], &regs, 0, NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid; return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
......
...@@ -524,7 +524,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) ...@@ -524,7 +524,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
seq_printf(m, "vendor_id : IBM/S390\n" seq_printf(m, "vendor_id : IBM/S390\n"
"# processors : %i\n" "# processors : %i\n"
"bogomips per cpu: %lu.%02lu\n", "bogomips per cpu: %lu.%02lu\n",
smp_num_cpus, loops_per_jiffy/(500000/HZ), num_online_cpus(), loops_per_jiffy/(500000/HZ),
(loops_per_jiffy/(5000/HZ))%100); (loops_per_jiffy/(5000/HZ))%100);
} }
if (cpu_online_map & (1 << n)) { if (cpu_online_map & (1 << n)) {
......
...@@ -60,11 +60,11 @@ sys_sigsuspend(struct pt_regs * regs,int history0, int history1, old_sigset_t ma ...@@ -60,11 +60,11 @@ sys_sigsuspend(struct pt_regs * regs,int history0, int history1, old_sigset_t ma
sigset_t saveset; sigset_t saveset;
mask &= _BLOCKABLE; mask &= _BLOCKABLE;
spin_lock_irq(&current->sigmask_lock); spin_lock_irq(&current->sig->siglock);
saveset = current->blocked; saveset = current->blocked;
siginitset(&current->blocked, mask); siginitset(&current->blocked, mask);
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock); spin_unlock_irq(&current->sig->siglock);
regs->gprs[2] = -EINTR; regs->gprs[2] = -EINTR;
while (1) { while (1) {
...@@ -88,11 +88,11 @@ sys_rt_sigsuspend(struct pt_regs * regs,sigset_t *unewset, size_t sigsetsize) ...@@ -88,11 +88,11 @@ sys_rt_sigsuspend(struct pt_regs * regs,sigset_t *unewset, size_t sigsetsize)
return -EFAULT; return -EFAULT;
sigdelsetmask(&newset, ~_BLOCKABLE); sigdelsetmask(&newset, ~_BLOCKABLE);
spin_lock_irq(&current->sigmask_lock); spin_lock_irq(&current->sig->siglock);
saveset = current->blocked; saveset = current->blocked;
current->blocked = newset; current->blocked = newset;
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock); spin_unlock_irq(&current->sig->siglock);
regs->gprs[2] = -EINTR; regs->gprs[2] = -EINTR;
while (1) { while (1) {
...@@ -191,10 +191,10 @@ asmlinkage long sys_sigreturn(struct pt_regs *regs) ...@@ -191,10 +191,10 @@ asmlinkage long sys_sigreturn(struct pt_regs *regs)
goto badframe; goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE); sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sigmask_lock); spin_lock_irq(&current->sig->siglock);
current->blocked = set; current->blocked = set;
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock); spin_unlock_irq(&current->sig->siglock);
if (restore_sigregs(regs, &frame->sregs)) if (restore_sigregs(regs, &frame->sregs))
goto badframe; goto badframe;
...@@ -217,10 +217,10 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) ...@@ -217,10 +217,10 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
goto badframe; goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE); sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sigmask_lock); spin_lock_irq(&current->sig->siglock);
current->blocked = set; current->blocked = set;
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock); spin_unlock_irq(&current->sig->siglock);
if (restore_sigregs(regs, &frame->uc.uc_mcontext)) if (restore_sigregs(regs, &frame->uc.uc_mcontext))
goto badframe; goto badframe;
...@@ -420,11 +420,11 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset, ...@@ -420,11 +420,11 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
ka->sa.sa_handler = SIG_DFL; ka->sa.sa_handler = SIG_DFL;
if (!(ka->sa.sa_flags & SA_NODEFER)) { if (!(ka->sa.sa_flags & SA_NODEFER)) {
spin_lock_irq(&current->sigmask_lock); spin_lock_irq(&current->sig->siglock);
sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask); sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
sigaddset(&current->blocked,sig); sigaddset(&current->blocked,sig);
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock); spin_unlock_irq(&current->sig->siglock);
} }
} }
......
This diff is collapsed.
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/delay.h> #include <asm/delay.h>
#include <asm/s390_ext.h> #include <asm/s390_ext.h>
#include <asm/div64.h>
#include <linux/timex.h> #include <linux/timex.h>
#include <linux/config.h> #include <linux/config.h>
...@@ -47,45 +48,22 @@ static uint64_t init_timer_cc; ...@@ -47,45 +48,22 @@ static uint64_t init_timer_cc;
extern rwlock_t xtime_lock; extern rwlock_t xtime_lock;
extern unsigned long wall_jiffies; extern unsigned long wall_jiffies;
void tod_to_timeval(__u64 todval, struct timeval *xtime) void tod_to_timeval(__u64 todval, struct timespec *xtime)
{ {
const int high_bit = 0x80000000L; unsigned long long sec;
const int c_f4240 = 0xf4240L;
const int c_7a120 = 0x7a120; sec = todval >> 12;
/* We have to divide the 64 bit value todval by 4096 do_div(sec, 1000000);
* (because the 2^12 bit is the one that changes every xtime->tv_sec = sec;
* microsecond) and then split it into seconds and todval -= (sec * 1000000) << 12;
* microseconds. A value of max (2^52-1) divided by xtime->tv_nsec = ((todval * 1000) >> 12);
* the value 0xF4240 can yield a max result of approx
* (2^32.068). Thats to big to fit into a signed int
* ... hacking time!
*/
asm volatile ("L 2,%1\n\t"
"LR 3,2\n\t"
"SRL 2,12\n\t"
"SLL 3,20\n\t"
"L 4,%O1+4(%R1)\n\t"
"SRL 4,12\n\t"
"OR 3,4\n\t" /* now R2/R3 contain (todval >> 12) */
"SR 4,4\n\t"
"CL 2,%2\n\t"
"JL .+12\n\t"
"S 2,%2\n\t"
"L 4,%3\n\t"
"D 2,%4\n\t"
"OR 3,4\n\t"
"ST 2,%O0+4(%R0)\n\t"
"ST 3,%0"
: "=m" (*xtime) : "m" (todval),
"m" (c_7a120), "m" (high_bit), "m" (c_f4240)
: "cc", "memory", "2", "3", "4" );
} }
static inline unsigned long do_gettimeoffset(void) static inline unsigned long do_gettimeoffset(void)
{ {
__u64 now; __u64 now;
asm ("STCK 0(%0)" : : "a" (&now) : "memory", "cc"); asm volatile ("STCK 0(%0)" : : "a" (&now) : "memory", "cc");
now = (now - init_timer_cc) >> 12; now = (now - init_timer_cc) >> 12;
/* We require the offset from the latest update of xtime */ /* We require the offset from the latest update of xtime */
now -= (__u64) wall_jiffies*USECS_PER_JIFFY; now -= (__u64) wall_jiffies*USECS_PER_JIFFY;
...@@ -102,7 +80,7 @@ void do_gettimeofday(struct timeval *tv) ...@@ -102,7 +80,7 @@ void do_gettimeofday(struct timeval *tv)
read_lock_irqsave(&xtime_lock, flags); read_lock_irqsave(&xtime_lock, flags);
sec = xtime.tv_sec; sec = xtime.tv_sec;
usec = xtime.tv_usec + do_gettimeoffset(); usec = xtime.tv_nsec / 1000 + do_gettimeoffset();
read_unlock_irqrestore(&xtime_lock, flags); read_unlock_irqrestore(&xtime_lock, flags);
while (usec >= 1000000) { while (usec >= 1000000) {
...@@ -118,7 +96,7 @@ void do_settimeofday(struct timeval *tv) ...@@ -118,7 +96,7 @@ void do_settimeofday(struct timeval *tv)
{ {
write_lock_irq(&xtime_lock); write_lock_irq(&xtime_lock);
/* This is revolting. We need to set the xtime.tv_usec /* This is revolting. We need to set the xtime.tv_nsec
* correctly. However, the value in this location is * correctly. However, the value in this location is
* is value at the last tick. * is value at the last tick.
* Discover what correction gettimeofday * Discover what correction gettimeofday
...@@ -131,7 +109,8 @@ void do_settimeofday(struct timeval *tv) ...@@ -131,7 +109,8 @@ void do_settimeofday(struct timeval *tv)
tv->tv_sec--; tv->tv_sec--;
} }
xtime = *tv; xtime.tv_sec = tv->tv_sec;
xtime.tv_nsec = tv->tv_usec * 1000;
time_adjust = 0; /* stop active adjtime() */ time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC; time_status |= STA_UNSYNC;
time_maxerror = NTP_PHASE_LIMIT; time_maxerror = NTP_PHASE_LIMIT;
...@@ -152,7 +131,7 @@ static void do_comparator_interrupt(struct pt_regs *regs, __u16 error_code) ...@@ -152,7 +131,7 @@ static void do_comparator_interrupt(struct pt_regs *regs, __u16 error_code)
{ {
int cpu = smp_processor_id(); int cpu = smp_processor_id();
irq_enter(cpu, 0); irq_enter();
/* /*
* set clock comparator for next tick * set clock comparator for next tick
...@@ -174,7 +153,7 @@ static void do_comparator_interrupt(struct pt_regs *regs, __u16 error_code) ...@@ -174,7 +153,7 @@ static void do_comparator_interrupt(struct pt_regs *regs, __u16 error_code)
do_timer(regs); do_timer(regs);
#endif #endif
irq_exit(cpu, 0); irq_exit();
} }
/* /*
......
...@@ -170,6 +170,14 @@ void show_stack(unsigned long *sp) ...@@ -170,6 +170,14 @@ void show_stack(unsigned long *sp)
show_trace(sp); show_trace(sp);
} }
/*
* The architecture-independent dump_stack generator
*/
void dump_stack(void)
{
show_stack(0);
}
void show_registers(struct pt_regs *regs) void show_registers(struct pt_regs *regs)
{ {
mm_segment_t old_fs; mm_segment_t old_fs;
......
...@@ -46,7 +46,6 @@ extern spinlock_t timerlist_lock; ...@@ -46,7 +46,6 @@ extern spinlock_t timerlist_lock;
*/ */
void bust_spinlocks(int yes) void bust_spinlocks(int yes)
{ {
spin_lock_init(&timerlist_lock);
if (yes) { if (yes) {
oops_in_progress = 1; oops_in_progress = 1;
} else { } else {
......
...@@ -5,10 +5,10 @@ ...@@ -5,10 +5,10 @@
EXTRA_TARGETS := head.o init_task.o EXTRA_TARGETS := head.o init_task.o
EXTRA_AFLAGS := -traditional EXTRA_AFLAGS := -traditional
export-objs := debug.o ebcdic.o irq.o s390_ext.o smp.o s390_ksyms.o \ export-objs := debug.o ebcdic.o s390_ext.o smp.o s390_ksyms.o \
exec32.o exec32.o
obj-y := entry.o bitmap.o traps.o time.o process.o irq.o \ obj-y := entry.o bitmap.o traps.o time.o process.o \
setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
semaphore.o s390fpu.o reipl.o s390_ext.o debug.o semaphore.o s390fpu.o reipl.o s390_ext.o debug.o
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include <asm/cache.h> #include <asm/cache.h>
#include <asm/lowcore.h> #include <asm/lowcore.h>
#include <asm/errno.h> #include <asm/errno.h>
#include <asm/smp.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/thread_info.h> #include <asm/thread_info.h>
...@@ -551,8 +550,8 @@ sys_call_table: ...@@ -551,8 +550,8 @@ sys_call_table:
.long SYSCALL(sys_rt_sigtimedwait,sys32_rt_sigtimedwait_wrapper) .long SYSCALL(sys_rt_sigtimedwait,sys32_rt_sigtimedwait_wrapper)
.long SYSCALL(sys_rt_sigqueueinfo,sys32_rt_sigqueueinfo_wrapper) .long SYSCALL(sys_rt_sigqueueinfo,sys32_rt_sigqueueinfo_wrapper)
.long SYSCALL(sys_rt_sigsuspend_glue,sys32_rt_sigsuspend_glue) .long SYSCALL(sys_rt_sigsuspend_glue,sys32_rt_sigsuspend_glue)
.long SYSCALL(sys_pread,sys32_pread_wrapper) /* 180 */ .long SYSCALL(sys_pread64,sys32_pread_wrapper) /* 180 */
.long SYSCALL(sys_pwrite,sys32_pwrite_wrapper) .long SYSCALL(sys_pwrite64,sys32_pwrite_wrapper)
.long SYSCALL(sys_ni_syscall,sys32_chown16_wrapper) /* old chown16 syscall */ .long SYSCALL(sys_ni_syscall,sys32_chown16_wrapper) /* old chown16 syscall */
.long SYSCALL(sys_getcwd,sys32_getcwd_wrapper) .long SYSCALL(sys_getcwd,sys32_getcwd_wrapper)
.long SYSCALL(sys_capget,sys32_capget_wrapper) .long SYSCALL(sys_capget,sys32_capget_wrapper)
......
...@@ -645,5 +645,5 @@ _stext: basr %r13,0 # get base ...@@ -645,5 +645,5 @@ _stext: basr %r13,0 # get base
# #
.align 8 .align 8
.Ldw: .quad 0x0002000180000000,0x0000000000000000 .Ldw: .quad 0x0002000180000000,0x0000000000000000
.Laregs: .long 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0 .Laregs: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
static struct fs_struct init_fs = INIT_FS; static struct fs_struct init_fs = INIT_FS;
static struct files_struct init_files = INIT_FILES; static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS; static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
struct mm_struct init_mm = INIT_MM(init_mm); struct mm_struct init_mm = INIT_MM(init_mm);
/* /*
......
/*
* arch/s390/kernel/irq.c
*
* S390 version
* Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Ingo Adlung (adlung@de.ibm.com)
*
* Derived from "arch/i386/kernel/irq.c"
* Copyright (C) 1992, 1999 Linus Torvalds, Ingo Molnar
*
* S/390 I/O interrupt processing and I/O request processing is
* implemented in arch/s390/kernel/s390io.c
*/
#include <linux/module.h>
#include <linux/config.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/kernel_stat.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/random.h>
#include <linux/smp.h>
#include <linux/threads.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/seq_file.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bitops.h>
#include <asm/smp.h>
#include <asm/pgtable.h>
#include <asm/delay.h>
#include <asm/lowcore.h>
void s390_init_IRQ ( void );
void s390_free_irq ( unsigned int irq, void *dev_id);
int s390_request_irq( unsigned int irq,
void (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags,
const char *devname,
void *dev_id);
#if 0
/*
* The following vectors are part of the Linux architecture, there
* is no hardware IRQ pin equivalent for them, they are triggered
* through the ICC by us (IPIs), via smp_message_pass():
*/
BUILD_SMP_INTERRUPT(reschedule_interrupt)
BUILD_SMP_INTERRUPT(invalidate_interrupt)
BUILD_SMP_INTERRUPT(stop_cpu_interrupt)
BUILD_SMP_INTERRUPT(mtrr_interrupt)
BUILD_SMP_INTERRUPT(spurious_interrupt)
#endif
int show_interrupts(struct seq_file *p, void *v)
{
int i, j;
seq_puts(p, " ");
for (j=0; j<smp_num_cpus; j++)
seq_printf(p, "CPU%d ",j);
seq_putc(p, '\n');
for (i = 0 ; i < NR_IRQS ; i++)
{
if (ioinfo[i] == INVALID_STORAGE_AREA)
continue;
seq_printf(p, "%3d: ",i);
seq_printf(p, " %s", ioinfo[i]->irq_desc.name);
seq_putc(p, '\n');
} /* endfor */
return 0;
}
/*
* Global interrupt locks for SMP. Allow interrupts to come in on any
* CPU, yet make cli/sti act globally to protect critical regions..
*/
#ifdef CONFIG_SMP
atomic_t global_irq_holder = ATOMIC_INIT(NO_PROC_ID);
atomic_t global_irq_lock = ATOMIC_INIT(0);
atomic_t global_irq_count = ATOMIC_INIT(0);
atomic_t global_bh_count;
/*
* "global_cli()" is a special case, in that it can hold the
* interrupts disabled for a longish time, and also because
* we may be doing TLB invalidates when holding the global
* IRQ lock for historical reasons. Thus we may need to check
* SMP invalidate events specially by hand here (but not in
* any normal spinlocks)
*
* Thankfully we don't need this as we can deliver flush tlbs with
* interrupts disabled DJB :-)
*/
#define check_smp_invalidate(cpu)
extern void show_stack(unsigned long* esp);
static void show(char * str)
{
int cpu = smp_processor_id();
printk("\n%s, CPU %d:\n", str, cpu);
printk("irq: %d [%d]\n",
atomic_read(&global_irq_count),local_irq_count(smp_processor_id()));
printk("bh: %d [%d]\n",
atomic_read(&global_bh_count),local_bh_count(smp_processor_id()));
show_stack(NULL);
}
#define MAXCOUNT 100000000
static inline void wait_on_bh(void)
{
int count = MAXCOUNT;
do {
if (!--count) {
show("wait_on_bh");
count = ~0;
}
/* nothing .. wait for the other bh's to go away */
} while (atomic_read(&global_bh_count) != 0);
}
static inline void wait_on_irq(int cpu)
{
int count = MAXCOUNT;
for (;;) {
/*
* Wait until all interrupts are gone. Wait
* for bottom half handlers unless we're
* already executing in one..
*/
if (!atomic_read(&global_irq_count)) {
if (local_bh_count(cpu)||
!atomic_read(&global_bh_count))
break;
}
/* Duh, we have to loop. Release the lock to avoid deadlocks */
atomic_set(&global_irq_lock, 0);
for (;;) {
if (!--count) {
show("wait_on_irq");
count = ~0;
}
local_irq_enable();
SYNC_OTHER_CORES(cpu);
local_irq_disable();
check_smp_invalidate(cpu);
if (atomic_read(&global_irq_count))
continue;
if (atomic_read(&global_irq_lock))
continue;
if (!local_bh_count(cpu)
&& atomic_read(&global_bh_count))
continue;
if (!atomic_compare_and_swap(0, 1, &global_irq_lock))
break;
}
}
}
/*
* This is called when we want to synchronize with
* bottom half handlers. We need to wait until
* no other CPU is executing any bottom half handler.
*
* Don't wait if we're already running in an interrupt
* context or are inside a bh handler.
*/
void synchronize_bh(void)
{
if (atomic_read(&global_bh_count) && !in_interrupt())
wait_on_bh();
}
/*
* This is called when we want to synchronize with
* interrupts. We may for example tell a device to
* stop sending interrupts: but to make sure there
* are no interrupts that are executing on another
* CPU we need to call this function.
*/
void synchronize_irq(void)
{
if (atomic_read(&global_irq_count)) {
/* Stupid approach */
cli();
sti();
}
}
static inline void get_irqlock(int cpu)
{
if (atomic_compare_and_swap(0,1,&global_irq_lock) != 0) {
/* do we already hold the lock? */
if ( cpu == atomic_read(&global_irq_holder))
return;
/* Uhhuh.. Somebody else got it. Wait.. */
do {
check_smp_invalidate(cpu);
} while (atomic_compare_and_swap(0,1,&global_irq_lock) != 0);
}
/*
* We also to make sure that nobody else is running
* in an interrupt context.
*/
wait_on_irq(cpu);
/*
* Ok, finally..
*/
atomic_set(&global_irq_holder,cpu);
}
#define EFLAGS_I_SHIFT 57
/*
* A global "cli()" while in an interrupt context
* turns into just a local cli(). Interrupts
* should use spinlocks for the (very unlikely)
* case that they ever want to protect against
* each other.
*
* If we already have local interrupts disabled,
* this will not turn a local disable into a
* global one (problems with spinlocks: this makes
* save_flags+cli+sti usable inside a spinlock).
*/
void __global_cli(void)
{
unsigned long flags;
local_save_flags(flags);
if (flags & (1UL << EFLAGS_I_SHIFT)) {
int cpu = smp_processor_id();
local_irq_disable();
if (!in_irq())
get_irqlock(cpu);
}
}
void __global_sti(void)
{
if (!in_irq())
release_irqlock(smp_processor_id());
local_irq_enable();
}
/*
* SMP flags value to restore to:
* 0 - global cli
* 1 - global sti
* 2 - local cli
* 3 - local sti
*/
unsigned long __global_save_flags(void)
{
int retval;
int local_enabled;
unsigned long flags;
local_save_flags(flags);
local_enabled = (flags >> EFLAGS_I_SHIFT) & 1;
/* default to local */
retval = 2 + local_enabled;
/* check for global flags if we're not in an interrupt */
if (!in_irq())
{
if (local_enabled)
retval = 1;
if (atomic_read(&global_irq_holder)== smp_processor_id())
retval = 0;
}
return retval;
}
void __global_restore_flags(unsigned long flags)
{
switch (flags) {
case 0:
__global_cli();
break;
case 1:
__global_sti();
break;
case 2:
local_irq_disable();
break;
case 3:
local_irq_enable();
break;
default:
printk("global_restore_flags: %08lx (%08lx)\n",
flags, (&flags)[-1]);
}
}
#endif
void __init init_IRQ(void)
{
s390_init_IRQ();
}
void free_irq(unsigned int irq, void *dev_id)
{
s390_free_irq( irq, dev_id);
}
int request_irq( unsigned int irq,
void (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags,
const char *devname,
void *dev_id)
{
return( s390_request_irq( irq, handler, irqflags, devname, dev_id ) );
}
void init_irq_proc(void)
{
/* For now, nothing... */
}
#ifdef CONFIG_SMP
EXPORT_SYMBOL(__global_cli);
EXPORT_SYMBOL(__global_sti);
EXPORT_SYMBOL(__global_save_flags);
EXPORT_SYMBOL(__global_restore_flags);
EXPORT_SYMBOL(global_irq_holder);
EXPORT_SYMBOL(global_irq_lock);
EXPORT_SYMBOL(global_irq_count);
EXPORT_SYMBOL(global_bh_count);
#endif
EXPORT_SYMBOL(global_bh_lock);
...@@ -1953,15 +1953,17 @@ sys32_rt_sigtimedwait(sigset_t32 *uthese, siginfo_t32 *uinfo, ...@@ -1953,15 +1953,17 @@ sys32_rt_sigtimedwait(sigset_t32 *uthese, siginfo_t32 *uinfo,
return -EINVAL; return -EINVAL;
} }
spin_lock_irq(&current->sigmask_lock); spin_lock_irq(&current->sig->siglock);
sig = dequeue_signal(&these, &info); sig = dequeue_signal(&current->sig->shared_pending, &these, &info);
if (!sig)
sig = dequeue_signal(&current->pending, &these, &info);
if (!sig) { if (!sig) {
/* None ready -- temporarily unblock those we're interested /* None ready -- temporarily unblock those we're interested
in so that we'll be awakened when they arrive. */ in so that we'll be awakened when they arrive. */
sigset_t oldblocked = current->blocked; current->real_blocked = current->blocked;
sigandsets(&current->blocked, &current->blocked, &these); sigandsets(&current->blocked, &current->blocked, &these);
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock); spin_unlock_irq(&current->sig->siglock);
timeout = MAX_SCHEDULE_TIMEOUT; timeout = MAX_SCHEDULE_TIMEOUT;
if (uts) if (uts)
...@@ -1971,12 +1973,15 @@ sys32_rt_sigtimedwait(sigset_t32 *uthese, siginfo_t32 *uinfo, ...@@ -1971,12 +1973,15 @@ sys32_rt_sigtimedwait(sigset_t32 *uthese, siginfo_t32 *uinfo,
current->state = TASK_INTERRUPTIBLE; current->state = TASK_INTERRUPTIBLE;
timeout = schedule_timeout(timeout); timeout = schedule_timeout(timeout);
spin_lock_irq(&current->sigmask_lock); spin_lock_irq(&current->sig->siglock);
sig = dequeue_signal(&these, &info); sig = dequeue_signal(&current->sig->shared_pending, &these, &info);
current->blocked = oldblocked; if (!sig)
sig = dequeue_signal(&current->pending, &these, &info);
current->blocked = current->real_blocked;
siginitset(&current->real_blocked, 0);
recalc_sigpending(); recalc_sigpending();
} }
spin_unlock_irq(&current->sigmask_lock); spin_unlock_irq(&current->sig->siglock);
if (sig) { if (sig) {
ret = sig; ret = sig;
......
...@@ -15,9 +15,6 @@ ...@@ -15,9 +15,6 @@
* This file handles the architecture-dependent parts of process handling.. * This file handles the architecture-dependent parts of process handling..
*/ */
#define __KERNEL_SYSCALLS__
#include <stdarg.h>
#include <linux/config.h> #include <linux/config.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/sched.h> #include <linux/sched.h>
...@@ -118,31 +115,35 @@ void show_regs(struct pt_regs *regs) ...@@ -118,31 +115,35 @@ void show_regs(struct pt_regs *regs)
show_trace((unsigned long *) regs->gprs[15]); show_trace((unsigned long *) regs->gprs[15]);
} }
extern void kernel_thread_starter(void);
__asm__(".align 4\n"
"kernel_thread_starter:\n"
" lg 15,0(8)\n"
" sgr 15,7\n"
" stosm 48(15),3\n"
" lgr 2,10\n"
" basr 14,9\n"
" sgr 2,2\n"
" br 11\n");
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{ {
int clone_arg = flags | CLONE_VM; struct task_struct *p;
int retval; struct pt_regs regs;
__asm__ __volatile__( memset(&regs, 0, sizeof(regs));
" slgr 2,2\n" regs.psw.mask = _SVC_PSW_MASK;
" lgr 3,%1\n" regs.psw.addr = (__u64) kernel_thread_starter;
" lg 4,%6\n" /* load kernel stack ptr of parent */ regs.gprs[7] = STACK_FRAME_OVERHEAD;
" svc %b2\n" /* Linux system call*/ regs.gprs[8] = __LC_KERNEL_STACK;
" clg 4,%6\n" /* compare ksp's: child or parent ? */ regs.gprs[9] = (unsigned long) fn;
" je 0f\n" /* parent - jump*/ regs.gprs[10] = (unsigned long) arg;
" lg 15,%6\n" /* fix kernel stack pointer*/ regs.gprs[11] = (unsigned long) do_exit;
" aghi 15,%7\n" regs.orig_gpr2 = -1;
" xc 0(160,15),0(15)\n" /* clear save area */
" lgr 2,%4\n" /* load argument*/ /* Ok, create the new process.. */
" basr 14,%5\n" /* call fn*/ p = do_fork(flags | CLONE_VM, 0, &regs, 0, NULL);
" svc %b3\n" /* Linux system call*/ return IS_ERR(p) ? PTR_ERR(p) : p->pid;
"0: lgr %0,2"
: "=a" (retval)
: "d" (clone_arg), "i" (__NR_clone), "i" (__NR_exit),
"d" (arg), "a" (fn), "i" (__LC_KERNEL_STACK) ,
"i" (-STACK_FRAME_OVERHEAD)
: "2", "3", "4" );
return retval;
} }
/* /*
...@@ -184,17 +185,20 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp, ...@@ -184,17 +185,20 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
(THREAD_SIZE + (unsigned long) p->thread_info)) - 1; (THREAD_SIZE + (unsigned long) p->thread_info)) - 1;
p->thread.ksp = (unsigned long) frame; p->thread.ksp = (unsigned long) frame;
frame->childregs = *regs; frame->childregs = *regs;
frame->childregs.gprs[2] = 0; /* child returns 0 on fork. */
frame->childregs.gprs[15] = new_stackp; frame->childregs.gprs[15] = new_stackp;
frame->back_chain = frame->eos = 0; frame->back_chain = frame->eos = 0;
/* new return point is ret_from_sys_call */ /* new return point is ret_from_fork */
frame->gprs[8] = (unsigned long) &ret_from_fork; frame->gprs[8] = (unsigned long) ret_from_fork;
/* fake return stack for resume(), don't go back to schedule */ /* fake return stack for resume(), don't go back to schedule */
frame->gprs[9] = (unsigned long) frame; frame->gprs[9] = (unsigned long) frame;
/* save fprs, if used in last task */ /* save fprs */
save_fp_regs(&p->thread.fp_regs); save_fp_regs(&p->thread.fp_regs);
p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _REGION_TABLE; p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _REGION_TABLE;
/* start new process with ar4 pointing to the correct address space */
p->thread.ar4 = get_fs().ar4;
/* Don't copy debug registers */ /* Don't copy debug registers */
memset(&p->thread.per_info,0,sizeof(p->thread.per_info)); memset(&p->thread.per_info,0,sizeof(p->thread.per_info));
return 0; return 0;
...@@ -203,7 +207,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp, ...@@ -203,7 +207,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
asmlinkage int sys_fork(struct pt_regs regs) asmlinkage int sys_fork(struct pt_regs regs)
{ {
struct task_struct *p; struct task_struct *p;
p = do_fork(SIGCHLD, regs.gprs[15], &regs, 0); p = do_fork(SIGCHLD, regs.gprs[15], &regs, 0, NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid; return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
...@@ -212,12 +216,14 @@ asmlinkage int sys_clone(struct pt_regs regs) ...@@ -212,12 +216,14 @@ asmlinkage int sys_clone(struct pt_regs regs)
unsigned long clone_flags; unsigned long clone_flags;
unsigned long newsp; unsigned long newsp;
struct task_struct *p; struct task_struct *p;
int *user_tid;
clone_flags = regs.gprs[3]; clone_flags = regs.gprs[3];
newsp = regs.orig_gpr2; newsp = regs.orig_gpr2;
user_tid = (int *) regs.gprs[4];
if (!newsp) if (!newsp)
newsp = regs.gprs[15]; newsp = regs.gprs[15];
p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0); p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0, user_tid);
return IS_ERR(p) ? PTR_ERR(p) : p->pid; return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
...@@ -234,7 +240,8 @@ asmlinkage int sys_clone(struct pt_regs regs) ...@@ -234,7 +240,8 @@ asmlinkage int sys_clone(struct pt_regs regs)
asmlinkage int sys_vfork(struct pt_regs regs) asmlinkage int sys_vfork(struct pt_regs regs)
{ {
struct task_struct *p; struct task_struct *p;
p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.gprs[15], &regs, 0); p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
regs.gprs[15], &regs, 0, NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid; return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
......
...@@ -514,7 +514,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) ...@@ -514,7 +514,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
seq_printf(m, "vendor_id : IBM/S390\n" seq_printf(m, "vendor_id : IBM/S390\n"
"# processors : %i\n" "# processors : %i\n"
"bogomips per cpu: %lu.%02lu\n", "bogomips per cpu: %lu.%02lu\n",
smp_num_cpus, loops_per_jiffy/(500000/HZ), num_online_cpus(), loops_per_jiffy/(500000/HZ),
(loops_per_jiffy/(5000/HZ))%100); (loops_per_jiffy/(5000/HZ))%100);
} }
if (cpu_online_map & (1 << n)) { if (cpu_online_map & (1 << n)) {
......
...@@ -60,11 +60,11 @@ sys_sigsuspend(struct pt_regs * regs,int history0, int history1, old_sigset_t ma ...@@ -60,11 +60,11 @@ sys_sigsuspend(struct pt_regs * regs,int history0, int history1, old_sigset_t ma
sigset_t saveset; sigset_t saveset;
mask &= _BLOCKABLE; mask &= _BLOCKABLE;
spin_lock_irq(&current->sigmask_lock); spin_lock_irq(&current->sig->siglock);
saveset = current->blocked; saveset = current->blocked;
siginitset(&current->blocked, mask); siginitset(&current->blocked, mask);
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock); spin_unlock_irq(&current->sig->siglock);
regs->gprs[2] = -EINTR; regs->gprs[2] = -EINTR;
while (1) { while (1) {
...@@ -88,11 +88,11 @@ sys_rt_sigsuspend(struct pt_regs * regs,sigset_t *unewset, size_t sigsetsize) ...@@ -88,11 +88,11 @@ sys_rt_sigsuspend(struct pt_regs * regs,sigset_t *unewset, size_t sigsetsize)
return -EFAULT; return -EFAULT;
sigdelsetmask(&newset, ~_BLOCKABLE); sigdelsetmask(&newset, ~_BLOCKABLE);
spin_lock_irq(&current->sigmask_lock); spin_lock_irq(&current->sig->siglock);
saveset = current->blocked; saveset = current->blocked;
current->blocked = newset; current->blocked = newset;
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock); spin_unlock_irq(&current->sig->siglock);
regs->gprs[2] = -EINTR; regs->gprs[2] = -EINTR;
while (1) { while (1) {
...@@ -191,10 +191,10 @@ asmlinkage long sys_sigreturn(struct pt_regs *regs) ...@@ -191,10 +191,10 @@ asmlinkage long sys_sigreturn(struct pt_regs *regs)
goto badframe; goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE); sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sigmask_lock); spin_lock_irq(&current->sig->siglock);
current->blocked = set; current->blocked = set;
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock); spin_unlock_irq(&current->sig->siglock);
if (restore_sigregs(regs, &frame->sregs)) if (restore_sigregs(regs, &frame->sregs))
goto badframe; goto badframe;
...@@ -217,10 +217,10 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) ...@@ -217,10 +217,10 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
goto badframe; goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE); sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sigmask_lock); spin_lock_irq(&current->sig->siglock);
current->blocked = set; current->blocked = set;
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock); spin_unlock_irq(&current->sig->siglock);
if (restore_sigregs(regs, &frame->uc.uc_mcontext)) if (restore_sigregs(regs, &frame->uc.uc_mcontext))
goto badframe; goto badframe;
...@@ -420,11 +420,11 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset, ...@@ -420,11 +420,11 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
ka->sa.sa_handler = SIG_DFL; ka->sa.sa_handler = SIG_DFL;
if (!(ka->sa.sa_flags & SA_NODEFER)) { if (!(ka->sa.sa_flags & SA_NODEFER)) {
spin_lock_irq(&current->sigmask_lock); spin_lock_irq(&current->sig->siglock);
sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask); sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
sigaddset(&current->blocked,sig); sigaddset(&current->blocked,sig);
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock); spin_unlock_irq(&current->sig->siglock);
} }
} }
......
...@@ -112,11 +112,11 @@ sys32_sigsuspend(struct pt_regs * regs,int history0, int history1, old_sigset_t ...@@ -112,11 +112,11 @@ sys32_sigsuspend(struct pt_regs * regs,int history0, int history1, old_sigset_t
sigset_t saveset; sigset_t saveset;
mask &= _BLOCKABLE; mask &= _BLOCKABLE;
spin_lock_irq(&current->sigmask_lock); spin_lock_irq(&current->sig->siglock);
saveset = current->blocked; saveset = current->blocked;
siginitset(&current->blocked, mask); siginitset(&current->blocked, mask);
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock); spin_unlock_irq(&current->sig->siglock);
regs->gprs[2] = -EINTR; regs->gprs[2] = -EINTR;
while (1) { while (1) {
...@@ -147,11 +147,11 @@ sys32_rt_sigsuspend(struct pt_regs * regs,sigset_t32 *unewset, size_t sigsetsize ...@@ -147,11 +147,11 @@ sys32_rt_sigsuspend(struct pt_regs * regs,sigset_t32 *unewset, size_t sigsetsize
} }
sigdelsetmask(&newset, ~_BLOCKABLE); sigdelsetmask(&newset, ~_BLOCKABLE);
spin_lock_irq(&current->sigmask_lock); spin_lock_irq(&current->sig->siglock);
saveset = current->blocked; saveset = current->blocked;
current->blocked = newset; current->blocked = newset;
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock); spin_unlock_irq(&current->sig->siglock);
regs->gprs[2] = -EINTR; regs->gprs[2] = -EINTR;
while (1) { while (1) {
...@@ -352,10 +352,10 @@ asmlinkage long sys32_sigreturn(struct pt_regs *regs) ...@@ -352,10 +352,10 @@ asmlinkage long sys32_sigreturn(struct pt_regs *regs)
goto badframe; goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE); sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sigmask_lock); spin_lock_irq(&current->sig->siglock);
current->blocked = set; current->blocked = set;
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock); spin_unlock_irq(&current->sig->siglock);
if (restore_sigregs32(regs, &frame->sregs)) if (restore_sigregs32(regs, &frame->sregs))
goto badframe; goto badframe;
...@@ -382,10 +382,10 @@ asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs) ...@@ -382,10 +382,10 @@ asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
goto badframe; goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE); sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sigmask_lock); spin_lock_irq(&current->sig->siglock);
current->blocked = set; current->blocked = set;
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock); spin_unlock_irq(&current->sig->siglock);
if (restore_sigregs32(regs, &frame->uc.uc_mcontext)) if (restore_sigregs32(regs, &frame->uc.uc_mcontext))
goto badframe; goto badframe;
...@@ -595,11 +595,11 @@ handle_signal32(unsigned long sig, siginfo_t *info, sigset_t *oldset, ...@@ -595,11 +595,11 @@ handle_signal32(unsigned long sig, siginfo_t *info, sigset_t *oldset,
ka->sa.sa_handler = SIG_DFL; ka->sa.sa_handler = SIG_DFL;
if (!(ka->sa.sa_flags & SA_NODEFER)) { if (!(ka->sa.sa_flags & SA_NODEFER)) {
spin_lock_irq(&current->sigmask_lock); spin_lock_irq(&current->sig->siglock);
sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask); sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
sigaddset(&current->blocked,sig); sigaddset(&current->blocked,sig);
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock); spin_unlock_irq(&current->sig->siglock);
} }
} }
......
This diff is collapsed.
...@@ -47,18 +47,18 @@ static uint64_t init_timer_cc; ...@@ -47,18 +47,18 @@ static uint64_t init_timer_cc;
extern rwlock_t xtime_lock; extern rwlock_t xtime_lock;
extern unsigned long wall_jiffies; extern unsigned long wall_jiffies;
void tod_to_timeval(__u64 todval, struct timeval *xtime) void tod_to_timeval(__u64 todval, struct timespec *xtime)
{ {
todval >>= 12; xtime->tv_sec = (todval >> 12) / 1000000;
xtime->tv_sec = todval / 1000000; todval -= (xtime->tv_sec * 1000000) << 12;
xtime->tv_usec = todval % 1000000; xtime->tv_nsec = ((todval * 1000) >> 12);
} }
static inline unsigned long do_gettimeoffset(void) static inline unsigned long do_gettimeoffset(void)
{ {
__u64 now; __u64 now;
asm ("STCK 0(%0)" : : "a" (&now) : "memory", "cc"); asm volatile ("STCK 0(%0)" : : "a" (&now) : "memory", "cc");
now = (now - init_timer_cc) >> 12; now = (now - init_timer_cc) >> 12;
/* We require the offset from the latest update of xtime */ /* We require the offset from the latest update of xtime */
now -= (__u64) wall_jiffies*USECS_PER_JIFFY; now -= (__u64) wall_jiffies*USECS_PER_JIFFY;
...@@ -75,7 +75,7 @@ void do_gettimeofday(struct timeval *tv) ...@@ -75,7 +75,7 @@ void do_gettimeofday(struct timeval *tv)
read_lock_irqsave(&xtime_lock, flags); read_lock_irqsave(&xtime_lock, flags);
sec = xtime.tv_sec; sec = xtime.tv_sec;
usec = xtime.tv_usec + do_gettimeoffset(); usec = xtime.tv_nsec + do_gettimeoffset();
read_unlock_irqrestore(&xtime_lock, flags); read_unlock_irqrestore(&xtime_lock, flags);
while (usec >= 1000000) { while (usec >= 1000000) {
...@@ -104,7 +104,8 @@ void do_settimeofday(struct timeval *tv) ...@@ -104,7 +104,8 @@ void do_settimeofday(struct timeval *tv)
tv->tv_sec--; tv->tv_sec--;
} }
xtime = *tv; xtime.tv_sec = tv->tv_sec;
xtime.tv_nsec = tv->tv_usec * 1000;
time_adjust = 0; /* stop active adjtime() */ time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC; time_status |= STA_UNSYNC;
time_maxerror = NTP_PHASE_LIMIT; time_maxerror = NTP_PHASE_LIMIT;
...@@ -125,7 +126,7 @@ static void do_comparator_interrupt(struct pt_regs *regs, __u16 error_code) ...@@ -125,7 +126,7 @@ static void do_comparator_interrupt(struct pt_regs *regs, __u16 error_code)
{ {
int cpu = smp_processor_id(); int cpu = smp_processor_id();
irq_enter(cpu, 0); irq_enter();
/* /*
* set clock comparator for next tick * set clock comparator for next tick
...@@ -147,7 +148,7 @@ static void do_comparator_interrupt(struct pt_regs *regs, __u16 error_code) ...@@ -147,7 +148,7 @@ static void do_comparator_interrupt(struct pt_regs *regs, __u16 error_code)
do_timer(regs); do_timer(regs);
#endif #endif
irq_exit(cpu, 0); irq_exit();
} }
/* /*
......
...@@ -172,6 +172,14 @@ void show_stack(unsigned long *sp) ...@@ -172,6 +172,14 @@ void show_stack(unsigned long *sp)
show_trace(sp); show_trace(sp);
} }
/*
* The architecture-independent dump_stack generator
*/
void dump_stack(void)
{
show_stack(0);
}
void show_registers(struct pt_regs *regs) void show_registers(struct pt_regs *regs)
{ {
mm_segment_t old_fs; mm_segment_t old_fs;
......
...@@ -45,7 +45,6 @@ extern spinlock_t timerlist_lock; ...@@ -45,7 +45,6 @@ extern spinlock_t timerlist_lock;
*/ */
void bust_spinlocks(int yes) void bust_spinlocks(int yes)
{ {
spin_lock_init(&timerlist_lock);
if (yes) { if (yes) {
oops_in_progress = 1; oops_in_progress = 1;
} else { } else {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment