Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 
     28 #include <errno.h>
     29 #include <limits.h>
     30 #include <strings.h>
     31 #include <unistd.h>
     32 #include <topo_error.h>
     33 #include <fm/topo_mod.h>
     34 #include <sys/fm/protocol.h>
     35 
     36 #include <topo_method.h>
     37 #include <cpu.h>
     38 
     39 /*
     40  * platform specific cpu module
     41  */
     42 #define	PLATFORM_CPU_VERSION	CPU_VERSION
     43 #define	PLATFORM_CPU_NAME	"platform-cpu"
     44 
     45 static int cpu_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t,
     46     topo_instance_t, void *, void *);
     47 static void cpu_release(topo_mod_t *, tnode_t *);
     48 static int cpu_nvl2str(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
     49     nvlist_t **);
     50 static int cpu_str2nvl(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
     51     nvlist_t **);
     52 static int cpu_fmri_asru(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
     53     nvlist_t **);
     54 static int cpu_fmri_create_meth(topo_mod_t *, tnode_t *, topo_version_t,
     55     nvlist_t *, nvlist_t **);
     56 static nvlist_t *fmri_create(topo_mod_t *, uint32_t, uint8_t, char *);
     57 
     58 static const topo_method_t cpu_methods[] = {
     59 	{ TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION,
     60 	    TOPO_STABILITY_INTERNAL, cpu_nvl2str },
     61 	{ TOPO_METH_STR2NVL, TOPO_METH_STR2NVL_DESC, TOPO_METH_STR2NVL_VERSION,
     62 	    TOPO_STABILITY_INTERNAL, cpu_str2nvl },
     63 	{ TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC,
     64 	    TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL,
     65 	    cpu_fmri_asru },
     66 	{ TOPO_METH_FMRI, TOPO_METH_FMRI_DESC, TOPO_METH_FMRI_VERSION,
     67 	    TOPO_STABILITY_INTERNAL, cpu_fmri_create_meth },
     68 	{ NULL }
     69 };
     70 
     71 static const topo_modops_t cpu_ops =
     72 	{ cpu_enum, cpu_release };
     73 
     74 static const topo_modinfo_t cpu_info =
     75 	{ "cpu", FM_FMRI_SCHEME_CPU, CPU_VERSION, &cpu_ops };
     76 
     77 int
     78 cpu_init(topo_mod_t *mod, topo_version_t version)
     79 {
     80 	cpu_node_t *cpuip;
     81 
     82 	if (getenv("TOPOCPUDEBUG"))
     83 		topo_mod_setdebug(mod);
     84 	topo_mod_dprintf(mod, "initializing cpu builtin\n");
     85 
     86 	if (version != CPU_VERSION)
     87 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
     88 
     89 	if ((cpuip = topo_mod_zalloc(mod, sizeof (cpu_node_t))) == NULL)
     90 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
     91 
     92 	if ((cpuip->cn_kc = kstat_open()) == NULL) {
     93 		topo_mod_dprintf(mod, "kstat_open failed: %s\n",
     94 		    strerror(errno));
     95 		topo_mod_free(mod, cpuip, sizeof (cpu_node_t));
     96 		return (-1);
     97 	}
     98 
     99 	cpuip->cn_ncpustats = sysconf(_SC_CPUID_MAX);
    100 	if ((cpuip->cn_cpustats = topo_mod_zalloc(mod, (
    101 	    cpuip->cn_ncpustats + 1) * sizeof (kstat_t *))) == NULL) {
    102 		(void) kstat_close(cpuip->cn_kc);
    103 		topo_mod_free(mod, cpuip, sizeof (cpu_node_t));
    104 		return (-1);
    105 	}
    106 
    107 	if (topo_mod_register(mod, &cpu_info, TOPO_VERSION) != 0) {
    108 		topo_mod_dprintf(mod, "failed to register cpu_info: "
    109 		    "%s\n", topo_mod_errmsg(mod));
    110 		topo_mod_free(mod, cpuip->cn_cpustats,
    111 		    (cpuip->cn_ncpustats + 1) * sizeof (kstat_t *));
    112 		(void) kstat_close(cpuip->cn_kc);
    113 		topo_mod_free(mod, cpuip, sizeof (cpu_node_t));
    114 		return (-1);
    115 	}
    116 
    117 	topo_mod_setspecific(mod, (void *)cpuip);
    118 
    119 	return (0);
    120 }
    121 
    122 void
    123 cpu_fini(topo_mod_t *mod)
    124 {
    125 	cpu_node_t *cpuip;
    126 
    127 	cpuip = topo_mod_getspecific(mod);
    128 
    129 	if (cpuip->cn_cpustats != NULL)
    130 		topo_mod_free(mod, cpuip->cn_cpustats,
    131 		    (cpuip->cn_ncpustats + 1) * sizeof (kstat_t *));
    132 
    133 	(void) kstat_close(cpuip->cn_kc);
    134 	topo_mod_free(mod, cpuip, sizeof (cpu_node_t));
    135 
    136 	topo_mod_unregister(mod);
    137 }
    138 
    139 static int
    140 cpu_kstat_init(cpu_node_t *cpuip, int i)
    141 {
    142 	kstat_t *ksp;
    143 
    144 	if (cpuip->cn_cpustats[i] == NULL) {
    145 		if ((ksp = kstat_lookup(cpuip->cn_kc, "cpu_info", i, NULL)) ==
    146 		    NULL || kstat_read(cpuip->cn_kc, ksp, NULL) < 0)
    147 			return (-1);
    148 
    149 		cpuip->cn_cpustats[i] = ksp;
    150 	} else {
    151 		ksp = cpuip->cn_cpustats[i];
    152 	}
    153 
    154 	return (ksp->ks_instance);
    155 }
    156 
    157 /*ARGSUSED*/
    158 static int
    159 cpu_create(topo_mod_t *mod, tnode_t *rnode, const char *name,
    160     topo_instance_t min, topo_instance_t max, cpu_node_t *cpuip)
    161 {
    162 	int i;
    163 	processorid_t cpu_id;
    164 	char *s, sbuf[21];
    165 	kstat_named_t *ks;
    166 	nvlist_t *fmri;
    167 
    168 	for (i = 0; i <= cpuip->cn_ncpustats; i++) {
    169 
    170 		if ((cpu_id = cpu_kstat_init(cpuip, i)) < 0)
    171 			continue;
    172 
    173 		if ((ks = kstat_data_lookup(cpuip->cn_cpustats[i],
    174 		    "device_ID")) != NULL) {
    175 			(void) snprintf(sbuf, 21, "%llX", ks->value.ui64);
    176 			s = sbuf;
    177 		} else {
    178 			s = NULL;
    179 		}
    180 
    181 		if ((fmri = fmri_create(mod, cpu_id, 0, s)) == NULL)
    182 			continue;
    183 		(void) topo_node_bind(mod, rnode, name, cpu_id, fmri);
    184 		nvlist_free(fmri);
    185 	}
    186 
    187 	return (0);
    188 }
    189 
    190 
    191 /*ARGSUSED*/
    192 static int
    193 cpu_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
    194     topo_instance_t min, topo_instance_t max, void *arg, void *notused2)
    195 {
    196 	topo_mod_t *nmp;
    197 	cpu_node_t *cpuip = (cpu_node_t *)arg;
    198 
    199 	if ((nmp = topo_mod_load(mod, PLATFORM_CPU_NAME,
    200 	    PLATFORM_CPU_VERSION)) == NULL) {
    201 		if (topo_mod_errno(mod) == ETOPO_MOD_NOENT) {
    202 			/*
    203 			 * There is no platform specific cpu module, so use
    204 			 * the default enumeration with kstats of this builtin
    205 			 * cpu module.
    206 			 */
    207 			if (topo_node_range_create(mod, pnode, name, 0,
    208 			    cpuip->cn_ncpustats + 1) < 0) {
    209 				topo_mod_dprintf(mod,
    210 				    "cpu enumeration failed to create "
    211 				    "cpu range [0-%d]: %s\n",
    212 				    cpuip->cn_ncpustats + 1,
    213 				    topo_mod_errmsg(mod));
    214 				return (-1); /* mod_errno set */
    215 			}
    216 			(void) topo_method_register(mod, pnode, cpu_methods);
    217 			return (cpu_create(mod, pnode, name, min, max, cpuip));
    218 
    219 		} else {
    220 			/* Fail to load the module */
    221 			topo_mod_dprintf(mod,
    222 			    "Failed to load module %s: %s",
    223 			    PLATFORM_CPU_NAME,
    224 			    topo_mod_errmsg(mod));
    225 			return (-1);
    226 		}
    227 	}
    228 
    229 	if (topo_mod_enumerate(nmp, pnode, PLATFORM_CPU_NAME, name,
    230 	    min, max, NULL) < 0) {
    231 		topo_mod_dprintf(mod,
    232 		    "%s failed to enumerate: %s",
    233 		    PLATFORM_CPU_NAME,
    234 		    topo_mod_errmsg(mod));
    235 		return (-1);
    236 	}
    237 	(void) topo_method_register(mod, pnode, cpu_methods);
    238 
    239 	return (0);
    240 }
    241 
    242 static void
    243 cpu_release(topo_mod_t *mod, tnode_t *node)
    244 {
    245 	topo_method_unregister_all(mod, node);
    246 }
    247 
    248 ssize_t
    249 fmri_nvl2str(nvlist_t *nvl, uint8_t version, char *buf, size_t buflen)
    250 {
    251 	int rc;
    252 	uint8_t	type;
    253 	uint32_t cpuid, way;
    254 	uint32_t	index;
    255 	uint16_t	bit;
    256 	uint64_t serint;
    257 	char *serstr = NULL;
    258 
    259 	if (version == CPU_SCHEME_VERSION0) {
    260 		if (nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0 ||
    261 		    nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, &serint)
    262 		    != 0)
    263 			return (0);
    264 
    265 		return (snprintf(buf, buflen, "cpu:///%s=%u/%s=%llX",
    266 		    FM_FMRI_CPU_ID, cpuid, FM_FMRI_CPU_SERIAL_ID,
    267 		    (u_longlong_t)serint));
    268 
    269 	} else if (version == CPU_SCHEME_VERSION1) {
    270 		if (nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0)
    271 			return (0);
    272 
    273 		/*
    274 		 * Serial number is an optional element
    275 		 */
    276 		if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID,
    277 		    &serstr)) != 0)
    278 
    279 			if (rc != ENOENT)
    280 				return (0);
    281 
    282 		/*
    283 		 * Cache index, way and type are optional elements
    284 		 * But if we have one of them, we must have them all.
    285 		 */
    286 		rc = nvlist_lookup_uint32(nvl, FM_FMRI_CPU_CACHE_INDEX,
    287 		    &index);
    288 		rc |= nvlist_lookup_uint32(nvl, FM_FMRI_CPU_CACHE_WAY, &way);
    289 		rc |= nvlist_lookup_uint16(nvl, FM_FMRI_CPU_CACHE_BIT, &bit);
    290 		rc |= nvlist_lookup_uint8(nvl, FM_FMRI_CPU_CACHE_TYPE, &type);
    291 
    292 		/* Insure there were no errors accessing the nvl */
    293 		if (rc != 0 && rc != ENOENT)
    294 			return (0);
    295 
    296 		if (serstr == NULL) {
    297 			/* If we have a serial string and no cache info */
    298 			if (rc == ENOENT)
    299 				return (snprintf(buf, buflen, "cpu:///%s=%u",
    300 				    FM_FMRI_CPU_ID, cpuid));
    301 			else {
    302 				return (snprintf(buf, buflen,
    303 				    "cpu:///%s=%u/%s=%u/%s=%u/%s=%d/%s=%d",
    304 				    FM_FMRI_CPU_ID, cpuid,
    305 				    FM_FMRI_CPU_CACHE_INDEX, index,
    306 				    FM_FMRI_CPU_CACHE_WAY, way,
    307 				    FM_FMRI_CPU_CACHE_BIT, bit,
    308 				    FM_FMRI_CPU_CACHE_TYPE, type));
    309 			}
    310 		} else {
    311 			if (rc == ENOENT) {
    312 				return (snprintf(buf, buflen,
    313 				    "cpu:///%s=%u/%s=%s",
    314 				    FM_FMRI_CPU_ID, cpuid,
    315 				    FM_FMRI_CPU_SERIAL_ID, serstr));
    316 			} else {
    317 				return (snprintf(buf, buflen,
    318 				"cpu:///%s=%u/%s=%s/%s=%u/%s=%u/%s=%d/%s=%d",
    319 				    FM_FMRI_CPU_ID, cpuid,
    320 				    FM_FMRI_CPU_SERIAL_ID, serstr,
    321 				    FM_FMRI_CPU_CACHE_INDEX, index,
    322 				    FM_FMRI_CPU_CACHE_WAY, way,
    323 				    FM_FMRI_CPU_CACHE_BIT, bit,
    324 				    FM_FMRI_CPU_CACHE_TYPE, type));
    325 			}
    326 		}
    327 	} else
    328 		return (0);
    329 }
    330 
    331 /*ARGSUSED*/
    332 static int
    333 cpu_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version,
    334     nvlist_t *in, nvlist_t **out)
    335 {
    336 	uint8_t fver;
    337 	ssize_t len;
    338 	char *name;
    339 
    340 	if (version > TOPO_METH_NVL2STR_VERSION)
    341 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
    342 
    343 	if (nvlist_lookup_uint8(in, FM_VERSION, &fver) != 0)
    344 		return (topo_mod_seterrno(mod, EMOD_FMRI_VERSION));
    345 
    346 	if ((len = fmri_nvl2str(in, fver, NULL, 0)) == 0 ||
    347 	    (name = topo_mod_alloc(mod, len + 1)) == NULL ||
    348 	    fmri_nvl2str(in, fver, name, len + 1) == 0)
    349 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
    350 
    351 	if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) < 0) {
    352 		topo_mod_free(mod, name, len + 1);
    353 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
    354 	}
    355 
    356 	if (nvlist_add_string(*out, "fmri-string", name) != 0) {
    357 		topo_mod_free(mod, name, len + 1);
    358 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
    359 	}
    360 	topo_mod_free(mod, name, len + 1);
    361 
    362 	return (0);
    363 }
    364 
    365 /*ARGSUSED*/
    366 static int
    367 cpu_str2nvl(topo_mod_t *mod, tnode_t *node, topo_version_t version,
    368     nvlist_t *in, nvlist_t **out)
    369 {
    370 	int err;
    371 	ulong_t cpuid;
    372 	uint8_t	type = 0;
    373 	uint32_t way = 0;
    374 	uint32_t index = 0;
    375 	int	index_present = 0;
    376 	uint16_t	bit = 0;
    377 	char *str, *s, *end, *serial_end;
    378 	char *serial = NULL;
    379 	nvlist_t *fmri;
    380 
    381 	if (version > TOPO_METH_STR2NVL_VERSION)
    382 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
    383 
    384 	if (nvlist_lookup_string(in, "fmri-string", &str) != 0)
    385 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
    386 
    387 	/* We're expecting a string version of a cpu scheme FMRI */
    388 	if (strncmp(str, "cpu:///", 7) != 0)
    389 		return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
    390 
    391 	s = strchr(str + 7, '=');
    392 	if (s == NULL)
    393 		return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
    394 
    395 	++s;
    396 	cpuid = strtoul(s, &end, 0);
    397 
    398 	if (cpuid == ULONG_MAX && errno == ERANGE)
    399 		return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
    400 
    401 	/* If there is a serial #, then there might also be cache data */
    402 	if (*(s = end) == '/') {
    403 		s = strchr(s, '=');
    404 		++s;
    405 		serial = s;
    406 		serial_end = strchr(s, '/');
    407 		/* If there is cache data, all must be present */
    408 		if (serial_end != NULL) {
    409 			/* Now terminate the serial string */
    410 			*serial_end = '\0';
    411 			index_present = 1;
    412 			s = serial_end + 1;
    413 			s = strchr(s, '=');
    414 			++s;
    415 			index = strtoul(s, &end, 0);
    416 			if (*(s = end) != '/') {
    417 				return (topo_mod_seterrno(mod,
    418 				    EMOD_FMRI_MALFORM));
    419 			}
    420 			s = strchr(s, '=');
    421 			if (s == NULL) {
    422 				return (topo_mod_seterrno(mod,
    423 				    EMOD_FMRI_MALFORM));
    424 			}
    425 			++s;
    426 			way = strtoul(s, &end, 0);
    427 			if (*(s = end) != '/') {
    428 				return (topo_mod_seterrno(mod,
    429 				    EMOD_FMRI_MALFORM));
    430 			}
    431 			s = strchr(s, '=');
    432 			if (s == NULL) {
    433 				return (topo_mod_seterrno(mod,
    434 				    EMOD_FMRI_MALFORM));
    435 			}
    436 			++s;
    437 			bit = strtoul(s, &end, 0);
    438 			if (*(s = end) != '/') {
    439 				return (topo_mod_seterrno(mod,
    440 				    EMOD_FMRI_MALFORM));
    441 			}
    442 			s = strchr(s, '=');
    443 			if (s == NULL) {
    444 				return (topo_mod_seterrno(mod,
    445 				    EMOD_FMRI_MALFORM));
    446 			}
    447 			++s;
    448 			type = strtoul(s, &end, 0);
    449 		}
    450 
    451 	}
    452 	if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0)
    453 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
    454 
    455 	err = nvlist_add_uint8(fmri, FM_VERSION, CPU_SCHEME_VERSION1);
    456 	err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU);
    457 	err |= nvlist_add_uint32(fmri, FM_FMRI_CPU_ID, (uint32_t)cpuid);
    458 	err |= nvlist_add_uint8(fmri, FM_FMRI_CPU_MASK, 0);
    459 	if (serial != NULL)
    460 		err |= nvlist_add_string(fmri, FM_FMRI_CPU_SERIAL_ID,
    461 		    serial);
    462 
    463 	if (index_present) {
    464 		err |= nvlist_add_uint32(fmri, FM_FMRI_CPU_CACHE_INDEX,
    465 		    index);
    466 		err |= nvlist_add_uint32(fmri, FM_FMRI_CPU_CACHE_WAY,
    467 		    way);
    468 		err |= nvlist_add_uint16(fmri, FM_FMRI_CPU_CACHE_BIT,
    469 		    bit);
    470 		err |= nvlist_add_uint8(fmri, FM_FMRI_CPU_CACHE_TYPE,
    471 		    type);
    472 	}
    473 	if (err != 0) {
    474 		nvlist_free(fmri);
    475 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
    476 	}
    477 	*out = fmri;
    478 
    479 	return (0);
    480 }
    481 
    482 static nvlist_t *
    483 fmri_create(topo_mod_t *mod, uint32_t cpu_id, uint8_t cpumask, char *s)
    484 {
    485 	int err;
    486 	nvlist_t *fmri;
    487 
    488 	if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0) {
    489 		(void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
    490 		return (NULL);
    491 	}
    492 
    493 	err = nvlist_add_uint8(fmri, FM_VERSION, FM_CPU_SCHEME_VERSION);
    494 	err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU);
    495 	err |= nvlist_add_uint32(fmri, FM_FMRI_CPU_ID, cpu_id);
    496 	err |= nvlist_add_uint8(fmri, FM_FMRI_CPU_MASK, cpumask);
    497 	if (s != NULL)
    498 		err |= nvlist_add_string(fmri, FM_FMRI_CPU_SERIAL_ID, s);
    499 	if (err != 0) {
    500 		nvlist_free(fmri);
    501 		(void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
    502 		return (NULL);
    503 	}
    504 
    505 	return (fmri);
    506 }
    507 
    508 /*ARGSUSED*/
    509 static int
    510 cpu_fmri_asru(topo_mod_t *mod, tnode_t *node, topo_version_t version,
    511     nvlist_t *in, nvlist_t **out)
    512 {
    513 	int rc;
    514 	uint32_t cpu_id;
    515 	uint8_t cpumask = 0;
    516 	char *serial = NULL;
    517 
    518 	if ((rc = nvlist_lookup_uint32(in, FM_FMRI_CPU_ID, &cpu_id)) != 0) {
    519 		if (rc == ENOENT)
    520 			return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
    521 		else
    522 			return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
    523 	}
    524 
    525 	(void) nvlist_lookup_string(in, FM_FMRI_CPU_SERIAL_ID, &serial);
    526 	(void) nvlist_lookup_uint8(in, FM_FMRI_CPU_MASK, &cpumask);
    527 
    528 	*out = fmri_create(mod, cpu_id, cpumask, serial);
    529 
    530 	return (0);
    531 }
    532 
    533 /*ARGSUSED*/
    534 static int
    535 cpu_fmri_create_meth(topo_mod_t *mod, tnode_t *node, topo_version_t version,
    536     nvlist_t *in, nvlist_t **out)
    537 {
    538 	int		rc;
    539 	nvlist_t	*args;
    540 	uint32_t	cpu_id;
    541 	uint8_t		cpumask = 0;
    542 	char		*serial = NULL;
    543 
    544 	if (version > TOPO_METH_FMRI_VERSION) {
    545 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
    546 	}
    547 
    548 	rc = nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NVL, &args);
    549 	if (rc != 0) {
    550 		/*
    551 		 * This routine requires arguments to be packed in the
    552 		 * format used in topo_fmri_create()
    553 		 */
    554 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
    555 	}
    556 
    557 	if (nvlist_lookup_string(args, FM_FMRI_CPU_SERIAL_ID, &serial) != 0 ||
    558 	    nvlist_lookup_uint32(args, FM_FMRI_CPU_ID, &cpu_id) != 0 ||
    559 	    nvlist_lookup_uint8(args, FM_FMRI_CPU_MASK, &cpumask) != 0) {
    560 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
    561 	}
    562 
    563 	*out = fmri_create(mod, cpu_id, cpumask, serial);
    564 	if (*out == NULL) {
    565 		return (-1);
    566 	}
    567 
    568 	return (0);
    569 }
    570