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
56struct acpidev_cpu_map_item {
57	uint32_t	proc_id;
58	uint32_t	apic_id;
59};
60
61struct acpidev_cpu_MAT_arg {
62	boolean_t	found;
63	boolean_t	enabled;
64	uint32_t	proc_id;
65	uint32_t	apic_id;
66};
67
68static ACPI_STATUS acpidev_cpu_pre_probe(acpidev_walk_info_t *infop);
69static ACPI_STATUS acpidev_cpu_post_probe(acpidev_walk_info_t *infop);
70static ACPI_STATUS acpidev_cpu_probe(acpidev_walk_info_t *infop);
71static acpidev_filter_result_t acpidev_cpu_filter(acpidev_walk_info_t *infop,
72    char *devname, int maxlen);
73static ACPI_STATUS acpidev_cpu_init(acpidev_walk_info_t *infop);
74static void acpidev_cpu_fini(ACPI_HANDLE hdl, acpidev_data_handle_t dhdl,
75    acpidev_class_t *clsp);
76
77static 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);
80static int acpidev_cpu_create_dip(cpu_t *, dev_info_t **);
81static int acpidev_cpu_get_dip(cpu_t *, dev_info_t **);
82
83/*
84 * Default class driver for ACPI processor/CPU objects.
85 */
86acpidev_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 */
105acpidev_class_list_t *acpidev_class_list_cpu = NULL;
106
107/* Filter rule table for the first probe at boot time. */
108static 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. */
132static char *acpidev_processor_device_ids[] = {
133	ACPIDEV_HID_CPU,
134};
135
136static char *acpidev_cpu_uid_formats[] = {
137	"SCK%x-CPU%x",
138};
139
140static ACPI_HANDLE acpidev_cpu_map_hdl;
141static uint32_t acpidev_cpu_map_count;
142static struct acpidev_cpu_map_item *acpidev_cpu_map;
143
144extern int (*psm_cpu_create_devinfo)(cpu_t *, dev_info_t **);
145static int (*psm_cpu_create_devinfo_old)(cpu_t *, dev_info_t **);
146extern int (*psm_cpu_get_devinfo)(cpu_t *, dev_info_t **);
147static int (*psm_cpu_get_devinfo_old)(cpu_t *, dev_info_t **);
148
149/* Count how many enabled CPUs are in the MADT table. */
150static ACPI_STATUS
151acpidev_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. */
184static ACPI_STATUS
185acpidev_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
225static ACPI_STATUS
226acpidev_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 */
244static ACPI_STATUS
245acpidev_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 */
312static ACPI_STATUS
313acpidev_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
373static ACPI_STATUS
374acpidev_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
426static ACPI_STATUS
427acpidev_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
455static ACPI_STATUS
456acpidev_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
481static ACPI_STATUS
482acpidev_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
544static acpidev_filter_result_t
545acpidev_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
597static acpidev_filter_result_t
598acpidev_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
616static ACPI_STATUS
617acpidev_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
718static void
719acpidev_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 */
742static int
743acpidev_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
770static int
771acpidev_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
784static int
785acpidev_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