aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2017-08-07 09:16:15 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2017-08-09 09:09:35 -0400
commitcd4386a931b6310b05559d2e28efda04d30ab593 (patch)
treed1fbc2a6a8e86af9308ce8713e842e6717471c8e
parent267239cc10f18251892a0783104df3dc22b620d5 (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.h7
-rw-r--r--arch/s390/kernel/cpcmd.c13
-rw-r--r--drivers/s390/char/vmcp.c2
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 */
15extern int __cpcmd(const char *cmd, char *response, int rlen, int *response_code); 14int __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 */
30extern int cpcmd(const char *cmd, char *response, int rlen, int *response_code); 29int 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 */
63int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) 59int __cpcmd(const char *cmd, char *response, int rlen, int *response_code)
@@ -88,13 +84,12 @@ EXPORT_SYMBOL(__cpcmd);
88 84
89int cpcmd(const char *cmd, char *response, int rlen, int *response_code) 85int 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);