tbxface.c 15.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2
/******************************************************************************
 *
3
 * Module Name: tbxface - ACPI table-oriented external interfaces
L
Linus Torvalds 已提交
4 5 6 7
 *
 *****************************************************************************/

/*
8
 * Copyright (C) 2000 - 2013, Intel Corp.
L
Linus Torvalds 已提交
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer,
 *    without modification.
 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
 *    substantially similar to the "NO WARRANTY" disclaimer below
 *    ("Disclaimer") and any redistribution must be conditioned upon
 *    including a substantially similar Disclaimer requirement for further
 *    binary redistribution.
 * 3. Neither the names of the above-listed copyright holders nor the names
 *    of any contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * Alternatively, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") version 2 as published by the Free
 * Software Foundation.
 *
 * NO WARRANTY
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 */

44
#include <linux/export.h>
L
Linus Torvalds 已提交
45
#include <acpi/acpi.h>
L
Len Brown 已提交
46 47
#include "accommon.h"
#include "actables.h"
L
Linus Torvalds 已提交
48 49

#define _COMPONENT          ACPI_TABLES
L
Len Brown 已提交
50
ACPI_MODULE_NAME("tbxface")
L
Linus Torvalds 已提交
51

52 53 54 55 56 57 58 59 60
/*******************************************************************************
 *
 * FUNCTION:    acpi_allocate_root_table
 *
 * PARAMETERS:  initial_table_count - Size of initial_table_array, in number of
 *                                    struct acpi_table_desc structures
 *
 * RETURN:      Status
 *
61
 * DESCRIPTION: Allocate a root table array. Used by iASL compiler and
62 63 64 65 66 67
 *              acpi_initialize_tables.
 *
 ******************************************************************************/
acpi_status acpi_allocate_root_table(u32 initial_table_count)
{

68
	acpi_gbl_root_table_list.max_table_count = initial_table_count;
69 70 71 72 73
	acpi_gbl_root_table_list.flags = ACPI_ROOT_ALLOW_RESIZE;

	return (acpi_tb_resize_root_table_list());
}

L
Linus Torvalds 已提交
74 75
/*******************************************************************************
 *
76
 * FUNCTION:    acpi_initialize_tables
L
Linus Torvalds 已提交
77
 *
78 79 80 81 82
 * PARAMETERS:  initial_table_array - Pointer to an array of pre-allocated
 *                                    struct acpi_table_desc structures. If NULL, the
 *                                    array is dynamically allocated.
 *              initial_table_count - Size of initial_table_array, in number of
 *                                    struct acpi_table_desc structures
83
 *              allow_resize        - Flag to tell Table Manager if resize of
84 85
 *                                    pre-allocated array is allowed. Ignored
 *                                    if initial_table_array is NULL.
L
Linus Torvalds 已提交
86 87 88
 *
 * RETURN:      Status
 *
89 90 91 92 93 94 95 96
 * DESCRIPTION: Initialize the table manager, get the RSDP and RSDT/XSDT.
 *
 * NOTE:        Allows static allocation of the initial table array in order
 *              to avoid the use of dynamic memory in confined environments
 *              such as the kernel boot sequence where it may not be available.
 *
 *              If the host OS memory managers are initialized, use NULL for
 *              initial_table_array, and the table will be dynamically allocated.
L
Linus Torvalds 已提交
97 98
 *
 ******************************************************************************/
99

100
acpi_status __init
101
acpi_initialize_tables(struct acpi_table_desc * initial_table_array,
102
		       u32 initial_table_count, u8 allow_resize)
L
Linus Torvalds 已提交
103
{
104
	acpi_physical_address rsdp_address;
L
Len Brown 已提交
105
	acpi_status status;
L
Linus Torvalds 已提交
106

107
	ACPI_FUNCTION_TRACE(acpi_initialize_tables);
L
Linus Torvalds 已提交
108

109
	/*
110 111
	 * Setup the Root Table Array and allocate the table array
	 * if requested
112 113
	 */
	if (!initial_table_array) {
114
		status = acpi_allocate_root_table(initial_table_count);
115 116 117 118 119 120
		if (ACPI_FAILURE(status)) {
			return_ACPI_STATUS(status);
		}
	} else {
		/* Root Table Array has been statically allocated by the host */

B
Bob Moore 已提交
121
		ACPI_MEMSET(initial_table_array, 0,
122
			    (acpi_size) initial_table_count *
B
Bob Moore 已提交
123
			    sizeof(struct acpi_table_desc));
124

125
		acpi_gbl_root_table_list.tables = initial_table_array;
126
		acpi_gbl_root_table_list.max_table_count = initial_table_count;
127
		acpi_gbl_root_table_list.flags = ACPI_ROOT_ORIGIN_UNKNOWN;
128
		if (allow_resize) {
129 130
			acpi_gbl_root_table_list.flags |=
			    ACPI_ROOT_ALLOW_RESIZE;
131
		}
L
Linus Torvalds 已提交
132 133
	}

134
	/* Get the address of the RSDP */
L
Linus Torvalds 已提交
135

136 137
	rsdp_address = acpi_os_get_root_pointer();
	if (!rsdp_address) {
138 139
		return_ACPI_STATUS(AE_NOT_FOUND);
	}
L
Linus Torvalds 已提交
140

141 142 143 144 145
	/*
	 * Get the root table (RSDT or XSDT) and extract all entries to the local
	 * Root Table Array. This array contains the information of the RSDT/XSDT
	 * in a common, more useable format.
	 */
146
	status = acpi_tb_parse_root_table(rsdp_address);
147 148
	return_ACPI_STATUS(status);
}
L
Linus Torvalds 已提交
149

150 151 152 153 154 155 156 157 158 159 160
/*******************************************************************************
 *
 * FUNCTION:    acpi_reallocate_root_table
 *
 * PARAMETERS:  None
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Reallocate Root Table List into dynamic memory. Copies the
 *              root list from the previously provided scratch area. Should
 *              be called once dynamic memory allocation is available in the
161
 *              kernel.
162 163 164 165
 *
 ******************************************************************************/
acpi_status acpi_reallocate_root_table(void)
{
166
	acpi_status status;
167 168 169 170 171 172 173

	ACPI_FUNCTION_TRACE(acpi_reallocate_root_table);

	/*
	 * Only reallocate the root table if the host provided a static buffer
	 * for the table array in the call to acpi_initialize_tables.
	 */
174
	if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
175
		return_ACPI_STATUS(AE_SUPPORT);
L
Linus Torvalds 已提交
176 177
	}

178
	acpi_gbl_root_table_list.flags |= ACPI_ROOT_ALLOW_RESIZE;
L
Linus Torvalds 已提交
179

180 181
	status = acpi_tb_resize_root_table_list();
	return_ACPI_STATUS(status);
182
}
L
Len Brown 已提交
183

184
/*******************************************************************************
185 186 187
 *
 * FUNCTION:    acpi_get_table_header
 *
188 189
 * PARAMETERS:  signature           - ACPI signature of needed table
 *              instance            - Which instance (for SSDTs)
190
 *              out_table_header    - The pointer to the table header to fill
191 192 193 194 195 196 197 198
 *
 * RETURN:      Status and pointer to mapped table header
 *
 * DESCRIPTION: Finds an ACPI table header.
 *
 * NOTE:        Caller is responsible in unmapping the header with
 *              acpi_os_unmap_memory
 *
199
 ******************************************************************************/
200 201
acpi_status
acpi_get_table_header(char *signature,
202
		      u32 instance, struct acpi_table_header *out_table_header)
203
{
204 205
       u32 i;
       u32 j;
206
	struct acpi_table_header *header;
207

208 209 210 211 212 213
	/* Parameter validation */

	if (!signature || !out_table_header) {
		return (AE_BAD_PARAMETER);
	}

214 215
	/* Walk the root table list */

216 217
	for (i = 0, j = 0; i < acpi_gbl_root_table_list.current_table_count;
	     i++) {
218 219 220 221
		if (!ACPI_COMPARE_NAME
		    (&(acpi_gbl_root_table_list.tables[i].signature),
		     signature)) {
			continue;
222 223
		}

224 225 226
		if (++j < instance) {
			continue;
		}
L
Linus Torvalds 已提交
227

228
		if (!acpi_gbl_root_table_list.tables[i].pointer) {
229 230
			if ((acpi_gbl_root_table_list.tables[i].flags &
			     ACPI_TABLE_ORIGIN_MASK) ==
231 232 233 234 235 236 237
			    ACPI_TABLE_ORIGIN_MAPPED) {
				header =
				    acpi_os_map_memory(acpi_gbl_root_table_list.
						       tables[i].address,
						       sizeof(struct
							      acpi_table_header));
				if (!header) {
238
					return (AE_NO_MEMORY);
239 240 241 242 243 244 245
				}
				ACPI_MEMCPY(out_table_header, header,
					    sizeof(struct acpi_table_header));
				acpi_os_unmap_memory(header,
						     sizeof(struct
							    acpi_table_header));
			} else {
246
				return (AE_NOT_FOUND);
247 248 249 250 251
			}
		} else {
			ACPI_MEMCPY(out_table_header,
				    acpi_gbl_root_table_list.tables[i].pointer,
				    sizeof(struct acpi_table_header));
252 253
		}
		return (AE_OK);
L
Linus Torvalds 已提交
254 255
	}

256
	return (AE_NOT_FOUND);
L
Linus Torvalds 已提交
257 258
}

259
ACPI_EXPORT_SYMBOL(acpi_get_table_header)
B
Bob Moore 已提交
260

261
/*******************************************************************************
262 263 264
 *
 * FUNCTION:    acpi_unload_table_id
 *
265
 * PARAMETERS:  id            - Owner ID of the table to be removed.
266 267 268 269 270 271
 *
 * RETURN:      Status
 *
 * DESCRIPTION: This routine is used to force the unload of a table (by id)
 *
 ******************************************************************************/
272
acpi_status acpi_unload_table_id(acpi_owner_id id)
273
{
274 275
	int i;
	acpi_status status = AE_NOT_EXIST;
276

277
	ACPI_FUNCTION_TRACE(acpi_unload_table_id);
278

279
	/* Find table in the global table list */
280
	for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) {
281 282 283 284
		if (id != acpi_gbl_root_table_list.tables[i].owner_id) {
			continue;
		}
		/*
L
Len Brown 已提交
285 286 287 288 289
		 * Delete all namespace objects owned by this table. Note that these
		 * objects can appear anywhere in the namespace by virtue of the AML
		 * "Scope" operator. Thus, we need to track ownership by an ID, not
		 * simply a position within the hierarchy
		 */
290
		acpi_tb_delete_namespace_by_owner(i);
291
		status = acpi_tb_release_owner_id(i);
292
		acpi_tb_set_table_loaded_flag(i, FALSE);
293
		break;
294 295
	}
	return_ACPI_STATUS(status);
296 297 298 299
}

ACPI_EXPORT_SYMBOL(acpi_unload_table_id)

L
Linus Torvalds 已提交
300 301
/*******************************************************************************
 *
302
 * FUNCTION:    acpi_get_table_with_size
L
Linus Torvalds 已提交
303
 *
304 305
 * PARAMETERS:  signature           - ACPI signature of needed table
 *              instance            - Which instance (for SSDTs)
306
 *              out_table           - Where the pointer to the table is returned
L
Linus Torvalds 已提交
307
 *
308
 * RETURN:      Status and pointer to the requested table
L
Linus Torvalds 已提交
309
 *
310 311
 * DESCRIPTION: Finds and verifies an ACPI table. Table must be in the
 *              RSDT/XSDT.
L
Linus Torvalds 已提交
312
 *
313
 ******************************************************************************/
314
acpi_status
315 316 317
acpi_get_table_with_size(char *signature,
	       u32 instance, struct acpi_table_header **out_table,
	       acpi_size *tbl_size)
L
Linus Torvalds 已提交
318
{
319 320
       u32 i;
       u32 j;
321
	acpi_status status;
L
Linus Torvalds 已提交
322

323 324 325 326 327 328
	/* Parameter validation */

	if (!signature || !out_table) {
		return (AE_BAD_PARAMETER);
	}

329 330
	/* Walk the root table list */

331 332
	for (i = 0, j = 0; i < acpi_gbl_root_table_list.current_table_count;
	     i++) {
333 334 335 336 337
		if (!ACPI_COMPARE_NAME
		    (&(acpi_gbl_root_table_list.tables[i].signature),
		     signature)) {
			continue;
		}
L
Linus Torvalds 已提交
338

339 340 341
		if (++j < instance) {
			continue;
		}
L
Linus Torvalds 已提交
342

343 344 345 346
		status =
		    acpi_tb_verify_table(&acpi_gbl_root_table_list.tables[i]);
		if (ACPI_SUCCESS(status)) {
			*out_table = acpi_gbl_root_table_list.tables[i].pointer;
347
			*tbl_size = acpi_gbl_root_table_list.tables[i].length;
348
		}
B
Bob Moore 已提交
349

350
		if (!acpi_gbl_permanent_mmap) {
R
Randy Dunlap 已提交
351
			acpi_gbl_root_table_list.tables[i].pointer = NULL;
352 353
		}

354
		return (status);
L
Linus Torvalds 已提交
355 356
	}

357
	return (AE_NOT_FOUND);
L
Linus Torvalds 已提交
358
}
359
ACPI_EXPORT_SYMBOL(acpi_get_table_with_size)
L
Linus Torvalds 已提交
360

361 362 363 364 365 366 367 368 369
acpi_status
acpi_get_table(char *signature,
	       u32 instance, struct acpi_table_header **out_table)
{
	acpi_size tbl_size;

	return acpi_get_table_with_size(signature,
		       instance, out_table, &tbl_size);
}
370
ACPI_EXPORT_SYMBOL(acpi_get_table)
B
Bob Moore 已提交
371

L
Linus Torvalds 已提交
372 373
/*******************************************************************************
 *
374
 * FUNCTION:    acpi_get_table_by_index
L
Linus Torvalds 已提交
375
 *
376
 * PARAMETERS:  table_index         - Table index
377
 *              table               - Where the pointer to the table is returned
L
Linus Torvalds 已提交
378
 *
379
 * RETURN:      Status and pointer to the requested table
L
Linus Torvalds 已提交
380
 *
381 382
 * DESCRIPTION: Obtain a table by an index into the global table list. Used
 *              internally also.
L
Linus Torvalds 已提交
383 384 385
 *
 ******************************************************************************/
acpi_status
386
acpi_get_table_by_index(u32 table_index, struct acpi_table_header **table)
L
Linus Torvalds 已提交
387
{
L
Len Brown 已提交
388
	acpi_status status;
L
Linus Torvalds 已提交
389

390
	ACPI_FUNCTION_TRACE(acpi_get_table_by_index);
L
Linus Torvalds 已提交
391

392 393 394 395 396 397
	/* Parameter validation */

	if (!table) {
		return_ACPI_STATUS(AE_BAD_PARAMETER);
	}

398
	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
L
Linus Torvalds 已提交
399

400
	/* Validate index */
L
Linus Torvalds 已提交
401

402
	if (table_index >= acpi_gbl_root_table_list.current_table_count) {
403
		(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
L
Len Brown 已提交
404
		return_ACPI_STATUS(AE_BAD_PARAMETER);
L
Linus Torvalds 已提交
405 406
	}

407
	if (!acpi_gbl_root_table_list.tables[table_index].pointer) {
L
Linus Torvalds 已提交
408

409
		/* Table is not mapped, map it */
L
Linus Torvalds 已提交
410

411 412 413 414 415 416 417
		status =
		    acpi_tb_verify_table(&acpi_gbl_root_table_list.
					 tables[table_index]);
		if (ACPI_FAILURE(status)) {
			(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
			return_ACPI_STATUS(status);
		}
L
Linus Torvalds 已提交
418 419
	}

420 421 422
	*table = acpi_gbl_root_table_list.tables[table_index].pointer;
	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
423 424
}

425
ACPI_EXPORT_SYMBOL(acpi_get_table_by_index)
L
Linus Torvalds 已提交
426

427

428 429 430 431
/*******************************************************************************
 *
 * FUNCTION:    acpi_install_table_handler
 *
432 433
 * PARAMETERS:  handler         - Table event handler
 *              context         - Value passed to the handler on each event
434 435 436
 *
 * RETURN:      Status
 *
437
 * DESCRIPTION: Install a global table event handler.
438 439 440
 *
 ******************************************************************************/
acpi_status
441
acpi_install_table_handler(acpi_table_handler handler, void *context)
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
{
	acpi_status status;

	ACPI_FUNCTION_TRACE(acpi_install_table_handler);

	if (!handler) {
		return_ACPI_STATUS(AE_BAD_PARAMETER);
	}

	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
	}

	/* Don't allow more than one handler */

	if (acpi_gbl_table_handler) {
		status = AE_ALREADY_EXISTS;
		goto cleanup;
	}

	/* Install the handler */

	acpi_gbl_table_handler = handler;
	acpi_gbl_table_handler_context = context;

      cleanup:
	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
	return_ACPI_STATUS(status);
}

ACPI_EXPORT_SYMBOL(acpi_install_table_handler)

/*******************************************************************************
 *
 * FUNCTION:    acpi_remove_table_handler
 *
479
 * PARAMETERS:  handler         - Table event handler that was installed
480 481 482 483
 *                                previously.
 *
 * RETURN:      Status
 *
484
 * DESCRIPTION: Remove a table event handler
485 486
 *
 ******************************************************************************/
487
acpi_status acpi_remove_table_handler(acpi_table_handler handler)
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
{
	acpi_status status;

	ACPI_FUNCTION_TRACE(acpi_remove_table_handler);

	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
	}

	/* Make sure that the installed handler is the same */

	if (!handler || handler != acpi_gbl_table_handler) {
		status = AE_BAD_PARAMETER;
		goto cleanup;
	}

	/* Remove the handler */

	acpi_gbl_table_handler = NULL;

      cleanup:
	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
	return_ACPI_STATUS(status);
}

ACPI_EXPORT_SYMBOL(acpi_remove_table_handler)