evregion.c 29.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7
/******************************************************************************
 *
 * Module Name: evregion - ACPI address_space (op_region) handler dispatch
 *
 *****************************************************************************/

/*
L
Len Brown 已提交
8
 * Copyright (C) 2000 - 2008, 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 44
 * 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.
 */

#include <acpi/acpi.h>
45
#include <acpi/accommon.h>
L
Linus Torvalds 已提交
46 47 48 49 50
#include <acpi/acevents.h>
#include <acpi/acnamesp.h>
#include <acpi/acinterp.h>

#define _COMPONENT          ACPI_EVENTS
L
Len Brown 已提交
51
ACPI_MODULE_NAME("evregion")
L
Linus Torvalds 已提交
52

R
Robert Moore 已提交
53 54
/* Local prototypes */
static acpi_status
L
Len Brown 已提交
55 56
acpi_ev_reg_run(acpi_handle obj_handle,
		u32 level, void *context, void **return_value);
R
Robert Moore 已提交
57 58

static acpi_status
L
Len Brown 已提交
59 60
acpi_ev_install_handler(acpi_handle obj_handle,
			u32 level, void *context, void **return_value);
L
Linus Torvalds 已提交
61

62 63 64 65 66 67 68 69 70 71 72
/* These are the address spaces that will get default handlers */

#define ACPI_NUM_DEFAULT_SPACES     4

static u8 acpi_gbl_default_address_spaces[ACPI_NUM_DEFAULT_SPACES] = {
	ACPI_ADR_SPACE_SYSTEM_MEMORY,
	ACPI_ADR_SPACE_SYSTEM_IO,
	ACPI_ADR_SPACE_PCI_CONFIG,
	ACPI_ADR_SPACE_DATA_TABLE
};

L
Linus Torvalds 已提交
73 74 75 76 77 78 79 80 81 82 83 84
/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_install_region_handlers
 *
 * PARAMETERS:  None
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Installs the core subsystem default address space handlers.
 *
 ******************************************************************************/

L
Len Brown 已提交
85 86 87
acpi_status acpi_ev_install_region_handlers(void)
{
	acpi_status status;
88
	u32 i;
L
Linus Torvalds 已提交
89

B
Bob Moore 已提交
90
	ACPI_FUNCTION_TRACE(ev_install_region_handlers);
L
Linus Torvalds 已提交
91

L
Len Brown 已提交
92 93 94
	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
95 96 97
	}

	/*
98 99
	 * All address spaces (PCI Config, EC, SMBus) are scope dependent and
	 * registration must occur for a specific device.
L
Linus Torvalds 已提交
100
	 *
101 102 103
	 * In the case of the system memory and IO address spaces there is
	 * currently no device associated with the address space. For these we
	 * use the root.
L
Linus Torvalds 已提交
104
	 *
105 106 107 108 109 110
	 * We install the default PCI config space handler at the root so that
	 * this space is immediately available even though the we have not
	 * enumerated all the PCI Root Buses yet. This is to conform to the ACPI
	 * specification which states that the PCI config space must be always
	 * available -- even though we are nowhere near ready to find the PCI root
	 * buses at this point.
L
Linus Torvalds 已提交
111 112 113 114 115 116
	 *
	 * NOTE: We ignore AE_ALREADY_EXISTS because this means that a handler
	 * has already been installed (via acpi_install_address_space_handler).
	 * Similar for AE_SAME_HANDLER.
	 */
	for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) {
L
Len Brown 已提交
117 118 119 120 121
		status = acpi_ev_install_space_handler(acpi_gbl_root_node,
						       acpi_gbl_default_address_spaces
						       [i],
						       ACPI_DEFAULT_HANDLER,
						       NULL, NULL);
L
Linus Torvalds 已提交
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
		switch (status) {
		case AE_OK:
		case AE_SAME_HANDLER:
		case AE_ALREADY_EXISTS:

			/* These exceptions are all OK */

			status = AE_OK;
			break;

		default:

			goto unlock_and_exit;
		}
	}

L
Len Brown 已提交
138 139 140
      unlock_and_exit:
	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_initialize_op_regions
 *
 * PARAMETERS:  None
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Execute _REG methods for all Operation Regions that have
 *              an installed default region handler.
 *
 ******************************************************************************/

L
Len Brown 已提交
156
acpi_status acpi_ev_initialize_op_regions(void)
L
Linus Torvalds 已提交
157
{
L
Len Brown 已提交
158
	acpi_status status;
159
	u32 i;
L
Linus Torvalds 已提交
160

B
Bob Moore 已提交
161
	ACPI_FUNCTION_TRACE(ev_initialize_op_regions);
L
Linus Torvalds 已提交
162

L
Len Brown 已提交
163 164 165
	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
166 167
	}

168
	/* Run the _REG methods for op_regions in each default address space */
B
Bob Moore 已提交
169

170 171 172
	for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) {
		/*
		 * TBD: Make sure handler is the DEFAULT handler, otherwise
L
Linus Torvalds 已提交
173 174
		 * _REG will have already been run.
		 */
L
Len Brown 已提交
175 176 177
		status = acpi_ev_execute_reg_methods(acpi_gbl_root_node,
						     acpi_gbl_default_address_spaces
						     [i]);
L
Linus Torvalds 已提交
178 179
	}

L
Len Brown 已提交
180 181
	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
182 183 184 185 186 187
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_execute_reg_method
 *
R
Robert Moore 已提交
188 189
 * PARAMETERS:  region_obj          - Region object
 *              Function            - Passed to _REG: On (1) or Off (0)
L
Linus Torvalds 已提交
190 191 192 193 194 195 196 197
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Execute _REG method for a region
 *
 ******************************************************************************/

acpi_status
L
Len Brown 已提交
198
acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
L
Linus Torvalds 已提交
199
{
B
Bob Moore 已提交
200 201
	struct acpi_evaluate_info *info;
	union acpi_operand_object *args[3];
L
Len Brown 已提交
202 203
	union acpi_operand_object *region_obj2;
	acpi_status status;
L
Linus Torvalds 已提交
204

B
Bob Moore 已提交
205
	ACPI_FUNCTION_TRACE(ev_execute_reg_method);
L
Linus Torvalds 已提交
206

L
Len Brown 已提交
207
	region_obj2 = acpi_ns_get_secondary_object(region_obj);
L
Linus Torvalds 已提交
208
	if (!region_obj2) {
L
Len Brown 已提交
209
		return_ACPI_STATUS(AE_NOT_EXIST);
L
Linus Torvalds 已提交
210 211 212
	}

	if (region_obj2->extra.method_REG == NULL) {
L
Len Brown 已提交
213
		return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
214 215
	}

B
Bob Moore 已提交
216 217 218 219 220 221 222 223 224 225 226 227
	/* Allocate and initialize the evaluation information block */

	info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
	if (!info) {
		return_ACPI_STATUS(AE_NO_MEMORY);
	}

	info->prefix_node = region_obj2->extra.method_REG;
	info->pathname = NULL;
	info->parameters = args;
	info->flags = ACPI_IGNORE_RETURN_VALUE;

L
Linus Torvalds 已提交
228 229 230
	/*
	 * The _REG method has two arguments:
	 *
B
Bob Moore 已提交
231 232 233 234 235 236
	 * Arg0 - Integer:
	 *  Operation region space ID Same value as region_obj->Region.space_id
	 *
	 * Arg1 - Integer:
	 *  connection status 1 for connecting the handler, 0 for disconnecting
	 *  the handler (Passed as a parameter)
L
Linus Torvalds 已提交
237
	 */
B
Bob Moore 已提交
238 239 240 241
	args[0] = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
	if (!args[0]) {
		status = AE_NO_MEMORY;
		goto cleanup1;
L
Linus Torvalds 已提交
242 243
	}

B
Bob Moore 已提交
244 245
	args[1] = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
	if (!args[1]) {
L
Linus Torvalds 已提交
246
		status = AE_NO_MEMORY;
B
Bob Moore 已提交
247
		goto cleanup2;
L
Linus Torvalds 已提交
248 249 250 251
	}

	/* Setup the parameter objects */

B
Bob Moore 已提交
252 253 254
	args[0]->integer.value = region_obj->region.space_id;
	args[1]->integer.value = function;
	args[2] = NULL;
L
Linus Torvalds 已提交
255 256 257

	/* Execute the method, no return value */

L
Len Brown 已提交
258
	ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
B
Bob Moore 已提交
259 260 261 262
			(ACPI_TYPE_METHOD, info->prefix_node, NULL));

	status = acpi_ns_evaluate(info);
	acpi_ut_remove_reference(args[1]);
L
Linus Torvalds 已提交
263

B
Bob Moore 已提交
264 265
      cleanup2:
	acpi_ut_remove_reference(args[0]);
L
Linus Torvalds 已提交
266

B
Bob Moore 已提交
267 268
      cleanup1:
	ACPI_FREE(info);
L
Len Brown 已提交
269
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
270 271 272 273 274 275 276 277 278 279
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_address_space_dispatch
 *
 * PARAMETERS:  region_obj          - Internal region object
 *              Function            - Read or Write operation
 *              Address             - Where in the space to read or write
 *              bit_width           - Field width in bits (8, 16, 32, or 64)
B
Bob Moore 已提交
280 281
 *              Value               - Pointer to in or out value, must be
 *                                    full 64-bit acpi_integer
L
Linus Torvalds 已提交
282 283 284 285 286 287 288 289 290
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Dispatch an address space or operation region access to
 *              a previously installed handler.
 *
 ******************************************************************************/

acpi_status
L
Len Brown 已提交
291 292 293
acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
			       u32 function,
			       acpi_physical_address address,
B
Bob Moore 已提交
294
			       u32 bit_width, acpi_integer * value)
L
Linus Torvalds 已提交
295
{
L
Len Brown 已提交
296 297 298 299 300 301
	acpi_status status;
	acpi_adr_space_handler handler;
	acpi_adr_space_setup region_setup;
	union acpi_operand_object *handler_desc;
	union acpi_operand_object *region_obj2;
	void *region_context = NULL;
L
Linus Torvalds 已提交
302

B
Bob Moore 已提交
303
	ACPI_FUNCTION_TRACE(ev_address_space_dispatch);
L
Linus Torvalds 已提交
304

L
Len Brown 已提交
305
	region_obj2 = acpi_ns_get_secondary_object(region_obj);
L
Linus Torvalds 已提交
306
	if (!region_obj2) {
L
Len Brown 已提交
307
		return_ACPI_STATUS(AE_NOT_EXIST);
L
Linus Torvalds 已提交
308 309 310 311 312 313
	}

	/* Ensure that there is a handler associated with this region */

	handler_desc = region_obj->region.handler;
	if (!handler_desc) {
B
Bob Moore 已提交
314 315 316 317 318 319
		ACPI_ERROR((AE_INFO,
			    "No handler for Region [%4.4s] (%p) [%s]",
			    acpi_ut_get_node_name(region_obj->region.node),
			    region_obj,
			    acpi_ut_get_region_name(region_obj->region.
						    space_id)));
L
Len Brown 已提交
320 321

		return_ACPI_STATUS(AE_NOT_EXIST);
L
Linus Torvalds 已提交
322 323 324
	}

	/*
325
	 * It may be the case that the region has never been initialized.
L
Linus Torvalds 已提交
326 327 328
	 * Some types of regions require special init code
	 */
	if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) {
329 330 331

		/* This region has not been initialized yet, do it */

L
Linus Torvalds 已提交
332 333
		region_setup = handler_desc->address_space.setup;
		if (!region_setup) {
B
Bob Moore 已提交
334

L
Linus Torvalds 已提交
335 336
			/* No initialization routine, exit with error */

B
Bob Moore 已提交
337 338 339 340 341
			ACPI_ERROR((AE_INFO,
				    "No init routine for region(%p) [%s]",
				    region_obj,
				    acpi_ut_get_region_name(region_obj->region.
							    space_id)));
L
Len Brown 已提交
342
			return_ACPI_STATUS(AE_NOT_EXIST);
L
Linus Torvalds 已提交
343 344 345
		}

		/*
346 347 348
		 * We must exit the interpreter because the region setup will
		 * potentially execute control methods (for example, the _REG method
		 * for this region)
L
Linus Torvalds 已提交
349
		 */
350
		acpi_ex_exit_interpreter();
L
Linus Torvalds 已提交
351

L
Len Brown 已提交
352 353 354
		status = region_setup(region_obj, ACPI_REGION_ACTIVATE,
				      handler_desc->address_space.context,
				      &region_context);
L
Linus Torvalds 已提交
355 356 357

		/* Re-enter the interpreter */

358
		acpi_ex_enter_interpreter();
L
Linus Torvalds 已提交
359 360 361

		/* Check for failure of the Region Setup */

L
Len Brown 已提交
362
		if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
363 364 365 366 367
			ACPI_EXCEPTION((AE_INFO, status,
					"During region initialization: [%s]",
					acpi_ut_get_region_name(region_obj->
								region.
								space_id)));
L
Len Brown 已提交
368
			return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
369 370
		}

371 372
		/* Region initialization may have been completed by region_setup */

L
Linus Torvalds 已提交
373 374 375 376
		if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) {
			region_obj->region.flags |= AOPOBJ_SETUP_COMPLETE;

			if (region_obj2->extra.region_context) {
B
Bob Moore 已提交
377

L
Linus Torvalds 已提交
378 379
				/* The handler for this region was already installed */

B
Bob Moore 已提交
380
				ACPI_FREE(region_context);
L
Len Brown 已提交
381
			} else {
L
Linus Torvalds 已提交
382 383 384 385
				/*
				 * Save the returned context for use in all accesses to
				 * this particular region
				 */
L
Len Brown 已提交
386 387
				region_obj2->extra.region_context =
				    region_context;
L
Linus Torvalds 已提交
388 389 390 391 392 393 394 395
			}
		}
	}

	/* We have everything we need, we can invoke the address space handler */

	handler = handler_desc->address_space.handler;

L
Len Brown 已提交
396 397 398
	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
			  "Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
			  &region_obj->region.handler->address_space, handler,
399
			  ACPI_FORMAT_NATIVE_UINT(address),
L
Len Brown 已提交
400 401
			  acpi_ut_get_region_name(region_obj->region.
						  space_id)));
L
Linus Torvalds 已提交
402

B
Bob Moore 已提交
403 404
	if (!(handler_desc->address_space.handler_flags &
	      ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
L
Linus Torvalds 已提交
405 406 407 408 409
		/*
		 * For handlers other than the default (supplied) handlers, we must
		 * exit the interpreter because the handler *might* block -- we don't
		 * know what it will do, so we can't hold the lock on the intepreter.
		 */
410
		acpi_ex_exit_interpreter();
L
Linus Torvalds 已提交
411 412 413 414
	}

	/* Call the handler */

L
Len Brown 已提交
415
	status = handler(function, address, bit_width, value,
L
Linus Torvalds 已提交
416 417 418
			 handler_desc->address_space.context,
			 region_obj2->extra.region_context);

L
Len Brown 已提交
419
	if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
420 421 422
		ACPI_EXCEPTION((AE_INFO, status, "Returned by Handler for [%s]",
				acpi_ut_get_region_name(region_obj->region.
							space_id)));
L
Linus Torvalds 已提交
423 424
	}

B
Bob Moore 已提交
425 426
	if (!(handler_desc->address_space.handler_flags &
	      ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
L
Linus Torvalds 已提交
427 428 429 430
		/*
		 * We just returned from a non-default handler, we must re-enter the
		 * interpreter
		 */
431
		acpi_ex_enter_interpreter();
L
Linus Torvalds 已提交
432 433
	}

L
Len Brown 已提交
434
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_detach_region
 *
 * PARAMETERS:  region_obj          - Region Object
 *              acpi_ns_is_locked   - Namespace Region Already Locked?
 *
 * RETURN:      None
 *
 * DESCRIPTION: Break the association between the handler and the region
 *              this is a two way association.
 *
 ******************************************************************************/

void
L
Len Brown 已提交
452 453
acpi_ev_detach_region(union acpi_operand_object *region_obj,
		      u8 acpi_ns_is_locked)
L
Linus Torvalds 已提交
454
{
L
Len Brown 已提交
455 456 457 458 459 460 461
	union acpi_operand_object *handler_obj;
	union acpi_operand_object *obj_desc;
	union acpi_operand_object **last_obj_ptr;
	acpi_adr_space_setup region_setup;
	void **region_context;
	union acpi_operand_object *region_obj2;
	acpi_status status;
L
Linus Torvalds 已提交
462

B
Bob Moore 已提交
463
	ACPI_FUNCTION_TRACE(ev_detach_region);
L
Linus Torvalds 已提交
464

L
Len Brown 已提交
465
	region_obj2 = acpi_ns_get_secondary_object(region_obj);
L
Linus Torvalds 已提交
466 467 468 469 470 471 472 473 474
	if (!region_obj2) {
		return_VOID;
	}
	region_context = &region_obj2->extra.region_context;

	/* Get the address handler from the region object */

	handler_obj = region_obj->region.handler;
	if (!handler_obj) {
B
Bob Moore 已提交
475

L
Linus Torvalds 已提交
476 477 478 479 480 481 482 483 484 485 486
		/* This region has no handler, all done */

		return_VOID;
	}

	/* Find this region in the handler's list */

	obj_desc = handler_obj->address_space.region_list;
	last_obj_ptr = &handler_obj->address_space.region_list;

	while (obj_desc) {
B
Bob Moore 已提交
487

L
Linus Torvalds 已提交
488 489 490
		/* Is this the correct Region? */

		if (obj_desc == region_obj) {
L
Len Brown 已提交
491 492 493
			ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
					  "Removing Region %p from address handler %p\n",
					  region_obj, handler_obj));
L
Linus Torvalds 已提交
494 495 496 497

			/* This is it, remove it from the handler's list */

			*last_obj_ptr = obj_desc->region.next;
L
Len Brown 已提交
498
			obj_desc->region.next = NULL;	/* Must clear field */
L
Linus Torvalds 已提交
499 500

			if (acpi_ns_is_locked) {
L
Len Brown 已提交
501 502 503
				status =
				    acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
				if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
504 505 506 507 508 509
					return_VOID;
				}
			}

			/* Now stop region accesses by executing the _REG method */

L
Len Brown 已提交
510 511
			status = acpi_ev_execute_reg_method(region_obj, 0);
			if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
512 513 514 515
				ACPI_EXCEPTION((AE_INFO, status,
						"from region _REG, [%s]",
						acpi_ut_get_region_name
						(region_obj->region.space_id)));
L
Linus Torvalds 已提交
516 517 518
			}

			if (acpi_ns_is_locked) {
L
Len Brown 已提交
519 520 521
				status =
				    acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
				if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
522 523 524 525
					return_VOID;
				}
			}

B
Bob Moore 已提交
526
			/*
527 528
			 * If the region has been activated, call the setup handler with
			 * the deactivate notification
B
Bob Moore 已提交
529 530 531 532 533 534 535 536
			 */
			if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) {
				region_setup = handler_obj->address_space.setup;
				status =
				    region_setup(region_obj,
						 ACPI_REGION_DEACTIVATE,
						 handler_obj->address_space.
						 context, region_context);
L
Linus Torvalds 已提交
537

B
Bob Moore 已提交
538
				/* Init routine may fail, Just ignore errors */
L
Linus Torvalds 已提交
539

B
Bob Moore 已提交
540 541 542 543 544 545 546
				if (ACPI_FAILURE(status)) {
					ACPI_EXCEPTION((AE_INFO, status,
							"from region handler - deactivate, [%s]",
							acpi_ut_get_region_name
							(region_obj->region.
							 space_id)));
				}
L
Linus Torvalds 已提交
547

B
Bob Moore 已提交
548 549
				region_obj->region.flags &=
				    ~(AOPOBJ_SETUP_COMPLETE);
L
Linus Torvalds 已提交
550 551 552 553 554
			}

			/*
			 * Remove handler reference in the region
			 *
B
Bob Moore 已提交
555 556
			 * NOTE: this doesn't mean that the region goes away, the region
			 * is just inaccessible as indicated to the _REG method
L
Linus Torvalds 已提交
557
			 *
B
Bob Moore 已提交
558 559
			 * If the region is on the handler's list, this must be the
			 * region's handler
L
Linus Torvalds 已提交
560 561
			 */
			region_obj->region.handler = NULL;
L
Len Brown 已提交
562
			acpi_ut_remove_reference(handler_obj);
L
Linus Torvalds 已提交
563 564 565 566 567 568 569 570 571 572 573 574

			return_VOID;
		}

		/* Walk the linked list of handlers */

		last_obj_ptr = &obj_desc->region.next;
		obj_desc = obj_desc->region.next;
	}

	/* If we get here, the region was not in the handler's region list */

L
Len Brown 已提交
575 576 577
	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
			  "Cannot remove region %p from address handler %p\n",
			  region_obj, handler_obj));
L
Linus Torvalds 已提交
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597

	return_VOID;
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_attach_region
 *
 * PARAMETERS:  handler_obj         - Handler Object
 *              region_obj          - Region Object
 *              acpi_ns_is_locked   - Namespace Region Already Locked?
 *
 * RETURN:      None
 *
 * DESCRIPTION: Create the association between the handler and the region
 *              this is a two way association.
 *
 ******************************************************************************/

acpi_status
L
Len Brown 已提交
598 599 600
acpi_ev_attach_region(union acpi_operand_object *handler_obj,
		      union acpi_operand_object *region_obj,
		      u8 acpi_ns_is_locked)
L
Linus Torvalds 已提交
601 602
{

B
Bob Moore 已提交
603
	ACPI_FUNCTION_TRACE(ev_attach_region);
L
Linus Torvalds 已提交
604

L
Len Brown 已提交
605 606 607 608 609 610
	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
			  "Adding Region [%4.4s] %p to address handler %p [%s]\n",
			  acpi_ut_get_node_name(region_obj->region.node),
			  region_obj, handler_obj,
			  acpi_ut_get_region_name(region_obj->region.
						  space_id)));
L
Linus Torvalds 已提交
611 612 613 614 615 616 617 618 619

	/* Link this region to the front of the handler's list */

	region_obj->region.next = handler_obj->address_space.region_list;
	handler_obj->address_space.region_list = region_obj;

	/* Install the region's handler */

	if (region_obj->region.handler) {
L
Len Brown 已提交
620
		return_ACPI_STATUS(AE_ALREADY_EXISTS);
L
Linus Torvalds 已提交
621 622 623
	}

	region_obj->region.handler = handler_obj;
L
Len Brown 已提交
624
	acpi_ut_add_reference(handler_obj);
L
Linus Torvalds 已提交
625

L
Len Brown 已提交
626
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_install_handler
 *
 * PARAMETERS:  walk_namespace callback
 *
 * DESCRIPTION: This routine installs an address handler into objects that are
 *              of type Region or Device.
 *
 *              If the Object is a Device, and the device has a handler of
 *              the same type then the search is terminated in that branch.
 *
 *              This is because the existing handler is closer in proximity
 *              to any more regions than the one we are trying to install.
 *
 ******************************************************************************/

R
Robert Moore 已提交
646
static acpi_status
L
Len Brown 已提交
647 648
acpi_ev_install_handler(acpi_handle obj_handle,
			u32 level, void *context, void **return_value)
L
Linus Torvalds 已提交
649
{
L
Len Brown 已提交
650 651 652 653 654
	union acpi_operand_object *handler_obj;
	union acpi_operand_object *next_handler_obj;
	union acpi_operand_object *obj_desc;
	struct acpi_namespace_node *node;
	acpi_status status;
L
Linus Torvalds 已提交
655

B
Bob Moore 已提交
656
	ACPI_FUNCTION_NAME(ev_install_handler);
L
Linus Torvalds 已提交
657

L
Len Brown 已提交
658
	handler_obj = (union acpi_operand_object *)context;
L
Linus Torvalds 已提交
659 660 661 662 663 664 665 666 667

	/* Parameter validation */

	if (!handler_obj) {
		return (AE_OK);
	}

	/* Convert and validate the device handle */

L
Len Brown 已提交
668
	node = acpi_ns_map_handle_to_node(obj_handle);
L
Linus Torvalds 已提交
669 670 671 672 673
	if (!node) {
		return (AE_BAD_PARAMETER);
	}

	/*
674 675
	 * We only care about regions and objects that are allowed to have
	 * address space handlers
L
Linus Torvalds 已提交
676 677
	 */
	if ((node->type != ACPI_TYPE_DEVICE) &&
L
Len Brown 已提交
678
	    (node->type != ACPI_TYPE_REGION) && (node != acpi_gbl_root_node)) {
L
Linus Torvalds 已提交
679 680 681 682 683
		return (AE_OK);
	}

	/* Check for an existing internal object */

L
Len Brown 已提交
684
	obj_desc = acpi_ns_get_attached_object(node);
L
Linus Torvalds 已提交
685
	if (!obj_desc) {
B
Bob Moore 已提交
686

L
Linus Torvalds 已提交
687 688 689 690 691 692 693
		/* No object, just exit */

		return (AE_OK);
	}

	/* Devices are handled different than regions */

L
Len Brown 已提交
694
	if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_DEVICE) {
B
Bob Moore 已提交
695

L
Linus Torvalds 已提交
696 697 698 699
		/* Check if this Device already has a handler for this address space */

		next_handler_obj = obj_desc->device.handler;
		while (next_handler_obj) {
B
Bob Moore 已提交
700

L
Linus Torvalds 已提交
701 702
			/* Found a handler, is it for the same address space? */

L
Len Brown 已提交
703 704 705 706 707 708 709 710 711
			if (next_handler_obj->address_space.space_id ==
			    handler_obj->address_space.space_id) {
				ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
						  "Found handler for region [%s] in device %p(%p) handler %p\n",
						  acpi_ut_get_region_name
						  (handler_obj->address_space.
						   space_id), obj_desc,
						  next_handler_obj,
						  handler_obj));
L
Linus Torvalds 已提交
712 713 714 715

				/*
				 * Since the object we found it on was a device, then it
				 * means that someone has already installed a handler for
716
				 * the branch of the namespace from this device on. Just
L
Linus Torvalds 已提交
717
				 * bail out telling the walk routine to not traverse this
718
				 * branch. This preserves the scoping rule for handlers.
L
Linus Torvalds 已提交
719 720 721 722 723 724 725 726 727 728
				 */
				return (AE_CTRL_DEPTH);
			}

			/* Walk the linked list of handlers attached to this device */

			next_handler_obj = next_handler_obj->address_space.next;
		}

		/*
729 730
		 * As long as the device didn't have a handler for this space we
		 * don't care about it. We just ignore it and proceed.
L
Linus Torvalds 已提交
731 732 733 734 735 736 737
		 */
		return (AE_OK);
	}

	/* Object is a Region */

	if (obj_desc->region.space_id != handler_obj->address_space.space_id) {
738 739 740

		/* This region is for a different address space, just ignore it */

L
Linus Torvalds 已提交
741 742 743 744
		return (AE_OK);
	}

	/*
745
	 * Now we have a region and it is for the handler's address space type.
L
Linus Torvalds 已提交
746 747 748
	 *
	 * First disconnect region for any previous handler (if any)
	 */
L
Len Brown 已提交
749
	acpi_ev_detach_region(obj_desc, FALSE);
L
Linus Torvalds 已提交
750 751 752

	/* Connect the region to the new handler */

L
Len Brown 已提交
753
	status = acpi_ev_attach_region(handler_obj, obj_desc, FALSE);
L
Linus Torvalds 已提交
754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774
	return (status);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_install_space_handler
 *
 * PARAMETERS:  Node            - Namespace node for the device
 *              space_id        - The address space ID
 *              Handler         - Address of the handler
 *              Setup           - Address of the setup function
 *              Context         - Value passed to the handler on each access
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Install a handler for all op_regions of a given space_id.
 *              Assumes namespace is locked
 *
 ******************************************************************************/

acpi_status
L
Len Brown 已提交
775 776 777 778
acpi_ev_install_space_handler(struct acpi_namespace_node * node,
			      acpi_adr_space_type space_id,
			      acpi_adr_space_handler handler,
			      acpi_adr_space_setup setup, void *context)
L
Linus Torvalds 已提交
779
{
L
Len Brown 已提交
780 781 782 783
	union acpi_operand_object *obj_desc;
	union acpi_operand_object *handler_obj;
	acpi_status status;
	acpi_object_type type;
B
Bob Moore 已提交
784
	u8 flags = 0;
L
Linus Torvalds 已提交
785

B
Bob Moore 已提交
786
	ACPI_FUNCTION_TRACE(ev_install_space_handler);
L
Linus Torvalds 已提交
787 788

	/*
789 790
	 * This registration is valid for only the types below and the root. This
	 * is where the default handlers get placed.
L
Linus Torvalds 已提交
791
	 */
L
Len Brown 已提交
792 793 794
	if ((node->type != ACPI_TYPE_DEVICE) &&
	    (node->type != ACPI_TYPE_PROCESSOR) &&
	    (node->type != ACPI_TYPE_THERMAL) && (node != acpi_gbl_root_node)) {
L
Linus Torvalds 已提交
795 796 797 798 799 800 801 802 803 804
		status = AE_BAD_PARAMETER;
		goto unlock_and_exit;
	}

	if (handler == ACPI_DEFAULT_HANDLER) {
		flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED;

		switch (space_id) {
		case ACPI_ADR_SPACE_SYSTEM_MEMORY:
			handler = acpi_ex_system_memory_space_handler;
L
Len Brown 已提交
805
			setup = acpi_ev_system_memory_region_setup;
L
Linus Torvalds 已提交
806 807 808 809
			break;

		case ACPI_ADR_SPACE_SYSTEM_IO:
			handler = acpi_ex_system_io_space_handler;
L
Len Brown 已提交
810
			setup = acpi_ev_io_space_region_setup;
L
Linus Torvalds 已提交
811 812 813 814
			break;

		case ACPI_ADR_SPACE_PCI_CONFIG:
			handler = acpi_ex_pci_config_space_handler;
L
Len Brown 已提交
815
			setup = acpi_ev_pci_config_region_setup;
L
Linus Torvalds 已提交
816 817 818 819
			break;

		case ACPI_ADR_SPACE_CMOS:
			handler = acpi_ex_cmos_space_handler;
L
Len Brown 已提交
820
			setup = acpi_ev_cmos_region_setup;
L
Linus Torvalds 已提交
821 822 823 824
			break;

		case ACPI_ADR_SPACE_PCI_BAR_TARGET:
			handler = acpi_ex_pci_bar_space_handler;
L
Len Brown 已提交
825
			setup = acpi_ev_pci_bar_region_setup;
L
Linus Torvalds 已提交
826 827 828 829
			break;

		case ACPI_ADR_SPACE_DATA_TABLE:
			handler = acpi_ex_data_table_space_handler;
L
Len Brown 已提交
830
			setup = NULL;
L
Linus Torvalds 已提交
831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
			break;

		default:
			status = AE_BAD_PARAMETER;
			goto unlock_and_exit;
		}
	}

	/* If the caller hasn't specified a setup routine, use the default */

	if (!setup) {
		setup = acpi_ev_default_region_setup;
	}

	/* Check for an existing internal object */

L
Len Brown 已提交
847
	obj_desc = acpi_ns_get_attached_object(node);
L
Linus Torvalds 已提交
848 849
	if (obj_desc) {
		/*
850 851
		 * The attached device object already exists. Make sure the handler
		 * is not already installed.
L
Linus Torvalds 已提交
852 853 854 855 856 857
		 */
		handler_obj = obj_desc->device.handler;

		/* Walk the handler list for this device */

		while (handler_obj) {
B
Bob Moore 已提交
858

L
Linus Torvalds 已提交
859 860 861
			/* Same space_id indicates a handler already installed */

			if (handler_obj->address_space.space_id == space_id) {
L
Len Brown 已提交
862 863
				if (handler_obj->address_space.handler ==
				    handler) {
L
Linus Torvalds 已提交
864 865
					/*
					 * It is (relatively) OK to attempt to install the SAME
866 867
					 * handler twice. This can easily happen with the
					 * PCI_Config space.
L
Linus Torvalds 已提交
868 869 870
					 */
					status = AE_SAME_HANDLER;
					goto unlock_and_exit;
L
Len Brown 已提交
871
				} else {
L
Linus Torvalds 已提交
872 873 874 875 876 877 878 879 880 881 882
					/* A handler is already installed */

					status = AE_ALREADY_EXISTS;
				}
				goto unlock_and_exit;
			}

			/* Walk the linked list of handlers */

			handler_obj = handler_obj->address_space.next;
		}
L
Len Brown 已提交
883 884 885 886
	} else {
		ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
				  "Creating object on Device %p while installing handler\n",
				  node));
L
Linus Torvalds 已提交
887 888 889 890 891

		/* obj_desc does not exist, create one */

		if (node->type == ACPI_TYPE_ANY) {
			type = ACPI_TYPE_DEVICE;
L
Len Brown 已提交
892
		} else {
L
Linus Torvalds 已提交
893 894 895
			type = node->type;
		}

L
Len Brown 已提交
896
		obj_desc = acpi_ut_create_internal_object(type);
L
Linus Torvalds 已提交
897 898 899 900 901 902 903 904 905 906 907
		if (!obj_desc) {
			status = AE_NO_MEMORY;
			goto unlock_and_exit;
		}

		/* Init new descriptor */

		obj_desc->common.type = (u8) type;

		/* Attach the new object to the Node */

L
Len Brown 已提交
908
		status = acpi_ns_attach_object(node, obj_desc, type);
L
Linus Torvalds 已提交
909 910 911

		/* Remove local reference to the object */

L
Len Brown 已提交
912
		acpi_ut_remove_reference(obj_desc);
L
Linus Torvalds 已提交
913

L
Len Brown 已提交
914
		if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
915 916 917 918
			goto unlock_and_exit;
		}
	}

L
Len Brown 已提交
919 920 921 922
	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
			  "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n",
			  acpi_ut_get_region_name(space_id), space_id,
			  acpi_ut_get_node_name(node), node, obj_desc));
L
Linus Torvalds 已提交
923 924 925 926

	/*
	 * Install the handler
	 *
927 928
	 * At this point there is no existing handler. Just allocate the object
	 * for the handler and link it into the list.
L
Linus Torvalds 已提交
929
	 */
L
Len Brown 已提交
930 931
	handler_obj =
	    acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_ADDRESS_HANDLER);
L
Linus Torvalds 已提交
932 933 934 935 936 937 938
	if (!handler_obj) {
		status = AE_NO_MEMORY;
		goto unlock_and_exit;
	}

	/* Init handler obj */

L
Len Brown 已提交
939
	handler_obj->address_space.space_id = (u8) space_id;
B
Bob Moore 已提交
940
	handler_obj->address_space.handler_flags = flags;
L
Linus Torvalds 已提交
941
	handler_obj->address_space.region_list = NULL;
L
Len Brown 已提交
942 943 944 945
	handler_obj->address_space.node = node;
	handler_obj->address_space.handler = handler;
	handler_obj->address_space.context = context;
	handler_obj->address_space.setup = setup;
L
Linus Torvalds 已提交
946 947 948

	/* Install at head of Device.address_space list */

L
Len Brown 已提交
949
	handler_obj->address_space.next = obj_desc->device.handler;
L
Linus Torvalds 已提交
950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968

	/*
	 * The Device object is the first reference on the handler_obj.
	 * Each region that uses the handler adds a reference.
	 */
	obj_desc->device.handler = handler_obj;

	/*
	 * Walk the namespace finding all of the regions this
	 * handler will manage.
	 *
	 * Start at the device and search the branch toward
	 * the leaf nodes until either the leaf is encountered or
	 * a device is detected that has an address handler of the
	 * same type.
	 *
	 * In either case, back up and search down the remainder
	 * of the branch
	 */
L
Len Brown 已提交
969 970 971 972
	status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX,
					ACPI_NS_WALK_UNLOCK,
					acpi_ev_install_handler, handler_obj,
					NULL);
L
Linus Torvalds 已提交
973

L
Len Brown 已提交
974 975
      unlock_and_exit:
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_execute_reg_methods
 *
 * PARAMETERS:  Node            - Namespace node for the device
 *              space_id        - The address space ID
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Run all _REG methods for the input Space ID;
 *              Note: assumes namespace is locked, or system init time.
 *
 ******************************************************************************/

acpi_status
L
Len Brown 已提交
993 994
acpi_ev_execute_reg_methods(struct acpi_namespace_node *node,
			    acpi_adr_space_type space_id)
L
Linus Torvalds 已提交
995
{
L
Len Brown 已提交
996
	acpi_status status;
L
Linus Torvalds 已提交
997

B
Bob Moore 已提交
998
	ACPI_FUNCTION_TRACE(ev_execute_reg_methods);
L
Linus Torvalds 已提交
999 1000

	/*
1001 1002 1003 1004
	 * Run all _REG methods for all Operation Regions for this space ID. This
	 * is a separate walk in order to handle any interdependencies between
	 * regions and _REG methods. (i.e. handlers must be installed for all
	 * regions of this Space ID before we can run any _REG methods)
L
Linus Torvalds 已提交
1005
	 */
L
Len Brown 已提交
1006 1007 1008
	status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX,
					ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run,
					&space_id, NULL);
L
Linus Torvalds 已提交
1009

L
Len Brown 已提交
1010
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
1011 1012 1013 1014 1015 1016 1017 1018
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_reg_run
 *
 * PARAMETERS:  walk_namespace callback
 *
B
Bob Moore 已提交
1019
 * DESCRIPTION: Run _REG method for region objects of the requested space_iD
L
Linus Torvalds 已提交
1020 1021 1022
 *
 ******************************************************************************/

R
Robert Moore 已提交
1023
static acpi_status
L
Len Brown 已提交
1024 1025
acpi_ev_reg_run(acpi_handle obj_handle,
		u32 level, void *context, void **return_value)
L
Linus Torvalds 已提交
1026
{
L
Len Brown 已提交
1027 1028 1029 1030
	union acpi_operand_object *obj_desc;
	struct acpi_namespace_node *node;
	acpi_adr_space_type space_id;
	acpi_status status;
L
Linus Torvalds 已提交
1031

L
Len Brown 已提交
1032
	space_id = *ACPI_CAST_PTR(acpi_adr_space_type, context);
L
Linus Torvalds 已提交
1033 1034 1035

	/* Convert and validate the device handle */

L
Len Brown 已提交
1036
	node = acpi_ns_map_handle_to_node(obj_handle);
L
Linus Torvalds 已提交
1037 1038 1039 1040 1041
	if (!node) {
		return (AE_BAD_PARAMETER);
	}

	/*
1042 1043
	 * We only care about regions.and objects that are allowed to have address
	 * space handlers
L
Linus Torvalds 已提交
1044
	 */
L
Len Brown 已提交
1045
	if ((node->type != ACPI_TYPE_REGION) && (node != acpi_gbl_root_node)) {
L
Linus Torvalds 已提交
1046 1047 1048 1049 1050
		return (AE_OK);
	}

	/* Check for an existing internal object */

L
Len Brown 已提交
1051
	obj_desc = acpi_ns_get_attached_object(node);
L
Linus Torvalds 已提交
1052
	if (!obj_desc) {
B
Bob Moore 已提交
1053

L
Linus Torvalds 已提交
1054 1055 1056 1057 1058 1059 1060 1061
		/* No object, just exit */

		return (AE_OK);
	}

	/* Object is a Region */

	if (obj_desc->region.space_id != space_id) {
1062 1063 1064

		/* This region is for a different address space, just ignore it */

L
Linus Torvalds 已提交
1065 1066 1067
		return (AE_OK);
	}

L
Len Brown 已提交
1068
	status = acpi_ev_execute_reg_method(obj_desc, 1);
L
Linus Torvalds 已提交
1069 1070
	return (status);
}