195b482a8SLen Brown /****************************************************************************** 295b482a8SLen Brown * 395b482a8SLen Brown * Module Name: tbinstal - ACPI table installation and removal 495b482a8SLen Brown * 595b482a8SLen Brown *****************************************************************************/ 695b482a8SLen Brown 795b482a8SLen Brown /* 8fbb7a2dcSBob Moore * Copyright (C) 2000 - 2014, Intel Corp. 995b482a8SLen Brown * All rights reserved. 1095b482a8SLen Brown * 1195b482a8SLen Brown * Redistribution and use in source and binary forms, with or without 1295b482a8SLen Brown * modification, are permitted provided that the following conditions 1395b482a8SLen Brown * are met: 1495b482a8SLen Brown * 1. Redistributions of source code must retain the above copyright 1595b482a8SLen Brown * notice, this list of conditions, and the following disclaimer, 1695b482a8SLen Brown * without modification. 1795b482a8SLen Brown * 2. Redistributions in binary form must reproduce at minimum a disclaimer 1895b482a8SLen Brown * substantially similar to the "NO WARRANTY" disclaimer below 1995b482a8SLen Brown * ("Disclaimer") and any redistribution must be conditioned upon 2095b482a8SLen Brown * including a substantially similar Disclaimer requirement for further 2195b482a8SLen Brown * binary redistribution. 2295b482a8SLen Brown * 3. Neither the names of the above-listed copyright holders nor the names 2395b482a8SLen Brown * of any contributors may be used to endorse or promote products derived 2495b482a8SLen Brown * from this software without specific prior written permission. 2595b482a8SLen Brown * 2695b482a8SLen Brown * Alternatively, this software may be distributed under the terms of the 2795b482a8SLen Brown * GNU General Public License ("GPL") version 2 as published by the Free 2895b482a8SLen Brown * Software Foundation. 2995b482a8SLen Brown * 3095b482a8SLen Brown * NO WARRANTY 3195b482a8SLen Brown * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3295b482a8SLen Brown * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3395b482a8SLen Brown * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 3495b482a8SLen Brown * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3595b482a8SLen Brown * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3695b482a8SLen Brown * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3795b482a8SLen Brown * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3895b482a8SLen Brown * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 3995b482a8SLen Brown * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 4095b482a8SLen Brown * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 4195b482a8SLen Brown * POSSIBILITY OF SUCH DAMAGES. 4295b482a8SLen Brown */ 4395b482a8SLen Brown 4495b482a8SLen Brown #include <acpi/acpi.h> 45e2f7a777SLen Brown #include "accommon.h" 46e2f7a777SLen Brown #include "acnamesp.h" 47e2f7a777SLen Brown #include "actables.h" 4895b482a8SLen Brown 4995b482a8SLen Brown #define _COMPONENT ACPI_TABLES 5095b482a8SLen Brown ACPI_MODULE_NAME("tbinstal") 5195b482a8SLen Brown 5295b482a8SLen Brown /****************************************************************************** 5395b482a8SLen Brown * 5495b482a8SLen Brown * FUNCTION: acpi_tb_verify_table 5595b482a8SLen Brown * 5695b482a8SLen Brown * PARAMETERS: table_desc - table 5795b482a8SLen Brown * 5895b482a8SLen Brown * RETURN: Status 5995b482a8SLen Brown * 6095b482a8SLen Brown * DESCRIPTION: this function is called to verify and map table 6195b482a8SLen Brown * 6295b482a8SLen Brown *****************************************************************************/ 6395b482a8SLen Brown acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc) 6495b482a8SLen Brown { 6595b482a8SLen Brown acpi_status status = AE_OK; 6695b482a8SLen Brown 6795b482a8SLen Brown ACPI_FUNCTION_TRACE(tb_verify_table); 6895b482a8SLen Brown 6995b482a8SLen Brown /* Map the table if necessary */ 7095b482a8SLen Brown 7195b482a8SLen Brown if (!table_desc->pointer) { 7295b482a8SLen Brown if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) == 7395b482a8SLen Brown ACPI_TABLE_ORIGIN_MAPPED) { 7495b482a8SLen Brown table_desc->pointer = 7595b482a8SLen Brown acpi_os_map_memory(table_desc->address, 7695b482a8SLen Brown table_desc->length); 7795b482a8SLen Brown } 78*5582982dSLv Zheng 7995b482a8SLen Brown if (!table_desc->pointer) { 8095b482a8SLen Brown return_ACPI_STATUS(AE_NO_MEMORY); 8195b482a8SLen Brown } 8295b482a8SLen Brown } 8395b482a8SLen Brown 8495b482a8SLen Brown /* Always calculate checksum, ignore bad checksum if requested */ 8595b482a8SLen Brown 8695b482a8SLen Brown status = 8794d4be67SLv Zheng acpi_tb_verify_checksum(table_desc->pointer, table_desc->length); 8895b482a8SLen Brown 8995b482a8SLen Brown return_ACPI_STATUS(status); 9095b482a8SLen Brown } 9195b482a8SLen Brown 9295b482a8SLen Brown /******************************************************************************* 9395b482a8SLen Brown * 9495b482a8SLen Brown * FUNCTION: acpi_tb_add_table 9595b482a8SLen Brown * 9695b482a8SLen Brown * PARAMETERS: table_desc - Table descriptor 9795b482a8SLen Brown * table_index - Where the table index is returned 9895b482a8SLen Brown * 9995b482a8SLen Brown * RETURN: Status 10095b482a8SLen Brown * 101d3ccaff8SBob Moore * DESCRIPTION: This function is called to add an ACPI table. It is used to 102d3ccaff8SBob Moore * dynamically load tables via the Load and load_table AML 103d3ccaff8SBob Moore * operators. 10495b482a8SLen Brown * 10595b482a8SLen Brown ******************************************************************************/ 10695b482a8SLen Brown 10795b482a8SLen Brown acpi_status 10895b482a8SLen Brown acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index) 10995b482a8SLen Brown { 11095b482a8SLen Brown u32 i; 11195b482a8SLen Brown acpi_status status = AE_OK; 11295b482a8SLen Brown 11395b482a8SLen Brown ACPI_FUNCTION_TRACE(tb_add_table); 11495b482a8SLen Brown 11595b482a8SLen Brown if (!table_desc->pointer) { 11695b482a8SLen Brown status = acpi_tb_verify_table(table_desc); 11795b482a8SLen Brown if (ACPI_FAILURE(status) || !table_desc->pointer) { 11895b482a8SLen Brown return_ACPI_STATUS(status); 11995b482a8SLen Brown } 12095b482a8SLen Brown } 12195b482a8SLen Brown 12295b482a8SLen Brown /* 123c8cefe30SBob Moore * Validate the incoming table signature. 124c8cefe30SBob Moore * 125c8cefe30SBob Moore * 1) Originally, we checked the table signature for "SSDT" or "PSDT". 126c8cefe30SBob Moore * 2) We added support for OEMx tables, signature "OEM". 127c8cefe30SBob Moore * 3) Valid tables were encountered with a null signature, so we just 128c8cefe30SBob Moore * gave up on validating the signature, (05/2008). 129c8cefe30SBob Moore * 4) We encountered non-AML tables such as the MADT, which caused 130c8cefe30SBob Moore * interpreter errors and kernel faults. So now, we once again allow 131c8cefe30SBob Moore * only "SSDT", "OEMx", and now, also a null signature. (05/2011). 13295b482a8SLen Brown */ 133c8cefe30SBob Moore if ((table_desc->pointer->signature[0] != 0x00) && 134c8cefe30SBob Moore (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT)) 135c8cefe30SBob Moore && (ACPI_STRNCMP(table_desc->pointer->signature, "OEM", 3))) { 1363b3ea775SBob Moore ACPI_BIOS_ERROR((AE_INFO, 1373b3ea775SBob Moore "Table has invalid signature [%4.4s] (0x%8.8X), " 1383b3ea775SBob Moore "must be SSDT or OEMx", 139de8e7db7SBob Moore acpi_ut_valid_acpi_name(table_desc->pointer-> 1403b3ea775SBob Moore signature) ? 1413b3ea775SBob Moore table_desc->pointer->signature : "????", 142c8cefe30SBob Moore *(u32 *)table_desc->pointer->signature)); 143c8cefe30SBob Moore 144c8cefe30SBob Moore return_ACPI_STATUS(AE_BAD_SIGNATURE); 145c8cefe30SBob Moore } 14695b482a8SLen Brown 14795b482a8SLen Brown (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); 14895b482a8SLen Brown 14995b482a8SLen Brown /* Check if table is already registered */ 15095b482a8SLen Brown 151b9ee2043SBob Moore for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { 15295b482a8SLen Brown if (!acpi_gbl_root_table_list.tables[i].pointer) { 15395b482a8SLen Brown status = 15495b482a8SLen Brown acpi_tb_verify_table(&acpi_gbl_root_table_list. 15595b482a8SLen Brown tables[i]); 15695b482a8SLen Brown if (ACPI_FAILURE(status) 15795b482a8SLen Brown || !acpi_gbl_root_table_list.tables[i].pointer) { 15895b482a8SLen Brown continue; 15995b482a8SLen Brown } 16095b482a8SLen Brown } 16195b482a8SLen Brown 16295b482a8SLen Brown /* 16395b482a8SLen Brown * Check for a table match on the entire table length, 16495b482a8SLen Brown * not just the header. 16595b482a8SLen Brown */ 16695b482a8SLen Brown if (table_desc->length != 16795b482a8SLen Brown acpi_gbl_root_table_list.tables[i].length) { 16895b482a8SLen Brown continue; 16995b482a8SLen Brown } 17095b482a8SLen Brown 17195b482a8SLen Brown if (ACPI_MEMCMP(table_desc->pointer, 17295b482a8SLen Brown acpi_gbl_root_table_list.tables[i].pointer, 17395b482a8SLen Brown acpi_gbl_root_table_list.tables[i].length)) { 17495b482a8SLen Brown continue; 17595b482a8SLen Brown } 17695b482a8SLen Brown 17795b482a8SLen Brown /* 17895b482a8SLen Brown * Note: the current mechanism does not unregister a table if it is 17995b482a8SLen Brown * dynamically unloaded. The related namespace entries are deleted, 18095b482a8SLen Brown * but the table remains in the root table list. 18195b482a8SLen Brown * 18295b482a8SLen Brown * The assumption here is that the number of different tables that 18395b482a8SLen Brown * will be loaded is actually small, and there is minimal overhead 18495b482a8SLen Brown * in just keeping the table in case it is needed again. 18595b482a8SLen Brown * 18695b482a8SLen Brown * If this assumption changes in the future (perhaps on large 18795b482a8SLen Brown * machines with many table load/unload operations), tables will 18895b482a8SLen Brown * need to be unregistered when they are unloaded, and slots in the 18995b482a8SLen Brown * root table list should be reused when empty. 19095b482a8SLen Brown */ 19195b482a8SLen Brown 19295b482a8SLen Brown /* 19395b482a8SLen Brown * Table is already registered. 19495b482a8SLen Brown * We can delete the table that was passed as a parameter. 19595b482a8SLen Brown */ 19695b482a8SLen Brown acpi_tb_delete_table(table_desc); 19795b482a8SLen Brown *table_index = i; 19895b482a8SLen Brown 19995b482a8SLen Brown if (acpi_gbl_root_table_list.tables[i]. 20095b482a8SLen Brown flags & ACPI_TABLE_IS_LOADED) { 20195b482a8SLen Brown 20295b482a8SLen Brown /* Table is still loaded, this is an error */ 20395b482a8SLen Brown 20495b482a8SLen Brown status = AE_ALREADY_EXISTS; 20595b482a8SLen Brown goto release; 20695b482a8SLen Brown } else { 20795b482a8SLen Brown /* Table was unloaded, allow it to be reloaded */ 20895b482a8SLen Brown 20995b482a8SLen Brown table_desc->pointer = 21095b482a8SLen Brown acpi_gbl_root_table_list.tables[i].pointer; 21195b482a8SLen Brown table_desc->address = 21295b482a8SLen Brown acpi_gbl_root_table_list.tables[i].address; 21395b482a8SLen Brown status = AE_OK; 21495b482a8SLen Brown goto print_header; 21595b482a8SLen Brown } 21695b482a8SLen Brown } 21795b482a8SLen Brown 218d3ccaff8SBob Moore /* 219d3ccaff8SBob Moore * ACPI Table Override: 220d3ccaff8SBob Moore * Allow the host to override dynamically loaded tables. 221f7b004a1SBob Moore * NOTE: the table is fully mapped at this point, and the mapping will 222f7b004a1SBob Moore * be deleted by tb_table_override if the table is actually overridden. 223d3ccaff8SBob Moore */ 224f7b004a1SBob Moore (void)acpi_tb_table_override(table_desc->pointer, table_desc); 225d3ccaff8SBob Moore 22695b482a8SLen Brown /* Add the table to the global root table list */ 22795b482a8SLen Brown 22895b482a8SLen Brown status = acpi_tb_store_table(table_desc->address, table_desc->pointer, 22995b482a8SLen Brown table_desc->length, table_desc->flags, 23095b482a8SLen Brown table_index); 23195b482a8SLen Brown if (ACPI_FAILURE(status)) { 23295b482a8SLen Brown goto release; 23395b482a8SLen Brown } 23495b482a8SLen Brown 23595b482a8SLen Brown print_header: 23695b482a8SLen Brown acpi_tb_print_table_header(table_desc->address, table_desc->pointer); 23795b482a8SLen Brown 23895b482a8SLen Brown release: 23995b482a8SLen Brown (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); 24095b482a8SLen Brown return_ACPI_STATUS(status); 24195b482a8SLen Brown } 24295b482a8SLen Brown 24395b482a8SLen Brown /******************************************************************************* 24495b482a8SLen Brown * 245f7b004a1SBob Moore * FUNCTION: acpi_tb_table_override 246f7b004a1SBob Moore * 247f7b004a1SBob Moore * PARAMETERS: table_header - Header for the original table 248f7b004a1SBob Moore * table_desc - Table descriptor initialized for the 249f7b004a1SBob Moore * original table. May or may not be mapped. 250f7b004a1SBob Moore * 251f7b004a1SBob Moore * RETURN: Pointer to the entire new table. NULL if table not overridden. 252f7b004a1SBob Moore * If overridden, installs the new table within the input table 253f7b004a1SBob Moore * descriptor. 254f7b004a1SBob Moore * 255f7b004a1SBob Moore * DESCRIPTION: Attempt table override by calling the OSL override functions. 256f7b004a1SBob Moore * Note: If the table is overridden, then the entire new table 257f7b004a1SBob Moore * is mapped and returned by this function. 258f7b004a1SBob Moore * 259f7b004a1SBob Moore ******************************************************************************/ 260f7b004a1SBob Moore 261f7b004a1SBob Moore struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header 262f7b004a1SBob Moore *table_header, 263f7b004a1SBob Moore struct acpi_table_desc 264f7b004a1SBob Moore *table_desc) 265f7b004a1SBob Moore { 266f7b004a1SBob Moore acpi_status status; 267f7b004a1SBob Moore struct acpi_table_header *new_table = NULL; 268f7b004a1SBob Moore acpi_physical_address new_address = 0; 269f7b004a1SBob Moore u32 new_table_length = 0; 270f7b004a1SBob Moore u8 new_flags; 271f7b004a1SBob Moore char *override_type; 272f7b004a1SBob Moore 273f7b004a1SBob Moore /* (1) Attempt logical override (returns a logical address) */ 274f7b004a1SBob Moore 275f7b004a1SBob Moore status = acpi_os_table_override(table_header, &new_table); 276f7b004a1SBob Moore if (ACPI_SUCCESS(status) && new_table) { 277f7b004a1SBob Moore new_address = ACPI_PTR_TO_PHYSADDR(new_table); 278f7b004a1SBob Moore new_table_length = new_table->length; 279f7b004a1SBob Moore new_flags = ACPI_TABLE_ORIGIN_OVERRIDE; 280f7b004a1SBob Moore override_type = "Logical"; 281f7b004a1SBob Moore goto finish_override; 282f7b004a1SBob Moore } 283f7b004a1SBob Moore 284f7b004a1SBob Moore /* (2) Attempt physical override (returns a physical address) */ 285f7b004a1SBob Moore 286f7b004a1SBob Moore status = acpi_os_physical_table_override(table_header, 287f7b004a1SBob Moore &new_address, 288f7b004a1SBob Moore &new_table_length); 289f7b004a1SBob Moore if (ACPI_SUCCESS(status) && new_address && new_table_length) { 290f7b004a1SBob Moore 291f7b004a1SBob Moore /* Map the entire new table */ 292f7b004a1SBob Moore 293f7b004a1SBob Moore new_table = acpi_os_map_memory(new_address, new_table_length); 294f7b004a1SBob Moore if (!new_table) { 295f7b004a1SBob Moore ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, 2962e19f8d0SBob Moore "%4.4s " ACPI_PRINTF_UINT 2972e19f8d0SBob Moore " Attempted physical table override failed", 298f7b004a1SBob Moore table_header->signature, 2992e19f8d0SBob Moore ACPI_FORMAT_TO_UINT(table_desc-> 3002e19f8d0SBob Moore address))); 301f7b004a1SBob Moore return (NULL); 302f7b004a1SBob Moore } 303f7b004a1SBob Moore 304f7b004a1SBob Moore override_type = "Physical"; 305f7b004a1SBob Moore new_flags = ACPI_TABLE_ORIGIN_MAPPED; 306f7b004a1SBob Moore goto finish_override; 307f7b004a1SBob Moore } 308f7b004a1SBob Moore 309f7b004a1SBob Moore return (NULL); /* There was no override */ 310f7b004a1SBob Moore 311f7b004a1SBob Moore finish_override: 312f7b004a1SBob Moore 3132e19f8d0SBob Moore ACPI_INFO((AE_INFO, "%4.4s " ACPI_PRINTF_UINT 3142e19f8d0SBob Moore " %s table override, new table: " ACPI_PRINTF_UINT, 315f7b004a1SBob Moore table_header->signature, 3162e19f8d0SBob Moore ACPI_FORMAT_TO_UINT(table_desc->address), 3172e19f8d0SBob Moore override_type, ACPI_FORMAT_TO_UINT(new_table))); 318f7b004a1SBob Moore 319f7b004a1SBob Moore /* We can now unmap/delete the original table (if fully mapped) */ 320f7b004a1SBob Moore 321f7b004a1SBob Moore acpi_tb_delete_table(table_desc); 322f7b004a1SBob Moore 323f7b004a1SBob Moore /* Setup descriptor for the new table */ 324f7b004a1SBob Moore 325f7b004a1SBob Moore table_desc->address = new_address; 326f7b004a1SBob Moore table_desc->pointer = new_table; 327f7b004a1SBob Moore table_desc->length = new_table_length; 328f7b004a1SBob Moore table_desc->flags = new_flags; 329f7b004a1SBob Moore 330f7b004a1SBob Moore return (new_table); 331f7b004a1SBob Moore } 332f7b004a1SBob Moore 333f7b004a1SBob Moore /******************************************************************************* 334f7b004a1SBob Moore * 33595b482a8SLen Brown * FUNCTION: acpi_tb_resize_root_table_list 33695b482a8SLen Brown * 33795b482a8SLen Brown * PARAMETERS: None 33895b482a8SLen Brown * 33995b482a8SLen Brown * RETURN: Status 34095b482a8SLen Brown * 34195b482a8SLen Brown * DESCRIPTION: Expand the size of global table array 34295b482a8SLen Brown * 34395b482a8SLen Brown ******************************************************************************/ 34495b482a8SLen Brown 34595b482a8SLen Brown acpi_status acpi_tb_resize_root_table_list(void) 34695b482a8SLen Brown { 34795b482a8SLen Brown struct acpi_table_desc *tables; 3482bc198c1SLv Zheng u32 table_count; 34995b482a8SLen Brown 35095b482a8SLen Brown ACPI_FUNCTION_TRACE(tb_resize_root_table_list); 35195b482a8SLen Brown 35295b482a8SLen Brown /* allow_resize flag is a parameter to acpi_initialize_tables */ 35395b482a8SLen Brown 35495b482a8SLen Brown if (!(acpi_gbl_root_table_list.flags & ACPI_ROOT_ALLOW_RESIZE)) { 35595b482a8SLen Brown ACPI_ERROR((AE_INFO, 35695b482a8SLen Brown "Resize of Root Table Array is not allowed")); 35795b482a8SLen Brown return_ACPI_STATUS(AE_SUPPORT); 35895b482a8SLen Brown } 35995b482a8SLen Brown 36095b482a8SLen Brown /* Increase the Table Array size */ 36195b482a8SLen Brown 3622bc198c1SLv Zheng if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { 3632bc198c1SLv Zheng table_count = acpi_gbl_root_table_list.max_table_count; 3642bc198c1SLv Zheng } else { 3652bc198c1SLv Zheng table_count = acpi_gbl_root_table_list.current_table_count; 3662bc198c1SLv Zheng } 3672bc198c1SLv Zheng 3682bc198c1SLv Zheng tables = ACPI_ALLOCATE_ZEROED(((acpi_size) table_count + 369ec41f193SBob Moore ACPI_ROOT_TABLE_SIZE_INCREMENT) * 370ec41f193SBob Moore sizeof(struct acpi_table_desc)); 37195b482a8SLen Brown if (!tables) { 37295b482a8SLen Brown ACPI_ERROR((AE_INFO, 37395b482a8SLen Brown "Could not allocate new root table array")); 37495b482a8SLen Brown return_ACPI_STATUS(AE_NO_MEMORY); 37595b482a8SLen Brown } 37695b482a8SLen Brown 37795b482a8SLen Brown /* Copy and free the previous table array */ 37895b482a8SLen Brown 37995b482a8SLen Brown if (acpi_gbl_root_table_list.tables) { 38095b482a8SLen Brown ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables, 3812bc198c1SLv Zheng (acpi_size) table_count * 3822bc198c1SLv Zheng sizeof(struct acpi_table_desc)); 38395b482a8SLen Brown 38495b482a8SLen Brown if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { 38595b482a8SLen Brown ACPI_FREE(acpi_gbl_root_table_list.tables); 38695b482a8SLen Brown } 38795b482a8SLen Brown } 38895b482a8SLen Brown 38995b482a8SLen Brown acpi_gbl_root_table_list.tables = tables; 3902bc198c1SLv Zheng acpi_gbl_root_table_list.max_table_count = 3912bc198c1SLv Zheng table_count + ACPI_ROOT_TABLE_SIZE_INCREMENT; 3922bc198c1SLv Zheng acpi_gbl_root_table_list.flags |= ACPI_ROOT_ORIGIN_ALLOCATED; 39395b482a8SLen Brown 39495b482a8SLen Brown return_ACPI_STATUS(AE_OK); 39595b482a8SLen Brown } 39695b482a8SLen Brown 39795b482a8SLen Brown /******************************************************************************* 39895b482a8SLen Brown * 39995b482a8SLen Brown * FUNCTION: acpi_tb_store_table 40095b482a8SLen Brown * 401ba494beeSBob Moore * PARAMETERS: address - Table address 402ba494beeSBob Moore * table - Table header 403ba494beeSBob Moore * length - Table length 404ba494beeSBob Moore * flags - flags 40595b482a8SLen Brown * 40695b482a8SLen Brown * RETURN: Status and table index. 40795b482a8SLen Brown * 40895b482a8SLen Brown * DESCRIPTION: Add an ACPI table to the global table list 40995b482a8SLen Brown * 41095b482a8SLen Brown ******************************************************************************/ 41195b482a8SLen Brown 41295b482a8SLen Brown acpi_status 41395b482a8SLen Brown acpi_tb_store_table(acpi_physical_address address, 41495b482a8SLen Brown struct acpi_table_header *table, 41595b482a8SLen Brown u32 length, u8 flags, u32 *table_index) 41695b482a8SLen Brown { 417b9ee2043SBob Moore acpi_status status; 418b9ee2043SBob Moore struct acpi_table_desc *new_table; 41995b482a8SLen Brown 42095b482a8SLen Brown /* Ensure that there is room for the table in the Root Table List */ 42195b482a8SLen Brown 422b9ee2043SBob Moore if (acpi_gbl_root_table_list.current_table_count >= 423b9ee2043SBob Moore acpi_gbl_root_table_list.max_table_count) { 42495b482a8SLen Brown status = acpi_tb_resize_root_table_list(); 42595b482a8SLen Brown if (ACPI_FAILURE(status)) { 42695b482a8SLen Brown return (status); 42795b482a8SLen Brown } 42895b482a8SLen Brown } 42995b482a8SLen Brown 430b9ee2043SBob Moore new_table = 431b9ee2043SBob Moore &acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list. 432b9ee2043SBob Moore current_table_count]; 433b9ee2043SBob Moore 43495b482a8SLen Brown /* Initialize added table */ 43595b482a8SLen Brown 436b9ee2043SBob Moore new_table->address = address; 437b9ee2043SBob Moore new_table->pointer = table; 438b9ee2043SBob Moore new_table->length = length; 439b9ee2043SBob Moore new_table->owner_id = 0; 440b9ee2043SBob Moore new_table->flags = flags; 44195b482a8SLen Brown 442b9ee2043SBob Moore ACPI_MOVE_32_TO_32(&new_table->signature, table->signature); 44395b482a8SLen Brown 444b9ee2043SBob Moore *table_index = acpi_gbl_root_table_list.current_table_count; 445b9ee2043SBob Moore acpi_gbl_root_table_list.current_table_count++; 446b9ee2043SBob Moore return (AE_OK); 44795b482a8SLen Brown } 44895b482a8SLen Brown 44995b482a8SLen Brown /******************************************************************************* 45095b482a8SLen Brown * 45195b482a8SLen Brown * FUNCTION: acpi_tb_delete_table 45295b482a8SLen Brown * 45395b482a8SLen Brown * PARAMETERS: table_index - Table index 45495b482a8SLen Brown * 45595b482a8SLen Brown * RETURN: None 45695b482a8SLen Brown * 45795b482a8SLen Brown * DESCRIPTION: Delete one internal ACPI table 45895b482a8SLen Brown * 45995b482a8SLen Brown ******************************************************************************/ 46095b482a8SLen Brown 46195b482a8SLen Brown void acpi_tb_delete_table(struct acpi_table_desc *table_desc) 46295b482a8SLen Brown { 463*5582982dSLv Zheng 46495b482a8SLen Brown /* Table must be mapped or allocated */ 465*5582982dSLv Zheng 46695b482a8SLen Brown if (!table_desc->pointer) { 46795b482a8SLen Brown return; 46895b482a8SLen Brown } 469*5582982dSLv Zheng 47095b482a8SLen Brown switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { 47195b482a8SLen Brown case ACPI_TABLE_ORIGIN_MAPPED: 4721d1ea1b7SChao Guan 47395b482a8SLen Brown acpi_os_unmap_memory(table_desc->pointer, table_desc->length); 47495b482a8SLen Brown break; 4751d1ea1b7SChao Guan 47695b482a8SLen Brown case ACPI_TABLE_ORIGIN_ALLOCATED: 4771d1ea1b7SChao Guan 47895b482a8SLen Brown ACPI_FREE(table_desc->pointer); 47995b482a8SLen Brown break; 480f7b004a1SBob Moore 481f7b004a1SBob Moore /* Not mapped or allocated, there is nothing we can do */ 482f7b004a1SBob Moore 483f7b004a1SBob Moore default: 4841d1ea1b7SChao Guan 485f7b004a1SBob Moore return; 48695b482a8SLen Brown } 48795b482a8SLen Brown 48895b482a8SLen Brown table_desc->pointer = NULL; 48995b482a8SLen Brown } 49095b482a8SLen Brown 49195b482a8SLen Brown /******************************************************************************* 49295b482a8SLen Brown * 49395b482a8SLen Brown * FUNCTION: acpi_tb_terminate 49495b482a8SLen Brown * 49595b482a8SLen Brown * PARAMETERS: None 49695b482a8SLen Brown * 49795b482a8SLen Brown * RETURN: None 49895b482a8SLen Brown * 49995b482a8SLen Brown * DESCRIPTION: Delete all internal ACPI tables 50095b482a8SLen Brown * 50195b482a8SLen Brown ******************************************************************************/ 50295b482a8SLen Brown 50395b482a8SLen Brown void acpi_tb_terminate(void) 50495b482a8SLen Brown { 50595b482a8SLen Brown u32 i; 50695b482a8SLen Brown 50795b482a8SLen Brown ACPI_FUNCTION_TRACE(tb_terminate); 50895b482a8SLen Brown 50995b482a8SLen Brown (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); 51095b482a8SLen Brown 51195b482a8SLen Brown /* Delete the individual tables */ 51295b482a8SLen Brown 513b9ee2043SBob Moore for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) { 51495b482a8SLen Brown acpi_tb_delete_table(&acpi_gbl_root_table_list.tables[i]); 51595b482a8SLen Brown } 51695b482a8SLen Brown 51795b482a8SLen Brown /* 51895b482a8SLen Brown * Delete the root table array if allocated locally. Array cannot be 51995b482a8SLen Brown * mapped, so we don't need to check for that flag. 52095b482a8SLen Brown */ 52195b482a8SLen Brown if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { 52295b482a8SLen Brown ACPI_FREE(acpi_gbl_root_table_list.tables); 52395b482a8SLen Brown } 52495b482a8SLen Brown 52595b482a8SLen Brown acpi_gbl_root_table_list.tables = NULL; 52695b482a8SLen Brown acpi_gbl_root_table_list.flags = 0; 527b9ee2043SBob Moore acpi_gbl_root_table_list.current_table_count = 0; 52895b482a8SLen Brown 52995b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n")); 53095b482a8SLen Brown (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); 53168aafc35SBob Moore 53268aafc35SBob Moore return_VOID; 53395b482a8SLen Brown } 53495b482a8SLen Brown 53595b482a8SLen Brown /******************************************************************************* 53695b482a8SLen Brown * 53795b482a8SLen Brown * FUNCTION: acpi_tb_delete_namespace_by_owner 53895b482a8SLen Brown * 53995b482a8SLen Brown * PARAMETERS: table_index - Table index 54095b482a8SLen Brown * 5418a335a23SBob Moore * RETURN: Status 54295b482a8SLen Brown * 54395b482a8SLen Brown * DESCRIPTION: Delete all namespace objects created when this table was loaded. 54495b482a8SLen Brown * 54595b482a8SLen Brown ******************************************************************************/ 54695b482a8SLen Brown 5478a335a23SBob Moore acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index) 54895b482a8SLen Brown { 54995b482a8SLen Brown acpi_owner_id owner_id; 5508a335a23SBob Moore acpi_status status; 55195b482a8SLen Brown 5528a335a23SBob Moore ACPI_FUNCTION_TRACE(tb_delete_namespace_by_owner); 5538a335a23SBob Moore 5548a335a23SBob Moore status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES); 5558a335a23SBob Moore if (ACPI_FAILURE(status)) { 5568a335a23SBob Moore return_ACPI_STATUS(status); 55795b482a8SLen Brown } 55895b482a8SLen Brown 559b9ee2043SBob Moore if (table_index >= acpi_gbl_root_table_list.current_table_count) { 5608a335a23SBob Moore 5618a335a23SBob Moore /* The table index does not exist */ 5628a335a23SBob Moore 56395b482a8SLen Brown (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); 5648a335a23SBob Moore return_ACPI_STATUS(AE_NOT_EXIST); 5658a335a23SBob Moore } 5668a335a23SBob Moore 5678a335a23SBob Moore /* Get the owner ID for this table, used to delete namespace nodes */ 5688a335a23SBob Moore 5698a335a23SBob Moore owner_id = acpi_gbl_root_table_list.tables[table_index].owner_id; 5708a335a23SBob Moore (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); 5718a335a23SBob Moore 5728a335a23SBob Moore /* 5738a335a23SBob Moore * Need to acquire the namespace writer lock to prevent interference 5748a335a23SBob Moore * with any concurrent namespace walks. The interpreter must be 5758a335a23SBob Moore * released during the deletion since the acquisition of the deletion 5768a335a23SBob Moore * lock may block, and also since the execution of a namespace walk 5778a335a23SBob Moore * must be allowed to use the interpreter. 5788a335a23SBob Moore */ 579e4c1ebfcSBob Moore (void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); 5808a335a23SBob Moore status = acpi_ut_acquire_write_lock(&acpi_gbl_namespace_rw_lock); 5818a335a23SBob Moore 58295b482a8SLen Brown acpi_ns_delete_namespace_by_owner(owner_id); 5838a335a23SBob Moore if (ACPI_FAILURE(status)) { 5848a335a23SBob Moore return_ACPI_STATUS(status); 5858a335a23SBob Moore } 5868a335a23SBob Moore 5878a335a23SBob Moore acpi_ut_release_write_lock(&acpi_gbl_namespace_rw_lock); 5888a335a23SBob Moore 5898a335a23SBob Moore status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER); 5908a335a23SBob Moore return_ACPI_STATUS(status); 59195b482a8SLen Brown } 59295b482a8SLen Brown 59395b482a8SLen Brown /******************************************************************************* 59495b482a8SLen Brown * 59595b482a8SLen Brown * FUNCTION: acpi_tb_allocate_owner_id 59695b482a8SLen Brown * 59795b482a8SLen Brown * PARAMETERS: table_index - Table index 59895b482a8SLen Brown * 59995b482a8SLen Brown * RETURN: Status 60095b482a8SLen Brown * 60195b482a8SLen Brown * DESCRIPTION: Allocates owner_id in table_desc 60295b482a8SLen Brown * 60395b482a8SLen Brown ******************************************************************************/ 60495b482a8SLen Brown 60595b482a8SLen Brown acpi_status acpi_tb_allocate_owner_id(u32 table_index) 60695b482a8SLen Brown { 60795b482a8SLen Brown acpi_status status = AE_BAD_PARAMETER; 60895b482a8SLen Brown 60995b482a8SLen Brown ACPI_FUNCTION_TRACE(tb_allocate_owner_id); 61095b482a8SLen Brown 61195b482a8SLen Brown (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); 612b9ee2043SBob Moore if (table_index < acpi_gbl_root_table_list.current_table_count) { 61395b482a8SLen Brown status = acpi_ut_allocate_owner_id 61495b482a8SLen Brown (&(acpi_gbl_root_table_list.tables[table_index].owner_id)); 61595b482a8SLen Brown } 61695b482a8SLen Brown 61795b482a8SLen Brown (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); 61895b482a8SLen Brown return_ACPI_STATUS(status); 61995b482a8SLen Brown } 62095b482a8SLen Brown 62195b482a8SLen Brown /******************************************************************************* 62295b482a8SLen Brown * 62395b482a8SLen Brown * FUNCTION: acpi_tb_release_owner_id 62495b482a8SLen Brown * 62595b482a8SLen Brown * PARAMETERS: table_index - Table index 62695b482a8SLen Brown * 62795b482a8SLen Brown * RETURN: Status 62895b482a8SLen Brown * 62995b482a8SLen Brown * DESCRIPTION: Releases owner_id in table_desc 63095b482a8SLen Brown * 63195b482a8SLen Brown ******************************************************************************/ 63295b482a8SLen Brown 63395b482a8SLen Brown acpi_status acpi_tb_release_owner_id(u32 table_index) 63495b482a8SLen Brown { 63595b482a8SLen Brown acpi_status status = AE_BAD_PARAMETER; 63695b482a8SLen Brown 63795b482a8SLen Brown ACPI_FUNCTION_TRACE(tb_release_owner_id); 63895b482a8SLen Brown 63995b482a8SLen Brown (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); 640b9ee2043SBob Moore if (table_index < acpi_gbl_root_table_list.current_table_count) { 64195b482a8SLen Brown acpi_ut_release_owner_id(& 64295b482a8SLen Brown (acpi_gbl_root_table_list. 64395b482a8SLen Brown tables[table_index].owner_id)); 64495b482a8SLen Brown status = AE_OK; 64595b482a8SLen Brown } 64695b482a8SLen Brown 64795b482a8SLen Brown (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); 64895b482a8SLen Brown return_ACPI_STATUS(status); 64995b482a8SLen Brown } 65095b482a8SLen Brown 65195b482a8SLen Brown /******************************************************************************* 65295b482a8SLen Brown * 65395b482a8SLen Brown * FUNCTION: acpi_tb_get_owner_id 65495b482a8SLen Brown * 65595b482a8SLen Brown * PARAMETERS: table_index - Table index 65695b482a8SLen Brown * owner_id - Where the table owner_id is returned 65795b482a8SLen Brown * 65895b482a8SLen Brown * RETURN: Status 65995b482a8SLen Brown * 66095b482a8SLen Brown * DESCRIPTION: returns owner_id for the ACPI table 66195b482a8SLen Brown * 66295b482a8SLen Brown ******************************************************************************/ 66395b482a8SLen Brown 66495b482a8SLen Brown acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id * owner_id) 66595b482a8SLen Brown { 66695b482a8SLen Brown acpi_status status = AE_BAD_PARAMETER; 66795b482a8SLen Brown 66895b482a8SLen Brown ACPI_FUNCTION_TRACE(tb_get_owner_id); 66995b482a8SLen Brown 67095b482a8SLen Brown (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); 671b9ee2043SBob Moore if (table_index < acpi_gbl_root_table_list.current_table_count) { 67295b482a8SLen Brown *owner_id = 67395b482a8SLen Brown acpi_gbl_root_table_list.tables[table_index].owner_id; 67495b482a8SLen Brown status = AE_OK; 67595b482a8SLen Brown } 67695b482a8SLen Brown 67795b482a8SLen Brown (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); 67895b482a8SLen Brown return_ACPI_STATUS(status); 67995b482a8SLen Brown } 68095b482a8SLen Brown 68195b482a8SLen Brown /******************************************************************************* 68295b482a8SLen Brown * 68395b482a8SLen Brown * FUNCTION: acpi_tb_is_table_loaded 68495b482a8SLen Brown * 68595b482a8SLen Brown * PARAMETERS: table_index - Table index 68695b482a8SLen Brown * 68795b482a8SLen Brown * RETURN: Table Loaded Flag 68895b482a8SLen Brown * 68995b482a8SLen Brown ******************************************************************************/ 69095b482a8SLen Brown 69195b482a8SLen Brown u8 acpi_tb_is_table_loaded(u32 table_index) 69295b482a8SLen Brown { 69395b482a8SLen Brown u8 is_loaded = FALSE; 69495b482a8SLen Brown 69595b482a8SLen Brown (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); 696b9ee2043SBob Moore if (table_index < acpi_gbl_root_table_list.current_table_count) { 69795b482a8SLen Brown is_loaded = (u8) 698ec41f193SBob Moore (acpi_gbl_root_table_list.tables[table_index].flags & 699ec41f193SBob Moore ACPI_TABLE_IS_LOADED); 70095b482a8SLen Brown } 70195b482a8SLen Brown 70295b482a8SLen Brown (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); 70395b482a8SLen Brown return (is_loaded); 70495b482a8SLen Brown } 70595b482a8SLen Brown 70695b482a8SLen Brown /******************************************************************************* 70795b482a8SLen Brown * 70895b482a8SLen Brown * FUNCTION: acpi_tb_set_table_loaded_flag 70995b482a8SLen Brown * 71095b482a8SLen Brown * PARAMETERS: table_index - Table index 71195b482a8SLen Brown * is_loaded - TRUE if table is loaded, FALSE otherwise 71295b482a8SLen Brown * 71395b482a8SLen Brown * RETURN: None 71495b482a8SLen Brown * 71595b482a8SLen Brown * DESCRIPTION: Sets the table loaded flag to either TRUE or FALSE. 71695b482a8SLen Brown * 71795b482a8SLen Brown ******************************************************************************/ 71895b482a8SLen Brown 71995b482a8SLen Brown void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded) 72095b482a8SLen Brown { 72195b482a8SLen Brown 72295b482a8SLen Brown (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); 723b9ee2043SBob Moore if (table_index < acpi_gbl_root_table_list.current_table_count) { 72495b482a8SLen Brown if (is_loaded) { 72595b482a8SLen Brown acpi_gbl_root_table_list.tables[table_index].flags |= 72695b482a8SLen Brown ACPI_TABLE_IS_LOADED; 72795b482a8SLen Brown } else { 72895b482a8SLen Brown acpi_gbl_root_table_list.tables[table_index].flags &= 72995b482a8SLen Brown ~ACPI_TABLE_IS_LOADED; 73095b482a8SLen Brown } 73195b482a8SLen Brown } 73295b482a8SLen Brown 73395b482a8SLen Brown (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); 73495b482a8SLen Brown } 735