dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / uts / i86pc / io / acpi / acpidev / acpidev_cpu.c
blobebfc0fcd86188daa31ef7c007e93b9ae53d9945d
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2016 Nexenta Systems, Inc.
28 * Copyright (c) 2009-2010, Intel Corporation.
29 * All rights reserved.
33 * [Support of X2APIC]
34 * According to the ACPI Spec, when using the X2APIC interrupt model, logical
35 * processors with APIC ID values of 255 and greater are required to have a
36 * Processor Device object and must convey the Processor's APIC information to
37 * OSPM using the Processor Local X2APIC structure. Logical Processors with APIC
38 * ID values less than 255 must use the Processor Local XAPIC structure to
39 * convey their APIC information to OSPM.
41 * Some systems ignore that requirement of ACPI Spec and use Processor Local
42 * X2APIC structures even for Logical Processors with APIC ID values less than
43 * 255.
46 #include <sys/types.h>
47 #include <sys/atomic.h>
48 #include <sys/bootconf.h>
49 #include <sys/cpuvar.h>
50 #include <sys/machsystm.h>
51 #include <sys/note.h>
52 #include <sys/psm_types.h>
53 #include <sys/x86_archext.h>
54 #include <sys/sunddi.h>
55 #include <sys/sunndi.h>
56 #include <sys/acpi/acpi.h>
57 #include <sys/acpica.h>
58 #include <sys/acpidev.h>
59 #include <sys/acpidev_impl.h>
61 struct acpidev_cpu_map_item {
62 uint32_t proc_id;
63 uint32_t apic_id;
66 struct acpidev_cpu_MAT_arg {
67 boolean_t found;
68 boolean_t enabled;
69 uint32_t proc_id;
70 uint32_t apic_id;
73 static ACPI_STATUS acpidev_cpu_pre_probe(acpidev_walk_info_t *infop);
74 static ACPI_STATUS acpidev_cpu_post_probe(acpidev_walk_info_t *infop);
75 static ACPI_STATUS acpidev_cpu_probe(acpidev_walk_info_t *infop);
76 static acpidev_filter_result_t acpidev_cpu_filter(acpidev_walk_info_t *infop,
77 char *devname, int maxlen);
78 static ACPI_STATUS acpidev_cpu_init(acpidev_walk_info_t *infop);
79 static void acpidev_cpu_fini(ACPI_HANDLE hdl, acpidev_data_handle_t dhdl,
80 acpidev_class_t *clsp);
82 static acpidev_filter_result_t acpidev_cpu_filter_func(
83 acpidev_walk_info_t *infop, ACPI_HANDLE hdl, acpidev_filter_rule_t *afrp,
84 char *devname, int len);
85 static int acpidev_cpu_create_dip(cpu_t *, dev_info_t **);
86 static int acpidev_cpu_get_dip(cpu_t *, dev_info_t **);
89 * Default class driver for ACPI processor/CPU objects.
91 acpidev_class_t acpidev_class_cpu = {
92 0, /* adc_refcnt */
93 ACPIDEV_CLASS_REV1, /* adc_version */
94 ACPIDEV_CLASS_ID_CPU, /* adc_class_id */
95 "ACPI CPU", /* adc_class_name */
96 ACPIDEV_TYPE_CPU, /* adc_dev_type */
97 NULL, /* adc_private */
98 acpidev_cpu_pre_probe, /* adc_pre_probe */
99 acpidev_cpu_post_probe, /* adc_post_probe */
100 acpidev_cpu_probe, /* adc_probe */
101 acpidev_cpu_filter, /* adc_filter */
102 acpidev_cpu_init, /* adc_init */
103 acpidev_cpu_fini, /* adc_fini */
107 * List of class drivers which will be called in order when handling
108 * children of ACPI cpu/processor objects.
110 acpidev_class_list_t *acpidev_class_list_cpu = NULL;
112 /* Filter rule table for the first probe at boot time. */
113 static acpidev_filter_rule_t acpidev_cpu_filters[] = {
114 { /* Skip all processors under root node, should be there. */
115 NULL,
117 ACPIDEV_FILTER_SKIP,
118 NULL,
121 NULL,
122 NULL,
124 { /* Create and scan other processor objects */
125 acpidev_cpu_filter_func,
127 ACPIDEV_FILTER_DEFAULT,
128 &acpidev_class_list_cpu,
130 INT_MAX,
131 NULL,
132 ACPIDEV_NODE_NAME_CPU,
136 /* ACPI/PNP hardware id for processor. */
137 static char *acpidev_processor_device_ids[] = {
138 ACPIDEV_HID_CPU,
141 static char *acpidev_cpu_uid_formats[] = {
142 "SCK%x-CPU%x",
145 static ACPI_HANDLE acpidev_cpu_map_hdl;
146 static uint32_t acpidev_cpu_map_count;
147 static struct acpidev_cpu_map_item *acpidev_cpu_map;
149 extern int (*psm_cpu_create_devinfo)(cpu_t *, dev_info_t **);
150 static int (*psm_cpu_create_devinfo_old)(cpu_t *, dev_info_t **);
151 extern int (*psm_cpu_get_devinfo)(cpu_t *, dev_info_t **);
152 static int (*psm_cpu_get_devinfo_old)(cpu_t *, dev_info_t **);
154 /* Count how many enabled CPUs are in the MADT table. */
155 static ACPI_STATUS
156 acpidev_cpu_count_MADT(ACPI_SUBTABLE_HEADER *ap, void *context)
158 uint32_t *cntp;
159 ACPI_MADT_LOCAL_APIC *mpa;
160 ACPI_MADT_LOCAL_X2APIC *mpx2a;
162 cntp = (uint32_t *)context;
163 switch (ap->Type) {
164 case ACPI_MADT_TYPE_LOCAL_APIC:
165 mpa = (ACPI_MADT_LOCAL_APIC *)ap;
166 if (mpa->LapicFlags & ACPI_MADT_ENABLED) {
167 ASSERT(mpa->Id != 255);
168 (*cntp)++;
170 break;
172 case ACPI_MADT_TYPE_LOCAL_X2APIC:
173 mpx2a = (ACPI_MADT_LOCAL_X2APIC *)ap;
174 if ((mpx2a->LapicFlags & ACPI_MADT_ENABLED)) {
175 (*cntp)++;
177 break;
179 default:
180 break;
183 return (AE_OK);
186 /* Extract information from the enabled CPUs using the MADT table. */
187 static ACPI_STATUS
188 acpidev_cpu_parse_MADT(ACPI_SUBTABLE_HEADER *ap, void *context)
190 uint32_t *cntp;
191 ACPI_MADT_LOCAL_APIC *mpa;
192 ACPI_MADT_LOCAL_X2APIC *mpx2a;
194 cntp = (uint32_t *)context;
195 switch (ap->Type) {
196 case ACPI_MADT_TYPE_LOCAL_APIC:
197 mpa = (ACPI_MADT_LOCAL_APIC *)ap;
198 if (mpa->LapicFlags & ACPI_MADT_ENABLED) {
199 ASSERT(mpa->Id != 255);
200 ASSERT(*cntp < acpidev_cpu_map_count);
201 acpidev_cpu_map[*cntp].proc_id = mpa->ProcessorId;
202 acpidev_cpu_map[*cntp].apic_id = mpa->Id;
203 (*cntp)++;
205 break;
207 case ACPI_MADT_TYPE_LOCAL_X2APIC:
208 mpx2a = (ACPI_MADT_LOCAL_X2APIC *)ap;
209 /* See comment at beginning about 255 limitation. */
210 if (mpx2a->LocalApicId < 255) {
211 ACPIDEV_DEBUG(CE_WARN,
212 "!acpidev: encountered CPU with X2APIC Id < 255.");
214 if (mpx2a->LapicFlags & ACPI_MADT_ENABLED) {
215 ASSERT(*cntp < acpidev_cpu_map_count);
216 acpidev_cpu_map[*cntp].proc_id = mpx2a->Uid;
217 acpidev_cpu_map[*cntp].apic_id = mpx2a->LocalApicId;
218 (*cntp)++;
220 break;
222 default:
223 break;
226 return (AE_OK);
229 static ACPI_STATUS
230 acpidev_cpu_get_apicid(uint32_t procid, uint32_t *apicidp)
232 uint32_t i;
234 for (i = 0; i < acpidev_cpu_map_count; i++) {
235 if (acpidev_cpu_map[i].proc_id == procid) {
236 *apicidp = acpidev_cpu_map[i].apic_id;
237 return (AE_OK);
241 return (AE_NOT_FOUND);
245 * Extract information for enabled CPUs from the buffer returned
246 * by the _MAT method.
248 static ACPI_STATUS
249 acpidev_cpu_query_MAT(ACPI_SUBTABLE_HEADER *ap, void *context)
251 ACPI_MADT_LOCAL_APIC *mpa;
252 ACPI_MADT_LOCAL_X2APIC *mpx2a;
253 struct acpidev_cpu_MAT_arg *rp;
255 rp = (struct acpidev_cpu_MAT_arg *)context;
256 switch (ap->Type) {
257 case ACPI_MADT_TYPE_LOCAL_APIC:
258 mpa = (ACPI_MADT_LOCAL_APIC *)ap;
259 rp->found = B_TRUE;
260 rp->proc_id = mpa->ProcessorId;
261 rp->apic_id = mpa->Id;
262 if (mpa->LapicFlags & ACPI_MADT_ENABLED) {
263 ASSERT(mpa->Id != 255);
264 rp->enabled = B_TRUE;
265 } else {
266 rp->enabled = B_FALSE;
268 return (AE_CTRL_TERMINATE);
270 case ACPI_MADT_TYPE_LOCAL_X2APIC:
271 mpx2a = (ACPI_MADT_LOCAL_X2APIC *)ap;
272 if (mpx2a->LocalApicId < 255) {
273 ACPIDEV_DEBUG(CE_WARN, "!acpidev: encountered CPU "
274 "with X2APIC Id < 255 in _MAT.");
276 rp->found = B_TRUE;
277 rp->proc_id = mpx2a->Uid;
278 rp->apic_id = mpx2a->LocalApicId;
279 if (mpx2a->LapicFlags & ACPI_MADT_ENABLED) {
280 rp->enabled = B_TRUE;
281 } else {
282 rp->enabled = B_FALSE;
284 return (AE_CTRL_TERMINATE);
286 case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
287 /* UNIMPLEMENTED */
288 break;
290 case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI:
291 /* UNIMPLEMENTED */
292 break;
294 default:
296 * According to the ACPI Spec, the buffer returned by _MAT
297 * for a processor object should only contain Local APIC,
298 * Local SAPIC, and local APIC NMI entries.
299 * x2APIC Specification extends it to support Processor
300 * x2APIC and x2APIC NMI Structure.
302 ACPIDEV_DEBUG(CE_NOTE,
303 "!acpidev: unknown APIC entry type %u in _MAT.", ap->Type);
304 break;
307 return (AE_OK);
311 * Query ACPI processor ID by evaluating ACPI _MAT, _UID, and PROCESSOR
312 * objects.
314 static ACPI_STATUS
315 acpidev_cpu_get_procid(acpidev_walk_info_t *infop, uint32_t *idp)
317 int id;
318 ACPI_HANDLE hdl;
319 struct acpidev_cpu_MAT_arg mat;
321 if (infop->awi_info->Type != ACPI_TYPE_PROCESSOR &&
322 infop->awi_info->Type != ACPI_TYPE_DEVICE) {
323 ACPIDEV_DEBUG(CE_WARN,
324 "!acpidev: object %s is not PROCESSOR or DEVICE.",
325 infop->awi_name);
326 return (AE_BAD_PARAMETER);
328 hdl = infop->awi_hdl;
331 * First try to evaluate _MAT.
332 * According to the ACPI Spec3.0b, it's legal for ACPI PROCESSOR objects
333 * to have ACPI method objects.
335 bzero(&mat, sizeof (mat));
336 (void) acpidev_walk_apic(NULL, hdl, ACPIDEV_METHOD_NAME_MAT,
337 acpidev_cpu_query_MAT, &mat);
338 if (mat.found) {
339 *idp = mat.proc_id;
340 return (AE_OK);
343 /* Then evalute PROCESSOR object. */
344 if (infop->awi_info->Type == ACPI_TYPE_PROCESSOR) {
345 ACPI_BUFFER rb;
347 rb.Pointer = NULL;
348 rb.Length = ACPI_ALLOCATE_BUFFER;
349 if (ACPI_SUCCESS(AcpiEvaluateObjectTyped(hdl, NULL, NULL, &rb,
350 ACPI_TYPE_PROCESSOR))) {
351 *idp = ((ACPI_OBJECT *)rb.Pointer)->Processor.ProcId;
352 AcpiOsFree(rb.Pointer);
353 return (AE_OK);
354 } else {
355 ACPIDEV_DEBUG(CE_WARN,
356 "!acpidev: failed to evaluate ACPI object %s.",
357 infop->awi_name);
362 * Finally, try to evalute the _UID method.
363 * According to the ACPI Spec3.0b, it's legal for ACPI PROCESSOR objects
364 * to have ACPI method objects.
365 * The CPU _UID method should return Processor Id as an integer on x86.
367 if (ACPI_SUCCESS(acpica_eval_int(hdl, METHOD_NAME__UID, &id))) {
368 *idp = id;
369 return (AE_OK);
372 return (AE_NOT_FOUND);
375 static ACPI_STATUS
376 acpidev_cpu_get_proximity_id(ACPI_HANDLE hdl, uint32_t apicid, uint32_t *pxmidp)
378 int len, off;
379 ACPI_SUBTABLE_HEADER *sp;
380 ACPI_SRAT_CPU_AFFINITY *xp;
381 ACPI_SRAT_X2APIC_CPU_AFFINITY *x2p;
383 ASSERT(hdl != NULL);
384 ASSERT(pxmidp != NULL);
385 *pxmidp = UINT32_MAX;
387 if (ACPI_SUCCESS(acpidev_eval_pxm(hdl, pxmidp))) {
388 return (AE_OK);
390 if (acpidev_srat_tbl_ptr == NULL) {
391 return (AE_NOT_FOUND);
394 /* Search the static ACPI SRAT table for proximity domain id. */
395 sp = (ACPI_SUBTABLE_HEADER *)(acpidev_srat_tbl_ptr + 1);
396 len = acpidev_srat_tbl_ptr->Header.Length;
397 off = sizeof (*acpidev_srat_tbl_ptr);
398 while (off < len) {
399 switch (sp->Type) {
400 case ACPI_SRAT_TYPE_CPU_AFFINITY:
401 xp = (ACPI_SRAT_CPU_AFFINITY *)sp;
402 if ((xp->Flags & ACPI_SRAT_CPU_ENABLED) &&
403 xp->ApicId == apicid) {
404 *pxmidp = xp->ProximityDomainLo;
405 *pxmidp |= xp->ProximityDomainHi[0] << 8;
406 *pxmidp |= xp->ProximityDomainHi[1] << 16;
407 *pxmidp |= xp->ProximityDomainHi[2] << 24;
408 return (AE_OK);
410 break;
412 case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY:
413 x2p = (ACPI_SRAT_X2APIC_CPU_AFFINITY *)sp;
414 if ((x2p->Flags & ACPI_SRAT_CPU_ENABLED) &&
415 x2p->ApicId == apicid) {
416 *pxmidp = x2p->ProximityDomain;
417 return (AE_OK);
419 break;
421 off += sp->Length;
422 sp = (ACPI_SUBTABLE_HEADER *)(((char *)sp) + sp->Length);
425 return (AE_NOT_FOUND);
428 static ACPI_STATUS
429 acpidev_cpu_pre_probe(acpidev_walk_info_t *infop)
431 uint32_t count = 0;
433 /* Parse and cache APIC info in MADT on the first probe at boot time. */
434 ASSERT(infop != NULL);
435 if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE &&
436 acpidev_cpu_map_hdl == NULL) {
437 /* Parse CPU relative information in the ACPI MADT table. */
438 (void) acpidev_walk_apic(NULL, NULL, NULL,
439 acpidev_cpu_count_MADT, &acpidev_cpu_map_count);
440 acpidev_cpu_map = kmem_zalloc(sizeof (acpidev_cpu_map[0])
441 * acpidev_cpu_map_count, KM_SLEEP);
442 (void) acpidev_walk_apic(NULL, NULL, NULL,
443 acpidev_cpu_parse_MADT, &count);
444 ASSERT(count == acpidev_cpu_map_count);
445 acpidev_cpu_map_hdl = infop->awi_hdl;
447 /* Cache pointer to the ACPI SRAT table. */
448 if (ACPI_FAILURE(AcpiGetTable(ACPI_SIG_SRAT, 1,
449 (ACPI_TABLE_HEADER **)&acpidev_srat_tbl_ptr))) {
450 acpidev_srat_tbl_ptr = NULL;
454 return (AE_OK);
457 static ACPI_STATUS
458 acpidev_cpu_post_probe(acpidev_walk_info_t *infop)
460 /* Free cached APIC info on the second probe at boot time. */
461 ASSERT(infop != NULL);
462 if (infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE &&
463 acpidev_cpu_map_hdl != NULL &&
464 infop->awi_hdl == acpidev_cpu_map_hdl) {
465 if (acpidev_cpu_map != NULL && acpidev_cpu_map_count != 0) {
466 kmem_free(acpidev_cpu_map, sizeof (acpidev_cpu_map[0])
467 * acpidev_cpu_map_count);
469 acpidev_cpu_map = NULL;
470 acpidev_cpu_map_count = 0;
471 acpidev_cpu_map_hdl = NULL;
473 /* replace psm_cpu_create_devinfo with local implementation. */
474 psm_cpu_create_devinfo_old = psm_cpu_create_devinfo;
475 psm_cpu_create_devinfo = acpidev_cpu_create_dip;
476 psm_cpu_get_devinfo_old = psm_cpu_get_devinfo;
477 psm_cpu_get_devinfo = acpidev_cpu_get_dip;
480 return (AE_OK);
483 static ACPI_STATUS
484 acpidev_cpu_probe(acpidev_walk_info_t *infop)
486 ACPI_STATUS rc = AE_OK;
487 int flags;
489 ASSERT(infop != NULL);
490 ASSERT(infop->awi_hdl != NULL);
491 ASSERT(infop->awi_info != NULL);
492 ASSERT(infop->awi_class_curr == &acpidev_class_cpu);
493 if (infop->awi_info->Type != ACPI_TYPE_PROCESSOR &&
494 (infop->awi_info->Type != ACPI_TYPE_DEVICE ||
495 acpidev_match_device_id(infop->awi_info,
496 ACPIDEV_ARRAY_PARAM(acpidev_processor_device_ids)) == 0)) {
497 return (AE_OK);
500 flags = ACPIDEV_PROCESS_FLAG_SCAN;
501 switch (infop->awi_op_type) {
502 case ACPIDEV_OP_BOOT_PROBE:
504 * Mark device as offline. It will be changed to online state
505 * when the corresponding CPU starts up.
507 if (acpica_get_devcfg_feature(ACPI_DEVCFG_CPU)) {
508 flags |= ACPIDEV_PROCESS_FLAG_CREATE |
509 ACPIDEV_PROCESS_FLAG_OFFLINE;
511 break;
513 case ACPIDEV_OP_BOOT_REPROBE:
514 break;
516 case ACPIDEV_OP_HOTPLUG_PROBE:
517 if (acpica_get_devcfg_feature(ACPI_DEVCFG_CPU)) {
518 flags |= ACPIDEV_PROCESS_FLAG_CREATE |
519 ACPIDEV_PROCESS_FLAG_OFFLINE |
520 ACPIDEV_PROCESS_FLAG_SYNCSTATUS |
521 ACPIDEV_PROCESS_FLAG_HOLDBRANCH;
523 break;
525 default:
526 ACPIDEV_DEBUG(CE_WARN, "!acpidev: unknown operation type %u in "
527 "acpidev_cpu_probe().", infop->awi_op_type);
528 rc = AE_BAD_PARAMETER;
529 break;
532 if (rc == AE_OK) {
533 rc = acpidev_process_object(infop, flags);
535 if (ACPI_FAILURE(rc) && rc != AE_NOT_EXIST && rc != AE_ALREADY_EXISTS) {
536 cmn_err(CE_WARN,
537 "!acpidev: failed to process processor object %s.",
538 infop->awi_name);
539 } else {
540 rc = AE_OK;
543 return (rc);
546 static acpidev_filter_result_t
547 acpidev_cpu_filter_func(acpidev_walk_info_t *infop, ACPI_HANDLE hdl,
548 acpidev_filter_rule_t *afrp, char *devname, int len)
550 acpidev_filter_result_t res;
552 ASSERT(afrp != NULL);
553 if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
554 infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE) {
555 uint32_t procid;
556 uint32_t apicid;
558 if (acpidev_cpu_get_procid(infop, &procid) != 0) {
559 ACPIDEV_DEBUG(CE_WARN,
560 "!acpidev: failed to query processor id for %s.",
561 infop->awi_name);
562 return (ACPIDEV_FILTER_SKIP);
563 } else if (acpidev_cpu_get_apicid(procid, &apicid) != 0) {
564 ACPIDEV_DEBUG(CE_WARN,
565 "!acpidev: failed to query apic id for %s.",
566 infop->awi_name);
567 return (ACPIDEV_FILTER_SKIP);
570 infop->awi_scratchpad[0] = procid;
571 infop->awi_scratchpad[1] = apicid;
572 } else if (infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
573 struct acpidev_cpu_MAT_arg mat;
575 bzero(&mat, sizeof (mat));
576 (void) acpidev_walk_apic(NULL, hdl, ACPIDEV_METHOD_NAME_MAT,
577 acpidev_cpu_query_MAT, &mat);
578 if (!mat.found) {
579 cmn_err(CE_WARN,
580 "!acpidev: failed to walk apic resource for %s.",
581 infop->awi_name);
582 return (ACPIDEV_FILTER_SKIP);
583 } else if (!mat.enabled) {
584 ACPIDEV_DEBUG(CE_NOTE,
585 "!acpidev: CPU %s has been disabled.",
586 infop->awi_name);
587 return (ACPIDEV_FILTER_SKIP);
589 /* Save processor id and APIC id in scratchpad memory. */
590 infop->awi_scratchpad[0] = mat.proc_id;
591 infop->awi_scratchpad[1] = mat.apic_id;
594 res = acpidev_filter_default(infop, hdl, afrp, devname, len);
596 return (res);
599 static acpidev_filter_result_t
600 acpidev_cpu_filter(acpidev_walk_info_t *infop, char *devname, int maxlen)
602 acpidev_filter_result_t res;
604 ASSERT(infop != NULL);
605 ASSERT(devname == NULL || maxlen >= ACPIDEV_MAX_NAMELEN);
606 if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
607 infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE ||
608 infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
609 res = acpidev_filter_device(infop, infop->awi_hdl,
610 ACPIDEV_ARRAY_PARAM(acpidev_cpu_filters), devname, maxlen);
611 } else {
612 res = ACPIDEV_FILTER_FAILED;
615 return (res);
618 static ACPI_STATUS
619 acpidev_cpu_init(acpidev_walk_info_t *infop)
621 int count;
622 uint32_t pxmid;
623 dev_info_t *dip;
624 ACPI_HANDLE hdl;
625 char unitaddr[64];
626 char **compatpp;
627 static char *compatible[] = {
628 ACPIDEV_HID_PROCESSOR,
629 ACPIDEV_TYPE_CPU,
630 "cpu"
633 ASSERT(infop != NULL);
634 dip = infop->awi_dip;
635 hdl = infop->awi_hdl;
637 /* Create "apic_id", "processor_id" and "proximity_id" properties. */
638 if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
639 ACPIDEV_PROP_NAME_PROCESSOR_ID, infop->awi_scratchpad[0]) !=
640 NDI_SUCCESS) {
641 cmn_err(CE_WARN,
642 "!acpidev: failed to set processor_id property for %s.",
643 infop->awi_name);
644 return (AE_ERROR);
646 if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
647 ACPIDEV_PROP_NAME_LOCALAPIC_ID, infop->awi_scratchpad[1]) !=
648 NDI_SUCCESS) {
649 cmn_err(CE_WARN,
650 "!acpidev: failed to set apic_id property for %s.",
651 infop->awi_name);
652 return (AE_ERROR);
654 if (ACPI_SUCCESS(acpidev_cpu_get_proximity_id(infop->awi_hdl,
655 infop->awi_scratchpad[1], &pxmid))) {
656 if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
657 ACPIDEV_PROP_NAME_PROXIMITY_ID, pxmid) != NDI_SUCCESS) {
658 cmn_err(CE_WARN, "!acpidev: failed to set proximity id "
659 "property for %s.", infop->awi_name);
660 return (AE_ERROR);
664 /* Set "compatible" property for CPU dip */
665 count = sizeof (compatible) / sizeof (compatible[0]);
666 if (infop->awi_info->Type == ACPI_TYPE_PROCESSOR) {
667 compatpp = compatible;
668 } else if (infop->awi_info->Type == ACPI_TYPE_DEVICE) {
670 * skip first item for pseudo processor HID.
671 * acpidev_set_compatible() will handle HID/CID for CPU device.
673 compatpp = &compatible[1];
674 count--;
675 } else {
676 return (AE_BAD_PARAMETER);
678 if (ACPI_FAILURE(acpidev_set_compatible(infop, compatpp, count))) {
679 return (AE_ERROR);
683 * Set device unit-address property.
684 * First try to generate meaningful unit address from _UID,
685 * then use Processor Id if that fails.
687 if ((infop->awi_info->Valid & ACPI_VALID_UID) == 0 ||
688 acpidev_generate_unitaddr(infop->awi_info->UniqueId.String,
689 ACPIDEV_ARRAY_PARAM(acpidev_cpu_uid_formats),
690 unitaddr, sizeof (unitaddr)) == NULL) {
691 (void) snprintf(unitaddr, sizeof (unitaddr), "%u",
692 (uint32_t)infop->awi_scratchpad[0]);
694 if (ACPI_FAILURE(acpidev_set_unitaddr(infop, NULL, 0, unitaddr))) {
695 return (AE_ERROR);
699 * Build binding information for CPUs.
701 if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
702 infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE ||
703 infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
704 if (ACPI_FAILURE(acpica_add_processor_to_map(
705 infop->awi_scratchpad[0], hdl, infop->awi_scratchpad[1]))) {
706 cmn_err(CE_WARN, "!acpidev: failed to bind processor "
707 "id/object handle for %s.", infop->awi_name);
708 return (AE_ERROR);
710 } else {
711 ACPIDEV_DEBUG(CE_WARN,
712 "!acpidev: unknown operation type %u in acpidev_cpu_init.",
713 infop->awi_op_type);
714 return (AE_BAD_PARAMETER);
717 return (AE_OK);
720 static void
721 acpidev_cpu_fini(ACPI_HANDLE hdl, acpidev_data_handle_t dhdl,
722 acpidev_class_t *clsp)
724 _NOTE(ARGUNUSED(clsp, dhdl));
726 int rc;
727 uint32_t procid;
729 rc = acpica_get_procid_by_object(hdl, &procid);
730 ASSERT(ACPI_SUCCESS(rc));
731 if (ACPI_SUCCESS(rc)) {
732 rc = acpica_remove_processor_from_map(procid);
733 ASSERT(ACPI_SUCCESS(rc));
734 if (ACPI_FAILURE(rc)) {
735 cmn_err(CE_WARN, "!acpidev: failed to remove "
736 "processor from ACPICA.");
742 * Lookup the dip for a CPU if ACPI CPU autoconfig is enabled.
744 static int
745 acpidev_cpu_lookup_dip(cpu_t *cp, dev_info_t **dipp)
747 uint32_t apicid;
748 ACPI_HANDLE hdl;
749 dev_info_t *dip = NULL;
751 *dipp = NULL;
752 if (acpica_get_devcfg_feature(ACPI_DEVCFG_CPU)) {
753 apicid = cpuid_get_apicid(cp);
754 if (acpica_get_cpu_object_by_cpuid(cp->cpu_id, &hdl) == 0 ||
755 (apicid != UINT32_MAX &&
756 acpica_get_cpu_object_by_apicid(apicid, &hdl) == 0)) {
757 ASSERT(hdl != NULL);
758 if (ACPI_SUCCESS(acpica_get_devinfo(hdl, &dip))) {
759 ASSERT(dip != NULL);
760 *dipp = dip;
761 return (PSM_SUCCESS);
764 ACPIDEV_DEBUG(CE_WARN,
765 "!acpidev: failed to lookup dip for cpu %d(%p).",
766 cp->cpu_id, (void *)cp);
769 return (PSM_FAILURE);
772 static int
773 acpidev_cpu_create_dip(cpu_t *cp, dev_info_t **dipp)
775 if (acpidev_cpu_lookup_dip(cp, dipp) == PSM_SUCCESS) {
776 ndi_hold_devi(*dipp);
777 return (PSM_SUCCESS);
779 if (psm_cpu_create_devinfo_old != NULL) {
780 return (psm_cpu_create_devinfo_old(cp, dipp));
781 } else {
782 return (PSM_FAILURE);
786 static int
787 acpidev_cpu_get_dip(cpu_t *cp, dev_info_t **dipp)
789 if (acpidev_cpu_lookup_dip(cp, dipp) == PSM_SUCCESS) {
790 return (PSM_SUCCESS);
792 if (psm_cpu_get_devinfo_old != NULL) {
793 return (psm_cpu_get_devinfo_old(cp, dipp));
794 } else {
795 return (PSM_FAILURE);