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