Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Heiko Carstens and committed by
Martin Schwidefsky
cd4386a9 267239cc

+8 -14
+3 -4
arch/s390/include/asm/cpcmd.h
··· 10 10 11 11 /* 12 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 17 * cpcmd is the in-kernel interface for issuing CP commands ··· 24 25 * response_code: return pointer for VM's error code 25 26 * return value: the size of the response. The caller can check if the buffer 26 27 * was large enough by comparing the return value and rlen 27 - * NOTE: If the response buffer is not below 2 GB, cpcmd can sleep 28 + * NOTE: If the response buffer is not in real storage, cpcmd can sleep 28 29 */ 29 - extern int cpcmd(const char *cmd, char *response, int rlen, int *response_code); 30 + int cpcmd(const char *cmd, char *response, int rlen, int *response_code); 30 31 31 32 #endif /* _ASM_S390_CPCMD_H */
+4 -9
arch/s390/kernel/cpcmd.c
··· 14 14 #include <linux/spinlock.h> 15 15 #include <linux/stddef.h> 16 16 #include <linux/string.h> 17 + #include <linux/mm.h> 17 18 #include <asm/diag.h> 18 19 #include <asm/ebcdic.h> 19 20 #include <asm/cpcmd.h> ··· 29 28 register unsigned long reg3 asm ("3") = cmdlen; 30 29 31 30 asm volatile( 32 - " sam31\n" 33 31 " diag %1,%0,0x8\n" 34 - " sam64\n" 35 32 : "+d" (reg3) : "d" (reg2) : "cc"); 36 33 return reg3; 37 34 } ··· 42 43 register unsigned long reg5 asm ("5") = *rlen; 43 44 44 45 asm volatile( 45 - " sam31\n" 46 46 " diag %2,%0,0x8\n" 47 - " sam64\n" 48 47 " brc 8,1f\n" 49 48 " agr %1,%4\n" 50 49 "1:\n" ··· 54 57 55 58 /* 56 59 * __cpcmd has some restrictions over cpcmd 57 - * - the response buffer must reside below 2GB (if any) 58 60 * - __cpcmd is unlocked and therefore not SMP-safe 59 61 */ 60 62 int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) ··· 84 88 85 89 int cpcmd(const char *cmd, char *response, int rlen, int *response_code) 86 90 { 91 + unsigned long flags; 87 92 char *lowbuf; 88 93 int len; 89 - unsigned long flags; 90 94 91 - if ((virt_to_phys(response) != (unsigned long) response) || 92 - (((unsigned long)response + rlen) >> 31)) { 93 - lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA); 95 + if (is_vmalloc_or_module_addr(response)) { 96 + lowbuf = kmalloc(rlen, GFP_KERNEL); 94 97 if (!lowbuf) { 95 98 pr_warn("The cpcmd kernel function failed to allocate a response buffer\n"); 96 99 return -ENOMEM;
+1 -1
drivers/s390/char/vmcp.c
··· 98 98 } 99 99 if (!session->response) 100 100 session->response = (char *)__get_free_pages(GFP_KERNEL 101 - | __GFP_RETRY_MAYFAIL | GFP_DMA, 101 + | __GFP_RETRY_MAYFAIL, 102 102 get_order(session->bufsize)); 103 103 if (!session->response) { 104 104 mutex_unlock(&session->mutex);