diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2017-08-07 09:16:15 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2017-08-09 09:09:35 -0400 |
commit | cd4386a931b6310b05559d2e28efda04d30ab593 (patch) | |
tree | d1fbc2a6a8e86af9308ce8713e842e6717471c8e | |
parent | 267239cc10f18251892a0783104df3dc22b620d5 (diff) |
s390/cpcmd,vmcp: avoid GFP_DMA allocations
According to the CP Programming Services manual Diagnose Code 8
"Virtual Console Function" can be used in all addressing modes. Also
the input and output buffers do not have a limitation which specifies
they need to be below the 2GB line.
This is true at least since z/VM 5.4.
Therefore remove the sam31/64 instructions and allow for simple
GFP_KERNEL allocations. This makes it easier to allocate a 1MB page
if the user requested such a large return buffer.
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | arch/s390/include/asm/cpcmd.h | 7 | ||||
-rw-r--r-- | arch/s390/kernel/cpcmd.c | 13 | ||||
-rw-r--r-- | drivers/s390/char/vmcp.c | 2 |
3 files changed, 8 insertions, 14 deletions
diff --git a/arch/s390/include/asm/cpcmd.h b/arch/s390/include/asm/cpcmd.h index 3dfadb5d648f..ca2b0624ad46 100644 --- a/arch/s390/include/asm/cpcmd.h +++ b/arch/s390/include/asm/cpcmd.h | |||
@@ -10,9 +10,8 @@ | |||
10 | 10 | ||
11 | /* | 11 | /* |
12 | * the lowlevel function for cpcmd | 12 | * the lowlevel function for cpcmd |
13 | * the caller of __cpcmd has to ensure that the response buffer is below 2 GB | ||
14 | */ | 13 | */ |
15 | extern int __cpcmd(const char *cmd, char *response, int rlen, int *response_code); | 14 | int __cpcmd(const char *cmd, char *response, int rlen, int *response_code); |
16 | 15 | ||
17 | /* | 16 | /* |
18 | * cpcmd is the in-kernel interface for issuing CP commands | 17 | * cpcmd is the in-kernel interface for issuing CP commands |
@@ -25,8 +24,8 @@ extern int __cpcmd(const char *cmd, char *response, int rlen, int *response_code | |||
25 | * response_code: return pointer for VM's error code | 24 | * response_code: return pointer for VM's error code |
26 | * return value: the size of the response. The caller can check if the buffer | 25 | * return value: the size of the response. The caller can check if the buffer |
27 | * was large enough by comparing the return value and rlen | 26 | * was large enough by comparing the return value and rlen |
28 | * NOTE: If the response buffer is not below 2 GB, cpcmd can sleep | 27 | * NOTE: If the response buffer is not in real storage, cpcmd can sleep |
29 | */ | 28 | */ |
30 | extern int cpcmd(const char *cmd, char *response, int rlen, int *response_code); | 29 | int cpcmd(const char *cmd, char *response, int rlen, int *response_code); |
31 | 30 | ||
32 | #endif /* _ASM_S390_CPCMD_H */ | 31 | #endif /* _ASM_S390_CPCMD_H */ |
diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c index 9f0e4a2785f7..63bc6603e0ed 100644 --- a/arch/s390/kernel/cpcmd.c +++ b/arch/s390/kernel/cpcmd.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/spinlock.h> | 14 | #include <linux/spinlock.h> |
15 | #include <linux/stddef.h> | 15 | #include <linux/stddef.h> |
16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
17 | #include <linux/mm.h> | ||
17 | #include <asm/diag.h> | 18 | #include <asm/diag.h> |
18 | #include <asm/ebcdic.h> | 19 | #include <asm/ebcdic.h> |
19 | #include <asm/cpcmd.h> | 20 | #include <asm/cpcmd.h> |
@@ -28,9 +29,7 @@ static int diag8_noresponse(int cmdlen) | |||
28 | register unsigned long reg3 asm ("3") = cmdlen; | 29 | register unsigned long reg3 asm ("3") = cmdlen; |
29 | 30 | ||
30 | asm volatile( | 31 | asm volatile( |
31 | " sam31\n" | ||
32 | " diag %1,%0,0x8\n" | 32 | " diag %1,%0,0x8\n" |
33 | " sam64\n" | ||
34 | : "+d" (reg3) : "d" (reg2) : "cc"); | 33 | : "+d" (reg3) : "d" (reg2) : "cc"); |
35 | return reg3; | 34 | return reg3; |
36 | } | 35 | } |
@@ -43,9 +42,7 @@ static int diag8_response(int cmdlen, char *response, int *rlen) | |||
43 | register unsigned long reg5 asm ("5") = *rlen; | 42 | register unsigned long reg5 asm ("5") = *rlen; |
44 | 43 | ||
45 | asm volatile( | 44 | asm volatile( |
46 | " sam31\n" | ||
47 | " diag %2,%0,0x8\n" | 45 | " diag %2,%0,0x8\n" |
48 | " sam64\n" | ||
49 | " brc 8,1f\n" | 46 | " brc 8,1f\n" |
50 | " agr %1,%4\n" | 47 | " agr %1,%4\n" |
51 | "1:\n" | 48 | "1:\n" |
@@ -57,7 +54,6 @@ static int diag8_response(int cmdlen, char *response, int *rlen) | |||
57 | 54 | ||
58 | /* | 55 | /* |
59 | * __cpcmd has some restrictions over cpcmd | 56 | * __cpcmd has some restrictions over cpcmd |
60 | * - the response buffer must reside below 2GB (if any) | ||
61 | * - __cpcmd is unlocked and therefore not SMP-safe | 57 | * - __cpcmd is unlocked and therefore not SMP-safe |
62 | */ | 58 | */ |
63 | int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) | 59 | int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) |
@@ -88,13 +84,12 @@ EXPORT_SYMBOL(__cpcmd); | |||
88 | 84 | ||
89 | int cpcmd(const char *cmd, char *response, int rlen, int *response_code) | 85 | int cpcmd(const char *cmd, char *response, int rlen, int *response_code) |
90 | { | 86 | { |
87 | unsigned long flags; | ||
91 | char *lowbuf; | 88 | char *lowbuf; |
92 | int len; | 89 | int len; |
93 | unsigned long flags; | ||
94 | 90 | ||
95 | if ((virt_to_phys(response) != (unsigned long) response) || | 91 | if (is_vmalloc_or_module_addr(response)) { |
96 | (((unsigned long)response + rlen) >> 31)) { | 92 | lowbuf = kmalloc(rlen, GFP_KERNEL); |
97 | lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA); | ||
98 | if (!lowbuf) { | 93 | if (!lowbuf) { |
99 | pr_warn("The cpcmd kernel function failed to allocate a response buffer\n"); | 94 | pr_warn("The cpcmd kernel function failed to allocate a response buffer\n"); |
100 | return -ENOMEM; | 95 | return -ENOMEM; |
diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 66d5e9f83e0d..b5e3a49745f9 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c | |||
@@ -98,7 +98,7 @@ vmcp_write(struct file *file, const char __user *buff, size_t count, | |||
98 | } | 98 | } |
99 | if (!session->response) | 99 | if (!session->response) |
100 | session->response = (char *)__get_free_pages(GFP_KERNEL | 100 | session->response = (char *)__get_free_pages(GFP_KERNEL |
101 | | __GFP_RETRY_MAYFAIL | GFP_DMA, | 101 | | __GFP_RETRY_MAYFAIL, |
102 | get_order(session->bufsize)); | 102 | get_order(session->bufsize)); |
103 | if (!session->response) { | 103 | if (!session->response) { |
104 | mutex_unlock(&session->mutex); | 104 | mutex_unlock(&session->mutex); |