Commit 0b0d1173 authored by Claudio Imbrenda's avatar Claudio Imbrenda Committed by Martin Schwidefsky

s390/sclp: 32 bit event mask compatibility mode

Qemu before version 2.11 does not implement the architecture correctly,
and does not allow for a mask size of size different than 4.

This patch introduces a compatibility mode for such systems, forcing
the mask sizes to 4.

Since the mask size is currently still 4 anyway, this patch should have
no impact whatsoever by itself, but it will be needed when the mask size
is increased to 64 bits in the next patch.
Reviewed-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: default avatarClaudio Imbrenda <imbrenda@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent b8435635
...@@ -765,6 +765,9 @@ __sclp_make_init_req(sccb_mask_t receive_mask, sccb_mask_t send_mask) ...@@ -765,6 +765,9 @@ __sclp_make_init_req(sccb_mask_t receive_mask, sccb_mask_t send_mask)
sclp_init_req.callback_data = NULL; sclp_init_req.callback_data = NULL;
sclp_init_req.sccb = sccb; sclp_init_req.sccb = sccb;
sccb->header.length = sizeof(*sccb); sccb->header.length = sizeof(*sccb);
if (sclp_mask_compat_mode)
sccb->mask_length = SCLP_MASK_SIZE_COMPAT;
else
sccb->mask_length = sizeof(sccb_mask_t); sccb->mask_length = sizeof(sccb_mask_t);
sccb_set_recv_mask(sccb, receive_mask); sccb_set_recv_mask(sccb, receive_mask);
sccb_set_send_mask(sccb, send_mask); sccb_set_send_mask(sccb, send_mask);
...@@ -977,12 +980,18 @@ sclp_check_interface(void) ...@@ -977,12 +980,18 @@ sclp_check_interface(void)
irq_subclass_unregister(IRQ_SUBCLASS_SERVICE_SIGNAL); irq_subclass_unregister(IRQ_SUBCLASS_SERVICE_SIGNAL);
spin_lock_irqsave(&sclp_lock, flags); spin_lock_irqsave(&sclp_lock, flags);
del_timer(&sclp_request_timer); del_timer(&sclp_request_timer);
if (sclp_init_req.status == SCLP_REQ_DONE && rc = -EBUSY;
sccb->header.response_code == 0x20) { if (sclp_init_req.status == SCLP_REQ_DONE) {
if (sccb->header.response_code == 0x20) {
rc = 0; rc = 0;
break; break;
} else } else if (sccb->header.response_code == 0x74f0) {
rc = -EBUSY; if (!sclp_mask_compat_mode) {
sclp_mask_compat_mode = true;
retry = 0;
}
}
}
} }
unregister_external_irq(EXT_IRQ_SERVICE_SIG, sclp_check_handler); unregister_external_irq(EXT_IRQ_SERVICE_SIG, sclp_check_handler);
spin_unlock_irqrestore(&sclp_lock, flags); spin_unlock_irqrestore(&sclp_lock, flags);
......
...@@ -109,6 +109,8 @@ struct init_sccb { ...@@ -109,6 +109,8 @@ struct init_sccb {
*/ */
} __attribute__((packed)); } __attribute__((packed));
#define SCLP_MASK_SIZE_COMPAT 4
static inline sccb_mask_t sccb_get_mask(u8 *masks, size_t len, int i) static inline sccb_mask_t sccb_get_mask(u8 *masks, size_t len, int i)
{ {
sccb_mask_t res = 0; sccb_mask_t res = 0;
...@@ -262,6 +264,7 @@ extern int sclp_init_state; ...@@ -262,6 +264,7 @@ extern int sclp_init_state;
extern int sclp_console_pages; extern int sclp_console_pages;
extern int sclp_console_drop; extern int sclp_console_drop;
extern unsigned long sclp_console_full; extern unsigned long sclp_console_full;
extern bool sclp_mask_compat_mode;
extern char sclp_early_sccb[PAGE_SIZE]; extern char sclp_early_sccb[PAGE_SIZE];
......
...@@ -14,6 +14,11 @@ ...@@ -14,6 +14,11 @@
char sclp_early_sccb[PAGE_SIZE] __aligned(PAGE_SIZE) __section(.data); char sclp_early_sccb[PAGE_SIZE] __aligned(PAGE_SIZE) __section(.data);
int sclp_init_state __section(.data) = sclp_init_state_uninitialized; 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) void sclp_early_wait_irq(void)
{ {
...@@ -145,13 +150,21 @@ int sclp_early_set_event_mask(struct init_sccb *sccb, ...@@ -145,13 +150,21 @@ int sclp_early_set_event_mask(struct init_sccb *sccb,
sccb_mask_t receive_mask, sccb_mask_t receive_mask,
sccb_mask_t send_mask) sccb_mask_t send_mask)
{ {
retry:
memset(sccb, 0, sizeof(*sccb)); memset(sccb, 0, sizeof(*sccb));
sccb->header.length = sizeof(*sccb); sccb->header.length = sizeof(*sccb);
if (sclp_mask_compat_mode)
sccb->mask_length = SCLP_MASK_SIZE_COMPAT;
else
sccb->mask_length = sizeof(sccb_mask_t); sccb->mask_length = sizeof(sccb_mask_t);
sccb_set_recv_mask(sccb, receive_mask); sccb_set_recv_mask(sccb, receive_mask);
sccb_set_send_mask(sccb, send_mask); sccb_set_send_mask(sccb, send_mask);
if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_MASK, sccb)) if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_MASK, sccb))
return -EIO; 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) if (sccb->header.response_code != 0x20)
return -EIO; return -EIO;
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment