diff options
Diffstat (limited to 'drivers/s390/char/sclp_early_core.c')
-rw-r--r-- | drivers/s390/char/sclp_early_core.c | 38 |
1 files changed, 30 insertions, 8 deletions
diff --git a/drivers/s390/char/sclp_early_core.c b/drivers/s390/char/sclp_early_core.c index 17b0c67f3e8d..5f8d9ea69ebd 100644 --- a/drivers/s390/char/sclp_early_core.c +++ b/drivers/s390/char/sclp_early_core.c @@ -14,6 +14,11 @@ char sclp_early_sccb[PAGE_SIZE] __aligned(PAGE_SIZE) __section(.data); int sclp_init_state __section(.data) = sclp_init_state_uninitialized; +/* + * Used to keep track of the size of the event masks. Qemu until version 2.11 + * only supports 4 and needs a workaround. + */ +bool sclp_mask_compat_mode; void sclp_early_wait_irq(void) { @@ -142,16 +147,24 @@ static void sclp_early_print_vt220(const char *str, unsigned int len) } int sclp_early_set_event_mask(struct init_sccb *sccb, - unsigned long receive_mask, - unsigned long send_mask) + sccb_mask_t receive_mask, + sccb_mask_t send_mask) { +retry: memset(sccb, 0, sizeof(*sccb)); sccb->header.length = sizeof(*sccb); - sccb->mask_length = sizeof(sccb_mask_t); - sccb->receive_mask = receive_mask; - sccb->send_mask = send_mask; + if (sclp_mask_compat_mode) + sccb->mask_length = SCLP_MASK_SIZE_COMPAT; + else + sccb->mask_length = sizeof(sccb_mask_t); + sccb_set_recv_mask(sccb, receive_mask); + sccb_set_send_mask(sccb, send_mask); if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_MASK, sccb)) return -EIO; + if ((sccb->header.response_code == 0x74f0) && !sclp_mask_compat_mode) { + sclp_mask_compat_mode = true; + goto retry; + } if (sccb->header.response_code != 0x20) return -EIO; return 0; @@ -159,19 +172,28 @@ int sclp_early_set_event_mask(struct init_sccb *sccb, unsigned int sclp_early_con_check_linemode(struct init_sccb *sccb) { - if (!(sccb->sclp_send_mask & EVTYP_OPCMD_MASK)) + if (!(sccb_get_sclp_send_mask(sccb) & EVTYP_OPCMD_MASK)) return 0; - if (!(sccb->sclp_receive_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK))) + if (!(sccb_get_sclp_recv_mask(sccb) & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK))) return 0; return 1; } +unsigned int sclp_early_con_check_vt220(struct init_sccb *sccb) +{ + if (sccb_get_sclp_send_mask(sccb) & EVTYP_VT220MSG_MASK) + return 1; + return 0; +} + static int sclp_early_setup(int disable, int *have_linemode, int *have_vt220) { unsigned long receive_mask, send_mask; struct init_sccb *sccb; int rc; + BUILD_BUG_ON(sizeof(struct init_sccb) > PAGE_SIZE); + *have_linemode = *have_vt220 = 0; sccb = (struct init_sccb *) &sclp_early_sccb; receive_mask = disable ? 0 : EVTYP_OPCMD_MASK; @@ -180,7 +202,7 @@ static int sclp_early_setup(int disable, int *have_linemode, int *have_vt220) if (rc) return rc; *have_linemode = sclp_early_con_check_linemode(sccb); - *have_vt220 = sccb->send_mask & EVTYP_VT220MSG_MASK; + *have_vt220 = !!(sccb_get_send_mask(sccb) & EVTYP_VT220MSG_MASK); return rc; } |