1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2024 Oxide Computer Company
14  */
15 
16 /*
17  * This file is focused upon building up the tree of information that we need to
18  * build the module's various topology nodes as well as any methods that need to
19  * operate on them.
20  */
21 
22 #include <sys/fm/protocol.h>
23 #include <fm/topo_hc.h>
24 #include <sys/devfm.h>
25 #include <assert.h>
26 
27 #include "topo_zen_impl.h"
28 
29 static const topo_pgroup_info_t topo_zen_chip_pgroup = {
30 	TOPO_PGROUP_CHIP,
31 	TOPO_STABILITY_PRIVATE,
32 	TOPO_STABILITY_PRIVATE,
33 	1
34 };
35 
36 static const topo_pgroup_info_t topo_zen_ccd_pgroup = {
37 	TOPO_PGROUP_CCD,
38 	TOPO_STABILITY_PRIVATE,
39 	TOPO_STABILITY_PRIVATE,
40 	1
41 };
42 
43 static const topo_pgroup_info_t topo_zen_ccx_pgroup = {
44 	TOPO_PGROUP_CCX,
45 	TOPO_STABILITY_PRIVATE,
46 	TOPO_STABILITY_PRIVATE,
47 	1
48 };
49 
50 static const topo_pgroup_info_t topo_zen_core_pgroup = {
51 	TOPO_PGROUP_CORE,
52 	TOPO_STABILITY_PRIVATE,
53 	TOPO_STABILITY_PRIVATE,
54 	1
55 };
56 
57 static const topo_pgroup_info_t topo_zen_strand_pgroup = {
58 	TOPO_PGROUP_STRAND,
59 	TOPO_STABILITY_PRIVATE,
60 	TOPO_STABILITY_PRIVATE,
61 	1
62 };
63 
64 static const topo_pgroup_info_t topo_zen_cache_pgroup = {
65 	TOPO_PGROUP_CACHE,
66 	TOPO_STABILITY_PRIVATE,
67 	TOPO_STABILITY_PRIVATE,
68 	1
69 };
70 
71 /*
72  * Common interface to create a topo node in our socket and bind it to its
73  * parent. The following properties are commonly shared between all nodes in the
74  * chip:
75  *
76  * o The serial and revision are part of the FMRI. We don't have a good way to
77  *   get the orderable OPN for this. The brand string doesn't feel appropriate
78  *   for this use case.
79  * o The FRU is always set to the top-level chip.
80  * o We do not set the ASRU given that it will vary from device to device.
81  */
82 static tnode_t *
topo_zen_create_tn(topo_mod_t * mod,zen_topo_enum_sock_t * sock,tnode_t * pnode,topo_instance_t inst,const char * name)83 topo_zen_create_tn(topo_mod_t *mod, zen_topo_enum_sock_t *sock, tnode_t *pnode,
84     topo_instance_t inst, const char *name)
85 {
86 	int ret, err;
87 	tnode_t *tn = NULL;
88 	nvlist_t *fmri = NULL, *auth = NULL;
89 
90 	auth = topo_mod_auth(mod, pnode);
91 	if (auth == NULL) {
92 		topo_mod_dprintf(mod, "failed to get auth for %s[%" PRIu64 "]: "
93 		    "%s", name, inst, topo_mod_errmsg(mod));
94 		return (NULL);
95 	}
96 
97 	fmri = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION, name, inst,
98 	    NULL, auth, NULL, sock->ztes_cpu_rev, sock->ztes_cpu_serial);
99 	if (fmri == NULL) {
100 		topo_mod_dprintf(mod, "failed to create FMRI for %s[%" PRIu64
101 		    "]: %s", name, inst, topo_mod_errmsg(mod));
102 		nvlist_free(auth);
103 		return (NULL);
104 	}
105 
106 	tn = topo_node_bind(mod, pnode, name, inst, fmri);
107 	nvlist_free(auth);
108 	if (tn == NULL) {
109 		topo_mod_dprintf(mod, "failed to bind node %s[%" PRIu64 "]: %s",
110 		    name, inst, topo_mod_errmsg(mod));
111 		nvlist_free(fmri);
112 		return (NULL);
113 	}
114 
115 	if (sock->ztes_tn == NULL) {
116 		ret = topo_node_fru_set(tn, fmri, 0, &err);
117 	} else {
118 		ret = topo_node_fru_set(tn, NULL, 0, &err);
119 	}
120 	nvlist_free(fmri);
121 
122 	if (ret != 0) {
123 		topo_mod_dprintf(mod, "failed to set FRU for %s[%" PRIu64 "]: "
124 		    "%s", name, inst, topo_strerror(err));
125 		(void) topo_mod_seterrno(mod, err);
126 		topo_node_unbind(tn);
127 		return (NULL);
128 	}
129 
130 	return (tn);
131 }
132 
133 static tnode_t *
topo_zen_build_cache(topo_mod_t * mod,zen_topo_enum_sock_t * sock,tnode_t * pnode,topo_instance_t inst,nvlist_t * nvl)134 topo_zen_build_cache(topo_mod_t *mod, zen_topo_enum_sock_t *sock,
135     tnode_t *pnode, topo_instance_t inst, nvlist_t *nvl)
136 {
137 	int err;
138 	uint32_t level, type, ways, line;
139 	uint64_t sets, size, id;
140 	const char *types[2];
141 	const char *flags[2];
142 	uint_t ntypes = 0, nflags = 0;
143 
144 	tnode_t *tn = topo_zen_create_tn(mod, sock, pnode, inst, CACHE);
145 	if (tn == NULL) {
146 		return (NULL);
147 	}
148 
149 	if (nvlist_lookup_pairs(nvl, 0,
150 	    FM_CACHE_INFO_LEVEL, DATA_TYPE_UINT32, &level,
151 	    FM_CACHE_INFO_TYPE, DATA_TYPE_UINT32, &type,
152 	    FM_CACHE_INFO_NWAYS, DATA_TYPE_UINT32, &ways,
153 	    FM_CACHE_INFO_LINE_SIZE, DATA_TYPE_UINT32, &line,
154 	    FM_CACHE_INFO_NSETS, DATA_TYPE_UINT64, &sets,
155 	    FM_CACHE_INFO_TOTAL_SIZE, DATA_TYPE_UINT64, &size,
156 	    FM_CACHE_INFO_ID, DATA_TYPE_UINT64, &id, NULL) != 0) {
157 		topo_mod_dprintf(mod, "internal cache nvlist missing expected "
158 		    "keys");
159 		goto err;
160 	}
161 
162 	if ((type & FM_CACHE_INFO_T_DATA) != 0) {
163 		types[ntypes] = TOPO_PGROUP_CACHE_TYPES_DATA;
164 		ntypes++;
165 	}
166 
167 	if ((type & FM_CACHE_INFO_T_INSTR) != 0) {
168 		types[ntypes] = TOPO_PGROUP_CACHE_TYPES_INSTR;
169 		ntypes++;
170 	}
171 
172 	if ((type & FM_CACHE_INFO_T_UNIFIED) != 0) {
173 		flags[nflags] = TOPO_PGROUP_CACHE_FLAGS_UNIFIED;
174 		nflags++;
175 	}
176 
177 	if (nvlist_lookup_boolean(nvl, FM_CACHE_INFO_FULLY_ASSOC) == 0) {
178 		flags[nflags] = TOPO_PGROUP_CACHE_FLAGS_FA;
179 		nflags++;
180 	}
181 
182 	assert(ntypes > 0);
183 	if (topo_create_props(mod, tn, TOPO_PROP_IMMUTABLE,
184 	    &topo_zen_cache_pgroup,
185 	    TOPO_PGROUP_CACHE_LEVEL, TOPO_TYPE_UINT32, level,
186 	    TOPO_PGROUP_CACHE_WAYS, TOPO_TYPE_UINT32, ways,
187 	    TOPO_PGROUP_CACHE_SETS, TOPO_TYPE_UINT64, sets,
188 	    TOPO_PGROUP_CACHE_LINE_SIZE, TOPO_TYPE_UINT32, line,
189 	    TOPO_PGROUP_CACHE_SYSTEM_ID, TOPO_TYPE_UINT64, id,
190 	    TOPO_PGROUP_CACHE_SIZE, TOPO_TYPE_UINT64, size,
191 	    TOPO_PGROUP_CACHE_TYPES, TOPO_TYPE_STRING_ARRAY, types, ntypes,
192 	    NULL) != 0) {
193 		goto err;
194 	}
195 
196 	if (nflags > 0 && topo_prop_set_string_array(tn, TOPO_PGROUP_CACHE,
197 	    TOPO_PGROUP_CACHE_FLAGS, TOPO_PROP_IMMUTABLE, flags, nflags,
198 	    &err) != 0) {
199 		topo_mod_dprintf(mod, "failed to create %s property: %s",
200 		    TOPO_PGROUP_CACHE_FLAGS, topo_strerror(err));
201 		(void) topo_mod_seterrno(mod, err);
202 		goto err;
203 	}
204 
205 	return (tn);
206 
207 err:
208 	topo_node_unbind(tn);
209 	return (NULL);
210 
211 }
212 
213 /*
214  * Build up an FMRI for the CPU scheme for this thread and set that as our ASRU
215  * for the thread.
216  */
217 static int
topo_zen_build_strand_asru(topo_mod_t * mod,zen_topo_enum_sock_t * sock,tnode_t * tn,uint32_t cpuid)218 topo_zen_build_strand_asru(topo_mod_t *mod, zen_topo_enum_sock_t *sock,
219     tnode_t *tn, uint32_t cpuid)
220 {
221 	int err, ret;
222 	nvlist_t *fmri;
223 
224 	if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0) {
225 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
226 	}
227 
228 	if (nvlist_add_uint8(fmri, FM_VERSION, FM_CPU_SCHEME_VERSION) != 0 ||
229 	    nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU) != 0 ||
230 	    nvlist_add_uint32(fmri, FM_FMRI_CPU_ID, cpuid) != 0 ||
231 	    (sock->ztes_cpu_serial != NULL && nvlist_add_string(fmri,
232 	    FM_FMRI_CPU_SERIAL_ID, sock->ztes_cpu_serial) != 0)) {
233 		topo_mod_dprintf(mod, "failed to construct CPU FMRI\n");
234 		nvlist_free(fmri);
235 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
236 	}
237 
238 	ret = topo_node_asru_set(tn, fmri, 0, &err);
239 	nvlist_free(fmri);
240 	if (ret != 0) {
241 		topo_mod_dprintf(mod, "failed to set ASRU for thread: %s\n",
242 		    topo_strerror(err));
243 		return (topo_mod_seterrno(mod, err));
244 	}
245 
246 	return (0);
247 }
248 
249 static int
topo_zen_build_strand(topo_mod_t * mod,zen_topo_enum_sock_t * sock,const amdzen_topo_core_t * core,zen_topo_enum_core_t * zt_core,uint32_t tid)250 topo_zen_build_strand(topo_mod_t *mod, zen_topo_enum_sock_t *sock,
251     const amdzen_topo_core_t *core, zen_topo_enum_core_t *zt_core, uint32_t tid)
252 {
253 	uint32_t cpuid;
254 	tnode_t *tn;
255 
256 	tn = topo_zen_create_tn(mod, sock, zt_core->ztcore_tn, tid, STRAND);
257 	if (tn == NULL) {
258 		return (-1);
259 	}
260 
261 	/*
262 	 * Strands (hardware threads) have an ASRU that relates to their logical
263 	 * CPU. Set that up now. We currently only opt to set it on the strand
264 	 * because if we want to offline the core, it seems like that needs
265 	 * better semantics and perhaps wants a better way to indicate that in
266 	 * the scheme.
267 	 */
268 	if (nvlist_lookup_pairs(zt_core->ztcore_nvls[tid], 0,
269 	    FM_PHYSCPU_INFO_CPU_ID, DATA_TYPE_INT32,
270 	    &cpuid, NULL) != 0) {
271 		topo_mod_dprintf(mod, "internal thread %u nvlist "
272 		    "missing expected keys", tid);
273 		topo_node_unbind(tn);
274 		return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM));
275 	}
276 
277 	if (topo_zen_build_strand_asru(mod, sock, tn, cpuid) != 0) {
278 		topo_node_unbind(tn);
279 		return (-1);
280 	}
281 
282 	if (topo_create_props(mod, tn, TOPO_PROP_IMMUTABLE,
283 	    &topo_zen_strand_pgroup,
284 	    TOPO_PGROUP_STRAND_CPUID, TOPO_TYPE_UINT32, cpuid,
285 	    TOPO_PGROUP_STRAND_APICID, TOPO_TYPE_UINT32,
286 	    core->atcore_apicids[tid], NULL) != 0) {
287 		topo_mod_dprintf(mod, "failed to set strand properties\n");
288 		topo_node_unbind(tn);
289 		return (-1);
290 	}
291 
292 	zt_core->ztcore_thr_tn[tid] = tn;
293 	return (0);
294 }
295 
296 static int
topo_zen_build_core(topo_mod_t * mod,zen_topo_enum_sock_t * sock,tnode_t * ccx_tn,const amdzen_topo_core_t * core,zen_topo_enum_core_t * zt_core)297 topo_zen_build_core(topo_mod_t *mod, zen_topo_enum_sock_t *sock,
298     tnode_t *ccx_tn, const amdzen_topo_core_t *core,
299     zen_topo_enum_core_t *zt_core)
300 {
301 	zt_core->ztcore_tn = topo_zen_create_tn(mod, sock, ccx_tn,
302 	    core->atcore_phys_no, CORE);
303 	if (zt_core->ztcore_tn == NULL) {
304 		return (-1);
305 	}
306 
307 	if (topo_create_props(mod, zt_core->ztcore_tn, TOPO_PROP_IMMUTABLE,
308 	    &topo_zen_core_pgroup,
309 	    TOPO_PGROUP_CORE_LOGID, TOPO_TYPE_UINT32, core->atcore_log_no,
310 	    TOPO_PGROUP_CORE_PHYSID, TOPO_TYPE_UINT32, core->atcore_phys_no,
311 	    NULL) != 0) {
312 		return (-1);
313 	}
314 
315 	if (topo_node_range_create(mod, zt_core->ztcore_tn, CACHE, 0, 2) != 0) {
316 		topo_mod_dprintf(mod, "failed to create cache range: %s\n",
317 		    topo_mod_errmsg(mod));
318 		return (-1);
319 	}
320 
321 	if (zt_core->ztcore_l2 != NULL) {
322 		zt_core->ztcore_l2_tn = topo_zen_build_cache(mod, sock,
323 		    zt_core->ztcore_tn, 2, zt_core->ztcore_l2);
324 		if (zt_core->ztcore_l2_tn == NULL) {
325 			return (-1);
326 		}
327 	}
328 
329 	if (zt_core->ztcore_l1i != NULL) {
330 		zt_core->ztcore_l1i_tn = topo_zen_build_cache(mod, sock,
331 		    zt_core->ztcore_tn, 1, zt_core->ztcore_l1i);
332 		if (zt_core->ztcore_l1i_tn == NULL) {
333 			return (-1);
334 		}
335 	}
336 
337 	if (zt_core->ztcore_l1d != NULL) {
338 		zt_core->ztcore_l1d_tn = topo_zen_build_cache(mod, sock,
339 		    zt_core->ztcore_tn, 0, zt_core->ztcore_l1d);
340 		if (zt_core->ztcore_l1d_tn == NULL) {
341 			return (-1);
342 		}
343 	}
344 
345 	if (topo_node_range_create(mod, zt_core->ztcore_tn, STRAND, 0,
346 	    core->atcore_nthreads - 1) != 0) {
347 		topo_mod_dprintf(mod, "failed to create strand range: %s\n",
348 		    topo_mod_errmsg(mod));
349 		return (-1);
350 	}
351 
352 	for (uint32_t tid = 0; tid < core->atcore_nthreads; tid++) {
353 		int ret;
354 
355 		if (core->atcore_thr_en[tid] == 0) {
356 			continue;
357 		}
358 
359 		if ((ret = topo_zen_build_strand(mod, sock, core, zt_core,
360 		    tid)) != 0) {
361 			return (ret);
362 		}
363 	}
364 
365 	return (0);
366 }
367 
368 static int
topo_zen_build_ccx(topo_mod_t * mod,zen_topo_enum_sock_t * sock,tnode_t * ccd_tn,const amdzen_topo_ccx_t * ccx,zen_topo_enum_ccx_t * zt_ccx)369 topo_zen_build_ccx(topo_mod_t *mod, zen_topo_enum_sock_t *sock, tnode_t *ccd_tn,
370     const amdzen_topo_ccx_t *ccx, zen_topo_enum_ccx_t *zt_ccx)
371 {
372 	zt_ccx->ztccx_tn = topo_zen_create_tn(mod, sock, ccd_tn,
373 	    ccx->atccx_phys_no, CCX);
374 	if (zt_ccx->ztccx_tn == NULL) {
375 		return (-1);
376 	}
377 
378 	if (topo_create_props(mod, zt_ccx->ztccx_tn, TOPO_PROP_IMMUTABLE,
379 	    &topo_zen_ccx_pgroup,
380 	    TOPO_PGROUP_CCX_LOGID, TOPO_TYPE_UINT32, ccx->atccx_log_no,
381 	    TOPO_PGROUP_CCX_PHYSID, TOPO_TYPE_UINT32, ccx->atccx_phys_no,
382 	    NULL) != 0) {
383 		topo_node_unbind(zt_ccx->ztccx_tn);
384 		zt_ccx->ztccx_tn = NULL;
385 		return (-1);
386 	}
387 
388 	if (topo_node_range_create(mod, zt_ccx->ztccx_tn, CACHE, 0, 0) != 0) {
389 		topo_mod_dprintf(mod, "failed to create cache range: %s\n",
390 		    topo_mod_errmsg(mod));
391 		topo_node_unbind(zt_ccx->ztccx_tn);
392 		zt_ccx->ztccx_tn = NULL;
393 		return (-1);
394 	}
395 
396 	if (zt_ccx->ztccx_l3 != NULL) {
397 		zt_ccx->ztccx_l3_tn = topo_zen_build_cache(mod, sock,
398 		    zt_ccx->ztccx_tn, 0, zt_ccx->ztccx_l3);
399 		if (zt_ccx->ztccx_l3_tn == NULL) {
400 			return (-1);
401 		}
402 	}
403 
404 	if (topo_node_range_create(mod, zt_ccx->ztccx_tn, CORE, 0,
405 	    ccx->atccx_nphys_cores - 1) != 0) {
406 		topo_mod_dprintf(mod, "failed to create cores range: %s\n",
407 		    topo_mod_errmsg(mod));
408 		return (-1);
409 	}
410 
411 	for (uint32_t coreno = 0; coreno < ccx->atccx_nphys_cores; coreno++) {
412 		int ret;
413 
414 		if (ccx->atccx_core_en[coreno] == 0) {
415 			topo_mod_dprintf(mod, "skipping core %u\n", coreno);
416 			continue;
417 		}
418 
419 		if ((ret = topo_zen_build_core(mod, sock, zt_ccx->ztccx_tn,
420 		    &ccx->atccx_cores[coreno], &zt_ccx->ztccx_core[coreno])) !=
421 		    0) {
422 			return (ret);
423 		}
424 	}
425 
426 	return (0);
427 }
428 
429 static int
topo_zen_build_ccds(topo_mod_t * mod,zen_topo_enum_sock_t * sock)430 topo_zen_build_ccds(topo_mod_t *mod, zen_topo_enum_sock_t *sock)
431 {
432 	tnode_t *chip = sock->ztes_tn;
433 
434 	if (topo_node_range_create(mod, chip, CCD, 0, sock->ztes_nccd - 1) !=
435 	    0) {
436 		topo_mod_dprintf(mod, "failed to create CCD range: %s\n",
437 		    topo_mod_errmsg(mod));
438 		return (-1);
439 	}
440 
441 	for (uint32_t ccdno = 0; ccdno < sock->ztes_nccd; ccdno++) {
442 		const amdzen_topo_ccd_t *ccd = &sock->ztes_ccd[ccdno];
443 		zen_topo_enum_ccd_t *zt_ccd = &sock->ztes_tn_ccd[ccdno];
444 
445 		/*
446 		 * Make sure we skip any CCDs that don't actually exist.
447 		 */
448 		if (ccd->atccd_err != AMDZEN_TOPO_CCD_E_OK) {
449 			continue;
450 		}
451 
452 		zt_ccd->ztccd_tn = topo_zen_create_tn(mod, sock, chip, ccdno,
453 		    CCD);
454 		if (zt_ccd->ztccd_tn == NULL) {
455 			return (-1);
456 		}
457 
458 		if (topo_create_props(mod, zt_ccd->ztccd_tn,
459 		    TOPO_PROP_IMMUTABLE, &topo_zen_ccd_pgroup,
460 		    TOPO_PGROUP_CCD_LOGID, TOPO_TYPE_UINT32, ccd->atccd_log_no,
461 		    TOPO_PGROUP_CCD_PHYSID, TOPO_TYPE_UINT32,
462 		    ccd->atccd_phys_no, NULL) != 0) {
463 			topo_node_unbind(zt_ccd->ztccd_tn);
464 			zt_ccd->ztccd_tn = NULL;
465 			return (-1);
466 		}
467 
468 		/*
469 		 * At this point we should go create any additional sensors
470 		 * (such as the per-CCD Tctl) and probably set some methods,
471 		 * etc.
472 		 */
473 
474 		if (topo_node_range_create(mod, zt_ccd->ztccd_tn, CCX, 0,
475 		    ccd->atccd_nphys_ccx) != 0) {
476 			topo_mod_dprintf(mod, "failed to create CCD range: "
477 			    "%s\n", topo_mod_errmsg(mod));
478 			return (-1);
479 		}
480 
481 		for (uint32_t ccxno = 0; ccxno < ccd->atccd_nphys_ccx;
482 		    ccxno++) {
483 			int ret;
484 
485 			if (ccd->atccd_ccx_en[ccxno] == 0) {
486 				continue;
487 			}
488 
489 			if ((ret = topo_zen_build_ccx(mod, sock,
490 			    zt_ccd->ztccd_tn, &ccd->atccd_ccx[ccxno],
491 			    &zt_ccd->ztccd_ccx[ccxno])) != 0) {
492 				return (ret);
493 			}
494 		}
495 	}
496 
497 	return (0);
498 }
499 
500 int
topo_zen_build_chip(topo_mod_t * mod,tnode_t * pnode,topo_instance_t inst,zen_topo_enum_sock_t * sock)501 topo_zen_build_chip(topo_mod_t *mod, tnode_t *pnode, topo_instance_t inst,
502     zen_topo_enum_sock_t *sock)
503 {
504 	int ret;
505 	tnode_t *chip;
506 
507 	chip = topo_zen_create_tn(mod, sock, pnode, inst, CHIP);
508 	if (chip == NULL) {
509 		return (-1);
510 	}
511 
512 	if (topo_create_props(mod, chip, TOPO_PROP_IMMUTABLE,
513 	    &topo_zen_chip_pgroup,
514 	    TOPO_PGROUP_CHIP_BRAND, TOPO_TYPE_STRING, sock->ztes_cpu_brand,
515 	    TOPO_PGROUP_CHIP_FAMILY, TOPO_TYPE_INT32, sock->ztes_cpu_fam,
516 	    TOPO_PGROUP_CHIP_MODEL, TOPO_TYPE_INT32, sock->ztes_cpu_model,
517 	    TOPO_PGROUP_CHIP_STEPPING, TOPO_TYPE_INT32, sock->ztes_cpu_step,
518 	    TOPO_PGROUP_CHIP_SOCKET, TOPO_TYPE_STRING, sock->ztes_cpu_sock,
519 	    NULL) != 0) {
520 		topo_node_unbind(chip);
521 		return (-1);
522 	}
523 
524 	if (sock->ztes_cpu_rev != NULL && topo_create_props(mod, chip,
525 	    TOPO_PROP_IMMUTABLE, &topo_zen_chip_pgroup,
526 	    TOPO_PGROUP_CHIP_REVISION, TOPO_TYPE_STRING, sock->ztes_cpu_rev,
527 	    NULL) != 0) {
528 		topo_node_unbind(chip);
529 		return (-1);
530 	}
531 
532 	sock->ztes_tn = chip;
533 	ret = topo_zen_build_ccds(mod, sock);
534 
535 	/*
536 	 * At this point we should flesh out the I/O die and all the UMCs, IOMS
537 	 * instances, and related. we would put the general thermal sensor that
538 	 * smntemp exposes as procnode.%u under the I/O die when we have it.
539 	 */
540 
541 	return (ret);
542 }
543