4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 * Copyright (c) 2009-2010, Intel Corporation.
27 * All rights reserved.
31 * There are three types of container objects defined in the ACPI Spec as below.
32 * PNP0A05: Generic Container Device
33 * A device whose settings are totally controlled by its ACPI resource
34 * information, and otherwise needs no device or bus-specific driver support.
35 * This was originally known as Generic ISA Bus Device.
36 * This ID should only be used for containers that do not produce resources
37 * for consumption by child devices. Any system resources claimed by a PNP0A05
38 * device's _CRS object must be consumed by the container itself.
39 * PNP0A06: Generic Container Device
40 * This device behaves exactly the same as the PNP0A05 device.
41 * This was originally known as Extended I/O Bus.
42 * This ID should only be used for containers that do not produce resources
43 * for consumption by child devices. Any system resources claimed by a PNP0A06
44 * device's _CRS object must be consumed by the container itself.
45 * ACPI0004: Module Device.
46 * This device is a container object that acts as a bus node in a namespace.
47 * A Module Device without any of the _CRS, _PRS and _SRS methods behaves
48 * the same way as the Generic Container Devices (PNP0A05 or PNP0A06).
49 * If the Module Device contains a _CRS method, only the resources
50 * described in the _CRS are available for consumption by its child devices.
51 * Also, the Module Device can support _PRS and _SRS methods if _CRS is
55 #include <sys/types.h>
56 #include <sys/atomic.h>
58 #include <sys/sunddi.h>
59 #include <sys/sunndi.h>
60 #include <sys/acpi/acpi.h>
61 #include <sys/acpica.h>
62 #include <sys/acpidev.h>
63 #include <sys/acpidev_dr.h>
64 #include <sys/acpidev_impl.h>
66 static ACPI_STATUS
acpidev_container_probe(acpidev_walk_info_t
*infop
);
67 static acpidev_filter_result_t
acpidev_container_filter(
68 acpidev_walk_info_t
*infop
, char *devname
, int maxlen
);
69 static ACPI_STATUS
acpidev_container_init(acpidev_walk_info_t
*infop
);
70 static acpidev_filter_result_t
acpidev_container_filter_func(
71 acpidev_walk_info_t
*infop
, ACPI_HANDLE hdl
, acpidev_filter_rule_t
*rulep
,
72 char *devname
, int devnamelen
);
75 * Default class driver for ACPI container objects.
77 acpidev_class_t acpidev_class_container
= {
79 ACPIDEV_CLASS_REV1
, /* adc_version */
80 ACPIDEV_CLASS_ID_CONTAINER
, /* adc_class_id */
81 "ACPI Container", /* adc_class_name */
82 ACPIDEV_TYPE_CONTAINER
, /* adc_dev_type */
83 NULL
, /* adc_private */
84 NULL
, /* adc_pre_probe */
85 NULL
, /* adc_post_probe */
86 acpidev_container_probe
, /* adc_probe */
87 acpidev_container_filter
, /* adc_filter */
88 acpidev_container_init
, /* adc_init */
92 static char *acpidev_container_device_ids
[] = {
94 ACPIDEV_HID_CONTAINER1
,
95 ACPIDEV_HID_CONTAINER2
,
98 static char *acpidev_container_uid_formats
[] = {
102 /* Filter rule table for container objects. */
103 static acpidev_filter_rule_t acpidev_container_filters
[] = {
104 { /* Ignore all container objects under ACPI root object */
114 { /* Create node and scan child for all other container objects */
115 acpidev_container_filter_func
,
117 ACPIDEV_FILTER_DEFAULT
,
118 &acpidev_class_list_device
,
122 ACPIDEV_NODE_NAME_CONTAINER
,
127 acpidev_container_probe(acpidev_walk_info_t
*infop
)
129 ACPI_STATUS rc
= AE_OK
;
132 ASSERT(infop
!= NULL
);
133 ASSERT(infop
->awi_hdl
!= NULL
);
134 ASSERT(infop
->awi_info
!= NULL
);
136 if (infop
->awi_info
->Type
!= ACPI_TYPE_DEVICE
||
137 acpidev_match_device_id(infop
->awi_info
,
138 ACPIDEV_ARRAY_PARAM(acpidev_container_device_ids
)) == 0) {
142 flags
= ACPIDEV_PROCESS_FLAG_SCAN
;
143 switch (infop
->awi_op_type
) {
144 case ACPIDEV_OP_BOOT_PROBE
:
145 if (acpica_get_devcfg_feature(ACPI_DEVCFG_CONTAINER
)) {
146 flags
|= ACPIDEV_PROCESS_FLAG_CREATE
;
147 acpidev_dr_check(infop
);
151 case ACPIDEV_OP_BOOT_REPROBE
:
154 case ACPIDEV_OP_HOTPLUG_PROBE
:
155 if (acpica_get_devcfg_feature(ACPI_DEVCFG_CONTAINER
)) {
156 flags
|= ACPIDEV_PROCESS_FLAG_CREATE
|
157 ACPIDEV_PROCESS_FLAG_SYNCSTATUS
|
158 ACPIDEV_PROCESS_FLAG_HOLDBRANCH
;
163 ACPIDEV_DEBUG(CE_WARN
, "!acpidev: unknown operation type %u in "
164 "acpidev_container_probe().", infop
->awi_op_type
);
165 rc
= AE_BAD_PARAMETER
;
170 rc
= acpidev_process_object(infop
, flags
);
172 if (ACPI_FAILURE(rc
) && rc
!= AE_NOT_EXIST
&& rc
!= AE_ALREADY_EXISTS
) {
174 "!acpidev: failed to process container object %s.",
184 acpidev_container_search_dev(ACPI_HANDLE hdl
, UINT32 lvl
, void *ctx
,
187 _NOTE(ARGUNUSED(hdl
, retval
));
189 int *fp
= (int *)ctx
;
193 return (AE_CTRL_TERMINATE
);
196 static acpidev_filter_result_t
197 acpidev_container_filter_func(acpidev_walk_info_t
*infop
, ACPI_HANDLE hdl
,
198 acpidev_filter_rule_t
*rulep
, char *devname
, int devnamelen
)
202 int proc_lvl
, cpu_lvl
, module_lvl
;
203 acpidev_filter_result_t res
;
204 static char *cpu_hids
[] = {
207 static char *module_hids
[] = {
211 res
= acpidev_filter_default(infop
, hdl
, rulep
, devname
, devnamelen
);
212 /* Return if we don't need to generate a device name. */
213 if (devname
== NULL
|| res
== ACPIDEV_FILTER_FAILED
||
214 res
== ACPIDEV_FILTER_SKIP
) {
218 /* Try to figure out the most specific device name for the object. */
222 module_lvl
= INT_MAX
;
224 /* Search for ACPI Processor object. */
225 (void) AcpiWalkNamespace(ACPI_TYPE_PROCESSOR
, hdl
, 2,
226 acpidev_container_search_dev
, NULL
, &proc_lvl
, &retval
);
228 /* Search for CPU Device object. */
229 (void) acpidev_get_device_by_id(hdl
, ACPIDEV_ARRAY_PARAM(cpu_hids
), 2,
230 B_FALSE
, acpidev_container_search_dev
, &cpu_lvl
, &retval
);
232 /* Search for Module Device object. */
233 (void) acpidev_get_device_by_id(hdl
, ACPIDEV_ARRAY_PARAM(module_hids
),
234 2, B_FALSE
, acpidev_container_search_dev
, &module_lvl
, &retval
);
236 buf
.Pointer
= devname
;
237 buf
.Length
= devnamelen
;
238 if (cpu_lvl
> proc_lvl
) {
242 /* CPU as child, most likely a physical CPU. */
243 (void) strlcpy(devname
, ACPIDEV_NODE_NAME_MODULE_CPU
,
245 } else if (cpu_lvl
== 2 && module_lvl
== 1) {
246 /* CPU as grandchild, most likely a system board. */
247 (void) strlcpy(devname
, ACPIDEV_NODE_NAME_MODULE_SBD
,
249 } else if (ACPI_FAILURE(AcpiGetName(infop
->awi_hdl
,
250 ACPI_SINGLE_NAME
, &buf
))) {
252 * Failed to get ACPI object name; use ACPI object name
253 * as the default name.
255 (void) strlcpy(devname
, ACPIDEV_NODE_NAME_CONTAINER
,
262 static acpidev_filter_result_t
263 acpidev_container_filter(acpidev_walk_info_t
*infop
, char *devname
, int maxlen
)
265 acpidev_filter_result_t res
;
267 ASSERT(infop
!= NULL
);
268 if (infop
->awi_op_type
== ACPIDEV_OP_BOOT_PROBE
||
269 infop
->awi_op_type
== ACPIDEV_OP_BOOT_REPROBE
||
270 infop
->awi_op_type
== ACPIDEV_OP_HOTPLUG_PROBE
) {
271 res
= acpidev_filter_device(infop
, infop
->awi_hdl
,
272 ACPIDEV_ARRAY_PARAM(acpidev_container_filters
),
275 res
= ACPIDEV_FILTER_FAILED
;
282 acpidev_container_init(acpidev_walk_info_t
*infop
)
284 static char *compatible
[] = {
285 ACPIDEV_TYPE_CONTAINER
,
287 ACPIDEV_TYPE_VIRTNEX
,
290 ASSERT(infop
!= NULL
);
291 ASSERT(infop
->awi_hdl
!= NULL
);
292 ASSERT(infop
->awi_dip
!= NULL
);
294 if (ACPI_FAILURE(acpidev_set_compatible(infop
,
295 ACPIDEV_ARRAY_PARAM(compatible
)))) {
298 if (ACPI_FAILURE(acpidev_set_unitaddr(infop
,
299 ACPIDEV_ARRAY_PARAM(acpidev_container_uid_formats
), NULL
))) {