1 /*
2 * Copyright (c) 2009, Intel Corporation.
3 * All rights reserved.
4 */
5
6 #include <sys/types.h>
7 #include <sys/atomic.h>
8 #include <sys/sunddi.h>
9 #include <sys/sunndi.h>
10 #include <sys/acpi/acpi.h>
11 #include <sys/acpica.h>
12 #include <sys/acpidev.h>
13 #include <sys/acpidev_impl.h>
14
15 static ACPI_STATUS acpidev_scope_probe(acpidev_walk_info_t *infop);
16 static acpidev_filter_result_t acpidev_scope_filter(acpidev_walk_info_t *infop,
17 char *devname, int maxlen);
18 static ACPI_STATUS acpidev_scope_init(acpidev_walk_info_t *infop);
19
20 /*
21 * Default class driver for ACPI scope object.
22 * This class dirver is used to handle predefined ACPI SCOPE object
23 * under ACPI root object, such as _PR_, _SB_ and _TZ_ etc.
24 * Default policy for ACPI SCOPE object is SKIP.
25 */
26 acpidev_class_t acpidev_class_scope = {
27 0, /* adc_refcnt */
28 ACPIDEV_CLASS_REV1, /* adc_version */
29 ACPIDEV_CLASS_ID_SCOPE, /* adc_class_id */
30 "ACPI Scope", /* adc_class_name */
31 ACPIDEV_TYPE_SCOPE, /* adc_dev_type */
32 NULL, /* adc_private */
33 NULL, /* adc_pre_probe */
34 NULL, /* adc_post_probe */
35 acpidev_scope_probe, /* adc_probe */
36 acpidev_scope_filter, /* adc_filter */
37 acpidev_scope_init, /* adc_init */
38 NULL, /* adc_fini */
39 };
40
41 acpidev_class_list_t *acpidev_class_list_scope = NULL;
42
43 /*
44 * All SCOPE objects share a global pseudo unit address space across system.
45 */
46 static uint32_t acpidev_scope_unitaddr = 0;
47
48 /* Filter rule table for ACPI SCOPE object. */
49 static acpidev_filter_rule_t acpidev_scope_filters[] = {
50 { /* For safety, though _SB_ is hardcoded as DEVICE by acpica */
51 NULL,
52 0,
53 ACPIDEV_FILTER_SCAN,
54 &acpidev_class_list_device,
55 1,
56 1,
57 ACPIDEV_OBJECT_NAME_SB,
58 "",
59 },
60 { /* Handle _PR_ object. */
61 NULL,
62 0,
63 ACPIDEV_FILTER_SCAN,
64 &acpidev_class_list_scope,
65 1,
66 1,
67 ACPIDEV_OBJECT_NAME_PR,
68 ACPIDEV_NODE_NAME_PROCESSOR,
69 },
70 { /* Ignore all other scope objects. */
71 NULL,
72 0,
73 ACPIDEV_FILTER_SKIP,
74 NULL,
75 1,
76 INT_MAX,
77 NULL,
78 NULL,
79 }
80 };
81
82 static ACPI_STATUS
83 acpidev_scope_probe(acpidev_walk_info_t *infop)
84 {
85 ACPI_STATUS rc;
86 int flags;
87
88 ASSERT(infop != NULL);
89 ASSERT(infop->awi_hdl != NULL);
90 ASSERT(infop->awi_info != NULL);
91 if (infop->awi_info->Type != ACPI_TYPE_LOCAL_SCOPE) {
92 return (AE_OK);
93 }
94
95 if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE) {
96 flags = ACPIDEV_PROCESS_FLAG_SCAN | ACPIDEV_PROCESS_FLAG_CREATE;
97 rc = acpidev_process_object(infop, flags);
98 } else if (infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE) {
99 flags = ACPIDEV_PROCESS_FLAG_SCAN;
100 rc = acpidev_process_object(infop, flags);
101 } else if (infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
102 flags = ACPIDEV_PROCESS_FLAG_SCAN;
103 rc = acpidev_process_object(infop, flags);
104 } else {
105 ACPIDEV_DEBUG(CE_WARN,
106 "acpidev: unknown operation type %u in scope_probe().",
107 infop->awi_op_type);
108 rc = AE_BAD_PARAMETER;
109 }
110 if (ACPI_FAILURE(rc) && rc != AE_NOT_EXIST && rc != AE_ALREADY_EXISTS) {
111 cmn_err(CE_CONT,
112 "?acpidev: failed to process scope object %s.\n",
113 infop->awi_name);
114 } else {
115 rc = AE_OK;
116 }
117
118 return (rc);
119 }
120
121 static acpidev_filter_result_t
122 acpidev_scope_filter(acpidev_walk_info_t *infop, char *devname, int maxlen)
123 {
124 acpidev_filter_result_t res;
125
126 ASSERT(infop != NULL);
127 if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
128 infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE ||
129 infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
130 res = acpidev_filter_device(infop, infop->awi_hdl,
131 ACPIDEV_ARRAY_PARAM(acpidev_scope_filters),
132 devname, maxlen);
133 } else {
134 ACPIDEV_DEBUG(CE_WARN,
135 "acpidev: unknown operation type %u in scope_filter().",
136 infop->awi_op_type);
137 res = ACPIDEV_FILTER_FAILED;
138 }
139
140 return (res);
141 }
142
143 /*ARGSUSED*/
144 static ACPI_STATUS
145 acpidev_scope_init(acpidev_walk_info_t *infop)
146 {
147 char unitaddr[32];
148 char *compatibles[] = {
149 ACPIDEV_HID_SCOPE,
150 ACPIDEV_TYPE_SCOPE,
151 ACPIDEV_HID_VIRTNEX,
152 ACPIDEV_TYPE_VIRTNEX,
153 };
154
155 ASSERT(infop != NULL);
156 ASSERT(infop->awi_hdl != NULL);
157 ASSERT(infop->awi_dip != NULL);
158 if (ACPI_FAILURE(acpidev_set_compatibles(infop,
159 ACPIDEV_ARRAY_PARAM(compatibles)))) {
160 return (AE_ERROR);
161 }
162 (void) snprintf(unitaddr, sizeof (unitaddr), "%u",
163 atomic_inc_32_nv(&acpidev_scope_unitaddr) - 1);
164 if (ACPI_FAILURE(acpidev_set_unitaddr(infop, NULL, 0, unitaddr))) {
165 return (AE_ERROR);
166 }
167
168 return (AE_OK);
169 }