xref: /linux/arch/s390/kernel/diag/diag310.c (revision f96a974170b749e3a56844e25b31d46a7233b6f6)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Request memory topology information via diag0x310.
4  *
5  * Copyright IBM Corp. 2025
6  */
7 
8 #include <linux/kernel.h>
9 #include <linux/types.h>
10 #include <linux/uaccess.h>
11 #include <linux/vmalloc.h>
12 #include <asm/diag.h>
13 #include <asm/sclp.h>
14 #include <uapi/asm/diag.h>
15 #include "diag_ioctl.h"
16 
17 #define DIAG310_LEVELMIN 1
18 #define DIAG310_LEVELMAX 6
19 
20 enum diag310_sc {
21 	DIAG310_SUBC_0 = 0,
22 	DIAG310_SUBC_1 = 1,
23 	DIAG310_SUBC_4 = 4,
24 	DIAG310_SUBC_5 = 5
25 };
26 
27 enum diag310_retcode {
28 	DIAG310_RET_SUCCESS	= 0x0001,
29 	DIAG310_RET_BUSY	= 0x0101,
30 	DIAG310_RET_OPNOTSUPP	= 0x0102,
31 	DIAG310_RET_SC4_INVAL	= 0x0401,
32 	DIAG310_RET_SC4_NODATA	= 0x0402,
33 	DIAG310_RET_SC5_INVAL	= 0x0501,
34 	DIAG310_RET_SC5_NODATA	= 0x0502,
35 	DIAG310_RET_SC5_ESIZE	= 0x0503
36 };
37 
38 union diag310_response {
39 	u64 response;
40 	struct {
41 		u64 result	: 32;
42 		u64		: 16;
43 		u64 rc		: 16;
44 	};
45 };
46 
47 union diag310_req_subcode {
48 	u64 subcode;
49 	struct {
50 		u64		: 48;
51 		u64 st		: 8;
52 		u64 sc		: 8;
53 	};
54 };
55 
56 union diag310_req_size {
57 	u64 size;
58 	struct {
59 		u64 page_count	: 32;
60 		u64		: 32;
61 	};
62 };
63 
64 static inline unsigned long diag310(unsigned long subcode, unsigned long size, void *addr)
65 {
66 	union register_pair rp = { .even = (unsigned long)addr, .odd = size };
67 
68 	diag_stat_inc(DIAG_STAT_X310);
69 	asm volatile("diag	%[rp],%[subcode],0x310\n"
70 		     : [rp] "+d" (rp.pair)
71 		     : [subcode] "d" (subcode)
72 		     : "memory");
73 	return rp.odd;
74 }
75 
76 static int diag310_result_to_errno(unsigned int result)
77 {
78 	switch (result) {
79 	case DIAG310_RET_BUSY:
80 		return -EBUSY;
81 	case DIAG310_RET_OPNOTSUPP:
82 		return -EOPNOTSUPP;
83 	default:
84 		return -EINVAL;
85 	}
86 }
87 
88 static int diag310_get_subcode_mask(unsigned long *mask)
89 {
90 	union diag310_response res;
91 
92 	res.response = diag310(DIAG310_SUBC_0, 0, NULL);
93 	if (res.rc != DIAG310_RET_SUCCESS)
94 		return diag310_result_to_errno(res.rc);
95 	*mask = res.response;
96 	return 0;
97 }
98 
99 static int diag310_get_memtop_stride(unsigned long *stride)
100 {
101 	union diag310_response res;
102 
103 	res.response = diag310(DIAG310_SUBC_1, 0, NULL);
104 	if (res.rc != DIAG310_RET_SUCCESS)
105 		return diag310_result_to_errno(res.rc);
106 	*stride = res.result;
107 	return 0;
108 }
109 
110 static int diag310_get_memtop_size(unsigned long *pages, unsigned long level)
111 {
112 	union diag310_req_subcode req = { .sc = DIAG310_SUBC_4, .st = level };
113 	union diag310_response res;
114 
115 	res.response = diag310(req.subcode, 0, NULL);
116 	switch (res.rc) {
117 	case DIAG310_RET_SUCCESS:
118 		*pages = res.result;
119 		return 0;
120 	case DIAG310_RET_SC4_NODATA:
121 		return -ENODATA;
122 	case DIAG310_RET_SC4_INVAL:
123 		return -EINVAL;
124 	default:
125 		return diag310_result_to_errno(res.rc);
126 	}
127 }
128 
129 static int diag310_store_topology_map(void *buf, unsigned long pages, unsigned long level)
130 {
131 	union diag310_req_subcode req_sc = { .sc = DIAG310_SUBC_5, .st = level };
132 	union diag310_req_size req_size = { .page_count = pages };
133 	union diag310_response res;
134 
135 	res.response = diag310(req_sc.subcode, req_size.size, buf);
136 	switch (res.rc) {
137 	case DIAG310_RET_SUCCESS:
138 		return 0;
139 	case DIAG310_RET_SC5_NODATA:
140 		return -ENODATA;
141 	case DIAG310_RET_SC5_ESIZE:
142 		return -EOVERFLOW;
143 	case DIAG310_RET_SC5_INVAL:
144 		return -EINVAL;
145 	default:
146 		return diag310_result_to_errno(res.rc);
147 	}
148 }
149 
150 static int diag310_check_features(void)
151 {
152 	static int features_available;
153 	unsigned long mask;
154 	int rc;
155 
156 	if (READ_ONCE(features_available))
157 		return 0;
158 	if (!sclp.has_diag310)
159 		return -EOPNOTSUPP;
160 	rc = diag310_get_subcode_mask(&mask);
161 	if (rc)
162 		return rc;
163 	if (!test_bit_inv(DIAG310_SUBC_1, &mask))
164 		return -EOPNOTSUPP;
165 	if (!test_bit_inv(DIAG310_SUBC_4, &mask))
166 		return -EOPNOTSUPP;
167 	if (!test_bit_inv(DIAG310_SUBC_5, &mask))
168 		return -EOPNOTSUPP;
169 	WRITE_ONCE(features_available, 1);
170 	return 0;
171 }
172 
173 static int memtop_get_stride_len(unsigned long *res)
174 {
175 	static unsigned long memtop_stride;
176 	unsigned long stride;
177 	int rc;
178 
179 	stride = READ_ONCE(memtop_stride);
180 	if (!stride) {
181 		rc = diag310_get_memtop_stride(&stride);
182 		if (rc)
183 			return rc;
184 		WRITE_ONCE(memtop_stride, stride);
185 	}
186 	*res = stride;
187 	return 0;
188 }
189 
190 static int memtop_get_page_count(unsigned long *res, unsigned long level)
191 {
192 	static unsigned long memtop_pages[DIAG310_LEVELMAX];
193 	unsigned long pages;
194 	int rc;
195 
196 	if (level > DIAG310_LEVELMAX || level < DIAG310_LEVELMIN)
197 		return -EINVAL;
198 	pages = READ_ONCE(memtop_pages[level - 1]);
199 	if (!pages) {
200 		rc = diag310_get_memtop_size(&pages, level);
201 		if (rc)
202 			return rc;
203 		WRITE_ONCE(memtop_pages[level - 1], pages);
204 	}
205 	*res = pages;
206 	return 0;
207 }
208 
209 long diag310_memtop_stride(unsigned long arg)
210 {
211 	size_t __user *argp = (void __user *)arg;
212 	unsigned long stride;
213 	int rc;
214 
215 	rc = diag310_check_features();
216 	if (rc)
217 		return rc;
218 	rc = memtop_get_stride_len(&stride);
219 	if (rc)
220 		return rc;
221 	if (put_user(stride, argp))
222 		return -EFAULT;
223 	return 0;
224 }
225 
226 long diag310_memtop_len(unsigned long arg)
227 {
228 	size_t __user *argp = (void __user *)arg;
229 	unsigned long pages, level;
230 	int rc;
231 
232 	rc = diag310_check_features();
233 	if (rc)
234 		return rc;
235 	if (get_user(level, argp))
236 		return -EFAULT;
237 	rc = memtop_get_page_count(&pages, level);
238 	if (rc)
239 		return rc;
240 	if (put_user(pages * PAGE_SIZE, argp))
241 		return -EFAULT;
242 	return 0;
243 }
244 
245 long diag310_memtop_buf(unsigned long arg)
246 {
247 	struct diag310_memtop __user *udata = (struct diag310_memtop __user *)arg;
248 	unsigned long level, pages, data_size;
249 	u64 address;
250 	void *buf;
251 	int rc;
252 
253 	rc = diag310_check_features();
254 	if (rc)
255 		return rc;
256 	if (get_user(level, &udata->nesting_lvl))
257 		return -EFAULT;
258 	if (get_user(address, &udata->address))
259 		return -EFAULT;
260 	rc = memtop_get_page_count(&pages, level);
261 	if (rc)
262 		return rc;
263 	data_size = pages * PAGE_SIZE;
264 	buf = __vmalloc_node(data_size, PAGE_SIZE, GFP_KERNEL | __GFP_ZERO | __GFP_ACCOUNT,
265 			     NUMA_NO_NODE, __builtin_return_address(0));
266 	if (!buf)
267 		return -ENOMEM;
268 	rc = diag310_store_topology_map(buf, pages, level);
269 	if (rc)
270 		goto out;
271 	if (copy_to_user((void __user *)address, buf, data_size))
272 		rc = -EFAULT;
273 out:
274 	vfree(buf);
275 	return rc;
276 }
277