Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6: [S390] signal: use set_restore_sigmask() helper [S390] smp: remove pointless comments in startup_secondary() [S390] qdio: Use kstrtoul_from_user [S390] sclp_async: Use kstrtoul_from_user [S390] exec: remove redundant set_fs(USER_DS) [S390] cpu hotplug: on cpu start wait until being marked active [S390] signal: convert to use set_current_blocked() [S390] asm offsets: fix coding style [S390] Add support for IBM zEnterprise 114 [S390] dasd: check if raw track access is supported [S390] Use diagnose 308 for system reset [S390] Export store_status() function [S390] dasd: use vmalloc for statistics input buffer [S390] Add PSW restart shutdown trigger [S390] missing return in page_table_alloc_pgste [S390] qdio: 2nd stage retry on SIGA-W busy conditions
This commit is contained in:
Коммит
447e1363bc
|
@ -274,11 +274,11 @@ config MARCH_Z10
|
|||
on older machines.
|
||||
|
||||
config MARCH_Z196
|
||||
bool "IBM zEnterprise 196"
|
||||
bool "IBM zEnterprise 114 and 196"
|
||||
help
|
||||
Select this to enable optimizations for IBM zEnterprise 196
|
||||
(2817 series). The kernel will be slightly faster but will not work
|
||||
on older machines.
|
||||
Select this to enable optimizations for IBM zEnterprise 114 and 196
|
||||
(2818 and 2817 series). The kernel will be slightly faster but will
|
||||
not work on older machines.
|
||||
|
||||
endchoice
|
||||
|
||||
|
|
|
@ -167,5 +167,6 @@ enum diag308_rc {
|
|||
};
|
||||
|
||||
extern int diag308(unsigned long subcode, void *addr);
|
||||
extern void diag308_reset(void);
|
||||
|
||||
#endif /* _ASM_S390_IPL_H */
|
||||
|
|
|
@ -18,6 +18,7 @@ void system_call(void);
|
|||
void pgm_check_handler(void);
|
||||
void mcck_int_handler(void);
|
||||
void io_int_handler(void);
|
||||
void psw_restart_int_handler(void);
|
||||
|
||||
#ifdef CONFIG_32BIT
|
||||
|
||||
|
@ -150,7 +151,10 @@ struct _lowcore {
|
|||
*/
|
||||
__u32 ipib; /* 0x0e00 */
|
||||
__u32 ipib_checksum; /* 0x0e04 */
|
||||
__u8 pad_0x0e08[0x0f00-0x0e08]; /* 0x0e08 */
|
||||
|
||||
/* 64 bit save area */
|
||||
__u64 save_area_64; /* 0x0e08 */
|
||||
__u8 pad_0x0e10[0x0f00-0x0e10]; /* 0x0e10 */
|
||||
|
||||
/* Extended facility list */
|
||||
__u64 stfle_fac_list[32]; /* 0x0f00 */
|
||||
|
@ -286,7 +290,10 @@ struct _lowcore {
|
|||
*/
|
||||
__u64 ipib; /* 0x0e00 */
|
||||
__u32 ipib_checksum; /* 0x0e08 */
|
||||
__u8 pad_0x0e0c[0x0f00-0x0e0c]; /* 0x0e0c */
|
||||
|
||||
/* 64 bit save area */
|
||||
__u64 save_area_64; /* 0x0e0c */
|
||||
__u8 pad_0x0e14[0x0f00-0x0e14]; /* 0x0e14 */
|
||||
|
||||
/* Extended facility list */
|
||||
__u64 stfle_fac_list[32]; /* 0x0f00 */
|
||||
|
|
|
@ -119,14 +119,12 @@ struct stack_frame {
|
|||
* Do necessary setup to start up a new thread.
|
||||
*/
|
||||
#define start_thread(regs, new_psw, new_stackp) do { \
|
||||
set_fs(USER_DS); \
|
||||
regs->psw.mask = psw_user_bits; \
|
||||
regs->psw.addr = new_psw | PSW_ADDR_AMODE; \
|
||||
regs->gprs[15] = new_stackp; \
|
||||
} while (0)
|
||||
|
||||
#define start_thread31(regs, new_psw, new_stackp) do { \
|
||||
set_fs(USER_DS); \
|
||||
regs->psw.mask = psw_user32_bits; \
|
||||
regs->psw.addr = new_psw | PSW_ADDR_AMODE; \
|
||||
regs->gprs[15] = new_stackp; \
|
||||
|
|
|
@ -113,6 +113,7 @@ extern void pfault_fini(void);
|
|||
|
||||
extern void cmma_init(void);
|
||||
extern int memcpy_real(void *, void *, size_t);
|
||||
extern void copy_to_absolute_zero(void *dest, void *src, size_t count);
|
||||
|
||||
#define finish_arch_switch(prev) do { \
|
||||
set_fs(current->thread.mm_segment); \
|
||||
|
|
|
@ -27,12 +27,9 @@ int main(void)
|
|||
BLANK();
|
||||
DEFINE(__TASK_pid, offsetof(struct task_struct, pid));
|
||||
BLANK();
|
||||
DEFINE(__THREAD_per_cause,
|
||||
offsetof(struct task_struct, thread.per_event.cause));
|
||||
DEFINE(__THREAD_per_address,
|
||||
offsetof(struct task_struct, thread.per_event.address));
|
||||
DEFINE(__THREAD_per_paid,
|
||||
offsetof(struct task_struct, thread.per_event.paid));
|
||||
DEFINE(__THREAD_per_cause, offsetof(struct task_struct, thread.per_event.cause));
|
||||
DEFINE(__THREAD_per_address, offsetof(struct task_struct, thread.per_event.address));
|
||||
DEFINE(__THREAD_per_paid, offsetof(struct task_struct, thread.per_event.paid));
|
||||
BLANK();
|
||||
DEFINE(__TI_task, offsetof(struct thread_info, task));
|
||||
DEFINE(__TI_domain, offsetof(struct thread_info, exec_domain));
|
||||
|
@ -142,6 +139,7 @@ int main(void)
|
|||
DEFINE(__LC_FPREGS_SAVE_AREA, offsetof(struct _lowcore, floating_pt_save_area));
|
||||
DEFINE(__LC_GPREGS_SAVE_AREA, offsetof(struct _lowcore, gpregs_save_area));
|
||||
DEFINE(__LC_CREGS_SAVE_AREA, offsetof(struct _lowcore, cregs_save_area));
|
||||
DEFINE(__LC_SAVE_AREA_64, offsetof(struct _lowcore, save_area_64));
|
||||
#ifdef CONFIG_32BIT
|
||||
DEFINE(SAVE_AREA_BASE, offsetof(struct _lowcore, extended_save_area_addr));
|
||||
#else /* CONFIG_32BIT */
|
||||
|
|
|
@ -76,6 +76,42 @@ s390_base_pgm_handler_fn:
|
|||
.quad 0
|
||||
.previous
|
||||
|
||||
#
|
||||
# Calls diag 308 subcode 1 and continues execution
|
||||
#
|
||||
# The following conditions must be ensured before calling this function:
|
||||
# * Prefix register = 0
|
||||
# * Lowcore protection is disabled
|
||||
#
|
||||
ENTRY(diag308_reset)
|
||||
larl %r4,.Lctlregs # Save control registers
|
||||
stctg %c0,%c15,0(%r4)
|
||||
larl %r4,.Lrestart_psw # Setup restart PSW at absolute 0
|
||||
lghi %r3,0
|
||||
lg %r4,0(%r4) # Save PSW
|
||||
sturg %r4,%r3 # Use sturg, because of large pages
|
||||
lghi %r1,1
|
||||
diag %r1,%r1,0x308
|
||||
.Lrestart_part2:
|
||||
lhi %r0,0 # Load r0 with zero
|
||||
lhi %r1,2 # Use mode 2 = ESAME (dump)
|
||||
sigp %r1,%r0,0x12 # Switch to ESAME mode
|
||||
sam64 # Switch to 64 bit addressing mode
|
||||
larl %r4,.Lctlregs # Restore control registers
|
||||
lctlg %c0,%c15,0(%r4)
|
||||
br %r14
|
||||
.align 16
|
||||
.Lrestart_psw:
|
||||
.long 0x00080000,0x80000000 + .Lrestart_part2
|
||||
|
||||
.section .bss
|
||||
.align 8
|
||||
.Lctlregs:
|
||||
.rept 16
|
||||
.quad 0
|
||||
.endr
|
||||
.previous
|
||||
|
||||
#else /* CONFIG_64BIT */
|
||||
|
||||
ENTRY(s390_base_mcck_handler)
|
||||
|
|
|
@ -380,20 +380,13 @@ asmlinkage long sys32_sigreturn(void)
|
|||
goto badframe;
|
||||
if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE32))
|
||||
goto badframe;
|
||||
|
||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
current->blocked = set;
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
|
||||
set_current_blocked(&set);
|
||||
if (restore_sigregs32(regs, &frame->sregs))
|
||||
goto badframe;
|
||||
if (restore_sigregs_gprs_high(regs, frame->gprs_high))
|
||||
goto badframe;
|
||||
|
||||
return regs->gprs[2];
|
||||
|
||||
badframe:
|
||||
force_sig(SIGSEGV, current);
|
||||
return 0;
|
||||
|
@ -413,31 +406,22 @@ asmlinkage long sys32_rt_sigreturn(void)
|
|||
goto badframe;
|
||||
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
|
||||
goto badframe;
|
||||
|
||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
current->blocked = set;
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
|
||||
set_current_blocked(&set);
|
||||
if (restore_sigregs32(regs, &frame->uc.uc_mcontext))
|
||||
goto badframe;
|
||||
if (restore_sigregs_gprs_high(regs, frame->gprs_high))
|
||||
goto badframe;
|
||||
|
||||
err = __get_user(ss_sp, &frame->uc.uc_stack.ss_sp);
|
||||
st.ss_sp = compat_ptr(ss_sp);
|
||||
err |= __get_user(st.ss_size, &frame->uc.uc_stack.ss_size);
|
||||
err |= __get_user(st.ss_flags, &frame->uc.uc_stack.ss_flags);
|
||||
if (err)
|
||||
goto badframe;
|
||||
|
||||
set_fs (KERNEL_DS);
|
||||
do_sigaltstack((stack_t __force __user *)&st, NULL, regs->gprs[15]);
|
||||
set_fs (old_fs);
|
||||
|
||||
return regs->gprs[2];
|
||||
|
||||
badframe:
|
||||
force_sig(SIGSEGV, current);
|
||||
return 0;
|
||||
|
@ -605,10 +589,10 @@ give_sigsegv:
|
|||
* OK, we're invoking a handler
|
||||
*/
|
||||
|
||||
int
|
||||
handle_signal32(unsigned long sig, struct k_sigaction *ka,
|
||||
siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
|
||||
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 */
|
||||
|
@ -616,15 +600,12 @@ handle_signal32(unsigned long sig, struct k_sigaction *ka,
|
|||
ret = setup_rt_frame32(sig, ka, info, oldset, regs);
|
||||
else
|
||||
ret = setup_frame32(sig, ka, oldset, regs);
|
||||
|
||||
if (ret == 0) {
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
|
||||
if (!(ka->sa.sa_flags & SA_NODEFER))
|
||||
sigaddset(¤t->blocked,sig);
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
}
|
||||
return ret;
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -849,6 +849,34 @@ restart_crash:
|
|||
restart_go:
|
||||
#endif
|
||||
|
||||
#
|
||||
# PSW restart interrupt handler
|
||||
#
|
||||
ENTRY(psw_restart_int_handler)
|
||||
st %r15,__LC_SAVE_AREA_64(%r0) # save r15
|
||||
basr %r15,0
|
||||
0: l %r15,.Lrestart_stack-0b(%r15) # load restart stack
|
||||
l %r15,0(%r15)
|
||||
ahi %r15,-SP_SIZE # make room for pt_regs
|
||||
stm %r0,%r14,SP_R0(%r15) # store gprs %r0-%r14 to stack
|
||||
mvc SP_R15(4,%r15),__LC_SAVE_AREA_64(%r0)# store saved %r15 to stack
|
||||
mvc SP_PSW(8,%r15),__LC_RST_OLD_PSW(%r0) # store restart old psw
|
||||
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # set backchain to 0
|
||||
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
|
||||
|
||||
.section .kprobes.text, "ax"
|
||||
|
||||
#ifdef CONFIG_CHECK_STACK
|
||||
|
|
|
@ -865,6 +865,26 @@ restart_crash:
|
|||
restart_go:
|
||||
#endif
|
||||
|
||||
#
|
||||
# PSW restart interrupt handler
|
||||
#
|
||||
ENTRY(psw_restart_int_handler)
|
||||
stg %r15,__LC_SAVE_AREA_64(%r0) # save r15
|
||||
larl %r15,restart_stack # load restart stack
|
||||
lg %r15,0(%r15)
|
||||
aghi %r15,-SP_SIZE # make room for pt_regs
|
||||
stmg %r0,%r14,SP_R0(%r15) # store gprs %r0-%r14 to stack
|
||||
mvc SP_R15(8,%r15),__LC_SAVE_AREA_64(%r0)# store saved %r15 to stack
|
||||
mvc SP_PSW(16,%r15),__LC_RST_OLD_PSW(%r0)# store restart old psw
|
||||
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) # set backchain to 0
|
||||
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
|
||||
|
||||
.section .kprobes.text, "ax"
|
||||
|
||||
#ifdef CONFIG_CHECK_STACK
|
||||
|
|
|
@ -45,11 +45,13 @@
|
|||
* - halt
|
||||
* - power off
|
||||
* - reipl
|
||||
* - restart
|
||||
*/
|
||||
#define ON_PANIC_STR "on_panic"
|
||||
#define ON_HALT_STR "on_halt"
|
||||
#define ON_POFF_STR "on_poff"
|
||||
#define ON_REIPL_STR "on_reboot"
|
||||
#define ON_RESTART_STR "on_restart"
|
||||
|
||||
struct shutdown_action;
|
||||
struct shutdown_trigger {
|
||||
|
@ -1544,17 +1546,20 @@ static char vmcmd_on_reboot[128];
|
|||
static char vmcmd_on_panic[128];
|
||||
static char vmcmd_on_halt[128];
|
||||
static char vmcmd_on_poff[128];
|
||||
static char vmcmd_on_restart[128];
|
||||
|
||||
DEFINE_IPL_ATTR_STR_RW(vmcmd, on_reboot, "%s\n", "%s\n", vmcmd_on_reboot);
|
||||
DEFINE_IPL_ATTR_STR_RW(vmcmd, on_panic, "%s\n", "%s\n", vmcmd_on_panic);
|
||||
DEFINE_IPL_ATTR_STR_RW(vmcmd, on_halt, "%s\n", "%s\n", vmcmd_on_halt);
|
||||
DEFINE_IPL_ATTR_STR_RW(vmcmd, on_poff, "%s\n", "%s\n", vmcmd_on_poff);
|
||||
DEFINE_IPL_ATTR_STR_RW(vmcmd, on_restart, "%s\n", "%s\n", vmcmd_on_restart);
|
||||
|
||||
static struct attribute *vmcmd_attrs[] = {
|
||||
&sys_vmcmd_on_reboot_attr.attr,
|
||||
&sys_vmcmd_on_panic_attr.attr,
|
||||
&sys_vmcmd_on_halt_attr.attr,
|
||||
&sys_vmcmd_on_poff_attr.attr,
|
||||
&sys_vmcmd_on_restart_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
@ -1576,6 +1581,8 @@ static void vmcmd_run(struct shutdown_trigger *trigger)
|
|||
cmd = vmcmd_on_halt;
|
||||
else if (strcmp(trigger->name, ON_POFF_STR) == 0)
|
||||
cmd = vmcmd_on_poff;
|
||||
else if (strcmp(trigger->name, ON_RESTART_STR) == 0)
|
||||
cmd = vmcmd_on_restart;
|
||||
else
|
||||
return;
|
||||
|
||||
|
@ -1707,6 +1714,34 @@ static void do_panic(void)
|
|||
stop_run(&on_panic_trigger);
|
||||
}
|
||||
|
||||
/* on restart */
|
||||
|
||||
static struct shutdown_trigger on_restart_trigger = {ON_RESTART_STR,
|
||||
&reipl_action};
|
||||
|
||||
static ssize_t on_restart_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *page)
|
||||
{
|
||||
return sprintf(page, "%s\n", on_restart_trigger.action->name);
|
||||
}
|
||||
|
||||
static ssize_t on_restart_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
return set_trigger(buf, &on_restart_trigger, len);
|
||||
}
|
||||
|
||||
static struct kobj_attribute on_restart_attr =
|
||||
__ATTR(on_restart, 0644, on_restart_show, on_restart_store);
|
||||
|
||||
void do_restart(void)
|
||||
{
|
||||
smp_send_stop();
|
||||
on_restart_trigger.action->fn(&on_restart_trigger);
|
||||
stop_run(&on_restart_trigger);
|
||||
}
|
||||
|
||||
/* on halt */
|
||||
|
||||
static struct shutdown_trigger on_halt_trigger = {ON_HALT_STR, &stop_action};
|
||||
|
@ -1783,7 +1818,9 @@ static void __init shutdown_triggers_init(void)
|
|||
if (sysfs_create_file(&shutdown_actions_kset->kobj,
|
||||
&on_poff_attr.attr))
|
||||
goto fail;
|
||||
|
||||
if (sysfs_create_file(&shutdown_actions_kset->kobj,
|
||||
&on_restart_attr.attr))
|
||||
goto fail;
|
||||
return;
|
||||
fail:
|
||||
panic("shutdown_triggers_init failed\n");
|
||||
|
@ -1959,6 +1996,12 @@ static void do_reset_calls(void)
|
|||
{
|
||||
struct reset_call *reset;
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
if (diag308_set_works) {
|
||||
diag308_reset();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
list_for_each_entry(reset, &rcall, list)
|
||||
reset->fn();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright IBM Corp 2000,2009
|
||||
* Copyright IBM Corp 2000,2011
|
||||
* Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com>,
|
||||
* Denis Joseph Barrow,
|
||||
*/
|
||||
|
@ -7,6 +7,64 @@
|
|||
#include <linux/linkage.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
|
||||
#
|
||||
# store_status
|
||||
#
|
||||
# Prerequisites to run this function:
|
||||
# - Prefix register is set to zero
|
||||
# - Original prefix register is stored in "dump_prefix_page"
|
||||
# - Lowcore protection is off
|
||||
#
|
||||
ENTRY(store_status)
|
||||
/* Save register one and load save area base */
|
||||
stg %r1,__LC_SAVE_AREA_64(%r0)
|
||||
lghi %r1,SAVE_AREA_BASE
|
||||
/* General purpose registers */
|
||||
stmg %r0,%r15,__LC_GPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
|
||||
lg %r2,__LC_SAVE_AREA_64(%r0)
|
||||
stg %r2,__LC_GPREGS_SAVE_AREA-SAVE_AREA_BASE+8(%r1)
|
||||
/* Control registers */
|
||||
stctg %c0,%c15,__LC_CREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
|
||||
/* Access registers */
|
||||
stam %a0,%a15,__LC_AREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
|
||||
/* Floating point registers */
|
||||
std %f0, 0x00 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
|
||||
std %f1, 0x08 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
|
||||
std %f2, 0x10 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
|
||||
std %f3, 0x18 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
|
||||
std %f4, 0x20 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
|
||||
std %f5, 0x28 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
|
||||
std %f6, 0x30 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
|
||||
std %f7, 0x38 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
|
||||
std %f8, 0x40 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
|
||||
std %f9, 0x48 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
|
||||
std %f10,0x50 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
|
||||
std %f11,0x58 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
|
||||
std %f12,0x60 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
|
||||
std %f13,0x68 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
|
||||
std %f14,0x70 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
|
||||
std %f15,0x78 + __LC_FPREGS_SAVE_AREA-SAVE_AREA_BASE(%r1)
|
||||
/* Floating point control register */
|
||||
stfpc __LC_FP_CREG_SAVE_AREA-SAVE_AREA_BASE(%r1)
|
||||
/* CPU timer */
|
||||
stpt __LC_CPU_TIMER_SAVE_AREA-SAVE_AREA_BASE(%r1)
|
||||
/* Saved prefix register */
|
||||
larl %r2,dump_prefix_page
|
||||
mvc __LC_PREFIX_SAVE_AREA-SAVE_AREA_BASE(4,%r1),0(%r2)
|
||||
/* Clock comparator - seven bytes */
|
||||
larl %r2,.Lclkcmp
|
||||
stckc 0(%r2)
|
||||
mvc __LC_CLOCK_COMP_SAVE_AREA-SAVE_AREA_BASE + 1(7,%r1),1(%r2)
|
||||
/* Program status word */
|
||||
epsw %r2,%r3
|
||||
st %r2,__LC_PSW_SAVE_AREA-SAVE_AREA_BASE + 0(%r1)
|
||||
st %r3,__LC_PSW_SAVE_AREA-SAVE_AREA_BASE + 4(%r1)
|
||||
larl %r2,store_status
|
||||
stg %r2,__LC_PSW_SAVE_AREA-SAVE_AREA_BASE + 8(%r1)
|
||||
br %r14
|
||||
.align 8
|
||||
.Lclkcmp: .quad 0x0000000000000000
|
||||
|
||||
#
|
||||
# do_reipl_asm
|
||||
# Parameter: r2 = schid of reipl device
|
||||
|
@ -15,22 +73,7 @@
|
|||
ENTRY(do_reipl_asm)
|
||||
basr %r13,0
|
||||
.Lpg0: lpswe .Lnewpsw-.Lpg0(%r13)
|
||||
.Lpg1: # do store status of all registers
|
||||
|
||||
stg %r1,.Lregsave-.Lpg0(%r13)
|
||||
lghi %r1,0x1000
|
||||
stmg %r0,%r15,__LC_GPREGS_SAVE_AREA-0x1000(%r1)
|
||||
lg %r0,.Lregsave-.Lpg0(%r13)
|
||||
stg %r0,__LC_GPREGS_SAVE_AREA-0x1000+8(%r1)
|
||||
stctg %c0,%c15,__LC_CREGS_SAVE_AREA-0x1000(%r1)
|
||||
stam %a0,%a15,__LC_AREGS_SAVE_AREA-0x1000(%r1)
|
||||
lg %r10,.Ldump_pfx-.Lpg0(%r13)
|
||||
mvc __LC_PREFIX_SAVE_AREA-0x1000(4,%r1),0(%r10)
|
||||
stfpc __LC_FP_CREG_SAVE_AREA-0x1000(%r1)
|
||||
stckc .Lclkcmp-.Lpg0(%r13)
|
||||
mvc __LC_CLOCK_COMP_SAVE_AREA-0x1000(7,%r1),.Lclkcmp-.Lpg0(%r13)
|
||||
stpt __LC_CPU_TIMER_SAVE_AREA-0x1000(%r1)
|
||||
stg %r13, __LC_PSW_SAVE_AREA-0x1000+8(%r1)
|
||||
.Lpg1: brasl %r14,store_status
|
||||
|
||||
lctlg %c6,%c6,.Lall-.Lpg0(%r13)
|
||||
lgr %r1,%r2
|
||||
|
@ -67,10 +110,7 @@ ENTRY(do_reipl_asm)
|
|||
st %r14,.Ldispsw+12-.Lpg0(%r13)
|
||||
lpswe .Ldispsw-.Lpg0(%r13)
|
||||
.align 8
|
||||
.Lclkcmp: .quad 0x0000000000000000
|
||||
.Lall: .quad 0x00000000ff000000
|
||||
.Ldump_pfx: .quad dump_prefix_page
|
||||
.Lregsave: .quad 0x0000000000000000
|
||||
.align 16
|
||||
/*
|
||||
* These addresses have to be 31 bit otherwise
|
||||
|
|
|
@ -346,7 +346,7 @@ setup_lowcore(void)
|
|||
lc = __alloc_bootmem_low(LC_PAGES * PAGE_SIZE, LC_PAGES * PAGE_SIZE, 0);
|
||||
lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
|
||||
lc->restart_psw.addr =
|
||||
PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
|
||||
PSW_ADDR_AMODE | (unsigned long) psw_restart_int_handler;
|
||||
if (user_mode != HOME_SPACE_MODE)
|
||||
lc->restart_psw.mask |= PSW_ASC_HOME;
|
||||
lc->external_new_psw.mask = psw_kernel_bits;
|
||||
|
@ -529,6 +529,27 @@ static void __init setup_memory_end(void)
|
|||
memory_end = memory_size;
|
||||
}
|
||||
|
||||
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_BASE_BITS | PSW_DEFAULT_KEY;
|
||||
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_memory(void)
|
||||
{
|
||||
|
@ -731,6 +752,7 @@ static void __init setup_hwcaps(void)
|
|||
strcpy(elf_platform, "z10");
|
||||
break;
|
||||
case 0x2817:
|
||||
case 0x2818:
|
||||
strcpy(elf_platform, "z196");
|
||||
break;
|
||||
}
|
||||
|
@ -792,6 +814,7 @@ setup_arch(char **cmdline_p)
|
|||
setup_addressing_mode();
|
||||
setup_memory();
|
||||
setup_resources();
|
||||
setup_restart_psw();
|
||||
setup_lowcore();
|
||||
|
||||
cpu_init();
|
||||
|
|
|
@ -57,17 +57,15 @@ typedef struct
|
|||
*/
|
||||
SYSCALL_DEFINE3(sigsuspend, int, history0, int, history1, old_sigset_t, mask)
|
||||
{
|
||||
mask &= _BLOCKABLE;
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
current->saved_sigmask = current->blocked;
|
||||
siginitset(¤t->blocked, mask);
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
sigset_t blocked;
|
||||
|
||||
current->saved_sigmask = current->blocked;
|
||||
mask &= _BLOCKABLE;
|
||||
siginitset(&blocked, mask);
|
||||
set_current_blocked(&blocked);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
schedule();
|
||||
set_thread_flag(TIF_RESTORE_SIGMASK);
|
||||
|
||||
set_restore_sigmask();
|
||||
return -ERESTARTNOHAND;
|
||||
}
|
||||
|
||||
|
@ -172,18 +170,11 @@ SYSCALL_DEFINE0(sigreturn)
|
|||
goto badframe;
|
||||
if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE))
|
||||
goto badframe;
|
||||
|
||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
current->blocked = set;
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
|
||||
set_current_blocked(&set);
|
||||
if (restore_sigregs(regs, &frame->sregs))
|
||||
goto badframe;
|
||||
|
||||
return regs->gprs[2];
|
||||
|
||||
badframe:
|
||||
force_sig(SIGSEGV, current);
|
||||
return 0;
|
||||
|
@ -199,21 +190,14 @@ SYSCALL_DEFINE0(rt_sigreturn)
|
|||
goto badframe;
|
||||
if (__copy_from_user(&set.sig, &frame->uc.uc_sigmask, sizeof(set)))
|
||||
goto badframe;
|
||||
|
||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
current->blocked = set;
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
|
||||
set_current_blocked(&set);
|
||||
if (restore_sigregs(regs, &frame->uc.uc_mcontext))
|
||||
goto badframe;
|
||||
|
||||
if (do_sigaltstack(&frame->uc.uc_stack, NULL,
|
||||
regs->gprs[15]) == -EFAULT)
|
||||
goto badframe;
|
||||
return regs->gprs[2];
|
||||
|
||||
badframe:
|
||||
force_sig(SIGSEGV, current);
|
||||
return 0;
|
||||
|
@ -385,14 +369,11 @@ give_sigsegv:
|
|||
return -EFAULT;
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, we're invoking a handler
|
||||
*/
|
||||
|
||||
static int
|
||||
handle_signal(unsigned long sig, struct k_sigaction *ka,
|
||||
siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
|
||||
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 */
|
||||
|
@ -400,17 +381,13 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
|
|||
ret = setup_rt_frame(sig, ka, info, oldset, regs);
|
||||
else
|
||||
ret = setup_frame(sig, ka, oldset, regs);
|
||||
|
||||
if (ret == 0) {
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
|
||||
if (!(ka->sa.sa_flags & SA_NODEFER))
|
||||
sigaddset(¤t->blocked,sig);
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
}
|
||||
|
||||
return ret;
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -452,23 +452,27 @@ out:
|
|||
*/
|
||||
int __cpuinit start_secondary(void *cpuvoid)
|
||||
{
|
||||
/* Setup the cpu */
|
||||
cpu_init();
|
||||
preempt_disable();
|
||||
/* Enable TOD clock interrupts on the secondary cpu. */
|
||||
init_cpu_timer();
|
||||
/* Enable cpu timer interrupts on the secondary cpu. */
|
||||
init_cpu_vtimer();
|
||||
/* Enable pfault pseudo page faults on this cpu. */
|
||||
pfault_init();
|
||||
|
||||
/* call cpu notifiers */
|
||||
notify_cpu_starting(smp_processor_id());
|
||||
/* Mark this cpu as online */
|
||||
ipi_call_lock();
|
||||
set_cpu_online(smp_processor_id(), true);
|
||||
ipi_call_unlock();
|
||||
/* Switch on interrupts */
|
||||
__ctl_clear_bit(0, 28); /* Disable lowcore protection */
|
||||
S390_lowcore.restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
|
||||
S390_lowcore.restart_psw.addr =
|
||||
PSW_ADDR_AMODE | (unsigned long) psw_restart_int_handler;
|
||||
__ctl_set_bit(0, 28); /* Enable lowcore protection */
|
||||
/*
|
||||
* Wait until the cpu which brought this one up marked it
|
||||
* active before enabling interrupts.
|
||||
*/
|
||||
while (!cpumask_test_cpu(smp_processor_id(), cpu_active_mask))
|
||||
cpu_relax();
|
||||
local_irq_enable();
|
||||
/* cpu_idle will call schedule for us */
|
||||
cpu_idle();
|
||||
|
@ -507,7 +511,11 @@ static int __cpuinit smp_alloc_lowcore(int cpu)
|
|||
memset((char *)lowcore + 512, 0, sizeof(*lowcore) - 512);
|
||||
lowcore->async_stack = async_stack + ASYNC_SIZE;
|
||||
lowcore->panic_stack = panic_stack + PAGE_SIZE;
|
||||
|
||||
lowcore->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
|
||||
lowcore->restart_psw.addr =
|
||||
PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
|
||||
if (user_mode != HOME_SPACE_MODE)
|
||||
lowcore->restart_psw.mask |= PSW_ASC_HOME;
|
||||
#ifndef CONFIG_64BIT
|
||||
if (MACHINE_HAS_IEEE) {
|
||||
unsigned long save_area;
|
||||
|
|
|
@ -85,3 +85,19 @@ int memcpy_real(void *dest, void *src, size_t count)
|
|||
arch_local_irq_restore(flags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy memory to absolute zero
|
||||
*/
|
||||
void copy_to_absolute_zero(void *dest, void *src, size_t count)
|
||||
{
|
||||
unsigned long cr0;
|
||||
|
||||
BUG_ON((unsigned long) dest + count >= sizeof(struct _lowcore));
|
||||
preempt_disable();
|
||||
__ctl_store(cr0, 0, 0);
|
||||
__ctl_clear_bit(0, 28); /* disable lowcore protection */
|
||||
memcpy_real(dest + store_prefix(), src, count);
|
||||
__ctl_load(cr0, 0, 0);
|
||||
preempt_enable();
|
||||
}
|
||||
|
|
|
@ -528,6 +528,7 @@ static inline void page_table_free_pgste(unsigned long *table)
|
|||
static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm,
|
||||
unsigned long vmaddr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void page_table_free_pgste(unsigned long *table)
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/mutex.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include <asm/ccwdev.h>
|
||||
#include <asm/ebcdic.h>
|
||||
|
@ -888,11 +889,11 @@ char *dasd_get_user_string(const char __user *user_buf, size_t user_len)
|
|||
{
|
||||
char *buffer;
|
||||
|
||||
buffer = kmalloc(user_len + 1, GFP_KERNEL);
|
||||
buffer = vmalloc(user_len + 1);
|
||||
if (buffer == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
if (copy_from_user(buffer, user_buf, user_len) != 0) {
|
||||
kfree(buffer);
|
||||
vfree(buffer);
|
||||
return ERR_PTR(-EFAULT);
|
||||
}
|
||||
/* got the string, now strip linefeed. */
|
||||
|
@ -930,7 +931,7 @@ static ssize_t dasd_stats_write(struct file *file,
|
|||
dasd_profile_off(prof);
|
||||
} else
|
||||
rc = -EINVAL;
|
||||
kfree(buffer);
|
||||
vfree(buffer);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1042,7 +1043,7 @@ static ssize_t dasd_stats_global_write(struct file *file,
|
|||
dasd_global_profile_level = DASD_PROFILE_OFF;
|
||||
} else
|
||||
rc = -EINVAL;
|
||||
kfree(buffer);
|
||||
vfree(buffer);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -1461,6 +1461,15 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
|
|||
"Read device characteristic failed, rc=%d", rc);
|
||||
goto out_err3;
|
||||
}
|
||||
|
||||
if ((device->features & DASD_FEATURE_USERAW) &&
|
||||
!(private->rdc_data.facilities.RT_in_LR)) {
|
||||
dev_err(&device->cdev->dev, "The storage server does not "
|
||||
"support raw-track access\n");
|
||||
rc = -EINVAL;
|
||||
goto out_err3;
|
||||
}
|
||||
|
||||
/* find the valid cylinder size */
|
||||
if (private->rdc_data.no_cyl == LV_COMPAT_CYL &&
|
||||
private->rdc_data.long_no_cyl)
|
||||
|
|
|
@ -312,14 +312,14 @@ static ssize_t dasd_stats_proc_write(struct file *file,
|
|||
pr_info("The statistics have been reset\n");
|
||||
} else
|
||||
goto out_parse_error;
|
||||
kfree(buffer);
|
||||
vfree(buffer);
|
||||
return user_len;
|
||||
out_parse_error:
|
||||
rc = -EINVAL;
|
||||
pr_warning("%s is not a supported value for /proc/dasd/statistics\n",
|
||||
str);
|
||||
out_error:
|
||||
kfree(buffer);
|
||||
vfree(buffer);
|
||||
return rc;
|
||||
#else
|
||||
pr_warning("/proc/dasd/statistics: is not activated in this kernel\n");
|
||||
|
|
|
@ -82,12 +82,9 @@ static int proc_handler_callhome(struct ctl_table *ctl, int write,
|
|||
return -EFAULT;
|
||||
} else {
|
||||
len = *count;
|
||||
rc = copy_from_user(buf, buffer, sizeof(buf));
|
||||
if (rc != 0)
|
||||
return -EFAULT;
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
if (strict_strtoul(buf, 0, &val) != 0)
|
||||
return -EINVAL;
|
||||
rc = kstrtoul_from_user(buffer, len, 0, &val);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (val != 0 && val != 1)
|
||||
return -EINVAL;
|
||||
callhome_enabled = val;
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include "chsc.h"
|
||||
|
||||
#define QDIO_BUSY_BIT_PATIENCE (100 << 12) /* 100 microseconds */
|
||||
#define QDIO_BUSY_BIT_RETRY_DELAY 10 /* 10 milliseconds */
|
||||
#define QDIO_BUSY_BIT_RETRIES 1000 /* = 10s retry time */
|
||||
#define QDIO_INPUT_THRESHOLD (500 << 12) /* 500 microseconds */
|
||||
|
||||
/*
|
||||
|
|
|
@ -188,19 +188,13 @@ static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
|
|||
struct qdio_irq *irq_ptr = seq->private;
|
||||
struct qdio_q *q;
|
||||
unsigned long val;
|
||||
char buf[8];
|
||||
int ret, i;
|
||||
|
||||
if (!irq_ptr)
|
||||
return 0;
|
||||
if (count >= sizeof(buf))
|
||||
return -EINVAL;
|
||||
if (copy_from_user(&buf, ubuf, count))
|
||||
return -EFAULT;
|
||||
buf[count] = 0;
|
||||
|
||||
ret = strict_strtoul(buf, 10, &val);
|
||||
if (ret < 0)
|
||||
ret = kstrtoul_from_user(ubuf, count, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (val) {
|
||||
|
|
|
@ -313,7 +313,7 @@ static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit)
|
|||
unsigned long schid = *((u32 *) &q->irq_ptr->schid);
|
||||
unsigned int fc = QDIO_SIGA_WRITE;
|
||||
u64 start_time = 0;
|
||||
int cc;
|
||||
int retries = 0, cc;
|
||||
|
||||
if (is_qebsm(q)) {
|
||||
schid = q->irq_ptr->sch_token;
|
||||
|
@ -325,6 +325,7 @@ again:
|
|||
/* hipersocket busy condition */
|
||||
if (unlikely(*busy_bit)) {
|
||||
WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2);
|
||||
retries++;
|
||||
|
||||
if (!start_time) {
|
||||
start_time = get_clock();
|
||||
|
@ -333,6 +334,11 @@ again:
|
|||
if ((get_clock() - start_time) < QDIO_BUSY_BIT_PATIENCE)
|
||||
goto again;
|
||||
}
|
||||
if (retries) {
|
||||
DBF_DEV_EVENT(DBF_WARN, q->irq_ptr,
|
||||
"%4x cc2 BB1:%1d", SCH_NO(q), q->nr);
|
||||
DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "count:%u", retries);
|
||||
}
|
||||
return cc;
|
||||
}
|
||||
|
||||
|
@ -728,13 +734,14 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q)
|
|||
|
||||
static int qdio_kick_outbound_q(struct qdio_q *q)
|
||||
{
|
||||
int retries = 0, cc;
|
||||
unsigned int busy_bit;
|
||||
int cc;
|
||||
|
||||
if (!need_siga_out(q))
|
||||
return 0;
|
||||
|
||||
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr);
|
||||
retry:
|
||||
qperf_inc(q, siga_write);
|
||||
|
||||
cc = qdio_siga_output(q, &busy_bit);
|
||||
|
@ -743,7 +750,11 @@ static int qdio_kick_outbound_q(struct qdio_q *q)
|
|||
break;
|
||||
case 2:
|
||||
if (busy_bit) {
|
||||
DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr);
|
||||
while (++retries < QDIO_BUSY_BIT_RETRIES) {
|
||||
mdelay(QDIO_BUSY_BIT_RETRY_DELAY);
|
||||
goto retry;
|
||||
}
|
||||
DBF_ERROR("%4x cc2 BBC:%1d", SCH_NO(q), q->nr);
|
||||
cc |= QDIO_ERROR_SIGA_BUSY;
|
||||
} else
|
||||
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr);
|
||||
|
@ -753,6 +764,10 @@ static int qdio_kick_outbound_q(struct qdio_q *q)
|
|||
DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc);
|
||||
break;
|
||||
}
|
||||
if (retries) {
|
||||
DBF_ERROR("%4x cc2 BB2:%1d", SCH_NO(q), q->nr);
|
||||
DBF_ERROR("count:%u", retries);
|
||||
}
|
||||
return cc;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче