diff options
author | Bob Moore <robert.moore@intel.com> | 2012-07-15 22:21:34 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2012-07-17 00:05:50 -0400 |
commit | f60d81813d0e01463e76155c393b75a09dd3bbb4 (patch) | |
tree | aa0d28a3cd2392ede13802281f977b4738252b63 | |
parent | d59b8ecd94ee6ab8c663fc187ed6acf8ffdd3b5d (diff) |
ACPICA: Add new ACPI table load/unload external interfaces
Add acpi_load_table and acpi_unload_parent_table to support
host-directed dynamic table load/unload. Intended to support
hotplug addition and removal of SSDTs.
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r-- | drivers/acpi/acpica/tbxface.c | 42 | ||||
-rw-r--r-- | drivers/acpi/acpica/tbxfload.c | 178 | ||||
-rw-r--r-- | include/acpi/acpixf.h | 13 |
3 files changed, 187 insertions, 46 deletions
diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index 472a91ccde95..9bf34f76d936 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c | |||
@@ -215,48 +215,6 @@ acpi_status acpi_reallocate_root_table(void) | |||
215 | 215 | ||
216 | /******************************************************************************* | 216 | /******************************************************************************* |
217 | * | 217 | * |
218 | * FUNCTION: acpi_load_table | ||
219 | * | ||
220 | * PARAMETERS: table_ptr - pointer to a buffer containing the entire | ||
221 | * table to be loaded | ||
222 | * | ||
223 | * RETURN: Status | ||
224 | * | ||
225 | * DESCRIPTION: This function is called to load a table from the caller's | ||
226 | * buffer. The buffer must contain an entire ACPI Table including | ||
227 | * a valid header. The header fields will be verified, and if it | ||
228 | * is determined that the table is invalid, the call will fail. | ||
229 | * | ||
230 | ******************************************************************************/ | ||
231 | acpi_status acpi_load_table(struct acpi_table_header *table_ptr) | ||
232 | { | ||
233 | acpi_status status; | ||
234 | u32 table_index; | ||
235 | struct acpi_table_desc table_desc; | ||
236 | |||
237 | if (!table_ptr) | ||
238 | return AE_BAD_PARAMETER; | ||
239 | |||
240 | ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc)); | ||
241 | table_desc.pointer = table_ptr; | ||
242 | table_desc.length = table_ptr->length; | ||
243 | table_desc.flags = ACPI_TABLE_ORIGIN_UNKNOWN; | ||
244 | |||
245 | /* | ||
246 | * Install the new table into the local data structures | ||
247 | */ | ||
248 | status = acpi_tb_add_table(&table_desc, &table_index); | ||
249 | if (ACPI_FAILURE(status)) { | ||
250 | return status; | ||
251 | } | ||
252 | status = acpi_ns_load_table(table_index, acpi_gbl_root_node); | ||
253 | return status; | ||
254 | } | ||
255 | |||
256 | ACPI_EXPORT_SYMBOL(acpi_load_table) | ||
257 | |||
258 | /******************************************************************************* | ||
259 | * | ||
260 | * FUNCTION: acpi_get_table_header | 218 | * FUNCTION: acpi_get_table_header |
261 | * | 219 | * |
262 | * PARAMETERS: Signature - ACPI signature of needed table | 220 | * PARAMETERS: Signature - ACPI signature of needed table |
diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index 54a01ae94f8b..f87cc63e69a1 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c | |||
@@ -199,6 +199,184 @@ static acpi_status acpi_tb_load_namespace(void) | |||
199 | return_ACPI_STATUS(status); | 199 | return_ACPI_STATUS(status); |
200 | } | 200 | } |
201 | 201 | ||
202 | /******************************************************************************* | ||
203 | * | ||
204 | * FUNCTION: acpi_load_table | ||
205 | * | ||
206 | * PARAMETERS: table - Pointer to a buffer containing the ACPI | ||
207 | * table to be loaded. | ||
208 | * | ||
209 | * RETURN: Status | ||
210 | * | ||
211 | * DESCRIPTION: Dynamically load an ACPI table from the caller's buffer. Must | ||
212 | * be a valid ACPI table with a valid ACPI table header. | ||
213 | * Note1: Mainly intended to support hotplug addition of SSDTs. | ||
214 | * Note2: Does not copy the incoming table. User is reponsible | ||
215 | * to ensure that the table is not deleted or unmapped. | ||
216 | * | ||
217 | ******************************************************************************/ | ||
218 | |||
219 | acpi_status acpi_load_table(struct acpi_table_header *table) | ||
220 | { | ||
221 | acpi_status status; | ||
222 | struct acpi_table_desc table_desc; | ||
223 | u32 table_index; | ||
224 | |||
225 | ACPI_FUNCTION_TRACE(acpi_load_table); | ||
226 | |||
227 | /* Parameter validation */ | ||
228 | |||
229 | if (!table) { | ||
230 | return_ACPI_STATUS(AE_BAD_PARAMETER); | ||
231 | } | ||
232 | |||
233 | /* Init local table descriptor */ | ||
234 | |||
235 | ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc)); | ||
236 | table_desc.address = ACPI_PTR_TO_PHYSADDR(table); | ||
237 | table_desc.pointer = table; | ||
238 | table_desc.length = table->length; | ||
239 | table_desc.flags = ACPI_TABLE_ORIGIN_UNKNOWN; | ||
240 | |||
241 | /* Must acquire the interpreter lock during this operation */ | ||
242 | |||
243 | status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER); | ||
244 | if (ACPI_FAILURE(status)) { | ||
245 | return_ACPI_STATUS(status); | ||
246 | } | ||
247 | |||
248 | /* Install the table and load it into the namespace */ | ||
249 | |||
250 | ACPI_INFO((AE_INFO, "Host-directed Dynamic ACPI Table Load:")); | ||
251 | status = acpi_tb_add_table(&table_desc, &table_index); | ||
252 | if (ACPI_FAILURE(status)) { | ||
253 | goto unlock_and_exit; | ||
254 | } | ||
255 | |||
256 | status = acpi_ns_load_table(table_index, acpi_gbl_root_node); | ||
257 | |||
258 | /* Invoke table handler if present */ | ||
259 | |||
260 | if (acpi_gbl_table_handler) { | ||
261 | (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD, table, | ||
262 | acpi_gbl_table_handler_context); | ||
263 | } | ||
264 | |||
265 | unlock_and_exit: | ||
266 | (void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); | ||
267 | return_ACPI_STATUS(status); | ||
268 | } | ||
269 | |||
270 | ACPI_EXPORT_SYMBOL(acpi_load_table) | ||
271 | |||
272 | /******************************************************************************* | ||
273 | * | ||
274 | * FUNCTION: acpi_unload_parent_table | ||
275 | * | ||
276 | * PARAMETERS: object - Handle to any namespace object owned by | ||
277 | * the table to be unloaded | ||
278 | * | ||
279 | * RETURN: Status | ||
280 | * | ||
281 | * DESCRIPTION: Via any namespace object within an SSDT or OEMx table, unloads | ||
282 | * the table and deletes all namespace objects associated with | ||
283 | * that table. Unloading of the DSDT is not allowed. | ||
284 | * Note: Mainly intended to support hotplug removal of SSDTs. | ||
285 | * | ||
286 | ******************************************************************************/ | ||
287 | acpi_status acpi_unload_parent_table(acpi_handle object) | ||
288 | { | ||
289 | struct acpi_namespace_node *node = | ||
290 | ACPI_CAST_PTR(struct acpi_namespace_node, object); | ||
291 | acpi_status status = AE_NOT_EXIST; | ||
292 | acpi_owner_id owner_id; | ||
293 | u32 i; | ||
294 | |||
295 | ACPI_FUNCTION_TRACE(acpi_unload_parent_table); | ||
296 | |||
297 | /* Parameter validation */ | ||
298 | |||
299 | if (!object) { | ||
300 | return_ACPI_STATUS(AE_BAD_PARAMETER); | ||
301 | } | ||
302 | |||
303 | /* | ||
304 | * The node owner_id is currently the same as the parent table ID. | ||
305 | * However, this could change in the future. | ||
306 | */ | ||
307 | owner_id = node->owner_id; | ||
308 | if (!owner_id) { | ||
309 | |||
310 | /* owner_id==0 means DSDT is the owner. DSDT cannot be unloaded */ | ||
311 | |||
312 | return_ACPI_STATUS(AE_TYPE); | ||
313 | } | ||
314 | |||
315 | /* Must acquire the interpreter lock during this operation */ | ||
316 | |||
317 | status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER); | ||
318 | if (ACPI_FAILURE(status)) { | ||
319 | return_ACPI_STATUS(status); | ||
320 | } | ||
321 | |||
322 | /* Find the table in the global table list */ | ||
323 | |||
324 | for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) { | ||
325 | if (owner_id != acpi_gbl_root_table_list.tables[i].owner_id) { | ||
326 | continue; | ||
327 | } | ||
328 | |||
329 | /* | ||
330 | * Allow unload of SSDT and OEMx tables only. Do not allow unload | ||
331 | * of the DSDT. No other types of tables should get here, since | ||
332 | * only these types can contain AML and thus are the only types | ||
333 | * that can create namespace objects. | ||
334 | */ | ||
335 | if (ACPI_COMPARE_NAME | ||
336 | (acpi_gbl_root_table_list.tables[i].signature.ascii, | ||
337 | ACPI_SIG_DSDT)) { | ||
338 | status = AE_TYPE; | ||
339 | break; | ||
340 | } | ||
341 | |||
342 | /* Ensure the table is actually loaded */ | ||
343 | |||
344 | if (!acpi_tb_is_table_loaded(i)) { | ||
345 | status = AE_NOT_EXIST; | ||
346 | break; | ||
347 | } | ||
348 | |||
349 | /* Invoke table handler if present */ | ||
350 | |||
351 | if (acpi_gbl_table_handler) { | ||
352 | (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_UNLOAD, | ||
353 | acpi_gbl_root_table_list. | ||
354 | tables[i].pointer, | ||
355 | acpi_gbl_table_handler_context); | ||
356 | } | ||
357 | |||
358 | /* | ||
359 | * Delete all namespace objects owned by this table. Note that | ||
360 | * these objects can appear anywhere in the namespace by virtue | ||
361 | * of the AML "Scope" operator. Thus, we need to track ownership | ||
362 | * by an ID, not simply a position within the hierarchy. | ||
363 | */ | ||
364 | status = acpi_tb_delete_namespace_by_owner(i); | ||
365 | if (ACPI_FAILURE(status)) { | ||
366 | break; | ||
367 | } | ||
368 | |||
369 | status = acpi_tb_release_owner_id(i); | ||
370 | acpi_tb_set_table_loaded_flag(i, FALSE); | ||
371 | break; | ||
372 | } | ||
373 | |||
374 | (void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); | ||
375 | return_ACPI_STATUS(status); | ||
376 | } | ||
377 | |||
378 | ACPI_EXPORT_SYMBOL(acpi_unload_parent_table) | ||
379 | |||
202 | static int __init acpi_no_auto_ssdt_setup(char *s) { | 380 | static int __init acpi_no_auto_ssdt_setup(char *s) { |
203 | 381 | ||
204 | printk(KERN_NOTICE "ACPI: SSDT auto-load disabled\n"); | 382 | printk(KERN_NOTICE "ACPI: SSDT auto-load disabled\n"); |
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 8f83f95c109d..079bb9067c91 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h | |||
@@ -154,15 +154,20 @@ void *acpi_callocate(u32 size); | |||
154 | void acpi_free(void *address); | 154 | void acpi_free(void *address); |
155 | 155 | ||
156 | /* | 156 | /* |
157 | * ACPI table manipulation interfaces | 157 | * ACPI table load/unload interfaces |
158 | */ | 158 | */ |
159 | acpi_status acpi_reallocate_root_table(void); | 159 | acpi_status acpi_load_table(struct acpi_table_header *table); |
160 | 160 | ||
161 | acpi_status acpi_find_root_pointer(acpi_size *rsdp_address); | 161 | acpi_status acpi_unload_parent_table(acpi_handle object); |
162 | 162 | ||
163 | acpi_status acpi_load_tables(void); | 163 | acpi_status acpi_load_tables(void); |
164 | 164 | ||
165 | acpi_status acpi_load_table(struct acpi_table_header *table_ptr); | 165 | /* |
166 | * ACPI table manipulation interfaces | ||
167 | */ | ||
168 | acpi_status acpi_reallocate_root_table(void); | ||
169 | |||
170 | acpi_status acpi_find_root_pointer(acpi_size *rsdp_address); | ||
166 | 171 | ||
167 | acpi_status acpi_unload_table_id(acpi_owner_id id); | 172 | acpi_status acpi_unload_table_id(acpi_owner_id id); |
168 | 173 | ||