evregion.c 29.5 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>
L
Len Brown 已提交
45 46 47 48
#include "accommon.h"
#include "acevents.h"
#include "acnamesp.h"
#include "acinterp.h"
L
Linus Torvalds 已提交
49 50

#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
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_address_space_dispatch
 *
 * PARAMETERS:  region_obj          - Internal region object
 *              Function            - Read or Write operation
278
 *              region_offset       - Where in the region to read or write
L
Linus Torvalds 已提交
279
 *              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
acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
			       u32 function,
293
			       u32 region_offset,
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 400
			  ACPI_FORMAT_NATIVE_UINT(region_obj->region.address +
						  region_offset),
L
Len Brown 已提交
401 402
			  acpi_ut_get_region_name(region_obj->region.
						  space_id)));
L
Linus Torvalds 已提交
403

B
Bob Moore 已提交
404 405
	if (!(handler_desc->address_space.handler_flags &
	      ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
L
Linus Torvalds 已提交
406 407 408 409 410
		/*
		 * 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.
		 */
411
		acpi_ex_exit_interpreter();
L
Linus Torvalds 已提交
412 413 414 415
	}

	/* Call the handler */

416 417 418
	status = handler(function,
			 (region_obj->region.address + region_offset),
			 bit_width, value, handler_desc->address_space.context,
L
Linus Torvalds 已提交
419 420
			 region_obj2->extra.region_context);

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

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

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

/*******************************************************************************
 *
 * 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 已提交
454 455
acpi_ev_detach_region(union acpi_operand_object *region_obj,
		      u8 acpi_ns_is_locked)
L
Linus Torvalds 已提交
456
{
L
Len Brown 已提交
457 458 459 460 461 462 463
	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 已提交
464

B
Bob Moore 已提交
465
	ACPI_FUNCTION_TRACE(ev_detach_region);
L
Linus Torvalds 已提交
466

L
Len Brown 已提交
467
	region_obj2 = acpi_ns_get_secondary_object(region_obj);
L
Linus Torvalds 已提交
468 469 470 471 472 473 474 475 476
	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 已提交
477

L
Linus Torvalds 已提交
478 479 480 481 482 483 484 485 486 487 488
		/* 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 已提交
489

L
Linus Torvalds 已提交
490 491 492
		/* Is this the correct Region? */

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

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

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

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

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

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

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

B
Bob Moore 已提交
528
			/*
529 530
			 * If the region has been activated, call the setup handler with
			 * the deactivate notification
B
Bob Moore 已提交
531 532 533 534 535 536 537 538
			 */
			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 已提交
539

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

B
Bob Moore 已提交
542 543 544 545 546 547 548
				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 已提交
549

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

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

			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 已提交
577 578 579
	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
			  "Cannot remove region %p from address handler %p\n",
			  region_obj, handler_obj));
L
Linus Torvalds 已提交
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599

	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 已提交
600 601 602
acpi_ev_attach_region(union acpi_operand_object *handler_obj,
		      union acpi_operand_object *region_obj,
		      u8 acpi_ns_is_locked)
L
Linus Torvalds 已提交
603 604
{

B
Bob Moore 已提交
605
	ACPI_FUNCTION_TRACE(ev_attach_region);
L
Linus Torvalds 已提交
606

L
Len Brown 已提交
607 608 609 610 611 612
	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 已提交
613 614 615 616 617 618 619 620 621

	/* 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 已提交
622
		return_ACPI_STATUS(AE_ALREADY_EXISTS);
L
Linus Torvalds 已提交
623 624 625
	}

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

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

/*******************************************************************************
 *
 * 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 已提交
648
static acpi_status
L
Len Brown 已提交
649 650
acpi_ev_install_handler(acpi_handle obj_handle,
			u32 level, void *context, void **return_value)
L
Linus Torvalds 已提交
651
{
L
Len Brown 已提交
652 653 654 655 656
	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 已提交
657

B
Bob Moore 已提交
658
	ACPI_FUNCTION_NAME(ev_install_handler);
L
Linus Torvalds 已提交
659

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

	/* Parameter validation */

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

	/* Convert and validate the device handle */

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

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

	/* Check for an existing internal object */

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

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

		return (AE_OK);
	}

	/* Devices are handled different than regions */

696
	if (obj_desc->common.type == ACPI_TYPE_DEVICE) {
B
Bob Moore 已提交
697

L
Linus Torvalds 已提交
698 699 700 701
		/* 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 已提交
702

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

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

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

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

			next_handler_obj = next_handler_obj->address_space.next;
		}

		/*
732 733
		 * 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 已提交
734 735 736 737 738 739 740
		 */
		return (AE_OK);
	}

	/* Object is a Region */

	if (obj_desc->region.space_id != handler_obj->address_space.space_id) {
741 742 743

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

L
Linus Torvalds 已提交
744 745 746 747
		return (AE_OK);
	}

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

	/* Connect the region to the new handler */

L
Len Brown 已提交
756
	status = acpi_ev_attach_region(handler_obj, obj_desc, FALSE);
L
Linus Torvalds 已提交
757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777
	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 已提交
778 779 780 781
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 已提交
782
{
L
Len Brown 已提交
783 784 785 786
	union acpi_operand_object *obj_desc;
	union acpi_operand_object *handler_obj;
	acpi_status status;
	acpi_object_type type;
B
Bob Moore 已提交
787
	u8 flags = 0;
L
Linus Torvalds 已提交
788

B
Bob Moore 已提交
789
	ACPI_FUNCTION_TRACE(ev_install_space_handler);
L
Linus Torvalds 已提交
790 791

	/*
792 793
	 * This registration is valid for only the types below and the root. This
	 * is where the default handlers get placed.
L
Linus Torvalds 已提交
794
	 */
L
Len Brown 已提交
795 796 797
	if ((node->type != ACPI_TYPE_DEVICE) &&
	    (node->type != ACPI_TYPE_PROCESSOR) &&
	    (node->type != ACPI_TYPE_THERMAL) && (node != acpi_gbl_root_node)) {
L
Linus Torvalds 已提交
798 799 800 801 802 803 804 805 806 807
		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 已提交
808
			setup = acpi_ev_system_memory_region_setup;
L
Linus Torvalds 已提交
809 810 811 812
			break;

		case ACPI_ADR_SPACE_SYSTEM_IO:
			handler = acpi_ex_system_io_space_handler;
L
Len Brown 已提交
813
			setup = acpi_ev_io_space_region_setup;
L
Linus Torvalds 已提交
814 815 816 817
			break;

		case ACPI_ADR_SPACE_PCI_CONFIG:
			handler = acpi_ex_pci_config_space_handler;
L
Len Brown 已提交
818
			setup = acpi_ev_pci_config_region_setup;
L
Linus Torvalds 已提交
819 820 821 822
			break;

		case ACPI_ADR_SPACE_CMOS:
			handler = acpi_ex_cmos_space_handler;
L
Len Brown 已提交
823
			setup = acpi_ev_cmos_region_setup;
L
Linus Torvalds 已提交
824 825 826 827
			break;

		case ACPI_ADR_SPACE_PCI_BAR_TARGET:
			handler = acpi_ex_pci_bar_space_handler;
L
Len Brown 已提交
828
			setup = acpi_ev_pci_bar_region_setup;
L
Linus Torvalds 已提交
829 830 831 832
			break;

		case ACPI_ADR_SPACE_DATA_TABLE:
			handler = acpi_ex_data_table_space_handler;
L
Len Brown 已提交
833
			setup = NULL;
L
Linus Torvalds 已提交
834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849
			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 已提交
850
	obj_desc = acpi_ns_get_attached_object(node);
L
Linus Torvalds 已提交
851 852
	if (obj_desc) {
		/*
853 854
		 * The attached device object already exists. Make sure the handler
		 * is not already installed.
L
Linus Torvalds 已提交
855 856 857 858 859 860
		 */
		handler_obj = obj_desc->device.handler;

		/* Walk the handler list for this device */

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

L
Linus Torvalds 已提交
862 863 864
			/* Same space_id indicates a handler already installed */

			if (handler_obj->address_space.space_id == space_id) {
L
Len Brown 已提交
865 866
				if (handler_obj->address_space.handler ==
				    handler) {
L
Linus Torvalds 已提交
867 868
					/*
					 * It is (relatively) OK to attempt to install the SAME
869 870
					 * handler twice. This can easily happen with the
					 * PCI_Config space.
L
Linus Torvalds 已提交
871 872 873
					 */
					status = AE_SAME_HANDLER;
					goto unlock_and_exit;
L
Len Brown 已提交
874
				} else {
L
Linus Torvalds 已提交
875 876 877 878 879 880 881 882 883 884 885
					/* 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 已提交
886 887 888 889
	} else {
		ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
				  "Creating object on Device %p while installing handler\n",
				  node));
L
Linus Torvalds 已提交
890 891 892 893 894

		/* obj_desc does not exist, create one */

		if (node->type == ACPI_TYPE_ANY) {
			type = ACPI_TYPE_DEVICE;
L
Len Brown 已提交
895
		} else {
L
Linus Torvalds 已提交
896 897 898
			type = node->type;
		}

L
Len Brown 已提交
899
		obj_desc = acpi_ut_create_internal_object(type);
L
Linus Torvalds 已提交
900 901 902 903 904 905 906 907 908 909 910
		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 已提交
911
		status = acpi_ns_attach_object(node, obj_desc, type);
L
Linus Torvalds 已提交
912 913 914

		/* Remove local reference to the object */

L
Len Brown 已提交
915
		acpi_ut_remove_reference(obj_desc);
L
Linus Torvalds 已提交
916

L
Len Brown 已提交
917
		if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
918 919 920 921
			goto unlock_and_exit;
		}
	}

L
Len Brown 已提交
922 923 924 925
	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 已提交
926 927 928 929

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

	/* Init handler obj */

L
Len Brown 已提交
942
	handler_obj->address_space.space_id = (u8) space_id;
B
Bob Moore 已提交
943
	handler_obj->address_space.handler_flags = flags;
L
Linus Torvalds 已提交
944
	handler_obj->address_space.region_list = NULL;
L
Len Brown 已提交
945 946 947 948
	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 已提交
949 950 951

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

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

	/*
	 * 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 已提交
972 973 974 975
	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 已提交
976

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

/*******************************************************************************
 *
 * 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 已提交
996 997
acpi_ev_execute_reg_methods(struct acpi_namespace_node *node,
			    acpi_adr_space_type space_id)
L
Linus Torvalds 已提交
998
{
L
Len Brown 已提交
999
	acpi_status status;
L
Linus Torvalds 已提交
1000

B
Bob Moore 已提交
1001
	ACPI_FUNCTION_TRACE(ev_execute_reg_methods);
L
Linus Torvalds 已提交
1002 1003

	/*
1004 1005 1006 1007
	 * 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 已提交
1008
	 */
L
Len Brown 已提交
1009 1010 1011
	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 已提交
1012

L
Len Brown 已提交
1013
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
1014 1015 1016 1017 1018 1019 1020 1021
}

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

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

L
Len Brown 已提交
1035
	space_id = *ACPI_CAST_PTR(acpi_adr_space_type, context);
L
Linus Torvalds 已提交
1036 1037 1038

	/* Convert and validate the device handle */

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

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

	/* Check for an existing internal object */

L
Len Brown 已提交
1054
	obj_desc = acpi_ns_get_attached_object(node);
L
Linus Torvalds 已提交
1055
	if (!obj_desc) {
B
Bob Moore 已提交
1056

L
Linus Torvalds 已提交
1057 1058 1059 1060 1061 1062 1063 1064
		/* No object, just exit */

		return (AE_OK);
	}

	/* Object is a Region */

	if (obj_desc->region.space_id != space_id) {
1065 1066 1067

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

L
Linus Torvalds 已提交
1068 1069 1070
		return (AE_OK);
	}

L
Len Brown 已提交
1071
	status = acpi_ev_execute_reg_method(obj_desc, 1);
L
Linus Torvalds 已提交
1072 1073
	return (status);
}