xref: /illumos-gate/usr/src/lib/fm/topo/modules/common/pciebus/topo_pcie_util.c (revision 84ceaea936ebcf122d4f0756d298adf307fd491d)
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 2023 Oxide Computer Company
14  */
15 
16 #include <stdbool.h>
17 #include <string.h>
18 
19 #include <sys/fm/protocol.h>
20 #include <fm/topo_mod.h>
21 #include <fm/topo_list.h>
22 #include <fm/topo_method.h>
23 
24 #include "topo_pcie_impl.h"
25 
26 const char *
pcie_type_name(pcie_node_type_t type)27 pcie_type_name(pcie_node_type_t type)
28 {
29 	switch (type) {
30 	case PCIE_NODE_ROOTNEXUS:
31 		return ("root-complex");
32 	case PCIE_NODE_ROOTPORT:
33 		return ("root-port");
34 	case PCIE_NODE_PCI_DEV:
35 		return ("pci");
36 	case PCIE_NODE_PCIE_DEV:
37 		return ("pcie");
38 	case PCIE_NODE_SWITCH_UP:
39 		return ("upstream-switch");
40 	case PCIE_NODE_SWITCH_DOWN:
41 		return ("downstream-switch");
42 	case PCIE_NODE_PCIE_PCI:
43 		return ("pcie-pci-bridge");
44 	case PCIE_NODE_PCI_PCIE:
45 		return ("pci-pcie-bridge");
46 	default:
47 		return ("unhandled type name");
48 	}
49 }
50 
51 uint_t
pcie_speed2gen(int64_t speed)52 pcie_speed2gen(int64_t speed)
53 {
54 	switch (speed) {
55 	case 2500000000LL:
56 		return (1);
57 	case 5000000000LL:
58 		return (2);
59 	case 8000000000LL:
60 		return (3);
61 	case 16000000000LL:
62 		return (4);
63 	case 32000000000LL:
64 		return (5);
65 	default:
66 		break;
67 	}
68 	return (0);
69 }
70 
71 const char *
pcie_speed2str(int64_t speed)72 pcie_speed2str(int64_t speed)
73 {
74 	switch (speed) {
75 	case 2500000000LL:
76 		return ("2.5");
77 	case 5000000000LL:
78 		return ("5.0");
79 	case 8000000000LL:
80 		return ("8.0");
81 	case 16000000000LL:
82 		return ("16.0");
83 	case 32000000000LL:
84 		return ("32.0");
85 	default:
86 		break;
87 	}
88 	return ("0");
89 }
90 
91 bool
pcie_topo_pgroup_create(topo_mod_t * mod,tnode_t * tn,const topo_pgroup_info_t * pg)92 pcie_topo_pgroup_create(topo_mod_t *mod, tnode_t *tn,
93     const topo_pgroup_info_t *pg)
94 {
95 	int err;
96 
97 	if (topo_pgroup_create(tn, pg, &err) != 0) {
98 		if (err == ETOPO_PROP_DEFD)
99 			return (true);
100 		topo_mod_dprintf(mod, "failed to create property group %s: %s",
101 		    pg->tpi_name, topo_strerror(err));
102 		(void) topo_mod_seterrno(mod, err);
103 		return (false);
104 	}
105 	return (true);
106 }
107 
108 bool
pcie_topo_range_create(topo_mod_t * mod,tnode_t * tn,const char * name,topo_instance_t min,topo_instance_t max)109 pcie_topo_range_create(topo_mod_t *mod, tnode_t *tn, const char *name,
110     topo_instance_t min, topo_instance_t max)
111 {
112 	int err;
113 
114 	err = topo_node_range_create(mod, tn, name, min, max);
115 	if (err == EMOD_NODE_DUP)
116 		return (true);
117 	if (err != 0) {
118 		topo_mod_dprintf(mod,
119 		    "Failed to create range for %s [%"PRIu64",%"PRIu64"]: %s",
120 		    name, min, max, topo_mod_errmsg(mod));
121 		return (false);
122 	}
123 	return (true);
124 }
125 
126 static bool
pcie_topo_prop_set(topo_mod_t * mod,tnode_t * tn,const topo_pgroup_info_t * pg,topo_type_t type,const char * name,void * val)127 pcie_topo_prop_set(topo_mod_t *mod, tnode_t *tn, const topo_pgroup_info_t *pg,
128     topo_type_t type, const char *name, void *val)
129 {
130 	int ret, err;
131 	/*
132 	 * All properties are flagged as immutable as they reflect read-only
133 	 * information derived from the device tree/device.
134 	 */
135 	const int flag = TOPO_PROP_IMMUTABLE;
136 
137 	switch (type) {
138 	case TOPO_TYPE_UINT32:
139 		ret = topo_prop_set_uint32(tn, pg->tpi_name, name, flag,
140 		    *(uint32_t *)val, &err);
141 		break;
142 	case TOPO_TYPE_UINT64:
143 		ret = topo_prop_set_uint64(tn, pg->tpi_name, name, flag,
144 		    *(uint64_t *)val, &err);
145 		break;
146 	case TOPO_TYPE_STRING:
147 		ret = topo_prop_set_string(tn, pg->tpi_name, name, flag,
148 		    (char *)val, &err);
149 		break;
150 	default:
151 		topo_mod_dprintf(mod, "%s - unhandled property type %u",
152 		    __func__, type);
153 		return (false);
154 	}
155 
156 	if (ret != 0) {
157 		topo_mod_dprintf(mod, "failed to set property %s/%s: %s",
158 		    pg->tpi_name, name, topo_strerror(err));
159 		(void) topo_mod_seterrno(mod, err);
160 		return (false);
161 	}
162 
163 	return (true);
164 }
165 
166 bool
pcie_topo_prop_set32(topo_mod_t * mod,tnode_t * tn,const topo_pgroup_info_t * pg,const char * name,uint32_t val)167 pcie_topo_prop_set32(topo_mod_t *mod, tnode_t *tn, const topo_pgroup_info_t *pg,
168     const char *name, uint32_t val)
169 {
170 	return (pcie_topo_prop_set(mod, tn, pg, TOPO_TYPE_UINT32, name,
171 	    (void *)&val));
172 }
173 
174 bool
pcie_topo_prop_set64(topo_mod_t * mod,tnode_t * tn,const topo_pgroup_info_t * pg,const char * name,uint64_t val)175 pcie_topo_prop_set64(topo_mod_t *mod, tnode_t *tn, const topo_pgroup_info_t *pg,
176     const char *name, uint64_t val)
177 {
178 	return (pcie_topo_prop_set(mod, tn, pg, TOPO_TYPE_UINT64, name,
179 	    (void *)&val));
180 }
181 
182 bool
pcie_topo_prop_set32_array(topo_mod_t * mod,tnode_t * tn,const topo_pgroup_info_t * pg,const char * name,uint32_t * vals,int nval)183 pcie_topo_prop_set32_array(topo_mod_t *mod, tnode_t *tn,
184     const topo_pgroup_info_t *pg, const char *name, uint32_t *vals, int nval)
185 {
186 	int ret, err;
187 
188 	ret = topo_prop_set_uint32_array(tn, pg->tpi_name, name, 0,
189 	    vals, nval, &err);
190 	if (ret != 0) {
191 		topo_mod_dprintf(mod, "failed to set property %s/%s: %s",
192 		    pg->tpi_name, name, topo_strerror(err));
193 		(void) topo_mod_seterrno(mod, err);
194 		return (false);
195 	}
196 
197 	return (true);
198 }
199 
200 bool
pcie_topo_prop_set64_array(topo_mod_t * mod,tnode_t * tn,const topo_pgroup_info_t * pg,const char * name,uint64_t * vals,int nval)201 pcie_topo_prop_set64_array(topo_mod_t *mod, tnode_t *tn,
202     const topo_pgroup_info_t *pg, const char *name, uint64_t *vals, int nval)
203 {
204 	int ret, err;
205 
206 	ret = topo_prop_set_uint64_array(tn, pg->tpi_name, name, 0,
207 	    vals, nval, &err);
208 	if (ret != 0) {
209 		topo_mod_dprintf(mod, "failed to set property %s/%s: %s",
210 		    pg->tpi_name, name, topo_strerror(err));
211 		(void) topo_mod_seterrno(mod, err);
212 		return (false);
213 	}
214 
215 	return (true);
216 }
217 
218 bool
pcie_topo_prop_setstr(topo_mod_t * mod,tnode_t * tn,const topo_pgroup_info_t * pg,const char * name,const char * val)219 pcie_topo_prop_setstr(topo_mod_t *mod, tnode_t *tn,
220     const topo_pgroup_info_t *pg, const char *name, const char *val)
221 {
222 	return (pcie_topo_prop_set(mod, tn, pg, TOPO_TYPE_STRING, name,
223 	    (void *)val));
224 }
225 
226 int32_t
pcie_devinfo_get32(topo_mod_t * mod,di_node_t did,const char * name)227 pcie_devinfo_get32(topo_mod_t *mod, di_node_t did, const char *name)
228 {
229 	int32_t *iprop;
230 	int nprop;
231 
232 	nprop = di_prop_lookup_ints(DDI_DEV_T_ANY, did, name, &iprop);
233 
234 	if (nprop != 1) {
235 		if (nprop != -1) {
236 			topo_mod_dprintf(mod,
237 			    "devinfo property %s has %u value(s); skipping",
238 			    name, nprop);
239 		}
240 		return (-1);
241 	}
242 
243 	return (iprop[0]);
244 }
245 
246 int64_t
pcie_devinfo_get64(topo_mod_t * mod,di_node_t did,const char * name)247 pcie_devinfo_get64(topo_mod_t *mod, di_node_t did, const char *name)
248 {
249 	int64_t *iprop;
250 	int nprop;
251 
252 	nprop = di_prop_lookup_int64(DDI_DEV_T_ANY, did, name, &iprop);
253 
254 	if (nprop != 1) {
255 		if (nprop != -1) {
256 			topo_mod_dprintf(mod,
257 			    "devinfo property %s has %u value(s); skipping",
258 			    name, nprop);
259 		}
260 		return (-1);
261 	}
262 
263 	return (iprop[0]);
264 }
265 
266 bool
pcie_devinfo_getbool(topo_mod_t * mod,di_node_t did,const char * name)267 pcie_devinfo_getbool(topo_mod_t *mod, di_node_t did, const char *name)
268 {
269 	di_prop_t prop;
270 
271 	prop = di_prop_find(DDI_DEV_T_ANY, did, name);
272 
273 	return (prop != DI_PROP_NIL &&
274 	    di_prop_type(prop) == DI_PROP_TYPE_BOOLEAN);
275 }
276 
277 /*
278  * This is a convenience function to copy a property from a devinfo node to
279  * a topo node property group, with appropriate error checking and output if
280  * anything goes wrong.
281  * devinfo numeric properties are signed but we always do explicit conversion to
282  * unsigned when storing the values back to the topo node.
283  */
284 bool
pcie_topo_prop_copy(topo_mod_t * mod,di_node_t did,tnode_t * tn,const topo_pgroup_info_t * pg,topo_type_t type,const char * src,const char * dst)285 pcie_topo_prop_copy(topo_mod_t *mod, di_node_t did, tnode_t *tn,
286     const topo_pgroup_info_t *pg, topo_type_t type,
287     const char *src, const char *dst)
288 {
289 	int32_t *iprop;
290 	int64_t *lprop;
291 	char *sprop;
292 	int nprop;
293 
294 	switch (type) {
295 	case TOPO_TYPE_UINT32:
296 	case TOPO_TYPE_UINT32_ARRAY:
297 		nprop = di_prop_lookup_ints(DDI_DEV_T_ANY, did, src, &iprop);
298 		break;
299 	case TOPO_TYPE_UINT64:
300 	case TOPO_TYPE_UINT64_ARRAY:
301 		nprop = di_prop_lookup_int64(DDI_DEV_T_ANY, did, src, &lprop);
302 		break;
303 	case TOPO_TYPE_STRING:
304 		nprop = di_prop_lookup_strings(DDI_DEV_T_ANY, did, src, &sprop);
305 		break;
306 	default:
307 		topo_mod_dprintf(mod, "%s - unhandled property type %u\n",
308 		    __func__, type);
309 		return (false);
310 	}
311 
312 	if (nprop < 1) {
313 		if (nprop != -1) {
314 			topo_mod_dprintf(mod,
315 			    "devinfo property %s has %u value(s); skipping",
316 			    src, nprop);
317 		}
318 		return (false);
319 	}
320 
321 	switch (type) {
322 	case TOPO_TYPE_UINT32:
323 		return (pcie_topo_prop_set32(mod, tn, pg, dst, iprop[0]));
324 	case TOPO_TYPE_UINT32_ARRAY:
325 		return (pcie_topo_prop_set32_array(mod, tn, pg, dst,
326 		    (uint32_t *)iprop, nprop));
327 	case TOPO_TYPE_UINT64:
328 		return (pcie_topo_prop_set64(mod, tn, pg, dst, lprop[0]));
329 	case TOPO_TYPE_UINT64_ARRAY:
330 		return (pcie_topo_prop_set64_array(mod, tn, pg, dst,
331 		    (uint64_t *)lprop, nprop));
332 	case TOPO_TYPE_STRING:
333 		return (pcie_topo_prop_setstr(mod, tn, pg, dst, sprop));
334 	default:
335 		abort();
336 	}
337 
338 	return (false);
339 }
340