Commit cd4386a9 authored by Heiko Carstens's avatar Heiko Carstens Committed by Martin Schwidefsky

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: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 267239cc
...@@ -10,9 +10,8 @@ ...@@ -10,9 +10,8 @@
/* /*
* the lowlevel function for cpcmd * the lowlevel function for cpcmd
* the caller of __cpcmd has to ensure that the response buffer is below 2 GB
*/ */
extern int __cpcmd(const char *cmd, char *response, int rlen, int *response_code); int __cpcmd(const char *cmd, char *response, int rlen, int *response_code);
/* /*
* cpcmd is the in-kernel interface for issuing CP commands * 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,8 +24,8 @@ extern int __cpcmd(const char *cmd, char *response, int rlen, int *response_code
* response_code: return pointer for VM's error code * response_code: return pointer for VM's error code
* return value: the size of the response. The caller can check if the buffer * return value: the size of the response. The caller can check if the buffer
* was large enough by comparing the return value and rlen * was large enough by comparing the return value and rlen
* NOTE: If the response buffer is not below 2 GB, cpcmd can sleep * NOTE: If the response buffer is not in real storage, cpcmd can sleep
*/ */
extern int cpcmd(const char *cmd, char *response, int rlen, int *response_code); int cpcmd(const char *cmd, char *response, int rlen, int *response_code);
#endif /* _ASM_S390_CPCMD_H */ #endif /* _ASM_S390_CPCMD_H */
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/mm.h>
#include <asm/diag.h> #include <asm/diag.h>
#include <asm/ebcdic.h> #include <asm/ebcdic.h>
#include <asm/cpcmd.h> #include <asm/cpcmd.h>
...@@ -28,9 +29,7 @@ static int diag8_noresponse(int cmdlen) ...@@ -28,9 +29,7 @@ static int diag8_noresponse(int cmdlen)
register unsigned long reg3 asm ("3") = cmdlen; register unsigned long reg3 asm ("3") = cmdlen;
asm volatile( asm volatile(
" sam31\n"
" diag %1,%0,0x8\n" " diag %1,%0,0x8\n"
" sam64\n"
: "+d" (reg3) : "d" (reg2) : "cc"); : "+d" (reg3) : "d" (reg2) : "cc");
return reg3; return reg3;
} }
...@@ -43,9 +42,7 @@ static int diag8_response(int cmdlen, char *response, int *rlen) ...@@ -43,9 +42,7 @@ static int diag8_response(int cmdlen, char *response, int *rlen)
register unsigned long reg5 asm ("5") = *rlen; register unsigned long reg5 asm ("5") = *rlen;
asm volatile( asm volatile(
" sam31\n"
" diag %2,%0,0x8\n" " diag %2,%0,0x8\n"
" sam64\n"
" brc 8,1f\n" " brc 8,1f\n"
" agr %1,%4\n" " agr %1,%4\n"
"1:\n" "1:\n"
...@@ -57,7 +54,6 @@ static int diag8_response(int cmdlen, char *response, int *rlen) ...@@ -57,7 +54,6 @@ static int diag8_response(int cmdlen, char *response, int *rlen)
/* /*
* __cpcmd has some restrictions over cpcmd * __cpcmd has some restrictions over cpcmd
* - the response buffer must reside below 2GB (if any)
* - __cpcmd is unlocked and therefore not SMP-safe * - __cpcmd is unlocked and therefore not SMP-safe
*/ */
int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) int __cpcmd(const char *cmd, char *response, int rlen, int *response_code)
...@@ -88,13 +84,12 @@ EXPORT_SYMBOL(__cpcmd); ...@@ -88,13 +84,12 @@ EXPORT_SYMBOL(__cpcmd);
int cpcmd(const char *cmd, char *response, int rlen, int *response_code) int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
{ {
unsigned long flags;
char *lowbuf; char *lowbuf;
int len; int len;
unsigned long flags;
if ((virt_to_phys(response) != (unsigned long) response) || if (is_vmalloc_or_module_addr(response)) {
(((unsigned long)response + rlen) >> 31)) { lowbuf = kmalloc(rlen, GFP_KERNEL);
lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA);
if (!lowbuf) { if (!lowbuf) {
pr_warn("The cpcmd kernel function failed to allocate a response buffer\n"); pr_warn("The cpcmd kernel function failed to allocate a response buffer\n");
return -ENOMEM; return -ENOMEM;
......
...@@ -98,7 +98,7 @@ vmcp_write(struct file *file, const char __user *buff, size_t count, ...@@ -98,7 +98,7 @@ vmcp_write(struct file *file, const char __user *buff, size_t count,
} }
if (!session->response) if (!session->response)
session->response = (char *)__get_free_pages(GFP_KERNEL session->response = (char *)__get_free_pages(GFP_KERNEL
| __GFP_RETRY_MAYFAIL | GFP_DMA, | __GFP_RETRY_MAYFAIL,
get_order(session->bufsize)); get_order(session->bufsize));
if (!session->response) { if (!session->response) {
mutex_unlock(&session->mutex); mutex_unlock(&session->mutex);
......
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