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