17aec1d6eScindi /* 27aec1d6eScindi * CDDL HEADER START 37aec1d6eScindi * 47aec1d6eScindi * The contents of this file are subject to the terms of the 580ab886dSwesolows * Common Development and Distribution License (the "License"). 680ab886dSwesolows * You may not use this file except in compliance with the License. 77aec1d6eScindi * 87aec1d6eScindi * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97aec1d6eScindi * or http://www.opensolaris.org/os/licensing. 107aec1d6eScindi * See the License for the specific language governing permissions 117aec1d6eScindi * and limitations under the License. 127aec1d6eScindi * 137aec1d6eScindi * When distributing Covered Code, include this CDDL HEADER in each 147aec1d6eScindi * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157aec1d6eScindi * If applicable, add the following below this CDDL HEADER, with the 167aec1d6eScindi * fields enclosed by brackets "[]" replaced with your own identifying 177aec1d6eScindi * information: Portions Copyright [yyyy] [name of copyright owner] 187aec1d6eScindi * 197aec1d6eScindi * CDDL HEADER END 207aec1d6eScindi */ 2180ab886dSwesolows 227aec1d6eScindi /* 23*a62774dfSSinanallur Balasubramanian * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247aec1d6eScindi * Use is subject to license terms. 257aec1d6eScindi */ 267aec1d6eScindi 27*a62774dfSSinanallur Balasubramanian 287aec1d6eScindi #include <errno.h> 297aec1d6eScindi #include <limits.h> 307aec1d6eScindi #include <strings.h> 317aec1d6eScindi #include <unistd.h> 3214ea4bb7Ssd77468 #include <topo_error.h> 337aec1d6eScindi #include <fm/topo_mod.h> 347aec1d6eScindi #include <sys/fm/protocol.h> 357aec1d6eScindi 360eb822a1Scindi #include <topo_method.h> 370eb822a1Scindi #include <cpu.h> 387aec1d6eScindi 3914ea4bb7Ssd77468 /* 4014ea4bb7Ssd77468 * platform specific cpu module 4114ea4bb7Ssd77468 */ 4214ea4bb7Ssd77468 #define PLATFORM_CPU_VERSION CPU_VERSION 4314ea4bb7Ssd77468 #define PLATFORM_CPU_NAME "platform-cpu" 4414ea4bb7Ssd77468 457aec1d6eScindi static int cpu_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, 460eb822a1Scindi topo_instance_t, void *, void *); 477aec1d6eScindi static void cpu_release(topo_mod_t *, tnode_t *); 487aec1d6eScindi static int cpu_nvl2str(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 497aec1d6eScindi nvlist_t **); 507aec1d6eScindi static int cpu_str2nvl(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 517aec1d6eScindi nvlist_t **); 527aec1d6eScindi static int cpu_fmri_asru(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 537aec1d6eScindi nvlist_t **); 54d5ea2cedSScott Davenport static int cpu_fmri_create_meth(topo_mod_t *, tnode_t *, topo_version_t, 55d5ea2cedSScott Davenport nvlist_t *, nvlist_t **); 567aec1d6eScindi static nvlist_t *fmri_create(topo_mod_t *, uint32_t, uint8_t, char *); 577aec1d6eScindi 587aec1d6eScindi static const topo_method_t cpu_methods[] = { 597aec1d6eScindi { TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION, 607aec1d6eScindi TOPO_STABILITY_INTERNAL, cpu_nvl2str }, 617aec1d6eScindi { TOPO_METH_STR2NVL, TOPO_METH_STR2NVL_DESC, TOPO_METH_STR2NVL_VERSION, 627aec1d6eScindi TOPO_STABILITY_INTERNAL, cpu_str2nvl }, 637aec1d6eScindi { TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC, 647aec1d6eScindi TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL, 657aec1d6eScindi cpu_fmri_asru }, 660eb822a1Scindi { TOPO_METH_FMRI, TOPO_METH_FMRI_DESC, TOPO_METH_FMRI_VERSION, 67d5ea2cedSScott Davenport TOPO_STABILITY_INTERNAL, cpu_fmri_create_meth }, 687aec1d6eScindi { NULL } 697aec1d6eScindi }; 707aec1d6eScindi 710eb822a1Scindi static const topo_modops_t cpu_ops = 720eb822a1Scindi { cpu_enum, cpu_release }; 737aec1d6eScindi 740eb822a1Scindi static const topo_modinfo_t cpu_info = 750eb822a1Scindi { "cpu", FM_FMRI_SCHEME_CPU, CPU_VERSION, &cpu_ops }; 760eb822a1Scindi 770eb822a1Scindi int 780eb822a1Scindi cpu_init(topo_mod_t *mod, topo_version_t version) 797aec1d6eScindi { 807aec1d6eScindi cpu_node_t *cpuip; 817aec1d6eScindi 820eb822a1Scindi if (getenv("TOPOCPUDEBUG")) 830eb822a1Scindi topo_mod_setdebug(mod); 847aec1d6eScindi topo_mod_dprintf(mod, "initializing cpu builtin\n"); 857aec1d6eScindi 860eb822a1Scindi if (version != CPU_VERSION) 870eb822a1Scindi return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 880eb822a1Scindi 897aec1d6eScindi if ((cpuip = topo_mod_zalloc(mod, sizeof (cpu_node_t))) == NULL) 900eb822a1Scindi return (topo_mod_seterrno(mod, EMOD_NOMEM)); 917aec1d6eScindi 927aec1d6eScindi if ((cpuip->cn_kc = kstat_open()) == NULL) { 937aec1d6eScindi topo_mod_dprintf(mod, "kstat_open failed: %s\n", 947aec1d6eScindi strerror(errno)); 957aec1d6eScindi topo_mod_free(mod, cpuip, sizeof (cpu_node_t)); 960eb822a1Scindi return (-1); 977aec1d6eScindi } 987aec1d6eScindi 997aec1d6eScindi cpuip->cn_ncpustats = sysconf(_SC_CPUID_MAX); 1007aec1d6eScindi if ((cpuip->cn_cpustats = topo_mod_zalloc(mod, ( 1017aec1d6eScindi cpuip->cn_ncpustats + 1) * sizeof (kstat_t *))) == NULL) { 1027aec1d6eScindi (void) kstat_close(cpuip->cn_kc); 1037aec1d6eScindi topo_mod_free(mod, cpuip, sizeof (cpu_node_t)); 1040eb822a1Scindi return (-1); 1057aec1d6eScindi } 1067aec1d6eScindi 1070eb822a1Scindi if (topo_mod_register(mod, &cpu_info, TOPO_VERSION) != 0) { 1087aec1d6eScindi topo_mod_dprintf(mod, "failed to register cpu_info: " 1097aec1d6eScindi "%s\n", topo_mod_errmsg(mod)); 1107aec1d6eScindi topo_mod_free(mod, cpuip->cn_cpustats, 1117aec1d6eScindi (cpuip->cn_ncpustats + 1) * sizeof (kstat_t *)); 1127aec1d6eScindi (void) kstat_close(cpuip->cn_kc); 1137aec1d6eScindi topo_mod_free(mod, cpuip, sizeof (cpu_node_t)); 1140eb822a1Scindi return (-1); 1157aec1d6eScindi } 1160eb822a1Scindi 1170eb822a1Scindi topo_mod_setspecific(mod, (void *)cpuip); 1180eb822a1Scindi 1190eb822a1Scindi return (0); 1207aec1d6eScindi } 1217aec1d6eScindi 1227aec1d6eScindi void 1237aec1d6eScindi cpu_fini(topo_mod_t *mod) 1247aec1d6eScindi { 1257aec1d6eScindi cpu_node_t *cpuip; 1267aec1d6eScindi 1270eb822a1Scindi cpuip = topo_mod_getspecific(mod); 1287aec1d6eScindi 1297aec1d6eScindi if (cpuip->cn_cpustats != NULL) 1307aec1d6eScindi topo_mod_free(mod, cpuip->cn_cpustats, 1317aec1d6eScindi (cpuip->cn_ncpustats + 1) * sizeof (kstat_t *)); 1327aec1d6eScindi 1337aec1d6eScindi (void) kstat_close(cpuip->cn_kc); 1347aec1d6eScindi topo_mod_free(mod, cpuip, sizeof (cpu_node_t)); 1357aec1d6eScindi 1367aec1d6eScindi topo_mod_unregister(mod); 1377aec1d6eScindi } 1387aec1d6eScindi 1397aec1d6eScindi static int 1407aec1d6eScindi cpu_kstat_init(cpu_node_t *cpuip, int i) 1417aec1d6eScindi { 1427aec1d6eScindi kstat_t *ksp; 1437aec1d6eScindi 1447aec1d6eScindi if (cpuip->cn_cpustats[i] == NULL) { 1457aec1d6eScindi if ((ksp = kstat_lookup(cpuip->cn_kc, "cpu_info", i, NULL)) == 1467aec1d6eScindi NULL || kstat_read(cpuip->cn_kc, ksp, NULL) < 0) 1477aec1d6eScindi return (-1); 1487aec1d6eScindi 1497aec1d6eScindi cpuip->cn_cpustats[i] = ksp; 1507aec1d6eScindi } else { 1517aec1d6eScindi ksp = cpuip->cn_cpustats[i]; 1527aec1d6eScindi } 1537aec1d6eScindi 1547aec1d6eScindi return (ksp->ks_instance); 1557aec1d6eScindi } 1567aec1d6eScindi 1577aec1d6eScindi /*ARGSUSED*/ 1587aec1d6eScindi static int 1597aec1d6eScindi cpu_create(topo_mod_t *mod, tnode_t *rnode, const char *name, 1607aec1d6eScindi topo_instance_t min, topo_instance_t max, cpu_node_t *cpuip) 1617aec1d6eScindi { 1627aec1d6eScindi int i; 1637aec1d6eScindi processorid_t cpu_id; 1647aec1d6eScindi char *s, sbuf[21]; 1657aec1d6eScindi kstat_named_t *ks; 1667aec1d6eScindi nvlist_t *fmri; 1677aec1d6eScindi 1687aec1d6eScindi for (i = 0; i <= cpuip->cn_ncpustats; i++) { 1697aec1d6eScindi 1707aec1d6eScindi if ((cpu_id = cpu_kstat_init(cpuip, i)) < 0) 1717aec1d6eScindi continue; 1727aec1d6eScindi 1737aec1d6eScindi if ((ks = kstat_data_lookup(cpuip->cn_cpustats[i], 1747aec1d6eScindi "device_ID")) != NULL) { 1757aec1d6eScindi (void) snprintf(sbuf, 21, "%llX", ks->value.ui64); 1767aec1d6eScindi s = sbuf; 1777aec1d6eScindi } else { 1787aec1d6eScindi s = NULL; 1797aec1d6eScindi } 1807aec1d6eScindi 1817aec1d6eScindi if ((fmri = fmri_create(mod, cpu_id, 0, s)) == NULL) 1827aec1d6eScindi continue; 1830eb822a1Scindi (void) topo_node_bind(mod, rnode, name, cpu_id, fmri); 1847aec1d6eScindi nvlist_free(fmri); 1857aec1d6eScindi } 1867aec1d6eScindi 1877aec1d6eScindi return (0); 1887aec1d6eScindi } 1897aec1d6eScindi 1907aec1d6eScindi 1917aec1d6eScindi /*ARGSUSED*/ 1927aec1d6eScindi static int 1937aec1d6eScindi cpu_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, 1940eb822a1Scindi topo_instance_t min, topo_instance_t max, void *arg, void *notused2) 1957aec1d6eScindi { 19614ea4bb7Ssd77468 topo_mod_t *nmp; 1977aec1d6eScindi cpu_node_t *cpuip = (cpu_node_t *)arg; 1987aec1d6eScindi 19914ea4bb7Ssd77468 if ((nmp = topo_mod_load(mod, PLATFORM_CPU_NAME, 20014ea4bb7Ssd77468 PLATFORM_CPU_VERSION)) == NULL) { 20114ea4bb7Ssd77468 if (topo_mod_errno(mod) == ETOPO_MOD_NOENT) { 20214ea4bb7Ssd77468 /* 20314ea4bb7Ssd77468 * There is no platform specific cpu module, so use 20414ea4bb7Ssd77468 * the default enumeration with kstats of this builtin 20514ea4bb7Ssd77468 * cpu module. 20614ea4bb7Ssd77468 */ 20714ea4bb7Ssd77468 if (topo_node_range_create(mod, pnode, name, 0, 2087aec1d6eScindi cpuip->cn_ncpustats + 1) < 0) { 20914ea4bb7Ssd77468 topo_mod_dprintf(mod, 21014ea4bb7Ssd77468 "cpu enumeration failed to create " 21114ea4bb7Ssd77468 "cpu range [0-%d]: %s\n", 21214ea4bb7Ssd77468 cpuip->cn_ncpustats + 1, 2137aec1d6eScindi topo_mod_errmsg(mod)); 2147aec1d6eScindi return (-1); /* mod_errno set */ 2157aec1d6eScindi } 21614ea4bb7Ssd77468 (void) topo_method_register(mod, pnode, cpu_methods); 21714ea4bb7Ssd77468 return (cpu_create(mod, pnode, name, min, max, cpuip)); 2187aec1d6eScindi 21914ea4bb7Ssd77468 } else { 22014ea4bb7Ssd77468 /* Fail to load the module */ 22114ea4bb7Ssd77468 topo_mod_dprintf(mod, 22214ea4bb7Ssd77468 "Failed to load module %s: %s", 22314ea4bb7Ssd77468 PLATFORM_CPU_NAME, 22414ea4bb7Ssd77468 topo_mod_errmsg(mod)); 22514ea4bb7Ssd77468 return (-1); 22614ea4bb7Ssd77468 } 22714ea4bb7Ssd77468 } 22814ea4bb7Ssd77468 22914ea4bb7Ssd77468 if (topo_mod_enumerate(nmp, pnode, PLATFORM_CPU_NAME, name, 23014ea4bb7Ssd77468 min, max, NULL) < 0) { 23114ea4bb7Ssd77468 topo_mod_dprintf(mod, 23214ea4bb7Ssd77468 "%s failed to enumerate: %s", 23314ea4bb7Ssd77468 PLATFORM_CPU_NAME, 23414ea4bb7Ssd77468 topo_mod_errmsg(mod)); 23514ea4bb7Ssd77468 return (-1); 23614ea4bb7Ssd77468 } 2377aec1d6eScindi (void) topo_method_register(mod, pnode, cpu_methods); 2387aec1d6eScindi 23914ea4bb7Ssd77468 return (0); 2407aec1d6eScindi } 2417aec1d6eScindi 2427aec1d6eScindi static void 2437aec1d6eScindi cpu_release(topo_mod_t *mod, tnode_t *node) 2447aec1d6eScindi { 2457aec1d6eScindi topo_method_unregister_all(mod, node); 2467aec1d6eScindi } 2477aec1d6eScindi 2487aec1d6eScindi ssize_t 2497aec1d6eScindi fmri_nvl2str(nvlist_t *nvl, uint8_t version, char *buf, size_t buflen) 2507aec1d6eScindi { 2517aec1d6eScindi int rc; 2527bebe46cSjc25722 uint8_t type; 253*a62774dfSSinanallur Balasubramanian uint32_t cpuid, way; 254*a62774dfSSinanallur Balasubramanian uint32_t index; 255*a62774dfSSinanallur Balasubramanian uint16_t bit; 2567aec1d6eScindi uint64_t serint; 2577bebe46cSjc25722 char *serstr = NULL; 2587aec1d6eScindi 2597aec1d6eScindi if (version == CPU_SCHEME_VERSION0) { 2607aec1d6eScindi if (nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0 || 2617aec1d6eScindi nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, &serint) 2627aec1d6eScindi != 0) 2637aec1d6eScindi return (0); 2647aec1d6eScindi 2657aec1d6eScindi return (snprintf(buf, buflen, "cpu:///%s=%u/%s=%llX", 2667aec1d6eScindi FM_FMRI_CPU_ID, cpuid, FM_FMRI_CPU_SERIAL_ID, 2677aec1d6eScindi (u_longlong_t)serint)); 2687bebe46cSjc25722 2697aec1d6eScindi } else if (version == CPU_SCHEME_VERSION1) { 2707aec1d6eScindi if (nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0) 2717aec1d6eScindi return (0); 2727aec1d6eScindi 2737aec1d6eScindi /* 2747aec1d6eScindi * Serial number is an optional element 2757aec1d6eScindi */ 2767aec1d6eScindi if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID, 2777aec1d6eScindi &serstr)) != 0) 2787bebe46cSjc25722 2797bebe46cSjc25722 if (rc != ENOENT) 2807bebe46cSjc25722 return (0); 2817bebe46cSjc25722 2827bebe46cSjc25722 /* 2837bebe46cSjc25722 * Cache index, way and type are optional elements 2847bebe46cSjc25722 * But if we have one of them, we must have them all. 2857bebe46cSjc25722 */ 2867bebe46cSjc25722 rc = nvlist_lookup_uint32(nvl, FM_FMRI_CPU_CACHE_INDEX, 2877bebe46cSjc25722 &index); 2887bebe46cSjc25722 rc |= nvlist_lookup_uint32(nvl, FM_FMRI_CPU_CACHE_WAY, &way); 289*a62774dfSSinanallur Balasubramanian rc |= nvlist_lookup_uint16(nvl, FM_FMRI_CPU_CACHE_BIT, &bit); 2907bebe46cSjc25722 rc |= nvlist_lookup_uint8(nvl, FM_FMRI_CPU_CACHE_TYPE, &type); 2917bebe46cSjc25722 2927bebe46cSjc25722 /* Insure there were no errors accessing the nvl */ 2937bebe46cSjc25722 if (rc != 0 && rc != ENOENT) 2947bebe46cSjc25722 return (0); 2957bebe46cSjc25722 2967bebe46cSjc25722 if (serstr == NULL) { 2977bebe46cSjc25722 /* If we have a serial string and no cache info */ 2987aec1d6eScindi if (rc == ENOENT) 2997aec1d6eScindi return (snprintf(buf, buflen, "cpu:///%s=%u", 3007aec1d6eScindi FM_FMRI_CPU_ID, cpuid)); 3017bebe46cSjc25722 else { 3027bebe46cSjc25722 return (snprintf(buf, buflen, 303*a62774dfSSinanallur Balasubramanian "cpu:///%s=%u/%s=%u/%s=%u/%s=%d/%s=%d", 3047bebe46cSjc25722 FM_FMRI_CPU_ID, cpuid, 3057bebe46cSjc25722 FM_FMRI_CPU_CACHE_INDEX, index, 3067bebe46cSjc25722 FM_FMRI_CPU_CACHE_WAY, way, 307*a62774dfSSinanallur Balasubramanian FM_FMRI_CPU_CACHE_BIT, bit, 3087bebe46cSjc25722 FM_FMRI_CPU_CACHE_TYPE, type)); 3097aec1d6eScindi } 3107bebe46cSjc25722 } else { 3117bebe46cSjc25722 if (rc == ENOENT) { 3127bebe46cSjc25722 return (snprintf(buf, buflen, 3137bebe46cSjc25722 "cpu:///%s=%u/%s=%s", 3147bebe46cSjc25722 FM_FMRI_CPU_ID, cpuid, 3157bebe46cSjc25722 FM_FMRI_CPU_SERIAL_ID, serstr)); 3167bebe46cSjc25722 } else { 3177bebe46cSjc25722 return (snprintf(buf, buflen, 318*a62774dfSSinanallur Balasubramanian "cpu:///%s=%u/%s=%s/%s=%u/%s=%u/%s=%d/%s=%d", 3197bebe46cSjc25722 FM_FMRI_CPU_ID, cpuid, 3207bebe46cSjc25722 FM_FMRI_CPU_SERIAL_ID, serstr, 3217bebe46cSjc25722 FM_FMRI_CPU_CACHE_INDEX, index, 3227bebe46cSjc25722 FM_FMRI_CPU_CACHE_WAY, way, 323*a62774dfSSinanallur Balasubramanian FM_FMRI_CPU_CACHE_BIT, bit, 3247bebe46cSjc25722 FM_FMRI_CPU_CACHE_TYPE, type)); 3257bebe46cSjc25722 } 3267bebe46cSjc25722 } 3277bebe46cSjc25722 } else 3287bebe46cSjc25722 return (0); 3297aec1d6eScindi } 3307aec1d6eScindi 3317aec1d6eScindi /*ARGSUSED*/ 3327aec1d6eScindi static int 3337aec1d6eScindi cpu_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version, 3347aec1d6eScindi nvlist_t *in, nvlist_t **out) 3357aec1d6eScindi { 3367aec1d6eScindi uint8_t fver; 3377aec1d6eScindi ssize_t len; 3387aec1d6eScindi char *name; 3397aec1d6eScindi 3407aec1d6eScindi if (version > TOPO_METH_NVL2STR_VERSION) 3417aec1d6eScindi return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 3427aec1d6eScindi 3437aec1d6eScindi if (nvlist_lookup_uint8(in, FM_VERSION, &fver) != 0) 3447aec1d6eScindi return (topo_mod_seterrno(mod, EMOD_FMRI_VERSION)); 3457aec1d6eScindi 3467aec1d6eScindi if ((len = fmri_nvl2str(in, fver, NULL, 0)) == 0 || 3477aec1d6eScindi (name = topo_mod_alloc(mod, len + 1)) == NULL || 3487aec1d6eScindi fmri_nvl2str(in, fver, name, len + 1) == 0) 3497aec1d6eScindi return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 3507aec1d6eScindi 3517aec1d6eScindi if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) < 0) { 3527aec1d6eScindi topo_mod_free(mod, name, len + 1); 3537aec1d6eScindi return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 3547aec1d6eScindi } 3557aec1d6eScindi 3567aec1d6eScindi if (nvlist_add_string(*out, "fmri-string", name) != 0) { 3577aec1d6eScindi topo_mod_free(mod, name, len + 1); 3587aec1d6eScindi return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 3597aec1d6eScindi } 3607aec1d6eScindi topo_mod_free(mod, name, len + 1); 3617aec1d6eScindi 3627aec1d6eScindi return (0); 3637aec1d6eScindi } 3647aec1d6eScindi 3657aec1d6eScindi /*ARGSUSED*/ 3667aec1d6eScindi static int 3677aec1d6eScindi cpu_str2nvl(topo_mod_t *mod, tnode_t *node, topo_version_t version, 3687aec1d6eScindi nvlist_t *in, nvlist_t **out) 3697aec1d6eScindi { 3707aec1d6eScindi int err; 37180ab886dSwesolows ulong_t cpuid; 372*a62774dfSSinanallur Balasubramanian uint8_t type = 0; 373*a62774dfSSinanallur Balasubramanian uint32_t way = 0; 374*a62774dfSSinanallur Balasubramanian uint32_t index = 0; 375*a62774dfSSinanallur Balasubramanian int index_present = 0; 376*a62774dfSSinanallur Balasubramanian uint16_t bit = 0; 3777bebe46cSjc25722 char *str, *s, *end, *serial_end; 3787aec1d6eScindi char *serial = NULL; 3797aec1d6eScindi nvlist_t *fmri; 3807aec1d6eScindi 3817aec1d6eScindi if (version > TOPO_METH_STR2NVL_VERSION) 3827aec1d6eScindi return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 3837aec1d6eScindi 3847aec1d6eScindi if (nvlist_lookup_string(in, "fmri-string", &str) != 0) 3857aec1d6eScindi return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 3867aec1d6eScindi 3877aec1d6eScindi /* We're expecting a string version of a cpu scheme FMRI */ 3887aec1d6eScindi if (strncmp(str, "cpu:///", 7) != 0) 3897aec1d6eScindi return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 3907aec1d6eScindi 3917aec1d6eScindi s = strchr(str + 7, '='); 3927aec1d6eScindi if (s == NULL) 3937aec1d6eScindi return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 3947aec1d6eScindi 3957aec1d6eScindi ++s; 3967aec1d6eScindi cpuid = strtoul(s, &end, 0); 3977aec1d6eScindi 3987aec1d6eScindi if (cpuid == ULONG_MAX && errno == ERANGE) 3997aec1d6eScindi return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 4007aec1d6eScindi 4017bebe46cSjc25722 /* If there is a serial #, then there might also be cache data */ 4027aec1d6eScindi if (*(s = end) == '/') { 4037aec1d6eScindi s = strchr(s, '='); 4047aec1d6eScindi ++s; 4057aec1d6eScindi serial = s; 4067bebe46cSjc25722 serial_end = strchr(s, '/'); 4077bebe46cSjc25722 /* If there is cache data, all must be present */ 408*a62774dfSSinanallur Balasubramanian if (serial_end != NULL) { 409*a62774dfSSinanallur Balasubramanian /* Now terminate the serial string */ 410*a62774dfSSinanallur Balasubramanian *serial_end = '\0'; 411*a62774dfSSinanallur Balasubramanian index_present = 1; 412*a62774dfSSinanallur Balasubramanian s = serial_end + 1; 4137bebe46cSjc25722 s = strchr(s, '='); 4147bebe46cSjc25722 ++s; 4157bebe46cSjc25722 index = strtoul(s, &end, 0); 4167bebe46cSjc25722 if (*(s = end) != '/') { 4177bebe46cSjc25722 return (topo_mod_seterrno(mod, 4187bebe46cSjc25722 EMOD_FMRI_MALFORM)); 4197bebe46cSjc25722 } 4207bebe46cSjc25722 s = strchr(s, '='); 421*a62774dfSSinanallur Balasubramanian if (s == NULL) { 422*a62774dfSSinanallur Balasubramanian return (topo_mod_seterrno(mod, 423*a62774dfSSinanallur Balasubramanian EMOD_FMRI_MALFORM)); 424*a62774dfSSinanallur Balasubramanian } 4257bebe46cSjc25722 ++s; 4267bebe46cSjc25722 way = strtoul(s, &end, 0); 4277bebe46cSjc25722 if (*(s = end) != '/') { 4287bebe46cSjc25722 return (topo_mod_seterrno(mod, 4297bebe46cSjc25722 EMOD_FMRI_MALFORM)); 4307bebe46cSjc25722 } 4317bebe46cSjc25722 s = strchr(s, '='); 432*a62774dfSSinanallur Balasubramanian if (s == NULL) { 433*a62774dfSSinanallur Balasubramanian return (topo_mod_seterrno(mod, 434*a62774dfSSinanallur Balasubramanian EMOD_FMRI_MALFORM)); 435*a62774dfSSinanallur Balasubramanian } 4367bebe46cSjc25722 ++s; 437*a62774dfSSinanallur Balasubramanian bit = strtoul(s, &end, 0); 4387bebe46cSjc25722 if (*(s = end) != '/') { 4397bebe46cSjc25722 return (topo_mod_seterrno(mod, 4407bebe46cSjc25722 EMOD_FMRI_MALFORM)); 4417bebe46cSjc25722 } 442*a62774dfSSinanallur Balasubramanian s = strchr(s, '='); 443*a62774dfSSinanallur Balasubramanian if (s == NULL) { 444*a62774dfSSinanallur Balasubramanian return (topo_mod_seterrno(mod, 445*a62774dfSSinanallur Balasubramanian EMOD_FMRI_MALFORM)); 4467bebe46cSjc25722 } 447*a62774dfSSinanallur Balasubramanian ++s; 448*a62774dfSSinanallur Balasubramanian type = strtoul(s, &end, 0); 4497aec1d6eScindi } 4507aec1d6eScindi 451*a62774dfSSinanallur Balasubramanian } 4527aec1d6eScindi if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0) 4537aec1d6eScindi return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 4547aec1d6eScindi 4557aec1d6eScindi err = nvlist_add_uint8(fmri, FM_VERSION, CPU_SCHEME_VERSION1); 4567aec1d6eScindi err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU); 45780ab886dSwesolows err |= nvlist_add_uint32(fmri, FM_FMRI_CPU_ID, (uint32_t)cpuid); 4587aec1d6eScindi err |= nvlist_add_uint8(fmri, FM_FMRI_CPU_MASK, 0); 4597aec1d6eScindi if (serial != NULL) 4607aec1d6eScindi err |= nvlist_add_string(fmri, FM_FMRI_CPU_SERIAL_ID, 4617aec1d6eScindi serial); 4627aec1d6eScindi 463*a62774dfSSinanallur Balasubramanian if (index_present) { 4647bebe46cSjc25722 err |= nvlist_add_uint32(fmri, FM_FMRI_CPU_CACHE_INDEX, 4657bebe46cSjc25722 index); 4667bebe46cSjc25722 err |= nvlist_add_uint32(fmri, FM_FMRI_CPU_CACHE_WAY, 4677bebe46cSjc25722 way); 468*a62774dfSSinanallur Balasubramanian err |= nvlist_add_uint16(fmri, FM_FMRI_CPU_CACHE_BIT, 469*a62774dfSSinanallur Balasubramanian bit); 4707bebe46cSjc25722 err |= nvlist_add_uint8(fmri, FM_FMRI_CPU_CACHE_TYPE, 4717bebe46cSjc25722 type); 4727bebe46cSjc25722 } 4737aec1d6eScindi if (err != 0) { 4747aec1d6eScindi nvlist_free(fmri); 4757aec1d6eScindi return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 4767aec1d6eScindi } 4777aec1d6eScindi *out = fmri; 4787aec1d6eScindi 4797aec1d6eScindi return (0); 4807aec1d6eScindi } 4817aec1d6eScindi 4827aec1d6eScindi static nvlist_t * 4837aec1d6eScindi fmri_create(topo_mod_t *mod, uint32_t cpu_id, uint8_t cpumask, char *s) 4847aec1d6eScindi { 4857aec1d6eScindi int err; 4867aec1d6eScindi nvlist_t *fmri; 4877aec1d6eScindi 4887aec1d6eScindi if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0) { 4897aec1d6eScindi (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL); 4907aec1d6eScindi return (NULL); 4917aec1d6eScindi } 4927aec1d6eScindi 4937aec1d6eScindi err = nvlist_add_uint8(fmri, FM_VERSION, FM_CPU_SCHEME_VERSION); 4947aec1d6eScindi err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU); 4957aec1d6eScindi err |= nvlist_add_uint32(fmri, FM_FMRI_CPU_ID, cpu_id); 4967aec1d6eScindi err |= nvlist_add_uint8(fmri, FM_FMRI_CPU_MASK, cpumask); 4977aec1d6eScindi if (s != NULL) 4987aec1d6eScindi err |= nvlist_add_string(fmri, FM_FMRI_CPU_SERIAL_ID, s); 4997aec1d6eScindi if (err != 0) { 5007aec1d6eScindi nvlist_free(fmri); 5017aec1d6eScindi (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL); 5027aec1d6eScindi return (NULL); 5037aec1d6eScindi } 5047aec1d6eScindi 5057aec1d6eScindi return (fmri); 5067aec1d6eScindi } 5077aec1d6eScindi 5087aec1d6eScindi /*ARGSUSED*/ 5097aec1d6eScindi static int 5107aec1d6eScindi cpu_fmri_asru(topo_mod_t *mod, tnode_t *node, topo_version_t version, 5117aec1d6eScindi nvlist_t *in, nvlist_t **out) 5127aec1d6eScindi { 5137aec1d6eScindi int rc; 5147aec1d6eScindi uint32_t cpu_id; 5157aec1d6eScindi uint8_t cpumask = 0; 5167aec1d6eScindi char *serial = NULL; 5177aec1d6eScindi 5187aec1d6eScindi if ((rc = nvlist_lookup_uint32(in, FM_FMRI_CPU_ID, &cpu_id)) != 0) { 5197aec1d6eScindi if (rc == ENOENT) 5207aec1d6eScindi return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 5217aec1d6eScindi else 5227aec1d6eScindi return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 5237aec1d6eScindi } 5247aec1d6eScindi 5257aec1d6eScindi (void) nvlist_lookup_string(in, FM_FMRI_CPU_SERIAL_ID, &serial); 5267aec1d6eScindi (void) nvlist_lookup_uint8(in, FM_FMRI_CPU_MASK, &cpumask); 5277aec1d6eScindi 5287aec1d6eScindi *out = fmri_create(mod, cpu_id, cpumask, serial); 5297aec1d6eScindi 5307aec1d6eScindi return (0); 5317aec1d6eScindi } 532d5ea2cedSScott Davenport 533d5ea2cedSScott Davenport /*ARGSUSED*/ 534d5ea2cedSScott Davenport static int 535d5ea2cedSScott Davenport cpu_fmri_create_meth(topo_mod_t *mod, tnode_t *node, topo_version_t version, 536d5ea2cedSScott Davenport nvlist_t *in, nvlist_t **out) 537d5ea2cedSScott Davenport { 538d5ea2cedSScott Davenport int rc; 539d5ea2cedSScott Davenport nvlist_t *args; 540d5ea2cedSScott Davenport uint32_t cpu_id; 541d5ea2cedSScott Davenport uint8_t cpumask = 0; 542d5ea2cedSScott Davenport char *serial = NULL; 543d5ea2cedSScott Davenport 544d5ea2cedSScott Davenport if (version > TOPO_METH_FMRI_VERSION) { 545d5ea2cedSScott Davenport return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 546d5ea2cedSScott Davenport } 547d5ea2cedSScott Davenport 548d5ea2cedSScott Davenport rc = nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NVL, &args); 549d5ea2cedSScott Davenport if (rc != 0) { 550d5ea2cedSScott Davenport /* 551d5ea2cedSScott Davenport * This routine requires arguments to be packed in the 552d5ea2cedSScott Davenport * format used in topo_fmri_create() 553d5ea2cedSScott Davenport */ 554d5ea2cedSScott Davenport return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 555d5ea2cedSScott Davenport } 556d5ea2cedSScott Davenport 557d5ea2cedSScott Davenport if (nvlist_lookup_string(args, FM_FMRI_CPU_SERIAL_ID, &serial) != 0 || 558d5ea2cedSScott Davenport nvlist_lookup_uint32(args, FM_FMRI_CPU_ID, &cpu_id) != 0 || 559d5ea2cedSScott Davenport nvlist_lookup_uint8(args, FM_FMRI_CPU_MASK, &cpumask) != 0) { 560d5ea2cedSScott Davenport return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 561d5ea2cedSScott Davenport } 562d5ea2cedSScott Davenport 563d5ea2cedSScott Davenport *out = fmri_create(mod, cpu_id, cpumask, serial); 564d5ea2cedSScott Davenport if (*out == NULL) { 565d5ea2cedSScott Davenport return (-1); 566d5ea2cedSScott Davenport } 567d5ea2cedSScott Davenport 568d5ea2cedSScott Davenport return (0); 569d5ea2cedSScott Davenport } 570