17532SSean.Ye@Sun.COM /* 27532SSean.Ye@Sun.COM * CDDL HEADER START 37532SSean.Ye@Sun.COM * 47532SSean.Ye@Sun.COM * The contents of this file are subject to the terms of the 57532SSean.Ye@Sun.COM * Common Development and Distribution License (the "License"). 67532SSean.Ye@Sun.COM * You may not use this file except in compliance with the License. 77532SSean.Ye@Sun.COM * 87532SSean.Ye@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97532SSean.Ye@Sun.COM * or http://www.opensolaris.org/os/licensing. 107532SSean.Ye@Sun.COM * See the License for the specific language governing permissions 117532SSean.Ye@Sun.COM * and limitations under the License. 127532SSean.Ye@Sun.COM * 137532SSean.Ye@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 147532SSean.Ye@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157532SSean.Ye@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 167532SSean.Ye@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 177532SSean.Ye@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 187532SSean.Ye@Sun.COM * 197532SSean.Ye@Sun.COM * CDDL HEADER END 207532SSean.Ye@Sun.COM */ 217532SSean.Ye@Sun.COM /* 22*10942STom.Pothier@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237532SSean.Ye@Sun.COM * Use is subject to license terms. 247532SSean.Ye@Sun.COM */ 257532SSean.Ye@Sun.COM 267532SSean.Ye@Sun.COM #include <sys/stat.h> 277532SSean.Ye@Sun.COM #include <sys/types.h> 287532SSean.Ye@Sun.COM #include <sys/time.h> 297532SSean.Ye@Sun.COM 307532SSean.Ye@Sun.COM #include <sys/fm/protocol.h> 31*10942STom.Pothier@Sun.COM #include <sys/fm/smb/fmsmb.h> 327532SSean.Ye@Sun.COM #include <sys/devfm.h> 337532SSean.Ye@Sun.COM 347532SSean.Ye@Sun.COM #include <sys/cpu_module.h> 357532SSean.Ye@Sun.COM 367532SSean.Ye@Sun.COM #define ANY_ID (uint_t)-1 377532SSean.Ye@Sun.COM 387532SSean.Ye@Sun.COM /* 397532SSean.Ye@Sun.COM * INIT_HDLS is the initial size of cmi_hdl_t array. We fill the array 407532SSean.Ye@Sun.COM * during cmi_hdl_walk, if the array overflows, we will reallocate 417532SSean.Ye@Sun.COM * a new array twice the size of the old one. 427532SSean.Ye@Sun.COM */ 437532SSean.Ye@Sun.COM #define INIT_HDLS 16 447532SSean.Ye@Sun.COM 457532SSean.Ye@Sun.COM typedef struct fm_cmi_walk_t 467532SSean.Ye@Sun.COM { 477532SSean.Ye@Sun.COM uint_t chipid; /* chipid to match during walk */ 487532SSean.Ye@Sun.COM uint_t coreid; /* coreid to match */ 497532SSean.Ye@Sun.COM uint_t strandid; /* strandid to match */ 507532SSean.Ye@Sun.COM int (*cbfunc)(cmi_hdl_t, void *, void *); /* callback function */ 517532SSean.Ye@Sun.COM cmi_hdl_t *hdls; /* allocated array to save the handles */ 527532SSean.Ye@Sun.COM int nhdl_max; /* allocated array size */ 537532SSean.Ye@Sun.COM int nhdl; /* handles saved */ 547532SSean.Ye@Sun.COM } fm_cmi_walk_t; 557532SSean.Ye@Sun.COM 56*10942STom.Pothier@Sun.COM extern int x86gentopo_legacy; 57*10942STom.Pothier@Sun.COM 587532SSean.Ye@Sun.COM int 597532SSean.Ye@Sun.COM fm_get_paddr(nvlist_t *nvl, uint64_t *paddr) 607532SSean.Ye@Sun.COM { 617532SSean.Ye@Sun.COM uint8_t version; 627532SSean.Ye@Sun.COM uint64_t pa; 637532SSean.Ye@Sun.COM char *scheme; 647532SSean.Ye@Sun.COM int err; 657532SSean.Ye@Sun.COM 667532SSean.Ye@Sun.COM /* Verify FMRI scheme name and version number */ 677532SSean.Ye@Sun.COM if ((nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0) || 687532SSean.Ye@Sun.COM (strcmp(scheme, FM_FMRI_SCHEME_HC) != 0) || 697532SSean.Ye@Sun.COM (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0) || 707532SSean.Ye@Sun.COM version > FM_HC_SCHEME_VERSION) { 717532SSean.Ye@Sun.COM return (EINVAL); 727532SSean.Ye@Sun.COM } 737532SSean.Ye@Sun.COM 747532SSean.Ye@Sun.COM if ((err = cmi_mc_unumtopa(NULL, nvl, &pa)) != CMI_SUCCESS && 757532SSean.Ye@Sun.COM err != CMIERR_MC_PARTIALUNUMTOPA) 767532SSean.Ye@Sun.COM return (EINVAL); 777532SSean.Ye@Sun.COM 787532SSean.Ye@Sun.COM *paddr = pa; 797532SSean.Ye@Sun.COM return (0); 807532SSean.Ye@Sun.COM } 817532SSean.Ye@Sun.COM 827532SSean.Ye@Sun.COM /* 837532SSean.Ye@Sun.COM * Routines for cmi handles walk. 847532SSean.Ye@Sun.COM */ 857532SSean.Ye@Sun.COM 867532SSean.Ye@Sun.COM static void 877532SSean.Ye@Sun.COM walk_init(fm_cmi_walk_t *wp, uint_t chipid, uint_t coreid, uint_t strandid, 887532SSean.Ye@Sun.COM int (*cbfunc)(cmi_hdl_t, void *, void *)) 897532SSean.Ye@Sun.COM { 907532SSean.Ye@Sun.COM wp->chipid = chipid; 917532SSean.Ye@Sun.COM wp->coreid = coreid; 927532SSean.Ye@Sun.COM wp->strandid = strandid; 937532SSean.Ye@Sun.COM /* 947532SSean.Ye@Sun.COM * If callback is not set, we allocate an array to save the 957532SSean.Ye@Sun.COM * cmi handles. 967532SSean.Ye@Sun.COM */ 977532SSean.Ye@Sun.COM if ((wp->cbfunc = cbfunc) == NULL) { 987532SSean.Ye@Sun.COM wp->hdls = kmem_alloc(sizeof (cmi_hdl_t) * INIT_HDLS, KM_SLEEP); 997532SSean.Ye@Sun.COM wp->nhdl_max = INIT_HDLS; 1007532SSean.Ye@Sun.COM wp->nhdl = 0; 1017532SSean.Ye@Sun.COM } 1027532SSean.Ye@Sun.COM } 1037532SSean.Ye@Sun.COM 1047532SSean.Ye@Sun.COM static void 1057532SSean.Ye@Sun.COM walk_fini(fm_cmi_walk_t *wp) 1067532SSean.Ye@Sun.COM { 1077532SSean.Ye@Sun.COM if (wp->cbfunc == NULL) 1087532SSean.Ye@Sun.COM kmem_free(wp->hdls, sizeof (cmi_hdl_t) * wp->nhdl_max); 1097532SSean.Ye@Sun.COM } 1107532SSean.Ye@Sun.COM 1117532SSean.Ye@Sun.COM static int 1127532SSean.Ye@Sun.COM select_cmi_hdl(cmi_hdl_t hdl, void *arg1, void *arg2, void *arg3) 1137532SSean.Ye@Sun.COM { 1147532SSean.Ye@Sun.COM fm_cmi_walk_t *wp = (fm_cmi_walk_t *)arg1; 1157532SSean.Ye@Sun.COM 1167532SSean.Ye@Sun.COM if (wp->chipid != ANY_ID && wp->chipid != cmi_hdl_chipid(hdl)) 1177532SSean.Ye@Sun.COM return (CMI_HDL_WALK_NEXT); 1187532SSean.Ye@Sun.COM if (wp->coreid != ANY_ID && wp->coreid != cmi_hdl_coreid(hdl)) 1197532SSean.Ye@Sun.COM return (CMI_HDL_WALK_NEXT); 1207532SSean.Ye@Sun.COM if (wp->strandid != ANY_ID && wp->strandid != cmi_hdl_strandid(hdl)) 1217532SSean.Ye@Sun.COM return (CMI_HDL_WALK_NEXT); 1227532SSean.Ye@Sun.COM 1237532SSean.Ye@Sun.COM /* 1247532SSean.Ye@Sun.COM * Call the callback function if any exists, otherwise we hold a 1257532SSean.Ye@Sun.COM * reference of the handle and push it to preallocated array. 1267532SSean.Ye@Sun.COM * If the allocated array is going to overflow, reallocate a 1277532SSean.Ye@Sun.COM * bigger one to replace it. 1287532SSean.Ye@Sun.COM */ 1297532SSean.Ye@Sun.COM if (wp->cbfunc != NULL) 1307532SSean.Ye@Sun.COM return (wp->cbfunc(hdl, arg2, arg3)); 1317532SSean.Ye@Sun.COM 1327532SSean.Ye@Sun.COM if (wp->nhdl == wp->nhdl_max) { 1337532SSean.Ye@Sun.COM size_t sz = sizeof (cmi_hdl_t) * wp->nhdl_max; 1347532SSean.Ye@Sun.COM cmi_hdl_t *newarray = kmem_alloc(sz << 1, KM_SLEEP); 1357532SSean.Ye@Sun.COM 1367532SSean.Ye@Sun.COM bcopy(wp->hdls, newarray, sz); 1377532SSean.Ye@Sun.COM kmem_free(wp->hdls, sz); 1387532SSean.Ye@Sun.COM wp->hdls = newarray; 1397532SSean.Ye@Sun.COM wp->nhdl_max <<= 1; 1407532SSean.Ye@Sun.COM } 1417532SSean.Ye@Sun.COM 1427532SSean.Ye@Sun.COM cmi_hdl_hold(hdl); 1437532SSean.Ye@Sun.COM wp->hdls[wp->nhdl++] = hdl; 1447532SSean.Ye@Sun.COM 1457532SSean.Ye@Sun.COM return (CMI_HDL_WALK_NEXT); 1467532SSean.Ye@Sun.COM } 1477532SSean.Ye@Sun.COM 1487532SSean.Ye@Sun.COM static void 1497532SSean.Ye@Sun.COM populate_cpu(nvlist_t **nvlp, cmi_hdl_t hdl) 1507532SSean.Ye@Sun.COM { 151*10942STom.Pothier@Sun.COM uint_t fm_chipid; 152*10942STom.Pothier@Sun.COM uint16_t smbios_id; 153*10942STom.Pothier@Sun.COM 1547532SSean.Ye@Sun.COM (void) nvlist_alloc(nvlp, NV_UNIQUE_NAME, KM_SLEEP); 155*10942STom.Pothier@Sun.COM 156*10942STom.Pothier@Sun.COM /* 157*10942STom.Pothier@Sun.COM * If SMBIOS satisfies FMA Topology needs, gather 158*10942STom.Pothier@Sun.COM * more information on the chip's physical roots 159*10942STom.Pothier@Sun.COM * like /chassis=x/motherboard=y/cpuboard=z and 160*10942STom.Pothier@Sun.COM * set the chip_id to match the SMBIOS' Type 4 161*10942STom.Pothier@Sun.COM * ordering & this has to match the ereport's chip 162*10942STom.Pothier@Sun.COM * resource instance derived off of SMBIOS. 163*10942STom.Pothier@Sun.COM * Multi-Chip-Module support should set the chipid 164*10942STom.Pothier@Sun.COM * in terms of the processor package rather than 165*10942STom.Pothier@Sun.COM * the die/node in the processor package, for FM. 166*10942STom.Pothier@Sun.COM */ 167*10942STom.Pothier@Sun.COM 168*10942STom.Pothier@Sun.COM if (!x86gentopo_legacy) { 169*10942STom.Pothier@Sun.COM smbios_id = cmi_hdl_smbiosid(hdl); 170*10942STom.Pothier@Sun.COM fm_chipid = cmi_hdl_smb_chipid(hdl); 171*10942STom.Pothier@Sun.COM (void) nvlist_add_nvlist(*nvlp, FM_PHYSCPU_INFO_CHIP_ROOTS, 172*10942STom.Pothier@Sun.COM cmi_hdl_smb_bboard(hdl)); 173*10942STom.Pothier@Sun.COM (void) nvlist_add_uint16(*nvlp, FM_PHYSCPU_INFO_SMBIOS_ID, 174*10942STom.Pothier@Sun.COM (uint16_t)smbios_id); 175*10942STom.Pothier@Sun.COM } else 176*10942STom.Pothier@Sun.COM fm_chipid = cmi_hdl_chipid(hdl); 177*10942STom.Pothier@Sun.COM 1787532SSean.Ye@Sun.COM fm_payload_set(*nvlp, 1797532SSean.Ye@Sun.COM FM_PHYSCPU_INFO_VENDOR_ID, DATA_TYPE_STRING, 1807532SSean.Ye@Sun.COM cmi_hdl_vendorstr(hdl), 1817532SSean.Ye@Sun.COM FM_PHYSCPU_INFO_FAMILY, DATA_TYPE_INT32, 1827532SSean.Ye@Sun.COM (int32_t)cmi_hdl_family(hdl), 1837532SSean.Ye@Sun.COM FM_PHYSCPU_INFO_MODEL, DATA_TYPE_INT32, 1847532SSean.Ye@Sun.COM (int32_t)cmi_hdl_model(hdl), 1857532SSean.Ye@Sun.COM FM_PHYSCPU_INFO_STEPPING, DATA_TYPE_INT32, 1867532SSean.Ye@Sun.COM (int32_t)cmi_hdl_stepping(hdl), 1877532SSean.Ye@Sun.COM FM_PHYSCPU_INFO_CHIP_ID, DATA_TYPE_INT32, 188*10942STom.Pothier@Sun.COM (int32_t)fm_chipid, 1897532SSean.Ye@Sun.COM FM_PHYSCPU_INFO_CORE_ID, DATA_TYPE_INT32, 1907532SSean.Ye@Sun.COM (int32_t)cmi_hdl_coreid(hdl), 1917532SSean.Ye@Sun.COM FM_PHYSCPU_INFO_STRAND_ID, DATA_TYPE_INT32, 1927532SSean.Ye@Sun.COM (int32_t)cmi_hdl_strandid(hdl), 193*10942STom.Pothier@Sun.COM FM_PHYSCPU_INFO_STRAND_APICID, DATA_TYPE_INT32, 194*10942STom.Pothier@Sun.COM (int32_t)cmi_hdl_strand_apicid(hdl), 1957532SSean.Ye@Sun.COM FM_PHYSCPU_INFO_CHIP_REV, DATA_TYPE_STRING, 1967532SSean.Ye@Sun.COM cmi_hdl_chiprevstr(hdl), 1977532SSean.Ye@Sun.COM FM_PHYSCPU_INFO_SOCKET_TYPE, DATA_TYPE_UINT32, 1987532SSean.Ye@Sun.COM (uint32_t)cmi_hdl_getsockettype(hdl), 1997532SSean.Ye@Sun.COM FM_PHYSCPU_INFO_CPU_ID, DATA_TYPE_INT32, 2007532SSean.Ye@Sun.COM (int32_t)cmi_hdl_logical_id(hdl), 2017532SSean.Ye@Sun.COM NULL); 2027532SSean.Ye@Sun.COM } 2037532SSean.Ye@Sun.COM 2047532SSean.Ye@Sun.COM /*ARGSUSED*/ 2057532SSean.Ye@Sun.COM int 2067532SSean.Ye@Sun.COM fm_ioctl_physcpu_info(int cmd, nvlist_t *invl, nvlist_t **onvlp) 2077532SSean.Ye@Sun.COM { 2087532SSean.Ye@Sun.COM nvlist_t **cpus, *nvl; 2097532SSean.Ye@Sun.COM int i, err; 2107532SSean.Ye@Sun.COM fm_cmi_walk_t wk; 2117532SSean.Ye@Sun.COM 2127532SSean.Ye@Sun.COM /* 2137532SSean.Ye@Sun.COM * Do a walk to save all the cmi handles in the array. 2147532SSean.Ye@Sun.COM */ 2157532SSean.Ye@Sun.COM walk_init(&wk, ANY_ID, ANY_ID, ANY_ID, NULL); 2167532SSean.Ye@Sun.COM cmi_hdl_walk(select_cmi_hdl, &wk, NULL, NULL); 2177532SSean.Ye@Sun.COM 2187532SSean.Ye@Sun.COM if (wk.nhdl == 0) { 2197532SSean.Ye@Sun.COM walk_fini(&wk); 2207532SSean.Ye@Sun.COM return (ENOENT); 2217532SSean.Ye@Sun.COM } 2227532SSean.Ye@Sun.COM 2237532SSean.Ye@Sun.COM cpus = kmem_alloc(sizeof (nvlist_t *) * wk.nhdl, KM_SLEEP); 2247532SSean.Ye@Sun.COM for (i = 0; i < wk.nhdl; i++) { 2257532SSean.Ye@Sun.COM populate_cpu(cpus + i, wk.hdls[i]); 2267532SSean.Ye@Sun.COM cmi_hdl_rele(wk.hdls[i]); 2277532SSean.Ye@Sun.COM } 2287532SSean.Ye@Sun.COM 2297532SSean.Ye@Sun.COM walk_fini(&wk); 2307532SSean.Ye@Sun.COM 2317532SSean.Ye@Sun.COM (void) nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP); 2327532SSean.Ye@Sun.COM err = nvlist_add_nvlist_array(nvl, FM_PHYSCPU_INFO_CPUS, 2337532SSean.Ye@Sun.COM cpus, wk.nhdl); 2347532SSean.Ye@Sun.COM 2357532SSean.Ye@Sun.COM for (i = 0; i < wk.nhdl; i++) 2367532SSean.Ye@Sun.COM nvlist_free(cpus[i]); 2377532SSean.Ye@Sun.COM kmem_free(cpus, sizeof (nvlist_t *) * wk.nhdl); 2387532SSean.Ye@Sun.COM 2397532SSean.Ye@Sun.COM if (err != 0) { 2407532SSean.Ye@Sun.COM nvlist_free(nvl); 2417532SSean.Ye@Sun.COM return (err); 2427532SSean.Ye@Sun.COM } 2437532SSean.Ye@Sun.COM 2447532SSean.Ye@Sun.COM *onvlp = nvl; 2457532SSean.Ye@Sun.COM return (0); 2467532SSean.Ye@Sun.COM } 2477532SSean.Ye@Sun.COM 2487532SSean.Ye@Sun.COM int 2497532SSean.Ye@Sun.COM fm_ioctl_cpu_retire(int cmd, nvlist_t *invl, nvlist_t **onvlp) 2507532SSean.Ye@Sun.COM { 2517532SSean.Ye@Sun.COM int32_t chipid, coreid, strandid; 2527532SSean.Ye@Sun.COM int rc, new_status, old_status; 2537532SSean.Ye@Sun.COM cmi_hdl_t hdl; 2547532SSean.Ye@Sun.COM nvlist_t *nvl; 2557532SSean.Ye@Sun.COM 2567532SSean.Ye@Sun.COM switch (cmd) { 2577532SSean.Ye@Sun.COM case FM_IOC_CPU_RETIRE: 2587532SSean.Ye@Sun.COM new_status = P_FAULTED; 2597532SSean.Ye@Sun.COM break; 2607532SSean.Ye@Sun.COM case FM_IOC_CPU_STATUS: 2617532SSean.Ye@Sun.COM new_status = P_STATUS; 2627532SSean.Ye@Sun.COM break; 2637532SSean.Ye@Sun.COM case FM_IOC_CPU_UNRETIRE: 2647532SSean.Ye@Sun.COM new_status = P_ONLINE; 2657532SSean.Ye@Sun.COM break; 2667532SSean.Ye@Sun.COM default: 2677532SSean.Ye@Sun.COM return (ENOTTY); 2687532SSean.Ye@Sun.COM } 2697532SSean.Ye@Sun.COM 2707532SSean.Ye@Sun.COM if (nvlist_lookup_int32(invl, FM_CPU_RETIRE_CHIP_ID, &chipid) != 0 || 2717532SSean.Ye@Sun.COM nvlist_lookup_int32(invl, FM_CPU_RETIRE_CORE_ID, &coreid) != 0 || 2727532SSean.Ye@Sun.COM nvlist_lookup_int32(invl, FM_CPU_RETIRE_STRAND_ID, &strandid) != 0) 2737532SSean.Ye@Sun.COM return (EINVAL); 2747532SSean.Ye@Sun.COM 2757532SSean.Ye@Sun.COM hdl = cmi_hdl_lookup(CMI_HDL_NEUTRAL, chipid, coreid, strandid); 2767532SSean.Ye@Sun.COM if (hdl == NULL) 2777532SSean.Ye@Sun.COM return (EINVAL); 2787532SSean.Ye@Sun.COM 2797532SSean.Ye@Sun.COM rc = cmi_hdl_online(hdl, new_status, &old_status); 2807532SSean.Ye@Sun.COM cmi_hdl_rele(hdl); 2817532SSean.Ye@Sun.COM 2827532SSean.Ye@Sun.COM if (rc == 0) { 2837532SSean.Ye@Sun.COM (void) nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP); 2847532SSean.Ye@Sun.COM (void) nvlist_add_int32(nvl, FM_CPU_RETIRE_OLDSTATUS, 2857532SSean.Ye@Sun.COM old_status); 2867532SSean.Ye@Sun.COM *onvlp = nvl; 2877532SSean.Ye@Sun.COM } 2887532SSean.Ye@Sun.COM 2897532SSean.Ye@Sun.COM return (rc); 2907532SSean.Ye@Sun.COM } 291*10942STom.Pothier@Sun.COM 292*10942STom.Pothier@Sun.COM /* 293*10942STom.Pothier@Sun.COM * Retrun the value of x86gentopo_legacy variable as an nvpair. 294*10942STom.Pothier@Sun.COM * 295*10942STom.Pothier@Sun.COM * The caller is responsible for freeing the nvlist. 296*10942STom.Pothier@Sun.COM */ 297*10942STom.Pothier@Sun.COM /* ARGSUSED */ 298*10942STom.Pothier@Sun.COM int 299*10942STom.Pothier@Sun.COM fm_ioctl_gentopo_legacy(int cmd, nvlist_t *invl, nvlist_t **onvlp) 300*10942STom.Pothier@Sun.COM { 301*10942STom.Pothier@Sun.COM nvlist_t *nvl; 302*10942STom.Pothier@Sun.COM 303*10942STom.Pothier@Sun.COM if (cmd != FM_IOC_GENTOPO_LEGACY) { 304*10942STom.Pothier@Sun.COM return (ENOTTY); 305*10942STom.Pothier@Sun.COM } 306*10942STom.Pothier@Sun.COM 307*10942STom.Pothier@Sun.COM /* 308*10942STom.Pothier@Sun.COM * Inform the caller of the intentions of the ereport generators to 309*10942STom.Pothier@Sun.COM * generate either a "generic" or "legacy" x86 topology. 310*10942STom.Pothier@Sun.COM */ 311*10942STom.Pothier@Sun.COM 312*10942STom.Pothier@Sun.COM (void) nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP); 313*10942STom.Pothier@Sun.COM (void) nvlist_add_int32(nvl, FM_GENTOPO_LEGACY, x86gentopo_legacy); 314*10942STom.Pothier@Sun.COM *onvlp = nvl; 315*10942STom.Pothier@Sun.COM 316*10942STom.Pothier@Sun.COM return (0); 317*10942STom.Pothier@Sun.COM } 318