xref: /onnv-gate/usr/src/uts/i86pc/io/acpi/acpidev/acpidev_cpu.c (revision 12004:93f274d4a367)
110394SMichael.Corcoran@Sun.COM /*
210394SMichael.Corcoran@Sun.COM  * CDDL HEADER START
310394SMichael.Corcoran@Sun.COM  *
410394SMichael.Corcoran@Sun.COM  * The contents of this file are subject to the terms of the
510394SMichael.Corcoran@Sun.COM  * Common Development and Distribution License (the "License").
610394SMichael.Corcoran@Sun.COM  * You may not use this file except in compliance with the License.
710394SMichael.Corcoran@Sun.COM  *
810394SMichael.Corcoran@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910394SMichael.Corcoran@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1010394SMichael.Corcoran@Sun.COM  * See the License for the specific language governing permissions
1110394SMichael.Corcoran@Sun.COM  * and limitations under the License.
1210394SMichael.Corcoran@Sun.COM  *
1310394SMichael.Corcoran@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1410394SMichael.Corcoran@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510394SMichael.Corcoran@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1610394SMichael.Corcoran@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1710394SMichael.Corcoran@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1810394SMichael.Corcoran@Sun.COM  *
1910394SMichael.Corcoran@Sun.COM  * CDDL HEADER END
2010394SMichael.Corcoran@Sun.COM  */
2110394SMichael.Corcoran@Sun.COM 
2210394SMichael.Corcoran@Sun.COM /*
2310394SMichael.Corcoran@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2410394SMichael.Corcoran@Sun.COM  * Use is subject to license terms.
2510394SMichael.Corcoran@Sun.COM  */
2610394SMichael.Corcoran@Sun.COM /*
27*12004Sjiang.liu@intel.com  * Copyright (c) 2009-2010, Intel Corporation.
2810394SMichael.Corcoran@Sun.COM  * All rights reserved.
2910394SMichael.Corcoran@Sun.COM  */
3010394SMichael.Corcoran@Sun.COM 
3110394SMichael.Corcoran@Sun.COM /*
3210394SMichael.Corcoran@Sun.COM  * [Support of X2APIC]
3310394SMichael.Corcoran@Sun.COM  * According to the ACPI Spec, when using the X2APIC interrupt model, logical
3410394SMichael.Corcoran@Sun.COM  * processors with APIC ID values of 255 and greater are required to have a
3510394SMichael.Corcoran@Sun.COM  * Processor Device object and must convey the Processor's APIC information to
3610394SMichael.Corcoran@Sun.COM  * OSPM using the Processor Local X2APIC structure. Logical Processors with APIC
3710394SMichael.Corcoran@Sun.COM  * ID values less than 255 must use the Processor Local XAPIC structure to
3810394SMichael.Corcoran@Sun.COM  * convey their APIC information to OSPM.
3910394SMichael.Corcoran@Sun.COM  */
4010394SMichael.Corcoran@Sun.COM 
4110394SMichael.Corcoran@Sun.COM #include <sys/types.h>
4210394SMichael.Corcoran@Sun.COM #include <sys/atomic.h>
4310394SMichael.Corcoran@Sun.COM #include <sys/bootconf.h>
4410394SMichael.Corcoran@Sun.COM #include <sys/cpuvar.h>
4510394SMichael.Corcoran@Sun.COM #include <sys/machsystm.h>
46*12004Sjiang.liu@intel.com #include <sys/note.h>
4710394SMichael.Corcoran@Sun.COM #include <sys/psm_types.h>
4810394SMichael.Corcoran@Sun.COM #include <sys/x86_archext.h>
4910394SMichael.Corcoran@Sun.COM #include <sys/sunddi.h>
5010394SMichael.Corcoran@Sun.COM #include <sys/sunndi.h>
5110394SMichael.Corcoran@Sun.COM #include <sys/acpi/acpi.h>
5210394SMichael.Corcoran@Sun.COM #include <sys/acpica.h>
5310394SMichael.Corcoran@Sun.COM #include <sys/acpidev.h>
5410394SMichael.Corcoran@Sun.COM #include <sys/acpidev_impl.h>
5510394SMichael.Corcoran@Sun.COM 
5610394SMichael.Corcoran@Sun.COM struct acpidev_cpu_map_item {
5710394SMichael.Corcoran@Sun.COM 	uint32_t	proc_id;
5810394SMichael.Corcoran@Sun.COM 	uint32_t	apic_id;
5910394SMichael.Corcoran@Sun.COM };
6010394SMichael.Corcoran@Sun.COM 
6110394SMichael.Corcoran@Sun.COM struct acpidev_cpu_MAT_arg {
6210394SMichael.Corcoran@Sun.COM 	boolean_t	found;
6310394SMichael.Corcoran@Sun.COM 	boolean_t	enabled;
6410394SMichael.Corcoran@Sun.COM 	uint32_t	proc_id;
6510394SMichael.Corcoran@Sun.COM 	uint32_t	apic_id;
6610394SMichael.Corcoran@Sun.COM };
6710394SMichael.Corcoran@Sun.COM 
6810394SMichael.Corcoran@Sun.COM static ACPI_STATUS acpidev_cpu_pre_probe(acpidev_walk_info_t *infop);
6910394SMichael.Corcoran@Sun.COM static ACPI_STATUS acpidev_cpu_post_probe(acpidev_walk_info_t *infop);
7010394SMichael.Corcoran@Sun.COM static ACPI_STATUS acpidev_cpu_probe(acpidev_walk_info_t *infop);
7110394SMichael.Corcoran@Sun.COM static acpidev_filter_result_t acpidev_cpu_filter(acpidev_walk_info_t *infop,
7210394SMichael.Corcoran@Sun.COM     char *devname, int maxlen);
7310394SMichael.Corcoran@Sun.COM static ACPI_STATUS acpidev_cpu_init(acpidev_walk_info_t *infop);
74*12004Sjiang.liu@intel.com static void acpidev_cpu_fini(ACPI_HANDLE hdl, acpidev_data_handle_t dhdl,
75*12004Sjiang.liu@intel.com     acpidev_class_t *clsp);
7610394SMichael.Corcoran@Sun.COM 
7710394SMichael.Corcoran@Sun.COM static acpidev_filter_result_t acpidev_cpu_filter_func(
7810394SMichael.Corcoran@Sun.COM     acpidev_walk_info_t *infop, ACPI_HANDLE hdl, acpidev_filter_rule_t *afrp,
7910394SMichael.Corcoran@Sun.COM     char *devname, int len);
80*12004Sjiang.liu@intel.com static int acpidev_cpu_create_dip(cpu_t *, dev_info_t **);
81*12004Sjiang.liu@intel.com static int acpidev_cpu_get_dip(cpu_t *, dev_info_t **);
8210394SMichael.Corcoran@Sun.COM 
8310394SMichael.Corcoran@Sun.COM /*
8410394SMichael.Corcoran@Sun.COM  * Default class driver for ACPI processor/CPU objects.
8510394SMichael.Corcoran@Sun.COM  */
8610394SMichael.Corcoran@Sun.COM acpidev_class_t acpidev_class_cpu = {
8710394SMichael.Corcoran@Sun.COM 	0,				/* adc_refcnt */
8810394SMichael.Corcoran@Sun.COM 	ACPIDEV_CLASS_REV1,		/* adc_version */
8910394SMichael.Corcoran@Sun.COM 	ACPIDEV_CLASS_ID_CPU,		/* adc_class_id */
9010394SMichael.Corcoran@Sun.COM 	"ACPI CPU",			/* adc_class_name */
9110394SMichael.Corcoran@Sun.COM 	ACPIDEV_TYPE_CPU,		/* adc_dev_type */
9210394SMichael.Corcoran@Sun.COM 	NULL,				/* adc_private */
9310394SMichael.Corcoran@Sun.COM 	acpidev_cpu_pre_probe,		/* adc_pre_probe */
9410394SMichael.Corcoran@Sun.COM 	acpidev_cpu_post_probe,		/* adc_post_probe */
9510394SMichael.Corcoran@Sun.COM 	acpidev_cpu_probe,		/* adc_probe */
9610394SMichael.Corcoran@Sun.COM 	acpidev_cpu_filter,		/* adc_filter */
9710394SMichael.Corcoran@Sun.COM 	acpidev_cpu_init,		/* adc_init */
98*12004Sjiang.liu@intel.com 	acpidev_cpu_fini,		/* adc_fini */
9910394SMichael.Corcoran@Sun.COM };
10010394SMichael.Corcoran@Sun.COM 
10110394SMichael.Corcoran@Sun.COM /*
10210394SMichael.Corcoran@Sun.COM  * List of class drivers which will be called in order when handling
10310394SMichael.Corcoran@Sun.COM  * children of ACPI cpu/processor objects.
10410394SMichael.Corcoran@Sun.COM  */
10510394SMichael.Corcoran@Sun.COM acpidev_class_list_t *acpidev_class_list_cpu = NULL;
10610394SMichael.Corcoran@Sun.COM 
10710394SMichael.Corcoran@Sun.COM /* Filter rule table for the first probe at boot time. */
10810394SMichael.Corcoran@Sun.COM static acpidev_filter_rule_t acpidev_cpu_filters[] = {
10910394SMichael.Corcoran@Sun.COM 	{	/* Skip all processors under root node, should be there. */
11010394SMichael.Corcoran@Sun.COM 		NULL,
11110394SMichael.Corcoran@Sun.COM 		0,
11210394SMichael.Corcoran@Sun.COM 		ACPIDEV_FILTER_SKIP,
11310394SMichael.Corcoran@Sun.COM 		NULL,
11410394SMichael.Corcoran@Sun.COM 		1,
11510394SMichael.Corcoran@Sun.COM 		1,
11610394SMichael.Corcoran@Sun.COM 		NULL,
11710394SMichael.Corcoran@Sun.COM 		NULL,
11810394SMichael.Corcoran@Sun.COM 	},
11910394SMichael.Corcoran@Sun.COM 	{	/* Create and scan other processor objects */
12010394SMichael.Corcoran@Sun.COM 		acpidev_cpu_filter_func,
12110394SMichael.Corcoran@Sun.COM 		0,
12210394SMichael.Corcoran@Sun.COM 		ACPIDEV_FILTER_DEFAULT,
12310394SMichael.Corcoran@Sun.COM 		&acpidev_class_list_cpu,
12410394SMichael.Corcoran@Sun.COM 		2,
12510394SMichael.Corcoran@Sun.COM 		INT_MAX,
12610394SMichael.Corcoran@Sun.COM 		NULL,
12710394SMichael.Corcoran@Sun.COM 		ACPIDEV_NODE_NAME_CPU,
12810394SMichael.Corcoran@Sun.COM 	}
12910394SMichael.Corcoran@Sun.COM };
13010394SMichael.Corcoran@Sun.COM 
13110394SMichael.Corcoran@Sun.COM /* ACPI/PNP hardware id for processor. */
13210394SMichael.Corcoran@Sun.COM static char *acpidev_processor_device_ids[] = {
13310394SMichael.Corcoran@Sun.COM 	ACPIDEV_HID_CPU,
13410394SMichael.Corcoran@Sun.COM };
13510394SMichael.Corcoran@Sun.COM 
13610394SMichael.Corcoran@Sun.COM static char *acpidev_cpu_uid_formats[] = {
13710394SMichael.Corcoran@Sun.COM 	"SCK%x-CPU%x",
13810394SMichael.Corcoran@Sun.COM };
13910394SMichael.Corcoran@Sun.COM 
140*12004Sjiang.liu@intel.com static ACPI_HANDLE acpidev_cpu_map_hdl;
141*12004Sjiang.liu@intel.com static uint32_t acpidev_cpu_map_count;
142*12004Sjiang.liu@intel.com static struct acpidev_cpu_map_item *acpidev_cpu_map;
14310394SMichael.Corcoran@Sun.COM 
14410394SMichael.Corcoran@Sun.COM extern int (*psm_cpu_create_devinfo)(cpu_t *, dev_info_t **);
145*12004Sjiang.liu@intel.com static int (*psm_cpu_create_devinfo_old)(cpu_t *, dev_info_t **);
146*12004Sjiang.liu@intel.com extern int (*psm_cpu_get_devinfo)(cpu_t *, dev_info_t **);
147*12004Sjiang.liu@intel.com static int (*psm_cpu_get_devinfo_old)(cpu_t *, dev_info_t **);
14810394SMichael.Corcoran@Sun.COM 
14910394SMichael.Corcoran@Sun.COM /* Count how many enabled CPUs are in the MADT table. */
15010394SMichael.Corcoran@Sun.COM static ACPI_STATUS
acpidev_cpu_count_MADT(ACPI_SUBTABLE_HEADER * ap,void * context)15110394SMichael.Corcoran@Sun.COM acpidev_cpu_count_MADT(ACPI_SUBTABLE_HEADER *ap, void *context)
15210394SMichael.Corcoran@Sun.COM {
15310394SMichael.Corcoran@Sun.COM 	uint32_t *cntp;
15410394SMichael.Corcoran@Sun.COM 	ACPI_MADT_LOCAL_APIC *mpa;
15510394SMichael.Corcoran@Sun.COM 	ACPI_MADT_LOCAL_X2APIC *mpx2a;
15610394SMichael.Corcoran@Sun.COM 
15710394SMichael.Corcoran@Sun.COM 	cntp = (uint32_t *)context;
15810394SMichael.Corcoran@Sun.COM 	switch (ap->Type) {
15910394SMichael.Corcoran@Sun.COM 	case ACPI_MADT_TYPE_LOCAL_APIC:
16010394SMichael.Corcoran@Sun.COM 		mpa = (ACPI_MADT_LOCAL_APIC *)ap;
16110394SMichael.Corcoran@Sun.COM 		if (mpa->LapicFlags & ACPI_MADT_ENABLED) {
16210394SMichael.Corcoran@Sun.COM 			ASSERT(mpa->Id != 255);
16310394SMichael.Corcoran@Sun.COM 			(*cntp)++;
16410394SMichael.Corcoran@Sun.COM 		}
16510394SMichael.Corcoran@Sun.COM 		break;
16610394SMichael.Corcoran@Sun.COM 
16710394SMichael.Corcoran@Sun.COM 	case ACPI_MADT_TYPE_LOCAL_X2APIC:
16810394SMichael.Corcoran@Sun.COM 		mpx2a = (ACPI_MADT_LOCAL_X2APIC *)ap;
16910394SMichael.Corcoran@Sun.COM 		/* See comment at beginning about 255 limitation. */
17010394SMichael.Corcoran@Sun.COM 		if ((mpx2a->LapicFlags & ACPI_MADT_ENABLED) &&
17110394SMichael.Corcoran@Sun.COM 		    (mpx2a->LocalApicId >= 255)) {
17210394SMichael.Corcoran@Sun.COM 			(*cntp)++;
17310394SMichael.Corcoran@Sun.COM 		}
17410394SMichael.Corcoran@Sun.COM 		break;
17510394SMichael.Corcoran@Sun.COM 
17610394SMichael.Corcoran@Sun.COM 	default:
17710394SMichael.Corcoran@Sun.COM 		break;
17810394SMichael.Corcoran@Sun.COM 	}
17910394SMichael.Corcoran@Sun.COM 
18010394SMichael.Corcoran@Sun.COM 	return (AE_OK);
18110394SMichael.Corcoran@Sun.COM }
18210394SMichael.Corcoran@Sun.COM 
18310394SMichael.Corcoran@Sun.COM /* Extract information from the enabled CPUs using the MADT table. */
18410394SMichael.Corcoran@Sun.COM static ACPI_STATUS
acpidev_cpu_parse_MADT(ACPI_SUBTABLE_HEADER * ap,void * context)18510394SMichael.Corcoran@Sun.COM acpidev_cpu_parse_MADT(ACPI_SUBTABLE_HEADER *ap, void *context)
18610394SMichael.Corcoran@Sun.COM {
18710394SMichael.Corcoran@Sun.COM 	uint32_t *cntp;
18810394SMichael.Corcoran@Sun.COM 	ACPI_MADT_LOCAL_APIC *mpa;
18910394SMichael.Corcoran@Sun.COM 	ACPI_MADT_LOCAL_X2APIC *mpx2a;
19010394SMichael.Corcoran@Sun.COM 
19110394SMichael.Corcoran@Sun.COM 	cntp = (uint32_t *)context;
19210394SMichael.Corcoran@Sun.COM 	switch (ap->Type) {
19310394SMichael.Corcoran@Sun.COM 	case ACPI_MADT_TYPE_LOCAL_APIC:
19410394SMichael.Corcoran@Sun.COM 		mpa = (ACPI_MADT_LOCAL_APIC *)ap;
19510394SMichael.Corcoran@Sun.COM 		if (mpa->LapicFlags & ACPI_MADT_ENABLED) {
19610394SMichael.Corcoran@Sun.COM 			ASSERT(mpa->Id != 255);
19710394SMichael.Corcoran@Sun.COM 			ASSERT(*cntp < acpidev_cpu_map_count);
19810394SMichael.Corcoran@Sun.COM 			acpidev_cpu_map[*cntp].proc_id = mpa->ProcessorId;
19910394SMichael.Corcoran@Sun.COM 			acpidev_cpu_map[*cntp].apic_id = mpa->Id;
20010394SMichael.Corcoran@Sun.COM 			(*cntp)++;
20110394SMichael.Corcoran@Sun.COM 		}
20210394SMichael.Corcoran@Sun.COM 		break;
20310394SMichael.Corcoran@Sun.COM 
20410394SMichael.Corcoran@Sun.COM 	case ACPI_MADT_TYPE_LOCAL_X2APIC:
20510394SMichael.Corcoran@Sun.COM 		mpx2a = (ACPI_MADT_LOCAL_X2APIC *)ap;
20610394SMichael.Corcoran@Sun.COM 		/* See comment at beginning about 255 limitation. */
20710394SMichael.Corcoran@Sun.COM 		if (mpx2a->LocalApicId < 255) {
20810394SMichael.Corcoran@Sun.COM 			ACPIDEV_DEBUG(CE_WARN,
209*12004Sjiang.liu@intel.com 			    "!acpidev: encountered CPU with X2APIC Id < 255.");
21010394SMichael.Corcoran@Sun.COM 		} else if (mpx2a->LapicFlags & ACPI_MADT_ENABLED) {
21110394SMichael.Corcoran@Sun.COM 			ASSERT(*cntp < acpidev_cpu_map_count);
21210394SMichael.Corcoran@Sun.COM 			acpidev_cpu_map[*cntp].proc_id = mpx2a->Uid;
21310394SMichael.Corcoran@Sun.COM 			acpidev_cpu_map[*cntp].apic_id = mpx2a->LocalApicId;
21410394SMichael.Corcoran@Sun.COM 			(*cntp)++;
21510394SMichael.Corcoran@Sun.COM 		}
21610394SMichael.Corcoran@Sun.COM 		break;
21710394SMichael.Corcoran@Sun.COM 
21810394SMichael.Corcoran@Sun.COM 	default:
21910394SMichael.Corcoran@Sun.COM 		break;
22010394SMichael.Corcoran@Sun.COM 	}
22110394SMichael.Corcoran@Sun.COM 
22210394SMichael.Corcoran@Sun.COM 	return (AE_OK);
22310394SMichael.Corcoran@Sun.COM }
22410394SMichael.Corcoran@Sun.COM 
22510394SMichael.Corcoran@Sun.COM static ACPI_STATUS
acpidev_cpu_get_apicid(uint32_t procid,uint32_t * apicidp)22610394SMichael.Corcoran@Sun.COM acpidev_cpu_get_apicid(uint32_t procid, uint32_t *apicidp)
22710394SMichael.Corcoran@Sun.COM {
22810394SMichael.Corcoran@Sun.COM 	uint32_t i;
22910394SMichael.Corcoran@Sun.COM 
23010394SMichael.Corcoran@Sun.COM 	for (i = 0; i < acpidev_cpu_map_count; i++) {
23110394SMichael.Corcoran@Sun.COM 		if (acpidev_cpu_map[i].proc_id == procid) {
23210394SMichael.Corcoran@Sun.COM 			*apicidp = acpidev_cpu_map[i].apic_id;
23310394SMichael.Corcoran@Sun.COM 			return (AE_OK);
23410394SMichael.Corcoran@Sun.COM 		}
23510394SMichael.Corcoran@Sun.COM 	}
23610394SMichael.Corcoran@Sun.COM 
23710394SMichael.Corcoran@Sun.COM 	return (AE_NOT_FOUND);
23810394SMichael.Corcoran@Sun.COM }
23910394SMichael.Corcoran@Sun.COM 
24010394SMichael.Corcoran@Sun.COM /*
24110394SMichael.Corcoran@Sun.COM  * Extract information for enabled CPUs from the buffer returned
24210394SMichael.Corcoran@Sun.COM  * by the _MAT method.
24310394SMichael.Corcoran@Sun.COM  */
24410394SMichael.Corcoran@Sun.COM static ACPI_STATUS
acpidev_cpu_query_MAT(ACPI_SUBTABLE_HEADER * ap,void * context)24510394SMichael.Corcoran@Sun.COM acpidev_cpu_query_MAT(ACPI_SUBTABLE_HEADER *ap, void *context)
24610394SMichael.Corcoran@Sun.COM {
24710394SMichael.Corcoran@Sun.COM 	ACPI_MADT_LOCAL_APIC *mpa;
24810394SMichael.Corcoran@Sun.COM 	ACPI_MADT_LOCAL_X2APIC *mpx2a;
24910394SMichael.Corcoran@Sun.COM 	struct acpidev_cpu_MAT_arg *rp;
25010394SMichael.Corcoran@Sun.COM 
25110394SMichael.Corcoran@Sun.COM 	rp = (struct acpidev_cpu_MAT_arg *)context;
25210394SMichael.Corcoran@Sun.COM 	switch (ap->Type) {
25310394SMichael.Corcoran@Sun.COM 	case ACPI_MADT_TYPE_LOCAL_APIC:
25410394SMichael.Corcoran@Sun.COM 		mpa = (ACPI_MADT_LOCAL_APIC *)ap;
25510394SMichael.Corcoran@Sun.COM 		ASSERT(mpa->Id != 255);
25610394SMichael.Corcoran@Sun.COM 		rp->found = B_TRUE;
25710394SMichael.Corcoran@Sun.COM 		rp->proc_id = mpa->ProcessorId;
25810394SMichael.Corcoran@Sun.COM 		rp->apic_id = mpa->Id;
25910394SMichael.Corcoran@Sun.COM 		if (mpa->LapicFlags & ACPI_MADT_ENABLED) {
26010394SMichael.Corcoran@Sun.COM 			rp->enabled = B_TRUE;
26110394SMichael.Corcoran@Sun.COM 		} else {
26210394SMichael.Corcoran@Sun.COM 			rp->enabled = B_FALSE;
26310394SMichael.Corcoran@Sun.COM 		}
26410394SMichael.Corcoran@Sun.COM 		return (AE_CTRL_TERMINATE);
26510394SMichael.Corcoran@Sun.COM 
26610394SMichael.Corcoran@Sun.COM 	case ACPI_MADT_TYPE_LOCAL_X2APIC:
26710394SMichael.Corcoran@Sun.COM 		mpx2a = (ACPI_MADT_LOCAL_X2APIC *)ap;
26810394SMichael.Corcoran@Sun.COM 		if (mpx2a->LocalApicId >= 255) {
26910394SMichael.Corcoran@Sun.COM 			rp->found = B_TRUE;
27010394SMichael.Corcoran@Sun.COM 			rp->proc_id = mpx2a->Uid;
27110394SMichael.Corcoran@Sun.COM 			rp->apic_id = mpx2a->LocalApicId;
27210394SMichael.Corcoran@Sun.COM 			if (mpx2a->LapicFlags & ACPI_MADT_ENABLED) {
27310394SMichael.Corcoran@Sun.COM 				rp->enabled = B_TRUE;
27410394SMichael.Corcoran@Sun.COM 			} else {
27510394SMichael.Corcoran@Sun.COM 				rp->enabled = B_FALSE;
27610394SMichael.Corcoran@Sun.COM 			}
27710394SMichael.Corcoran@Sun.COM 			return (AE_CTRL_TERMINATE);
27810394SMichael.Corcoran@Sun.COM 		} else {
279*12004Sjiang.liu@intel.com 			ACPIDEV_DEBUG(CE_WARN, "!acpidev: encountered CPU "
28010394SMichael.Corcoran@Sun.COM 			    "with X2APIC Id < 255 in _MAT.");
28110394SMichael.Corcoran@Sun.COM 		}
28210394SMichael.Corcoran@Sun.COM 		break;
28310394SMichael.Corcoran@Sun.COM 
28410394SMichael.Corcoran@Sun.COM 	case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
28510394SMichael.Corcoran@Sun.COM 		/* UNIMPLEMENTED */
28610394SMichael.Corcoran@Sun.COM 		break;
28710394SMichael.Corcoran@Sun.COM 
28810394SMichael.Corcoran@Sun.COM 	case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI:
28910394SMichael.Corcoran@Sun.COM 		/* UNIMPLEMENTED */
29010394SMichael.Corcoran@Sun.COM 		break;
29110394SMichael.Corcoran@Sun.COM 
29210394SMichael.Corcoran@Sun.COM 	default:
29310394SMichael.Corcoran@Sun.COM 		/*
29410394SMichael.Corcoran@Sun.COM 		 * According to the ACPI Spec, the buffer returned by _MAT
29510394SMichael.Corcoran@Sun.COM 		 * for a processor object should only contain Local APIC,
29610394SMichael.Corcoran@Sun.COM 		 * Local SAPIC, and local APIC NMI entries.
29710394SMichael.Corcoran@Sun.COM 		 * x2APIC Specification extends it to support Processor
29810394SMichael.Corcoran@Sun.COM 		 * x2APIC and x2APIC NMI Structure.
29910394SMichael.Corcoran@Sun.COM 		 */
30010394SMichael.Corcoran@Sun.COM 		ACPIDEV_DEBUG(CE_NOTE,
301*12004Sjiang.liu@intel.com 		    "!acpidev: unknown APIC entry type %u in _MAT.", ap->Type);
30210394SMichael.Corcoran@Sun.COM 		break;
30310394SMichael.Corcoran@Sun.COM 	}
30410394SMichael.Corcoran@Sun.COM 
30510394SMichael.Corcoran@Sun.COM 	return (AE_OK);
30610394SMichael.Corcoran@Sun.COM }
30710394SMichael.Corcoran@Sun.COM 
30810394SMichael.Corcoran@Sun.COM /*
30910394SMichael.Corcoran@Sun.COM  * Query ACPI processor ID by evaluating ACPI _MAT, _UID, and PROCESSOR
31010394SMichael.Corcoran@Sun.COM  * objects.
31110394SMichael.Corcoran@Sun.COM  */
31210394SMichael.Corcoran@Sun.COM static ACPI_STATUS
acpidev_cpu_get_procid(acpidev_walk_info_t * infop,uint32_t * idp)31310394SMichael.Corcoran@Sun.COM acpidev_cpu_get_procid(acpidev_walk_info_t *infop, uint32_t *idp)
31410394SMichael.Corcoran@Sun.COM {
31510394SMichael.Corcoran@Sun.COM 	int id;
31610394SMichael.Corcoran@Sun.COM 	ACPI_HANDLE hdl;
31710394SMichael.Corcoran@Sun.COM 	struct acpidev_cpu_MAT_arg mat;
31810394SMichael.Corcoran@Sun.COM 
31910394SMichael.Corcoran@Sun.COM 	if (infop->awi_info->Type != ACPI_TYPE_PROCESSOR &&
32010394SMichael.Corcoran@Sun.COM 	    infop->awi_info->Type != ACPI_TYPE_DEVICE) {
32110394SMichael.Corcoran@Sun.COM 		ACPIDEV_DEBUG(CE_WARN,
322*12004Sjiang.liu@intel.com 		    "!acpidev: object %s is not PROCESSOR or DEVICE.",
32310394SMichael.Corcoran@Sun.COM 		    infop->awi_name);
32410394SMichael.Corcoran@Sun.COM 		return (AE_BAD_PARAMETER);
32510394SMichael.Corcoran@Sun.COM 	}
32610394SMichael.Corcoran@Sun.COM 	hdl = infop->awi_hdl;
32710394SMichael.Corcoran@Sun.COM 
32810394SMichael.Corcoran@Sun.COM 	/*
32910394SMichael.Corcoran@Sun.COM 	 * First try to evaluate _MAT.
33010394SMichael.Corcoran@Sun.COM 	 * According to the ACPI Spec3.0b, it's legal for ACPI PROCESSOR objects
33110394SMichael.Corcoran@Sun.COM 	 * to have ACPI method objects.
33210394SMichael.Corcoran@Sun.COM 	 */
33310394SMichael.Corcoran@Sun.COM 	bzero(&mat, sizeof (mat));
33410394SMichael.Corcoran@Sun.COM 	(void) acpidev_walk_apic(NULL, hdl, ACPIDEV_METHOD_NAME_MAT,
33510394SMichael.Corcoran@Sun.COM 	    acpidev_cpu_query_MAT, &mat);
33610394SMichael.Corcoran@Sun.COM 	if (mat.found) {
33710394SMichael.Corcoran@Sun.COM 		*idp = mat.proc_id;
33810394SMichael.Corcoran@Sun.COM 		return (AE_OK);
33910394SMichael.Corcoran@Sun.COM 	}
34010394SMichael.Corcoran@Sun.COM 
34110394SMichael.Corcoran@Sun.COM 	/* Then evalute PROCESSOR object. */
34210394SMichael.Corcoran@Sun.COM 	if (infop->awi_info->Type == ACPI_TYPE_PROCESSOR) {
34310394SMichael.Corcoran@Sun.COM 		ACPI_BUFFER rb;
34410394SMichael.Corcoran@Sun.COM 
34510394SMichael.Corcoran@Sun.COM 		rb.Pointer = NULL;
34610394SMichael.Corcoran@Sun.COM 		rb.Length = ACPI_ALLOCATE_BUFFER;
34710394SMichael.Corcoran@Sun.COM 		if (ACPI_SUCCESS(AcpiEvaluateObjectTyped(hdl, NULL, NULL, &rb,
34810394SMichael.Corcoran@Sun.COM 		    ACPI_TYPE_PROCESSOR))) {
34910394SMichael.Corcoran@Sun.COM 			*idp = ((ACPI_OBJECT *)rb.Pointer)->Processor.ProcId;
35010394SMichael.Corcoran@Sun.COM 			AcpiOsFree(rb.Pointer);
35110394SMichael.Corcoran@Sun.COM 			return (AE_OK);
35210394SMichael.Corcoran@Sun.COM 		} else {
35310394SMichael.Corcoran@Sun.COM 			ACPIDEV_DEBUG(CE_WARN,
354*12004Sjiang.liu@intel.com 			    "!acpidev: failed to evaluate ACPI object %s.",
35510394SMichael.Corcoran@Sun.COM 			    infop->awi_name);
35610394SMichael.Corcoran@Sun.COM 		}
35710394SMichael.Corcoran@Sun.COM 	}
35810394SMichael.Corcoran@Sun.COM 
35910394SMichael.Corcoran@Sun.COM 	/*
36010394SMichael.Corcoran@Sun.COM 	 * Finally, try to evalute the _UID method.
36110394SMichael.Corcoran@Sun.COM 	 * According to the ACPI Spec3.0b, it's legal for ACPI PROCESSOR objects
36210394SMichael.Corcoran@Sun.COM 	 * to have ACPI method objects.
36310394SMichael.Corcoran@Sun.COM 	 * The CPU _UID method should return Processor Id as an integer on x86.
36410394SMichael.Corcoran@Sun.COM 	 */
36510394SMichael.Corcoran@Sun.COM 	if (ACPI_SUCCESS(acpica_eval_int(hdl, METHOD_NAME__UID, &id))) {
36610394SMichael.Corcoran@Sun.COM 		*idp = id;
36710394SMichael.Corcoran@Sun.COM 		return (AE_OK);
36810394SMichael.Corcoran@Sun.COM 	}
36910394SMichael.Corcoran@Sun.COM 
37010394SMichael.Corcoran@Sun.COM 	return (AE_NOT_FOUND);
37110394SMichael.Corcoran@Sun.COM }
37210394SMichael.Corcoran@Sun.COM 
37310394SMichael.Corcoran@Sun.COM static ACPI_STATUS
acpidev_cpu_get_proximity_id(ACPI_HANDLE hdl,uint32_t apicid,uint32_t * pxmidp)374*12004Sjiang.liu@intel.com acpidev_cpu_get_proximity_id(ACPI_HANDLE hdl, uint32_t apicid, uint32_t *pxmidp)
375*12004Sjiang.liu@intel.com {
376*12004Sjiang.liu@intel.com 	int len, off;
377*12004Sjiang.liu@intel.com 	ACPI_SUBTABLE_HEADER *sp;
378*12004Sjiang.liu@intel.com 	ACPI_SRAT_CPU_AFFINITY *xp;
379*12004Sjiang.liu@intel.com 	ACPI_SRAT_X2APIC_CPU_AFFINITY *x2p;
380*12004Sjiang.liu@intel.com 
381*12004Sjiang.liu@intel.com 	ASSERT(hdl != NULL);
382*12004Sjiang.liu@intel.com 	ASSERT(pxmidp != NULL);
383*12004Sjiang.liu@intel.com 	*pxmidp = UINT32_MAX;
384*12004Sjiang.liu@intel.com 
385*12004Sjiang.liu@intel.com 	if (ACPI_SUCCESS(acpidev_eval_pxm(hdl, pxmidp))) {
386*12004Sjiang.liu@intel.com 		return (AE_OK);
387*12004Sjiang.liu@intel.com 	}
388*12004Sjiang.liu@intel.com 	if (acpidev_srat_tbl_ptr == NULL) {
389*12004Sjiang.liu@intel.com 		return (AE_NOT_FOUND);
390*12004Sjiang.liu@intel.com 	}
391*12004Sjiang.liu@intel.com 
392*12004Sjiang.liu@intel.com 	/* Search the static ACPI SRAT table for proximity domain id. */
393*12004Sjiang.liu@intel.com 	sp = (ACPI_SUBTABLE_HEADER *)(acpidev_srat_tbl_ptr + 1);
394*12004Sjiang.liu@intel.com 	len = acpidev_srat_tbl_ptr->Header.Length;
395*12004Sjiang.liu@intel.com 	off = sizeof (*acpidev_srat_tbl_ptr);
396*12004Sjiang.liu@intel.com 	while (off < len) {
397*12004Sjiang.liu@intel.com 		switch (sp->Type) {
398*12004Sjiang.liu@intel.com 		case ACPI_SRAT_TYPE_CPU_AFFINITY:
399*12004Sjiang.liu@intel.com 			xp = (ACPI_SRAT_CPU_AFFINITY *)sp;
400*12004Sjiang.liu@intel.com 			if ((xp->Flags & ACPI_SRAT_CPU_ENABLED) &&
401*12004Sjiang.liu@intel.com 			    xp->ApicId == apicid) {
402*12004Sjiang.liu@intel.com 				*pxmidp = xp->ProximityDomainLo;
403*12004Sjiang.liu@intel.com 				*pxmidp |= xp->ProximityDomainHi[0] << 8;
404*12004Sjiang.liu@intel.com 				*pxmidp |= xp->ProximityDomainHi[1] << 16;
405*12004Sjiang.liu@intel.com 				*pxmidp |= xp->ProximityDomainHi[2] << 24;
406*12004Sjiang.liu@intel.com 				return (AE_OK);
407*12004Sjiang.liu@intel.com 			}
408*12004Sjiang.liu@intel.com 			break;
409*12004Sjiang.liu@intel.com 
410*12004Sjiang.liu@intel.com 		case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY:
411*12004Sjiang.liu@intel.com 			x2p = (ACPI_SRAT_X2APIC_CPU_AFFINITY *)sp;
412*12004Sjiang.liu@intel.com 			if ((x2p->Flags & ACPI_SRAT_CPU_ENABLED) &&
413*12004Sjiang.liu@intel.com 			    x2p->ApicId == apicid) {
414*12004Sjiang.liu@intel.com 				*pxmidp = x2p->ProximityDomain;
415*12004Sjiang.liu@intel.com 				return (AE_OK);
416*12004Sjiang.liu@intel.com 			}
417*12004Sjiang.liu@intel.com 			break;
418*12004Sjiang.liu@intel.com 		}
419*12004Sjiang.liu@intel.com 		off += sp->Length;
420*12004Sjiang.liu@intel.com 		sp = (ACPI_SUBTABLE_HEADER *)(((char *)sp) + sp->Length);
421*12004Sjiang.liu@intel.com 	}
422*12004Sjiang.liu@intel.com 
423*12004Sjiang.liu@intel.com 	return (AE_NOT_FOUND);
424*12004Sjiang.liu@intel.com }
425*12004Sjiang.liu@intel.com 
426*12004Sjiang.liu@intel.com static ACPI_STATUS
acpidev_cpu_pre_probe(acpidev_walk_info_t * infop)42710394SMichael.Corcoran@Sun.COM acpidev_cpu_pre_probe(acpidev_walk_info_t *infop)
42810394SMichael.Corcoran@Sun.COM {
42910394SMichael.Corcoran@Sun.COM 	uint32_t count = 0;
43010394SMichael.Corcoran@Sun.COM 
43110394SMichael.Corcoran@Sun.COM 	/* Parse and cache APIC info in MADT on the first probe at boot time. */
43210394SMichael.Corcoran@Sun.COM 	ASSERT(infop != NULL);
43310394SMichael.Corcoran@Sun.COM 	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE &&
43410394SMichael.Corcoran@Sun.COM 	    acpidev_cpu_map_hdl == NULL) {
435*12004Sjiang.liu@intel.com 		/* Parse CPU relative information in the ACPI MADT table. */
43610394SMichael.Corcoran@Sun.COM 		(void) acpidev_walk_apic(NULL, NULL, NULL,
43710394SMichael.Corcoran@Sun.COM 		    acpidev_cpu_count_MADT, &acpidev_cpu_map_count);
43810394SMichael.Corcoran@Sun.COM 		acpidev_cpu_map = kmem_zalloc(sizeof (acpidev_cpu_map[0])
43910394SMichael.Corcoran@Sun.COM 		    * acpidev_cpu_map_count, KM_SLEEP);
44010394SMichael.Corcoran@Sun.COM 		(void) acpidev_walk_apic(NULL, NULL, NULL,
44110394SMichael.Corcoran@Sun.COM 		    acpidev_cpu_parse_MADT, &count);
44210394SMichael.Corcoran@Sun.COM 		ASSERT(count == acpidev_cpu_map_count);
44310394SMichael.Corcoran@Sun.COM 		acpidev_cpu_map_hdl = infop->awi_hdl;
444*12004Sjiang.liu@intel.com 
445*12004Sjiang.liu@intel.com 		/* Cache pointer to the ACPI SRAT table. */
446*12004Sjiang.liu@intel.com 		if (ACPI_FAILURE(AcpiGetTable(ACPI_SIG_SRAT, 1,
447*12004Sjiang.liu@intel.com 		    (ACPI_TABLE_HEADER **)&acpidev_srat_tbl_ptr))) {
448*12004Sjiang.liu@intel.com 			acpidev_srat_tbl_ptr = NULL;
449*12004Sjiang.liu@intel.com 		}
45010394SMichael.Corcoran@Sun.COM 	}
45110394SMichael.Corcoran@Sun.COM 
45210394SMichael.Corcoran@Sun.COM 	return (AE_OK);
45310394SMichael.Corcoran@Sun.COM }
45410394SMichael.Corcoran@Sun.COM 
45510394SMichael.Corcoran@Sun.COM static ACPI_STATUS
acpidev_cpu_post_probe(acpidev_walk_info_t * infop)45610394SMichael.Corcoran@Sun.COM acpidev_cpu_post_probe(acpidev_walk_info_t *infop)
45710394SMichael.Corcoran@Sun.COM {
45810394SMichael.Corcoran@Sun.COM 	/* Free cached APIC info on the second probe at boot time. */
45910394SMichael.Corcoran@Sun.COM 	ASSERT(infop != NULL);
46010394SMichael.Corcoran@Sun.COM 	if (infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE &&
46110394SMichael.Corcoran@Sun.COM 	    acpidev_cpu_map_hdl != NULL &&
46210394SMichael.Corcoran@Sun.COM 	    infop->awi_hdl == acpidev_cpu_map_hdl) {
46310394SMichael.Corcoran@Sun.COM 		if (acpidev_cpu_map != NULL && acpidev_cpu_map_count != 0) {
46410394SMichael.Corcoran@Sun.COM 			kmem_free(acpidev_cpu_map, sizeof (acpidev_cpu_map[0])
46510394SMichael.Corcoran@Sun.COM 			    * acpidev_cpu_map_count);
46610394SMichael.Corcoran@Sun.COM 		}
46710394SMichael.Corcoran@Sun.COM 		acpidev_cpu_map = NULL;
46810394SMichael.Corcoran@Sun.COM 		acpidev_cpu_map_count = 0;
46910394SMichael.Corcoran@Sun.COM 		acpidev_cpu_map_hdl = NULL;
47010394SMichael.Corcoran@Sun.COM 
47110394SMichael.Corcoran@Sun.COM 		/* replace psm_cpu_create_devinfo with local implementation. */
47210394SMichael.Corcoran@Sun.COM 		psm_cpu_create_devinfo_old = psm_cpu_create_devinfo;
473*12004Sjiang.liu@intel.com 		psm_cpu_create_devinfo = acpidev_cpu_create_dip;
474*12004Sjiang.liu@intel.com 		psm_cpu_get_devinfo_old = psm_cpu_get_devinfo;
475*12004Sjiang.liu@intel.com 		psm_cpu_get_devinfo = acpidev_cpu_get_dip;
47610394SMichael.Corcoran@Sun.COM 	}
47710394SMichael.Corcoran@Sun.COM 
47810394SMichael.Corcoran@Sun.COM 	return (AE_OK);
47910394SMichael.Corcoran@Sun.COM }
48010394SMichael.Corcoran@Sun.COM 
48110394SMichael.Corcoran@Sun.COM static ACPI_STATUS
acpidev_cpu_probe(acpidev_walk_info_t * infop)48210394SMichael.Corcoran@Sun.COM acpidev_cpu_probe(acpidev_walk_info_t *infop)
48310394SMichael.Corcoran@Sun.COM {
48410394SMichael.Corcoran@Sun.COM 	ACPI_STATUS rc = AE_OK;
48510394SMichael.Corcoran@Sun.COM 	int flags;
48610394SMichael.Corcoran@Sun.COM 
48710394SMichael.Corcoran@Sun.COM 	ASSERT(infop != NULL);
48810394SMichael.Corcoran@Sun.COM 	ASSERT(infop->awi_hdl != NULL);
48910394SMichael.Corcoran@Sun.COM 	ASSERT(infop->awi_info != NULL);
49010394SMichael.Corcoran@Sun.COM 	ASSERT(infop->awi_class_curr == &acpidev_class_cpu);
49110394SMichael.Corcoran@Sun.COM 	if (infop->awi_info->Type != ACPI_TYPE_PROCESSOR &&
49210394SMichael.Corcoran@Sun.COM 	    (infop->awi_info->Type != ACPI_TYPE_DEVICE ||
49310394SMichael.Corcoran@Sun.COM 	    acpidev_match_device_id(infop->awi_info,
49410394SMichael.Corcoran@Sun.COM 	    ACPIDEV_ARRAY_PARAM(acpidev_processor_device_ids)) == 0)) {
49510394SMichael.Corcoran@Sun.COM 		return (AE_OK);
49610394SMichael.Corcoran@Sun.COM 	}
49710394SMichael.Corcoran@Sun.COM 
498*12004Sjiang.liu@intel.com 	flags = ACPIDEV_PROCESS_FLAG_SCAN;
499*12004Sjiang.liu@intel.com 	switch (infop->awi_op_type) {
500*12004Sjiang.liu@intel.com 	case  ACPIDEV_OP_BOOT_PROBE:
501*12004Sjiang.liu@intel.com 		/*
502*12004Sjiang.liu@intel.com 		 * Mark device as offline. It will be changed to online state
503*12004Sjiang.liu@intel.com 		 * when the corresponding CPU starts up.
504*12004Sjiang.liu@intel.com 		 */
505*12004Sjiang.liu@intel.com 		if (acpica_get_devcfg_feature(ACPI_DEVCFG_CPU)) {
506*12004Sjiang.liu@intel.com 			flags |= ACPIDEV_PROCESS_FLAG_CREATE |
507*12004Sjiang.liu@intel.com 			    ACPIDEV_PROCESS_FLAG_OFFLINE;
508*12004Sjiang.liu@intel.com 		}
509*12004Sjiang.liu@intel.com 		break;
510*12004Sjiang.liu@intel.com 
511*12004Sjiang.liu@intel.com 	case ACPIDEV_OP_BOOT_REPROBE:
512*12004Sjiang.liu@intel.com 		break;
513*12004Sjiang.liu@intel.com 
514*12004Sjiang.liu@intel.com 	case ACPIDEV_OP_HOTPLUG_PROBE:
515*12004Sjiang.liu@intel.com 		if (acpica_get_devcfg_feature(ACPI_DEVCFG_CPU)) {
516*12004Sjiang.liu@intel.com 			flags |= ACPIDEV_PROCESS_FLAG_CREATE |
517*12004Sjiang.liu@intel.com 			    ACPIDEV_PROCESS_FLAG_OFFLINE |
518*12004Sjiang.liu@intel.com 			    ACPIDEV_PROCESS_FLAG_SYNCSTATUS |
519*12004Sjiang.liu@intel.com 			    ACPIDEV_PROCESS_FLAG_HOLDBRANCH;
520*12004Sjiang.liu@intel.com 		}
521*12004Sjiang.liu@intel.com 		break;
522*12004Sjiang.liu@intel.com 
523*12004Sjiang.liu@intel.com 	default:
524*12004Sjiang.liu@intel.com 		ACPIDEV_DEBUG(CE_WARN, "!acpidev: unknown operation type %u in "
52510394SMichael.Corcoran@Sun.COM 		    "acpidev_cpu_probe().", infop->awi_op_type);
52610394SMichael.Corcoran@Sun.COM 		rc = AE_BAD_PARAMETER;
527*12004Sjiang.liu@intel.com 		break;
528*12004Sjiang.liu@intel.com 	}
529*12004Sjiang.liu@intel.com 
530*12004Sjiang.liu@intel.com 	if (rc == AE_OK) {
531*12004Sjiang.liu@intel.com 		rc = acpidev_process_object(infop, flags);
53210394SMichael.Corcoran@Sun.COM 	}
53310394SMichael.Corcoran@Sun.COM 	if (ACPI_FAILURE(rc) && rc != AE_NOT_EXIST && rc != AE_ALREADY_EXISTS) {
53410394SMichael.Corcoran@Sun.COM 		cmn_err(CE_WARN,
53510394SMichael.Corcoran@Sun.COM 		    "!acpidev: failed to process processor object %s.",
53610394SMichael.Corcoran@Sun.COM 		    infop->awi_name);
53710394SMichael.Corcoran@Sun.COM 	} else {
53810394SMichael.Corcoran@Sun.COM 		rc = AE_OK;
53910394SMichael.Corcoran@Sun.COM 	}
54010394SMichael.Corcoran@Sun.COM 
54110394SMichael.Corcoran@Sun.COM 	return (rc);
54210394SMichael.Corcoran@Sun.COM }
54310394SMichael.Corcoran@Sun.COM 
54410394SMichael.Corcoran@Sun.COM static acpidev_filter_result_t
acpidev_cpu_filter_func(acpidev_walk_info_t * infop,ACPI_HANDLE hdl,acpidev_filter_rule_t * afrp,char * devname,int len)54510394SMichael.Corcoran@Sun.COM acpidev_cpu_filter_func(acpidev_walk_info_t *infop, ACPI_HANDLE hdl,
54610394SMichael.Corcoran@Sun.COM     acpidev_filter_rule_t *afrp, char *devname, int len)
54710394SMichael.Corcoran@Sun.COM {
54810394SMichael.Corcoran@Sun.COM 	acpidev_filter_result_t res;
54910394SMichael.Corcoran@Sun.COM 
55010394SMichael.Corcoran@Sun.COM 	ASSERT(afrp != NULL);
55110394SMichael.Corcoran@Sun.COM 	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
55210394SMichael.Corcoran@Sun.COM 	    infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE) {
55310394SMichael.Corcoran@Sun.COM 		uint32_t procid;
55410394SMichael.Corcoran@Sun.COM 		uint32_t apicid;
55510394SMichael.Corcoran@Sun.COM 
55610394SMichael.Corcoran@Sun.COM 		if (acpidev_cpu_get_procid(infop, &procid) != 0) {
55710394SMichael.Corcoran@Sun.COM 			ACPIDEV_DEBUG(CE_WARN,
558*12004Sjiang.liu@intel.com 			    "!acpidev: failed to query processor id for %s.",
55910394SMichael.Corcoran@Sun.COM 			    infop->awi_name);
56010394SMichael.Corcoran@Sun.COM 			return (ACPIDEV_FILTER_SKIP);
56110394SMichael.Corcoran@Sun.COM 		} else if (acpidev_cpu_get_apicid(procid, &apicid) != 0) {
56210394SMichael.Corcoran@Sun.COM 			ACPIDEV_DEBUG(CE_WARN,
563*12004Sjiang.liu@intel.com 			    "!acpidev: failed to query apic id for %s.",
56410394SMichael.Corcoran@Sun.COM 			    infop->awi_name);
56510394SMichael.Corcoran@Sun.COM 			return (ACPIDEV_FILTER_SKIP);
56610394SMichael.Corcoran@Sun.COM 		}
56710394SMichael.Corcoran@Sun.COM 
56810394SMichael.Corcoran@Sun.COM 		infop->awi_scratchpad[0] = procid;
56910394SMichael.Corcoran@Sun.COM 		infop->awi_scratchpad[1] = apicid;
57010394SMichael.Corcoran@Sun.COM 	} else if (infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
57110394SMichael.Corcoran@Sun.COM 		struct acpidev_cpu_MAT_arg mat;
57210394SMichael.Corcoran@Sun.COM 
57310394SMichael.Corcoran@Sun.COM 		bzero(&mat, sizeof (mat));
57410394SMichael.Corcoran@Sun.COM 		(void) acpidev_walk_apic(NULL, hdl, ACPIDEV_METHOD_NAME_MAT,
57510394SMichael.Corcoran@Sun.COM 		    acpidev_cpu_query_MAT, &mat);
57610394SMichael.Corcoran@Sun.COM 		if (!mat.found) {
57710394SMichael.Corcoran@Sun.COM 			cmn_err(CE_WARN,
57810394SMichael.Corcoran@Sun.COM 			    "!acpidev: failed to walk apic resource for %s.",
57910394SMichael.Corcoran@Sun.COM 			    infop->awi_name);
58010394SMichael.Corcoran@Sun.COM 			return (ACPIDEV_FILTER_SKIP);
58110394SMichael.Corcoran@Sun.COM 		} else if (!mat.enabled) {
58210394SMichael.Corcoran@Sun.COM 			ACPIDEV_DEBUG(CE_NOTE,
583*12004Sjiang.liu@intel.com 			    "!acpidev: CPU %s has been disabled.",
58410394SMichael.Corcoran@Sun.COM 			    infop->awi_name);
58510394SMichael.Corcoran@Sun.COM 			return (ACPIDEV_FILTER_SKIP);
58610394SMichael.Corcoran@Sun.COM 		}
58710394SMichael.Corcoran@Sun.COM 		/* Save processor id and APIC id in scratchpad memory. */
58810394SMichael.Corcoran@Sun.COM 		infop->awi_scratchpad[0] = mat.proc_id;
58910394SMichael.Corcoran@Sun.COM 		infop->awi_scratchpad[1] = mat.apic_id;
59010394SMichael.Corcoran@Sun.COM 	}
59110394SMichael.Corcoran@Sun.COM 
59210394SMichael.Corcoran@Sun.COM 	res = acpidev_filter_default(infop, hdl, afrp, devname, len);
59310394SMichael.Corcoran@Sun.COM 
59410394SMichael.Corcoran@Sun.COM 	return (res);
59510394SMichael.Corcoran@Sun.COM }
59610394SMichael.Corcoran@Sun.COM 
59710394SMichael.Corcoran@Sun.COM static acpidev_filter_result_t
acpidev_cpu_filter(acpidev_walk_info_t * infop,char * devname,int maxlen)59810394SMichael.Corcoran@Sun.COM acpidev_cpu_filter(acpidev_walk_info_t *infop, char *devname, int maxlen)
59910394SMichael.Corcoran@Sun.COM {
60010394SMichael.Corcoran@Sun.COM 	acpidev_filter_result_t res;
60110394SMichael.Corcoran@Sun.COM 
60210394SMichael.Corcoran@Sun.COM 	ASSERT(infop != NULL);
60310394SMichael.Corcoran@Sun.COM 	ASSERT(devname == NULL || maxlen >= ACPIDEV_MAX_NAMELEN);
60410394SMichael.Corcoran@Sun.COM 	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
60510394SMichael.Corcoran@Sun.COM 	    infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE ||
60610394SMichael.Corcoran@Sun.COM 	    infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
60710394SMichael.Corcoran@Sun.COM 		res = acpidev_filter_device(infop, infop->awi_hdl,
60810394SMichael.Corcoran@Sun.COM 		    ACPIDEV_ARRAY_PARAM(acpidev_cpu_filters), devname, maxlen);
60910394SMichael.Corcoran@Sun.COM 	} else {
61010394SMichael.Corcoran@Sun.COM 		res = ACPIDEV_FILTER_FAILED;
61110394SMichael.Corcoran@Sun.COM 	}
61210394SMichael.Corcoran@Sun.COM 
61310394SMichael.Corcoran@Sun.COM 	return (res);
61410394SMichael.Corcoran@Sun.COM }
61510394SMichael.Corcoran@Sun.COM 
61610394SMichael.Corcoran@Sun.COM static ACPI_STATUS
acpidev_cpu_init(acpidev_walk_info_t * infop)61710394SMichael.Corcoran@Sun.COM acpidev_cpu_init(acpidev_walk_info_t *infop)
61810394SMichael.Corcoran@Sun.COM {
61910394SMichael.Corcoran@Sun.COM 	int count;
620*12004Sjiang.liu@intel.com 	uint32_t pxmid;
62110394SMichael.Corcoran@Sun.COM 	dev_info_t *dip;
62210394SMichael.Corcoran@Sun.COM 	ACPI_HANDLE hdl;
62310394SMichael.Corcoran@Sun.COM 	char unitaddr[64];
62410394SMichael.Corcoran@Sun.COM 	char **compatpp;
62510394SMichael.Corcoran@Sun.COM 	static char *compatible[] = {
62610394SMichael.Corcoran@Sun.COM 		ACPIDEV_HID_PROCESSOR,
62710394SMichael.Corcoran@Sun.COM 		ACPIDEV_TYPE_CPU,
62810394SMichael.Corcoran@Sun.COM 		"cpu"
62910394SMichael.Corcoran@Sun.COM 	};
63010394SMichael.Corcoran@Sun.COM 
63110394SMichael.Corcoran@Sun.COM 	ASSERT(infop != NULL);
63210394SMichael.Corcoran@Sun.COM 	dip = infop->awi_dip;
63310394SMichael.Corcoran@Sun.COM 	hdl = infop->awi_hdl;
63410394SMichael.Corcoran@Sun.COM 
635*12004Sjiang.liu@intel.com 	/* Create "apic_id", "processor_id" and "proximity_id" properties. */
63610394SMichael.Corcoran@Sun.COM 	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
63710394SMichael.Corcoran@Sun.COM 	    ACPIDEV_PROP_NAME_PROCESSOR_ID, infop->awi_scratchpad[0]) !=
63810394SMichael.Corcoran@Sun.COM 	    NDI_SUCCESS) {
63910394SMichael.Corcoran@Sun.COM 		cmn_err(CE_WARN,
64010394SMichael.Corcoran@Sun.COM 		    "!acpidev: failed to set processor_id property for %s.",
64110394SMichael.Corcoran@Sun.COM 		    infop->awi_name);
64210394SMichael.Corcoran@Sun.COM 		return (AE_ERROR);
64310394SMichael.Corcoran@Sun.COM 	}
64410394SMichael.Corcoran@Sun.COM 	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
64510394SMichael.Corcoran@Sun.COM 	    ACPIDEV_PROP_NAME_LOCALAPIC_ID, infop->awi_scratchpad[1]) !=
64610394SMichael.Corcoran@Sun.COM 	    NDI_SUCCESS) {
64710394SMichael.Corcoran@Sun.COM 		cmn_err(CE_WARN,
64810394SMichael.Corcoran@Sun.COM 		    "!acpidev: failed to set apic_id property for %s.",
64910394SMichael.Corcoran@Sun.COM 		    infop->awi_name);
65010394SMichael.Corcoran@Sun.COM 		return (AE_ERROR);
65110394SMichael.Corcoran@Sun.COM 	}
652*12004Sjiang.liu@intel.com 	if (ACPI_SUCCESS(acpidev_cpu_get_proximity_id(infop->awi_hdl,
653*12004Sjiang.liu@intel.com 	    infop->awi_scratchpad[1], &pxmid))) {
654*12004Sjiang.liu@intel.com 		if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
655*12004Sjiang.liu@intel.com 		    ACPIDEV_PROP_NAME_PROXIMITY_ID, pxmid) != NDI_SUCCESS) {
656*12004Sjiang.liu@intel.com 			cmn_err(CE_WARN, "!acpidev: failed to set proximity id "
657*12004Sjiang.liu@intel.com 			    "property for %s.", infop->awi_name);
658*12004Sjiang.liu@intel.com 			return (AE_ERROR);
659*12004Sjiang.liu@intel.com 		}
660*12004Sjiang.liu@intel.com 	}
66110394SMichael.Corcoran@Sun.COM 
66210394SMichael.Corcoran@Sun.COM 	/* Set "compatible" property for CPU dip */
66310394SMichael.Corcoran@Sun.COM 	count = sizeof (compatible) / sizeof (compatible[0]);
66410394SMichael.Corcoran@Sun.COM 	if (infop->awi_info->Type == ACPI_TYPE_PROCESSOR) {
66510394SMichael.Corcoran@Sun.COM 		compatpp = compatible;
66610394SMichael.Corcoran@Sun.COM 	} else if (infop->awi_info->Type == ACPI_TYPE_DEVICE) {
66710394SMichael.Corcoran@Sun.COM 		/*
66810394SMichael.Corcoran@Sun.COM 		 * skip first item for pseudo processor HID.
66910394SMichael.Corcoran@Sun.COM 		 * acpidev_set_compatible() will handle HID/CID for CPU device.
67010394SMichael.Corcoran@Sun.COM 		 */
67110394SMichael.Corcoran@Sun.COM 		compatpp = &compatible[1];
67210394SMichael.Corcoran@Sun.COM 		count--;
67310394SMichael.Corcoran@Sun.COM 	} else {
67410394SMichael.Corcoran@Sun.COM 		return (AE_BAD_PARAMETER);
67510394SMichael.Corcoran@Sun.COM 	}
67610394SMichael.Corcoran@Sun.COM 	if (ACPI_FAILURE(acpidev_set_compatible(infop, compatpp, count))) {
67710394SMichael.Corcoran@Sun.COM 		return (AE_ERROR);
67810394SMichael.Corcoran@Sun.COM 	}
67910394SMichael.Corcoran@Sun.COM 
68010394SMichael.Corcoran@Sun.COM 	/*
68110394SMichael.Corcoran@Sun.COM 	 * Set device unit-address property.
68210394SMichael.Corcoran@Sun.COM 	 * First try to generate meaningful unit address from _UID,
68310394SMichael.Corcoran@Sun.COM 	 * then use Processor Id if that fails.
68410394SMichael.Corcoran@Sun.COM 	 */
68510394SMichael.Corcoran@Sun.COM 	if ((infop->awi_info->Valid & ACPI_VALID_UID) == 0 ||
68611225SDana.Myers@Sun.COM 	    acpidev_generate_unitaddr(infop->awi_info->UniqueId.String,
68710394SMichael.Corcoran@Sun.COM 	    ACPIDEV_ARRAY_PARAM(acpidev_cpu_uid_formats),
68810394SMichael.Corcoran@Sun.COM 	    unitaddr, sizeof (unitaddr)) == NULL) {
68910394SMichael.Corcoran@Sun.COM 		(void) snprintf(unitaddr, sizeof (unitaddr), "%u",
69010394SMichael.Corcoran@Sun.COM 		    (uint32_t)infop->awi_scratchpad[0]);
69110394SMichael.Corcoran@Sun.COM 	}
69210394SMichael.Corcoran@Sun.COM 	if (ACPI_FAILURE(acpidev_set_unitaddr(infop, NULL, 0, unitaddr))) {
69310394SMichael.Corcoran@Sun.COM 		return (AE_ERROR);
69410394SMichael.Corcoran@Sun.COM 	}
69510394SMichael.Corcoran@Sun.COM 
69610394SMichael.Corcoran@Sun.COM 	/*
69710394SMichael.Corcoran@Sun.COM 	 * Build binding information for CPUs.
69810394SMichael.Corcoran@Sun.COM 	 */
69910394SMichael.Corcoran@Sun.COM 	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
70010394SMichael.Corcoran@Sun.COM 	    infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE ||
70110394SMichael.Corcoran@Sun.COM 	    infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
70210394SMichael.Corcoran@Sun.COM 		if (ACPI_FAILURE(acpica_add_processor_to_map(
70310394SMichael.Corcoran@Sun.COM 		    infop->awi_scratchpad[0], hdl, infop->awi_scratchpad[1]))) {
70410394SMichael.Corcoran@Sun.COM 			cmn_err(CE_WARN, "!acpidev: failed to bind processor "
70510394SMichael.Corcoran@Sun.COM 			    "id/object handle for %s.", infop->awi_name);
70610394SMichael.Corcoran@Sun.COM 			return (AE_ERROR);
70710394SMichael.Corcoran@Sun.COM 		}
70810394SMichael.Corcoran@Sun.COM 	} else {
70910394SMichael.Corcoran@Sun.COM 		ACPIDEV_DEBUG(CE_WARN,
710*12004Sjiang.liu@intel.com 		    "!acpidev: unknown operation type %u in acpidev_cpu_init.",
71110394SMichael.Corcoran@Sun.COM 		    infop->awi_op_type);
71210394SMichael.Corcoran@Sun.COM 		return (AE_BAD_PARAMETER);
71310394SMichael.Corcoran@Sun.COM 	}
71410394SMichael.Corcoran@Sun.COM 
71510394SMichael.Corcoran@Sun.COM 	return (AE_OK);
71610394SMichael.Corcoran@Sun.COM }
71710394SMichael.Corcoran@Sun.COM 
718*12004Sjiang.liu@intel.com static void
acpidev_cpu_fini(ACPI_HANDLE hdl,acpidev_data_handle_t dhdl,acpidev_class_t * clsp)719*12004Sjiang.liu@intel.com acpidev_cpu_fini(ACPI_HANDLE hdl, acpidev_data_handle_t dhdl,
720*12004Sjiang.liu@intel.com     acpidev_class_t *clsp)
721*12004Sjiang.liu@intel.com {
722*12004Sjiang.liu@intel.com 	_NOTE(ARGUNUSED(clsp, dhdl));
723*12004Sjiang.liu@intel.com 
724*12004Sjiang.liu@intel.com 	int rc;
725*12004Sjiang.liu@intel.com 	uint32_t procid;
726*12004Sjiang.liu@intel.com 
727*12004Sjiang.liu@intel.com 	rc = acpica_get_procid_by_object(hdl, &procid);
728*12004Sjiang.liu@intel.com 	ASSERT(ACPI_SUCCESS(rc));
729*12004Sjiang.liu@intel.com 	if (ACPI_SUCCESS(rc)) {
730*12004Sjiang.liu@intel.com 		rc = acpica_remove_processor_from_map(procid);
731*12004Sjiang.liu@intel.com 		ASSERT(ACPI_SUCCESS(rc));
732*12004Sjiang.liu@intel.com 		if (ACPI_FAILURE(rc)) {
733*12004Sjiang.liu@intel.com 			cmn_err(CE_WARN, "!acpidev: failed to remove "
734*12004Sjiang.liu@intel.com 			    "processor from ACPICA.");
735*12004Sjiang.liu@intel.com 		}
736*12004Sjiang.liu@intel.com 	}
737*12004Sjiang.liu@intel.com }
738*12004Sjiang.liu@intel.com 
739*12004Sjiang.liu@intel.com /*
740*12004Sjiang.liu@intel.com  * Lookup the dip for a CPU if ACPI CPU autoconfig is enabled.
741*12004Sjiang.liu@intel.com  */
74210394SMichael.Corcoran@Sun.COM static int
acpidev_cpu_lookup_dip(cpu_t * cp,dev_info_t ** dipp)743*12004Sjiang.liu@intel.com acpidev_cpu_lookup_dip(cpu_t *cp, dev_info_t **dipp)
74410394SMichael.Corcoran@Sun.COM {
74510394SMichael.Corcoran@Sun.COM 	uint32_t apicid;
74610394SMichael.Corcoran@Sun.COM 	ACPI_HANDLE hdl;
74710394SMichael.Corcoran@Sun.COM 	dev_info_t *dip = NULL;
74810394SMichael.Corcoran@Sun.COM 
74910394SMichael.Corcoran@Sun.COM 	*dipp = NULL;
75010394SMichael.Corcoran@Sun.COM 	if (acpica_get_devcfg_feature(ACPI_DEVCFG_CPU)) {
75110394SMichael.Corcoran@Sun.COM 		apicid = cpuid_get_apicid(cp);
75210394SMichael.Corcoran@Sun.COM 		if (acpica_get_cpu_object_by_cpuid(cp->cpu_id, &hdl) == 0 ||
75310394SMichael.Corcoran@Sun.COM 		    (apicid != UINT32_MAX &&
75410394SMichael.Corcoran@Sun.COM 		    acpica_get_cpu_object_by_apicid(apicid, &hdl) == 0)) {
75510394SMichael.Corcoran@Sun.COM 			ASSERT(hdl != NULL);
75610394SMichael.Corcoran@Sun.COM 			if (ACPI_SUCCESS(acpica_get_devinfo(hdl, &dip))) {
75710394SMichael.Corcoran@Sun.COM 				ASSERT(dip != NULL);
75810394SMichael.Corcoran@Sun.COM 				*dipp = dip;
75910394SMichael.Corcoran@Sun.COM 				return (PSM_SUCCESS);
76010394SMichael.Corcoran@Sun.COM 			}
76110394SMichael.Corcoran@Sun.COM 		}
762*12004Sjiang.liu@intel.com 		ACPIDEV_DEBUG(CE_WARN,
763*12004Sjiang.liu@intel.com 		    "!acpidev: failed to lookup dip for cpu %d(%p).",
764*12004Sjiang.liu@intel.com 		    cp->cpu_id, (void *)cp);
76510394SMichael.Corcoran@Sun.COM 	}
76610394SMichael.Corcoran@Sun.COM 
767*12004Sjiang.liu@intel.com 	return (PSM_FAILURE);
768*12004Sjiang.liu@intel.com }
769*12004Sjiang.liu@intel.com 
770*12004Sjiang.liu@intel.com static int
acpidev_cpu_create_dip(cpu_t * cp,dev_info_t ** dipp)771*12004Sjiang.liu@intel.com acpidev_cpu_create_dip(cpu_t *cp, dev_info_t **dipp)
772*12004Sjiang.liu@intel.com {
773*12004Sjiang.liu@intel.com 	if (acpidev_cpu_lookup_dip(cp, dipp) == PSM_SUCCESS) {
774*12004Sjiang.liu@intel.com 		ndi_hold_devi(*dipp);
775*12004Sjiang.liu@intel.com 		return (PSM_SUCCESS);
776*12004Sjiang.liu@intel.com 	}
77710394SMichael.Corcoran@Sun.COM 	if (psm_cpu_create_devinfo_old != NULL) {
77810394SMichael.Corcoran@Sun.COM 		return (psm_cpu_create_devinfo_old(cp, dipp));
77910394SMichael.Corcoran@Sun.COM 	} else {
78010394SMichael.Corcoran@Sun.COM 		return (PSM_FAILURE);
78110394SMichael.Corcoran@Sun.COM 	}
78210394SMichael.Corcoran@Sun.COM }
783*12004Sjiang.liu@intel.com 
784*12004Sjiang.liu@intel.com static int
acpidev_cpu_get_dip(cpu_t * cp,dev_info_t ** dipp)785*12004Sjiang.liu@intel.com acpidev_cpu_get_dip(cpu_t *cp, dev_info_t **dipp)
786*12004Sjiang.liu@intel.com {
787*12004Sjiang.liu@intel.com 	if (acpidev_cpu_lookup_dip(cp, dipp) == PSM_SUCCESS) {
788*12004Sjiang.liu@intel.com 		return (PSM_SUCCESS);
789*12004Sjiang.liu@intel.com 	}
790*12004Sjiang.liu@intel.com 	if (psm_cpu_get_devinfo_old != NULL) {
791*12004Sjiang.liu@intel.com 		return (psm_cpu_get_devinfo_old(cp, dipp));
792*12004Sjiang.liu@intel.com 	} else {
793*12004Sjiang.liu@intel.com 		return (PSM_FAILURE);
794*12004Sjiang.liu@intel.com 	}
795*12004Sjiang.liu@intel.com }
796