summaryrefslogtreecommitdiffstats
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
commit3f4298427ad521fdc74fb991b17d84959513218a (patch)
treec4a9cff2e5ac1261c745b74dc3a70a644fd448bd
parentcd4386a931b6310b05559d2e28efda04d30ab593 (diff)
s390/vmcp: make use of contiguous memory allocator
If memory is fragmented it is unlikely that large order memory allocations succeed. This has been an issue with the vmcp device driver since a long time, since it requires large physical contiguous memory ares for large responses. To hopefully resolve this issue make use of the contiguous memory allocator (cma). This patch adds a vmcp specific vmcp cma area with a default size of 4MB. The size can be changed either via the VMCP_CMA_SIZE config option at compile time or with the "vmcp_cma" kernel parameter (e.g. "vmcp_cma=16m"). For any vmcp response buffers larger than 16k memory from the cma area will be allocated. If such an allocation fails, there is a fallback to the buddy allocator. Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--Documentation/admin-guide/kernel-parameters.txt4
-rw-r--r--arch/s390/include/asm/setup.h6
-rw-r--r--arch/s390/kernel/setup.c1
-rw-r--r--drivers/s390/char/Kconfig11
-rw-r--r--drivers/s390/char/vmcp.c74
-rw-r--r--drivers/s390/char/vmcp.h3
6 files changed, 90 insertions, 9 deletions
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index d9c171ce4190..5a2d5079139b 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -4375,6 +4375,10 @@
4375 decrease the size and leave more room for directly 4375 decrease the size and leave more room for directly
4376 mapped kernel RAM. 4376 mapped kernel RAM.
4377 4377
4378 vmcp_cma=nn[MG] [KNL,S390]
4379 Sets the memory size reserved for contiguous memory
4380 allocations for the vmcp device driver.
4381
4378 vmhalt= [KNL,S390] Perform z/VM CP command after system halt. 4382 vmhalt= [KNL,S390] Perform z/VM CP command after system halt.
4379 Format: <command> 4383 Format: <command>
4380 4384
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h
index 61da4bd6edad..490e035b3716 100644
--- a/arch/s390/include/asm/setup.h
+++ b/arch/s390/include/asm/setup.h
@@ -108,6 +108,12 @@ extern void pfault_fini(void);
108#define pfault_fini() do { } while (0) 108#define pfault_fini() do { } while (0)
109#endif /* CONFIG_PFAULT */ 109#endif /* CONFIG_PFAULT */
110 110
111#ifdef CONFIG_VMCP
112void vmcp_cma_reserve(void);
113#else
114static inline void vmcp_cma_reserve(void) { }
115#endif
116
111void report_user_fault(struct pt_regs *regs, long signr, int is_mm_fault); 117void report_user_fault(struct pt_regs *regs, long signr, int is_mm_fault);
112 118
113void cmma_init(void); 119void cmma_init(void);
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index a50238e17867..164a1e16b53e 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -925,6 +925,7 @@ void __init setup_arch(char **cmdline_p)
925 setup_memory_end(); 925 setup_memory_end();
926 setup_memory(); 926 setup_memory();
927 dma_contiguous_reserve(memory_end); 927 dma_contiguous_reserve(memory_end);
928 vmcp_cma_reserve();
928 929
929 check_initrd(); 930 check_initrd();
930 reserve_crashkernel(); 931 reserve_crashkernel();
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig
index b3f1c458905f..97c4c9fdd53d 100644
--- a/drivers/s390/char/Kconfig
+++ b/drivers/s390/char/Kconfig
@@ -169,10 +169,21 @@ config VMCP
169 def_bool y 169 def_bool y
170 prompt "Support for the z/VM CP interface" 170 prompt "Support for the z/VM CP interface"
171 depends on S390 171 depends on S390
172 select CMA
172 help 173 help
173 Select this option if you want to be able to interact with the control 174 Select this option if you want to be able to interact with the control
174 program on z/VM 175 program on z/VM
175 176
177config VMCP_CMA_SIZE
178 int "Memory in MiB reserved for z/VM CP interface"
179 default "4"
180 depends on VMCP
181 help
182 Specify the default amount of memory in MiB reserved for the z/VM CP
183 interface. If needed this memory is used for large contiguous memory
184 allocations. The default can be changed with the kernel command line
185 parameter "vmcp_cma".
186
176config MONREADER 187config MONREADER
177 def_tristate m 188 def_tristate m
178 prompt "API for reading z/VM monitor service records" 189 prompt "API for reading z/VM monitor service records"
diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c
index b5e3a49745f9..c202b407698f 100644
--- a/drivers/s390/char/vmcp.c
+++ b/drivers/s390/char/vmcp.c
@@ -17,15 +17,77 @@
17#include <linux/kernel.h> 17#include <linux/kernel.h>
18#include <linux/miscdevice.h> 18#include <linux/miscdevice.h>
19#include <linux/slab.h> 19#include <linux/slab.h>
20#include <linux/uaccess.h>
20#include <linux/export.h> 21#include <linux/export.h>
22#include <linux/mutex.h>
23#include <linux/cma.h>
24#include <linux/mm.h>
21#include <asm/compat.h> 25#include <asm/compat.h>
22#include <asm/cpcmd.h> 26#include <asm/cpcmd.h>
23#include <asm/debug.h> 27#include <asm/debug.h>
24#include <linux/uaccess.h>
25#include "vmcp.h" 28#include "vmcp.h"
26 29
27static debug_info_t *vmcp_debug; 30static debug_info_t *vmcp_debug;
28 31
32static unsigned long vmcp_cma_size __initdata = CONFIG_VMCP_CMA_SIZE * 1024 * 1024;
33static struct cma *vmcp_cma;
34
35static int __init early_parse_vmcp_cma(char *p)
36{
37 vmcp_cma_size = ALIGN(memparse(p, NULL), PAGE_SIZE);
38 return 0;
39}
40early_param("vmcp_cma", early_parse_vmcp_cma);
41
42void __init vmcp_cma_reserve(void)
43{
44 if (!MACHINE_IS_VM)
45 return;
46 cma_declare_contiguous(0, vmcp_cma_size, 0, 0, 0, false, "vmcp", &vmcp_cma);
47}
48
49static void vmcp_response_alloc(struct vmcp_session *session)
50{
51 struct page *page = NULL;
52 int nr_pages, order;
53
54 order = get_order(session->bufsize);
55 nr_pages = ALIGN(session->bufsize, PAGE_SIZE) >> PAGE_SHIFT;
56 /*
57 * For anything below order 3 allocations rely on the buddy
58 * allocator. If such low-order allocations can't be handled
59 * anymore the system won't work anyway.
60 */
61 if (order > 2)
62 page = cma_alloc(vmcp_cma, nr_pages, 0, GFP_KERNEL);
63 if (page) {
64 session->response = (char *)page_to_phys(page);
65 session->cma_alloc = 1;
66 return;
67 }
68 session->response = (char *)__get_free_pages(GFP_KERNEL | __GFP_RETRY_MAYFAIL, order);
69}
70
71static void vmcp_response_free(struct vmcp_session *session)
72{
73 int nr_pages, order;
74 struct page *page;
75
76 if (!session->response)
77 return;
78 order = get_order(session->bufsize);
79 nr_pages = ALIGN(session->bufsize, PAGE_SIZE) >> PAGE_SHIFT;
80 if (session->cma_alloc) {
81 page = phys_to_page((unsigned long)session->response);
82 cma_release(vmcp_cma, page, nr_pages);
83 session->cma_alloc = 0;
84 goto out;
85 }
86 free_pages((unsigned long)session->response, order);
87out:
88 session->response = NULL;
89}
90
29static int vmcp_open(struct inode *inode, struct file *file) 91static int vmcp_open(struct inode *inode, struct file *file)
30{ 92{
31 struct vmcp_session *session; 93 struct vmcp_session *session;
@@ -51,7 +113,7 @@ static int vmcp_release(struct inode *inode, struct file *file)
51 113
52 session = file->private_data; 114 session = file->private_data;
53 file->private_data = NULL; 115 file->private_data = NULL;
54 free_pages((unsigned long)session->response, get_order(session->bufsize)); 116 vmcp_response_free(session);
55 kfree(session); 117 kfree(session);
56 return 0; 118 return 0;
57} 119}
@@ -97,9 +159,7 @@ vmcp_write(struct file *file, const char __user *buff, size_t count,
97 return -ERESTARTSYS; 159 return -ERESTARTSYS;
98 } 160 }
99 if (!session->response) 161 if (!session->response)
100 session->response = (char *)__get_free_pages(GFP_KERNEL 162 vmcp_response_alloc(session);
101 | __GFP_RETRY_MAYFAIL,
102 get_order(session->bufsize));
103 if (!session->response) { 163 if (!session->response) {
104 mutex_unlock(&session->mutex); 164 mutex_unlock(&session->mutex);
105 kfree(cmd); 165 kfree(cmd);
@@ -146,9 +206,7 @@ static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
146 mutex_unlock(&session->mutex); 206 mutex_unlock(&session->mutex);
147 return put_user(temp, argp); 207 return put_user(temp, argp);
148 case VMCP_SETBUF: 208 case VMCP_SETBUF:
149 free_pages((unsigned long)session->response, 209 vmcp_response_free(session);
150 get_order(session->bufsize));
151 session->response=NULL;
152 temp = get_user(session->bufsize, argp); 210 temp = get_user(session->bufsize, argp);
153 if (temp) 211 if (temp)
154 session->bufsize = PAGE_SIZE; 212 session->bufsize = PAGE_SIZE;
diff --git a/drivers/s390/char/vmcp.h b/drivers/s390/char/vmcp.h
index 1e29b0418382..4e725edf449f 100644
--- a/drivers/s390/char/vmcp.h
+++ b/drivers/s390/char/vmcp.h
@@ -20,8 +20,9 @@
20#define VMCP_GETSIZE _IOR(0x10, 3, int) 20#define VMCP_GETSIZE _IOR(0x10, 3, int)
21 21
22struct vmcp_session { 22struct vmcp_session {
23 unsigned int bufsize;
24 char *response; 23 char *response;
24 unsigned int bufsize;
25 unsigned int cma_alloc : 1;
25 int resp_size; 26 int resp_size;
26 int resp_code; 27 int resp_code;
27 /* As we use copy_from/to_user, which might * 28 /* As we use copy_from/to_user, which might *