Browse Source

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>
Heiko Carstens 8 years ago
parent
commit
cd4386a931
3 changed files with 8 additions and 14 deletions
  1. 3 4
      arch/s390/include/asm/cpcmd.h
  2. 4 9
      arch/s390/kernel/cpcmd.c
  3. 1 1
      drivers/s390/char/vmcp.c

+ 3 - 4
arch/s390/include/asm/cpcmd.h

@@ -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
  * 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 */

+ 4 - 9
arch/s390/kernel/cpcmd.c

@@ -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)
 	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)
 	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)
 
 
 /*
 /*
  * __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);
 
 
 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) ||
-			(((unsigned long)response + rlen) >> 31)) {
-		lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA);
+	if (is_vmalloc_or_module_addr(response)) {
+		lowbuf = kmalloc(rlen, GFP_KERNEL);
 		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;

+ 1 - 1
drivers/s390/char/vmcp.c

@@ -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);