diff options
Diffstat (limited to 'drivers/s390/char/sclp_early_core.c')
| -rw-r--r-- | drivers/s390/char/sclp_early_core.c | 68 |
1 files changed, 53 insertions, 15 deletions
diff --git a/drivers/s390/char/sclp_early_core.c b/drivers/s390/char/sclp_early_core.c index 676634de65a8..55e50d428aab 100644 --- a/drivers/s390/char/sclp_early_core.c +++ b/drivers/s390/char/sclp_early_core.c @@ -7,17 +7,19 @@ #include <linux/kernel.h> #include <asm/processor.h> #include <asm/lowcore.h> +#include <asm/ctlreg.h> #include <asm/ebcdic.h> #include <asm/irq.h> #include <asm/sections.h> -#include <asm/mem_detect.h> +#include <asm/physmem_info.h> #include <asm/facility.h> +#include <asm/machine.h> #include "sclp.h" #include "sclp_rw.h" static struct read_info_sccb __bootdata(sclp_info_sccb); static int __bootdata(sclp_info_sccb_valid); -char *__bootdata(sclp_early_sccb); +char *__bootdata_preserved(sclp_early_sccb); int sclp_init_state = sclp_init_state_uninitialized; /* * Used to keep track of the size of the event masks. Qemu until version 2.11 @@ -31,17 +33,17 @@ void sclp_early_wait_irq(void) psw_t psw_ext_save, psw_wait; union ctlreg0 cr0, cr0_new; - __ctl_store(cr0.val, 0, 0); + local_ctl_store(0, &cr0.reg); cr0_new.val = cr0.val & ~CR0_IRQ_SUBCLASS_MASK; cr0_new.lap = 0; cr0_new.sssm = 1; - __ctl_load(cr0_new.val, 0, 0); + local_ctl_load(0, &cr0_new.reg); - psw_ext_save = S390_lowcore.external_new_psw; + psw_ext_save = get_lowcore()->external_new_psw; psw_mask = __extract_psw(); - S390_lowcore.external_new_psw.mask = psw_mask; + get_lowcore()->external_new_psw.mask = psw_mask; psw_wait.mask = psw_mask | PSW_MASK_EXT | PSW_MASK_WAIT; - S390_lowcore.ext_int_code = 0; + get_lowcore()->ext_int_code = 0; do { asm volatile( @@ -49,16 +51,16 @@ void sclp_early_wait_irq(void) " stg %[addr],%[psw_wait_addr]\n" " stg %[addr],%[psw_ext_addr]\n" " lpswe %[psw_wait]\n" - "0:\n" + "0:" : [addr] "=&d" (addr), [psw_wait_addr] "=Q" (psw_wait.addr), - [psw_ext_addr] "=Q" (S390_lowcore.external_new_psw.addr) + [psw_ext_addr] "=Q" (get_lowcore()->external_new_psw.addr) : [psw_wait] "Q" (psw_wait) : "cc", "memory"); - } while (S390_lowcore.ext_int_code != EXT_IRQ_SERVICE_SIG); + } while (get_lowcore()->ext_int_code != EXT_IRQ_SERVICE_SIG); - S390_lowcore.external_new_psw = psw_ext_save; - __ctl_load(cr0.val, 0, 0); + get_lowcore()->external_new_psw = psw_ext_save; + local_ctl_load(0, &cr0.reg); } int sclp_early_cmd(sclp_cmdw_t cmd, void *sccb) @@ -241,6 +243,30 @@ void sclp_early_printk(const char *str) } /* + * Use sclp_emergency_printk() to print a string when the system is in a + * state where regular console drivers cannot be assumed to work anymore. + * + * Callers must make sure that no concurrent SCLP requests are outstanding + * and all other CPUs are stopped, or at least disabled for external + * interrupts. + */ +void sclp_emergency_printk(const char *str) +{ + int have_linemode, have_vt220; + unsigned int len; + + len = strlen(str); + /* + * Don't care about return values; if requests fail, just ignore and + * continue to have a rather high chance that anything is printed. + */ + sclp_early_setup(0, &have_linemode, &have_vt220); + sclp_early_print_lm(str, len); + sclp_early_print_vt220(str, len); + sclp_early_setup(1, &have_linemode, &have_vt220); +} + +/* * We can't pass sclp_info_sccb to sclp_early_cmd() here directly, * because it might not fulfil the requiremets for a SCLP communication buffer: * - lie below 2G in memory @@ -310,9 +336,21 @@ int __init sclp_early_get_hsa_size(unsigned long *hsa_size) return 0; } +void __init sclp_early_detect_machine_features(void) +{ + struct read_info_sccb *sccb = &sclp_info_sccb; + + if (!sclp_info_sccb_valid) + return; + if (sccb->fac85 & 0x02) + set_machine_feature(MFEATURE_ESOP); + if (sccb->fac91 & 0x40) + set_machine_feature(MFEATURE_TLB_GUEST); +} + #define SCLP_STORAGE_INFO_FACILITY 0x0000400000000000UL -void __weak __init add_mem_detect_block(u64 start, u64 end) {} +void __weak __init add_physmem_online_range(u64 start, u64 end) {} int __init sclp_early_read_storage_info(void) { struct read_storage_sccb *sccb = (struct read_storage_sccb *)sclp_early_sccb; @@ -345,7 +383,7 @@ int __init sclp_early_read_storage_info(void) if (!sccb->entries[sn]) continue; rn = sccb->entries[sn] >> 16; - add_mem_detect_block((rn - 1) * rzm, rn * rzm); + add_physmem_online_range((rn - 1) * rzm, rn * rzm); } break; case 0x0310: @@ -358,6 +396,6 @@ int __init sclp_early_read_storage_info(void) return 0; fail: - mem_detect.count = 0; + physmem_info.range_count = 0; return -EIO; } |
