mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 06:02:05 +00:00
s390: assume diag308 set always works
diag308 set has been available for many machine generations, and alternative reipl code paths has not been exercised and seems to be broken without noticing for a while now. So, cleaning up all obsolete reipl methods except currently used ones, assuming that diag308 set always works. Also removing not longer needed reset callbacks. Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
ecc0df0f23
commit
d485235b00
@ -328,8 +328,6 @@ static inline u8 pathmask_to_pos(u8 mask)
|
||||
void channel_subsystem_reinit(void);
|
||||
extern void css_schedule_reprobe(void);
|
||||
|
||||
extern void reipl_ccw_dev(struct ccw_dev_id *id);
|
||||
|
||||
/* Function from drivers/s390/cio/chsc.c */
|
||||
int chsc_sstpc(void *page, unsigned int op, u16 ctrl, u64 *clock_delta);
|
||||
int chsc_sstpi(void *page, void *result, size_t size);
|
||||
|
@ -87,6 +87,7 @@ struct save_area * __init save_area_boot_cpu(void);
|
||||
void __init save_area_add_regs(struct save_area *, void *regs);
|
||||
void __init save_area_add_vxrs(struct save_area *, __vector128 *vxrs);
|
||||
|
||||
extern void s390_reset_system(void);
|
||||
extern void do_reipl(void);
|
||||
extern void do_halt(void);
|
||||
extern void do_poff(void);
|
||||
|
@ -1,20 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright IBM Corp. 2006
|
||||
* Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
|
||||
*/
|
||||
|
||||
#ifndef _ASM_S390_RESET_H
|
||||
#define _ASM_S390_RESET_H
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
struct reset_call {
|
||||
struct list_head list;
|
||||
void (*fn)(void);
|
||||
};
|
||||
|
||||
extern void register_reset_call(struct reset_call *reset);
|
||||
extern void unregister_reset_call(struct reset_call *reset);
|
||||
extern void s390_reset_system(void);
|
||||
#endif /* _ASM_S390_RESET_H */
|
@ -25,7 +25,6 @@
|
||||
#include <asm/setup.h>
|
||||
#include <asm/cpcmd.h>
|
||||
#include <asm/ebcdic.h>
|
||||
#include <asm/reset.h>
|
||||
#include <asm/sclp.h>
|
||||
#include <asm/checksum.h>
|
||||
#include <asm/debug.h>
|
||||
@ -119,29 +118,20 @@ static char *dump_type_str(enum dump_type type)
|
||||
}
|
||||
|
||||
enum ipl_method {
|
||||
REIPL_METHOD_CCW_CIO,
|
||||
REIPL_METHOD_CCW_DIAG,
|
||||
REIPL_METHOD_CCW_VM,
|
||||
REIPL_METHOD_FCP_RO_DIAG,
|
||||
REIPL_METHOD_FCP_RW_DIAG,
|
||||
REIPL_METHOD_FCP_RO_VM,
|
||||
REIPL_METHOD_FCP_DIAG,
|
||||
REIPL_METHOD_FCP_DUMP,
|
||||
REIPL_METHOD_NSS,
|
||||
REIPL_METHOD_NSS_DIAG,
|
||||
REIPL_METHOD_DEFAULT,
|
||||
};
|
||||
|
||||
enum dump_method {
|
||||
DUMP_METHOD_NONE,
|
||||
DUMP_METHOD_CCW_CIO,
|
||||
DUMP_METHOD_CCW_DIAG,
|
||||
DUMP_METHOD_CCW_VM,
|
||||
DUMP_METHOD_FCP_DIAG,
|
||||
};
|
||||
|
||||
static int ipl_block_valid;
|
||||
static int diag308_set_works;
|
||||
|
||||
static struct ipl_parameter_block ipl_block;
|
||||
|
||||
static int reipl_capabilities = IPL_TYPE_UNKNOWN;
|
||||
@ -256,14 +246,6 @@ static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
|
||||
sys_##_prefix##_##_name##_show, \
|
||||
sys_##_prefix##_##_name##_store)
|
||||
|
||||
static void make_attrs_ro(struct attribute **attrs)
|
||||
{
|
||||
while (*attrs) {
|
||||
(*attrs)->mode = S_IRUGO;
|
||||
attrs++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ipl section
|
||||
*/
|
||||
@ -541,10 +523,6 @@ static void __ipl_run(void *unused)
|
||||
{
|
||||
__bpon();
|
||||
diag308(DIAG308_LOAD_CLEAR, NULL);
|
||||
if (MACHINE_IS_VM)
|
||||
__cpcmd("IPL", NULL, 0, NULL);
|
||||
else if (ipl_info.type == IPL_TYPE_CCW)
|
||||
reipl_ccw_dev(&ipl_info.data.ccw.dev_id);
|
||||
}
|
||||
|
||||
static void ipl_run(struct shutdown_trigger *trigger)
|
||||
@ -951,31 +929,18 @@ static int reipl_set_type(enum ipl_type type)
|
||||
|
||||
switch(type) {
|
||||
case IPL_TYPE_CCW:
|
||||
if (diag308_set_works)
|
||||
reipl_method = REIPL_METHOD_CCW_DIAG;
|
||||
else if (MACHINE_IS_VM)
|
||||
reipl_method = REIPL_METHOD_CCW_VM;
|
||||
else
|
||||
reipl_method = REIPL_METHOD_CCW_CIO;
|
||||
reipl_method = REIPL_METHOD_CCW_DIAG;
|
||||
set_reipl_block_actual(reipl_block_ccw);
|
||||
break;
|
||||
case IPL_TYPE_FCP:
|
||||
if (diag308_set_works)
|
||||
reipl_method = REIPL_METHOD_FCP_RW_DIAG;
|
||||
else if (MACHINE_IS_VM)
|
||||
reipl_method = REIPL_METHOD_FCP_RO_VM;
|
||||
else
|
||||
reipl_method = REIPL_METHOD_FCP_RO_DIAG;
|
||||
reipl_method = REIPL_METHOD_FCP_DIAG;
|
||||
set_reipl_block_actual(reipl_block_fcp);
|
||||
break;
|
||||
case IPL_TYPE_FCP_DUMP:
|
||||
reipl_method = REIPL_METHOD_FCP_DUMP;
|
||||
break;
|
||||
case IPL_TYPE_NSS:
|
||||
if (diag308_set_works)
|
||||
reipl_method = REIPL_METHOD_NSS_DIAG;
|
||||
else
|
||||
reipl_method = REIPL_METHOD_NSS;
|
||||
reipl_method = REIPL_METHOD_NSS_DIAG;
|
||||
set_reipl_block_actual(reipl_block_nss);
|
||||
break;
|
||||
case IPL_TYPE_UNKNOWN:
|
||||
@ -1015,74 +980,22 @@ static struct kobj_attribute reipl_type_attr =
|
||||
static struct kset *reipl_kset;
|
||||
static struct kset *reipl_fcp_kset;
|
||||
|
||||
static void get_ipl_string(char *dst, struct ipl_parameter_block *ipb,
|
||||
const enum ipl_method m)
|
||||
{
|
||||
char loadparm[LOADPARM_LEN + 1] = {};
|
||||
char vmparm[DIAG308_VMPARM_SIZE + 1] = {};
|
||||
char nss_name[NSS_NAME_SIZE + 1] = {};
|
||||
size_t pos = 0;
|
||||
|
||||
reipl_get_ascii_loadparm(loadparm, ipb);
|
||||
reipl_get_ascii_nss_name(nss_name, ipb);
|
||||
reipl_get_ascii_vmparm(vmparm, sizeof(vmparm), ipb);
|
||||
|
||||
switch (m) {
|
||||
case REIPL_METHOD_CCW_VM:
|
||||
pos = sprintf(dst, "IPL %X CLEAR", ipb->ipl_info.ccw.devno);
|
||||
break;
|
||||
case REIPL_METHOD_NSS:
|
||||
pos = sprintf(dst, "IPL %s", nss_name);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (strlen(loadparm) > 0)
|
||||
pos += sprintf(dst + pos, " LOADPARM '%s'", loadparm);
|
||||
if (strlen(vmparm) > 0)
|
||||
sprintf(dst + pos, " PARM %s", vmparm);
|
||||
}
|
||||
|
||||
static void __reipl_run(void *unused)
|
||||
{
|
||||
struct ccw_dev_id devid;
|
||||
static char buf[128];
|
||||
|
||||
switch (reipl_method) {
|
||||
case REIPL_METHOD_CCW_CIO:
|
||||
devid.ssid = reipl_block_ccw->ipl_info.ccw.ssid;
|
||||
devid.devno = reipl_block_ccw->ipl_info.ccw.devno;
|
||||
reipl_ccw_dev(&devid);
|
||||
break;
|
||||
case REIPL_METHOD_CCW_VM:
|
||||
get_ipl_string(buf, reipl_block_ccw, REIPL_METHOD_CCW_VM);
|
||||
__cpcmd(buf, NULL, 0, NULL);
|
||||
break;
|
||||
case REIPL_METHOD_CCW_DIAG:
|
||||
diag308(DIAG308_SET, reipl_block_ccw);
|
||||
diag308(DIAG308_LOAD_CLEAR, NULL);
|
||||
break;
|
||||
case REIPL_METHOD_FCP_RW_DIAG:
|
||||
case REIPL_METHOD_FCP_DIAG:
|
||||
diag308(DIAG308_SET, reipl_block_fcp);
|
||||
diag308(DIAG308_LOAD_CLEAR, NULL);
|
||||
break;
|
||||
case REIPL_METHOD_FCP_RO_DIAG:
|
||||
diag308(DIAG308_LOAD_CLEAR, NULL);
|
||||
break;
|
||||
case REIPL_METHOD_FCP_RO_VM:
|
||||
__cpcmd("IPL", NULL, 0, NULL);
|
||||
break;
|
||||
case REIPL_METHOD_NSS_DIAG:
|
||||
diag308(DIAG308_SET, reipl_block_nss);
|
||||
diag308(DIAG308_LOAD_CLEAR, NULL);
|
||||
break;
|
||||
case REIPL_METHOD_NSS:
|
||||
get_ipl_string(buf, reipl_block_nss, REIPL_METHOD_NSS);
|
||||
__cpcmd(buf, NULL, 0, NULL);
|
||||
break;
|
||||
case REIPL_METHOD_DEFAULT:
|
||||
if (MACHINE_IS_VM)
|
||||
__cpcmd("IPL", NULL, 0, NULL);
|
||||
diag308(DIAG308_LOAD_CLEAR, NULL);
|
||||
break;
|
||||
case REIPL_METHOD_FCP_DUMP:
|
||||
@ -1138,9 +1051,6 @@ static int __init reipl_nss_init(void)
|
||||
if (!reipl_block_nss)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!diag308_set_works)
|
||||
sys_reipl_nss_vmparm_attr.attr.mode = S_IRUGO;
|
||||
|
||||
rc = sysfs_create_group(&reipl_kset->kobj, &reipl_nss_attr_group);
|
||||
if (rc)
|
||||
return rc;
|
||||
@ -1158,17 +1068,9 @@ static int __init reipl_ccw_init(void)
|
||||
if (!reipl_block_ccw)
|
||||
return -ENOMEM;
|
||||
|
||||
if (MACHINE_IS_VM) {
|
||||
if (!diag308_set_works)
|
||||
sys_reipl_ccw_vmparm_attr.attr.mode = S_IRUGO;
|
||||
rc = sysfs_create_group(&reipl_kset->kobj,
|
||||
&reipl_ccw_attr_group_vm);
|
||||
} else {
|
||||
if(!diag308_set_works)
|
||||
sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO;
|
||||
rc = sysfs_create_group(&reipl_kset->kobj,
|
||||
&reipl_ccw_attr_group_lpar);
|
||||
}
|
||||
rc = sysfs_create_group(&reipl_kset->kobj,
|
||||
MACHINE_IS_VM ? &reipl_ccw_attr_group_vm
|
||||
: &reipl_ccw_attr_group_lpar);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
@ -1187,14 +1089,6 @@ static int __init reipl_fcp_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!diag308_set_works) {
|
||||
if (ipl_info.type == IPL_TYPE_FCP) {
|
||||
make_attrs_ro(reipl_fcp_attrs);
|
||||
sys_reipl_fcp_scp_data_attr.attr.mode = S_IRUGO;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
|
||||
if (!reipl_block_fcp)
|
||||
return -ENOMEM;
|
||||
@ -1339,12 +1233,7 @@ static int dump_set_type(enum dump_type type)
|
||||
return -EINVAL;
|
||||
switch (type) {
|
||||
case DUMP_TYPE_CCW:
|
||||
if (diag308_set_works)
|
||||
dump_method = DUMP_METHOD_CCW_DIAG;
|
||||
else if (MACHINE_IS_VM)
|
||||
dump_method = DUMP_METHOD_CCW_VM;
|
||||
else
|
||||
dump_method = DUMP_METHOD_CCW_CIO;
|
||||
dump_method = DUMP_METHOD_CCW_DIAG;
|
||||
break;
|
||||
case DUMP_TYPE_FCP:
|
||||
dump_method = DUMP_METHOD_FCP_DIAG;
|
||||
@ -1394,21 +1283,7 @@ static void diag308_dump(void *dump_block)
|
||||
|
||||
static void __dump_run(void *unused)
|
||||
{
|
||||
struct ccw_dev_id devid;
|
||||
static char buf[100];
|
||||
|
||||
switch (dump_method) {
|
||||
case DUMP_METHOD_CCW_CIO:
|
||||
devid.ssid = dump_block_ccw->ipl_info.ccw.ssid;
|
||||
devid.devno = dump_block_ccw->ipl_info.ccw.devno;
|
||||
reipl_ccw_dev(&devid);
|
||||
break;
|
||||
case DUMP_METHOD_CCW_VM:
|
||||
sprintf(buf, "STORE STATUS");
|
||||
__cpcmd(buf, NULL, 0, NULL);
|
||||
sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno);
|
||||
__cpcmd(buf, NULL, 0, NULL);
|
||||
break;
|
||||
case DUMP_METHOD_CCW_DIAG:
|
||||
diag308_dump(dump_block_ccw);
|
||||
break;
|
||||
@ -1454,8 +1329,6 @@ static int __init dump_fcp_init(void)
|
||||
|
||||
if (!sclp_ipl_info.has_dump)
|
||||
return 0; /* LDIPL DUMP is not installed */
|
||||
if (!diag308_set_works)
|
||||
return 0;
|
||||
dump_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
|
||||
if (!dump_block_fcp)
|
||||
return -ENOMEM;
|
||||
@ -1513,18 +1386,9 @@ static void dump_reipl_run(struct shutdown_trigger *trigger)
|
||||
dump_run(trigger);
|
||||
}
|
||||
|
||||
static int __init dump_reipl_init(void)
|
||||
{
|
||||
if (!diag308_set_works)
|
||||
return -EOPNOTSUPP;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct shutdown_action __refdata dump_reipl_action = {
|
||||
.name = SHUTDOWN_ACTION_DUMP_REIPL_STR,
|
||||
.fn = dump_reipl_run,
|
||||
.init = dump_reipl_init,
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1944,67 +1808,16 @@ void __init ipl_store_parameters(void)
|
||||
int rc;
|
||||
|
||||
rc = diag308(DIAG308_STORE, &ipl_block);
|
||||
if ((rc == DIAG308_RC_OK) || (rc == DIAG308_RC_NOCONFIG))
|
||||
diag308_set_works = 1;
|
||||
if (rc == DIAG308_RC_OK && ipl_block.hdr.version <= IPL_MAX_SUPPORTED_VERSION)
|
||||
ipl_block_valid = 1;
|
||||
}
|
||||
|
||||
static LIST_HEAD(rcall);
|
||||
static DEFINE_MUTEX(rcall_mutex);
|
||||
|
||||
void register_reset_call(struct reset_call *reset)
|
||||
{
|
||||
mutex_lock(&rcall_mutex);
|
||||
list_add(&reset->list, &rcall);
|
||||
mutex_unlock(&rcall_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(register_reset_call);
|
||||
|
||||
void unregister_reset_call(struct reset_call *reset)
|
||||
{
|
||||
mutex_lock(&rcall_mutex);
|
||||
list_del(&reset->list);
|
||||
mutex_unlock(&rcall_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(unregister_reset_call);
|
||||
|
||||
static void do_reset_calls(void)
|
||||
{
|
||||
struct reset_call *reset;
|
||||
|
||||
if (diag308_set_works) {
|
||||
diag308_reset();
|
||||
return;
|
||||
}
|
||||
list_for_each_entry(reset, &rcall, list)
|
||||
reset->fn();
|
||||
}
|
||||
|
||||
void s390_reset_system(void)
|
||||
{
|
||||
struct lowcore *lc;
|
||||
|
||||
lc = (struct lowcore *)(unsigned long) store_prefix();
|
||||
|
||||
/* Stack for interrupt/machine check handler */
|
||||
lc->panic_stack = S390_lowcore.panic_stack;
|
||||
|
||||
/* Disable prefixing */
|
||||
set_prefix(0);
|
||||
|
||||
/* Disable lowcore protection */
|
||||
__ctl_clear_bit(0,28);
|
||||
|
||||
/* Set new machine check handler */
|
||||
S390_lowcore.mcck_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_DAT;
|
||||
S390_lowcore.mcck_new_psw.addr =
|
||||
(unsigned long) s390_base_mcck_handler;
|
||||
|
||||
/* Set new program check handler */
|
||||
S390_lowcore.program_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_DAT;
|
||||
S390_lowcore.program_new_psw.addr =
|
||||
(unsigned long) s390_base_pgm_handler;
|
||||
|
||||
do_reset_calls();
|
||||
__ctl_clear_bit(0, 28);
|
||||
diag308_reset();
|
||||
}
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/smp.h>
|
||||
#include <asm/reset.h>
|
||||
#include <asm/ipl.h>
|
||||
#include <asm/diag.h>
|
||||
#include <asm/elf.h>
|
||||
|
@ -75,90 +75,3 @@ ENTRY(store_status)
|
||||
.align 8
|
||||
.Lclkcmp: .quad 0x0000000000000000
|
||||
.previous
|
||||
|
||||
#
|
||||
# do_reipl_asm
|
||||
# Parameter: r2 = schid of reipl device
|
||||
#
|
||||
|
||||
ENTRY(do_reipl_asm)
|
||||
basr %r13,0
|
||||
.Lpg0: lpswe .Lnewpsw-.Lpg0(%r13)
|
||||
.Lpg1: lgr %r3,%r2
|
||||
larl %r2,.Lstatus
|
||||
brasl %r14,store_status
|
||||
|
||||
.Lstatus: lctlg %c6,%c6,.Lall-.Lpg0(%r13)
|
||||
lgr %r1,%r2
|
||||
mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13)
|
||||
stsch .Lschib-.Lpg0(%r13)
|
||||
oi .Lschib+5-.Lpg0(%r13),0x84
|
||||
.Lecs: xi .Lschib+27-.Lpg0(%r13),0x01
|
||||
msch .Lschib-.Lpg0(%r13)
|
||||
lghi %r0,5
|
||||
.Lssch: ssch .Liplorb-.Lpg0(%r13)
|
||||
jz .L001
|
||||
brct %r0,.Lssch
|
||||
bas %r14,.Ldisab-.Lpg0(%r13)
|
||||
.L001: mvc __LC_IO_NEW_PSW(16),.Lionew-.Lpg0(%r13)
|
||||
.Ltpi: lpswe .Lwaitpsw-.Lpg0(%r13)
|
||||
.Lcont: c %r1,__LC_SUBCHANNEL_ID
|
||||
jnz .Ltpi
|
||||
clc __LC_IO_INT_PARM(4),.Liplorb-.Lpg0(%r13)
|
||||
jnz .Ltpi
|
||||
tsch .Liplirb-.Lpg0(%r13)
|
||||
tm .Liplirb+9-.Lpg0(%r13),0xbf
|
||||
jz .L002
|
||||
bas %r14,.Ldisab-.Lpg0(%r13)
|
||||
.L002: tm .Liplirb+8-.Lpg0(%r13),0xf3
|
||||
jz .L003
|
||||
bas %r14,.Ldisab-.Lpg0(%r13)
|
||||
.L003: st %r1,__LC_SUBCHANNEL_ID
|
||||
lhi %r1,0 # mode 0 = esa
|
||||
slr %r0,%r0 # set cpuid to zero
|
||||
sigp %r1,%r0,SIGP_SET_ARCHITECTURE # switch to esa mode
|
||||
lpsw 0
|
||||
.Ldisab: sll %r14,1
|
||||
srl %r14,1 # need to kill hi bit to avoid specification exceptions.
|
||||
st %r14,.Ldispsw+12-.Lpg0(%r13)
|
||||
lpswe .Ldispsw-.Lpg0(%r13)
|
||||
.align 8
|
||||
.Lall: .quad 0x00000000ff000000
|
||||
.align 16
|
||||
/*
|
||||
* These addresses have to be 31 bit otherwise
|
||||
* the sigp will throw a specifcation exception
|
||||
* when switching to ESA mode as bit 31 be set
|
||||
* in the ESA psw.
|
||||
* Bit 31 of the addresses has to be 0 for the
|
||||
* 31bit lpswe instruction a fact they appear to have
|
||||
* omitted from the pop.
|
||||
*/
|
||||
.Lnewpsw: .quad 0x0000000080000000
|
||||
.quad .Lpg1
|
||||
.Lpcnew: .quad 0x0000000080000000
|
||||
.quad .Lecs
|
||||
.Lionew: .quad 0x0000000080000000
|
||||
.quad .Lcont
|
||||
.Lwaitpsw: .quad 0x0202000080000000
|
||||
.quad .Ltpi
|
||||
.Ldispsw: .quad 0x0002000080000000
|
||||
.quad 0x0000000000000000
|
||||
.Liplccws: .long 0x02000000,0x60000018
|
||||
.long 0x08000008,0x20000001
|
||||
.Liplorb: .long 0x0049504c,0x0040ff80
|
||||
.long 0x00000000+.Liplccws
|
||||
.Lschib: .long 0x00000000,0x00000000
|
||||
.long 0x00000000,0x00000000
|
||||
.long 0x00000000,0x00000000
|
||||
.long 0x00000000,0x00000000
|
||||
.long 0x00000000,0x00000000
|
||||
.long 0x00000000,0x00000000
|
||||
.Liplirb: .long 0x00000000,0x00000000
|
||||
.long 0x00000000,0x00000000
|
||||
.long 0x00000000,0x00000000
|
||||
.long 0x00000000,0x00000000
|
||||
.long 0x00000000,0x00000000
|
||||
.long 0x00000000,0x00000000
|
||||
.long 0x00000000,0x00000000
|
||||
.long 0x00000000,0x00000000
|
||||
|
@ -29,33 +29,6 @@
|
||||
ENTRY(relocate_kernel)
|
||||
basr %r13,0 # base address
|
||||
.base:
|
||||
stctg %c0,%c15,ctlregs-.base(%r13)
|
||||
stmg %r0,%r15,gprregs-.base(%r13)
|
||||
lghi %r0,3
|
||||
sllg %r0,%r0,31
|
||||
stg %r0,0x1d0(%r0)
|
||||
la %r0,.back_pgm-.base(%r13)
|
||||
stg %r0,0x1d8(%r0)
|
||||
la %r1,load_psw-.base(%r13)
|
||||
mvc 0(8,%r0),0(%r1)
|
||||
la %r0,.back-.base(%r13)
|
||||
st %r0,4(%r0)
|
||||
oi 4(%r0),0x80
|
||||
lghi %r0,0
|
||||
diag %r0,%r0,0x308
|
||||
.back:
|
||||
lhi %r1,1 # mode 1 = esame
|
||||
sigp %r1,%r0,SIGP_SET_ARCHITECTURE # switch to esame mode
|
||||
sam64 # switch to 64 bit addressing mode
|
||||
basr %r13,0
|
||||
.back_base:
|
||||
oi have_diag308-.back_base(%r13),0x01
|
||||
lctlg %c0,%c15,ctlregs-.back_base(%r13)
|
||||
lmg %r0,%r15,gprregs-.back_base(%r13)
|
||||
j .top
|
||||
.back_pgm:
|
||||
lmg %r0,%r15,gprregs-.base(%r13)
|
||||
.top:
|
||||
lghi %r7,PAGE_SIZE # load PAGE_SIZE in r7
|
||||
lghi %r9,PAGE_SIZE # load PAGE_SIZE in r9
|
||||
lg %r5,0(%r2) # read another word for indirection page
|
||||
@ -64,55 +37,36 @@ ENTRY(relocate_kernel)
|
||||
je .indir_check # NO, goto "indir_check"
|
||||
lgr %r6,%r5 # r6 = r5
|
||||
nill %r6,0xf000 # mask it out and...
|
||||
j .top # ...next iteration
|
||||
j .base # ...next iteration
|
||||
.indir_check:
|
||||
tml %r5,0x2 # is it a indirection page?
|
||||
je .done_test # NO, goto "done_test"
|
||||
nill %r5,0xf000 # YES, mask out,
|
||||
lgr %r2,%r5 # move it into the right register,
|
||||
j .top # and read next...
|
||||
j .base # and read next...
|
||||
.done_test:
|
||||
tml %r5,0x4 # is it the done indicator?
|
||||
je .source_test # NO! Well, then it should be the source indicator...
|
||||
j .done # ok, lets finish it here...
|
||||
.source_test:
|
||||
tml %r5,0x8 # it should be a source indicator...
|
||||
je .top # NO, ignore it...
|
||||
je .base # NO, ignore it...
|
||||
lgr %r8,%r5 # r8 = r5
|
||||
nill %r8,0xf000 # masking
|
||||
0: mvcle %r6,%r8,0x0 # copy PAGE_SIZE bytes from r8 to r6 - pad with 0
|
||||
jo 0b
|
||||
j .top
|
||||
j .base
|
||||
.done:
|
||||
sgr %r0,%r0 # clear register r0
|
||||
la %r4,load_psw-.base(%r13) # load psw-address into the register
|
||||
o %r3,4(%r4) # or load address into psw
|
||||
st %r3,4(%r4)
|
||||
mvc 0(8,%r0),0(%r4) # copy psw to absolute address 0
|
||||
tm have_diag308-.base(%r13),0x01
|
||||
jno .no_diag308
|
||||
diag %r0,%r0,0x308
|
||||
.no_diag308:
|
||||
sam31 # 31 bit mode
|
||||
sr %r1,%r1 # erase register r1
|
||||
sr %r2,%r2 # erase register r2
|
||||
sigp %r1,%r2,SIGP_SET_ARCHITECTURE # set cpuid to zero
|
||||
lpsw 0 # hopefully start new kernel...
|
||||
|
||||
.align 8
|
||||
load_psw:
|
||||
.long 0x00080000,0x80000000
|
||||
ctlregs:
|
||||
.rept 16
|
||||
.quad 0
|
||||
.endr
|
||||
gprregs:
|
||||
.rept 16
|
||||
.quad 0
|
||||
.endr
|
||||
have_diag308:
|
||||
.byte 0
|
||||
.align 8
|
||||
relocate_kernel_end:
|
||||
.align 8
|
||||
.globl relocate_kernel_len
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include <asm/irq.h>
|
||||
#include <asm/irq_regs.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/reset.h>
|
||||
#include <asm/ipl.h>
|
||||
#include <asm/chpid.h>
|
||||
#include <asm/airq.h>
|
||||
@ -767,229 +766,6 @@ void cio_register_early_subchannels(void)
|
||||
}
|
||||
#endif /* CONFIG_CCW_CONSOLE */
|
||||
|
||||
static int
|
||||
__disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
|
||||
{
|
||||
int retry, cc;
|
||||
|
||||
cc = 0;
|
||||
for (retry=0;retry<3;retry++) {
|
||||
schib->pmcw.ena = 0;
|
||||
cc = msch(schid, schib);
|
||||
if (cc)
|
||||
return (cc==3?-ENODEV:-EBUSY);
|
||||
if (stsch(schid, schib) || !css_sch_is_valid(schib))
|
||||
return -ENODEV;
|
||||
if (!schib->pmcw.ena)
|
||||
return 0;
|
||||
}
|
||||
return -EBUSY; /* uhm... */
|
||||
}
|
||||
|
||||
static int
|
||||
__clear_io_subchannel_easy(struct subchannel_id schid)
|
||||
{
|
||||
int retry;
|
||||
|
||||
if (csch(schid))
|
||||
return -ENODEV;
|
||||
for (retry=0;retry<20;retry++) {
|
||||
struct tpi_info ti;
|
||||
|
||||
if (tpi(&ti)) {
|
||||
tsch(ti.schid, this_cpu_ptr(&cio_irb));
|
||||
if (schid_equal(&ti.schid, &schid))
|
||||
return 0;
|
||||
}
|
||||
udelay_simple(100);
|
||||
}
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static void __clear_chsc_subchannel_easy(void)
|
||||
{
|
||||
/* It seems we can only wait for a bit here :/ */
|
||||
udelay_simple(100);
|
||||
}
|
||||
|
||||
static int pgm_check_occured;
|
||||
|
||||
static void cio_reset_pgm_check_handler(void)
|
||||
{
|
||||
pgm_check_occured = 1;
|
||||
}
|
||||
|
||||
static int stsch_reset(struct subchannel_id schid, struct schib *addr)
|
||||
{
|
||||
int rc;
|
||||
|
||||
pgm_check_occured = 0;
|
||||
s390_base_pgm_handler_fn = cio_reset_pgm_check_handler;
|
||||
rc = stsch(schid, addr);
|
||||
s390_base_pgm_handler_fn = NULL;
|
||||
|
||||
/* The program check handler could have changed pgm_check_occured. */
|
||||
barrier();
|
||||
|
||||
if (pgm_check_occured)
|
||||
return -EIO;
|
||||
else
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __shutdown_subchannel_easy(struct subchannel_id schid, void *data)
|
||||
{
|
||||
struct schib schib;
|
||||
|
||||
if (stsch_reset(schid, &schib))
|
||||
return -ENXIO;
|
||||
if (!schib.pmcw.ena)
|
||||
return 0;
|
||||
switch(__disable_subchannel_easy(schid, &schib)) {
|
||||
case 0:
|
||||
case -ENODEV:
|
||||
break;
|
||||
default: /* -EBUSY */
|
||||
switch (schib.pmcw.st) {
|
||||
case SUBCHANNEL_TYPE_IO:
|
||||
if (__clear_io_subchannel_easy(schid))
|
||||
goto out; /* give up... */
|
||||
break;
|
||||
case SUBCHANNEL_TYPE_CHSC:
|
||||
__clear_chsc_subchannel_easy();
|
||||
break;
|
||||
default:
|
||||
/* No default clear strategy */
|
||||
break;
|
||||
}
|
||||
stsch(schid, &schib);
|
||||
__disable_subchannel_easy(schid, &schib);
|
||||
}
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static atomic_t chpid_reset_count;
|
||||
|
||||
static void s390_reset_chpids_mcck_handler(void)
|
||||
{
|
||||
struct crw crw;
|
||||
union mci mci;
|
||||
|
||||
/* Check for pending channel report word. */
|
||||
mci.val = S390_lowcore.mcck_interruption_code;
|
||||
if (!mci.cp)
|
||||
return;
|
||||
/* Process channel report words. */
|
||||
while (stcrw(&crw) == 0) {
|
||||
/* Check for responses to RCHP. */
|
||||
if (crw.slct && crw.rsc == CRW_RSC_CPATH)
|
||||
atomic_dec(&chpid_reset_count);
|
||||
}
|
||||
}
|
||||
|
||||
#define RCHP_TIMEOUT (30 * USEC_PER_SEC)
|
||||
static void css_reset(void)
|
||||
{
|
||||
int i, ret;
|
||||
unsigned long long timeout;
|
||||
struct chp_id chpid;
|
||||
|
||||
/* Reset subchannels. */
|
||||
for_each_subchannel(__shutdown_subchannel_easy, NULL);
|
||||
/* Reset channel paths. */
|
||||
s390_base_mcck_handler_fn = s390_reset_chpids_mcck_handler;
|
||||
/* Enable channel report machine checks. */
|
||||
__ctl_set_bit(14, 28);
|
||||
/* Temporarily reenable machine checks. */
|
||||
local_mcck_enable();
|
||||
chp_id_init(&chpid);
|
||||
for (i = 0; i <= __MAX_CHPID; i++) {
|
||||
chpid.id = i;
|
||||
ret = rchp(chpid);
|
||||
if ((ret == 0) || (ret == 2))
|
||||
/*
|
||||
* rchp either succeeded, or another rchp is already
|
||||
* in progress. In either case, we'll get a crw.
|
||||
*/
|
||||
atomic_inc(&chpid_reset_count);
|
||||
}
|
||||
/* Wait for machine check for all channel paths. */
|
||||
timeout = get_tod_clock_fast() + (RCHP_TIMEOUT << 12);
|
||||
while (atomic_read(&chpid_reset_count) != 0) {
|
||||
if (get_tod_clock_fast() > timeout)
|
||||
break;
|
||||
cpu_relax();
|
||||
}
|
||||
/* Disable machine checks again. */
|
||||
local_mcck_disable();
|
||||
/* Disable channel report machine checks. */
|
||||
__ctl_clear_bit(14, 28);
|
||||
s390_base_mcck_handler_fn = NULL;
|
||||
}
|
||||
|
||||
static struct reset_call css_reset_call = {
|
||||
.fn = css_reset,
|
||||
};
|
||||
|
||||
static int __init init_css_reset_call(void)
|
||||
{
|
||||
atomic_set(&chpid_reset_count, 0);
|
||||
register_reset_call(&css_reset_call);
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(init_css_reset_call);
|
||||
|
||||
struct sch_match_id {
|
||||
struct subchannel_id schid;
|
||||
struct ccw_dev_id devid;
|
||||
int rc;
|
||||
};
|
||||
|
||||
static int __reipl_subchannel_match(struct subchannel_id schid, void *data)
|
||||
{
|
||||
struct schib schib;
|
||||
struct sch_match_id *match_id = data;
|
||||
|
||||
if (stsch_reset(schid, &schib))
|
||||
return -ENXIO;
|
||||
if ((schib.pmcw.st == SUBCHANNEL_TYPE_IO) && schib.pmcw.dnv &&
|
||||
(schib.pmcw.dev == match_id->devid.devno) &&
|
||||
(schid.ssid == match_id->devid.ssid)) {
|
||||
match_id->schid = schid;
|
||||
match_id->rc = 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reipl_find_schid(struct ccw_dev_id *devid,
|
||||
struct subchannel_id *schid)
|
||||
{
|
||||
struct sch_match_id match_id;
|
||||
|
||||
match_id.devid = *devid;
|
||||
match_id.rc = -ENODEV;
|
||||
for_each_subchannel(__reipl_subchannel_match, &match_id);
|
||||
if (match_id.rc == 0)
|
||||
*schid = match_id.schid;
|
||||
return match_id.rc;
|
||||
}
|
||||
|
||||
extern void do_reipl_asm(__u32 schid);
|
||||
|
||||
/* Make sure all subchannels are quiet before we re-ipl an lpar. */
|
||||
void reipl_ccw_dev(struct ccw_dev_id *devid)
|
||||
{
|
||||
struct subchannel_id uninitialized_var(schid);
|
||||
|
||||
s390_reset_system();
|
||||
if (reipl_find_schid(devid, &schid) != 0)
|
||||
panic("IPL Device not found\n");
|
||||
do_reipl_asm(*((__u32*)&schid));
|
||||
}
|
||||
|
||||
/**
|
||||
* cio_tm_start_key - perform start function
|
||||
* @sch: subchannel on which to perform the start function
|
||||
|
@ -183,30 +183,6 @@ int chsc(void *chsc_area)
|
||||
}
|
||||
EXPORT_SYMBOL(chsc);
|
||||
|
||||
static inline int __rchp(struct chp_id chpid)
|
||||
{
|
||||
register struct chp_id reg1 asm ("1") = chpid;
|
||||
int ccode;
|
||||
|
||||
asm volatile(
|
||||
" lr 1,%1\n"
|
||||
" rchp\n"
|
||||
" ipm %0\n"
|
||||
" srl %0,28"
|
||||
: "=d" (ccode) : "d" (reg1) : "cc");
|
||||
return ccode;
|
||||
}
|
||||
|
||||
int rchp(struct chp_id chpid)
|
||||
{
|
||||
int ccode;
|
||||
|
||||
ccode = __rchp(chpid);
|
||||
trace_s390_cio_rchp(chpid, ccode);
|
||||
|
||||
return ccode;
|
||||
}
|
||||
|
||||
static inline int __rsch(struct subchannel_id schid)
|
||||
{
|
||||
register struct subchannel_id reg1 asm("1") = schid;
|
||||
|
@ -20,7 +20,6 @@ int ssch(struct subchannel_id schid, union orb *addr);
|
||||
int csch(struct subchannel_id schid);
|
||||
int tpi(struct tpi_info *addr);
|
||||
int chsc(void *chsc_area);
|
||||
int rchp(struct chp_id chpid);
|
||||
int rsch(struct subchannel_id schid);
|
||||
int hsch(struct subchannel_id schid);
|
||||
int xsch(struct subchannel_id schid);
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <asm/reset.h>
|
||||
#include <asm/airq.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <asm/isc.h>
|
||||
@ -1197,25 +1196,6 @@ static void ap_config_timeout(struct timer_list *unused)
|
||||
queue_work(system_long_wq, &ap_scan_work);
|
||||
}
|
||||
|
||||
static void ap_reset_all(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < AP_DOMAINS; i++) {
|
||||
if (!ap_test_config_domain(i))
|
||||
continue;
|
||||
for (j = 0; j < AP_DEVICES; j++) {
|
||||
if (!ap_test_config_card_id(j))
|
||||
continue;
|
||||
ap_rapq(AP_MKQID(j, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct reset_call ap_reset_call = {
|
||||
.fn = ap_reset_all,
|
||||
};
|
||||
|
||||
int __init ap_debug_init(void)
|
||||
{
|
||||
ap_dbf_info = debug_register("ap", 1, 1,
|
||||
@ -1269,8 +1249,6 @@ int __init ap_module_init(void)
|
||||
ap_airq_flag = (rc == 0);
|
||||
}
|
||||
|
||||
register_reset_call(&ap_reset_call);
|
||||
|
||||
/* Create /sys/bus/ap. */
|
||||
rc = bus_register(&ap_bus_type);
|
||||
if (rc)
|
||||
@ -1326,7 +1304,6 @@ out_bus:
|
||||
bus_remove_file(&ap_bus_type, ap_bus_attrs[i]);
|
||||
bus_unregister(&ap_bus_type);
|
||||
out:
|
||||
unregister_reset_call(&ap_reset_call);
|
||||
if (ap_using_interrupts())
|
||||
unregister_adapter_interrupt(&ap_airq);
|
||||
kfree(ap_configuration);
|
||||
|
Loading…
Reference in New Issue
Block a user