Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+3 −4
Original line number Diff line number Diff line
@@ -10,9 +10,8 @@

/*
 * 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
@@ -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
 * return value: the size of the response. The caller can check if the buffer
 *		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 */
+4 −9
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include <linux/spinlock.h>
#include <linux/stddef.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <asm/diag.h>
#include <asm/ebcdic.h>
#include <asm/cpcmd.h>
@@ -28,9 +29,7 @@ static int diag8_noresponse(int cmdlen)
	register unsigned long reg3 asm ("3") = cmdlen;

	asm volatile(
		"	sam31\n"
		"	diag	%1,%0,0x8\n"
		"	sam64\n"
		: "+d" (reg3) : "d" (reg2) : "cc");
	return reg3;
}
@@ -43,9 +42,7 @@ static int diag8_response(int cmdlen, char *response, int *rlen)
	register unsigned long reg5 asm ("5") = *rlen;

	asm volatile(
		"	sam31\n"
		"	diag	%2,%0,0x8\n"
		"	sam64\n"
		"	brc	8,1f\n"
		"	agr	%1,%4\n"
		"1:\n"
@@ -57,7 +54,6 @@ static int diag8_response(int cmdlen, char *response, int *rlen)

/*
 * __cpcmd has some restrictions over cpcmd
 *  - the response buffer must reside below 2GB (if any)
 *  - __cpcmd is unlocked and therefore not SMP-safe
 */
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)
{
	unsigned long flags;
	char *lowbuf;
	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) {
			pr_warn("The cpcmd kernel function failed to allocate a response buffer\n");
			return -ENOMEM;
+1 −1
Original line number Diff line number Diff line
@@ -98,7 +98,7 @@ vmcp_write(struct file *file, const char __user *buff, size_t count,
	}
	if (!session->response)
		session->response = (char *)__get_free_pages(GFP_KERNEL
						| __GFP_RETRY_MAYFAIL | GFP_DMA,
						| __GFP_RETRY_MAYFAIL,
						get_order(session->bufsize));
	if (!session->response) {
		mutex_unlock(&session->mutex);