mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 patches from Martin Schwidefsky: "The biggest patch is the rework of the smp code, something I wanted to do for some time. There are some patches for our various dump methods and one new thing: z/VM LGR detection. LGR stands for linux-guest- relocation and is the guest migration feature of z/VM. For debugging purposes we keep a log of the systems where a specific guest has lived." Fix up trivial conflict in arch/s390/kernel/smp.c due to the scheduler cleanup having removed some code next to removed s390 code. * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: [S390] kernel: Pass correct stack for smp_call_ipl_cpu() [S390] Ensure that vmcore_info pointer is never accessed directly [S390] dasd: prevent validate server for offline devices [S390] Remove monolithic build option for zcrypt driver. [S390] stack dump: fix indentation in output [S390] kernel: Add OS info memory interface [S390] Use block_sigmask() [S390] kernel: Add z/VM LGR detection [S390] irq: external interrupt code passing [S390] irq: set __ARCH_IRQ_EXIT_IRQS_DISABLED [S390] zfcpdump: Implement async sdias event processing [S390] Use copy_to_absolute_zero() instead of "stura/sturg" [S390] rework idle code [S390] rework smp code [S390] rename lowcore field [S390] Fix gcc 4.6.0 compile warning
This commit is contained in:
@@ -23,7 +23,7 @@ CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w
|
||||
obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o vtime.o \
|
||||
processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o \
|
||||
debug.o irq.o ipl.o dis.o diag.o mem_detect.o sclp.o vdso.o \
|
||||
sysinfo.o jump_label.o
|
||||
sysinfo.o jump_label.o lgr.o os_info.o
|
||||
|
||||
obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o)
|
||||
obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
|
||||
@@ -34,8 +34,6 @@ extra-y += $(if $(CONFIG_64BIT),head64.o,head31.o)
|
||||
obj-$(CONFIG_MODULES) += s390_ksyms.o module.o
|
||||
obj-$(CONFIG_SMP) += smp.o
|
||||
obj-$(CONFIG_SCHED_BOOK) += topology.o
|
||||
obj-$(CONFIG_SMP) += $(if $(CONFIG_64BIT),switch_cpu64.o, \
|
||||
switch_cpu.o)
|
||||
obj-$(CONFIG_HIBERNATION) += suspend.o swsusp_asm64.o
|
||||
obj-$(CONFIG_AUDIT) += audit.o
|
||||
compat-obj-$(CONFIG_AUDIT) += compat_audit.o
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
|
||||
#include <linux/kbuild.h>
|
||||
#include <linux/sched.h>
|
||||
#include <asm/cputime.h>
|
||||
#include <asm/timer.h>
|
||||
#include <asm/vdso.h>
|
||||
#include <asm/sigp.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
/*
|
||||
* Make sure that the compiler is new enough. We want a compiler that
|
||||
@@ -70,15 +72,15 @@ int main(void)
|
||||
DEFINE(__CLOCK_MONOTONIC, CLOCK_MONOTONIC);
|
||||
DEFINE(__CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC);
|
||||
BLANK();
|
||||
/* constants for SIGP */
|
||||
DEFINE(__SIGP_STOP, sigp_stop);
|
||||
DEFINE(__SIGP_RESTART, sigp_restart);
|
||||
DEFINE(__SIGP_SENSE, sigp_sense);
|
||||
DEFINE(__SIGP_INITIAL_CPU_RESET, sigp_initial_cpu_reset);
|
||||
BLANK();
|
||||
/* idle data offsets */
|
||||
DEFINE(__IDLE_ENTER, offsetof(struct s390_idle_data, idle_enter));
|
||||
DEFINE(__IDLE_EXIT, offsetof(struct s390_idle_data, idle_exit));
|
||||
/* vtimer queue offsets */
|
||||
DEFINE(__VQ_IDLE_ENTER, offsetof(struct vtimer_queue, idle_enter));
|
||||
DEFINE(__VQ_IDLE_EXIT, offsetof(struct vtimer_queue, idle_exit));
|
||||
/* lowcore offsets */
|
||||
DEFINE(__LC_EXT_PARAMS, offsetof(struct _lowcore, ext_params));
|
||||
DEFINE(__LC_CPU_ADDRESS, offsetof(struct _lowcore, cpu_addr));
|
||||
DEFINE(__LC_EXT_CPU_ADDR, offsetof(struct _lowcore, ext_cpu_addr));
|
||||
DEFINE(__LC_EXT_INT_CODE, offsetof(struct _lowcore, ext_int_code));
|
||||
DEFINE(__LC_SVC_ILC, offsetof(struct _lowcore, svc_ilc));
|
||||
DEFINE(__LC_SVC_INT_CODE, offsetof(struct _lowcore, svc_code));
|
||||
@@ -95,20 +97,19 @@ int main(void)
|
||||
DEFINE(__LC_IO_INT_WORD, offsetof(struct _lowcore, io_int_word));
|
||||
DEFINE(__LC_STFL_FAC_LIST, offsetof(struct _lowcore, stfl_fac_list));
|
||||
DEFINE(__LC_MCCK_CODE, offsetof(struct _lowcore, mcck_interruption_code));
|
||||
DEFINE(__LC_DUMP_REIPL, offsetof(struct _lowcore, ipib));
|
||||
BLANK();
|
||||
DEFINE(__LC_RST_NEW_PSW, offsetof(struct _lowcore, restart_psw));
|
||||
DEFINE(__LC_RST_OLD_PSW, offsetof(struct _lowcore, restart_old_psw));
|
||||
DEFINE(__LC_EXT_OLD_PSW, offsetof(struct _lowcore, external_old_psw));
|
||||
DEFINE(__LC_SVC_OLD_PSW, offsetof(struct _lowcore, svc_old_psw));
|
||||
DEFINE(__LC_PGM_OLD_PSW, offsetof(struct _lowcore, program_old_psw));
|
||||
DEFINE(__LC_MCK_OLD_PSW, offsetof(struct _lowcore, mcck_old_psw));
|
||||
DEFINE(__LC_IO_OLD_PSW, offsetof(struct _lowcore, io_old_psw));
|
||||
DEFINE(__LC_RST_NEW_PSW, offsetof(struct _lowcore, restart_psw));
|
||||
DEFINE(__LC_EXT_NEW_PSW, offsetof(struct _lowcore, external_new_psw));
|
||||
DEFINE(__LC_SVC_NEW_PSW, offsetof(struct _lowcore, svc_new_psw));
|
||||
DEFINE(__LC_PGM_NEW_PSW, offsetof(struct _lowcore, program_new_psw));
|
||||
DEFINE(__LC_MCK_NEW_PSW, offsetof(struct _lowcore, mcck_new_psw));
|
||||
DEFINE(__LC_IO_NEW_PSW, offsetof(struct _lowcore, io_new_psw));
|
||||
BLANK();
|
||||
DEFINE(__LC_SAVE_AREA_SYNC, offsetof(struct _lowcore, save_area_sync));
|
||||
DEFINE(__LC_SAVE_AREA_ASYNC, offsetof(struct _lowcore, save_area_async));
|
||||
DEFINE(__LC_SAVE_AREA_RESTART, offsetof(struct _lowcore, save_area_restart));
|
||||
@@ -129,12 +130,16 @@ int main(void)
|
||||
DEFINE(__LC_KERNEL_STACK, offsetof(struct _lowcore, kernel_stack));
|
||||
DEFINE(__LC_ASYNC_STACK, offsetof(struct _lowcore, async_stack));
|
||||
DEFINE(__LC_PANIC_STACK, offsetof(struct _lowcore, panic_stack));
|
||||
DEFINE(__LC_RESTART_STACK, offsetof(struct _lowcore, restart_stack));
|
||||
DEFINE(__LC_RESTART_FN, offsetof(struct _lowcore, restart_fn));
|
||||
DEFINE(__LC_USER_ASCE, offsetof(struct _lowcore, user_asce));
|
||||
DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock));
|
||||
DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock));
|
||||
DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags));
|
||||
DEFINE(__LC_FTRACE_FUNC, offsetof(struct _lowcore, ftrace_func));
|
||||
DEFINE(__LC_IRB, offsetof(struct _lowcore, irb));
|
||||
DEFINE(__LC_DUMP_REIPL, offsetof(struct _lowcore, ipib));
|
||||
BLANK();
|
||||
DEFINE(__LC_CPU_TIMER_SAVE_AREA, offsetof(struct _lowcore, cpu_timer_save_area));
|
||||
DEFINE(__LC_CLOCK_COMP_SAVE_AREA, offsetof(struct _lowcore, clock_comp_save_area));
|
||||
DEFINE(__LC_PSW_SAVE_AREA, offsetof(struct _lowcore, psw_save_area));
|
||||
|
||||
@@ -581,7 +581,6 @@ give_sigsegv:
|
||||
int handle_signal32(unsigned long sig, struct k_sigaction *ka,
|
||||
siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
|
||||
{
|
||||
sigset_t blocked;
|
||||
int ret;
|
||||
|
||||
/* Set up the stack frame */
|
||||
@@ -591,10 +590,7 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka,
|
||||
ret = setup_frame32(sig, ka, oldset, regs);
|
||||
if (ret)
|
||||
return ret;
|
||||
sigorsets(&blocked, ¤t->blocked, &ka->sa.sa_mask);
|
||||
if (!(ka->sa.sa_flags & SA_NODEFER))
|
||||
sigaddset(&blocked, sig);
|
||||
set_current_blocked(&blocked);
|
||||
block_sigmask(ka, sig);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/elf.h>
|
||||
#include <asm/ipl.h>
|
||||
#include <asm/os_info.h>
|
||||
|
||||
#define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y)))
|
||||
#define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y)))
|
||||
@@ -51,7 +52,7 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
|
||||
/*
|
||||
* Copy memory from old kernel
|
||||
*/
|
||||
static int copy_from_oldmem(void *dest, void *src, size_t count)
|
||||
int copy_from_oldmem(void *dest, void *src, size_t count)
|
||||
{
|
||||
unsigned long copied = 0;
|
||||
int rc;
|
||||
@@ -224,28 +225,44 @@ static void *nt_prpsinfo(void *ptr)
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize vmcoreinfo note (new kernel)
|
||||
* Get vmcoreinfo using lowcore->vmcore_info (new kernel)
|
||||
*/
|
||||
static void *nt_vmcoreinfo(void *ptr)
|
||||
static void *get_vmcoreinfo_old(unsigned long *size)
|
||||
{
|
||||
char nt_name[11], *vmcoreinfo;
|
||||
Elf64_Nhdr note;
|
||||
void *addr;
|
||||
|
||||
if (copy_from_oldmem(&addr, &S390_lowcore.vmcore_info, sizeof(addr)))
|
||||
return ptr;
|
||||
return NULL;
|
||||
memset(nt_name, 0, sizeof(nt_name));
|
||||
if (copy_from_oldmem(¬e, addr, sizeof(note)))
|
||||
return ptr;
|
||||
return NULL;
|
||||
if (copy_from_oldmem(nt_name, addr + sizeof(note), sizeof(nt_name) - 1))
|
||||
return ptr;
|
||||
return NULL;
|
||||
if (strcmp(nt_name, "VMCOREINFO") != 0)
|
||||
return ptr;
|
||||
vmcoreinfo = kzalloc_panic(note.n_descsz + 1);
|
||||
return NULL;
|
||||
vmcoreinfo = kzalloc_panic(note.n_descsz);
|
||||
if (copy_from_oldmem(vmcoreinfo, addr + 24, note.n_descsz))
|
||||
return NULL;
|
||||
*size = note.n_descsz;
|
||||
return vmcoreinfo;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize vmcoreinfo note (new kernel)
|
||||
*/
|
||||
static void *nt_vmcoreinfo(void *ptr)
|
||||
{
|
||||
unsigned long size;
|
||||
void *vmcoreinfo;
|
||||
|
||||
vmcoreinfo = os_info_old_entry(OS_INFO_VMCOREINFO, &size);
|
||||
if (!vmcoreinfo)
|
||||
vmcoreinfo = get_vmcoreinfo_old(&size);
|
||||
if (!vmcoreinfo)
|
||||
return ptr;
|
||||
vmcoreinfo[note.n_descsz + 1] = 0;
|
||||
return nt_init(ptr, 0, vmcoreinfo, note.n_descsz, "VMCOREINFO");
|
||||
return nt_init(ptr, 0, vmcoreinfo, size, "VMCOREINFO");
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
* arch/s390/kernel/debug.c
|
||||
* S/390 debug facility
|
||||
*
|
||||
* Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
|
||||
* IBM Corporation
|
||||
* Copyright IBM Corp. 1999, 2012
|
||||
*
|
||||
* Author(s): Michael Holzheu (holzheu@de.ibm.com),
|
||||
* Holger Smolinski (Holger.Smolinski@de.ibm.com)
|
||||
*
|
||||
@@ -167,6 +167,7 @@ static debug_info_t *debug_area_last = NULL;
|
||||
static DEFINE_MUTEX(debug_mutex);
|
||||
|
||||
static int initialized;
|
||||
static int debug_critical;
|
||||
|
||||
static const struct file_operations debug_file_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
@@ -932,6 +933,11 @@ debug_stop_all(void)
|
||||
}
|
||||
|
||||
|
||||
void debug_set_critical(void)
|
||||
{
|
||||
debug_critical = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* debug_event_common:
|
||||
* - write debug entry with given size
|
||||
@@ -945,7 +951,11 @@ debug_event_common(debug_info_t * id, int level, const void *buf, int len)
|
||||
|
||||
if (!debug_active || !id->areas)
|
||||
return NULL;
|
||||
spin_lock_irqsave(&id->lock, flags);
|
||||
if (debug_critical) {
|
||||
if (!spin_trylock_irqsave(&id->lock, flags))
|
||||
return NULL;
|
||||
} else
|
||||
spin_lock_irqsave(&id->lock, flags);
|
||||
active = get_active_entry(id);
|
||||
memset(DEBUG_DATA(active), 0, id->buf_size);
|
||||
memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size));
|
||||
@@ -968,7 +978,11 @@ debug_entry_t
|
||||
|
||||
if (!debug_active || !id->areas)
|
||||
return NULL;
|
||||
spin_lock_irqsave(&id->lock, flags);
|
||||
if (debug_critical) {
|
||||
if (!spin_trylock_irqsave(&id->lock, flags))
|
||||
return NULL;
|
||||
} else
|
||||
spin_lock_irqsave(&id->lock, flags);
|
||||
active = get_active_entry(id);
|
||||
memset(DEBUG_DATA(active), 0, id->buf_size);
|
||||
memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size));
|
||||
@@ -1013,7 +1027,11 @@ debug_sprintf_event(debug_info_t* id, int level,char *string,...)
|
||||
return NULL;
|
||||
numargs=debug_count_numargs(string);
|
||||
|
||||
spin_lock_irqsave(&id->lock, flags);
|
||||
if (debug_critical) {
|
||||
if (!spin_trylock_irqsave(&id->lock, flags))
|
||||
return NULL;
|
||||
} else
|
||||
spin_lock_irqsave(&id->lock, flags);
|
||||
active = get_active_entry(id);
|
||||
curr_event=(debug_sprintf_entry_t *) DEBUG_DATA(active);
|
||||
va_start(ap,string);
|
||||
@@ -1047,7 +1065,11 @@ debug_sprintf_exception(debug_info_t* id, int level,char *string,...)
|
||||
|
||||
numargs=debug_count_numargs(string);
|
||||
|
||||
spin_lock_irqsave(&id->lock, flags);
|
||||
if (debug_critical) {
|
||||
if (!spin_trylock_irqsave(&id->lock, flags))
|
||||
return NULL;
|
||||
} else
|
||||
spin_lock_irqsave(&id->lock, flags);
|
||||
active = get_active_entry(id);
|
||||
curr_event=(debug_sprintf_entry_t *)DEBUG_DATA(active);
|
||||
va_start(ap,string);
|
||||
@@ -1428,10 +1450,10 @@ debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
|
||||
rc += sprintf(out_buf + rc, "| ");
|
||||
for (i = 0; i < id->buf_size; i++) {
|
||||
unsigned char c = in_buf[i];
|
||||
if (!isprint(c))
|
||||
rc += sprintf(out_buf + rc, ".");
|
||||
else
|
||||
if (isascii(c) && isprint(c))
|
||||
rc += sprintf(out_buf + rc, "%c", c);
|
||||
else
|
||||
rc += sprintf(out_buf + rc, ".");
|
||||
}
|
||||
rc += sprintf(out_buf + rc, "\n");
|
||||
return rc;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <asm/sysinfo.h>
|
||||
#include <asm/cpcmd.h>
|
||||
#include <asm/sclp.h>
|
||||
#include <asm/system.h>
|
||||
#include "entry.h"
|
||||
|
||||
/*
|
||||
@@ -262,25 +263,8 @@ static noinline __init void setup_lowcore_early(void)
|
||||
|
||||
static noinline __init void setup_facility_list(void)
|
||||
{
|
||||
unsigned long nr;
|
||||
|
||||
S390_lowcore.stfl_fac_list = 0;
|
||||
asm volatile(
|
||||
" .insn s,0xb2b10000,0(0)\n" /* stfl */
|
||||
"0:\n"
|
||||
EX_TABLE(0b,0b) : "=m" (S390_lowcore.stfl_fac_list));
|
||||
memcpy(&S390_lowcore.stfle_fac_list, &S390_lowcore.stfl_fac_list, 4);
|
||||
nr = 4; /* # bytes stored by stfl */
|
||||
if (test_facility(7)) {
|
||||
/* More facility bits available with stfle */
|
||||
register unsigned long reg0 asm("0") = MAX_FACILITY_BIT/64 - 1;
|
||||
asm volatile(".insn s,0xb2b00000,%0" /* stfle */
|
||||
: "=m" (S390_lowcore.stfle_fac_list), "+d" (reg0)
|
||||
: : "cc");
|
||||
nr = (reg0 + 1) * 8; /* # bytes stored by stfle */
|
||||
}
|
||||
memset((char *) S390_lowcore.stfle_fac_list + nr, 0,
|
||||
MAX_FACILITY_BIT/8 - nr);
|
||||
stfle(S390_lowcore.stfle_fac_list,
|
||||
ARRAY_SIZE(S390_lowcore.stfle_fac_list));
|
||||
}
|
||||
|
||||
static noinline __init void setup_hpage(void)
|
||||
|
||||
+88
-71
@@ -2,7 +2,7 @@
|
||||
* arch/s390/kernel/entry.S
|
||||
* S390 low-level entry points.
|
||||
*
|
||||
* Copyright (C) IBM Corp. 1999,2006
|
||||
* Copyright (C) IBM Corp. 1999,2012
|
||||
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
|
||||
* Hartmut Penner (hp@de.ibm.com),
|
||||
* Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
|
||||
@@ -105,14 +105,14 @@ STACK_SIZE = 1 << STACK_SHIFT
|
||||
|
||||
.macro ADD64 high,low,timer
|
||||
al \high,\timer
|
||||
al \low,\timer+4
|
||||
al \low,4+\timer
|
||||
brc 12,.+8
|
||||
ahi \high,1
|
||||
.endm
|
||||
|
||||
.macro SUB64 high,low,timer
|
||||
sl \high,\timer
|
||||
sl \low,\timer+4
|
||||
sl \low,4+\timer
|
||||
brc 3,.+8
|
||||
ahi \high,-1
|
||||
.endm
|
||||
@@ -471,7 +471,6 @@ io_tif:
|
||||
jnz io_work # there is work to do (signals etc.)
|
||||
io_restore:
|
||||
mvc __LC_RETURN_PSW(8),__PT_PSW(%r11)
|
||||
ni __LC_RETURN_PSW+1,0xfd # clean wait state bit
|
||||
stpt __LC_EXIT_TIMER
|
||||
lm %r0,%r15,__PT_R0(%r11)
|
||||
lpsw __LC_RETURN_PSW
|
||||
@@ -606,12 +605,32 @@ ext_skip:
|
||||
stm %r8,%r9,__PT_PSW(%r11)
|
||||
TRACE_IRQS_OFF
|
||||
lr %r2,%r11 # pass pointer to pt_regs
|
||||
l %r3,__LC_CPU_ADDRESS # get cpu address + interruption code
|
||||
l %r3,__LC_EXT_CPU_ADDR # get cpu address + interruption code
|
||||
l %r4,__LC_EXT_PARAMS # get external parameters
|
||||
l %r1,BASED(.Ldo_extint)
|
||||
basr %r14,%r1 # call do_extint
|
||||
j io_return
|
||||
|
||||
/*
|
||||
* Load idle PSW. The second "half" of this function is in cleanup_idle.
|
||||
*/
|
||||
ENTRY(psw_idle)
|
||||
st %r4,__SF_EMPTY(%r15)
|
||||
basr %r1,0
|
||||
la %r1,psw_idle_lpsw+4-.(%r1)
|
||||
st %r1,__SF_EMPTY+4(%r15)
|
||||
oi __SF_EMPTY+4(%r15),0x80
|
||||
la %r1,.Lvtimer_max-psw_idle_lpsw-4(%r1)
|
||||
stck __IDLE_ENTER(%r2)
|
||||
ltr %r5,%r5
|
||||
stpt __VQ_IDLE_ENTER(%r3)
|
||||
jz psw_idle_lpsw
|
||||
spt 0(%r1)
|
||||
psw_idle_lpsw:
|
||||
lpsw __SF_EMPTY(%r15)
|
||||
br %r14
|
||||
psw_idle_end:
|
||||
|
||||
__critical_end:
|
||||
|
||||
/*
|
||||
@@ -673,7 +692,6 @@ mcck_skip:
|
||||
TRACE_IRQS_ON
|
||||
mcck_return:
|
||||
mvc __LC_RETURN_MCCK_PSW(8),__PT_PSW(%r11) # move return PSW
|
||||
ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit
|
||||
tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ?
|
||||
jno 0f
|
||||
lm %r0,%r15,__PT_R0(%r11)
|
||||
@@ -691,77 +709,30 @@ mcck_panic:
|
||||
0: ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
|
||||
j mcck_skip
|
||||
|
||||
/*
|
||||
* Restart interruption handler, kick starter for additional CPUs
|
||||
*/
|
||||
#ifdef CONFIG_SMP
|
||||
__CPUINIT
|
||||
ENTRY(restart_int_handler)
|
||||
basr %r1,0
|
||||
restart_base:
|
||||
spt restart_vtime-restart_base(%r1)
|
||||
stck __LC_LAST_UPDATE_CLOCK
|
||||
mvc __LC_LAST_UPDATE_TIMER(8),restart_vtime-restart_base(%r1)
|
||||
mvc __LC_EXIT_TIMER(8),restart_vtime-restart_base(%r1)
|
||||
l %r15,__LC_GPREGS_SAVE_AREA+60 # load ksp
|
||||
lctl %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs
|
||||
lam %a0,%a15,__LC_AREGS_SAVE_AREA
|
||||
lm %r6,%r15,__SF_GPRS(%r15)# load registers from clone
|
||||
l %r1,__LC_THREAD_INFO
|
||||
mvc __LC_USER_TIMER(8),__TI_user_timer(%r1)
|
||||
mvc __LC_SYSTEM_TIMER(8),__TI_system_timer(%r1)
|
||||
xc __LC_STEAL_TIMER(8),__LC_STEAL_TIMER
|
||||
ssm __LC_PGM_NEW_PSW # turn dat on, keep irqs off
|
||||
basr %r14,0
|
||||
l %r14,restart_addr-.(%r14)
|
||||
basr %r14,%r14 # call start_secondary
|
||||
restart_addr:
|
||||
.long start_secondary
|
||||
.align 8
|
||||
restart_vtime:
|
||||
.long 0x7fffffff,0xffffffff
|
||||
.previous
|
||||
#else
|
||||
/*
|
||||
* If we do not run with SMP enabled, let the new CPU crash ...
|
||||
*/
|
||||
ENTRY(restart_int_handler)
|
||||
basr %r1,0
|
||||
restart_base:
|
||||
lpsw restart_crash-restart_base(%r1)
|
||||
.align 8
|
||||
restart_crash:
|
||||
.long 0x000a0000,0x00000000
|
||||
restart_go:
|
||||
#endif
|
||||
|
||||
#
|
||||
# PSW restart interrupt handler
|
||||
#
|
||||
ENTRY(psw_restart_int_handler)
|
||||
ENTRY(restart_int_handler)
|
||||
st %r15,__LC_SAVE_AREA_RESTART
|
||||
basr %r15,0
|
||||
0: l %r15,.Lrestart_stack-0b(%r15) # load restart stack
|
||||
l %r15,0(%r15)
|
||||
l %r15,__LC_RESTART_STACK
|
||||
ahi %r15,-__PT_SIZE # create pt_regs on stack
|
||||
xc 0(__PT_SIZE,%r15),0(%r15)
|
||||
stm %r0,%r14,__PT_R0(%r15)
|
||||
mvc __PT_R15(4,%r15),__LC_SAVE_AREA_RESTART
|
||||
mvc __PT_PSW(8,%r15),__LC_RST_OLD_PSW # store restart old psw
|
||||
ahi %r15,-STACK_FRAME_OVERHEAD
|
||||
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
|
||||
basr %r14,0
|
||||
1: l %r14,.Ldo_restart-1b(%r14)
|
||||
basr %r14,%r14
|
||||
basr %r14,0 # load disabled wait PSW if
|
||||
2: lpsw restart_psw_crash-2b(%r14) # do_restart returns
|
||||
.align 4
|
||||
.Ldo_restart:
|
||||
.long do_restart
|
||||
.Lrestart_stack:
|
||||
.long restart_stack
|
||||
.align 8
|
||||
restart_psw_crash:
|
||||
.long 0x000a0000,0x00000000 + restart_psw_crash
|
||||
ahi %r15,-STACK_FRAME_OVERHEAD # create stack frame on stack
|
||||
xc 0(STACK_FRAME_OVERHEAD,%r15),0(%r15)
|
||||
lm %r1,%r3,__LC_RESTART_FN # load fn, parm & source cpu
|
||||
ltr %r3,%r3 # test source cpu address
|
||||
jm 1f # negative -> skip source stop
|
||||
0: sigp %r4,%r3,1 # sigp sense to source cpu
|
||||
brc 10,0b # wait for status stored
|
||||
1: basr %r14,%r1 # call function
|
||||
stap __SF_EMPTY(%r15) # store cpu address
|
||||
lh %r3,__SF_EMPTY(%r15)
|
||||
2: sigp %r4,%r3,5 # sigp stop to current cpu
|
||||
brc 2,2b
|
||||
3: j 3b
|
||||
|
||||
.section .kprobes.text, "ax"
|
||||
|
||||
@@ -795,6 +766,8 @@ cleanup_table:
|
||||
.long io_tif + 0x80000000
|
||||
.long io_restore + 0x80000000
|
||||
.long io_done + 0x80000000
|
||||
.long psw_idle + 0x80000000
|
||||
.long psw_idle_end + 0x80000000
|
||||
|
||||
cleanup_critical:
|
||||
cl %r9,BASED(cleanup_table) # system_call
|
||||
@@ -813,6 +786,10 @@ cleanup_critical:
|
||||
jl cleanup_io_tif
|
||||
cl %r9,BASED(cleanup_table+28) # io_done
|
||||
jl cleanup_io_restore
|
||||
cl %r9,BASED(cleanup_table+32) # psw_idle
|
||||
jl 0f
|
||||
cl %r9,BASED(cleanup_table+36) # psw_idle_end
|
||||
jl cleanup_idle
|
||||
0: br %r14
|
||||
|
||||
cleanup_system_call:
|
||||
@@ -896,7 +873,6 @@ cleanup_io_restore:
|
||||
jhe 0f
|
||||
l %r9,12(%r11) # get saved r11 pointer to pt_regs
|
||||
mvc __LC_RETURN_PSW(8),__PT_PSW(%r9)
|
||||
ni __LC_RETURN_PSW+1,0xfd # clear wait state bit
|
||||
mvc 0(32,%r11),__PT_R8(%r9)
|
||||
lm %r0,%r7,__PT_R0(%r9)
|
||||
0: lm %r8,%r9,__LC_RETURN_PSW
|
||||
@@ -904,11 +880,52 @@ cleanup_io_restore:
|
||||
cleanup_io_restore_insn:
|
||||
.long io_done - 4 + 0x80000000
|
||||
|
||||
cleanup_idle:
|
||||
# copy interrupt clock & cpu timer
|
||||
mvc __IDLE_EXIT(8,%r2),__LC_INT_CLOCK
|
||||
mvc __VQ_IDLE_EXIT(8,%r3),__LC_ASYNC_ENTER_TIMER
|
||||
chi %r11,__LC_SAVE_AREA_ASYNC
|
||||
je 0f
|
||||
mvc __IDLE_EXIT(8,%r2),__LC_MCCK_CLOCK
|
||||
mvc __VQ_IDLE_EXIT(8,%r3),__LC_MCCK_ENTER_TIMER
|
||||
0: # check if stck has been executed
|
||||
cl %r9,BASED(cleanup_idle_insn)
|
||||
jhe 1f
|
||||
mvc __IDLE_ENTER(8,%r2),__IDLE_EXIT(%r2)
|
||||
mvc __VQ_IDLE_ENTER(8,%r3),__VQ_IDLE_EXIT(%r3)
|
||||
j 2f
|
||||
1: # check if the cpu timer has been reprogrammed
|
||||
ltr %r5,%r5
|
||||
jz 2f
|
||||
spt __VQ_IDLE_ENTER(%r3)
|
||||
2: # account system time going idle
|
||||
lm %r9,%r10,__LC_STEAL_TIMER
|
||||
ADD64 %r9,%r10,__IDLE_ENTER(%r2)
|
||||
SUB64 %r9,%r10,__LC_LAST_UPDATE_CLOCK
|
||||
stm %r9,%r10,__LC_STEAL_TIMER
|
||||
mvc __LC_LAST_UPDATE_CLOCK(8),__IDLE_EXIT(%r2)
|
||||
lm %r9,%r10,__LC_SYSTEM_TIMER
|
||||
ADD64 %r9,%r10,__LC_LAST_UPDATE_TIMER
|
||||
SUB64 %r9,%r10,__VQ_IDLE_ENTER(%r3)
|
||||
stm %r9,%r10,__LC_SYSTEM_TIMER
|
||||
mvc __LC_LAST_UPDATE_TIMER(8),__VQ_IDLE_EXIT(%r3)
|
||||
# prepare return psw
|
||||
n %r8,BASED(cleanup_idle_wait) # clear wait state bit
|
||||
l %r9,24(%r11) # return from psw_idle
|
||||
br %r14
|
||||
cleanup_idle_insn:
|
||||
.long psw_idle_lpsw + 0x80000000
|
||||
cleanup_idle_wait:
|
||||
.long 0xfffdffff
|
||||
|
||||
/*
|
||||
* Integer constants
|
||||
*/
|
||||
.align 4
|
||||
.Lnr_syscalls: .long NR_syscalls
|
||||
.Lnr_syscalls:
|
||||
.long NR_syscalls
|
||||
.Lvtimer_max:
|
||||
.quad 0x7fffffffffffffff
|
||||
|
||||
/*
|
||||
* Symbol constants
|
||||
|
||||
@@ -4,11 +4,22 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/signal.h>
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
#include <asm/cputime.h>
|
||||
#include <asm/timer.h>
|
||||
|
||||
extern void (*pgm_check_table[128])(struct pt_regs *);
|
||||
extern void *restart_stack;
|
||||
|
||||
void system_call(void);
|
||||
void pgm_check_handler(void);
|
||||
void ext_int_handler(void);
|
||||
void io_int_handler(void);
|
||||
void mcck_int_handler(void);
|
||||
void restart_int_handler(void);
|
||||
void restart_call_handler(void);
|
||||
void psw_idle(struct s390_idle_data *, struct vtimer_queue *,
|
||||
unsigned long, int);
|
||||
|
||||
asmlinkage long do_syscall_trace_enter(struct pt_regs *regs);
|
||||
asmlinkage void do_syscall_trace_exit(struct pt_regs *regs);
|
||||
|
||||
@@ -24,9 +35,9 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka,
|
||||
siginfo_t *info, sigset_t *oldset, struct pt_regs *regs);
|
||||
void do_notify_resume(struct pt_regs *regs);
|
||||
|
||||
void do_extint(struct pt_regs *regs, unsigned int, unsigned int, unsigned long);
|
||||
struct ext_code;
|
||||
void do_extint(struct pt_regs *regs, struct ext_code, unsigned int, unsigned long);
|
||||
void do_restart(void);
|
||||
int __cpuinit start_secondary(void *cpuvoid);
|
||||
void __init startup_init(void);
|
||||
void die(struct pt_regs *regs, const char *str);
|
||||
|
||||
|
||||
+80
-59
@@ -2,7 +2,7 @@
|
||||
* arch/s390/kernel/entry64.S
|
||||
* S390 low-level entry points.
|
||||
*
|
||||
* Copyright (C) IBM Corp. 1999,2010
|
||||
* Copyright (C) IBM Corp. 1999,2012
|
||||
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
|
||||
* Hartmut Penner (hp@de.ibm.com),
|
||||
* Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
|
||||
@@ -489,7 +489,6 @@ io_restore:
|
||||
lg %r14,__LC_VDSO_PER_CPU
|
||||
lmg %r0,%r10,__PT_R0(%r11)
|
||||
mvc __LC_RETURN_PSW(16),__PT_PSW(%r11)
|
||||
ni __LC_RETURN_PSW+1,0xfd # clear wait state bit
|
||||
stpt __LC_EXIT_TIMER
|
||||
mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER
|
||||
lmg %r11,%r15,__PT_R11(%r11)
|
||||
@@ -625,12 +624,30 @@ ext_skip:
|
||||
TRACE_IRQS_OFF
|
||||
lghi %r1,4096
|
||||
lgr %r2,%r11 # pass pointer to pt_regs
|
||||
llgf %r3,__LC_CPU_ADDRESS # get cpu address + interruption code
|
||||
llgf %r3,__LC_EXT_CPU_ADDR # get cpu address + interruption code
|
||||
llgf %r4,__LC_EXT_PARAMS # get external parameter
|
||||
lg %r5,__LC_EXT_PARAMS2-4096(%r1) # get 64 bit external parameter
|
||||
brasl %r14,do_extint
|
||||
j io_return
|
||||
|
||||
/*
|
||||
* Load idle PSW. The second "half" of this function is in cleanup_idle.
|
||||
*/
|
||||
ENTRY(psw_idle)
|
||||
stg %r4,__SF_EMPTY(%r15)
|
||||
larl %r1,psw_idle_lpsw+4
|
||||
stg %r1,__SF_EMPTY+8(%r15)
|
||||
larl %r1,.Lvtimer_max
|
||||
stck __IDLE_ENTER(%r2)
|
||||
ltr %r5,%r5
|
||||
stpt __VQ_IDLE_ENTER(%r3)
|
||||
jz psw_idle_lpsw
|
||||
spt 0(%r1)
|
||||
psw_idle_lpsw:
|
||||
lpswe __SF_EMPTY(%r15)
|
||||
br %r14
|
||||
psw_idle_end:
|
||||
|
||||
__critical_end:
|
||||
|
||||
/*
|
||||
@@ -696,7 +713,6 @@ mcck_return:
|
||||
lg %r14,__LC_VDSO_PER_CPU
|
||||
lmg %r0,%r10,__PT_R0(%r11)
|
||||
mvc __LC_RETURN_MCCK_PSW(16),__PT_PSW(%r11) # move return PSW
|
||||
ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit
|
||||
tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ?
|
||||
jno 0f
|
||||
stpt __LC_EXIT_TIMER
|
||||
@@ -713,68 +729,30 @@ mcck_panic:
|
||||
0: aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
|
||||
j mcck_skip
|
||||
|
||||
/*
|
||||
* Restart interruption handler, kick starter for additional CPUs
|
||||
*/
|
||||
#ifdef CONFIG_SMP
|
||||
__CPUINIT
|
||||
ENTRY(restart_int_handler)
|
||||
basr %r1,0
|
||||
restart_base:
|
||||
spt restart_vtime-restart_base(%r1)
|
||||
stck __LC_LAST_UPDATE_CLOCK
|
||||
mvc __LC_LAST_UPDATE_TIMER(8),restart_vtime-restart_base(%r1)
|
||||
mvc __LC_EXIT_TIMER(8),restart_vtime-restart_base(%r1)
|
||||
lghi %r10,__LC_GPREGS_SAVE_AREA
|
||||
lg %r15,120(%r10) # load ksp
|
||||
lghi %r10,__LC_CREGS_SAVE_AREA
|
||||
lctlg %c0,%c15,0(%r10) # get new ctl regs
|
||||
lghi %r10,__LC_AREGS_SAVE_AREA
|
||||
lam %a0,%a15,0(%r10)
|
||||
lmg %r6,%r15,__SF_GPRS(%r15)# load registers from clone
|
||||
lg %r1,__LC_THREAD_INFO
|
||||
mvc __LC_USER_TIMER(8),__TI_user_timer(%r1)
|
||||
mvc __LC_SYSTEM_TIMER(8),__TI_system_timer(%r1)
|
||||
xc __LC_STEAL_TIMER(8),__LC_STEAL_TIMER
|
||||
ssm __LC_PGM_NEW_PSW # turn dat on, keep irqs off
|
||||
brasl %r14,start_secondary
|
||||
.align 8
|
||||
restart_vtime:
|
||||
.long 0x7fffffff,0xffffffff
|
||||
.previous
|
||||
#else
|
||||
/*
|
||||
* If we do not run with SMP enabled, let the new CPU crash ...
|
||||
*/
|
||||
ENTRY(restart_int_handler)
|
||||
basr %r1,0
|
||||
restart_base:
|
||||
lpswe restart_crash-restart_base(%r1)
|
||||
.align 8
|
||||
restart_crash:
|
||||
.long 0x000a0000,0x00000000,0x00000000,0x00000000
|
||||
restart_go:
|
||||
#endif
|
||||
|
||||
#
|
||||
# PSW restart interrupt handler
|
||||
#
|
||||
ENTRY(psw_restart_int_handler)
|
||||
ENTRY(restart_int_handler)
|
||||
stg %r15,__LC_SAVE_AREA_RESTART
|
||||
larl %r15,restart_stack # load restart stack
|
||||
lg %r15,0(%r15)
|
||||
lg %r15,__LC_RESTART_STACK
|
||||
aghi %r15,-__PT_SIZE # create pt_regs on stack
|
||||
xc 0(__PT_SIZE,%r15),0(%r15)
|
||||
stmg %r0,%r14,__PT_R0(%r15)
|
||||
mvc __PT_R15(8,%r15),__LC_SAVE_AREA_RESTART
|
||||
mvc __PT_PSW(16,%r15),__LC_RST_OLD_PSW # store restart old psw
|
||||
aghi %r15,-STACK_FRAME_OVERHEAD
|
||||
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
|
||||
brasl %r14,do_restart
|
||||
larl %r14,restart_psw_crash # load disabled wait PSW if
|
||||
lpswe 0(%r14) # do_restart returns
|
||||
.align 8
|
||||
restart_psw_crash:
|
||||
.quad 0x0002000080000000,0x0000000000000000 + restart_psw_crash
|
||||
aghi %r15,-STACK_FRAME_OVERHEAD # create stack frame on stack
|
||||
xc 0(STACK_FRAME_OVERHEAD,%r15),0(%r15)
|
||||
lmg %r1,%r3,__LC_RESTART_FN # load fn, parm & source cpu
|
||||
ltgr %r3,%r3 # test source cpu address
|
||||
jm 1f # negative -> skip source stop
|
||||
0: sigp %r4,%r3,1 # sigp sense to source cpu
|
||||
brc 10,0b # wait for status stored
|
||||
1: basr %r14,%r1 # call function
|
||||
stap __SF_EMPTY(%r15) # store cpu address
|
||||
llgh %r3,__SF_EMPTY(%r15)
|
||||
2: sigp %r4,%r3,5 # sigp stop to current cpu
|
||||
brc 2,2b
|
||||
3: j 3b
|
||||
|
||||
.section .kprobes.text, "ax"
|
||||
|
||||
@@ -808,6 +786,8 @@ cleanup_table:
|
||||
.quad io_tif
|
||||
.quad io_restore
|
||||
.quad io_done
|
||||
.quad psw_idle
|
||||
.quad psw_idle_end
|
||||
|
||||
cleanup_critical:
|
||||
clg %r9,BASED(cleanup_table) # system_call
|
||||
@@ -826,6 +806,10 @@ cleanup_critical:
|
||||
jl cleanup_io_tif
|
||||
clg %r9,BASED(cleanup_table+56) # io_done
|
||||
jl cleanup_io_restore
|
||||
clg %r9,BASED(cleanup_table+64) # psw_idle
|
||||
jl 0f
|
||||
clg %r9,BASED(cleanup_table+72) # psw_idle_end
|
||||
jl cleanup_idle
|
||||
0: br %r14
|
||||
|
||||
|
||||
@@ -915,7 +899,6 @@ cleanup_io_restore:
|
||||
je 0f
|
||||
lg %r9,24(%r11) # get saved r11 pointer to pt_regs
|
||||
mvc __LC_RETURN_PSW(16),__PT_PSW(%r9)
|
||||
ni __LC_RETURN_PSW+1,0xfd # clear wait state bit
|
||||
mvc 0(64,%r11),__PT_R8(%r9)
|
||||
lmg %r0,%r7,__PT_R0(%r9)
|
||||
0: lmg %r8,%r9,__LC_RETURN_PSW
|
||||
@@ -923,6 +906,42 @@ cleanup_io_restore:
|
||||
cleanup_io_restore_insn:
|
||||
.quad io_done - 4
|
||||
|
||||
cleanup_idle:
|
||||
# copy interrupt clock & cpu timer
|
||||
mvc __IDLE_EXIT(8,%r2),__LC_INT_CLOCK
|
||||
mvc __VQ_IDLE_EXIT(8,%r3),__LC_ASYNC_ENTER_TIMER
|
||||
cghi %r11,__LC_SAVE_AREA_ASYNC
|
||||
je 0f
|
||||
mvc __IDLE_EXIT(8,%r2),__LC_MCCK_CLOCK
|
||||
mvc __VQ_IDLE_EXIT(8,%r3),__LC_MCCK_ENTER_TIMER
|
||||
0: # check if stck & stpt have been executed
|
||||
clg %r9,BASED(cleanup_idle_insn)
|
||||
jhe 1f
|
||||
mvc __IDLE_ENTER(8,%r2),__IDLE_EXIT(%r2)
|
||||
mvc __VQ_IDLE_ENTER(8,%r3),__VQ_IDLE_EXIT(%r3)
|
||||
j 2f
|
||||
1: # check if the cpu timer has been reprogrammed
|
||||
ltr %r5,%r5
|
||||
jz 2f
|
||||
spt __VQ_IDLE_ENTER(%r3)
|
||||
2: # account system time going idle
|
||||
lg %r9,__LC_STEAL_TIMER
|
||||
alg %r9,__IDLE_ENTER(%r2)
|
||||
slg %r9,__LC_LAST_UPDATE_CLOCK
|
||||
stg %r9,__LC_STEAL_TIMER
|
||||
mvc __LC_LAST_UPDATE_CLOCK(8),__IDLE_EXIT(%r2)
|
||||
lg %r9,__LC_SYSTEM_TIMER
|
||||
alg %r9,__LC_LAST_UPDATE_TIMER
|
||||
slg %r9,__VQ_IDLE_ENTER(%r3)
|
||||
stg %r9,__LC_SYSTEM_TIMER
|
||||
mvc __LC_LAST_UPDATE_TIMER(8),__VQ_IDLE_EXIT(%r3)
|
||||
# prepare return psw
|
||||
nihh %r8,0xfffd # clear wait state bit
|
||||
lg %r9,48(%r11) # return from psw_idle
|
||||
br %r14
|
||||
cleanup_idle_insn:
|
||||
.quad psw_idle_lpsw
|
||||
|
||||
/*
|
||||
* Integer constants
|
||||
*/
|
||||
@@ -931,6 +950,8 @@ cleanup_io_restore_insn:
|
||||
.quad __critical_start
|
||||
.Lcritical_length:
|
||||
.quad __critical_end - __critical_start
|
||||
.Lvtimer_max:
|
||||
.quad 0x7fffffffffffffff
|
||||
|
||||
|
||||
#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
|
||||
|
||||
+58
-41
@@ -2,7 +2,7 @@
|
||||
* arch/s390/kernel/ipl.c
|
||||
* ipl/reipl/dump support for Linux on s390.
|
||||
*
|
||||
* Copyright IBM Corp. 2005,2007
|
||||
* Copyright IBM Corp. 2005,2012
|
||||
* Author(s): Michael Holzheu <holzheu@de.ibm.com>
|
||||
* Heiko Carstens <heiko.carstens@de.ibm.com>
|
||||
* Volker Sameske <sameske@de.ibm.com>
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/crash_dump.h>
|
||||
#include <linux/debug_locks.h>
|
||||
#include <asm/ipl.h>
|
||||
#include <asm/smp.h>
|
||||
#include <asm/setup.h>
|
||||
@@ -25,8 +26,9 @@
|
||||
#include <asm/ebcdic.h>
|
||||
#include <asm/reset.h>
|
||||
#include <asm/sclp.h>
|
||||
#include <asm/sigp.h>
|
||||
#include <asm/checksum.h>
|
||||
#include <asm/debug.h>
|
||||
#include <asm/os_info.h>
|
||||
#include "entry.h"
|
||||
|
||||
#define IPL_PARM_BLOCK_VERSION 0
|
||||
@@ -571,7 +573,7 @@ static void __ipl_run(void *unused)
|
||||
|
||||
static void ipl_run(struct shutdown_trigger *trigger)
|
||||
{
|
||||
smp_switch_to_ipl_cpu(__ipl_run, NULL);
|
||||
smp_call_ipl_cpu(__ipl_run, NULL);
|
||||
}
|
||||
|
||||
static int __init ipl_init(void)
|
||||
@@ -950,6 +952,13 @@ static struct attribute_group reipl_nss_attr_group = {
|
||||
.attrs = reipl_nss_attrs,
|
||||
};
|
||||
|
||||
static void set_reipl_block_actual(struct ipl_parameter_block *reipl_block)
|
||||
{
|
||||
reipl_block_actual = reipl_block;
|
||||
os_info_entry_add(OS_INFO_REIPL_BLOCK, reipl_block_actual,
|
||||
reipl_block->hdr.len);
|
||||
}
|
||||
|
||||
/* reipl type */
|
||||
|
||||
static int reipl_set_type(enum ipl_type type)
|
||||
@@ -965,7 +974,7 @@ static int reipl_set_type(enum ipl_type type)
|
||||
reipl_method = REIPL_METHOD_CCW_VM;
|
||||
else
|
||||
reipl_method = REIPL_METHOD_CCW_CIO;
|
||||
reipl_block_actual = reipl_block_ccw;
|
||||
set_reipl_block_actual(reipl_block_ccw);
|
||||
break;
|
||||
case IPL_TYPE_FCP:
|
||||
if (diag308_set_works)
|
||||
@@ -974,7 +983,7 @@ static int reipl_set_type(enum ipl_type type)
|
||||
reipl_method = REIPL_METHOD_FCP_RO_VM;
|
||||
else
|
||||
reipl_method = REIPL_METHOD_FCP_RO_DIAG;
|
||||
reipl_block_actual = reipl_block_fcp;
|
||||
set_reipl_block_actual(reipl_block_fcp);
|
||||
break;
|
||||
case IPL_TYPE_FCP_DUMP:
|
||||
reipl_method = REIPL_METHOD_FCP_DUMP;
|
||||
@@ -984,7 +993,7 @@ static int reipl_set_type(enum ipl_type type)
|
||||
reipl_method = REIPL_METHOD_NSS_DIAG;
|
||||
else
|
||||
reipl_method = REIPL_METHOD_NSS;
|
||||
reipl_block_actual = reipl_block_nss;
|
||||
set_reipl_block_actual(reipl_block_nss);
|
||||
break;
|
||||
case IPL_TYPE_UNKNOWN:
|
||||
reipl_method = REIPL_METHOD_DEFAULT;
|
||||
@@ -1101,7 +1110,7 @@ static void __reipl_run(void *unused)
|
||||
|
||||
static void reipl_run(struct shutdown_trigger *trigger)
|
||||
{
|
||||
smp_switch_to_ipl_cpu(__reipl_run, NULL);
|
||||
smp_call_ipl_cpu(__reipl_run, NULL);
|
||||
}
|
||||
|
||||
static void reipl_block_ccw_init(struct ipl_parameter_block *ipb)
|
||||
@@ -1256,6 +1265,29 @@ static int __init reipl_fcp_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init reipl_type_init(void)
|
||||
{
|
||||
enum ipl_type reipl_type = ipl_info.type;
|
||||
struct ipl_parameter_block *reipl_block;
|
||||
unsigned long size;
|
||||
|
||||
reipl_block = os_info_old_entry(OS_INFO_REIPL_BLOCK, &size);
|
||||
if (!reipl_block)
|
||||
goto out;
|
||||
/*
|
||||
* If we have an OS info reipl block, this will be used
|
||||
*/
|
||||
if (reipl_block->hdr.pbt == DIAG308_IPL_TYPE_FCP) {
|
||||
memcpy(reipl_block_fcp, reipl_block, size);
|
||||
reipl_type = IPL_TYPE_FCP;
|
||||
} else if (reipl_block->hdr.pbt == DIAG308_IPL_TYPE_CCW) {
|
||||
memcpy(reipl_block_ccw, reipl_block, size);
|
||||
reipl_type = IPL_TYPE_CCW;
|
||||
}
|
||||
out:
|
||||
return reipl_set_type(reipl_type);
|
||||
}
|
||||
|
||||
static int __init reipl_init(void)
|
||||
{
|
||||
int rc;
|
||||
@@ -1277,10 +1309,7 @@ static int __init reipl_init(void)
|
||||
rc = reipl_nss_init();
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = reipl_set_type(ipl_info.type);
|
||||
if (rc)
|
||||
return rc;
|
||||
return 0;
|
||||
return reipl_type_init();
|
||||
}
|
||||
|
||||
static struct shutdown_action __refdata reipl_action = {
|
||||
@@ -1421,7 +1450,7 @@ static void dump_run(struct shutdown_trigger *trigger)
|
||||
if (dump_method == DUMP_METHOD_NONE)
|
||||
return;
|
||||
smp_send_stop();
|
||||
smp_switch_to_ipl_cpu(__dump_run, NULL);
|
||||
smp_call_ipl_cpu(__dump_run, NULL);
|
||||
}
|
||||
|
||||
static int __init dump_ccw_init(void)
|
||||
@@ -1499,30 +1528,12 @@ static struct shutdown_action __refdata dump_action = {
|
||||
|
||||
static void dump_reipl_run(struct shutdown_trigger *trigger)
|
||||
{
|
||||
preempt_disable();
|
||||
/*
|
||||
* Bypass dynamic address translation (DAT) when storing IPL parameter
|
||||
* information block address and checksum into the prefix area
|
||||
* (corresponding to absolute addresses 0-8191).
|
||||
* When enhanced DAT applies and the STE format control in one,
|
||||
* the absolute address is formed without prefixing. In this case a
|
||||
* normal store (stg/st) into the prefix area would no more match to
|
||||
* absolute addresses 0-8191.
|
||||
*/
|
||||
#ifdef CONFIG_64BIT
|
||||
asm volatile("sturg %0,%1"
|
||||
:: "a" ((unsigned long) reipl_block_actual),
|
||||
"a" (&lowcore_ptr[smp_processor_id()]->ipib));
|
||||
#else
|
||||
asm volatile("stura %0,%1"
|
||||
:: "a" ((unsigned long) reipl_block_actual),
|
||||
"a" (&lowcore_ptr[smp_processor_id()]->ipib));
|
||||
#endif
|
||||
asm volatile("stura %0,%1"
|
||||
:: "a" (csum_partial(reipl_block_actual,
|
||||
reipl_block_actual->hdr.len, 0)),
|
||||
"a" (&lowcore_ptr[smp_processor_id()]->ipib_checksum));
|
||||
preempt_enable();
|
||||
u32 csum;
|
||||
|
||||
csum = csum_partial(reipl_block_actual, reipl_block_actual->hdr.len, 0);
|
||||
copy_to_absolute_zero(&S390_lowcore.ipib_checksum, &csum, sizeof(csum));
|
||||
copy_to_absolute_zero(&S390_lowcore.ipib, &reipl_block_actual,
|
||||
sizeof(reipl_block_actual));
|
||||
dump_run(trigger);
|
||||
}
|
||||
|
||||
@@ -1623,9 +1634,7 @@ static void stop_run(struct shutdown_trigger *trigger)
|
||||
if (strcmp(trigger->name, ON_PANIC_STR) == 0 ||
|
||||
strcmp(trigger->name, ON_RESTART_STR) == 0)
|
||||
disabled_wait((unsigned long) __builtin_return_address(0));
|
||||
while (sigp(smp_processor_id(), sigp_stop) == sigp_busy)
|
||||
cpu_relax();
|
||||
for (;;);
|
||||
smp_stop_cpu();
|
||||
}
|
||||
|
||||
static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR,
|
||||
@@ -1713,6 +1722,7 @@ static struct kobj_attribute on_panic_attr =
|
||||
|
||||
static void do_panic(void)
|
||||
{
|
||||
lgr_info_log();
|
||||
on_panic_trigger.action->fn(&on_panic_trigger);
|
||||
stop_run(&on_panic_trigger);
|
||||
}
|
||||
@@ -1738,9 +1748,8 @@ static ssize_t on_restart_store(struct kobject *kobj,
|
||||
static struct kobj_attribute on_restart_attr =
|
||||
__ATTR(on_restart, 0644, on_restart_show, on_restart_store);
|
||||
|
||||
void do_restart(void)
|
||||
static void __do_restart(void *ignore)
|
||||
{
|
||||
smp_restart_with_online_cpu();
|
||||
smp_send_stop();
|
||||
#ifdef CONFIG_CRASH_DUMP
|
||||
crash_kexec(NULL);
|
||||
@@ -1749,6 +1758,14 @@ void do_restart(void)
|
||||
stop_run(&on_restart_trigger);
|
||||
}
|
||||
|
||||
void do_restart(void)
|
||||
{
|
||||
tracing_off();
|
||||
debug_locks_off();
|
||||
lgr_info_log();
|
||||
smp_call_online_cpu(__do_restart, NULL);
|
||||
}
|
||||
|
||||
/* on halt */
|
||||
|
||||
static struct shutdown_trigger on_halt_trigger = {ON_HALT_STR, &stop_action};
|
||||
|
||||
@@ -202,31 +202,27 @@ int unregister_external_interrupt(u16 code, ext_int_handler_t handler)
|
||||
}
|
||||
EXPORT_SYMBOL(unregister_external_interrupt);
|
||||
|
||||
void __irq_entry do_extint(struct pt_regs *regs, unsigned int ext_int_code,
|
||||
void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code,
|
||||
unsigned int param32, unsigned long param64)
|
||||
{
|
||||
struct pt_regs *old_regs;
|
||||
unsigned short code;
|
||||
struct ext_int_info *p;
|
||||
int index;
|
||||
|
||||
code = (unsigned short) ext_int_code;
|
||||
old_regs = set_irq_regs(regs);
|
||||
s390_idle_check(regs, S390_lowcore.int_clock,
|
||||
S390_lowcore.async_enter_timer);
|
||||
irq_enter();
|
||||
if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
|
||||
/* Serve timer interrupts first. */
|
||||
clock_comparator_work();
|
||||
kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
|
||||
if (code != 0x1004)
|
||||
if (ext_code.code != 0x1004)
|
||||
__get_cpu_var(s390_idle).nohz_delay = 1;
|
||||
|
||||
index = ext_hash(code);
|
||||
index = ext_hash(ext_code.code);
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(p, &ext_int_hash[index], entry)
|
||||
if (likely(p->code == code))
|
||||
p->handler(ext_int_code, param32, param64);
|
||||
if (likely(p->code == ext_code.code))
|
||||
p->handler(ext_code, param32, param64);
|
||||
rcu_read_unlock();
|
||||
irq_exit();
|
||||
set_irq_regs(old_regs);
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Linux Guest Relocation (LGR) detection
|
||||
*
|
||||
* Copyright IBM Corp. 2012
|
||||
* Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/sysinfo.h>
|
||||
#include <asm/ebcdic.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/debug.h>
|
||||
#include <asm/ipl.h>
|
||||
|
||||
#define LGR_TIMER_INTERVAL_SECS (30 * 60)
|
||||
#define VM_LEVEL_MAX 2 /* Maximum is 8, but we only record two levels */
|
||||
|
||||
/*
|
||||
* LGR info: Contains stfle and stsi data
|
||||
*/
|
||||
struct lgr_info {
|
||||
/* Bit field with facility information: 4 DWORDs are stored */
|
||||
u64 stfle_fac_list[4];
|
||||
/* Level of system (1 = CEC, 2 = LPAR, 3 = z/VM */
|
||||
u32 level;
|
||||
/* Level 1: CEC info (stsi 1.1.1) */
|
||||
char manufacturer[16];
|
||||
char type[4];
|
||||
char sequence[16];
|
||||
char plant[4];
|
||||
char model[16];
|
||||
/* Level 2: LPAR info (stsi 2.2.2) */
|
||||
u16 lpar_number;
|
||||
char name[8];
|
||||
/* Level 3: VM info (stsi 3.2.2) */
|
||||
u8 vm_count;
|
||||
struct {
|
||||
char name[8];
|
||||
char cpi[16];
|
||||
} vm[VM_LEVEL_MAX];
|
||||
} __packed __aligned(8);
|
||||
|
||||
/*
|
||||
* LGR globals
|
||||
*/
|
||||
static void *lgr_page;
|
||||
static struct lgr_info lgr_info_last;
|
||||
static struct lgr_info lgr_info_cur;
|
||||
static struct debug_info *lgr_dbf;
|
||||
|
||||
/*
|
||||
* Return number of valid stsi levels
|
||||
*/
|
||||
static inline int stsi_0(void)
|
||||
{
|
||||
int rc = stsi(NULL, 0, 0, 0);
|
||||
|
||||
return rc == -ENOSYS ? rc : (((unsigned int) rc) >> 28);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy buffer and then convert it to ASCII
|
||||
*/
|
||||
static void cpascii(char *dst, char *src, int size)
|
||||
{
|
||||
memcpy(dst, src, size);
|
||||
EBCASC(dst, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill LGR info with 1.1.1 stsi data
|
||||
*/
|
||||
static void lgr_stsi_1_1_1(struct lgr_info *lgr_info)
|
||||
{
|
||||
struct sysinfo_1_1_1 *si = lgr_page;
|
||||
|
||||
if (stsi(si, 1, 1, 1) == -ENOSYS)
|
||||
return;
|
||||
cpascii(lgr_info->manufacturer, si->manufacturer,
|
||||
sizeof(si->manufacturer));
|
||||
cpascii(lgr_info->type, si->type, sizeof(si->type));
|
||||
cpascii(lgr_info->model, si->model, sizeof(si->model));
|
||||
cpascii(lgr_info->sequence, si->sequence, sizeof(si->sequence));
|
||||
cpascii(lgr_info->plant, si->plant, sizeof(si->plant));
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill LGR info with 2.2.2 stsi data
|
||||
*/
|
||||
static void lgr_stsi_2_2_2(struct lgr_info *lgr_info)
|
||||
{
|
||||
struct sysinfo_2_2_2 *si = lgr_page;
|
||||
|
||||
if (stsi(si, 2, 2, 2) == -ENOSYS)
|
||||
return;
|
||||
cpascii(lgr_info->name, si->name, sizeof(si->name));
|
||||
memcpy(&lgr_info->lpar_number, &si->lpar_number,
|
||||
sizeof(lgr_info->lpar_number));
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill LGR info with 3.2.2 stsi data
|
||||
*/
|
||||
static void lgr_stsi_3_2_2(struct lgr_info *lgr_info)
|
||||
{
|
||||
struct sysinfo_3_2_2 *si = lgr_page;
|
||||
int i;
|
||||
|
||||
if (stsi(si, 3, 2, 2) == -ENOSYS)
|
||||
return;
|
||||
for (i = 0; i < min_t(u8, si->count, VM_LEVEL_MAX); i++) {
|
||||
cpascii(lgr_info->vm[i].name, si->vm[i].name,
|
||||
sizeof(si->vm[i].name));
|
||||
cpascii(lgr_info->vm[i].cpi, si->vm[i].cpi,
|
||||
sizeof(si->vm[i].cpi));
|
||||
}
|
||||
lgr_info->vm_count = si->count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill LGR info with current data
|
||||
*/
|
||||
static void lgr_info_get(struct lgr_info *lgr_info)
|
||||
{
|
||||
memset(lgr_info, 0, sizeof(*lgr_info));
|
||||
stfle(lgr_info->stfle_fac_list, ARRAY_SIZE(lgr_info->stfle_fac_list));
|
||||
lgr_info->level = stsi_0();
|
||||
if (lgr_info->level == -ENOSYS)
|
||||
return;
|
||||
if (lgr_info->level >= 1)
|
||||
lgr_stsi_1_1_1(lgr_info);
|
||||
if (lgr_info->level >= 2)
|
||||
lgr_stsi_2_2_2(lgr_info);
|
||||
if (lgr_info->level >= 3)
|
||||
lgr_stsi_3_2_2(lgr_info);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if LGR info has changed and if yes log new LGR info to s390dbf
|
||||
*/
|
||||
void lgr_info_log(void)
|
||||
{
|
||||
static DEFINE_SPINLOCK(lgr_info_lock);
|
||||
unsigned long flags;
|
||||
|
||||
if (!spin_trylock_irqsave(&lgr_info_lock, flags))
|
||||
return;
|
||||
lgr_info_get(&lgr_info_cur);
|
||||
if (memcmp(&lgr_info_last, &lgr_info_cur, sizeof(lgr_info_cur)) != 0) {
|
||||
debug_event(lgr_dbf, 1, &lgr_info_cur, sizeof(lgr_info_cur));
|
||||
lgr_info_last = lgr_info_cur;
|
||||
}
|
||||
spin_unlock_irqrestore(&lgr_info_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lgr_info_log);
|
||||
|
||||
static void lgr_timer_set(void);
|
||||
|
||||
/*
|
||||
* LGR timer callback
|
||||
*/
|
||||
static void lgr_timer_fn(unsigned long ignored)
|
||||
{
|
||||
lgr_info_log();
|
||||
lgr_timer_set();
|
||||
}
|
||||
|
||||
static struct timer_list lgr_timer =
|
||||
TIMER_DEFERRED_INITIALIZER(lgr_timer_fn, 0, 0);
|
||||
|
||||
/*
|
||||
* Setup next LGR timer
|
||||
*/
|
||||
static void lgr_timer_set(void)
|
||||
{
|
||||
mod_timer(&lgr_timer, jiffies + LGR_TIMER_INTERVAL_SECS * HZ);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize LGR: Add s390dbf, write initial lgr_info and setup timer
|
||||
*/
|
||||
static int __init lgr_init(void)
|
||||
{
|
||||
lgr_page = (void *) __get_free_pages(GFP_KERNEL, 0);
|
||||
if (!lgr_page)
|
||||
return -ENOMEM;
|
||||
lgr_dbf = debug_register("lgr", 1, 1, sizeof(struct lgr_info));
|
||||
if (!lgr_dbf) {
|
||||
free_page((unsigned long) lgr_page);
|
||||
return -ENOMEM;
|
||||
}
|
||||
debug_register_view(lgr_dbf, &debug_hex_ascii_view);
|
||||
lgr_info_get(&lgr_info_last);
|
||||
debug_event(lgr_dbf, 1, &lgr_info_last, sizeof(lgr_info_last));
|
||||
lgr_timer_set();
|
||||
return 0;
|
||||
}
|
||||
module_init(lgr_init);
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/ftrace.h>
|
||||
#include <linux/debug_locks.h>
|
||||
#include <asm/cio.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/pgtable.h>
|
||||
@@ -48,51 +49,22 @@ static void add_elf_notes(int cpu)
|
||||
memset(ptr, 0, sizeof(struct elf_note));
|
||||
}
|
||||
|
||||
/*
|
||||
* Store status of next available physical CPU
|
||||
*/
|
||||
static int store_status_next(int start_cpu, int this_cpu)
|
||||
{
|
||||
struct save_area *sa = (void *) 4608 + store_prefix();
|
||||
int cpu, rc;
|
||||
|
||||
for (cpu = start_cpu; cpu < 65536; cpu++) {
|
||||
if (cpu == this_cpu)
|
||||
continue;
|
||||
do {
|
||||
rc = raw_sigp(cpu, sigp_stop_and_store_status);
|
||||
} while (rc == sigp_busy);
|
||||
if (rc != sigp_order_code_accepted)
|
||||
continue;
|
||||
if (sa->pref_reg)
|
||||
return cpu;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize CPU ELF notes
|
||||
*/
|
||||
void setup_regs(void)
|
||||
{
|
||||
unsigned long sa = S390_lowcore.prefixreg_save_area + SAVE_AREA_BASE;
|
||||
int cpu, this_cpu, phys_cpu = 0, first = 1;
|
||||
int cpu, this_cpu;
|
||||
|
||||
this_cpu = stap();
|
||||
|
||||
if (!S390_lowcore.prefixreg_save_area)
|
||||
first = 0;
|
||||
this_cpu = smp_find_processor_id(stap());
|
||||
add_elf_notes(this_cpu);
|
||||
for_each_online_cpu(cpu) {
|
||||
if (first) {
|
||||
add_elf_notes(cpu);
|
||||
first = 0;
|
||||
if (cpu == this_cpu)
|
||||
continue;
|
||||
if (smp_store_status(cpu))
|
||||
continue;
|
||||
}
|
||||
phys_cpu = store_status_next(phys_cpu, this_cpu);
|
||||
if (phys_cpu == -1)
|
||||
break;
|
||||
add_elf_notes(cpu);
|
||||
phys_cpu++;
|
||||
}
|
||||
/* Copy dump CPU store status info to absolute zero */
|
||||
memcpy((void *) SAVE_AREA_BASE, (void *) sa, sizeof(struct save_area));
|
||||
@@ -238,10 +210,14 @@ static void __machine_kexec(void *data)
|
||||
struct kimage *image = data;
|
||||
|
||||
pfault_fini();
|
||||
if (image->type == KEXEC_TYPE_CRASH)
|
||||
tracing_off();
|
||||
debug_locks_off();
|
||||
if (image->type == KEXEC_TYPE_CRASH) {
|
||||
lgr_info_log();
|
||||
s390_reset_system(__do_machine_kdump, data);
|
||||
else
|
||||
} else {
|
||||
s390_reset_system(__do_machine_kexec, data);
|
||||
}
|
||||
disabled_wait((unsigned long) __builtin_return_address(0));
|
||||
}
|
||||
|
||||
@@ -255,5 +231,5 @@ void machine_kexec(struct kimage *image)
|
||||
return;
|
||||
tracer_disable();
|
||||
smp_send_stop();
|
||||
smp_switch_to_ipl_cpu(__machine_kexec, image);
|
||||
smp_call_ipl_cpu(__machine_kexec, image);
|
||||
}
|
||||
|
||||
@@ -254,8 +254,6 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
|
||||
int umode;
|
||||
|
||||
nmi_enter();
|
||||
s390_idle_check(regs, S390_lowcore.mcck_clock,
|
||||
S390_lowcore.mcck_enter_timer);
|
||||
kstat_cpu(smp_processor_id()).irqs[NMI_NMI]++;
|
||||
mci = (struct mci *) &S390_lowcore.mcck_interruption_code;
|
||||
mcck = &__get_cpu_var(cpu_mcck);
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* OS info memory interface
|
||||
*
|
||||
* Copyright IBM Corp. 2012
|
||||
* Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
|
||||
*/
|
||||
|
||||
#define KMSG_COMPONENT "os_info"
|
||||
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
|
||||
|
||||
#include <linux/crash_dump.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/checksum.h>
|
||||
#include <asm/lowcore.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/os_info.h>
|
||||
|
||||
/*
|
||||
* OS info structure has to be page aligned
|
||||
*/
|
||||
static struct os_info os_info __page_aligned_data;
|
||||
|
||||
/*
|
||||
* Compute checksum over OS info structure
|
||||
*/
|
||||
u32 os_info_csum(struct os_info *os_info)
|
||||
{
|
||||
int size = sizeof(*os_info) - offsetof(struct os_info, version_major);
|
||||
return csum_partial(&os_info->version_major, size, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add crashkernel info to OS info and update checksum
|
||||
*/
|
||||
void os_info_crashkernel_add(unsigned long base, unsigned long size)
|
||||
{
|
||||
os_info.crashkernel_addr = (u64)(unsigned long)base;
|
||||
os_info.crashkernel_size = (u64)(unsigned long)size;
|
||||
os_info.csum = os_info_csum(&os_info);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add OS info entry and update checksum
|
||||
*/
|
||||
void os_info_entry_add(int nr, void *ptr, u64 size)
|
||||
{
|
||||
os_info.entry[nr].addr = (u64)(unsigned long)ptr;
|
||||
os_info.entry[nr].size = size;
|
||||
os_info.entry[nr].csum = csum_partial(ptr, size, 0);
|
||||
os_info.csum = os_info_csum(&os_info);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize OS info struture and set lowcore pointer
|
||||
*/
|
||||
void __init os_info_init(void)
|
||||
{
|
||||
void *ptr = &os_info;
|
||||
|
||||
os_info.version_major = OS_INFO_VERSION_MAJOR;
|
||||
os_info.version_minor = OS_INFO_VERSION_MINOR;
|
||||
os_info.magic = OS_INFO_MAGIC;
|
||||
os_info.csum = os_info_csum(&os_info);
|
||||
copy_to_absolute_zero(&S390_lowcore.os_info, &ptr, sizeof(ptr));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CRASH_DUMP
|
||||
|
||||
static struct os_info *os_info_old;
|
||||
|
||||
/*
|
||||
* Allocate and copy OS info entry from oldmem
|
||||
*/
|
||||
static void os_info_old_alloc(int nr, int align)
|
||||
{
|
||||
unsigned long addr, size = 0;
|
||||
char *buf, *buf_align, *msg;
|
||||
u32 csum;
|
||||
|
||||
addr = os_info_old->entry[nr].addr;
|
||||
if (!addr) {
|
||||
msg = "not available";
|
||||
goto fail;
|
||||
}
|
||||
size = os_info_old->entry[nr].size;
|
||||
buf = kmalloc(size + align - 1, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
msg = "alloc failed";
|
||||
goto fail;
|
||||
}
|
||||
buf_align = PTR_ALIGN(buf, align);
|
||||
if (copy_from_oldmem(buf_align, (void *) addr, size)) {
|
||||
msg = "copy failed";
|
||||
goto fail_free;
|
||||
}
|
||||
csum = csum_partial(buf_align, size, 0);
|
||||
if (csum != os_info_old->entry[nr].csum) {
|
||||
msg = "checksum failed";
|
||||
goto fail_free;
|
||||
}
|
||||
os_info_old->entry[nr].addr = (u64)(unsigned long)buf_align;
|
||||
msg = "copied";
|
||||
goto out;
|
||||
fail_free:
|
||||
kfree(buf);
|
||||
fail:
|
||||
os_info_old->entry[nr].addr = 0;
|
||||
out:
|
||||
pr_info("entry %i: %s (addr=0x%lx size=%lu)\n",
|
||||
nr, msg, addr, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize os info and os info entries from oldmem
|
||||
*/
|
||||
static void os_info_old_init(void)
|
||||
{
|
||||
static int os_info_init;
|
||||
unsigned long addr;
|
||||
|
||||
if (os_info_init)
|
||||
return;
|
||||
if (!OLDMEM_BASE)
|
||||
goto fail;
|
||||
if (copy_from_oldmem(&addr, &S390_lowcore.os_info, sizeof(addr)))
|
||||
goto fail;
|
||||
if (addr == 0 || addr % PAGE_SIZE)
|
||||
goto fail;
|
||||
os_info_old = kzalloc(sizeof(*os_info_old), GFP_KERNEL);
|
||||
if (!os_info_old)
|
||||
goto fail;
|
||||
if (copy_from_oldmem(os_info_old, (void *) addr, sizeof(*os_info_old)))
|
||||
goto fail_free;
|
||||
if (os_info_old->magic != OS_INFO_MAGIC)
|
||||
goto fail_free;
|
||||
if (os_info_old->csum != os_info_csum(os_info_old))
|
||||
goto fail_free;
|
||||
if (os_info_old->version_major > OS_INFO_VERSION_MAJOR)
|
||||
goto fail_free;
|
||||
os_info_old_alloc(OS_INFO_VMCOREINFO, 1);
|
||||
os_info_old_alloc(OS_INFO_REIPL_BLOCK, 1);
|
||||
os_info_old_alloc(OS_INFO_INIT_FN, PAGE_SIZE);
|
||||
pr_info("crashkernel: addr=0x%lx size=%lu\n",
|
||||
(unsigned long) os_info_old->crashkernel_addr,
|
||||
(unsigned long) os_info_old->crashkernel_size);
|
||||
os_info_init = 1;
|
||||
return;
|
||||
fail_free:
|
||||
kfree(os_info_old);
|
||||
fail:
|
||||
os_info_init = 1;
|
||||
os_info_old = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return pointer to os infor entry and its size
|
||||
*/
|
||||
void *os_info_old_entry(int nr, unsigned long *size)
|
||||
{
|
||||
os_info_old_init();
|
||||
|
||||
if (!os_info_old)
|
||||
return NULL;
|
||||
if (!os_info_old->entry[nr].addr)
|
||||
return NULL;
|
||||
*size = (unsigned long) os_info_old->entry[nr].size;
|
||||
return (void *)(unsigned long)os_info_old->entry[nr].addr;
|
||||
}
|
||||
#endif
|
||||
@@ -77,13 +77,8 @@ static void default_idle(void)
|
||||
local_irq_enable();
|
||||
return;
|
||||
}
|
||||
trace_hardirqs_on();
|
||||
/* Don't trace preempt off for idle. */
|
||||
stop_critical_timings();
|
||||
/* Stop virtual timer and halt the cpu. */
|
||||
/* Halt the cpu and keep track of cpu time accounting. */
|
||||
vtime_stop_cpu();
|
||||
/* Reenable preemption tracer. */
|
||||
start_critical_timings();
|
||||
}
|
||||
|
||||
void cpu_idle(void)
|
||||
|
||||
+30
-31
@@ -2,7 +2,7 @@
|
||||
* arch/s390/kernel/setup.c
|
||||
*
|
||||
* S390 version
|
||||
* Copyright (C) IBM Corp. 1999,2010
|
||||
* Copyright (C) IBM Corp. 1999,2012
|
||||
* Author(s): Hartmut Penner (hp@de.ibm.com),
|
||||
* Martin Schwidefsky (schwidefsky@de.ibm.com)
|
||||
*
|
||||
@@ -62,6 +62,8 @@
|
||||
#include <asm/ebcdic.h>
|
||||
#include <asm/kvm_virtio.h>
|
||||
#include <asm/diag.h>
|
||||
#include <asm/os_info.h>
|
||||
#include "entry.h"
|
||||
|
||||
long psw_kernel_bits = PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_ASC_PRIMARY |
|
||||
PSW_MASK_EA | PSW_MASK_BA;
|
||||
@@ -351,8 +353,9 @@ static void setup_addressing_mode(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void __init
|
||||
setup_lowcore(void)
|
||||
void *restart_stack __attribute__((__section__(".data")));
|
||||
|
||||
static void __init setup_lowcore(void)
|
||||
{
|
||||
struct _lowcore *lc;
|
||||
|
||||
@@ -363,7 +366,7 @@ setup_lowcore(void)
|
||||
lc = __alloc_bootmem_low(LC_PAGES * PAGE_SIZE, LC_PAGES * PAGE_SIZE, 0);
|
||||
lc->restart_psw.mask = psw_kernel_bits;
|
||||
lc->restart_psw.addr =
|
||||
PSW_ADDR_AMODE | (unsigned long) psw_restart_int_handler;
|
||||
PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
|
||||
lc->external_new_psw.mask = psw_kernel_bits |
|
||||
PSW_MASK_DAT | PSW_MASK_MCHECK;
|
||||
lc->external_new_psw.addr =
|
||||
@@ -412,6 +415,24 @@ setup_lowcore(void)
|
||||
lc->last_update_timer = S390_lowcore.last_update_timer;
|
||||
lc->last_update_clock = S390_lowcore.last_update_clock;
|
||||
lc->ftrace_func = S390_lowcore.ftrace_func;
|
||||
|
||||
restart_stack = __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0);
|
||||
restart_stack += ASYNC_SIZE;
|
||||
|
||||
/*
|
||||
* Set up PSW restart to call ipl.c:do_restart(). Copy the relevant
|
||||
* restart data to the absolute zero lowcore. This is necesary if
|
||||
* PSW restart is done on an offline CPU that has lowcore zero.
|
||||
*/
|
||||
lc->restart_stack = (unsigned long) restart_stack;
|
||||
lc->restart_fn = (unsigned long) do_restart;
|
||||
lc->restart_data = 0;
|
||||
lc->restart_source = -1UL;
|
||||
memcpy(&S390_lowcore.restart_stack, &lc->restart_stack,
|
||||
4*sizeof(unsigned long));
|
||||
copy_to_absolute_zero(&S390_lowcore.restart_psw,
|
||||
&lc->restart_psw, sizeof(psw_t));
|
||||
|
||||
set_prefix((u32)(unsigned long) lc);
|
||||
lowcore_ptr[0] = lc;
|
||||
}
|
||||
@@ -572,27 +593,6 @@ static void __init setup_memory_end(void)
|
||||
}
|
||||
}
|
||||
|
||||
void *restart_stack __attribute__((__section__(".data")));
|
||||
|
||||
/*
|
||||
* Setup new PSW and allocate stack for PSW restart interrupt
|
||||
*/
|
||||
static void __init setup_restart_psw(void)
|
||||
{
|
||||
psw_t psw;
|
||||
|
||||
restart_stack = __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0);
|
||||
restart_stack += ASYNC_SIZE;
|
||||
|
||||
/*
|
||||
* Setup restart PSW for absolute zero lowcore. This is necesary
|
||||
* if PSW restart is done on an offline CPU that has lowcore zero
|
||||
*/
|
||||
psw.mask = PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_MASK_EA | PSW_MASK_BA;
|
||||
psw.addr = PSW_ADDR_AMODE | (unsigned long) psw_restart_int_handler;
|
||||
copy_to_absolute_zero(&S390_lowcore.restart_psw, &psw, sizeof(psw));
|
||||
}
|
||||
|
||||
static void __init setup_vmcoreinfo(void)
|
||||
{
|
||||
#ifdef CONFIG_KEXEC
|
||||
@@ -747,7 +747,7 @@ static void __init reserve_crashkernel(void)
|
||||
{
|
||||
#ifdef CONFIG_CRASH_DUMP
|
||||
unsigned long long crash_base, crash_size;
|
||||
char *msg;
|
||||
char *msg = NULL;
|
||||
int rc;
|
||||
|
||||
rc = parse_crashkernel(boot_command_line, memory_end, &crash_size,
|
||||
@@ -779,11 +779,11 @@ static void __init reserve_crashkernel(void)
|
||||
pr_info("Reserving %lluMB of memory at %lluMB "
|
||||
"for crashkernel (System RAM: %luMB)\n",
|
||||
crash_size >> 20, crash_base >> 20, memory_end >> 20);
|
||||
os_info_crashkernel_add(crash_base, crash_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __init
|
||||
setup_memory(void)
|
||||
static void __init setup_memory(void)
|
||||
{
|
||||
unsigned long bootmap_size;
|
||||
unsigned long start_pfn, end_pfn;
|
||||
@@ -1014,8 +1014,7 @@ static void __init setup_hwcaps(void)
|
||||
* was printed.
|
||||
*/
|
||||
|
||||
void __init
|
||||
setup_arch(char **cmdline_p)
|
||||
void __init setup_arch(char **cmdline_p)
|
||||
{
|
||||
/*
|
||||
* print what head.S has found out about the machine
|
||||
@@ -1060,6 +1059,7 @@ setup_arch(char **cmdline_p)
|
||||
|
||||
parse_early_param();
|
||||
|
||||
os_info_init();
|
||||
setup_ipl();
|
||||
setup_memory_end();
|
||||
setup_addressing_mode();
|
||||
@@ -1068,7 +1068,6 @@ setup_arch(char **cmdline_p)
|
||||
setup_memory();
|
||||
setup_resources();
|
||||
setup_vmcoreinfo();
|
||||
setup_restart_psw();
|
||||
setup_lowcore();
|
||||
|
||||
cpu_init();
|
||||
|
||||
@@ -384,7 +384,6 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka,
|
||||
siginfo_t *info, sigset_t *oldset,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
sigset_t blocked;
|
||||
int ret;
|
||||
|
||||
/* Set up the stack frame */
|
||||
@@ -394,10 +393,7 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka,
|
||||
ret = setup_frame(sig, ka, oldset, regs);
|
||||
if (ret)
|
||||
return ret;
|
||||
sigorsets(&blocked, ¤t->blocked, &ka->sa.sa_mask);
|
||||
if (!(ka->sa.sa_flags & SA_NODEFER))
|
||||
sigaddset(&blocked, sig);
|
||||
set_current_blocked(&blocked);
|
||||
block_sigmask(ka, sig);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+585
-578
File diff suppressed because it is too large
Load Diff
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* 31-bit switch cpu code
|
||||
*
|
||||
* Copyright IBM Corp. 2009
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
# smp_switch_to_cpu switches to destination cpu and executes the passed function
|
||||
# Parameter: %r2 - function to call
|
||||
# %r3 - function parameter
|
||||
# %r4 - stack poiner
|
||||
# %r5 - current cpu
|
||||
# %r6 - destination cpu
|
||||
|
||||
.section .text
|
||||
ENTRY(smp_switch_to_cpu)
|
||||
stm %r6,%r15,__SF_GPRS(%r15)
|
||||
lr %r1,%r15
|
||||
ahi %r15,-STACK_FRAME_OVERHEAD
|
||||
st %r1,__SF_BACKCHAIN(%r15)
|
||||
basr %r13,0
|
||||
0: la %r1,.gprregs_addr-0b(%r13)
|
||||
l %r1,0(%r1)
|
||||
stm %r0,%r15,0(%r1)
|
||||
1: sigp %r0,%r6,__SIGP_RESTART /* start destination CPU */
|
||||
brc 2,1b /* busy, try again */
|
||||
2: sigp %r0,%r5,__SIGP_STOP /* stop current CPU */
|
||||
brc 2,2b /* busy, try again */
|
||||
3: j 3b
|
||||
|
||||
ENTRY(smp_restart_cpu)
|
||||
basr %r13,0
|
||||
0: la %r1,.gprregs_addr-0b(%r13)
|
||||
l %r1,0(%r1)
|
||||
lm %r0,%r15,0(%r1)
|
||||
1: sigp %r0,%r5,__SIGP_SENSE /* Wait for calling CPU */
|
||||
brc 10,1b /* busy, accepted (status 0), running */
|
||||
tmll %r0,0x40 /* Test if calling CPU is stopped */
|
||||
jz 1b
|
||||
ltr %r4,%r4 /* New stack ? */
|
||||
jz 1f
|
||||
lr %r15,%r4
|
||||
1: lr %r14,%r2 /* r14: Function to call */
|
||||
lr %r2,%r3 /* r2 : Parameter for function*/
|
||||
basr %r14,%r14 /* Call function */
|
||||
|
||||
.gprregs_addr:
|
||||
.long .gprregs
|
||||
|
||||
.section .data,"aw",@progbits
|
||||
.gprregs:
|
||||
.rept 16
|
||||
.long 0
|
||||
.endr
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user