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>
3214ea4bb7Ssd #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
3914ea4bb7Ssd /*
4014ea4bb7Ssd * platform specific cpu module
4114ea4bb7Ssd */
4214ea4bb7Ssd #define PLATFORM_CPU_VERSION CPU_VERSION
4314ea4bb7Ssd #define PLATFORM_CPU_NAME "platform-cpu"
4414ea4bb7Ssd
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 };
730eb822a1Scindi
747aec1d6eScindi static const topo_modinfo_t cpu_info =
750eb822a1Scindi { "cpu", FM_FMRI_SCHEME_CPU, CPU_VERSION, &cpu_ops };
767aec1d6eScindi
770eb822a1Scindi int
cpu_init(topo_mod_t * mod,topo_version_t version)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
cpu_fini(topo_mod_t * mod)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
cpu_kstat_init(cpu_node_t * cpuip,int i)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
cpu_create(topo_mod_t * mod,tnode_t * rnode,const char * name,topo_instance_t min,topo_instance_t max,cpu_node_t * cpuip)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
cpu_enum(topo_mod_t * mod,tnode_t * pnode,const char * name,topo_instance_t min,topo_instance_t max,void * arg,void * notused2)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 {
19614ea4bb7Ssd topo_mod_t *nmp;
1977aec1d6eScindi cpu_node_t *cpuip = (cpu_node_t *)arg;
1987aec1d6eScindi
19914ea4bb7Ssd if ((nmp = topo_mod_load(mod, PLATFORM_CPU_NAME,
2007bebe46cSjc PLATFORM_CPU_VERSION)) == NULL) {
20114ea4bb7Ssd if (topo_mod_errno(mod) == ETOPO_MOD_NOENT) {
20214ea4bb7Ssd /*
20314ea4bb7Ssd * There is no platform specific cpu module, so use
20414ea4bb7Ssd * the default enumeration with kstats of this builtin
20514ea4bb7Ssd * cpu module.
20614ea4bb7Ssd */
20714ea4bb7Ssd if (topo_node_range_create(mod, pnode, name, 0,
2087bebe46cSjc cpuip->cn_ncpustats + 1) < 0) {
20914ea4bb7Ssd topo_mod_dprintf(mod,
2107bebe46cSjc "cpu enumeration failed to create "
2117bebe46cSjc "cpu range [0-%d]: %s\n",
2127bebe46cSjc cpuip->cn_ncpustats + 1,
2137bebe46cSjc topo_mod_errmsg(mod));
21414ea4bb7Ssd return (-1); /* mod_errno set */
21514ea4bb7Ssd }
21614ea4bb7Ssd (void) topo_method_register(mod, pnode, cpu_methods);
21714ea4bb7Ssd return (cpu_create(mod, pnode, name, min, max, cpuip));
21814ea4bb7Ssd
21914ea4bb7Ssd } else {
22014ea4bb7Ssd /* Fail to load the module */
22114ea4bb7Ssd topo_mod_dprintf(mod,
2227bebe46cSjc "Failed to load module %s: %s",
2237bebe46cSjc PLATFORM_CPU_NAME,
2247bebe46cSjc topo_mod_errmsg(mod));
22514ea4bb7Ssd return (-1);
22614ea4bb7Ssd }
2277aec1d6eScindi }
2287aec1d6eScindi
22914ea4bb7Ssd if (topo_mod_enumerate(nmp, pnode, PLATFORM_CPU_NAME, name,
2307bebe46cSjc min, max, NULL) < 0) {
23114ea4bb7Ssd topo_mod_dprintf(mod,
2327bebe46cSjc "%s failed to enumerate: %s",
2337bebe46cSjc PLATFORM_CPU_NAME,
2347bebe46cSjc topo_mod_errmsg(mod));
23514ea4bb7Ssd return (-1);
23614ea4bb7Ssd }
2377aec1d6eScindi (void) topo_method_register(mod, pnode, cpu_methods);
2387aec1d6eScindi
23914ea4bb7Ssd return (0);
2407aec1d6eScindi }
2417aec1d6eScindi
2427aec1d6eScindi static void
cpu_release(topo_mod_t * mod,tnode_t * node)2437aec1d6eScindi cpu_release(topo_mod_t *mod, tnode_t *node)
2447aec1d6eScindi {
2457aec1d6eScindi topo_method_unregister_all(mod, node);
2467aec1d6eScindi }
2477aec1d6eScindi
2487aec1d6eScindi ssize_t
fmri_nvl2str(nvlist_t * nvl,uint8_t version,char * buf,size_t buflen)2497aec1d6eScindi fmri_nvl2str(nvlist_t *nvl, uint8_t version, char *buf, size_t buflen)
2507aec1d6eScindi {
2517aec1d6eScindi int rc;
2527bebe46cSjc 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;
2577bebe46cSjc 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));
2687bebe46cSjc
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)
2787bebe46cSjc
2797bebe46cSjc if (rc != ENOENT)
2807bebe46cSjc return (0);
2817bebe46cSjc
2827bebe46cSjc /*
2837bebe46cSjc * Cache index, way and type are optional elements
2847bebe46cSjc * But if we have one of them, we must have them all.
2857bebe46cSjc */
2867bebe46cSjc rc = nvlist_lookup_uint32(nvl, FM_FMRI_CPU_CACHE_INDEX,
2877bebe46cSjc &index);
2887bebe46cSjc 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);
2907bebe46cSjc rc |= nvlist_lookup_uint8(nvl, FM_FMRI_CPU_CACHE_TYPE, &type);
2917bebe46cSjc
2927bebe46cSjc /* Insure there were no errors accessing the nvl */
2937bebe46cSjc if (rc != 0 && rc != ENOENT)
2947bebe46cSjc return (0);
2957bebe46cSjc
2967bebe46cSjc if (serstr == NULL) {
2977bebe46cSjc /* 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));
3017bebe46cSjc else {
3027bebe46cSjc return (snprintf(buf, buflen,
303*a62774dfSSinanallur Balasubramanian "cpu:///%s=%u/%s=%u/%s=%u/%s=%d/%s=%d",
3047bebe46cSjc FM_FMRI_CPU_ID, cpuid,
3057bebe46cSjc FM_FMRI_CPU_CACHE_INDEX, index,
3067bebe46cSjc FM_FMRI_CPU_CACHE_WAY, way,
307*a62774dfSSinanallur Balasubramanian FM_FMRI_CPU_CACHE_BIT, bit,
3087bebe46cSjc FM_FMRI_CPU_CACHE_TYPE, type));
3097bebe46cSjc }
3107bebe46cSjc } else {
3117bebe46cSjc if (rc == ENOENT) {
3127bebe46cSjc return (snprintf(buf, buflen,
3137bebe46cSjc "cpu:///%s=%u/%s=%s",
3147bebe46cSjc FM_FMRI_CPU_ID, cpuid,
3157bebe46cSjc FM_FMRI_CPU_SERIAL_ID, serstr));
3167bebe46cSjc } else {
3177bebe46cSjc return (snprintf(buf, buflen,
318*a62774dfSSinanallur Balasubramanian "cpu:///%s=%u/%s=%s/%s=%u/%s=%u/%s=%d/%s=%d",
3197bebe46cSjc FM_FMRI_CPU_ID, cpuid,
3207bebe46cSjc FM_FMRI_CPU_SERIAL_ID, serstr,
3217bebe46cSjc FM_FMRI_CPU_CACHE_INDEX, index,
3227bebe46cSjc FM_FMRI_CPU_CACHE_WAY, way,
323*a62774dfSSinanallur Balasubramanian FM_FMRI_CPU_CACHE_BIT, bit,
3247bebe46cSjc FM_FMRI_CPU_CACHE_TYPE, type));
3257bebe46cSjc }
3267bebe46cSjc }
3277bebe46cSjc } else
3287aec1d6eScindi return (0);
3297aec1d6eScindi }
3307aec1d6eScindi
3317aec1d6eScindi /*ARGSUSED*/
3327aec1d6eScindi static int
cpu_nvl2str(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)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
cpu_str2nvl(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)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;
3777bebe46cSjc 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
4017bebe46cSjc /* 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;
4067bebe46cSjc serial_end = strchr(s, '/');
4077bebe46cSjc /* 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;
4137bebe46cSjc s = strchr(s, '=');
4147bebe46cSjc ++s;
4157bebe46cSjc index = strtoul(s, &end, 0);
4167bebe46cSjc if (*(s = end) != '/') {
4177bebe46cSjc return (topo_mod_seterrno(mod,
4187bebe46cSjc EMOD_FMRI_MALFORM));
4197bebe46cSjc }
4207bebe46cSjc 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 }
4257bebe46cSjc ++s;
4267bebe46cSjc way = strtoul(s, &end, 0);
4277bebe46cSjc if (*(s = end) != '/') {
4287bebe46cSjc return (topo_mod_seterrno(mod,
4297bebe46cSjc EMOD_FMRI_MALFORM));
4307bebe46cSjc }
4317bebe46cSjc 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 }
4367bebe46cSjc ++s;
437*a62774dfSSinanallur Balasubramanian bit = strtoul(s, &end, 0);
4387bebe46cSjc if (*(s = end) != '/') {
4397bebe46cSjc return (topo_mod_seterrno(mod,
4407bebe46cSjc EMOD_FMRI_MALFORM));
4417bebe46cSjc }
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));
446*a62774dfSSinanallur Balasubramanian }
447*a62774dfSSinanallur Balasubramanian ++s;
448*a62774dfSSinanallur Balasubramanian type = strtoul(s, &end, 0);
4497bebe46cSjc }
4507bebe46cSjc
4517aec1d6eScindi }
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) {
4647bebe46cSjc err |= nvlist_add_uint32(fmri, FM_FMRI_CPU_CACHE_INDEX,
4657bebe46cSjc index);
4667bebe46cSjc err |= nvlist_add_uint32(fmri, FM_FMRI_CPU_CACHE_WAY,
4677bebe46cSjc way);
468*a62774dfSSinanallur Balasubramanian err |= nvlist_add_uint16(fmri, FM_FMRI_CPU_CACHE_BIT,
469*a62774dfSSinanallur Balasubramanian bit);
4707bebe46cSjc err |= nvlist_add_uint8(fmri, FM_FMRI_CPU_CACHE_TYPE,
4717bebe46cSjc type);
4727bebe46cSjc }
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 *
fmri_create(topo_mod_t * mod,uint32_t cpu_id,uint8_t cpumask,char * s)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
cpu_fmri_asru(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)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
cpu_fmri_create_meth(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)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