xref: /illumos-gate/usr/src/uts/i86pc/io/acpi/acpidev/acpidev_cpu.c (revision 598f4ceed9327d2d6c2325dd67cae3aa06f7fea6)
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 }
796