diff options
author | Bob Moore <robert.moore@intel.com> | 2007-02-02 11:48:18 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2007-02-02 21:14:21 -0500 |
commit | f3d2e7865c816258c699ff965768e46b50d536d3 (patch) | |
tree | 83d21269e506109275b77d3ed161883bba8a39cf /drivers/acpi/tables/tbxface.c | |
parent | 2e42005bcdb4f63bed1cea7f537a5534d4bd7a57 (diff) |
ACPICA: Implement simplified Table Manager
The Table Manager component has been completely
redesigned and reimplemented. The new design is much
simpler, and reduces the overall code and data size of
the kernel-resident ACPICA by approximately 5%. Also,
it is now possible to obtain the ACPI tables very early
during kernel initialization, even before dynamic memory
management is initialized.
Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/tables/tbxface.c')
-rw-r--r-- | drivers/acpi/tables/tbxface.c | 620 |
1 files changed, 351 insertions, 269 deletions
diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c index 5ba9303293ad..77439fc36c32 100644 --- a/drivers/acpi/tables/tbxface.c +++ b/drivers/acpi/tables/tbxface.c | |||
@@ -49,80 +49,146 @@ | |||
49 | #define _COMPONENT ACPI_TABLES | 49 | #define _COMPONENT ACPI_TABLES |
50 | ACPI_MODULE_NAME("tbxface") | 50 | ACPI_MODULE_NAME("tbxface") |
51 | 51 | ||
52 | /* Local prototypes */ | ||
53 | static acpi_status acpi_tb_load_namespace(void); | ||
54 | |||
52 | /******************************************************************************* | 55 | /******************************************************************************* |
53 | * | 56 | * |
54 | * FUNCTION: acpi_load_tables | 57 | * FUNCTION: acpi_initialize_tables |
55 | * | 58 | * |
56 | * PARAMETERS: None | 59 | * PARAMETERS: initial_table_array - Pointer to an array of pre-allocated |
60 | * struct acpi_table_desc structures. If NULL, the | ||
61 | * array is dynamically allocated. | ||
62 | * initial_table_count - Size of initial_table_array, in number of | ||
63 | * struct acpi_table_desc structures | ||
64 | * allow_realloc - Flag to tell Table Manager if resize of | ||
65 | * pre-allocated array is allowed. Ignored | ||
66 | * if initial_table_array is NULL. | ||
57 | * | 67 | * |
58 | * RETURN: Status | 68 | * RETURN: Status |
59 | * | 69 | * |
60 | * DESCRIPTION: This function is called to load the ACPI tables from the | 70 | * DESCRIPTION: Initialize the table manager, get the RSDP and RSDT/XSDT. |
61 | * provided RSDT | 71 | * |
72 | * NOTE: Allows static allocation of the initial table array in order | ||
73 | * to avoid the use of dynamic memory in confined environments | ||
74 | * such as the kernel boot sequence where it may not be available. | ||
75 | * | ||
76 | * If the host OS memory managers are initialized, use NULL for | ||
77 | * initial_table_array, and the table will be dynamically allocated. | ||
62 | * | 78 | * |
63 | ******************************************************************************/ | 79 | ******************************************************************************/ |
64 | acpi_status acpi_load_tables(void) | 80 | |
81 | acpi_status | ||
82 | acpi_initialize_tables(struct acpi_table_desc *initial_table_array, | ||
83 | u32 initial_table_count, u8 allow_resize) | ||
65 | { | 84 | { |
66 | struct acpi_pointer rsdp_address; | 85 | acpi_physical_address address; |
67 | acpi_status status; | 86 | acpi_status status; |
87 | struct acpi_table_rsdp *rsdp; | ||
68 | 88 | ||
69 | ACPI_FUNCTION_TRACE(acpi_load_tables); | 89 | ACPI_FUNCTION_TRACE(acpi_initialize_tables); |
70 | 90 | ||
71 | /* Get the RSDP */ | 91 | /* |
92 | * Set up the Root Table Array | ||
93 | * Allocate the table array if requested | ||
94 | */ | ||
95 | if (!initial_table_array) { | ||
96 | acpi_gbl_root_table_list.size = initial_table_count; | ||
97 | acpi_gbl_root_table_list.flags = ACPI_TABLE_FLAGS_ALLOW_RESIZE; | ||
72 | 98 | ||
73 | status = acpi_os_get_root_pointer(ACPI_LOGICAL_ADDRESSING, | 99 | status = acpi_tb_resize_root_table_list(); |
74 | &rsdp_address); | 100 | if (ACPI_FAILURE(status)) { |
75 | if (ACPI_FAILURE(status)) { | 101 | return_ACPI_STATUS(status); |
76 | ACPI_EXCEPTION((AE_INFO, status, "Could not get the RSDP")); | 102 | } |
77 | goto error_exit; | 103 | } else { |
104 | /* Root Table Array has been statically allocated by the host */ | ||
105 | |||
106 | acpi_gbl_root_table_list.tables = initial_table_array; | ||
107 | acpi_gbl_root_table_list.size = initial_table_count; | ||
108 | acpi_gbl_root_table_list.flags = ACPI_TABLE_ORIGIN_UNKNOWN; | ||
109 | if (allow_resize) { | ||
110 | acpi_gbl_root_table_list.flags = | ||
111 | ACPI_TABLE_FLAGS_ALLOW_RESIZE; | ||
112 | } | ||
78 | } | 113 | } |
79 | 114 | ||
80 | /* Map and validate the RSDP */ | 115 | /* Get the RSDP and map it */ |
81 | 116 | ||
82 | acpi_gbl_table_flags = rsdp_address.pointer_type; | 117 | address = acpi_os_get_root_pointer(); |
118 | if (!address) { | ||
119 | return_ACPI_STATUS(AE_NOT_FOUND); | ||
120 | } | ||
83 | 121 | ||
84 | status = acpi_tb_verify_rsdp(&rsdp_address); | 122 | rsdp = acpi_os_map_memory(address, sizeof(struct acpi_table_rsdp)); |
85 | if (ACPI_FAILURE(status)) { | 123 | if (!rsdp) { |
86 | ACPI_EXCEPTION((AE_INFO, status, "During RSDP validation")); | 124 | return_ACPI_STATUS(AE_NO_MEMORY); |
87 | goto error_exit; | ||
88 | } | 125 | } |
89 | 126 | ||
90 | /* Get the RSDT via the RSDP */ | 127 | ACPI_INFO((AE_INFO, "%.8s @ 0x%p", |
128 | rsdp->signature, ACPI_CAST_PTR(void, address))); | ||
91 | 129 | ||
92 | status = acpi_tb_get_table_rsdt(); | 130 | /* |
93 | if (ACPI_FAILURE(status)) { | 131 | * Get the root table (RSDT or XSDT) and extract all entries to the local |
94 | ACPI_EXCEPTION((AE_INFO, status, "Could not load RSDT")); | 132 | * Root Table Array. This array contains the information of the RSDT/XSDT |
95 | goto error_exit; | 133 | * in a common, more useable format. |
96 | } | 134 | */ |
135 | status = acpi_tb_parse_root_table(rsdp, ACPI_TABLE_ORIGIN_MAPPED); | ||
136 | acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp)); | ||
137 | return_ACPI_STATUS(status); | ||
138 | } | ||
97 | 139 | ||
98 | /* Now get the tables needed by this subsystem (FADT, DSDT, etc.) */ | 140 | ACPI_EXPORT_SYMBOL(acpi_initialize_tables) |
99 | 141 | ||
100 | status = acpi_tb_get_required_tables(); | 142 | /******************************************************************************* |
101 | if (ACPI_FAILURE(status)) { | 143 | * |
102 | ACPI_EXCEPTION((AE_INFO, status, | 144 | * FUNCTION: acpi_reallocate_root_table |
103 | "Could not get all required tables (DSDT/FADT/FACS)")); | 145 | * |
104 | goto error_exit; | 146 | * PARAMETERS: None |
147 | * | ||
148 | * RETURN: Status | ||
149 | * | ||
150 | * DESCRIPTION: Reallocate Root Table List into dynamic memory. Copies the | ||
151 | * root list from the previously provided scratch area. Should | ||
152 | * be called once dynamic memory allocation is available in the | ||
153 | * kernel | ||
154 | * | ||
155 | ******************************************************************************/ | ||
156 | acpi_status acpi_reallocate_root_table(void) | ||
157 | { | ||
158 | struct acpi_table_desc *tables; | ||
159 | acpi_size new_size; | ||
160 | |||
161 | ACPI_FUNCTION_TRACE(acpi_reallocate_root_table); | ||
162 | |||
163 | /* | ||
164 | * Only reallocate the root table if the host provided a static buffer | ||
165 | * for the table array in the call to acpi_initialize_tables. | ||
166 | */ | ||
167 | if ((acpi_gbl_root_table_list.flags & ACPI_TABLE_ORIGIN_MASK) != | ||
168 | ACPI_TABLE_ORIGIN_UNKNOWN) { | ||
169 | return_ACPI_STATUS(AE_SUPPORT); | ||
105 | } | 170 | } |
106 | 171 | ||
107 | ACPI_DEBUG_PRINT((ACPI_DB_INIT, "ACPI Tables successfully acquired\n")); | 172 | new_size = |
173 | (acpi_gbl_root_table_list.count + | ||
174 | ACPI_ROOT_TABLE_SIZE_INCREMENT) * sizeof(struct acpi_table_desc); | ||
108 | 175 | ||
109 | /* Load the namespace from the tables */ | 176 | /* Create new array and copy the old array */ |
110 | 177 | ||
111 | status = acpi_ns_load_namespace(); | 178 | tables = ACPI_ALLOCATE_ZEROED(new_size); |
112 | if (ACPI_FAILURE(status)) { | 179 | if (!tables) { |
113 | ACPI_EXCEPTION((AE_INFO, status, "Could not load namespace")); | 180 | return_ACPI_STATUS(AE_NO_MEMORY); |
114 | goto error_exit; | ||
115 | } | 181 | } |
116 | 182 | ||
117 | return_ACPI_STATUS(AE_OK); | 183 | ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables, new_size); |
118 | 184 | ||
119 | error_exit: | 185 | acpi_gbl_root_table_list.size = acpi_gbl_root_table_list.count; |
120 | ACPI_EXCEPTION((AE_INFO, status, "Could not load tables")); | 186 | acpi_gbl_root_table_list.tables = tables; |
121 | return_ACPI_STATUS(status); | 187 | acpi_gbl_root_table_list.flags = |
122 | } | 188 | ACPI_TABLE_ORIGIN_ALLOCATED | ACPI_TABLE_FLAGS_ALLOW_RESIZE; |
123 | |||
124 | ACPI_EXPORT_SYMBOL(acpi_load_tables) | ||
125 | 189 | ||
190 | return_ACPI_STATUS(AE_OK); | ||
191 | } | ||
126 | /******************************************************************************* | 192 | /******************************************************************************* |
127 | * | 193 | * |
128 | * FUNCTION: acpi_load_table | 194 | * FUNCTION: acpi_load_table |
@@ -141,342 +207,358 @@ ACPI_EXPORT_SYMBOL(acpi_load_tables) | |||
141 | acpi_status acpi_load_table(struct acpi_table_header *table_ptr) | 207 | acpi_status acpi_load_table(struct acpi_table_header *table_ptr) |
142 | { | 208 | { |
143 | acpi_status status; | 209 | acpi_status status; |
144 | struct acpi_table_desc table_info; | 210 | acpi_native_uint table_index; |
145 | struct acpi_pointer address; | ||
146 | |||
147 | ACPI_FUNCTION_TRACE(acpi_load_table); | ||
148 | |||
149 | if (!table_ptr) { | ||
150 | return_ACPI_STATUS(AE_BAD_PARAMETER); | ||
151 | } | ||
152 | 211 | ||
153 | /* Copy the table to a local buffer */ | 212 | /* |
154 | 213 | * Install the new table into the local data structures | |
155 | address.pointer_type = ACPI_LOGICAL_POINTER | ACPI_LOGICAL_ADDRESSING; | 214 | */ |
156 | address.pointer.logical = table_ptr; | 215 | status = acpi_tb_add_table(table_ptr, &table_index); |
157 | |||
158 | status = acpi_tb_get_table_body(&address, table_ptr, &table_info); | ||
159 | if (ACPI_FAILURE(status)) { | ||
160 | return_ACPI_STATUS(status); | ||
161 | } | ||
162 | |||
163 | /* Check signature for a valid table type */ | ||
164 | |||
165 | status = acpi_tb_recognize_table(&table_info, ACPI_TABLE_ALL); | ||
166 | if (ACPI_FAILURE(status)) { | 216 | if (ACPI_FAILURE(status)) { |
167 | return_ACPI_STATUS(status); | 217 | return_ACPI_STATUS(status); |
168 | } | 218 | } |
219 | status = acpi_ns_load_table(table_index, acpi_gbl_root_node); | ||
220 | return_ACPI_STATUS(status); | ||
221 | } | ||
169 | 222 | ||
170 | /* Install the new table into the local data structures */ | 223 | ACPI_EXPORT_SYMBOL(acpi_load_table) |
171 | |||
172 | status = acpi_tb_install_table(&table_info); | ||
173 | if (ACPI_FAILURE(status)) { | ||
174 | if (status == AE_ALREADY_EXISTS) { | ||
175 | 224 | ||
176 | /* Table already exists, no error */ | 225 | /****************************************************************************** |
226 | * | ||
227 | * FUNCTION: acpi_get_table_header | ||
228 | * | ||
229 | * PARAMETERS: Signature - ACPI signature of needed table | ||
230 | * Instance - Which instance (for SSDTs) | ||
231 | * out_table_header - Where the pointer to the table header | ||
232 | * is returned | ||
233 | * | ||
234 | * RETURN: Status and pointer to mapped table header | ||
235 | * | ||
236 | * DESCRIPTION: Finds an ACPI table header. | ||
237 | * | ||
238 | * NOTE: Caller is responsible in unmapping the header with | ||
239 | * acpi_os_unmap_memory | ||
240 | * | ||
241 | *****************************************************************************/ | ||
242 | acpi_status | ||
243 | acpi_get_table_header(char *signature, | ||
244 | acpi_native_uint instance, | ||
245 | struct acpi_table_header **out_table_header) | ||
246 | { | ||
247 | acpi_native_uint i; | ||
248 | acpi_native_uint j; | ||
177 | 249 | ||
178 | status = AE_OK; | 250 | /* |
251 | * Walk the root table list | ||
252 | */ | ||
253 | for (i = 0, j = 0; i < acpi_gbl_root_table_list.count; i++) { | ||
254 | if (!ACPI_COMPARE_NAME | ||
255 | (&(acpi_gbl_root_table_list.tables[i].signature), | ||
256 | signature)) { | ||
257 | continue; | ||
179 | } | 258 | } |
180 | 259 | ||
181 | /* Free table allocated by acpi_tb_get_table_body */ | 260 | if (++j < instance) { |
182 | 261 | continue; | |
183 | acpi_tb_delete_single_table(&table_info); | 262 | } |
184 | return_ACPI_STATUS(status); | ||
185 | } | ||
186 | |||
187 | /* Convert the table to common format if necessary */ | ||
188 | |||
189 | switch (table_info.type) { | ||
190 | case ACPI_TABLE_ID_FADT: | ||
191 | |||
192 | status = acpi_tb_convert_table_fadt(); | ||
193 | break; | ||
194 | |||
195 | case ACPI_TABLE_ID_FACS: | ||
196 | |||
197 | status = acpi_tb_build_common_facs(&table_info); | ||
198 | break; | ||
199 | |||
200 | default: | ||
201 | /* Load table into namespace if it contains executable AML */ | ||
202 | |||
203 | status = | ||
204 | acpi_ns_load_table(table_info.installed_desc, | ||
205 | acpi_gbl_root_node); | ||
206 | break; | ||
207 | } | ||
208 | 263 | ||
209 | if (ACPI_FAILURE(status)) { | 264 | *out_table_header = |
265 | acpi_tb_map(acpi_gbl_root_table_list.tables[i].address, | ||
266 | (u32) sizeof(struct acpi_table_header), | ||
267 | acpi_gbl_root_table_list.tables[i]. | ||
268 | flags & ACPI_TABLE_ORIGIN_MASK); | ||
210 | 269 | ||
211 | /* Uninstall table and free the buffer */ | 270 | if (!out_table_header) { |
271 | return (AE_NO_MEMORY); | ||
272 | } | ||
212 | 273 | ||
213 | (void)acpi_tb_uninstall_table(table_info.installed_desc); | 274 | return (AE_OK); |
214 | } | 275 | } |
215 | 276 | ||
216 | return_ACPI_STATUS(status); | 277 | return (AE_NOT_FOUND); |
217 | } | 278 | } |
218 | 279 | ||
219 | ACPI_EXPORT_SYMBOL(acpi_load_table) | 280 | ACPI_EXPORT_SYMBOL(acpi_get_table_header) |
220 | 281 | ||
221 | /******************************************************************************* | 282 | |
283 | /****************************************************************************** | ||
222 | * | 284 | * |
223 | * FUNCTION: acpi_unload_table_id | 285 | * FUNCTION: acpi_unload_table_id |
224 | * | 286 | * |
225 | * PARAMETERS: table_type - Type of table to be unloaded | 287 | * PARAMETERS: id - Owner ID of the table to be removed. |
226 | * id - Owner ID of the table to be removed. | ||
227 | * | 288 | * |
228 | * RETURN: Status | 289 | * RETURN: Status |
229 | * | 290 | * |
230 | * DESCRIPTION: This routine is used to force the unload of a table (by id) | 291 | * DESCRIPTION: This routine is used to force the unload of a table (by id) |
231 | * | 292 | * |
232 | ******************************************************************************/ | 293 | ******************************************************************************/ |
233 | acpi_status acpi_unload_table_id(acpi_table_type table_type, acpi_owner_id id) | 294 | acpi_status acpi_unload_table_id(acpi_owner_id id) |
234 | { | 295 | { |
235 | struct acpi_table_desc *table_desc; | 296 | int i; |
236 | acpi_status status; | 297 | acpi_status status = AE_NOT_EXIST; |
237 | 298 | ||
238 | ACPI_FUNCTION_TRACE(acpi_unload_table); | 299 | ACPI_FUNCTION_TRACE(acpi_unload_table); |
239 | 300 | ||
240 | /* Parameter validation */ | ||
241 | if (table_type > ACPI_TABLE_ID_MAX) | ||
242 | return_ACPI_STATUS(AE_BAD_PARAMETER); | ||
243 | |||
244 | /* Find table from the requested type list */ | 301 | /* Find table from the requested type list */ |
245 | table_desc = acpi_gbl_table_lists[table_type].next; | 302 | for (i = 0; i < acpi_gbl_root_table_list.count; ++i) { |
246 | while (table_desc && table_desc->owner_id != id) | 303 | if (id != acpi_gbl_root_table_list.tables[i].owner_id) { |
247 | table_desc = table_desc->next; | 304 | continue; |
248 | 305 | } | |
249 | if (!table_desc) | 306 | /* |
250 | return_ACPI_STATUS(AE_NOT_EXIST); | 307 | * Delete all namespace objects owned by this table. Note that these |
251 | 308 | * objects can appear anywhere in the namespace by virtue of the AML | |
252 | /* | 309 | * "Scope" operator. Thus, we need to track ownership by an ID, not |
253 | * Delete all namespace objects owned by this table. Note that these | 310 | * simply a position within the hierarchy |
254 | * objects can appear anywhere in the namespace by virtue of the AML | 311 | */ |
255 | * "Scope" operator. Thus, we need to track ownership by an ID, not | 312 | acpi_tb_delete_namespace_by_owner(i); |
256 | * simply a position within the hierarchy | 313 | acpi_tb_release_owner_id(i); |
257 | */ | 314 | acpi_tb_set_table_loaded_flag(i, FALSE); |
258 | acpi_ns_delete_namespace_by_owner(table_desc->owner_id); | 315 | } |
259 | 316 | return_ACPI_STATUS(status); | |
260 | status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES); | ||
261 | if (ACPI_FAILURE(status)) | ||
262 | return_ACPI_STATUS(status); | ||
263 | |||
264 | (void)acpi_tb_uninstall_table(table_desc); | ||
265 | |||
266 | (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); | ||
267 | |||
268 | return_ACPI_STATUS(AE_OK); | ||
269 | } | 317 | } |
270 | 318 | ||
271 | ACPI_EXPORT_SYMBOL(acpi_unload_table_id) | 319 | ACPI_EXPORT_SYMBOL(acpi_unload_table_id) |
272 | 320 | ||
273 | #ifdef ACPI_FUTURE_USAGE | ||
274 | /******************************************************************************* | 321 | /******************************************************************************* |
275 | * | 322 | * |
276 | * FUNCTION: acpi_unload_table | 323 | * FUNCTION: acpi_get_table |
277 | * | 324 | * |
278 | * PARAMETERS: table_type - Type of table to be unloaded | 325 | * PARAMETERS: Signature - ACPI signature of needed table |
326 | * Instance - Which instance (for SSDTs) | ||
327 | * out_table - Where the pointer to the table is returned | ||
279 | * | 328 | * |
280 | * RETURN: Status | 329 | * RETURN: Status and pointer to table |
281 | * | 330 | * |
282 | * DESCRIPTION: This routine is used to force the unload of a table | 331 | * DESCRIPTION: Finds and verifies an ACPI table. |
283 | * | 332 | * |
284 | ******************************************************************************/ | 333 | *****************************************************************************/ |
285 | acpi_status acpi_unload_table(acpi_table_type table_type) | 334 | acpi_status |
335 | acpi_get_table(char *signature, | ||
336 | acpi_native_uint instance, struct acpi_table_header ** out_table) | ||
286 | { | 337 | { |
287 | struct acpi_table_desc *table_desc; | 338 | acpi_native_uint i; |
288 | 339 | acpi_native_uint j; | |
289 | ACPI_FUNCTION_TRACE(acpi_unload_table); | 340 | acpi_status status; |
290 | |||
291 | /* Parameter validation */ | ||
292 | 341 | ||
293 | if (table_type > ACPI_TABLE_ID_MAX) { | 342 | /* |
294 | return_ACPI_STATUS(AE_BAD_PARAMETER); | 343 | * Walk the root table list |
295 | } | 344 | */ |
345 | for (i = 0, j = 0; i < acpi_gbl_root_table_list.count; i++) { | ||
346 | if (!ACPI_COMPARE_NAME | ||
347 | (&(acpi_gbl_root_table_list.tables[i].signature), | ||
348 | signature)) { | ||
349 | continue; | ||
350 | } | ||
296 | 351 | ||
297 | /* Find all tables of the requested type */ | 352 | if (++j < instance) { |
353 | continue; | ||
354 | } | ||
298 | 355 | ||
299 | table_desc = acpi_gbl_table_lists[table_type].next; | 356 | status = |
300 | if (!table_desc) { | 357 | acpi_tb_verify_table(&acpi_gbl_root_table_list.tables[i]); |
301 | return_ACPI_STATUS(AE_NOT_EXIST); | 358 | if (ACPI_SUCCESS(status)) { |
302 | } | 359 | *out_table = acpi_gbl_root_table_list.tables[i].pointer; |
360 | } | ||
303 | 361 | ||
304 | while (table_desc) { | 362 | return (status); |
305 | /* | ||
306 | * Delete all namespace objects owned by this table. Note that these | ||
307 | * objects can appear anywhere in the namespace by virtue of the AML | ||
308 | * "Scope" operator. Thus, we need to track ownership by an ID, not | ||
309 | * simply a position within the hierarchy | ||
310 | */ | ||
311 | acpi_ns_delete_namespace_by_owner(table_desc->owner_id); | ||
312 | table_desc = table_desc->next; | ||
313 | } | 363 | } |
314 | 364 | ||
315 | /* Delete (or unmap) all tables of this type */ | 365 | return (AE_NOT_FOUND); |
316 | |||
317 | acpi_tb_delete_tables_by_type(table_type); | ||
318 | return_ACPI_STATUS(AE_OK); | ||
319 | } | 366 | } |
320 | 367 | ||
321 | ACPI_EXPORT_SYMBOL(acpi_unload_table) | 368 | ACPI_EXPORT_SYMBOL(acpi_get_table) |
322 | 369 | ||
323 | /******************************************************************************* | 370 | /******************************************************************************* |
324 | * | 371 | * |
325 | * FUNCTION: acpi_get_table_header | 372 | * FUNCTION: acpi_get_table_by_index |
326 | * | 373 | * |
327 | * PARAMETERS: table_type - one of the defined table types | 374 | * PARAMETERS: table_index - Table index |
328 | * Instance - the non zero instance of the table, allows | 375 | * Table - Where the pointer to the table is returned |
329 | * support for multiple tables of the same type | ||
330 | * see acpi_gbl_acpi_table_flag | ||
331 | * out_table_header - pointer to the struct acpi_table_header if successful | ||
332 | * | 376 | * |
333 | * DESCRIPTION: This function is called to get an ACPI table header. The caller | 377 | * RETURN: Status and pointer to the table |
334 | * supplies an pointer to a data area sufficient to contain an ACPI | ||
335 | * struct acpi_table_header structure. | ||
336 | * | 378 | * |
337 | * The header contains a length field that can be used to determine | 379 | * DESCRIPTION: Obtain a table by an index into the global table list. |
338 | * the size of the buffer needed to contain the entire table. This | ||
339 | * function is not valid for the RSD PTR table since it does not | ||
340 | * have a standard header and is fixed length. | ||
341 | * | 380 | * |
342 | ******************************************************************************/ | 381 | ******************************************************************************/ |
343 | acpi_status | 382 | acpi_status |
344 | acpi_get_table_header(acpi_table_type table_type, | 383 | acpi_get_table_by_index(acpi_native_uint table_index, |
345 | u32 instance, struct acpi_table_header *out_table_header) | 384 | struct acpi_table_header ** table) |
346 | { | 385 | { |
347 | struct acpi_table_header *tbl_ptr; | ||
348 | acpi_status status; | 386 | acpi_status status; |
349 | 387 | ||
350 | ACPI_FUNCTION_TRACE(acpi_get_table_header); | 388 | ACPI_FUNCTION_TRACE(acpi_get_table_by_index); |
351 | 389 | ||
352 | if ((instance == 0) || | 390 | (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); |
353 | (table_type == ACPI_TABLE_ID_RSDP) || (!out_table_header)) { | ||
354 | return_ACPI_STATUS(AE_BAD_PARAMETER); | ||
355 | } | ||
356 | 391 | ||
357 | /* Check the table type and instance */ | 392 | /* Validate index */ |
358 | 393 | ||
359 | if ((table_type > ACPI_TABLE_ID_MAX) || | 394 | if (table_index >= acpi_gbl_root_table_list.count) { |
360 | (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags) && | 395 | (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
361 | instance > 1)) { | ||
362 | return_ACPI_STATUS(AE_BAD_PARAMETER); | 396 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
363 | } | 397 | } |
364 | 398 | ||
365 | /* Get a pointer to the entire table */ | 399 | if (!acpi_gbl_root_table_list.tables[table_index].pointer) { |
366 | 400 | ||
367 | status = acpi_tb_get_table_ptr(table_type, instance, &tbl_ptr); | 401 | /* Table is not mapped, map it */ |
368 | if (ACPI_FAILURE(status)) { | ||
369 | return_ACPI_STATUS(status); | ||
370 | } | ||
371 | 402 | ||
372 | /* The function will return a NULL pointer if the table is not loaded */ | 403 | status = |
373 | 404 | acpi_tb_verify_table(&acpi_gbl_root_table_list. | |
374 | if (tbl_ptr == NULL) { | 405 | tables[table_index]); |
375 | return_ACPI_STATUS(AE_NOT_EXIST); | 406 | if (ACPI_FAILURE(status)) { |
407 | (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); | ||
408 | return_ACPI_STATUS(status); | ||
409 | } | ||
376 | } | 410 | } |
377 | 411 | ||
378 | /* Copy the header to the caller's buffer */ | 412 | *table = acpi_gbl_root_table_list.tables[table_index].pointer; |
379 | 413 | (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); | |
380 | ACPI_MEMCPY(ACPI_CAST_PTR(void, out_table_header), | 414 | return_ACPI_STATUS(AE_OK); |
381 | ACPI_CAST_PTR(void, tbl_ptr), | ||
382 | sizeof(struct acpi_table_header)); | ||
383 | |||
384 | return_ACPI_STATUS(status); | ||
385 | } | 415 | } |
386 | 416 | ||
387 | ACPI_EXPORT_SYMBOL(acpi_get_table_header) | 417 | ACPI_EXPORT_SYMBOL(acpi_get_table_by_index) |
388 | #endif /* ACPI_FUTURE_USAGE */ | ||
389 | 418 | ||
390 | /******************************************************************************* | 419 | /******************************************************************************* |
391 | * | 420 | * |
392 | * FUNCTION: acpi_get_table | 421 | * FUNCTION: acpi_tb_load_namespace |
393 | * | 422 | * |
394 | * PARAMETERS: table_type - one of the defined table types | 423 | * PARAMETERS: None |
395 | * Instance - the non zero instance of the table, allows | ||
396 | * support for multiple tables of the same type | ||
397 | * see acpi_gbl_acpi_table_flag | ||
398 | * ret_buffer - pointer to a structure containing a buffer to | ||
399 | * receive the table | ||
400 | * | 424 | * |
401 | * RETURN: Status | 425 | * RETURN: Status |
402 | * | 426 | * |
403 | * DESCRIPTION: This function is called to get an ACPI table. The caller | 427 | * DESCRIPTION: Load the namespace from the DSDT and all SSDTs/PSDTs found in |
404 | * supplies an out_buffer large enough to contain the entire ACPI | 428 | * the RSDT/XSDT. |
405 | * table. The caller should call the acpi_get_table_header function | ||
406 | * first to determine the buffer size needed. Upon completion | ||
407 | * the out_buffer->Length field will indicate the number of bytes | ||
408 | * copied into the out_buffer->buf_ptr buffer. This table will be | ||
409 | * a complete table including the header. | ||
410 | * | 429 | * |
411 | ******************************************************************************/ | 430 | ******************************************************************************/ |
412 | acpi_status | 431 | static acpi_status acpi_tb_load_namespace(void) |
413 | acpi_get_table(acpi_table_type table_type, | ||
414 | u32 instance, struct acpi_buffer *ret_buffer) | ||
415 | { | 432 | { |
416 | struct acpi_table_header *tbl_ptr; | ||
417 | acpi_status status; | 433 | acpi_status status; |
418 | acpi_size table_length; | 434 | struct acpi_table_header *table; |
435 | acpi_native_uint i; | ||
419 | 436 | ||
420 | ACPI_FUNCTION_TRACE(acpi_get_table); | 437 | ACPI_FUNCTION_TRACE(tb_load_namespace); |
421 | 438 | ||
422 | /* Parameter validation */ | 439 | (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); |
423 | 440 | ||
424 | if (instance == 0) { | 441 | /* |
425 | return_ACPI_STATUS(AE_BAD_PARAMETER); | 442 | * Load the namespace. The DSDT is required, but any SSDT and PSDT tables |
443 | * are optional. | ||
444 | */ | ||
445 | if (!acpi_gbl_root_table_list.count || | ||
446 | !ACPI_COMPARE_NAME(& | ||
447 | (acpi_gbl_root_table_list. | ||
448 | tables[ACPI_TABLE_INDEX_DSDT].signature), | ||
449 | ACPI_SIG_DSDT) | ||
450 | || | ||
451 | ACPI_FAILURE(acpi_tb_verify_table | ||
452 | (&acpi_gbl_root_table_list. | ||
453 | tables[ACPI_TABLE_INDEX_DSDT]))) { | ||
454 | status = AE_NO_ACPI_TABLES; | ||
455 | goto unlock_and_exit; | ||
426 | } | 456 | } |
427 | 457 | ||
428 | status = acpi_ut_validate_buffer(ret_buffer); | 458 | /* |
429 | if (ACPI_FAILURE(status)) { | 459 | * Find DSDT table |
430 | return_ACPI_STATUS(status); | 460 | */ |
461 | status = | ||
462 | acpi_os_table_override(acpi_gbl_root_table_list. | ||
463 | tables[ACPI_TABLE_INDEX_DSDT].pointer, | ||
464 | &table); | ||
465 | if (ACPI_SUCCESS(status) && table) { | ||
466 | /* | ||
467 | * DSDT table has been found | ||
468 | */ | ||
469 | acpi_tb_delete_table(ACPI_TABLE_INDEX_DSDT); | ||
470 | acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].pointer = | ||
471 | table; | ||
472 | acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].length = | ||
473 | table->length; | ||
474 | acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].flags = | ||
475 | ACPI_TABLE_ORIGIN_UNKNOWN; | ||
476 | |||
477 | ACPI_INFO((AE_INFO, "Table DSDT replaced by host OS")); | ||
478 | acpi_tb_print_table_header(0, table); | ||
431 | } | 479 | } |
432 | 480 | ||
433 | /* Check the table type and instance */ | 481 | status = |
482 | acpi_tb_verify_table(&acpi_gbl_root_table_list. | ||
483 | tables[ACPI_TABLE_INDEX_DSDT]); | ||
484 | if (ACPI_FAILURE(status)) { | ||
485 | |||
486 | /* A valid DSDT is required */ | ||
434 | 487 | ||
435 | if ((table_type > ACPI_TABLE_ID_MAX) || | 488 | status = AE_NO_ACPI_TABLES; |
436 | (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags) && | 489 | goto unlock_and_exit; |
437 | instance > 1)) { | ||
438 | return_ACPI_STATUS(AE_BAD_PARAMETER); | ||
439 | } | 490 | } |
440 | 491 | ||
441 | /* Get a pointer to the entire table */ | 492 | (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
442 | 493 | ||
443 | status = acpi_tb_get_table_ptr(table_type, instance, &tbl_ptr); | 494 | /* |
495 | * Load and parse tables. | ||
496 | */ | ||
497 | status = acpi_ns_load_table(ACPI_TABLE_INDEX_DSDT, acpi_gbl_root_node); | ||
444 | if (ACPI_FAILURE(status)) { | 498 | if (ACPI_FAILURE(status)) { |
445 | return_ACPI_STATUS(status); | 499 | return_ACPI_STATUS(status); |
446 | } | 500 | } |
447 | 501 | ||
448 | /* | 502 | /* |
449 | * acpi_tb_get_table_ptr will return a NULL pointer if the | 503 | * Load any SSDT or PSDT tables. Note: Loop leaves tables locked |
450 | * table is not loaded. | ||
451 | */ | 504 | */ |
452 | if (tbl_ptr == NULL) { | 505 | (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); |
453 | return_ACPI_STATUS(AE_NOT_EXIST); | 506 | for (i = 0; i < acpi_gbl_root_table_list.count; ++i) { |
507 | if ((!ACPI_COMPARE_NAME | ||
508 | (&(acpi_gbl_root_table_list.tables[i].signature), | ||
509 | ACPI_SIG_SSDT) | ||
510 | && | ||
511 | !ACPI_COMPARE_NAME(& | ||
512 | (acpi_gbl_root_table_list.tables[i]. | ||
513 | signature), ACPI_SIG_PSDT)) | ||
514 | || | ||
515 | ACPI_FAILURE(acpi_tb_verify_table | ||
516 | (&acpi_gbl_root_table_list.tables[i]))) { | ||
517 | continue; | ||
518 | } | ||
519 | |||
520 | /* Ignore errors while loading tables, get as many as possible */ | ||
521 | |||
522 | (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); | ||
523 | (void)acpi_ns_load_table(i, acpi_gbl_root_node); | ||
524 | (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); | ||
454 | } | 525 | } |
455 | 526 | ||
456 | /* Get the table length */ | 527 | ACPI_DEBUG_PRINT((ACPI_DB_INIT, "ACPI Tables successfully acquired\n")); |
457 | 528 | ||
458 | if (table_type == ACPI_TABLE_ID_RSDP) { | 529 | unlock_and_exit: |
530 | (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); | ||
531 | return_ACPI_STATUS(status); | ||
532 | } | ||
459 | 533 | ||
460 | /* RSD PTR is the only "table" without a header */ | 534 | /******************************************************************************* |
535 | * | ||
536 | * FUNCTION: acpi_load_tables | ||
537 | * | ||
538 | * PARAMETERS: None | ||
539 | * | ||
540 | * RETURN: Status | ||
541 | * | ||
542 | * DESCRIPTION: Load the ACPI tables from the RSDT/XSDT | ||
543 | * | ||
544 | ******************************************************************************/ | ||
461 | 545 | ||
462 | table_length = sizeof(struct rsdp_descriptor); | 546 | acpi_status acpi_load_tables(void) |
463 | } else { | 547 | { |
464 | table_length = (acpi_size) tbl_ptr->length; | 548 | acpi_status status; |
465 | } | ||
466 | 549 | ||
467 | /* Validate/Allocate/Clear caller buffer */ | 550 | ACPI_FUNCTION_TRACE(acpi_load_tables); |
468 | 551 | ||
469 | status = acpi_ut_initialize_buffer(ret_buffer, table_length); | 552 | /* |
553 | * Load the namespace from the tables | ||
554 | */ | ||
555 | status = acpi_tb_load_namespace(); | ||
470 | if (ACPI_FAILURE(status)) { | 556 | if (ACPI_FAILURE(status)) { |
471 | return_ACPI_STATUS(status); | 557 | ACPI_EXCEPTION((AE_INFO, status, |
558 | "While loading namespace from ACPI tables")); | ||
472 | } | 559 | } |
473 | 560 | ||
474 | /* Copy the table to the buffer */ | 561 | return_ACPI_STATUS(status); |
475 | |||
476 | ACPI_MEMCPY(ACPI_CAST_PTR(void, ret_buffer->pointer), | ||
477 | ACPI_CAST_PTR(void, tbl_ptr), table_length); | ||
478 | |||
479 | return_ACPI_STATUS(AE_OK); | ||
480 | } | 562 | } |
481 | 563 | ||
482 | ACPI_EXPORT_SYMBOL(acpi_get_table) | 564 | ACPI_EXPORT_SYMBOL(acpi_load_tables) |