Commit 5266d3d1 authored by Sebastian Ott's avatar Sebastian Ott Committed by Greg Kroah-Hartman

s390/cio: fix accidental interrupt enabling during resume

commit d53c51f2 upstream.

Since commit 9f3d6d7a chsc_get_channel_measurement_chars is called with
interrupts disabled during resume from hibernate. Since this function
used spin_unlock_irq, interrupts have been enabled accidentally. Fix
this by using the irqsave variant.

Since we can't guarantee the IRQ-enablement state for all (future/
external) callers, change the locking in related functions to prevent
similar bugs in the future.

Fixes: 9f3d6d7a ("s390/cio: update measurement characteristics")
Signed-off-by: default avatarSebastian Ott <sebott@linux.vnet.ibm.com>
Reviewed-by: default avatarPeter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent fcf5e519
...@@ -95,12 +95,13 @@ struct chsc_ssd_area { ...@@ -95,12 +95,13 @@ struct chsc_ssd_area {
int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd) int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
{ {
struct chsc_ssd_area *ssd_area; struct chsc_ssd_area *ssd_area;
unsigned long flags;
int ccode; int ccode;
int ret; int ret;
int i; int i;
int mask; int mask;
spin_lock_irq(&chsc_page_lock); spin_lock_irqsave(&chsc_page_lock, flags);
memset(chsc_page, 0, PAGE_SIZE); memset(chsc_page, 0, PAGE_SIZE);
ssd_area = chsc_page; ssd_area = chsc_page;
ssd_area->request.length = 0x0010; ssd_area->request.length = 0x0010;
...@@ -144,7 +145,7 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd) ...@@ -144,7 +145,7 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
ssd->fla[i] = ssd_area->fla[i]; ssd->fla[i] = ssd_area->fla[i];
} }
out: out:
spin_unlock_irq(&chsc_page_lock); spin_unlock_irqrestore(&chsc_page_lock, flags);
return ret; return ret;
} }
...@@ -832,9 +833,10 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable) ...@@ -832,9 +833,10 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable)
u32 fmt : 4; u32 fmt : 4;
u32 : 16; u32 : 16;
} __attribute__ ((packed)) *secm_area; } __attribute__ ((packed)) *secm_area;
unsigned long flags;
int ret, ccode; int ret, ccode;
spin_lock_irq(&chsc_page_lock); spin_lock_irqsave(&chsc_page_lock, flags);
memset(chsc_page, 0, PAGE_SIZE); memset(chsc_page, 0, PAGE_SIZE);
secm_area = chsc_page; secm_area = chsc_page;
secm_area->request.length = 0x0050; secm_area->request.length = 0x0050;
...@@ -864,7 +866,7 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable) ...@@ -864,7 +866,7 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable)
CIO_CRW_EVENT(2, "chsc: secm failed (rc=%04x)\n", CIO_CRW_EVENT(2, "chsc: secm failed (rc=%04x)\n",
secm_area->response.code); secm_area->response.code);
out: out:
spin_unlock_irq(&chsc_page_lock); spin_unlock_irqrestore(&chsc_page_lock, flags);
return ret; return ret;
} }
...@@ -993,6 +995,7 @@ chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv, ...@@ -993,6 +995,7 @@ chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv,
int chsc_get_channel_measurement_chars(struct channel_path *chp) int chsc_get_channel_measurement_chars(struct channel_path *chp)
{ {
unsigned long flags;
int ccode, ret; int ccode, ret;
struct { struct {
...@@ -1022,7 +1025,7 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp) ...@@ -1022,7 +1025,7 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
if (!css_chsc_characteristics.scmc || !css_chsc_characteristics.secm) if (!css_chsc_characteristics.scmc || !css_chsc_characteristics.secm)
return 0; return 0;
spin_lock_irq(&chsc_page_lock); spin_lock_irqsave(&chsc_page_lock, flags);
memset(chsc_page, 0, PAGE_SIZE); memset(chsc_page, 0, PAGE_SIZE);
scmc_area = chsc_page; scmc_area = chsc_page;
scmc_area->request.length = 0x0010; scmc_area->request.length = 0x0010;
...@@ -1054,7 +1057,7 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp) ...@@ -1054,7 +1057,7 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
chsc_initialize_cmg_chars(chp, scmc_area->cmcv, chsc_initialize_cmg_chars(chp, scmc_area->cmcv,
(struct cmg_chars *) &scmc_area->data); (struct cmg_chars *) &scmc_area->data);
out: out:
spin_unlock_irq(&chsc_page_lock); spin_unlock_irqrestore(&chsc_page_lock, flags);
return ret; return ret;
} }
...@@ -1135,6 +1138,7 @@ struct css_chsc_char css_chsc_characteristics; ...@@ -1135,6 +1138,7 @@ struct css_chsc_char css_chsc_characteristics;
int __init int __init
chsc_determine_css_characteristics(void) chsc_determine_css_characteristics(void)
{ {
unsigned long flags;
int result; int result;
struct { struct {
struct chsc_header request; struct chsc_header request;
...@@ -1147,7 +1151,7 @@ chsc_determine_css_characteristics(void) ...@@ -1147,7 +1151,7 @@ chsc_determine_css_characteristics(void)
u32 chsc_char[508]; u32 chsc_char[508];
} __attribute__ ((packed)) *scsc_area; } __attribute__ ((packed)) *scsc_area;
spin_lock_irq(&chsc_page_lock); spin_lock_irqsave(&chsc_page_lock, flags);
memset(chsc_page, 0, PAGE_SIZE); memset(chsc_page, 0, PAGE_SIZE);
scsc_area = chsc_page; scsc_area = chsc_page;
scsc_area->request.length = 0x0010; scsc_area->request.length = 0x0010;
...@@ -1169,7 +1173,7 @@ chsc_determine_css_characteristics(void) ...@@ -1169,7 +1173,7 @@ chsc_determine_css_characteristics(void)
CIO_CRW_EVENT(2, "chsc: scsc failed (rc=%04x)\n", CIO_CRW_EVENT(2, "chsc: scsc failed (rc=%04x)\n",
scsc_area->response.code); scsc_area->response.code);
exit: exit:
spin_unlock_irq(&chsc_page_lock); spin_unlock_irqrestore(&chsc_page_lock, flags);
return result; return result;
} }
......
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