xref: /openbsd/sys/arch/sparc64/sparc64/mdesc.c (revision 9bec9e43)
1 /*	$OpenBSD: mdesc.c,v 1.9 2023/04/10 04:21:20 jsg Exp $	*/
2 /*
3  * Copyright (c) 2009 Mark Kettenis
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/device.h>
20 #include <sys/malloc.h>
21 #include <sys/systm.h>
22 
23 #include <uvm/uvm_extern.h>
24 
25 #include <machine/autoconf.h>
26 #include <machine/hypervisor.h>
27 #include <machine/mdesc.h>
28 #include <machine/sparc64.h>
29 
30 #define HSVC_GROUP_PARALLEL_BOOT	0x105
31 
32 caddr_t mdesc;
33 paddr_t mdesc_pa;
34 size_t mdesc_len;
35 
36 caddr_t pri;
37 paddr_t pri_pa;
38 size_t pri_len;
39 
40 void pri_init(void);
41 
42 void
mdesc_init(void)43 mdesc_init(void)
44 {
45 	struct pglist mlist;
46 	struct vm_page *m;
47 	psize_t len = 0, size;
48 	paddr_t pa;
49 	vaddr_t va;
50 	int err;
51 
52 	err = hv_mach_desc((paddr_t)NULL, &len);
53 	KASSERT(err == H_EINVAL);
54 	KASSERT(len != 0);
55 
56 again:
57 	size = round_page(len);
58 
59 	TAILQ_INIT(&mlist);
60 	err = uvm_pglistalloc(len, 0, -1, PAGE_SIZE, 0, &mlist, 1,
61 	    UVM_PLA_NOWAIT);
62 	if (err)
63 		panic("%s: out of memory", __func__);
64 
65 	len = size;
66 	pa = VM_PAGE_TO_PHYS(TAILQ_FIRST(&mlist));
67 	err = hv_mach_desc(pa, &len);
68 	if (err != H_EOK)
69 		goto fail;
70 
71 	va = (vaddr_t)km_alloc(size, &kv_any, &kp_none, &kd_nowait);
72 	if (va == 0)
73 		panic("%s: out of memory", __func__);
74 
75 	mdesc = (caddr_t)va;
76 	mdesc_pa = pa;
77 	mdesc_len = len;
78 
79 	m = TAILQ_FIRST(&mlist);
80 	for (; m != NULL; m = TAILQ_NEXT(m,pageq)) {
81 		pa = VM_PAGE_TO_PHYS(m);
82 		pmap_enter(pmap_kernel(), va, pa,
83 		    PROT_READ | PROT_WRITE,
84 		    PROT_READ | PROT_WRITE | PMAP_WIRED);
85 		va += PAGE_SIZE;
86 	}
87 	pmap_update(pmap_kernel());
88 
89 	pri_init();
90 	return;
91 
92 fail:
93 	uvm_pglistfree(&mlist);
94 
95 	/*
96 	 * If the machine description was updated while we were trying
97 	 * to fetch it, the allocated buffer may have been too small.
98 	 * Try again in that case.
99 	 */
100 	if (err == H_EINVAL && len > size)
101 		goto again;
102 
103 	return;
104 }
105 
106 void
pri_init(void)107 pri_init(void)
108 {
109 	struct pglist mlist;
110 	struct vm_page *m;
111 	uint64_t minor;
112 	psize_t len = 0, size;
113 	paddr_t pa;
114 	vaddr_t va;
115 	int err;
116 
117 	/*
118 	 * We can only fetch the physical resource inventory this way
119 	 * if the firmware supports parallel boot.
120 	 */
121 	if (prom_set_sun4v_api_version(HSVC_GROUP_PARALLEL_BOOT, 1, 0, &minor))
122 		return;
123 
124 	err = hv_mach_pri((paddr_t)NULL, &len);
125 	if (err != H_EINVAL)
126 		return;
127 
128 again:
129 	size = round_page(len);
130 
131 	TAILQ_INIT(&mlist);
132 	err = uvm_pglistalloc(len, 0, -1, PAGE_SIZE, 0, &mlist, 1,
133 	    UVM_PLA_NOWAIT);
134 	if (err)
135 		panic("%s: out of memory", __func__);
136 
137 	len = size;
138 	pa = VM_PAGE_TO_PHYS(TAILQ_FIRST(&mlist));
139 	err = hv_mach_pri(pa, &len);
140 	if (err != H_EOK)
141 		goto fail;
142 
143 	va = (vaddr_t)km_alloc(size, &kv_any, &kp_none, &kd_nowait);
144 	if (va == 0)
145 		panic("%s: out of memory", __func__);
146 
147 	pri = (caddr_t)va;
148 	pri_pa = pa;
149 	pri_len = len;
150 
151 	m = TAILQ_FIRST(&mlist);
152 	for (; m != NULL; m = TAILQ_NEXT(m,pageq)) {
153 		pa = VM_PAGE_TO_PHYS(m);
154 		pmap_enter(pmap_kernel(), va, pa,
155 		    PROT_READ | PROT_WRITE,
156 		    PROT_READ | PROT_WRITE | PMAP_WIRED);
157 		va += PAGE_SIZE;
158 	}
159 	pmap_update(pmap_kernel());
160 
161 	return;
162 
163 fail:
164 	uvm_pglistfree(&mlist);
165 
166 	/*
167 	 * If the physical resource inventory was updated while we
168 	 * were trying to fetch it, the allocated buffer may have been
169 	 * too small.  Try again in that case.
170 	 */
171 	if (err == H_EINVAL && len > size)
172 		goto again;
173 
174 	return;
175 }
176 
177 uint64_t
mdesc_get_prop_val(int idx,const char * name)178 mdesc_get_prop_val(int idx, const char *name)
179 {
180 	struct md_header *hdr;
181 	struct md_element *elem;
182 	const char *name_blk;
183 	const char *str;
184 
185 	hdr = (struct md_header *)mdesc;
186 	elem = (struct md_element *)(mdesc + sizeof(struct md_header));
187 	name_blk = mdesc + sizeof(struct md_header) + hdr->node_blk_sz;
188 
189 	while (elem[idx].tag != 'E') {
190 		str = name_blk + elem[idx].name_offset;
191 		if (elem[idx].tag == 'v' && strcmp(str, name) == 0)
192 			return (elem[idx].d.val);
193 		idx++;
194 	}
195 
196 	return (-1);
197 }
198 
199 const char *
mdesc_get_prop_str(int idx,const char * name)200 mdesc_get_prop_str(int idx, const char *name)
201 {
202 	struct md_header *hdr;
203 	struct md_element *elem;
204 	const char *name_blk;
205 	const char *data_blk;
206 	const char *str;
207 
208 	hdr = (struct md_header *)mdesc;
209 	elem = (struct md_element *)(mdesc + sizeof(struct md_header));
210 	name_blk = mdesc + sizeof(struct md_header) + hdr->node_blk_sz;
211 	data_blk = name_blk + hdr->name_blk_sz;
212 
213 	while (elem[idx].tag != 'E') {
214 		str = name_blk + elem[idx].name_offset;
215 		if (elem[idx].tag == 's' && strcmp(str, name) == 0)
216 			return (data_blk + elem[idx].d.y.data_offset);
217 		idx++;
218 	}
219 
220 	return (NULL);
221 }
222 
223 const char *
mdesc_get_prop_data(int idx,const char * name,size_t * len)224 mdesc_get_prop_data(int idx, const char *name, size_t *len)
225 {
226 	struct md_header *hdr;
227 	struct md_element *elem;
228 	const char *name_blk;
229 	const char *data_blk;
230 	const char *str;
231 
232 	hdr = (struct md_header *)mdesc;
233 	elem = (struct md_element *)(mdesc + sizeof(struct md_header));
234 	name_blk = mdesc + sizeof(struct md_header) + hdr->node_blk_sz;
235 	data_blk = name_blk + hdr->name_blk_sz;
236 
237 	while (elem[idx].tag != 'E') {
238 		str = name_blk + elem[idx].name_offset;
239 		if (elem[idx].tag == 'd' && strcmp(str, name) == 0) {
240 			*len = elem[idx].d.y.data_len;
241 			return (data_blk + elem[idx].d.y.data_offset);
242 		}
243 		idx++;
244 	}
245 
246 	return (NULL);
247 }
248 
249 int
mdesc_find(const char * name,uint64_t cfg_handle)250 mdesc_find(const char *name, uint64_t cfg_handle)
251 {
252 	struct md_header *hdr;
253 	struct md_element *elem;
254 	const char *str;
255 	uint64_t val;
256 	int idx;
257 
258 	hdr = (struct md_header *)mdesc;
259 	elem = (struct md_element *)(mdesc + sizeof(struct md_header));
260 
261 	for (idx = 0; elem[idx].tag == 'N'; idx = elem[idx].d.val) {
262 		str = mdesc_get_prop_str(idx, "name");
263 		val = mdesc_get_prop_val(idx, "cfg-handle");
264 		if (str && strcmp(str, name) == 0 && val == cfg_handle)
265 			return (idx);
266 	}
267 
268 	return (-1);
269 }
270 
271 int
mdesc_find_child(int idx,const char * name,uint64_t cfg_handle)272 mdesc_find_child(int idx, const char *name, uint64_t cfg_handle)
273 {
274 	struct md_header *hdr;
275 	struct md_element *elem;
276 	const char *name_blk;
277 	const char *str;
278 	uint64_t val;
279 	int arc;
280 
281 	hdr = (struct md_header *)mdesc;
282 	elem = (struct md_element *)(mdesc + sizeof(struct md_header));
283 	name_blk = mdesc + sizeof(struct md_header) + hdr->node_blk_sz;
284 
285 	for (; elem[idx].tag != 'E'; idx++) {
286 		str = name_blk + elem[idx].name_offset;
287 		if (elem[idx].tag != 'a' || strcmp(str, "fwd") != 0)
288 			continue;
289 
290 		arc = elem[idx].d.val;
291 		str = mdesc_get_prop_str(arc, "name");
292 		val = mdesc_get_prop_val(arc, "cfg-handle");
293 		if (str && strcmp(str, name) == 0 && val == cfg_handle)
294 			return (arc);
295 	}
296 
297 	return (-1);
298 }
299 
300 int
mdesc_find_node(const char * name)301 mdesc_find_node(const char *name)
302 {
303 	struct md_header *hdr;
304 	struct md_element *elem;
305 	const char *name_blk;
306 	const char *str;
307 	int idx;
308 
309 	hdr = (struct md_header *)mdesc;
310 	elem = (struct md_element *)(mdesc + sizeof(struct md_header));
311 	name_blk = mdesc + sizeof(struct md_header) + hdr->node_blk_sz;
312 
313 	for (idx = 0; elem[idx].tag == 'N'; idx = elem[idx].d.val) {
314 		str = name_blk + elem[idx].name_offset;
315 		if (str && strcmp(str, name) == 0)
316 			return (idx);
317 	}
318 
319 	return (-1);
320 }
321