mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-18 20:54:20 +00:00
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:
commit
447e1363bc
24 changed files with 336 additions and 140 deletions
|
@ -274,11 +274,11 @@ config MARCH_Z10
|
||||||
on older machines.
|
on older machines.
|
||||||
|
|
||||||
config MARCH_Z196
|
config MARCH_Z196
|
||||||
bool "IBM zEnterprise 196"
|
bool "IBM zEnterprise 114 and 196"
|
||||||
help
|
help
|
||||||
Select this to enable optimizations for IBM zEnterprise 196
|
Select this to enable optimizations for IBM zEnterprise 114 and 196
|
||||||
(2817 series). The kernel will be slightly faster but will not work
|
(2818 and 2817 series). The kernel will be slightly faster but will
|
||||||
on older machines.
|
not work on older machines.
|
||||||
|
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
|
|
|
@ -167,5 +167,6 @@ enum diag308_rc {
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int diag308(unsigned long subcode, void *addr);
|
extern int diag308(unsigned long subcode, void *addr);
|
||||||
|
extern void diag308_reset(void);
|
||||||
|
|
||||||
#endif /* _ASM_S390_IPL_H */
|
#endif /* _ASM_S390_IPL_H */
|
||||||
|
|
|
@ -18,6 +18,7 @@ void system_call(void);
|
||||||
void pgm_check_handler(void);
|
void pgm_check_handler(void);
|
||||||
void mcck_int_handler(void);
|
void mcck_int_handler(void);
|
||||||
void io_int_handler(void);
|
void io_int_handler(void);
|
||||||
|
void psw_restart_int_handler(void);
|
||||||
|
|
||||||
#ifdef CONFIG_32BIT
|
#ifdef CONFIG_32BIT
|
||||||
|
|
||||||
|
@ -150,7 +151,10 @@ struct _lowcore {
|
||||||
*/
|
*/
|
||||||
__u32 ipib; /* 0x0e00 */
|
__u32 ipib; /* 0x0e00 */
|
||||||
__u32 ipib_checksum; /* 0x0e04 */
|
__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 */
|
/* Extended facility list */
|
||||||
__u64 stfle_fac_list[32]; /* 0x0f00 */
|
__u64 stfle_fac_list[32]; /* 0x0f00 */
|
||||||
|
@ -286,7 +290,10 @@ struct _lowcore {
|
||||||
*/
|
*/
|
||||||
__u64 ipib; /* 0x0e00 */
|
__u64 ipib; /* 0x0e00 */
|
||||||
__u32 ipib_checksum; /* 0x0e08 */
|
__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 */
|
/* Extended facility list */
|
||||||
__u64 stfle_fac_list[32]; /* 0x0f00 */
|
__u64 stfle_fac_list[32]; /* 0x0f00 */
|
||||||
|
|
|
@ -119,14 +119,12 @@ struct stack_frame {
|
||||||
* Do necessary setup to start up a new thread.
|
* Do necessary setup to start up a new thread.
|
||||||
*/
|
*/
|
||||||
#define start_thread(regs, new_psw, new_stackp) do { \
|
#define start_thread(regs, new_psw, new_stackp) do { \
|
||||||
set_fs(USER_DS); \
|
|
||||||
regs->psw.mask = psw_user_bits; \
|
regs->psw.mask = psw_user_bits; \
|
||||||
regs->psw.addr = new_psw | PSW_ADDR_AMODE; \
|
regs->psw.addr = new_psw | PSW_ADDR_AMODE; \
|
||||||
regs->gprs[15] = new_stackp; \
|
regs->gprs[15] = new_stackp; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define start_thread31(regs, new_psw, new_stackp) do { \
|
#define start_thread31(regs, new_psw, new_stackp) do { \
|
||||||
set_fs(USER_DS); \
|
|
||||||
regs->psw.mask = psw_user32_bits; \
|
regs->psw.mask = psw_user32_bits; \
|
||||||
regs->psw.addr = new_psw | PSW_ADDR_AMODE; \
|
regs->psw.addr = new_psw | PSW_ADDR_AMODE; \
|
||||||
regs->gprs[15] = new_stackp; \
|
regs->gprs[15] = new_stackp; \
|
||||||
|
|
|
@ -113,6 +113,7 @@ extern void pfault_fini(void);
|
||||||
|
|
||||||
extern void cmma_init(void);
|
extern void cmma_init(void);
|
||||||
extern int memcpy_real(void *, void *, size_t);
|
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 { \
|
#define finish_arch_switch(prev) do { \
|
||||||
set_fs(current->thread.mm_segment); \
|
set_fs(current->thread.mm_segment); \
|
||||||
|
|
|
@ -27,12 +27,9 @@ int main(void)
|
||||||
BLANK();
|
BLANK();
|
||||||
DEFINE(__TASK_pid, offsetof(struct task_struct, pid));
|
DEFINE(__TASK_pid, offsetof(struct task_struct, pid));
|
||||||
BLANK();
|
BLANK();
|
||||||
DEFINE(__THREAD_per_cause,
|
DEFINE(__THREAD_per_cause, offsetof(struct task_struct, thread.per_event.cause));
|
||||||
offsetof(struct task_struct, thread.per_event.cause));
|
DEFINE(__THREAD_per_address, offsetof(struct task_struct, thread.per_event.address));
|
||||||
DEFINE(__THREAD_per_address,
|
DEFINE(__THREAD_per_paid, offsetof(struct task_struct, thread.per_event.paid));
|
||||||
offsetof(struct task_struct, thread.per_event.address));
|
|
||||||
DEFINE(__THREAD_per_paid,
|
|
||||||
offsetof(struct task_struct, thread.per_event.paid));
|
|
||||||
BLANK();
|
BLANK();
|
||||||
DEFINE(__TI_task, offsetof(struct thread_info, task));
|
DEFINE(__TI_task, offsetof(struct thread_info, task));
|
||||||
DEFINE(__TI_domain, offsetof(struct thread_info, exec_domain));
|
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_FPREGS_SAVE_AREA, offsetof(struct _lowcore, floating_pt_save_area));
|
||||||
DEFINE(__LC_GPREGS_SAVE_AREA, offsetof(struct _lowcore, gpregs_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_CREGS_SAVE_AREA, offsetof(struct _lowcore, cregs_save_area));
|
||||||
|
DEFINE(__LC_SAVE_AREA_64, offsetof(struct _lowcore, save_area_64));
|
||||||
#ifdef CONFIG_32BIT
|
#ifdef CONFIG_32BIT
|
||||||
DEFINE(SAVE_AREA_BASE, offsetof(struct _lowcore, extended_save_area_addr));
|
DEFINE(SAVE_AREA_BASE, offsetof(struct _lowcore, extended_save_area_addr));
|
||||||
#else /* CONFIG_32BIT */
|
#else /* CONFIG_32BIT */
|
||||||
|
|
|
@ -76,6 +76,42 @@ s390_base_pgm_handler_fn:
|
||||||
.quad 0
|
.quad 0
|
||||||
.previous
|
.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 */
|
#else /* CONFIG_64BIT */
|
||||||
|
|
||||||
ENTRY(s390_base_mcck_handler)
|
ENTRY(s390_base_mcck_handler)
|
||||||
|
|
|
@ -380,20 +380,13 @@ asmlinkage long sys32_sigreturn(void)
|
||||||
goto badframe;
|
goto badframe;
|
||||||
if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE32))
|
if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE32))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
|
|
||||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
sigdelsetmask(&set, ~_BLOCKABLE);
|
||||||
spin_lock_irq(¤t->sighand->siglock);
|
set_current_blocked(&set);
|
||||||
current->blocked = set;
|
|
||||||
recalc_sigpending();
|
|
||||||
spin_unlock_irq(¤t->sighand->siglock);
|
|
||||||
|
|
||||||
if (restore_sigregs32(regs, &frame->sregs))
|
if (restore_sigregs32(regs, &frame->sregs))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
if (restore_sigregs_gprs_high(regs, frame->gprs_high))
|
if (restore_sigregs_gprs_high(regs, frame->gprs_high))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
|
|
||||||
return regs->gprs[2];
|
return regs->gprs[2];
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
force_sig(SIGSEGV, current);
|
force_sig(SIGSEGV, current);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -413,31 +406,22 @@ asmlinkage long sys32_rt_sigreturn(void)
|
||||||
goto badframe;
|
goto badframe;
|
||||||
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
|
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
|
|
||||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
sigdelsetmask(&set, ~_BLOCKABLE);
|
||||||
spin_lock_irq(¤t->sighand->siglock);
|
set_current_blocked(&set);
|
||||||
current->blocked = set;
|
|
||||||
recalc_sigpending();
|
|
||||||
spin_unlock_irq(¤t->sighand->siglock);
|
|
||||||
|
|
||||||
if (restore_sigregs32(regs, &frame->uc.uc_mcontext))
|
if (restore_sigregs32(regs, &frame->uc.uc_mcontext))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
if (restore_sigregs_gprs_high(regs, frame->gprs_high))
|
if (restore_sigregs_gprs_high(regs, frame->gprs_high))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
|
|
||||||
err = __get_user(ss_sp, &frame->uc.uc_stack.ss_sp);
|
err = __get_user(ss_sp, &frame->uc.uc_stack.ss_sp);
|
||||||
st.ss_sp = compat_ptr(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_size, &frame->uc.uc_stack.ss_size);
|
||||||
err |= __get_user(st.ss_flags, &frame->uc.uc_stack.ss_flags);
|
err |= __get_user(st.ss_flags, &frame->uc.uc_stack.ss_flags);
|
||||||
if (err)
|
if (err)
|
||||||
goto badframe;
|
goto badframe;
|
||||||
|
|
||||||
set_fs (KERNEL_DS);
|
set_fs (KERNEL_DS);
|
||||||
do_sigaltstack((stack_t __force __user *)&st, NULL, regs->gprs[15]);
|
do_sigaltstack((stack_t __force __user *)&st, NULL, regs->gprs[15]);
|
||||||
set_fs (old_fs);
|
set_fs (old_fs);
|
||||||
|
|
||||||
return regs->gprs[2];
|
return regs->gprs[2];
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
force_sig(SIGSEGV, current);
|
force_sig(SIGSEGV, current);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -605,10 +589,10 @@ give_sigsegv:
|
||||||
* OK, we're invoking a handler
|
* OK, we're invoking a handler
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int handle_signal32(unsigned long sig, struct k_sigaction *ka,
|
||||||
handle_signal32(unsigned long sig, struct k_sigaction *ka,
|
siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
|
||||||
siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
|
|
||||||
{
|
{
|
||||||
|
sigset_t blocked;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Set up the stack frame */
|
/* 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);
|
ret = setup_rt_frame32(sig, ka, info, oldset, regs);
|
||||||
else
|
else
|
||||||
ret = setup_frame32(sig, ka, oldset, regs);
|
ret = setup_frame32(sig, ka, oldset, regs);
|
||||||
|
if (ret)
|
||||||
if (ret == 0) {
|
return ret;
|
||||||
spin_lock_irq(¤t->sighand->siglock);
|
sigorsets(&blocked, ¤t->blocked, &ka->sa.sa_mask);
|
||||||
sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
|
if (!(ka->sa.sa_flags & SA_NODEFER))
|
||||||
if (!(ka->sa.sa_flags & SA_NODEFER))
|
sigaddset(&blocked, sig);
|
||||||
sigaddset(¤t->blocked,sig);
|
set_current_blocked(&blocked);
|
||||||
recalc_sigpending();
|
return 0;
|
||||||
spin_unlock_irq(¤t->sighand->siglock);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -849,6 +849,34 @@ restart_crash:
|
||||||
restart_go:
|
restart_go:
|
||||||
#endif
|
#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"
|
.section .kprobes.text, "ax"
|
||||||
|
|
||||||
#ifdef CONFIG_CHECK_STACK
|
#ifdef CONFIG_CHECK_STACK
|
||||||
|
|
|
@ -865,6 +865,26 @@ restart_crash:
|
||||||
restart_go:
|
restart_go:
|
||||||
#endif
|
#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"
|
.section .kprobes.text, "ax"
|
||||||
|
|
||||||
#ifdef CONFIG_CHECK_STACK
|
#ifdef CONFIG_CHECK_STACK
|
||||||
|
|
|
@ -45,11 +45,13 @@
|
||||||
* - halt
|
* - halt
|
||||||
* - power off
|
* - power off
|
||||||
* - reipl
|
* - reipl
|
||||||
|
* - restart
|
||||||
*/
|
*/
|
||||||
#define ON_PANIC_STR "on_panic"
|
#define ON_PANIC_STR "on_panic"
|
||||||
#define ON_HALT_STR "on_halt"
|
#define ON_HALT_STR "on_halt"
|
||||||
#define ON_POFF_STR "on_poff"
|
#define ON_POFF_STR "on_poff"
|
||||||
#define ON_REIPL_STR "on_reboot"
|
#define ON_REIPL_STR "on_reboot"
|
||||||
|
#define ON_RESTART_STR "on_restart"
|
||||||
|
|
||||||
struct shutdown_action;
|
struct shutdown_action;
|
||||||
struct shutdown_trigger {
|
struct shutdown_trigger {
|
||||||
|
@ -1544,17 +1546,20 @@ static char vmcmd_on_reboot[128];
|
||||||
static char vmcmd_on_panic[128];
|
static char vmcmd_on_panic[128];
|
||||||
static char vmcmd_on_halt[128];
|
static char vmcmd_on_halt[128];
|
||||||
static char vmcmd_on_poff[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_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_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_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_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[] = {
|
static struct attribute *vmcmd_attrs[] = {
|
||||||
&sys_vmcmd_on_reboot_attr.attr,
|
&sys_vmcmd_on_reboot_attr.attr,
|
||||||
&sys_vmcmd_on_panic_attr.attr,
|
&sys_vmcmd_on_panic_attr.attr,
|
||||||
&sys_vmcmd_on_halt_attr.attr,
|
&sys_vmcmd_on_halt_attr.attr,
|
||||||
&sys_vmcmd_on_poff_attr.attr,
|
&sys_vmcmd_on_poff_attr.attr,
|
||||||
|
&sys_vmcmd_on_restart_attr.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1576,6 +1581,8 @@ static void vmcmd_run(struct shutdown_trigger *trigger)
|
||||||
cmd = vmcmd_on_halt;
|
cmd = vmcmd_on_halt;
|
||||||
else if (strcmp(trigger->name, ON_POFF_STR) == 0)
|
else if (strcmp(trigger->name, ON_POFF_STR) == 0)
|
||||||
cmd = vmcmd_on_poff;
|
cmd = vmcmd_on_poff;
|
||||||
|
else if (strcmp(trigger->name, ON_RESTART_STR) == 0)
|
||||||
|
cmd = vmcmd_on_restart;
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1707,6 +1714,34 @@ static void do_panic(void)
|
||||||
stop_run(&on_panic_trigger);
|
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 */
|
/* on halt */
|
||||||
|
|
||||||
static struct shutdown_trigger on_halt_trigger = {ON_HALT_STR, &stop_action};
|
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,
|
if (sysfs_create_file(&shutdown_actions_kset->kobj,
|
||||||
&on_poff_attr.attr))
|
&on_poff_attr.attr))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
if (sysfs_create_file(&shutdown_actions_kset->kobj,
|
||||||
|
&on_restart_attr.attr))
|
||||||
|
goto fail;
|
||||||
return;
|
return;
|
||||||
fail:
|
fail:
|
||||||
panic("shutdown_triggers_init failed\n");
|
panic("shutdown_triggers_init failed\n");
|
||||||
|
@ -1959,6 +1996,12 @@ static void do_reset_calls(void)
|
||||||
{
|
{
|
||||||
struct reset_call *reset;
|
struct reset_call *reset;
|
||||||
|
|
||||||
|
#ifdef CONFIG_64BIT
|
||||||
|
if (diag308_set_works) {
|
||||||
|
diag308_reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
list_for_each_entry(reset, &rcall, list)
|
list_for_each_entry(reset, &rcall, list)
|
||||||
reset->fn();
|
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>,
|
* Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com>,
|
||||||
* Denis Joseph Barrow,
|
* Denis Joseph Barrow,
|
||||||
*/
|
*/
|
||||||
|
@ -7,6 +7,64 @@
|
||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
#include <asm/asm-offsets.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
|
# do_reipl_asm
|
||||||
# Parameter: r2 = schid of reipl device
|
# Parameter: r2 = schid of reipl device
|
||||||
|
@ -15,22 +73,7 @@
|
||||||
ENTRY(do_reipl_asm)
|
ENTRY(do_reipl_asm)
|
||||||
basr %r13,0
|
basr %r13,0
|
||||||
.Lpg0: lpswe .Lnewpsw-.Lpg0(%r13)
|
.Lpg0: lpswe .Lnewpsw-.Lpg0(%r13)
|
||||||
.Lpg1: # do store status of all registers
|
.Lpg1: brasl %r14,store_status
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
lctlg %c6,%c6,.Lall-.Lpg0(%r13)
|
lctlg %c6,%c6,.Lall-.Lpg0(%r13)
|
||||||
lgr %r1,%r2
|
lgr %r1,%r2
|
||||||
|
@ -67,10 +110,7 @@ ENTRY(do_reipl_asm)
|
||||||
st %r14,.Ldispsw+12-.Lpg0(%r13)
|
st %r14,.Ldispsw+12-.Lpg0(%r13)
|
||||||
lpswe .Ldispsw-.Lpg0(%r13)
|
lpswe .Ldispsw-.Lpg0(%r13)
|
||||||
.align 8
|
.align 8
|
||||||
.Lclkcmp: .quad 0x0000000000000000
|
|
||||||
.Lall: .quad 0x00000000ff000000
|
.Lall: .quad 0x00000000ff000000
|
||||||
.Ldump_pfx: .quad dump_prefix_page
|
|
||||||
.Lregsave: .quad 0x0000000000000000
|
|
||||||
.align 16
|
.align 16
|
||||||
/*
|
/*
|
||||||
* These addresses have to be 31 bit otherwise
|
* 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 = __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.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
|
||||||
lc->restart_psw.addr =
|
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)
|
if (user_mode != HOME_SPACE_MODE)
|
||||||
lc->restart_psw.mask |= PSW_ASC_HOME;
|
lc->restart_psw.mask |= PSW_ASC_HOME;
|
||||||
lc->external_new_psw.mask = psw_kernel_bits;
|
lc->external_new_psw.mask = psw_kernel_bits;
|
||||||
|
@ -529,6 +529,27 @@ static void __init setup_memory_end(void)
|
||||||
memory_end = memory_size;
|
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
|
static void __init
|
||||||
setup_memory(void)
|
setup_memory(void)
|
||||||
{
|
{
|
||||||
|
@ -731,6 +752,7 @@ static void __init setup_hwcaps(void)
|
||||||
strcpy(elf_platform, "z10");
|
strcpy(elf_platform, "z10");
|
||||||
break;
|
break;
|
||||||
case 0x2817:
|
case 0x2817:
|
||||||
|
case 0x2818:
|
||||||
strcpy(elf_platform, "z196");
|
strcpy(elf_platform, "z196");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -792,6 +814,7 @@ setup_arch(char **cmdline_p)
|
||||||
setup_addressing_mode();
|
setup_addressing_mode();
|
||||||
setup_memory();
|
setup_memory();
|
||||||
setup_resources();
|
setup_resources();
|
||||||
|
setup_restart_psw();
|
||||||
setup_lowcore();
|
setup_lowcore();
|
||||||
|
|
||||||
cpu_init();
|
cpu_init();
|
||||||
|
|
|
@ -57,17 +57,15 @@ typedef struct
|
||||||
*/
|
*/
|
||||||
SYSCALL_DEFINE3(sigsuspend, int, history0, int, history1, old_sigset_t, mask)
|
SYSCALL_DEFINE3(sigsuspend, int, history0, int, history1, old_sigset_t, mask)
|
||||||
{
|
{
|
||||||
mask &= _BLOCKABLE;
|
sigset_t blocked;
|
||||||
spin_lock_irq(¤t->sighand->siglock);
|
|
||||||
current->saved_sigmask = current->blocked;
|
|
||||||
siginitset(¤t->blocked, mask);
|
|
||||||
recalc_sigpending();
|
|
||||||
spin_unlock_irq(¤t->sighand->siglock);
|
|
||||||
|
|
||||||
|
current->saved_sigmask = current->blocked;
|
||||||
|
mask &= _BLOCKABLE;
|
||||||
|
siginitset(&blocked, mask);
|
||||||
|
set_current_blocked(&blocked);
|
||||||
set_current_state(TASK_INTERRUPTIBLE);
|
set_current_state(TASK_INTERRUPTIBLE);
|
||||||
schedule();
|
schedule();
|
||||||
set_thread_flag(TIF_RESTORE_SIGMASK);
|
set_restore_sigmask();
|
||||||
|
|
||||||
return -ERESTARTNOHAND;
|
return -ERESTARTNOHAND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,18 +170,11 @@ SYSCALL_DEFINE0(sigreturn)
|
||||||
goto badframe;
|
goto badframe;
|
||||||
if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE))
|
if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
|
|
||||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
sigdelsetmask(&set, ~_BLOCKABLE);
|
||||||
spin_lock_irq(¤t->sighand->siglock);
|
set_current_blocked(&set);
|
||||||
current->blocked = set;
|
|
||||||
recalc_sigpending();
|
|
||||||
spin_unlock_irq(¤t->sighand->siglock);
|
|
||||||
|
|
||||||
if (restore_sigregs(regs, &frame->sregs))
|
if (restore_sigregs(regs, &frame->sregs))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
|
|
||||||
return regs->gprs[2];
|
return regs->gprs[2];
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
force_sig(SIGSEGV, current);
|
force_sig(SIGSEGV, current);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -199,21 +190,14 @@ SYSCALL_DEFINE0(rt_sigreturn)
|
||||||
goto badframe;
|
goto badframe;
|
||||||
if (__copy_from_user(&set.sig, &frame->uc.uc_sigmask, sizeof(set)))
|
if (__copy_from_user(&set.sig, &frame->uc.uc_sigmask, sizeof(set)))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
|
|
||||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
sigdelsetmask(&set, ~_BLOCKABLE);
|
||||||
spin_lock_irq(¤t->sighand->siglock);
|
set_current_blocked(&set);
|
||||||
current->blocked = set;
|
|
||||||
recalc_sigpending();
|
|
||||||
spin_unlock_irq(¤t->sighand->siglock);
|
|
||||||
|
|
||||||
if (restore_sigregs(regs, &frame->uc.uc_mcontext))
|
if (restore_sigregs(regs, &frame->uc.uc_mcontext))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
|
|
||||||
if (do_sigaltstack(&frame->uc.uc_stack, NULL,
|
if (do_sigaltstack(&frame->uc.uc_stack, NULL,
|
||||||
regs->gprs[15]) == -EFAULT)
|
regs->gprs[15]) == -EFAULT)
|
||||||
goto badframe;
|
goto badframe;
|
||||||
return regs->gprs[2];
|
return regs->gprs[2];
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
force_sig(SIGSEGV, current);
|
force_sig(SIGSEGV, current);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -385,14 +369,11 @@ give_sigsegv:
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int handle_signal(unsigned long sig, struct k_sigaction *ka,
|
||||||
* OK, we're invoking a handler
|
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;
|
int ret;
|
||||||
|
|
||||||
/* Set up the stack frame */
|
/* 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);
|
ret = setup_rt_frame(sig, ka, info, oldset, regs);
|
||||||
else
|
else
|
||||||
ret = setup_frame(sig, ka, oldset, regs);
|
ret = setup_frame(sig, ka, oldset, regs);
|
||||||
|
if (ret)
|
||||||
if (ret == 0) {
|
return ret;
|
||||||
spin_lock_irq(¤t->sighand->siglock);
|
sigorsets(&blocked, ¤t->blocked, &ka->sa.sa_mask);
|
||||||
sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
|
if (!(ka->sa.sa_flags & SA_NODEFER))
|
||||||
if (!(ka->sa.sa_flags & SA_NODEFER))
|
sigaddset(&blocked, sig);
|
||||||
sigaddset(¤t->blocked,sig);
|
set_current_blocked(&blocked);
|
||||||
recalc_sigpending();
|
return 0;
|
||||||
spin_unlock_irq(¤t->sighand->siglock);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -452,23 +452,27 @@ out:
|
||||||
*/
|
*/
|
||||||
int __cpuinit start_secondary(void *cpuvoid)
|
int __cpuinit start_secondary(void *cpuvoid)
|
||||||
{
|
{
|
||||||
/* Setup the cpu */
|
|
||||||
cpu_init();
|
cpu_init();
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
/* Enable TOD clock interrupts on the secondary cpu. */
|
|
||||||
init_cpu_timer();
|
init_cpu_timer();
|
||||||
/* Enable cpu timer interrupts on the secondary cpu. */
|
|
||||||
init_cpu_vtimer();
|
init_cpu_vtimer();
|
||||||
/* Enable pfault pseudo page faults on this cpu. */
|
|
||||||
pfault_init();
|
pfault_init();
|
||||||
|
|
||||||
/* call cpu notifiers */
|
|
||||||
notify_cpu_starting(smp_processor_id());
|
notify_cpu_starting(smp_processor_id());
|
||||||
/* Mark this cpu as online */
|
|
||||||
ipi_call_lock();
|
ipi_call_lock();
|
||||||
set_cpu_online(smp_processor_id(), true);
|
set_cpu_online(smp_processor_id(), true);
|
||||||
ipi_call_unlock();
|
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();
|
local_irq_enable();
|
||||||
/* cpu_idle will call schedule for us */
|
/* cpu_idle will call schedule for us */
|
||||||
cpu_idle();
|
cpu_idle();
|
||||||
|
@ -507,7 +511,11 @@ static int __cpuinit smp_alloc_lowcore(int cpu)
|
||||||
memset((char *)lowcore + 512, 0, sizeof(*lowcore) - 512);
|
memset((char *)lowcore + 512, 0, sizeof(*lowcore) - 512);
|
||||||
lowcore->async_stack = async_stack + ASYNC_SIZE;
|
lowcore->async_stack = async_stack + ASYNC_SIZE;
|
||||||
lowcore->panic_stack = panic_stack + PAGE_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
|
#ifndef CONFIG_64BIT
|
||||||
if (MACHINE_HAS_IEEE) {
|
if (MACHINE_HAS_IEEE) {
|
||||||
unsigned long save_area;
|
unsigned long save_area;
|
||||||
|
|
|
@ -85,3 +85,19 @@ int memcpy_real(void *dest, void *src, size_t count)
|
||||||
arch_local_irq_restore(flags);
|
arch_local_irq_restore(flags);
|
||||||
return rc;
|
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,
|
static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm,
|
||||||
unsigned long vmaddr)
|
unsigned long vmaddr)
|
||||||
{
|
{
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void page_table_free_pgste(unsigned long *table)
|
static inline void page_table_free_pgste(unsigned long *table)
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/debugfs.h>
|
#include <linux/debugfs.h>
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
|
#include <linux/vmalloc.h>
|
||||||
|
|
||||||
#include <asm/ccwdev.h>
|
#include <asm/ccwdev.h>
|
||||||
#include <asm/ebcdic.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;
|
char *buffer;
|
||||||
|
|
||||||
buffer = kmalloc(user_len + 1, GFP_KERNEL);
|
buffer = vmalloc(user_len + 1);
|
||||||
if (buffer == NULL)
|
if (buffer == NULL)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
if (copy_from_user(buffer, user_buf, user_len) != 0) {
|
if (copy_from_user(buffer, user_buf, user_len) != 0) {
|
||||||
kfree(buffer);
|
vfree(buffer);
|
||||||
return ERR_PTR(-EFAULT);
|
return ERR_PTR(-EFAULT);
|
||||||
}
|
}
|
||||||
/* got the string, now strip linefeed. */
|
/* got the string, now strip linefeed. */
|
||||||
|
@ -930,7 +931,7 @@ static ssize_t dasd_stats_write(struct file *file,
|
||||||
dasd_profile_off(prof);
|
dasd_profile_off(prof);
|
||||||
} else
|
} else
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
kfree(buffer);
|
vfree(buffer);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1042,7 +1043,7 @@ static ssize_t dasd_stats_global_write(struct file *file,
|
||||||
dasd_global_profile_level = DASD_PROFILE_OFF;
|
dasd_global_profile_level = DASD_PROFILE_OFF;
|
||||||
} else
|
} else
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
kfree(buffer);
|
vfree(buffer);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1461,6 +1461,15 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
|
||||||
"Read device characteristic failed, rc=%d", rc);
|
"Read device characteristic failed, rc=%d", rc);
|
||||||
goto out_err3;
|
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 */
|
/* find the valid cylinder size */
|
||||||
if (private->rdc_data.no_cyl == LV_COMPAT_CYL &&
|
if (private->rdc_data.no_cyl == LV_COMPAT_CYL &&
|
||||||
private->rdc_data.long_no_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");
|
pr_info("The statistics have been reset\n");
|
||||||
} else
|
} else
|
||||||
goto out_parse_error;
|
goto out_parse_error;
|
||||||
kfree(buffer);
|
vfree(buffer);
|
||||||
return user_len;
|
return user_len;
|
||||||
out_parse_error:
|
out_parse_error:
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
pr_warning("%s is not a supported value for /proc/dasd/statistics\n",
|
pr_warning("%s is not a supported value for /proc/dasd/statistics\n",
|
||||||
str);
|
str);
|
||||||
out_error:
|
out_error:
|
||||||
kfree(buffer);
|
vfree(buffer);
|
||||||
return rc;
|
return rc;
|
||||||
#else
|
#else
|
||||||
pr_warning("/proc/dasd/statistics: is not activated in this kernel\n");
|
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;
|
return -EFAULT;
|
||||||
} else {
|
} else {
|
||||||
len = *count;
|
len = *count;
|
||||||
rc = copy_from_user(buf, buffer, sizeof(buf));
|
rc = kstrtoul_from_user(buffer, len, 0, &val);
|
||||||
if (rc != 0)
|
if (rc)
|
||||||
return -EFAULT;
|
return rc;
|
||||||
buf[sizeof(buf) - 1] = '\0';
|
|
||||||
if (strict_strtoul(buf, 0, &val) != 0)
|
|
||||||
return -EINVAL;
|
|
||||||
if (val != 0 && val != 1)
|
if (val != 0 && val != 1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
callhome_enabled = val;
|
callhome_enabled = val;
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#include "chsc.h"
|
#include "chsc.h"
|
||||||
|
|
||||||
#define QDIO_BUSY_BIT_PATIENCE (100 << 12) /* 100 microseconds */
|
#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 */
|
#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_irq *irq_ptr = seq->private;
|
||||||
struct qdio_q *q;
|
struct qdio_q *q;
|
||||||
unsigned long val;
|
unsigned long val;
|
||||||
char buf[8];
|
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
|
||||||
if (!irq_ptr)
|
if (!irq_ptr)
|
||||||
return 0;
|
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);
|
ret = kstrtoul_from_user(ubuf, count, 10, &val);
|
||||||
if (ret < 0)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
switch (val) {
|
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 long schid = *((u32 *) &q->irq_ptr->schid);
|
||||||
unsigned int fc = QDIO_SIGA_WRITE;
|
unsigned int fc = QDIO_SIGA_WRITE;
|
||||||
u64 start_time = 0;
|
u64 start_time = 0;
|
||||||
int cc;
|
int retries = 0, cc;
|
||||||
|
|
||||||
if (is_qebsm(q)) {
|
if (is_qebsm(q)) {
|
||||||
schid = q->irq_ptr->sch_token;
|
schid = q->irq_ptr->sch_token;
|
||||||
|
@ -325,6 +325,7 @@ again:
|
||||||
/* hipersocket busy condition */
|
/* hipersocket busy condition */
|
||||||
if (unlikely(*busy_bit)) {
|
if (unlikely(*busy_bit)) {
|
||||||
WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2);
|
WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2);
|
||||||
|
retries++;
|
||||||
|
|
||||||
if (!start_time) {
|
if (!start_time) {
|
||||||
start_time = get_clock();
|
start_time = get_clock();
|
||||||
|
@ -333,6 +334,11 @@ again:
|
||||||
if ((get_clock() - start_time) < QDIO_BUSY_BIT_PATIENCE)
|
if ((get_clock() - start_time) < QDIO_BUSY_BIT_PATIENCE)
|
||||||
goto again;
|
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;
|
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)
|
static int qdio_kick_outbound_q(struct qdio_q *q)
|
||||||
{
|
{
|
||||||
|
int retries = 0, cc;
|
||||||
unsigned int busy_bit;
|
unsigned int busy_bit;
|
||||||
int cc;
|
|
||||||
|
|
||||||
if (!need_siga_out(q))
|
if (!need_siga_out(q))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr);
|
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr);
|
||||||
|
retry:
|
||||||
qperf_inc(q, siga_write);
|
qperf_inc(q, siga_write);
|
||||||
|
|
||||||
cc = qdio_siga_output(q, &busy_bit);
|
cc = qdio_siga_output(q, &busy_bit);
|
||||||
|
@ -743,7 +750,11 @@ static int qdio_kick_outbound_q(struct qdio_q *q)
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (busy_bit) {
|
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;
|
cc |= QDIO_ERROR_SIGA_BUSY;
|
||||||
} else
|
} else
|
||||||
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr);
|
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);
|
DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (retries) {
|
||||||
|
DBF_ERROR("%4x cc2 BB2:%1d", SCH_NO(q), q->nr);
|
||||||
|
DBF_ERROR("count:%u", retries);
|
||||||
|
}
|
||||||
return cc;
|
return cc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue