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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 #include <sys/types.h>
30 #include <sys/fm/protocol.h>
31 #include <sys/fm/smb/fmsmb.h>
32 #include <sys/devfm.h>
34 #include <sys/cpu_module.h>
36 #define ANY_ID (uint_t)-1
39 * INIT_HDLS is the initial size of cmi_hdl_t array. We fill the array
40 * during cmi_hdl_walk, if the array overflows, we will reallocate
41 * a new array twice the size of the old one.
45 typedef struct fm_cmi_walk_t
47 uint_t chipid
; /* chipid to match during walk */
48 uint_t coreid
; /* coreid to match */
49 uint_t strandid
; /* strandid to match */
50 int (*cbfunc
)(cmi_hdl_t
, void *, void *); /* callback function */
51 cmi_hdl_t
*hdls
; /* allocated array to save the handles */
52 int nhdl_max
; /* allocated array size */
53 int nhdl
; /* handles saved */
56 extern int x86gentopo_legacy
;
59 fm_get_paddr(nvlist_t
*nvl
, uint64_t *paddr
)
66 /* Verify FMRI scheme name and version number */
67 if ((nvlist_lookup_string(nvl
, FM_FMRI_SCHEME
, &scheme
) != 0) ||
68 (strcmp(scheme
, FM_FMRI_SCHEME_HC
) != 0) ||
69 (nvlist_lookup_uint8(nvl
, FM_VERSION
, &version
) != 0) ||
70 version
> FM_HC_SCHEME_VERSION
) {
74 if ((err
= cmi_mc_unumtopa(NULL
, nvl
, &pa
)) != CMI_SUCCESS
&&
75 err
!= CMIERR_MC_PARTIALUNUMTOPA
)
83 * Routines for cmi handles walk.
87 walk_init(fm_cmi_walk_t
*wp
, uint_t chipid
, uint_t coreid
, uint_t strandid
,
88 int (*cbfunc
)(cmi_hdl_t
, void *, void *))
92 wp
->strandid
= strandid
;
94 * If callback is not set, we allocate an array to save the
97 if ((wp
->cbfunc
= cbfunc
) == NULL
) {
98 wp
->hdls
= kmem_alloc(sizeof (cmi_hdl_t
) * INIT_HDLS
, KM_SLEEP
);
99 wp
->nhdl_max
= INIT_HDLS
;
105 walk_fini(fm_cmi_walk_t
*wp
)
107 if (wp
->cbfunc
== NULL
)
108 kmem_free(wp
->hdls
, sizeof (cmi_hdl_t
) * wp
->nhdl_max
);
112 select_cmi_hdl(cmi_hdl_t hdl
, void *arg1
, void *arg2
, void *arg3
)
114 fm_cmi_walk_t
*wp
= (fm_cmi_walk_t
*)arg1
;
116 if (wp
->chipid
!= ANY_ID
&& wp
->chipid
!= cmi_hdl_chipid(hdl
))
117 return (CMI_HDL_WALK_NEXT
);
118 if (wp
->coreid
!= ANY_ID
&& wp
->coreid
!= cmi_hdl_coreid(hdl
))
119 return (CMI_HDL_WALK_NEXT
);
120 if (wp
->strandid
!= ANY_ID
&& wp
->strandid
!= cmi_hdl_strandid(hdl
))
121 return (CMI_HDL_WALK_NEXT
);
124 * Call the callback function if any exists, otherwise we hold a
125 * reference of the handle and push it to preallocated array.
126 * If the allocated array is going to overflow, reallocate a
127 * bigger one to replace it.
129 if (wp
->cbfunc
!= NULL
)
130 return (wp
->cbfunc(hdl
, arg2
, arg3
));
132 if (wp
->nhdl
== wp
->nhdl_max
) {
133 size_t sz
= sizeof (cmi_hdl_t
) * wp
->nhdl_max
;
134 cmi_hdl_t
*newarray
= kmem_alloc(sz
<< 1, KM_SLEEP
);
136 bcopy(wp
->hdls
, newarray
, sz
);
137 kmem_free(wp
->hdls
, sz
);
143 wp
->hdls
[wp
->nhdl
++] = hdl
;
145 return (CMI_HDL_WALK_NEXT
);
149 populate_cpu(nvlist_t
**nvlp
, cmi_hdl_t hdl
)
154 (void) nvlist_alloc(nvlp
, NV_UNIQUE_NAME
, KM_SLEEP
);
157 * If SMBIOS satisfies FMA Topology needs, gather
158 * more information on the chip's physical roots
159 * like /chassis=x/motherboard=y/cpuboard=z and
160 * set the chip_id to match the SMBIOS' Type 4
161 * ordering & this has to match the ereport's chip
162 * resource instance derived off of SMBIOS.
163 * Multi-Chip-Module support should set the chipid
164 * in terms of the processor package rather than
165 * the die/node in the processor package, for FM.
168 if (!x86gentopo_legacy
) {
169 smbios_id
= cmi_hdl_smbiosid(hdl
);
170 fm_chipid
= cmi_hdl_smb_chipid(hdl
);
171 (void) nvlist_add_nvlist(*nvlp
, FM_PHYSCPU_INFO_CHIP_ROOTS
,
172 cmi_hdl_smb_bboard(hdl
));
173 (void) nvlist_add_uint16(*nvlp
, FM_PHYSCPU_INFO_SMBIOS_ID
,
174 (uint16_t)smbios_id
);
176 fm_chipid
= cmi_hdl_chipid(hdl
);
178 fm_payload_set(*nvlp
,
179 FM_PHYSCPU_INFO_VENDOR_ID
, DATA_TYPE_STRING
,
180 cmi_hdl_vendorstr(hdl
),
181 FM_PHYSCPU_INFO_FAMILY
, DATA_TYPE_INT32
,
182 (int32_t)cmi_hdl_family(hdl
),
183 FM_PHYSCPU_INFO_MODEL
, DATA_TYPE_INT32
,
184 (int32_t)cmi_hdl_model(hdl
),
185 FM_PHYSCPU_INFO_STEPPING
, DATA_TYPE_INT32
,
186 (int32_t)cmi_hdl_stepping(hdl
),
187 FM_PHYSCPU_INFO_CHIP_ID
, DATA_TYPE_INT32
,
189 FM_PHYSCPU_INFO_NPROCNODES
, DATA_TYPE_INT32
,
190 (int32_t)cmi_hdl_procnodes_per_pkg(hdl
),
191 FM_PHYSCPU_INFO_PROCNODE_ID
, DATA_TYPE_INT32
,
192 (int32_t)cmi_hdl_procnodeid(hdl
),
193 FM_PHYSCPU_INFO_CORE_ID
, DATA_TYPE_INT32
,
194 (int32_t)cmi_hdl_coreid(hdl
),
195 FM_PHYSCPU_INFO_STRAND_ID
, DATA_TYPE_INT32
,
196 (int32_t)cmi_hdl_strandid(hdl
),
197 FM_PHYSCPU_INFO_STRAND_APICID
, DATA_TYPE_INT32
,
198 (int32_t)cmi_hdl_strand_apicid(hdl
),
199 FM_PHYSCPU_INFO_CHIP_REV
, DATA_TYPE_STRING
,
200 cmi_hdl_chiprevstr(hdl
),
201 FM_PHYSCPU_INFO_SOCKET_TYPE
, DATA_TYPE_UINT32
,
202 (uint32_t)cmi_hdl_getsockettype(hdl
),
203 FM_PHYSCPU_INFO_CPU_ID
, DATA_TYPE_INT32
,
204 (int32_t)cmi_hdl_logical_id(hdl
),
210 fm_ioctl_physcpu_info(int cmd
, nvlist_t
*invl
, nvlist_t
**onvlp
)
212 nvlist_t
**cpus
, *nvl
;
217 * Do a walk to save all the cmi handles in the array.
219 walk_init(&wk
, ANY_ID
, ANY_ID
, ANY_ID
, NULL
);
220 cmi_hdl_walk(select_cmi_hdl
, &wk
, NULL
, NULL
);
227 cpus
= kmem_alloc(sizeof (nvlist_t
*) * wk
.nhdl
, KM_SLEEP
);
228 for (i
= 0; i
< wk
.nhdl
; i
++) {
229 populate_cpu(cpus
+ i
, wk
.hdls
[i
]);
230 cmi_hdl_rele(wk
.hdls
[i
]);
235 (void) nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, KM_SLEEP
);
236 err
= nvlist_add_nvlist_array(nvl
, FM_PHYSCPU_INFO_CPUS
,
239 for (i
= 0; i
< wk
.nhdl
; i
++)
240 nvlist_free(cpus
[i
]);
241 kmem_free(cpus
, sizeof (nvlist_t
*) * wk
.nhdl
);
253 fm_ioctl_cpu_retire(int cmd
, nvlist_t
*invl
, nvlist_t
**onvlp
)
255 int32_t chipid
, coreid
, strandid
;
256 int rc
, new_status
, old_status
;
261 case FM_IOC_CPU_RETIRE
:
262 new_status
= P_FAULTED
;
264 case FM_IOC_CPU_STATUS
:
265 new_status
= P_STATUS
;
267 case FM_IOC_CPU_UNRETIRE
:
268 new_status
= P_ONLINE
;
274 if (nvlist_lookup_int32(invl
, FM_CPU_RETIRE_CHIP_ID
, &chipid
) != 0 ||
275 nvlist_lookup_int32(invl
, FM_CPU_RETIRE_CORE_ID
, &coreid
) != 0 ||
276 nvlist_lookup_int32(invl
, FM_CPU_RETIRE_STRAND_ID
, &strandid
) != 0)
279 hdl
= cmi_hdl_lookup(CMI_HDL_NEUTRAL
, chipid
, coreid
, strandid
);
283 rc
= cmi_hdl_online(hdl
, new_status
, &old_status
);
287 (void) nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, KM_SLEEP
);
288 (void) nvlist_add_int32(nvl
, FM_CPU_RETIRE_OLDSTATUS
,
297 * Retrun the value of x86gentopo_legacy variable as an nvpair.
299 * The caller is responsible for freeing the nvlist.
303 fm_ioctl_gentopo_legacy(int cmd
, nvlist_t
*invl
, nvlist_t
**onvlp
)
307 if (cmd
!= FM_IOC_GENTOPO_LEGACY
) {
312 * Inform the caller of the intentions of the ereport generators to
313 * generate either a "generic" or "legacy" x86 topology.
316 (void) nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, KM_SLEEP
);
317 (void) nvlist_add_int32(nvl
, FM_GENTOPO_LEGACY
, x86gentopo_legacy
);