1 /*
2 * Copyright (c) 2009, Intel Corporation.
3 * All rights reserved.
4 */
5
6 /*
7 * Platform specific device enumerator for ACPI specific device.
8 * By x86 system device, it refers to the suite of hardware components which are
9 * common to x86 platform and play important roles in the system architecture
10 * but can't be enumerated/discovered through industry standard bus
11 * specifications. Examples of these x86 system devices include:
12 * * Logical processor/CPU
13 * * Memory device
14 * * Non-PCI discoveralbe IOMMU or DMA Remapping Engine
15 * * Non-PCI discoverable IOxAPIC
16 * * Non-PCI discoverable HPET(High Precision Event Timer)
17 * * ACPI defined devices, including power button, sleep button, battery etc.
18 *
19 * X86 system devices may be discovered through BIOS/Firmware interfaces, such
20 * as SMBIOS table, MPS table and ACPI table etc, though they couldn't be
21 * enumerated through industry standard bus specification.
22 *
23 * To aid Solaris flexibly manage x86 system devices, we are trying to organize
24 * x86 system devices into a specific firmware device subtree which is used to
25 * host all system devices and currently named as '/devices/fw'.
26 *
27 * This driver is aimed to populate the firmware device subtree with ACPI
28 * discoverable system devices if possible. To achieve that, ACPI object
29 * namespace is abstracted as ACPI virtual buses hosting system devices.
30 * Another nexus driver is developed for ACPI virtual bus to manage all devices
31 * connected to it.
32 *
33 * For detail information, please refer to PSARC/2009/104.
34 */
35
36 #include <sys/types.h>
37 #include <sys/bitmap.h>
38 #include <sys/cmn_err.h>
39 #include <sys/ddi_subrdefs.h>
40 #include <sys/errno.h>
41 #include <sys/modctl.h>
42 #include <sys/mutex.h>
43 #include <sys/obpdefs.h>
44 #include <sys/sunddi.h>
45 #include <sys/sunndi.h>
46 #include <sys/acpi/acpi.h>
47 #include <sys/acpica.h>
48 #include <sys/acpidev.h>
49 #include <sys/acpidev_impl.h>
50
51 /* Patchable through /etc/system */
52 int acpidev_options = 0;
53 #ifdef DEBUG
54 int acpidev_debug = 1;
55 #else
56 int acpidev_debug = 0;
57 #endif
58
59 acpidev_class_list_t *acpidev_class_list_root = NULL;
60
61 /* ACPI device autoconfig global status */
62 typedef enum acpidev_status {
63 ACPIDEV_STATUS_FAILED = -2, /* ACPI device autoconfig failed */
64 ACPIDEV_STATUS_DISABLED = -1, /* ACPI device autoconfig disabled */
65 ACPIDEV_STATUS_UNKNOWN = 0, /* initial status */
66 ACPIDEV_STATUS_INITIALIZED, /* ACPI deivce autoconfig initialized */
67 ACPIDEV_STATUS_FIRST_PASS, /* first probing finished */
68 ACPIDEV_STATUS_READY /* second probing finished */
69 } acpidev_status_t;
70
71 static acpidev_status_t acpidev_status = ACPIDEV_STATUS_UNKNOWN;
72 static kmutex_t acpidev_drv_lock;
73 static krwlock_t acpidev_class_lock;
74 static dev_info_t *acpidev_root_dip = NULL;
75 static ulong_t acpidev_object_type_mask[BT_BITOUL(ACPI_TYPE_NS_NODE_MAX + 1)];
76
77 /* Boot time ACPI device enumerator. */
78 static void acpidev_boot_probe(int type);
79
80 /* DDI module auto configuration interface */
81 extern struct mod_ops mod_miscops;
82
83 static struct modlmisc modlmisc = {
84 &mod_miscops,
85 "ACPI device enumerator"
86 };
87
88 static struct modlinkage modlinkage = {
89 MODREV_1,
90 (void *)&modlmisc,
91 NULL
92 };
93
94 int
95 _init(void)
96 {
97 int err;
98
99 if ((err = mod_install(&modlinkage)) == 0) {
100 mutex_init(&acpidev_drv_lock, NULL, MUTEX_DRIVER, NULL);
101 rw_init(&acpidev_class_lock, NULL, RW_DEFAULT, NULL);
102 impl_bus_add_probe(acpidev_boot_probe);
103 } else {
104 cmn_err(CE_WARN, "acpidev: failed to install driver.");
105 }
106
107 return (err);
108 }
109
110 int
111 _fini(void)
112 {
113 /* No support for module unload. */
114 return (EBUSY);
115 }
116
117 int
118 _info(struct modinfo *modinfop)
119 {
120 return (mod_info(&modlinkage, modinfop));
121 }
122
123 /* Check blacklists and load platform specific driver modules. */
124 static ACPI_STATUS
125 acpidev_load_plat_modules(void)
126 {
127 return (AE_OK);
128 }
129
130 /* Unload platform specific driver modules. */
131 static void
132 acpidev_unload_plat_modules(void)
133 {
134 }
135
136 /* Unregister all device class drivers from device driver lists. */
137 static void
138 acpidev_class_list_fini(void)
139 {
140 acpidev_unload_plat_modules();
141
142 if ((acpidev_options & ACPIDEV_OUSER_NO_MEM) == 0) {
143 (void) acpidev_unregister_class(&acpidev_class_list_device,
144 &acpidev_class_memory);
145 }
146
147 if (acpidev_options & ACPIDEV_OUSER_NO_CPU) {
148 (void) acpidev_unregister_class(&acpidev_class_list_device,
149 &acpidev_class_cpu);
150 (void) acpidev_unregister_class(&acpidev_class_list_scope,
151 &acpidev_class_cpu);
152 (void) acpidev_unregister_class(&acpidev_class_list_root,
153 &acpidev_class_cpu);
154 }
155
156 if ((acpidev_options & ACPIDEV_OUSER_NO_CONTAINER) == 0) {
157 (void) acpidev_unregister_class(&acpidev_class_list_device,
158 &acpidev_class_container);
159 }
160
161 (void) acpidev_unregister_class(&acpidev_class_list_device,
162 &acpidev_class_device);
163 (void) acpidev_unregister_class(&acpidev_class_list_root,
164 &acpidev_class_device);
165
166 (void) acpidev_unregister_class(&acpidev_class_list_root,
167 &acpidev_class_scope);
168 }
169
170 /* Register all device class drivers onto driver lists. */
171 static ACPI_STATUS
172 acpidev_class_list_init(uint64_t *fp)
173 {
174 ACPI_STATUS rc = AE_OK;
175
176 /* Set bit in mask for supported object types. */
177 BT_SET(acpidev_object_type_mask, ACPI_TYPE_LOCAL_SCOPE);
178 BT_SET(acpidev_object_type_mask, ACPI_TYPE_DEVICE);
179
180 /*
181 * Register ACPI scope class driver onto class driver lists.
182 * Currently only ACPI scope objects under ACPI root node, such as _PR,
183 * _SB, _TZ etc, need to be handled, so only register scope class
184 * driver onto root list.
185 */
186 if (ACPI_FAILURE(acpidev_register_class(&acpidev_class_list_root,
187 &acpidev_class_scope, B_FALSE))) {
188 goto error_out;
189 }
190
191 /*
192 * Register ACPI device class driver onto class dirver lists.
193 * ACPI device class driver should be reigstered at tail to handle all
194 * device objects which haven't handled by other HID/CID specific
195 * device class driver.
196 */
197 if (ACPI_FAILURE(acpidev_register_class(&acpidev_class_list_root,
198 &acpidev_class_device, B_TRUE))) {
199 goto error_root_device;
200 }
201 if (ACPI_FAILURE(acpidev_register_class(&acpidev_class_list_device,
202 &acpidev_class_device, B_TRUE))) {
203 goto error_device_device;
204 }
205
206 /* Check and register support for ACPI container device. */
207 if ((acpidev_options & ACPIDEV_OUSER_NO_CONTAINER) == 0) {
208 if (ACPI_FAILURE(acpidev_register_class(
209 &acpidev_class_list_device, &acpidev_class_container,
210 B_FALSE))) {
211 goto error_device_container;
212 }
213 *fp |= ACPI_DEVCFG_CONTAINER;
214 }
215
216 /* Check and register support for ACPI CPU device. */
217 if ((acpidev_options & ACPIDEV_OUSER_NO_CPU) == 0) {
218 /* Handle ACPI CPU Device */
219 if (ACPI_FAILURE(acpidev_register_class(
220 &acpidev_class_list_device, &acpidev_class_cpu, B_FALSE))) {
221 goto error_device_cpu;
222 }
223 /* Handle ACPI Processor under _PR */
224 if (ACPI_FAILURE(acpidev_register_class(
225 &acpidev_class_list_scope, &acpidev_class_cpu, B_FALSE))) {
226 goto error_scope_cpu;
227 }
228 /* House-keeping for CPU scan */
229 if (ACPI_FAILURE(acpidev_register_class(
230 &acpidev_class_list_root, &acpidev_class_cpu, B_FALSE))) {
231 goto error_root_cpu;
232 }
233 BT_SET(acpidev_object_type_mask, ACPI_TYPE_PROCESSOR);
234 *fp |= ACPI_DEVCFG_CPU;
235 }
236
237 /* Check support for ACPI memory device. */
238 if ((acpidev_options & ACPIDEV_OUSER_NO_MEM) == 0) {
239 /*
240 * Register ACPI memory class driver onto
241 * acpidev_class_list_device because ACPI module class driver
242 * uses that list.
243 */
244 if (ACPI_FAILURE(acpidev_register_class(
245 &acpidev_class_list_device, &acpidev_class_memory,
246 B_FALSE))) {
247 goto error_device_memory;
248 }
249 *fp |= ACPI_DEVCFG_MEMORY;
250 }
251
252 /* Check blacklist and load platform specific modules. */
253 rc = acpidev_load_plat_modules();
254 if (ACPI_FAILURE(rc)) {
255 ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to check blacklist "
256 "or load pratform modules.");
257 goto error_plat;
258 }
259
260 return (AE_OK);
261
262 error_plat:
263 if ((acpidev_options & ACPIDEV_OUSER_NO_MEM) == 0) {
264 (void) acpidev_unregister_class(&acpidev_class_list_device,
265 &acpidev_class_memory);
266 }
267 error_device_memory:
268 if (acpidev_options & ACPIDEV_OUSER_NO_CPU) {
269 (void) acpidev_unregister_class(&acpidev_class_list_root,
270 &acpidev_class_cpu);
271 }
272 error_root_cpu:
273 if (acpidev_options & ACPIDEV_OUSER_NO_CPU) {
274 (void) acpidev_unregister_class(&acpidev_class_list_scope,
275 &acpidev_class_cpu);
276 }
277 error_scope_cpu:
278 if (acpidev_options & ACPIDEV_OUSER_NO_CPU) {
279 (void) acpidev_unregister_class(&acpidev_class_list_device,
280 &acpidev_class_cpu);
281 }
282 error_device_cpu:
283 if ((acpidev_options & ACPIDEV_OUSER_NO_CONTAINER) == 0) {
284 (void) acpidev_unregister_class(&acpidev_class_list_device,
285 &acpidev_class_container);
286 }
287 error_device_container:
288 (void) acpidev_unregister_class(&acpidev_class_list_device,
289 &acpidev_class_device);
290 error_device_device:
291 (void) acpidev_unregister_class(&acpidev_class_list_root,
292 &acpidev_class_device);
293 error_root_device:
294 (void) acpidev_unregister_class(&acpidev_class_list_root,
295 &acpidev_class_scope);
296 error_out:
297 ACPIDEV_DEBUG(CE_WARN,
298 "acpidev: failed to register built-in class drivers.");
299 *fp = 0;
300
301 return (AE_ERROR);
302 }
303
304 /* Called in single thread context during boot, no protection for reentrance. */
305 static int
306 acpidev_create_root_node(void)
307 {
308 int circ, rv = AE_OK;
309 dev_info_t *dip = NULL;
310 acpidev_data_handle_t objhdl;
311 char *compatibles[] = {
312 ACPIDEV_HID_ROOTNEX,
313 ACPIDEV_TYPE_ROOTNEX,
314 ACPIDEV_HID_VIRTNEX,
315 ACPIDEV_TYPE_VIRTNEX,
316 };
317
318 ndi_devi_enter(ddi_root_node(), &circ);
319 ASSERT(acpidev_root_dip == NULL);
320
321 /* Query whether device node already exists. */
322 dip = ddi_find_devinfo(ACPIDEV_NODE_NAME_ROOT, -1, 0);
323 if (dip != NULL && ddi_get_parent(dip) == ddi_root_node()) {
324 ndi_devi_exit(ddi_root_node(), circ);
325 cmn_err(CE_WARN,
326 "acpidev: node /devices/%s already exists, disable driver.",
327 ACPIDEV_NODE_NAME_ROOT);
328 return (AE_ALREADY_EXISTS);
329 }
330
331 /* Create device node if doesn't exist. */
332 rv = ndi_devi_alloc(ddi_root_node(), ACPIDEV_NODE_NAME_ROOT,
333 (pnode_t)DEVI_SID_NODEID, &dip);
334 if (rv != NDI_SUCCESS) {
335 ndi_devi_exit(ddi_root_node(), circ);
336 ACPIDEV_DEBUG(CE_WARN,
337 "acpidev: failed to create node for %s with errcode %d.",
338 ACPIDEV_OBJECT_NAME_SB, rv);
339 return (AE_ERROR);
340 }
341
342 /* Build cross reference between dip and ACPI object. */
343 if (ACPI_FAILURE(acpica_tag_devinfo(dip, ACPI_ROOT_OBJECT))) {
344 (void) ddi_remove_child(dip, 0);
345 ndi_devi_exit(ddi_root_node(), circ);
346 ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to tag object %s.",
347 ACPIDEV_OBJECT_NAME_SB);
348 return (AE_ERROR);
349 }
350
351 /* Set device properties. */
352 rv = ndi_prop_update_string_array(DDI_DEV_T_NONE, dip,
353 OBP_COMPATIBLE, ACPIDEV_ARRAY_PARAM(compatibles));
354 if (rv == NDI_SUCCESS) {
355 rv = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
356 OBP_DEVICETYPE, ACPIDEV_TYPE_ROOTNEX);
357 }
358 if (rv != DDI_SUCCESS) {
359 ACPIDEV_DEBUG(CE_WARN,
360 "acpidev: failed to set device property for /devices/%s.",
361 ACPIDEV_NODE_NAME_ROOT);
362 goto error_out;
363 }
364
365 /* Manually create object handle for root node */
366 objhdl = acpidev_data_create_handle(ACPI_ROOT_OBJECT);
367 if (objhdl == NULL) {
368 ACPIDEV_DEBUG(CE_WARN,
369 "acpidev: failed to create object handle for root.");
370 goto error_out;
371 }
372 objhdl->aod_level = 0;
373 objhdl->aod_hdl = ACPI_ROOT_OBJECT;
374 objhdl->aod_dip = dip;
375 objhdl->aod_class = &acpidev_class_scope;
376 objhdl->aod_status = acpidev_query_device_status(ACPI_ROOT_OBJECT);
377 objhdl->aod_iflag = ACPIDEV_ODF_STATUS_VALID |
378 ACPIDEV_ODF_DEVINFO_CREATED | ACPIDEV_ODF_DEVINFO_TAGGED;
379
380 /* Bind device driver. */
381 (void) ndi_devi_bind_driver(dip, 0);
382
383 acpidev_root_dip = dip;
384 ndi_devi_exit(ddi_root_node(), circ);
385
386 return (AE_OK);
387
388 error_out:
389 (void) acpica_untag_devinfo(dip, ACPI_ROOT_OBJECT);
390 (void) ddi_remove_child(dip, 0);
391 ndi_devi_exit(ddi_root_node(), circ);
392 return (AE_ERROR);
393 }
394
395 static void
396 acpidev_initialize(void)
397 {
398 int rc;
399 char *str = NULL;
400 uint64_t features = 0;
401
402 /* Check whether it has already been initialized. */
403 if (acpidev_status != ACPIDEV_STATUS_UNKNOWN) {
404 ACPIDEV_DEBUG(CE_NOTE,
405 "acpidev: initialization called more than once.");
406 return;
407 }
408
409 /* Check whether ACPI device autoconfig has been disabled by user. */
410 rc = ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
411 DDI_PROP_DONTPASS, "acpidev-autoconfig", &str);
412 if (rc == DDI_SUCCESS) {
413 if (strcasecmp(str, "off") == 0 || strcasecmp(str, "no") == 0) {
414 cmn_err(CE_CONT, "?acpidev: ACPI device autoconfig "
415 "disabled by user.\n");
416 ddi_prop_free(str);
417 acpidev_status = ACPIDEV_STATUS_DISABLED;
418 return;
419 }
420 ddi_prop_free(str);
421 }
422
423 /* Initialize acpica subsystem. */
424 if (ACPI_FAILURE(acpica_init())) {
425 cmn_err(CE_CONT,
426 "?acpidev: failed to initialize acpica subsystem.\n");
427 acpidev_status = ACPIDEV_STATUS_FAILED;
428 return;
429 }
430
431 /* Check ACPICA subsystem status. */
432 if (!acpica_get_core_feature(ACPI_FEATURE_FULL_INIT)) {
433 cmn_err(CE_CONT,
434 "?acpidev: ACPI device autoconfig has been disabled "
435 "because ACPICA hasn't been fully initalized.\n");
436 acpidev_status = ACPIDEV_STATUS_DISABLED;
437 return;
438 }
439
440 /* Converts acpidev-options from type string to int, if any */
441 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
442 DDI_PROP_DONTPASS, "acpidev-options", &str) == DDI_PROP_SUCCESS) {
443 long data;
444 rc = ddi_strtol(str, NULL, 0, &data);
445 if (rc == 0) {
446 (void) e_ddi_prop_remove(DDI_DEV_T_NONE,
447 ddi_root_node(), "acpidev-options");
448 (void) e_ddi_prop_update_int(DDI_DEV_T_NONE,
449 ddi_root_node(), "acpidev-options", data);
450 }
451 ddi_prop_free(str);
452 }
453 /* Get acpidev_options user options. */
454 acpidev_options = ddi_prop_get_int(DDI_DEV_T_ANY, ddi_root_node(),
455 DDI_PROP_DONTPASS, "acpidev-options", acpidev_options);
456
457 /* Load all embbeded device class drivers. */
458 if (ACPI_FAILURE(acpidev_class_list_init(&features))) {
459 ACPIDEV_DEBUG(CE_NOTE,
460 "acpidev: failed to initalize class driver lists.");
461 acpidev_status = ACPIDEV_STATUS_FAILED;
462 return;
463 }
464
465 /* Create root node for ACPI/firmware device subtree. */
466 if (ACPI_FAILURE(acpidev_create_root_node())) {
467 cmn_err(CE_CONT, "?acpidev: failed to create root node "
468 "for acpi device tree.\n");
469 acpidev_class_list_fini();
470 acpidev_status = ACPIDEV_STATUS_FAILED;
471 return;
472 }
473
474 /* Notify acpica to enable ACPI device auto configuration. */
475 acpica_set_core_feature(ACPI_FEATURE_DEVCFG);
476 acpica_set_devcfg_feature(features);
477
478 ACPIDEV_DEBUG(CE_NOTE, "ACPI device autoconfig initialized.");
479 acpidev_status = ACPIDEV_STATUS_INITIALIZED;
480 }
481
482 /*
483 * Probe devices in ACPI namespace which can't be enumerated by other methods
484 * at boot time.
485 */
486 static ACPI_STATUS
487 acpidev_boot_probe_device(acpidev_op_type_t op_type)
488 {
489 ACPI_STATUS rc = AE_OK;
490 acpidev_walk_info_t *infop;
491
492 ASSERT(acpidev_root_dip != NULL);
493 ASSERT(op_type == ACPIDEV_OP_BOOT_PROBE ||
494 op_type == ACPIDEV_OP_BOOT_REPROBE);
495
496 /* Enumerate ACPI devices. */
497 infop = acpidev_alloc_walk_info(op_type, 0, ACPI_ROOT_OBJECT,
498 &acpidev_class_list_root, NULL);
499 if (infop == NULL) {
500 ACPIDEV_DEBUG(CE_NOTE, "acpidev: failed to allocate walk info "
501 "object in boot_probe_device().");
502 return (AE_ERROR);
503 }
504 rc = acpidev_probe_child(infop);
505 if (ACPI_FAILURE(rc)) {
506 cmn_err(CE_CONT, "?acpidev: failed to probe child object "
507 "under ACPI root node.");
508 }
509 acpidev_free_walk_info(infop);
510
511 return (rc);
512 }
513
514 /*
515 * Platform specific device prober for ACPI virtual bus.
516 * It will be called in single-thread environment to enumerate devices in
517 * ACPI namespace at boot time.
518 */
519 static void
520 acpidev_boot_probe(int type)
521 {
522 ACPI_STATUS rc;
523
524 /* Initialize subsystem on first pass. */
525 mutex_enter(&acpidev_drv_lock);
526 if (type == 0) {
527 acpidev_initialize();
528 if (acpidev_status != ACPIDEV_STATUS_INITIALIZED) {
529 cmn_err(CE_WARN, "acpidev: driver disabled due to "
530 "initalization failure.");
531 }
532 }
533
534 /* Probe ACPI devices */
535 if (type == 0 && acpidev_status == ACPIDEV_STATUS_INITIALIZED) {
536 rc = acpidev_boot_probe_device(ACPIDEV_OP_BOOT_PROBE);
537 if (ACPI_SUCCESS(rc)) {
538 acpidev_status = ACPIDEV_STATUS_FIRST_PASS;
539 } else {
540 ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to probe ACPI "
541 "devices during boot.");
542 acpidev_status = ACPIDEV_STATUS_FAILED;
543 }
544 } else if (type != 0 && acpidev_status == ACPIDEV_STATUS_FIRST_PASS) {
545 rc = acpidev_boot_probe_device(ACPIDEV_OP_BOOT_REPROBE);
546 if (ACPI_SUCCESS(rc)) {
547 acpidev_status = ACPIDEV_STATUS_READY;
548 } else {
549 ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to reprobe "
550 "ACPI devices during boot.");
551 acpidev_status = ACPIDEV_STATUS_FAILED;
552 }
553 } else if (acpidev_status != ACPIDEV_STATUS_FAILED &&
554 acpidev_status != ACPIDEV_STATUS_DISABLED &&
555 acpidev_status != ACPIDEV_STATUS_READY) {
556 cmn_err(CE_WARN,
557 "acpidev: invalid ACPI device autoconfig global status.");
558 }
559 mutex_exit(&acpidev_drv_lock);
560 }
561
562 ACPI_STATUS
563 acpidev_probe_child(acpidev_walk_info_t *infop)
564 {
565 int circ;
566 dev_info_t *pdip;
567 ACPI_STATUS res, rc = AE_OK;
568 ACPI_HANDLE child;
569 ACPI_OBJECT_TYPE type;
570 acpidev_class_list_t *it;
571 acpidev_walk_info_t *cinfop;
572 acpidev_data_handle_t datap;
573
574 /* Validate parameter first. */
575 ASSERT(infop != NULL);
576 if (infop == NULL) {
577 ACPIDEV_DEBUG(CE_WARN,
578 "acpidev: infop is NULL in probe_child().");
579 return (AE_BAD_PARAMETER);
580 }
581 ASSERT(infop->awi_level < ACPIDEV_MAX_ENUM_LEVELS - 1);
582 if (infop->awi_level >= ACPIDEV_MAX_ENUM_LEVELS - 1) {
583 ACPIDEV_DEBUG(CE_WARN,
584 "acpidev: recursive level is too deep in probe_child().");
585 return (AE_BAD_PARAMETER);
586 }
587 ASSERT(infop->awi_class_list != NULL);
588 ASSERT(infop->awi_hdl != NULL);
589 ASSERT(infop->awi_info != NULL);
590 ASSERT(infop->awi_name != NULL);
591 ASSERT(infop->awi_data != NULL);
592 if (infop->awi_class_list == NULL || infop->awi_hdl == NULL ||
593 infop->awi_info == NULL || infop->awi_name == NULL ||
594 infop->awi_data == NULL) {
595 ACPIDEV_DEBUG(CE_WARN,
596 "acpidev: infop has NULL fields in probe_child().");
597 return (AE_BAD_PARAMETER);
598 }
599 pdip = acpidev_walk_info_get_pdip(infop);
600 if (pdip == NULL) {
601 ACPIDEV_DEBUG(CE_WARN,
602 "acpidev: pdip is NULL in probe_child().");
603 return (AE_BAD_PARAMETER);
604 }
605
606 ndi_devi_enter(pdip, &circ);
607 rw_enter(&acpidev_class_lock, RW_READER);
608
609 /* Call pre-probe callback functions. */
610 for (it = *(infop->awi_class_list); it != NULL; it = it->acl_next) {
611 if (it->acl_class->adc_pre_probe == NULL) {
612 continue;
613 }
614 infop->awi_class_curr = it->acl_class;
615 if (ACPI_FAILURE(it->acl_class->adc_pre_probe(infop))) {
616 ACPIDEV_DEBUG(CE_NOTE, "acpidev: failed to pre probe "
617 "device of type %s under %s.",
618 it->acl_class->adc_class_name, infop->awi_name);
619 }
620 }
621
622 /* Walk child objects. */
623 child = NULL;
624 while (ACPI_SUCCESS(AcpiGetNextObject(ACPI_TYPE_ANY,
625 infop->awi_hdl, child, &child))) {
626 /* Skip object if not interested at. */
627 if (ACPI_FAILURE(AcpiGetType(child, &type)) ||
628 type > ACPI_TYPE_NS_NODE_MAX ||
629 BT_TEST(acpidev_object_type_mask, type) == 0) {
630 continue;
631 }
632
633 /* Allocate walk info structure. */
634 cinfop = acpidev_alloc_walk_info(infop->awi_op_type,
635 infop->awi_level + 1, child, NULL, infop);
636 if (cinfop == NULL) {
637 ACPIDEV_DEBUG(CE_NOTE, "acpidev: failed to allocate "
638 "walk info child object of %s.",
639 infop->awi_name);
640 /* Mark error and continue to handle next child. */
641 rc = AE_ERROR;
642 continue;
643 }
644
645 /*
646 * Remember class list used to handle this object.
647 * It should be the same list for different pass of scans.
648 */
649 ASSERT(cinfop->awi_data != NULL);
650 datap = cinfop->awi_data;
651 if (cinfop->awi_op_type == ACPIDEV_OP_BOOT_PROBE) {
652 datap->aod_class_list = infop->awi_class_list;
653 } else if (datap->aod_class_list != infop->awi_class_list) {
654 ACPIDEV_DEBUG(CE_WARN,
655 "acpidev: class list for %s has been changed",
656 infop->awi_name);
657 acpidev_free_walk_info(cinfop);
658 continue;
659 }
660
661 /* Call registered process callbacks. */
662 for (it = *(infop->awi_class_list); it != NULL;
663 it = it->acl_next) {
664 if (it->acl_class->adc_probe == NULL) {
665 continue;
666 }
667 cinfop->awi_class_curr = it->acl_class;
668 res = it->acl_class->adc_probe(cinfop);
669 if (ACPI_FAILURE(res)) {
670 rc = res;
671 ACPIDEV_DEBUG(CE_NOTE, "acpidev: failed to "
672 "process object of type %s under %s.",
673 it->acl_class->adc_class_name,
674 infop->awi_name);
675 }
676 }
677
678 /* Free resources. */
679 acpidev_free_walk_info(cinfop);
680 }
681
682 /* Call post-probe callback functions. */
683 for (it = *(infop->awi_class_list); it != NULL; it = it->acl_next) {
684 if (it->acl_class->adc_post_probe == NULL) {
685 continue;
686 }
687 infop->awi_class_curr = it->acl_class;
688 if (ACPI_FAILURE(it->acl_class->adc_post_probe(infop))) {
689 ACPIDEV_DEBUG(CE_NOTE, "acpidev: failed to post probe "
690 "device of type %s under %s.",
691 it->acl_class->adc_class_name, infop->awi_name);
692 }
693 }
694
695 rw_exit(&acpidev_class_lock);
696 ndi_devi_exit(pdip, circ);
697
698 return (rc);
699 }
700
701 ACPI_STATUS
702 acpidev_process_object(acpidev_walk_info_t *infop, int flags)
703 {
704 ACPI_STATUS rc = AE_OK;
705 char *devname;
706 dev_info_t *dip, *pdip;
707 ACPI_HANDLE hdl;
708 ACPI_DEVICE_INFO *adip;
709 acpidev_class_t *clsp;
710 acpidev_data_handle_t datap;
711 acpidev_filter_result_t res;
712
713 /* Validate parameters first. */
714 ASSERT(infop != NULL);
715 if (infop == NULL) {
716 ACPIDEV_DEBUG(CE_WARN,
717 "acpidev: infop is NULL in process_object().");
718 return (AE_BAD_PARAMETER);
719 }
720 ASSERT(infop->awi_hdl != NULL);
721 ASSERT(infop->awi_info != NULL);
722 ASSERT(infop->awi_data != NULL);
723 ASSERT(infop->awi_class_curr != NULL);
724 ASSERT(infop->awi_class_curr->adc_filter != NULL);
725 hdl = infop->awi_hdl;
726 adip = infop->awi_info;
727 datap = infop->awi_data;
728 clsp = infop->awi_class_curr;
729 if (hdl == NULL || datap == NULL || adip == NULL || clsp == NULL ||
730 clsp->adc_filter == NULL) {
731 ACPIDEV_DEBUG(CE_WARN,
732 "acpidev: infop has NULL pointer in process_object().");
733 return (AE_BAD_PARAMETER);
734 }
735 pdip = acpidev_walk_info_get_pdip(infop);
736 if (pdip == NULL) {
737 ACPIDEV_DEBUG(CE_WARN,
738 "acpidev: failed to get pdip for %s in process_object().",
739 infop->awi_name);
740 return (AE_BAD_PARAMETER);
741 }
742
743 /*
744 * Check whether object has already been handled.
745 * Tag and child dip pointer are used to indicate the object has been
746 * handled by ACPI auto configure driver. It has following usages:
747 * 1) Prevent from creating dip for objects which already has
748 * associating dip when reloading ACPI auto configure driver.
749 * 2) Prevent from creating multiple dips for ACPI object with ACPI
750 * alias. Currently ACPICA framework has no way to tell whether
751 * an object is an alias or not for some types of object. So tag
752 * is used to indicate that the object has been handled.
753 * 3) Prevent multiple class drivers to create multiple device for the
754 * same ACPI object.
755 */
756 if ((flags & ACPIDEV_PROCESS_FLAG_CREATE) &&
757 (flags & ACPIDEV_PROCESS_FLAG_CHECK) &&
758 !(infop->awi_flags & ACPIDEV_WI_DISABLE_CREATE) &&
759 (infop->awi_flags & ACPIDEV_WI_DEVICE_CREATED)) {
760 ASSERT(infop->awi_dip != NULL);
761 ACPIDEV_DEBUG(CE_NOTE,
762 "acpidev: device has already been created for object %s.",
763 infop->awi_name);
764 return (AE_ALREADY_EXISTS);
765 }
766
767 /*
768 * Determine action according to following rules based on device
769 * status return by _STA method. Please refer to ACPI3.0b section
770 * 6.3.1 and 6.5.1.
771 * present functioning enabled Action
772 * 0 0 x Do nothing
773 * 1 x 0 Create node in OFFLINE and scan child
774 * 1 x 1 Create node and scan child
775 * x 1 0 Create node in OFFLINE and scan child
776 * x 1 1 Create node and scan child
777 */
778 if ((datap->aod_iflag & ACPIDEV_ODF_STATUS_VALID) == 0 ||
779 (flags & ACPIDEV_PROCESS_FLAG_SYNCSTATUS)) {
780 if (adip->Valid & ACPI_VALID_STA) {
781 datap->aod_status = adip->CurrentStatus;
782 } else {
783 datap->aod_status = acpidev_query_device_status(hdl);
784 }
785 datap->aod_iflag |= ACPIDEV_ODF_STATUS_VALID;
786 }
787 if (!acpidev_check_device_present(datap->aod_status)) {
788 ACPIDEV_DEBUG(CE_NOTE, "acpidev: object %s doesn't exist.",
789 infop->awi_name);
790 return (AE_NOT_EXIST);
791 }
792
793 ASSERT(infop->awi_data != NULL);
794 ASSERT(infop->awi_parent != NULL);
795 ASSERT(infop->awi_parent->awi_data != NULL);
796 /* Put device into offline state if parent is in offline state. */
797 if (infop->awi_parent->awi_data->aod_iflag &
798 ACPIDEV_ODF_DEVINFO_OFFLINE) {
799 flags |= ACPIDEV_PROCESS_FLAG_OFFLINE;
800 /* Put device into offline state if it's disabled. */
801 } else if (!acpidev_check_device_enabled(datap->aod_status)) {
802 flags |= ACPIDEV_PROCESS_FLAG_OFFLINE;
803 }
804 /*
805 * Mark current node status as OFFLINE no matter device node will be
806 * created or not. This is needed to handle the case that current node
807 * is is SKIPPED (no device node will be created for it), so that all
808 * descedants of current nodes could be correctly marked as OFFLINE.
809 */
810 if (flags & ACPIDEV_PROCESS_FLAG_OFFLINE) {
811 infop->awi_data->aod_iflag |= ACPIDEV_ODF_DEVINFO_OFFLINE;
812 }
813
814 /* Evaluate filtering rules and generate device name. */
815 devname = kmem_zalloc(ACPIDEV_MAX_NAMELEN + 1, KM_SLEEP);
816 (void) memcpy(devname, (char *)&adip->Name, sizeof (adip->Name));
817 if (flags & ACPIDEV_PROCESS_FLAG_CREATE) {
818 res = clsp->adc_filter(infop, devname, ACPIDEV_MAX_NAMELEN);
819 } else {
820 res = clsp->adc_filter(infop, NULL, 0);
821 }
822
823 /* Create device if requested. */
824 if ((flags & ACPIDEV_PROCESS_FLAG_CREATE) &&
825 !(infop->awi_flags & ACPIDEV_WI_DISABLE_CREATE) &&
826 !(infop->awi_flags & ACPIDEV_WI_DEVICE_CREATED) &&
827 (res == ACPIDEV_FILTER_DEFAULT || res == ACPIDEV_FILTER_CREATE)) {
828 int ret;
829
830 /*
831 * Allocate dip and set default properties.
832 * Properties can be overrided in class specific init routine.
833 */
834 ASSERT(infop->awi_dip == NULL);
835 ndi_devi_alloc_sleep(pdip, devname, (pnode_t)DEVI_SID_NODEID,
836 &dip);
837 infop->awi_dip = dip;
838 ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
839 OBP_DEVICETYPE, clsp->adc_dev_type);
840 if (ret != NDI_SUCCESS) {
841 ACPIDEV_DEBUG(CE_WARN,
842 "acpidev: failed to set device property for %s.",
843 infop->awi_name);
844 (void) ddi_remove_child(dip, 0);
845 infop->awi_dip = NULL;
846 kmem_free(devname, ACPIDEV_MAX_NAMELEN + 1);
847 return (AE_ERROR);
848 }
849
850 /* Build cross reference between dip and ACPI object. */
851 if ((flags & ACPIDEV_PROCESS_FLAG_NOTAG) == 0 &&
852 ACPI_FAILURE(acpica_tag_devinfo(dip, hdl))) {
853 cmn_err(CE_CONT,
854 "?acpidev: failed to tag object %s.\n",
855 infop->awi_name);
856 (void) ddi_remove_child(dip, 0);
857 infop->awi_dip = NULL;
858 kmem_free(devname, ACPIDEV_MAX_NAMELEN + 1);
859 return (AE_ERROR);
860 }
861
862 /* Call class specific initialization callback. */
863 if (clsp->adc_init != NULL &&
864 ACPI_FAILURE(clsp->adc_init(infop))) {
865 ACPIDEV_DEBUG(CE_NOTE,
866 "acpidev: failed to initialize device %s.",
867 infop->awi_name);
868 if ((flags & ACPIDEV_PROCESS_FLAG_NOTAG) == 0) {
869 (void) acpica_untag_devinfo(dip, hdl);
870 }
871 (void) ddi_remove_child(dip, 0);
872 infop->awi_dip = NULL;
873 kmem_free(devname, ACPIDEV_MAX_NAMELEN + 1);
874 return (AE_ERROR);
875 }
876
877 /* Set device into offline state if requested. */
878 if (flags & ACPIDEV_PROCESS_FLAG_OFFLINE) {
879 mutex_enter(&(DEVI(dip)->devi_lock));
880 DEVI_SET_DEVICE_OFFLINE(dip);
881 mutex_exit(&(DEVI(dip)->devi_lock));
882 }
883
884 /* Mark status */
885 infop->awi_flags |= ACPIDEV_WI_DEVICE_CREATED;
886 datap->aod_iflag |= ACPIDEV_ODF_DEVINFO_CREATED;
887 datap->aod_dip = dip;
888 datap->aod_class = clsp;
889 /* Hold reference count on class driver. */
890 atomic_inc_32(&clsp->adc_refcnt);
891 if ((flags & ACPIDEV_PROCESS_FLAG_NOTAG) == 0) {
892 datap->aod_iflag |= ACPIDEV_ODF_DEVINFO_TAGGED;
893 }
894
895 /* Bind device driver. */
896 if ((flags & ACPIDEV_PROCESS_FLAG_NOBIND) == 0) {
897 mutex_enter(&(DEVI(dip)->devi_lock));
898 DEVI(dip)->devi_state |= DEVI_NO_BIND;
899 mutex_exit(&(DEVI(dip)->devi_lock));
900 }
901 (void) ndi_devi_bind_driver(dip, 0);
902 }
903
904 /* Free resources */
905 kmem_free(devname, ACPIDEV_MAX_NAMELEN + 1);
906 rc = AE_OK;
907
908 /* Recursively scan child objects if requested. */
909 switch (res) {
910 case ACPIDEV_FILTER_DEFAULT:
911 /* FALLTHROUGH */
912 case ACPIDEV_FILTER_SCAN:
913 /* Check whether need to scan child. */
914 if ((flags & ACPIDEV_PROCESS_FLAG_SCAN) &&
915 !(infop->awi_flags & ACPIDEV_WI_DISABLE_SCAN) &&
916 !(infop->awi_flags & ACPIDEV_WI_CHILD_SCANNED)) {
917 /* probe child object. */
918 rc = acpidev_probe_child(infop);
919 if (ACPI_FAILURE(rc)) {
920 ACPIDEV_DEBUG(CE_WARN,
921 "acpidev: failed to probe subtree of %s.",
922 infop->awi_name);
923 rc = AE_ERROR;
924 }
925 /* Mark object has been scanned. */
926 infop->awi_flags |= ACPIDEV_WI_CHILD_SCANNED;
927 }
928 break;
929
930 case ACPIDEV_FILTER_CREATE:
931 /* FALLTHROUGH */
932 case ACPIDEV_FILTER_CONTINUE:
933 /* FALLTHROUGH */
934 case ACPIDEV_FILTER_SKIP:
935 break;
936
937 case ACPIDEV_FILTER_FAILED:
938 ACPIDEV_DEBUG(CE_WARN,
939 "acpidev: failed to probe device for %s.",
940 infop->awi_name);
941 rc = AE_ERROR;
942 break;
943
944 default:
945 cmn_err(CE_CONT,
946 "?acpidev: unknown filter result code %d.\n", res);
947 rc = AE_ERROR;
948 break;
949 }
950
951 return (rc);
952 }
953
954 /*ARGSUSED*/
955 acpidev_filter_result_t
956 acpidev_filter_default(acpidev_walk_info_t *infop, ACPI_HANDLE hdl,
957 acpidev_filter_rule_t *afrp, char *devname, int len)
958 {
959 ASSERT(afrp != NULL);
960 ASSERT(devname == NULL || len >= ACPIDEV_MAX_NAMELEN);
961 if (infop->awi_level < afrp->adf_minlvl ||
962 infop->awi_level > afrp->adf_maxlvl) {
963 return (ACPIDEV_FILTER_CONTINUE);
964 } else if (afrp->adf_pattern != NULL &&
965 strncmp(afrp->adf_pattern,
966 (char *)&infop->awi_info->Name,
967 sizeof (infop->awi_info->Name))) {
968 return (ACPIDEV_FILTER_CONTINUE);
969 }
970 if (afrp->adf_replace != NULL && devname != NULL) {
971 (void) strncpy(devname, afrp->adf_replace, len - 1);
972 devname[len - 1] = 0;
973 }
974
975 return (afrp->adf_retcode);
976 }
977
978 acpidev_filter_result_t
979 acpidev_filter_device(acpidev_walk_info_t *infop, ACPI_HANDLE hdl,
980 acpidev_filter_rule_t *afrp, int entries, char *devname, int len)
981 {
982 acpidev_filter_result_t res;
983
984 /* Evaluate filtering rules. */
985 for (; entries > 0; entries--, afrp++) {
986 if (afrp->adf_filter_func != NULL) {
987 res = afrp->adf_filter_func(infop, hdl, afrp,
988 devname, len);
989 } else {
990 res = acpidev_filter_default(infop, hdl, afrp,
991 devname, len);
992 }
993 if (res == ACPIDEV_FILTER_DEFAULT ||
994 res == ACPIDEV_FILTER_SCAN) {
995 infop->awi_class_list = afrp->adf_class_list;
996 break;
997 }
998 }
999
1000 return (res);
1001 }
1002
1003 dev_info_t *
1004 acpidev_root_node(void)
1005 {
1006 return (acpidev_root_dip);
1007 }
1008
1009 ACPI_STATUS
1010 acpidev_register_class(acpidev_class_list_t **listpp, acpidev_class_t *clsp,
1011 boolean_t tail)
1012 {
1013 ACPI_STATUS rc;
1014 acpidev_class_list_t *item;
1015 acpidev_class_list_t *temp;
1016
1017 ASSERT(clsp != NULL);
1018 ASSERT(listpp != NULL);
1019 if (listpp == NULL || clsp == NULL) {
1020 ACPIDEV_DEBUG(CE_WARN,
1021 "acpidev: invalid parameter for register_class().");
1022 return (AE_BAD_PARAMETER);
1023 } else if (clsp->adc_version != ACPIDEV_CLASS_REV) {
1024 cmn_err(CE_CONT,
1025 "?acpidev: class driver %s version mismatch.\n",
1026 clsp->adc_class_name);
1027 return (AE_BAD_DATA);
1028 }
1029
1030 rc = AE_OK;
1031 item = kmem_zalloc(sizeof (*item), KM_SLEEP);
1032 item->acl_class = clsp;
1033 rw_enter(&acpidev_class_lock, RW_WRITER);
1034 /* Check for duplicated item. */
1035 for (temp = *listpp; temp != NULL; temp = temp->acl_next) {
1036 if (temp->acl_class == clsp) {
1037 cmn_err(CE_CONT,
1038 "?acpidev: register duplicate class driver %s.\n",
1039 clsp->adc_class_name);
1040 rc = AE_ALREADY_EXISTS;
1041 break;
1042 }
1043 }
1044 if (ACPI_SUCCESS(rc)) {
1045 if (tail) {
1046 while (*listpp) {
1047 listpp = &(*listpp)->acl_next;
1048 }
1049 }
1050 item->acl_next = *listpp;
1051 *listpp = item;
1052 }
1053 rw_exit(&acpidev_class_lock);
1054 if (ACPI_FAILURE(rc)) {
1055 kmem_free(item, sizeof (*item));
1056 }
1057
1058 return (rc);
1059 }
1060
1061 ACPI_STATUS
1062 acpidev_unregister_class(acpidev_class_list_t **listpp,
1063 acpidev_class_t *clsp)
1064 {
1065 ACPI_STATUS rc = AE_NOT_FOUND;
1066 acpidev_class_list_t *temp;
1067
1068 ASSERT(clsp != NULL);
1069 ASSERT(listpp != NULL);
1070 if (listpp == NULL || clsp == NULL) {
1071 ACPIDEV_DEBUG(CE_WARN,
1072 "acpidev: invalid parameter for unregister_class().");
1073 return (AE_BAD_PARAMETER);
1074 }
1075
1076 rw_enter(&acpidev_class_lock, RW_WRITER);
1077 for (temp = NULL; *listpp; listpp = &(*listpp)->acl_next) {
1078 if ((*listpp)->acl_class == clsp) {
1079 temp = *listpp;
1080 *listpp = (*listpp)->acl_next;
1081 break;
1082 }
1083 }
1084 if (temp == NULL) {
1085 ACPIDEV_DEBUG(CE_WARN,
1086 "acpidev: class %p(%s) doesn't exist when unregister.",
1087 (void *)clsp, clsp->adc_class_name);
1088 rc = AE_NOT_FOUND;
1089 } else if (temp->acl_class->adc_refcnt != 0) {
1090 ACPIDEV_DEBUG(CE_WARN,
1091 "acpidev: class %p(%s) is still in use when unregister.",
1092 (void *)clsp, clsp->adc_class_name);
1093 rc = AE_ERROR;
1094 } else {
1095 kmem_free(temp, sizeof (*temp));
1096 rc = AE_OK;
1097 }
1098 rw_exit(&acpidev_class_lock);
1099
1100 return (rc);
1101 }