tbxface.c 15.0 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 - 2012, 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 83 84 85
 * 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
 *              allow_realloc       - Flag to tell Table Manager if resize of
 *                                    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 112 113
	/*
	 * Set up the Root Table Array
	 * Allocate the table array if requested
	 */
	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 table
L
Linus Torvalds 已提交
309
 *
310
 * DESCRIPTION: Finds and verifies an ACPI table.
L
Linus Torvalds 已提交
311
 *
312
 ******************************************************************************/
313
acpi_status
314 315 316
acpi_get_table_with_size(char *signature,
	       u32 instance, struct acpi_table_header **out_table,
	       acpi_size *tbl_size)
L
Linus Torvalds 已提交
317
{
318 319
       u32 i;
       u32 j;
320
	acpi_status status;
L
Linus Torvalds 已提交
321

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

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

328 329
	/* Walk the root table list */

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

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

342 343 344 345
		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;
346
			*tbl_size = acpi_gbl_root_table_list.tables[i].length;
347
		}
B
Bob Moore 已提交
348

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

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

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

360 361 362 363 364 365 366 367 368
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);
}
369
ACPI_EXPORT_SYMBOL(acpi_get_table)
B
Bob Moore 已提交
370

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

388
	ACPI_FUNCTION_TRACE(acpi_get_table_by_index);
L
Linus Torvalds 已提交
389

390 391 392 393 394 395
	/* Parameter validation */

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

396
	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
L
Linus Torvalds 已提交
397

398
	/* Validate index */
L
Linus Torvalds 已提交
399

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

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

407
		/* Table is not mapped, map it */
L
Linus Torvalds 已提交
408

409 410 411 412 413 414 415
		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 已提交
416 417
	}

418 419 420
	*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 已提交
421 422
}

423
ACPI_EXPORT_SYMBOL(acpi_get_table_by_index)
L
Linus Torvalds 已提交
424

425

426 427 428 429
/*******************************************************************************
 *
 * FUNCTION:    acpi_install_table_handler
 *
430 431
 * PARAMETERS:  handler         - Table event handler
 *              context         - Value passed to the handler on each event
432 433 434 435 436 437 438 439 440 441 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
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Install table event handler
 *
 ******************************************************************************/
acpi_status
acpi_install_table_handler(acpi_tbl_handler handler, void *context)
{
	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
 *
477
 * PARAMETERS:  handler         - Table event handler that was installed
478 479 480 481 482 483 484 485 486 487 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
 *                                previously.
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Remove table event handler
 *
 ******************************************************************************/
acpi_status acpi_remove_table_handler(acpi_tbl_handler handler)
{
	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)