evgpeblk.c 34.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7
/******************************************************************************
 *
 * Module Name: evgpeblk - GPE block creation and initialization.
 *
 *****************************************************************************/

/*
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
#include "accommon.h"
#include "acevents.h"
#include "acnamesp.h"
L
Linus Torvalds 已提交
48 49

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

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

static acpi_status
L
Len Brown 已提交
58 59
acpi_ev_match_prw_and_gpe(acpi_handle obj_handle,
			  u32 level, void *info, void **return_value);
R
Robert Moore 已提交
60

L
Len Brown 已提交
61 62
static struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32
							       interrupt_number);
R
Robert Moore 已提交
63 64

static acpi_status
L
Len Brown 已提交
65
acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt);
R
Robert Moore 已提交
66 67

static acpi_status
L
Len Brown 已提交
68 69
acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block,
			  u32 interrupt_number);
R
Robert Moore 已提交
70 71

static acpi_status
L
Len Brown 已提交
72
acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block);
L
Linus Torvalds 已提交
73 74 75 76 77 78 79 80 81

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_valid_gpe_event
 *
 * PARAMETERS:  gpe_event_info              - Info for this GPE
 *
 * RETURN:      TRUE if the gpe_event is valid
 *
B
Bob Moore 已提交
82
 * DESCRIPTION: Validate a GPE event. DO NOT CALL FROM INTERRUPT LEVEL.
L
Linus Torvalds 已提交
83 84 85 86 87
 *              Should be called only when the GPE lists are semaphore locked
 *              and not subject to change.
 *
 ******************************************************************************/

L
Len Brown 已提交
88
u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info)
L
Linus Torvalds 已提交
89
{
L
Len Brown 已提交
90 91
	struct acpi_gpe_xrupt_info *gpe_xrupt_block;
	struct acpi_gpe_block_info *gpe_block;
L
Linus Torvalds 已提交
92

L
Len Brown 已提交
93
	ACPI_FUNCTION_ENTRY();
L
Linus Torvalds 已提交
94 95 96 97 98 99 100 101 102 103 104 105 106

	/* No need for spin lock since we are not changing any list elements */

	/* Walk the GPE interrupt levels */

	gpe_xrupt_block = acpi_gbl_gpe_xrupt_list_head;
	while (gpe_xrupt_block) {
		gpe_block = gpe_xrupt_block->gpe_block_list_head;

		/* Walk the GPE blocks on this interrupt level */

		while (gpe_block) {
			if ((&gpe_block->event_info[0] <= gpe_event_info) &&
107 108 109
			    (&gpe_block->event_info[((acpi_size)
						     gpe_block->
						     register_count) * 8] >
L
Len Brown 已提交
110
			     gpe_event_info)) {
L
Linus Torvalds 已提交
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
				return (TRUE);
			}

			gpe_block = gpe_block->next;
		}

		gpe_xrupt_block = gpe_xrupt_block->next;
	}

	return (FALSE);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_walk_gpe_list
 *
 * PARAMETERS:  gpe_walk_callback   - Routine called for each GPE block
128
 *              Context             - Value passed to callback
L
Linus Torvalds 已提交
129 130 131 132 133 134 135
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Walk the GPE lists.
 *
 ******************************************************************************/

136 137
acpi_status
acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback, void *context)
L
Linus Torvalds 已提交
138
{
L
Len Brown 已提交
139 140 141
	struct acpi_gpe_block_info *gpe_block;
	struct acpi_gpe_xrupt_info *gpe_xrupt_info;
	acpi_status status = AE_OK;
B
Bob Moore 已提交
142
	acpi_cpu_flags flags;
L
Linus Torvalds 已提交
143

B
Bob Moore 已提交
144
	ACPI_FUNCTION_TRACE(ev_walk_gpe_list);
L
Linus Torvalds 已提交
145

L
Len Brown 已提交
146
	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
L
Linus Torvalds 已提交
147 148 149 150 151

	/* Walk the interrupt level descriptor list */

	gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
	while (gpe_xrupt_info) {
B
Bob Moore 已提交
152

L
Linus Torvalds 已提交
153 154 155 156
		/* Walk all Gpe Blocks attached to this interrupt level */

		gpe_block = gpe_xrupt_info->gpe_block_list_head;
		while (gpe_block) {
B
Bob Moore 已提交
157

L
Linus Torvalds 已提交
158 159
			/* One callback per GPE block */

160 161 162
			status =
			    gpe_walk_callback(gpe_xrupt_info, gpe_block,
					      context);
L
Len Brown 已提交
163
			if (ACPI_FAILURE(status)) {
164 165 166
				if (status == AE_CTRL_END) {	/* Callback abort */
					status = AE_OK;
				}
L
Linus Torvalds 已提交
167 168 169 170 171 172 173 174 175
				goto unlock_and_exit;
			}

			gpe_block = gpe_block->next;
		}

		gpe_xrupt_info = gpe_xrupt_info->next;
	}

L
Len Brown 已提交
176 177 178
      unlock_and_exit:
	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
179 180
}

R
Robert Moore 已提交
181
/*******************************************************************************
L
Linus Torvalds 已提交
182 183 184 185 186 187 188 189 190 191 192 193 194 195
 *
 * FUNCTION:    acpi_ev_delete_gpe_handlers
 *
 * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
 *              gpe_block           - Gpe Block info
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Delete all Handler objects found in the GPE data structs.
 *              Used only prior to termination.
 *
 ******************************************************************************/

acpi_status
L
Len Brown 已提交
196
acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
197 198
			    struct acpi_gpe_block_info *gpe_block,
			    void *context)
L
Linus Torvalds 已提交
199
{
L
Len Brown 已提交
200
	struct acpi_gpe_event_info *gpe_event_info;
201 202
	u32 i;
	u32 j;
L
Linus Torvalds 已提交
203

B
Bob Moore 已提交
204
	ACPI_FUNCTION_TRACE(ev_delete_gpe_handlers);
L
Linus Torvalds 已提交
205 206 207 208

	/* Examine each GPE Register within the block */

	for (i = 0; i < gpe_block->register_count; i++) {
B
Bob Moore 已提交
209

L
Linus Torvalds 已提交
210 211 212
		/* Now look at the individual GPEs in this byte register */

		for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
213 214 215
			gpe_event_info = &gpe_block->event_info[((acpi_size) i *
								 ACPI_GPE_REGISTER_WIDTH)
								+ j];
L
Linus Torvalds 已提交
216

R
Robert Moore 已提交
217
			if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
L
Len Brown 已提交
218
			    ACPI_GPE_DISPATCH_HANDLER) {
B
Bob Moore 已提交
219
				ACPI_FREE(gpe_event_info->dispatch.handler);
L
Linus Torvalds 已提交
220
				gpe_event_info->dispatch.handler = NULL;
L
Len Brown 已提交
221 222
				gpe_event_info->flags &=
				    ~ACPI_GPE_DISPATCH_MASK;
L
Linus Torvalds 已提交
223 224 225 226
			}
		}
	}

L
Len Brown 已提交
227
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_save_method_info
 *
 * PARAMETERS:  Callback from walk_namespace
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Called from acpi_walk_namespace. Expects each object to be a
 *              control method under the _GPE portion of the namespace.
 *              Extract the name and GPE type from the object, saving this
 *              information for quick lookup during GPE dispatch
 *
 *              The name of each GPE control method is of the form:
 *              "_Lxx" or "_Exx"
 *              Where:
 *                  L      - means that the GPE is level triggered
 *                  E      - means that the GPE is edge triggered
 *                  xx     - is the GPE number [in HEX]
 *
 ******************************************************************************/

static acpi_status
L
Len Brown 已提交
253 254
acpi_ev_save_method_info(acpi_handle obj_handle,
			 u32 level, void *obj_desc, void **return_value)
L
Linus Torvalds 已提交
255
{
L
Len Brown 已提交
256 257 258 259 260 261
	struct acpi_gpe_block_info *gpe_block = (void *)obj_desc;
	struct acpi_gpe_event_info *gpe_event_info;
	u32 gpe_number;
	char name[ACPI_NAME_SIZE + 1];
	u8 type;
	acpi_status status;
L
Linus Torvalds 已提交
262

B
Bob Moore 已提交
263
	ACPI_FUNCTION_TRACE(ev_save_method_info);
L
Linus Torvalds 已提交
264 265 266 267 268 269

	/*
	 * _Lxx and _Exx GPE method support
	 *
	 * 1) Extract the name from the object and convert to a string
	 */
L
Len Brown 已提交
270 271 272
	ACPI_MOVE_32_TO_32(name,
			   &((struct acpi_namespace_node *)obj_handle)->name.
			   integer);
L
Linus Torvalds 已提交
273 274 275 276 277 278
	name[ACPI_NAME_SIZE] = 0;

	/*
	 * 2) Edge/Level determination is based on the 2nd character
	 *    of the method name
	 *
B
Bob Moore 已提交
279
	 * NOTE: Default GPE type is RUNTIME. May be changed later to WAKE
L
Linus Torvalds 已提交
280 281 282 283 284 285 286 287 288 289 290 291 292 293
	 * if a _PRW object is found that points to this GPE.
	 */
	switch (name[1]) {
	case 'L':
		type = ACPI_GPE_LEVEL_TRIGGERED;
		break;

	case 'E':
		type = ACPI_GPE_EDGE_TRIGGERED;
		break;

	default:
		/* Unknown method type, just ignore it! */

B
Bob Moore 已提交
294
		ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
295 296
				  "Ignoring unknown GPE method type: %s "
				  "(name not of form _Lxx or _Exx)", name));
L
Len Brown 已提交
297
		return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
298 299 300 301
	}

	/* Convert the last two characters of the name to the GPE Number */

L
Len Brown 已提交
302
	gpe_number = ACPI_STRTOUL(&name[2], NULL, 16);
L
Linus Torvalds 已提交
303
	if (gpe_number == ACPI_UINT32_MAX) {
B
Bob Moore 已提交
304

L
Linus Torvalds 已提交
305 306
		/* Conversion failed; invalid method, just ignore it */

B
Bob Moore 已提交
307
		ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
308 309
				  "Could not extract GPE number from name: %s "
				  "(name is not of form _Lxx or _Exx)", name));
L
Len Brown 已提交
310
		return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
311 312 313 314 315
	}

	/* Ensure that we have a valid GPE number for this GPE block */

	if ((gpe_number < gpe_block->block_base_number) ||
316 317
	    (gpe_number >= (gpe_block->block_base_number +
			    (gpe_block->register_count * 8)))) {
L
Linus Torvalds 已提交
318
		/*
319 320 321
		 * Not valid for this GPE block, just ignore it. However, it may be
		 * valid for a different GPE block, since GPE0 and GPE1 methods both
		 * appear under \_GPE.
L
Linus Torvalds 已提交
322
		 */
L
Len Brown 已提交
323
		return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
324 325 326
	}

	/*
327 328 329
	 * Now we can add this information to the gpe_event_info block for use
	 * during dispatch of this GPE. Default type is RUNTIME, although this may
	 * change when the _PRW methods are executed later.
L
Linus Torvalds 已提交
330
	 */
L
Len Brown 已提交
331 332
	gpe_event_info =
	    &gpe_block->event_info[gpe_number - gpe_block->block_base_number];
L
Linus Torvalds 已提交
333

B
Bob Moore 已提交
334 335
	gpe_event_info->flags = (u8)
	    (type | ACPI_GPE_DISPATCH_METHOD | ACPI_GPE_TYPE_RUNTIME);
L
Linus Torvalds 已提交
336

L
Len Brown 已提交
337 338
	gpe_event_info->dispatch.method_node =
	    (struct acpi_namespace_node *)obj_handle;
L
Linus Torvalds 已提交
339 340 341

	/* Update enable mask, but don't enable the HW GPE as of yet */

L
Len Brown 已提交
342
	status = acpi_ev_enable_gpe(gpe_event_info, FALSE);
L
Linus Torvalds 已提交
343

L
Len Brown 已提交
344 345 346 347
	ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
			  "Registered GPE method %s as GPE number 0x%.2X\n",
			  name, gpe_number));
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
348 349 350 351 352 353 354 355
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_match_prw_and_gpe
 *
 * PARAMETERS:  Callback from walk_namespace
 *
B
Bob Moore 已提交
356
 * RETURN:      Status. NOTE: We ignore errors so that the _PRW walk is
L
Linus Torvalds 已提交
357 358 359
 *              not aborted on a single _PRW failure.
 *
 * DESCRIPTION: Called from acpi_walk_namespace. Expects each object to be a
B
Bob Moore 已提交
360
 *              Device. Run the _PRW method. If present, extract the GPE
L
Linus Torvalds 已提交
361 362 363 364 365
 *              number and mark the GPE as a WAKE GPE.
 *
 ******************************************************************************/

static acpi_status
L
Len Brown 已提交
366 367
acpi_ev_match_prw_and_gpe(acpi_handle obj_handle,
			  u32 level, void *info, void **return_value)
L
Linus Torvalds 已提交
368
{
L
Len Brown 已提交
369 370 371 372 373 374 375 376 377 378
	struct acpi_gpe_walk_info *gpe_info = (void *)info;
	struct acpi_namespace_node *gpe_device;
	struct acpi_gpe_block_info *gpe_block;
	struct acpi_namespace_node *target_gpe_device;
	struct acpi_gpe_event_info *gpe_event_info;
	union acpi_operand_object *pkg_desc;
	union acpi_operand_object *obj_desc;
	u32 gpe_number;
	acpi_status status;

B
Bob Moore 已提交
379
	ACPI_FUNCTION_TRACE(ev_match_prw_and_gpe);
L
Linus Torvalds 已提交
380 381 382

	/* Check for a _PRW method under this device */

L
Len Brown 已提交
383 384 385
	status = acpi_ut_evaluate_object(obj_handle, METHOD_NAME__PRW,
					 ACPI_BTYPE_PACKAGE, &pkg_desc);
	if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
386

L
Linus Torvalds 已提交
387 388
		/* Ignore all errors from _PRW, we don't want to abort the subsystem */

L
Len Brown 已提交
389
		return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
390 391 392 393 394 395 396 397 398 399 400 401 402 403
	}

	/* The returned _PRW package must have at least two elements */

	if (pkg_desc->package.count < 2) {
		goto cleanup;
	}

	/* Extract pointers from the input context */

	gpe_device = gpe_info->gpe_device;
	gpe_block = gpe_info->gpe_block;

	/*
404 405
	 * The _PRW object must return a package, we are only interested in the
	 * first element
L
Linus Torvalds 已提交
406 407 408
	 */
	obj_desc = pkg_desc->package.elements[0];

409
	if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
B
Bob Moore 已提交
410

L
Linus Torvalds 已提交
411 412 413 414 415 416 417
		/* Use FADT-defined GPE device (from definition of _PRW) */

		target_gpe_device = acpi_gbl_fadt_gpe_device;

		/* Integer is the GPE number in the FADT described GPE blocks */

		gpe_number = (u32) obj_desc->integer.value;
418
	} else if (obj_desc->common.type == ACPI_TYPE_PACKAGE) {
B
Bob Moore 已提交
419

L
Linus Torvalds 已提交
420 421 422
		/* Package contains a GPE reference and GPE number within a GPE block */

		if ((obj_desc->package.count < 2) ||
423
		    ((obj_desc->package.elements[0])->common.type !=
424 425 426
		     ACPI_TYPE_LOCAL_REFERENCE) ||
		    ((obj_desc->package.elements[1])->common.type !=
		     ACPI_TYPE_INTEGER)) {
L
Linus Torvalds 已提交
427 428 429 430 431
			goto cleanup;
		}

		/* Get GPE block reference and decode */

L
Len Brown 已提交
432 433
		target_gpe_device =
		    obj_desc->package.elements[0]->reference.node;
L
Linus Torvalds 已提交
434
		gpe_number = (u32) obj_desc->package.elements[1]->integer.value;
L
Len Brown 已提交
435
	} else {
L
Linus Torvalds 已提交
436 437 438 439 440 441 442 443
		/* Unknown type, just ignore it */

		goto cleanup;
	}

	/*
	 * Is this GPE within this block?
	 *
444
	 * TRUE if and only if these conditions are true:
L
Linus Torvalds 已提交
445 446 447 448 449
	 *     1) The GPE devices match.
	 *     2) The GPE index(number) is within the range of the Gpe Block
	 *          associated with the GPE device.
	 */
	if ((gpe_device == target_gpe_device) &&
L
Len Brown 已提交
450
	    (gpe_number >= gpe_block->block_base_number) &&
451 452 453 454 455
	    (gpe_number < gpe_block->block_base_number +
	     (gpe_block->register_count * 8))) {
		gpe_event_info = &gpe_block->event_info[gpe_number -
							gpe_block->
							block_base_number];
L
Linus Torvalds 已提交
456 457 458

		/* Mark GPE for WAKE-ONLY but WAKE_DISABLED */

L
Len Brown 已提交
459 460
		gpe_event_info->flags &=
		    ~(ACPI_GPE_WAKE_ENABLED | ACPI_GPE_RUN_ENABLED);
B
Bob Moore 已提交
461

L
Len Brown 已提交
462 463 464
		status =
		    acpi_ev_set_gpe_type(gpe_event_info, ACPI_GPE_TYPE_WAKE);
		if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
465 466
			goto cleanup;
		}
467

L
Len Brown 已提交
468 469 470
		status =
		    acpi_ev_update_gpe_enable_masks(gpe_event_info,
						    ACPI_GPE_DISABLE);
L
Linus Torvalds 已提交
471 472
	}

L
Len Brown 已提交
473 474 475
      cleanup:
	acpi_ut_remove_reference(pkg_desc);
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
476 477 478 479 480 481
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_get_gpe_xrupt_block
 *
482
 * PARAMETERS:  interrupt_number     - Interrupt for a GPE block
L
Linus Torvalds 已提交
483 484 485
 *
 * RETURN:      A GPE interrupt block
 *
B
Bob Moore 已提交
486
 * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt
487 488 489
 *              block per unique interrupt level used for GPEs. Should be
 *              called only when the GPE lists are semaphore locked and not
 *              subject to change.
L
Linus Torvalds 已提交
490 491 492
 *
 ******************************************************************************/

L
Len Brown 已提交
493 494
static struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32
							       interrupt_number)
L
Linus Torvalds 已提交
495
{
L
Len Brown 已提交
496 497 498
	struct acpi_gpe_xrupt_info *next_gpe_xrupt;
	struct acpi_gpe_xrupt_info *gpe_xrupt;
	acpi_status status;
B
Bob Moore 已提交
499
	acpi_cpu_flags flags;
L
Linus Torvalds 已提交
500

B
Bob Moore 已提交
501
	ACPI_FUNCTION_TRACE(ev_get_gpe_xrupt_block);
L
Linus Torvalds 已提交
502

R
Robert Moore 已提交
503
	/* No need for lock since we are not changing any list elements here */
L
Linus Torvalds 已提交
504 505 506

	next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head;
	while (next_gpe_xrupt) {
507
		if (next_gpe_xrupt->interrupt_number == interrupt_number) {
L
Len Brown 已提交
508
			return_PTR(next_gpe_xrupt);
L
Linus Torvalds 已提交
509 510 511 512 513 514 515
		}

		next_gpe_xrupt = next_gpe_xrupt->next;
	}

	/* Not found, must allocate a new xrupt descriptor */

B
Bob Moore 已提交
516
	gpe_xrupt = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_xrupt_info));
L
Linus Torvalds 已提交
517
	if (!gpe_xrupt) {
L
Len Brown 已提交
518
		return_PTR(NULL);
L
Linus Torvalds 已提交
519 520
	}

521
	gpe_xrupt->interrupt_number = interrupt_number;
L
Linus Torvalds 已提交
522 523 524

	/* Install new interrupt descriptor with spin lock */

L
Len Brown 已提交
525
	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
L
Linus Torvalds 已提交
526 527 528 529 530 531 532 533
	if (acpi_gbl_gpe_xrupt_list_head) {
		next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head;
		while (next_gpe_xrupt->next) {
			next_gpe_xrupt = next_gpe_xrupt->next;
		}

		next_gpe_xrupt->next = gpe_xrupt;
		gpe_xrupt->previous = next_gpe_xrupt;
L
Len Brown 已提交
534
	} else {
L
Linus Torvalds 已提交
535 536
		acpi_gbl_gpe_xrupt_list_head = gpe_xrupt;
	}
L
Len Brown 已提交
537
	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
L
Linus Torvalds 已提交
538 539 540

	/* Install new interrupt handler if not SCI_INT */

541
	if (interrupt_number != acpi_gbl_FADT.sci_interrupt) {
L
Len Brown 已提交
542 543 544 545
		status = acpi_os_install_interrupt_handler(interrupt_number,
							   acpi_ev_gpe_xrupt_handler,
							   gpe_xrupt);
		if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
546 547 548
			ACPI_ERROR((AE_INFO,
				    "Could not install GPE interrupt handler at level 0x%X",
				    interrupt_number));
L
Len Brown 已提交
549
			return_PTR(NULL);
L
Linus Torvalds 已提交
550 551 552
		}
	}

L
Len Brown 已提交
553
	return_PTR(gpe_xrupt);
L
Linus Torvalds 已提交
554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_delete_gpe_xrupt
 *
 * PARAMETERS:  gpe_xrupt       - A GPE interrupt info block
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Remove and free a gpe_xrupt block. Remove an associated
 *              interrupt handler if not the SCI interrupt.
 *
 ******************************************************************************/

static acpi_status
L
Len Brown 已提交
570
acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt)
L
Linus Torvalds 已提交
571
{
L
Len Brown 已提交
572
	acpi_status status;
B
Bob Moore 已提交
573
	acpi_cpu_flags flags;
L
Linus Torvalds 已提交
574

B
Bob Moore 已提交
575
	ACPI_FUNCTION_TRACE(ev_delete_gpe_xrupt);
L
Linus Torvalds 已提交
576 577 578

	/* We never want to remove the SCI interrupt handler */

579
	if (gpe_xrupt->interrupt_number == acpi_gbl_FADT.sci_interrupt) {
L
Linus Torvalds 已提交
580
		gpe_xrupt->gpe_block_list_head = NULL;
L
Len Brown 已提交
581
		return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
582 583 584 585
	}

	/* Disable this interrupt */

B
Bob Moore 已提交
586 587 588
	status =
	    acpi_os_remove_interrupt_handler(gpe_xrupt->interrupt_number,
					     acpi_ev_gpe_xrupt_handler);
L
Len Brown 已提交
589 590
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
591 592 593 594
	}

	/* Unlink the interrupt block with lock */

L
Len Brown 已提交
595
	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
L
Linus Torvalds 已提交
596 597
	if (gpe_xrupt->previous) {
		gpe_xrupt->previous->next = gpe_xrupt->next;
598 599 600 601
	} else {
		/* No previous, update list head */

		acpi_gbl_gpe_xrupt_list_head = gpe_xrupt->next;
L
Linus Torvalds 已提交
602 603 604 605 606
	}

	if (gpe_xrupt->next) {
		gpe_xrupt->next->previous = gpe_xrupt->previous;
	}
L
Len Brown 已提交
607
	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
L
Linus Torvalds 已提交
608 609 610

	/* Free the block */

B
Bob Moore 已提交
611
	ACPI_FREE(gpe_xrupt);
L
Len Brown 已提交
612
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
613 614 615 616 617 618
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_install_gpe_block
 *
619 620 621
 * PARAMETERS:  gpe_block               - New GPE block
 *              interrupt_number        - Xrupt to be associated with this
 *                                        GPE block
L
Linus Torvalds 已提交
622 623 624 625 626 627 628 629
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Install new GPE block with mutex support
 *
 ******************************************************************************/

static acpi_status
L
Len Brown 已提交
630 631
acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block,
			  u32 interrupt_number)
L
Linus Torvalds 已提交
632
{
L
Len Brown 已提交
633 634 635
	struct acpi_gpe_block_info *next_gpe_block;
	struct acpi_gpe_xrupt_info *gpe_xrupt_block;
	acpi_status status;
B
Bob Moore 已提交
636
	acpi_cpu_flags flags;
L
Linus Torvalds 已提交
637

B
Bob Moore 已提交
638
	ACPI_FUNCTION_TRACE(ev_install_gpe_block);
L
Linus Torvalds 已提交
639

L
Len Brown 已提交
640 641 642
	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
643 644
	}

L
Len Brown 已提交
645
	gpe_xrupt_block = acpi_ev_get_gpe_xrupt_block(interrupt_number);
L
Linus Torvalds 已提交
646 647 648 649 650
	if (!gpe_xrupt_block) {
		status = AE_NO_MEMORY;
		goto unlock_and_exit;
	}

R
Robert Moore 已提交
651
	/* Install the new block at the end of the list with lock */
L
Linus Torvalds 已提交
652

L
Len Brown 已提交
653
	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
L
Linus Torvalds 已提交
654 655 656 657 658 659 660 661
	if (gpe_xrupt_block->gpe_block_list_head) {
		next_gpe_block = gpe_xrupt_block->gpe_block_list_head;
		while (next_gpe_block->next) {
			next_gpe_block = next_gpe_block->next;
		}

		next_gpe_block->next = gpe_block;
		gpe_block->previous = next_gpe_block;
L
Len Brown 已提交
662
	} else {
L
Linus Torvalds 已提交
663 664 665 666
		gpe_xrupt_block->gpe_block_list_head = gpe_block;
	}

	gpe_block->xrupt_block = gpe_xrupt_block;
L
Len Brown 已提交
667
	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
L
Linus Torvalds 已提交
668

L
Len Brown 已提交
669 670 671
      unlock_and_exit:
	status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
672 673 674 675 676 677
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_delete_gpe_block
 *
678
 * PARAMETERS:  gpe_block           - Existing GPE block
L
Linus Torvalds 已提交
679 680 681 682 683 684 685
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Remove a GPE block
 *
 ******************************************************************************/

L
Len Brown 已提交
686
acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block)
L
Linus Torvalds 已提交
687
{
L
Len Brown 已提交
688
	acpi_status status;
B
Bob Moore 已提交
689
	acpi_cpu_flags flags;
L
Linus Torvalds 已提交
690

B
Bob Moore 已提交
691
	ACPI_FUNCTION_TRACE(ev_install_gpe_block);
L
Linus Torvalds 已提交
692

L
Len Brown 已提交
693 694 695
	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
696 697 698 699
	}

	/* Disable all GPEs in this block */

700 701
	status =
	    acpi_hw_disable_gpe_block(gpe_block->xrupt_block, gpe_block, NULL);
L
Linus Torvalds 已提交
702 703

	if (!gpe_block->previous && !gpe_block->next) {
B
Bob Moore 已提交
704

L
Linus Torvalds 已提交
705 706
		/* This is the last gpe_block on this interrupt */

L
Len Brown 已提交
707 708
		status = acpi_ev_delete_gpe_xrupt(gpe_block->xrupt_block);
		if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
709 710
			goto unlock_and_exit;
		}
L
Len Brown 已提交
711
	} else {
L
Linus Torvalds 已提交
712 713
		/* Remove the block on this interrupt with lock */

L
Len Brown 已提交
714
		flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
L
Linus Torvalds 已提交
715 716
		if (gpe_block->previous) {
			gpe_block->previous->next = gpe_block->next;
L
Len Brown 已提交
717 718 719
		} else {
			gpe_block->xrupt_block->gpe_block_list_head =
			    gpe_block->next;
L
Linus Torvalds 已提交
720 721 722 723 724
		}

		if (gpe_block->next) {
			gpe_block->next->previous = gpe_block->previous;
		}
L
Len Brown 已提交
725
		acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
L
Linus Torvalds 已提交
726 727
	}

728 729 730
	acpi_current_gpe_count -=
	    gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH;

L
Linus Torvalds 已提交
731 732
	/* Free the gpe_block */

B
Bob Moore 已提交
733 734 735
	ACPI_FREE(gpe_block->register_info);
	ACPI_FREE(gpe_block->event_info);
	ACPI_FREE(gpe_block);
L
Linus Torvalds 已提交
736

L
Len Brown 已提交
737 738 739
      unlock_and_exit:
	status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_create_gpe_info_blocks
 *
 * PARAMETERS:  gpe_block   - New GPE block
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Create the register_info and event_info blocks for this GPE block
 *
 ******************************************************************************/

static acpi_status
L
Len Brown 已提交
755
acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
L
Linus Torvalds 已提交
756
{
L
Len Brown 已提交
757 758 759 760
	struct acpi_gpe_register_info *gpe_register_info = NULL;
	struct acpi_gpe_event_info *gpe_event_info = NULL;
	struct acpi_gpe_event_info *this_event;
	struct acpi_gpe_register_info *this_register;
761 762
	u32 i;
	u32 j;
L
Len Brown 已提交
763
	acpi_status status;
L
Linus Torvalds 已提交
764

B
Bob Moore 已提交
765
	ACPI_FUNCTION_TRACE(ev_create_gpe_info_blocks);
L
Linus Torvalds 已提交
766 767 768

	/* Allocate the GPE register information block */

B
Bob Moore 已提交
769 770 771 772
	gpe_register_info = ACPI_ALLOCATE_ZEROED((acpi_size) gpe_block->
						 register_count *
						 sizeof(struct
							acpi_gpe_register_info));
L
Linus Torvalds 已提交
773
	if (!gpe_register_info) {
B
Bob Moore 已提交
774
		ACPI_ERROR((AE_INFO,
B
Bob Moore 已提交
775
			    "Could not allocate the GpeRegisterInfo table"));
L
Len Brown 已提交
776
		return_ACPI_STATUS(AE_NO_MEMORY);
L
Linus Torvalds 已提交
777 778 779 780
	}

	/*
	 * Allocate the GPE event_info block. There are eight distinct GPEs
B
Bob Moore 已提交
781
	 * per register. Initialization to zeros is sufficient.
L
Linus Torvalds 已提交
782
	 */
B
Bob Moore 已提交
783 784 785 786 787
	gpe_event_info = ACPI_ALLOCATE_ZEROED(((acpi_size) gpe_block->
					       register_count *
					       ACPI_GPE_REGISTER_WIDTH) *
					      sizeof(struct
						     acpi_gpe_event_info));
L
Linus Torvalds 已提交
788
	if (!gpe_event_info) {
B
Bob Moore 已提交
789
		ACPI_ERROR((AE_INFO,
B
Bob Moore 已提交
790
			    "Could not allocate the GpeEventInfo table"));
L
Linus Torvalds 已提交
791 792 793 794 795 796 797
		status = AE_NO_MEMORY;
		goto error_exit;
	}

	/* Save the new Info arrays in the GPE block */

	gpe_block->register_info = gpe_register_info;
L
Len Brown 已提交
798
	gpe_block->event_info = gpe_event_info;
L
Linus Torvalds 已提交
799 800

	/*
B
Bob Moore 已提交
801
	 * Initialize the GPE Register and Event structures. A goal of these
802 803 804
	 * tables is to hide the fact that there are two separate GPE register
	 * sets in a given GPE hardware block, the status registers occupy the
	 * first half, and the enable registers occupy the second half.
L
Linus Torvalds 已提交
805 806
	 */
	this_register = gpe_register_info;
L
Len Brown 已提交
807
	this_event = gpe_event_info;
L
Linus Torvalds 已提交
808 809

	for (i = 0; i < gpe_block->register_count; i++) {
B
Bob Moore 已提交
810

L
Linus Torvalds 已提交
811 812
		/* Init the register_info for this GPE register (8 GPEs) */

L
Len Brown 已提交
813 814 815 816
		this_register->base_gpe_number =
		    (u8) (gpe_block->block_base_number +
			  (i * ACPI_GPE_REGISTER_WIDTH));

B
Bob Moore 已提交
817 818
		this_register->status_address.address =
		    gpe_block->block_address.address + i;
L
Len Brown 已提交
819

B
Bob Moore 已提交
820 821 822
		this_register->enable_address.address =
		    gpe_block->block_address.address + i +
		    gpe_block->register_count;
L
Len Brown 已提交
823

824 825 826 827 828
		this_register->status_address.space_id =
		    gpe_block->block_address.space_id;
		this_register->enable_address.space_id =
		    gpe_block->block_address.space_id;
		this_register->status_address.bit_width =
L
Len Brown 已提交
829
		    ACPI_GPE_REGISTER_WIDTH;
830
		this_register->enable_address.bit_width =
L
Len Brown 已提交
831
		    ACPI_GPE_REGISTER_WIDTH;
832 833
		this_register->status_address.bit_offset = 0;
		this_register->enable_address.bit_offset = 0;
L
Linus Torvalds 已提交
834 835 836 837

		/* Init the event_info for each GPE within this register */

		for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
838 839
			this_event->gpe_number =
			    (u8) (this_register->base_gpe_number + j);
L
Linus Torvalds 已提交
840 841 842 843
			this_event->register_info = this_register;
			this_event++;
		}

B
Bob Moore 已提交
844 845
		/* Disable all GPEs within this register */

846
		status = acpi_write(0x00, &this_register->enable_address);
L
Len Brown 已提交
847
		if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
848 849 850
			goto error_exit;
		}

B
Bob Moore 已提交
851 852
		/* Clear any pending GPE events within this register */

853
		status = acpi_write(0xFF, &this_register->status_address);
L
Len Brown 已提交
854
		if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
855 856 857 858 859 860
			goto error_exit;
		}

		this_register++;
	}

L
Len Brown 已提交
861
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
862

L
Len Brown 已提交
863
      error_exit:
L
Linus Torvalds 已提交
864
	if (gpe_register_info) {
B
Bob Moore 已提交
865
		ACPI_FREE(gpe_register_info);
L
Linus Torvalds 已提交
866 867
	}
	if (gpe_event_info) {
B
Bob Moore 已提交
868
		ACPI_FREE(gpe_event_info);
L
Linus Torvalds 已提交
869 870
	}

L
Len Brown 已提交
871
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
872 873 874 875 876 877 878 879 880 881
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_create_gpe_block
 *
 * PARAMETERS:  gpe_device          - Handle to the parent GPE block
 *              gpe_block_address   - Address and space_iD
 *              register_count      - Number of GPE register pairs in the block
 *              gpe_block_base_number - Starting GPE number for the block
882
 *              interrupt_number    - H/W interrupt for the block
L
Linus Torvalds 已提交
883 884 885 886
 *              return_gpe_block    - Where the new block descriptor is returned
 *
 * RETURN:      Status
 *
B
Bob Moore 已提交
887 888 889
 * DESCRIPTION: Create and Install a block of GPE registers. All GPEs within
 *              the block are disabled at exit.
 *              Note: Assumes namespace is locked.
L
Linus Torvalds 已提交
890 891 892 893
 *
 ******************************************************************************/

acpi_status
L
Len Brown 已提交
894 895 896 897 898 899
acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
			 struct acpi_generic_address *gpe_block_address,
			 u32 register_count,
			 u8 gpe_block_base_number,
			 u32 interrupt_number,
			 struct acpi_gpe_block_info **return_gpe_block)
L
Linus Torvalds 已提交
900
{
L
Len Brown 已提交
901
	acpi_status status;
B
Bob Moore 已提交
902
	struct acpi_gpe_block_info *gpe_block;
L
Linus Torvalds 已提交
903

B
Bob Moore 已提交
904
	ACPI_FUNCTION_TRACE(ev_create_gpe_block);
L
Linus Torvalds 已提交
905 906

	if (!register_count) {
L
Len Brown 已提交
907
		return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
908 909 910 911
	}

	/* Allocate a new GPE block */

B
Bob Moore 已提交
912
	gpe_block = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_block_info));
L
Linus Torvalds 已提交
913
	if (!gpe_block) {
L
Len Brown 已提交
914
		return_ACPI_STATUS(AE_NO_MEMORY);
L
Linus Torvalds 已提交
915 916 917 918
	}

	/* Initialize the new GPE block */

B
Bob Moore 已提交
919
	gpe_block->node = gpe_device;
L
Linus Torvalds 已提交
920 921 922
	gpe_block->register_count = register_count;
	gpe_block->block_base_number = gpe_block_base_number;

L
Len Brown 已提交
923 924
	ACPI_MEMCPY(&gpe_block->block_address, gpe_block_address,
		    sizeof(struct acpi_generic_address));
L
Linus Torvalds 已提交
925

B
Bob Moore 已提交
926 927 928 929
	/*
	 * Create the register_info and event_info sub-structures
	 * Note: disables and clears all GPEs in the block
	 */
L
Len Brown 已提交
930 931
	status = acpi_ev_create_gpe_info_blocks(gpe_block);
	if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
932
		ACPI_FREE(gpe_block);
L
Len Brown 已提交
933
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
934 935
	}

B
Bob Moore 已提交
936
	/* Install the new block in the global lists */
L
Linus Torvalds 已提交
937

L
Len Brown 已提交
938 939
	status = acpi_ev_install_gpe_block(gpe_block, interrupt_number);
	if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
940
		ACPI_FREE(gpe_block);
L
Len Brown 已提交
941
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
942 943 944 945
	}

	/* Find all GPE methods (_Lxx, _Exx) for this block */

L
Len Brown 已提交
946 947 948 949
	status = acpi_ns_walk_namespace(ACPI_TYPE_METHOD, gpe_device,
					ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK,
					acpi_ev_save_method_info, gpe_block,
					NULL);
L
Linus Torvalds 已提交
950

B
Bob Moore 已提交
951 952 953 954 955 956 957 958 959 960 961 962 963 964 965
	/* Return the new block */

	if (return_gpe_block) {
		(*return_gpe_block) = gpe_block;
	}

	ACPI_DEBUG_PRINT((ACPI_DB_INIT,
			  "GPE %02X to %02X [%4.4s] %u regs on int 0x%X\n",
			  (u32) gpe_block->block_base_number,
			  (u32) (gpe_block->block_base_number +
				 ((gpe_block->register_count *
				   ACPI_GPE_REGISTER_WIDTH) - 1)),
			  gpe_device->name.ascii, gpe_block->register_count,
			  interrupt_number));

966 967 968
	/* Update global count of currently available GPEs */

	acpi_current_gpe_count += register_count * ACPI_GPE_REGISTER_WIDTH;
B
Bob Moore 已提交
969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996
	return_ACPI_STATUS(AE_OK);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_initialize_gpe_block
 *
 * PARAMETERS:  gpe_device          - Handle to the parent GPE block
 *              gpe_block           - Gpe Block info
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Initialize and enable a GPE block. First find and run any
 *              _PRT methods associated with the block, then enable the
 *              appropriate GPEs.
 *              Note: Assumes namespace is locked.
 *
 ******************************************************************************/

acpi_status
acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
			     struct acpi_gpe_block_info *gpe_block)
{
	acpi_status status;
	struct acpi_gpe_event_info *gpe_event_info;
	struct acpi_gpe_walk_info gpe_info;
	u32 wake_gpe_count;
	u32 gpe_enabled_count;
997 998
	u32 i;
	u32 j;
B
Bob Moore 已提交
999

B
Bob Moore 已提交
1000
	ACPI_FUNCTION_TRACE(ev_initialize_gpe_block);
B
Bob Moore 已提交
1001 1002 1003 1004 1005 1006 1007

	/* Ignore a null GPE block (e.g., if no GPE block 1 exists) */

	if (!gpe_block) {
		return_ACPI_STATUS(AE_OK);
	}

L
Linus Torvalds 已提交
1008
	/*
B
Bob Moore 已提交
1009 1010
	 * Runtime option: Should wake GPEs be enabled at runtime?  The default
	 * is no, they should only be enabled just as the machine goes to sleep.
L
Linus Torvalds 已提交
1011 1012 1013
	 */
	if (acpi_gbl_leave_wake_gpes_disabled) {
		/*
B
Bob Moore 已提交
1014 1015 1016 1017
		 * Differentiate runtime vs wake GPEs, via the _PRW control methods.
		 * Each GPE that has one or more _PRWs that reference it is by
		 * definition a wake GPE and will not be enabled while the machine
		 * is running.
L
Linus Torvalds 已提交
1018 1019 1020 1021
		 */
		gpe_info.gpe_block = gpe_block;
		gpe_info.gpe_device = gpe_device;

L
Len Brown 已提交
1022 1023 1024 1025 1026
		status =
		    acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
					   ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK,
					   acpi_ev_match_prw_and_gpe, &gpe_info,
					   NULL);
L
Linus Torvalds 已提交
1027 1028 1029
	}

	/*
B
Bob Moore 已提交
1030 1031 1032 1033
	 * Enable all GPEs in this block that have these attributes:
	 * 1) are "runtime" or "run/wake" GPEs, and
	 * 2) have a corresponding _Lxx or _Exx method
	 *
1034 1035
	 * Any other GPEs within this block must be enabled via the
	 * acpi_enable_gpe() external interface.
L
Linus Torvalds 已提交
1036 1037 1038 1039 1040 1041
	 */
	wake_gpe_count = 0;
	gpe_enabled_count = 0;

	for (i = 0; i < gpe_block->register_count; i++) {
		for (j = 0; j < 8; j++) {
B
Bob Moore 已提交
1042

L
Linus Torvalds 已提交
1043 1044
			/* Get the info block for this particular GPE */

1045 1046 1047
			gpe_event_info = &gpe_block->event_info[((acpi_size) i *
								 ACPI_GPE_REGISTER_WIDTH)
								+ j];
L
Linus Torvalds 已提交
1048

L
Len Brown 已提交
1049
			if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
1050 1051
			     ACPI_GPE_DISPATCH_METHOD) &&
			    (gpe_event_info->flags & ACPI_GPE_TYPE_RUNTIME)) {
L
Linus Torvalds 已提交
1052 1053 1054 1055 1056 1057 1058 1059 1060
				gpe_enabled_count++;
			}

			if (gpe_event_info->flags & ACPI_GPE_TYPE_WAKE) {
				wake_gpe_count++;
			}
		}
	}

L
Len Brown 已提交
1061 1062 1063
	ACPI_DEBUG_PRINT((ACPI_DB_INIT,
			  "Found %u Wake, Enabled %u Runtime GPEs in this block\n",
			  wake_gpe_count, gpe_enabled_count));
L
Linus Torvalds 已提交
1064

B
Bob Moore 已提交
1065
	/* Enable all valid runtime GPEs found above */
L
Linus Torvalds 已提交
1066

1067
	status = acpi_hw_enable_runtime_gpe_block(NULL, gpe_block, NULL);
B
Bob Moore 已提交
1068
	if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
1069
		ACPI_ERROR((AE_INFO, "Could not enable GPEs in GpeBlock %p",
B
Bob Moore 已提交
1070
			    gpe_block));
L
Linus Torvalds 已提交
1071 1072
	}

B
Bob Moore 已提交
1073
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_gpe_initialize
 *
 * PARAMETERS:  None
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Initialize the GPE data structures
 *
 ******************************************************************************/

L
Len Brown 已提交
1088
acpi_status acpi_ev_gpe_initialize(void)
L
Linus Torvalds 已提交
1089
{
L
Len Brown 已提交
1090 1091 1092 1093
	u32 register_count0 = 0;
	u32 register_count1 = 0;
	u32 gpe_number_max = 0;
	acpi_status status;
L
Linus Torvalds 已提交
1094

B
Bob Moore 已提交
1095
	ACPI_FUNCTION_TRACE(ev_gpe_initialize);
L
Linus Torvalds 已提交
1096

L
Len Brown 已提交
1097 1098 1099
	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
1100 1101 1102 1103 1104
	}

	/*
	 * Initialize the GPE Block(s) defined in the FADT
	 *
1105 1106
	 * Why the GPE register block lengths are divided by 2:  From the ACPI
	 * Spec, section "General-Purpose Event Registers", we have:
L
Linus Torvalds 已提交
1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126
	 *
	 * "Each register block contains two registers of equal length
	 *  GPEx_STS and GPEx_EN (where x is 0 or 1). The length of the
	 *  GPE0_STS and GPE0_EN registers is equal to half the GPE0_LEN
	 *  The length of the GPE1_STS and GPE1_EN registers is equal to
	 *  half the GPE1_LEN. If a generic register block is not supported
	 *  then its respective block pointer and block length values in the
	 *  FADT table contain zeros. The GPE0_LEN and GPE1_LEN do not need
	 *  to be the same size."
	 */

	/*
	 * Determine the maximum GPE number for this machine.
	 *
	 * Note: both GPE0 and GPE1 are optional, and either can exist without
	 * the other.
	 *
	 * If EITHER the register length OR the block address are zero, then that
	 * particular block is not supported.
	 */
1127 1128
	if (acpi_gbl_FADT.gpe0_block_length &&
	    acpi_gbl_FADT.xgpe0_block.address) {
B
Bob Moore 已提交
1129

L
Linus Torvalds 已提交
1130 1131
		/* GPE block 0 exists (has both length and address > 0) */

1132
		register_count0 = (u16) (acpi_gbl_FADT.gpe0_block_length / 2);
L
Linus Torvalds 已提交
1133

L
Len Brown 已提交
1134 1135
		gpe_number_max =
		    (register_count0 * ACPI_GPE_REGISTER_WIDTH) - 1;
L
Linus Torvalds 已提交
1136 1137 1138

		/* Install GPE Block 0 */

L
Len Brown 已提交
1139
		status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
1140
						  &acpi_gbl_FADT.xgpe0_block,
L
Len Brown 已提交
1141
						  register_count0, 0,
1142
						  acpi_gbl_FADT.sci_interrupt,
L
Len Brown 已提交
1143
						  &acpi_gbl_gpe_fadt_blocks[0]);
L
Linus Torvalds 已提交
1144

L
Len Brown 已提交
1145
		if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
1146 1147
			ACPI_EXCEPTION((AE_INFO, status,
					"Could not create GPE Block 0"));
L
Linus Torvalds 已提交
1148 1149 1150
		}
	}

1151 1152
	if (acpi_gbl_FADT.gpe1_block_length &&
	    acpi_gbl_FADT.xgpe1_block.address) {
B
Bob Moore 已提交
1153

L
Linus Torvalds 已提交
1154 1155
		/* GPE block 1 exists (has both length and address > 0) */

1156
		register_count1 = (u16) (acpi_gbl_FADT.gpe1_block_length / 2);
L
Linus Torvalds 已提交
1157 1158 1159 1160

		/* Check for GPE0/GPE1 overlap (if both banks exist) */

		if ((register_count0) &&
1161
		    (gpe_number_max >= acpi_gbl_FADT.gpe1_base)) {
B
Bob Moore 已提交
1162
			ACPI_ERROR((AE_INFO,
1163 1164
				    "GPE0 block (GPE 0 to %d) overlaps the GPE1 block "
				    "(GPE %d to %d) - Ignoring GPE1",
1165 1166
				    gpe_number_max, acpi_gbl_FADT.gpe1_base,
				    acpi_gbl_FADT.gpe1_base +
B
Bob Moore 已提交
1167 1168
				    ((register_count1 *
				      ACPI_GPE_REGISTER_WIDTH) - 1)));
L
Linus Torvalds 已提交
1169 1170 1171 1172

			/* Ignore GPE1 block by setting the register count to zero */

			register_count1 = 0;
L
Len Brown 已提交
1173
		} else {
L
Linus Torvalds 已提交
1174 1175
			/* Install GPE Block 1 */

L
Len Brown 已提交
1176 1177
			status =
			    acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
1178
						     &acpi_gbl_FADT.xgpe1_block,
L
Len Brown 已提交
1179
						     register_count1,
1180 1181 1182
						     acpi_gbl_FADT.gpe1_base,
						     acpi_gbl_FADT.
						     sci_interrupt,
L
Len Brown 已提交
1183 1184 1185 1186
						     &acpi_gbl_gpe_fadt_blocks
						     [1]);

			if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
1187 1188
				ACPI_EXCEPTION((AE_INFO, status,
						"Could not create GPE Block 1"));
L
Linus Torvalds 已提交
1189 1190 1191 1192 1193 1194
			}

			/*
			 * GPE0 and GPE1 do not have to be contiguous in the GPE number
			 * space. However, GPE0 always starts at GPE number zero.
			 */
1195
			gpe_number_max = acpi_gbl_FADT.gpe1_base +
L
Len Brown 已提交
1196
			    ((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1);
L
Linus Torvalds 已提交
1197 1198 1199 1200 1201 1202
		}
	}

	/* Exit if there are no GPE registers */

	if ((register_count0 + register_count1) == 0) {
B
Bob Moore 已提交
1203

L
Linus Torvalds 已提交
1204 1205
		/* GPEs are not required by ACPI, this is OK */

L
Len Brown 已提交
1206 1207
		ACPI_DEBUG_PRINT((ACPI_DB_INIT,
				  "There are no GPE blocks defined in the FADT\n"));
L
Linus Torvalds 已提交
1208 1209 1210 1211 1212 1213 1214
		status = AE_OK;
		goto cleanup;
	}

	/* Check for Max GPE number out-of-range */

	if (gpe_number_max > ACPI_GPE_MAX) {
B
Bob Moore 已提交
1215 1216 1217
		ACPI_ERROR((AE_INFO,
			    "Maximum GPE number from FADT is too large: 0x%X",
			    gpe_number_max));
L
Linus Torvalds 已提交
1218 1219 1220 1221
		status = AE_BAD_VALUE;
		goto cleanup;
	}

L
Len Brown 已提交
1222 1223 1224
      cleanup:
	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
1225
}