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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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