summaryrefslogtreecommitdiff
path: root/drivers/s390/cio/chsc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/cio/chsc.c')
-rw-r--r--drivers/s390/cio/chsc.c29
1 files changed, 14 insertions, 15 deletions
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index 4038f5b4f144..ce7cb87479fe 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -29,6 +29,7 @@
#include "chsc.h"
static void *sei_page;
+static DEFINE_SPINLOCK(sda_lock);
/**
* chsc_error_from_response() - convert a chsc response to an error
@@ -832,11 +833,10 @@ void __init chsc_free_sei_area(void)
kfree(sei_page);
}
-int __init
-chsc_enable_facility(int operation_code)
+int chsc_enable_facility(int operation_code)
{
int ret;
- struct {
+ static struct {
struct chsc_header request;
u8 reserved1:4;
u8 format:4;
@@ -849,33 +849,32 @@ chsc_enable_facility(int operation_code)
u32 reserved5:4;
u32 format2:4;
u32 reserved6:24;
- } __attribute__ ((packed)) *sda_area;
+ } __attribute__ ((packed, aligned(4096))) sda_area;
- sda_area = (void *)get_zeroed_page(GFP_KERNEL|GFP_DMA);
- if (!sda_area)
- return -ENOMEM;
- sda_area->request.length = 0x0400;
- sda_area->request.code = 0x0031;
- sda_area->operation_code = operation_code;
+ spin_lock(&sda_lock);
+ memset(&sda_area, 0, sizeof(sda_area));
+ sda_area.request.length = 0x0400;
+ sda_area.request.code = 0x0031;
+ sda_area.operation_code = operation_code;
- ret = chsc(sda_area);
+ ret = chsc(&sda_area);
if (ret > 0) {
ret = (ret == 3) ? -ENODEV : -EBUSY;
goto out;
}
- switch (sda_area->response.code) {
+ switch (sda_area.response.code) {
case 0x0101:
ret = -EOPNOTSUPP;
break;
default:
- ret = chsc_error_from_response(sda_area->response.code);
+ ret = chsc_error_from_response(sda_area.response.code);
}
if (ret != 0)
CIO_CRW_EVENT(2, "chsc: sda (oc=%x) failed (rc=%04x)\n",
- operation_code, sda_area->response.code);
+ operation_code, sda_area.response.code);
out:
- free_page((unsigned long)sda_area);
+ spin_unlock(&sda_lock);
return ret;
}