1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2016 Nexenta Systems, Inc.
26 */
27 /*
28 * Copyright (c) 2009-2010, Intel Corporation.
29 * All rights reserved.
30 */
31
32 /*
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.
40 *
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.
44 */
45
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>
60
61 struct acpidev_cpu_map_item {
62 uint32_t proc_id;
63 uint32_t apic_id;
64 };
65
66 struct acpidev_cpu_MAT_arg {
67 boolean_t found;
68 boolean_t enabled;
69 uint32_t proc_id;
70 uint32_t apic_id;
71 };
72
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);
81
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 **);
87
88 /*
89 * Default class driver for ACPI processor/CPU objects.
90 */
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 */
104 };
105
106 /*
107 * List of class drivers which will be called in order when handling
108 * children of ACPI cpu/processor objects.
109 */
110 acpidev_class_list_t *acpidev_class_list_cpu = NULL;
111
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,
116 0,
117 ACPIDEV_FILTER_SKIP,
118 NULL,
119 1,
120 1,
121 NULL,
122 NULL,
123 },
124 { /* Create and scan other processor objects */
125 acpidev_cpu_filter_func,
126 0,
127 ACPIDEV_FILTER_DEFAULT,
128 &acpidev_class_list_cpu,
129 2,
130 INT_MAX,
131 NULL,
132 ACPIDEV_NODE_NAME_CPU,
133 }
134 };
135
136 /* ACPI/PNP hardware id for processor. */
137 static char *acpidev_processor_device_ids[] = {
138 ACPIDEV_HID_CPU,
139 };
140
141 static char *acpidev_cpu_uid_formats[] = {
142 "SCK%x-CPU%x",
143 };
144
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;
148
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 **);
153
154 /* Count how many enabled CPUs are in the MADT table. */
155 static ACPI_STATUS
acpidev_cpu_count_MADT(ACPI_SUBTABLE_HEADER * ap,void * context)156 acpidev_cpu_count_MADT(ACPI_SUBTABLE_HEADER *ap, void *context)
157 {
158 uint32_t *cntp;
159 ACPI_MADT_LOCAL_APIC *mpa;
160 ACPI_MADT_LOCAL_X2APIC *mpx2a;
161
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)++;
169 }
170 break;
171
172 case ACPI_MADT_TYPE_LOCAL_X2APIC:
173 mpx2a = (ACPI_MADT_LOCAL_X2APIC *)ap;
174 if ((mpx2a->LapicFlags & ACPI_MADT_ENABLED)) {
175 (*cntp)++;
176 }
177 break;
178
179 default:
180 break;
181 }
182
183 return (AE_OK);
184 }
185
186 /* Extract information from the enabled CPUs using the MADT table. */
187 static ACPI_STATUS
acpidev_cpu_parse_MADT(ACPI_SUBTABLE_HEADER * ap,void * context)188 acpidev_cpu_parse_MADT(ACPI_SUBTABLE_HEADER *ap, void *context)
189 {
190 uint32_t *cntp;
191 ACPI_MADT_LOCAL_APIC *mpa;
192 ACPI_MADT_LOCAL_X2APIC *mpx2a;
193
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)++;
204 }
205 break;
206
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.");
213 }
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)++;
219 }
220 break;
221
222 default:
223 break;
224 }
225
226 return (AE_OK);
227 }
228
229 static ACPI_STATUS
acpidev_cpu_get_apicid(uint32_t procid,uint32_t * apicidp)230 acpidev_cpu_get_apicid(uint32_t procid, uint32_t *apicidp)
231 {
232 uint32_t i;
233
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);
238 }
239 }
240
241 return (AE_NOT_FOUND);
242 }
243
244 /*
245 * Extract information for enabled CPUs from the buffer returned
246 * by the _MAT method.
247 */
248 static ACPI_STATUS
acpidev_cpu_query_MAT(ACPI_SUBTABLE_HEADER * ap,void * context)249 acpidev_cpu_query_MAT(ACPI_SUBTABLE_HEADER *ap, void *context)
250 {
251 ACPI_MADT_LOCAL_APIC *mpa;
252 ACPI_MADT_LOCAL_X2APIC *mpx2a;
253 struct acpidev_cpu_MAT_arg *rp;
254
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;
267 }
268 return (AE_CTRL_TERMINATE);
269
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.");
275 }
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;
283 }
284 return (AE_CTRL_TERMINATE);
285
286 case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
287 /* UNIMPLEMENTED */
288 break;
289
290 case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI:
291 /* UNIMPLEMENTED */
292 break;
293
294 default:
295 /*
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.
301 */
302 ACPIDEV_DEBUG(CE_NOTE,
303 "!acpidev: unknown APIC entry type %u in _MAT.", ap->Type);
304 break;
305 }
306
307 return (AE_OK);
308 }
309
310 /*
311 * Query ACPI processor ID by evaluating ACPI _MAT, _UID, and PROCESSOR
312 * objects.
313 */
314 static ACPI_STATUS
acpidev_cpu_get_procid(acpidev_walk_info_t * infop,uint32_t * idp)315 acpidev_cpu_get_procid(acpidev_walk_info_t *infop, uint32_t *idp)
316 {
317 int id;
318 ACPI_HANDLE hdl;
319 struct acpidev_cpu_MAT_arg mat;
320
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);
327 }
328 hdl = infop->awi_hdl;
329
330 /*
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.
334 */
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);
341 }
342
343 /* Then evalute PROCESSOR object. */
344 if (infop->awi_info->Type == ACPI_TYPE_PROCESSOR) {
345 ACPI_BUFFER rb;
346
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);
358 }
359 }
360
361 /*
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.
366 */
367 if (ACPI_SUCCESS(acpica_eval_int(hdl, METHOD_NAME__UID, &id))) {
368 *idp = id;
369 return (AE_OK);
370 }
371
372 return (AE_NOT_FOUND);
373 }
374
375 static ACPI_STATUS
acpidev_cpu_get_proximity_id(ACPI_HANDLE hdl,uint32_t apicid,uint32_t * pxmidp)376 acpidev_cpu_get_proximity_id(ACPI_HANDLE hdl, uint32_t apicid, uint32_t *pxmidp)
377 {
378 int len, off;
379 ACPI_SUBTABLE_HEADER *sp;
380 ACPI_SRAT_CPU_AFFINITY *xp;
381 ACPI_SRAT_X2APIC_CPU_AFFINITY *x2p;
382
383 ASSERT(hdl != NULL);
384 ASSERT(pxmidp != NULL);
385 *pxmidp = UINT32_MAX;
386
387 if (ACPI_SUCCESS(acpidev_eval_pxm(hdl, pxmidp))) {
388 return (AE_OK);
389 }
390 if (acpidev_srat_tbl_ptr == NULL) {
391 return (AE_NOT_FOUND);
392 }
393
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);
409 }
410 break;
411
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);
418 }
419 break;
420 }
421 off += sp->Length;
422 sp = (ACPI_SUBTABLE_HEADER *)(((char *)sp) + sp->Length);
423 }
424
425 return (AE_NOT_FOUND);
426 }
427
428 static ACPI_STATUS
acpidev_cpu_pre_probe(acpidev_walk_info_t * infop)429 acpidev_cpu_pre_probe(acpidev_walk_info_t *infop)
430 {
431 uint32_t count = 0;
432
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;
446
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;
451 }
452 }
453
454 return (AE_OK);
455 }
456
457 static ACPI_STATUS
acpidev_cpu_post_probe(acpidev_walk_info_t * infop)458 acpidev_cpu_post_probe(acpidev_walk_info_t *infop)
459 {
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);
468 }
469 acpidev_cpu_map = NULL;
470 acpidev_cpu_map_count = 0;
471 acpidev_cpu_map_hdl = NULL;
472
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;
478 }
479
480 return (AE_OK);
481 }
482
483 static ACPI_STATUS
acpidev_cpu_probe(acpidev_walk_info_t * infop)484 acpidev_cpu_probe(acpidev_walk_info_t *infop)
485 {
486 ACPI_STATUS rc = AE_OK;
487 int flags;
488
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);
498 }
499
500 flags = ACPIDEV_PROCESS_FLAG_SCAN;
501 switch (infop->awi_op_type) {
502 case ACPIDEV_OP_BOOT_PROBE:
503 /*
504 * Mark device as offline. It will be changed to online state
505 * when the corresponding CPU starts up.
506 */
507 if (acpica_get_devcfg_feature(ACPI_DEVCFG_CPU)) {
508 flags |= ACPIDEV_PROCESS_FLAG_CREATE |
509 ACPIDEV_PROCESS_FLAG_OFFLINE;
510 }
511 break;
512
513 case ACPIDEV_OP_BOOT_REPROBE:
514 break;
515
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;
522 }
523 break;
524
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;
530 }
531
532 if (rc == AE_OK) {
533 rc = acpidev_process_object(infop, flags);
534 }
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;
541 }
542
543 return (rc);
544 }
545
546 static acpidev_filter_result_t
acpidev_cpu_filter_func(acpidev_walk_info_t * infop,ACPI_HANDLE hdl,acpidev_filter_rule_t * afrp,char * devname,int len)547 acpidev_cpu_filter_func(acpidev_walk_info_t *infop, ACPI_HANDLE hdl,
548 acpidev_filter_rule_t *afrp, char *devname, int len)
549 {
550 acpidev_filter_result_t res;
551
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;
557
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);
568 }
569
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;
574
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);
588 }
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;
592 }
593
594 res = acpidev_filter_default(infop, hdl, afrp, devname, len);
595
596 return (res);
597 }
598
599 static acpidev_filter_result_t
acpidev_cpu_filter(acpidev_walk_info_t * infop,char * devname,int maxlen)600 acpidev_cpu_filter(acpidev_walk_info_t *infop, char *devname, int maxlen)
601 {
602 acpidev_filter_result_t res;
603
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;
613 }
614
615 return (res);
616 }
617
618 static ACPI_STATUS
acpidev_cpu_init(acpidev_walk_info_t * infop)619 acpidev_cpu_init(acpidev_walk_info_t *infop)
620 {
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"
631 };
632
633 ASSERT(infop != NULL);
634 dip = infop->awi_dip;
635 hdl = infop->awi_hdl;
636
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);
645 }
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);
653 }
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);
661 }
662 }
663
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) {
669 /*
670 * skip first item for pseudo processor HID.
671 * acpidev_set_compatible() will handle HID/CID for CPU device.
672 */
673 compatpp = &compatible[1];
674 count--;
675 } else {
676 return (AE_BAD_PARAMETER);
677 }
678 if (ACPI_FAILURE(acpidev_set_compatible(infop, compatpp, count))) {
679 return (AE_ERROR);
680 }
681
682 /*
683 * Set device unit-address property.
684 * First try to generate meaningful unit address from _UID,
685 * then use Processor Id if that fails.
686 */
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]);
693 }
694 if (ACPI_FAILURE(acpidev_set_unitaddr(infop, NULL, 0, unitaddr))) {
695 return (AE_ERROR);
696 }
697
698 /*
699 * Build binding information for CPUs.
700 */
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);
709 }
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);
715 }
716
717 return (AE_OK);
718 }
719
720 static void
acpidev_cpu_fini(ACPI_HANDLE hdl,acpidev_data_handle_t dhdl,acpidev_class_t * clsp)721 acpidev_cpu_fini(ACPI_HANDLE hdl, acpidev_data_handle_t dhdl,
722 acpidev_class_t *clsp)
723 {
724 _NOTE(ARGUNUSED(clsp, dhdl));
725
726 int rc;
727 uint32_t procid;
728
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.");
737 }
738 }
739 }
740
741 /*
742 * Lookup the dip for a CPU if ACPI CPU autoconfig is enabled.
743 */
744 static int
acpidev_cpu_lookup_dip(cpu_t * cp,dev_info_t ** dipp)745 acpidev_cpu_lookup_dip(cpu_t *cp, dev_info_t **dipp)
746 {
747 uint32_t apicid;
748 ACPI_HANDLE hdl;
749 dev_info_t *dip = NULL;
750
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);
762 }
763 }
764 ACPIDEV_DEBUG(CE_WARN,
765 "!acpidev: failed to lookup dip for cpu %d(%p).",
766 cp->cpu_id, (void *)cp);
767 }
768
769 return (PSM_FAILURE);
770 }
771
772 static int
acpidev_cpu_create_dip(cpu_t * cp,dev_info_t ** dipp)773 acpidev_cpu_create_dip(cpu_t *cp, dev_info_t **dipp)
774 {
775 if (acpidev_cpu_lookup_dip(cp, dipp) == PSM_SUCCESS) {
776 ndi_hold_devi(*dipp);
777 return (PSM_SUCCESS);
778 }
779 if (psm_cpu_create_devinfo_old != NULL) {
780 return (psm_cpu_create_devinfo_old(cp, dipp));
781 } else {
782 return (PSM_FAILURE);
783 }
784 }
785
786 static int
acpidev_cpu_get_dip(cpu_t * cp,dev_info_t ** dipp)787 acpidev_cpu_get_dip(cpu_t *cp, dev_info_t **dipp)
788 {
789 if (acpidev_cpu_lookup_dip(cp, dipp) == PSM_SUCCESS) {
790 return (PSM_SUCCESS);
791 }
792 if (psm_cpu_get_devinfo_old != NULL) {
793 return (psm_cpu_get_devinfo_old(cp, dipp));
794 } else {
795 return (PSM_FAILURE);
796 }
797 }
798