evgpe.c 19.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7
/******************************************************************************
 *
 * Module Name: evgpe - General Purpose Event handling and dispatch
 *
 *****************************************************************************/

/*
8
 * Copyright (C) 2000 - 2010, 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("evgpe")
L
Linus Torvalds 已提交
51

R
Robert Moore 已提交
52
/* Local prototypes */
L
Len Brown 已提交
53
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context);
L
Linus Torvalds 已提交
54 55 56 57 58 59 60 61 62

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_update_gpe_enable_masks
 *
 * PARAMETERS:  gpe_event_info          - GPE to update
 *
 * RETURN:      Status
 *
63 64
 * DESCRIPTION: Updates GPE register enable masks based upon whether there are
 *              references (either wake or run) to this GPE
L
Linus Torvalds 已提交
65 66 67 68
 *
 ******************************************************************************/

acpi_status
69
acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info)
L
Linus Torvalds 已提交
70
{
L
Len Brown 已提交
71 72
	struct acpi_gpe_register_info *gpe_register_info;
	u8 register_bit;
L
Linus Torvalds 已提交
73

B
Bob Moore 已提交
74
	ACPI_FUNCTION_TRACE(ev_update_gpe_enable_masks);
L
Linus Torvalds 已提交
75 76 77

	gpe_register_info = gpe_event_info->register_info;
	if (!gpe_register_info) {
L
Len Brown 已提交
78
		return_ACPI_STATUS(AE_NOT_EXIST);
L
Linus Torvalds 已提交
79
	}
80

81 82 83
	register_bit = (u8)
	    (1 <<
	     (gpe_event_info->gpe_number - gpe_register_info->base_gpe_number));
L
Linus Torvalds 已提交
84

85 86
	/* Clear the wake/run bits up front */

87 88
	ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake, register_bit);
	ACPI_CLEAR_BIT(gpe_register_info->enable_for_run, register_bit);
L
Linus Torvalds 已提交
89

90 91 92
	/* Set the mask bits only if there are references to this GPE */

	if (gpe_event_info->runtime_count) {
L
Len Brown 已提交
93
		ACPI_SET_BIT(gpe_register_info->enable_for_run, register_bit);
94
	}
L
Linus Torvalds 已提交
95

96
	if (gpe_event_info->wakeup_count) {
L
Len Brown 已提交
97
		ACPI_SET_BIT(gpe_register_info->enable_for_wake, register_bit);
98
	}
L
Linus Torvalds 已提交
99

L
Len Brown 已提交
100
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
101 102 103 104 105 106 107 108 109 110
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_enable_gpe
 *
 * PARAMETERS:  gpe_event_info          - GPE to enable
 *
 * RETURN:      Status
 *
111 112 113 114
 * DESCRIPTION: Hardware-enable a GPE. Always enables the GPE, regardless
 *              of type or number of references.
 *
 * Note: The GPE lock should be already acquired when this function is called.
L
Linus Torvalds 已提交
115 116 117
 *
 ******************************************************************************/

118
acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
L
Linus Torvalds 已提交
119
{
L
Len Brown 已提交
120
	acpi_status status;
L
Linus Torvalds 已提交
121

122

B
Bob Moore 已提交
123
	ACPI_FUNCTION_TRACE(ev_enable_gpe);
L
Linus Torvalds 已提交
124

125 126 127 128 129 130 131 132 133 134 135 136

	/*
	 * We will only allow a GPE to be enabled if it has either an
	 * associated method (_Lxx/_Exx) or a handler. Otherwise, the
	 * GPE will be immediately disabled by acpi_ev_gpe_dispatch the
	 * first time it fires.
	 */
	if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)) {
		return_ACPI_STATUS(AE_NO_HANDLER);
	}

	/* Ensure the HW enable masks are current */
L
Linus Torvalds 已提交
137

138
	status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
139
	if (ACPI_FAILURE(status)) {
L
Len Brown 已提交
140
		return_ACPI_STATUS(status);
141 142 143
	}

	/* Clear the GPE (of stale events) */
L
Linus Torvalds 已提交
144

145
	status = acpi_hw_clear_gpe(gpe_event_info);
146
	if (ACPI_FAILURE(status)) {
147
		return_ACPI_STATUS(status);
148
	}
L
Linus Torvalds 已提交
149

150
	/* Enable the requested GPE */
151

152 153
	status = acpi_hw_write_gpe_enable_reg(gpe_event_info);
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
154 155 156 157 158 159 160 161 162 163
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_disable_gpe
 *
 * PARAMETERS:  gpe_event_info          - GPE to disable
 *
 * RETURN:      Status
 *
164 165 166 167
 * DESCRIPTION: Hardware-disable a GPE. Always disables the requested GPE,
 *              regardless of the type or number of references.
 *
 * Note: The GPE lock should be already acquired when this function is called.
L
Linus Torvalds 已提交
168 169 170
 *
 ******************************************************************************/

L
Len Brown 已提交
171
acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
L
Linus Torvalds 已提交
172
{
L
Len Brown 已提交
173
	acpi_status status;
L
Linus Torvalds 已提交
174

B
Bob Moore 已提交
175
	ACPI_FUNCTION_TRACE(ev_disable_gpe);
L
Linus Torvalds 已提交
176

177 178 179 180 181 182 183 184

	/*
	 * Note: Always disable the GPE, even if we think that that it is already
	 * disabled. It is possible that the AML or some other code has enabled
	 * the GPE behind our back.
	 */

	/* Ensure the HW enable masks are current */
L
Linus Torvalds 已提交
185

186
	status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
187
	if (ACPI_FAILURE(status)) {
L
Len Brown 已提交
188
		return_ACPI_STATUS(status);
189
	}
L
Linus Torvalds 已提交
190

B
Bob Moore 已提交
191
	/*
192 193 194 195 196 197
	 * Always H/W disable this GPE, even if we don't know the GPE type.
	 * Simply clear the enable bit for this particular GPE, but do not
	 * write out the current GPE enable mask since this may inadvertently
	 * enable GPEs too early. An example is a rogue GPE that has arrived
	 * during ACPICA initialization - possibly because AML or other code
	 * has enabled the GPE.
B
Bob Moore 已提交
198 199 200
	 */
	status = acpi_hw_low_disable_gpe(gpe_event_info);
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
201 202
}

203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_low_get_gpe_info
 *
 * PARAMETERS:  gpe_number          - Raw GPE number
 *              gpe_block           - A GPE info block
 *
 * RETURN:      A GPE event_info struct. NULL if not a valid GPE (The gpe_number
 *              is not within the specified GPE block)
 *
 * DESCRIPTION: Returns the event_info struct associated with this GPE. This is
 *              the low-level implementation of ev_get_gpe_event_info.
 *
 ******************************************************************************/

struct acpi_gpe_event_info *acpi_ev_low_get_gpe_info(u32 gpe_number,
						     struct acpi_gpe_block_info
						     *gpe_block)
{
	u32 gpe_index;

	/*
	 * Validate that the gpe_number is within the specified gpe_block.
	 * (Two steps)
	 */
	if (!gpe_block || (gpe_number < gpe_block->block_base_number)) {
		return (NULL);
	}

	gpe_index = gpe_number - gpe_block->block_base_number;
	if (gpe_index >= gpe_block->gpe_count) {
		return (NULL);
	}

	return (&gpe_block->event_info[gpe_index]);
}


L
Linus Torvalds 已提交
242 243 244 245
/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_get_gpe_event_info
 *
246
 * PARAMETERS:  gpe_device          - Device node. NULL for GPE0/GPE1
L
Linus Torvalds 已提交
247 248 249 250 251 252 253 254 255 256 257 258
 *              gpe_number          - Raw GPE number
 *
 * RETURN:      A GPE event_info struct. NULL if not a valid GPE
 *
 * DESCRIPTION: Returns the event_info struct associated with this GPE.
 *              Validates the gpe_block and the gpe_number
 *
 *              Should be called only when the GPE lists are semaphore locked
 *              and not subject to change.
 *
 ******************************************************************************/

L
Len Brown 已提交
259 260
struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device,
						       u32 gpe_number)
L
Linus Torvalds 已提交
261
{
L
Len Brown 已提交
262
	union acpi_operand_object *obj_desc;
263
	struct acpi_gpe_event_info *gpe_info;
264
	u32 i;
L
Linus Torvalds 已提交
265

L
Len Brown 已提交
266
	ACPI_FUNCTION_ENTRY();
L
Linus Torvalds 已提交
267 268 269 270

	/* A NULL gpe_block means use the FADT-defined GPE block(s) */

	if (!gpe_device) {
B
Bob Moore 已提交
271

L
Linus Torvalds 已提交
272 273 274
		/* Examine GPE Block 0 and 1 (These blocks are permanent) */

		for (i = 0; i < ACPI_MAX_GPE_BLOCKS; i++) {
275 276 277 278 279
			gpe_info = acpi_ev_low_get_gpe_info(gpe_number,
							    acpi_gbl_gpe_fadt_blocks
							    [i]);
			if (gpe_info) {
				return (gpe_info);
L
Linus Torvalds 已提交
280 281 282 283 284 285 286 287 288 289
			}
		}

		/* The gpe_number was not in the range of either FADT GPE block */

		return (NULL);
	}

	/* A Non-NULL gpe_device means this is a GPE Block Device */

L
Len Brown 已提交
290 291
	obj_desc = acpi_ns_get_attached_object((struct acpi_namespace_node *)
					       gpe_device);
L
Len Brown 已提交
292
	if (!obj_desc || !obj_desc->device.gpe_block) {
L
Linus Torvalds 已提交
293 294 295
		return (NULL);
	}

296 297
	return (acpi_ev_low_get_gpe_info
		(gpe_number, obj_desc->device.gpe_block));
L
Linus Torvalds 已提交
298 299 300 301 302 303 304 305 306 307 308
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_gpe_detect
 *
 * PARAMETERS:  gpe_xrupt_list      - Interrupt block for this interrupt.
 *                                    Can have multiple GPE blocks attached.
 *
 * RETURN:      INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
 *
309
 * DESCRIPTION: Detect if any GP events have occurred. This function is
L
Linus Torvalds 已提交
310 311 312 313
 *              executed at interrupt level.
 *
 ******************************************************************************/

L
Len Brown 已提交
314
u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
L
Linus Torvalds 已提交
315
{
B
Bob Moore 已提交
316 317 318
	acpi_status status;
	struct acpi_gpe_block_info *gpe_block;
	struct acpi_gpe_register_info *gpe_register_info;
L
Len Brown 已提交
319 320 321 322
	u32 int_status = ACPI_INTERRUPT_NOT_HANDLED;
	u8 enabled_status_byte;
	u32 status_reg;
	u32 enable_reg;
B
Bob Moore 已提交
323
	acpi_cpu_flags flags;
324 325
	u32 i;
	u32 j;
L
Len Brown 已提交
326

B
Bob Moore 已提交
327
	ACPI_FUNCTION_NAME(ev_gpe_detect);
L
Linus Torvalds 已提交
328 329 330 331 332 333 334

	/* Check for the case where there are no GPEs */

	if (!gpe_xrupt_list) {
		return (int_status);
	}

B
Bob Moore 已提交
335 336
	/*
	 * We need to obtain the GPE lock for both the data structs and registers
337 338
	 * Note: Not necessary to obtain the hardware lock, since the GPE
	 * registers are owned by the gpe_lock.
B
Bob Moore 已提交
339
	 */
L
Len Brown 已提交
340
	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
B
Bob Moore 已提交
341 342 343

	/* Examine all GPE blocks attached to this interrupt level */

L
Linus Torvalds 已提交
344 345 346
	gpe_block = gpe_xrupt_list->gpe_block_list_head;
	while (gpe_block) {
		/*
347 348
		 * Read all of the 8-bit GPE status and enable registers in this GPE
		 * block, saving all of them. Find all currently active GP events.
L
Linus Torvalds 已提交
349 350
		 */
		for (i = 0; i < gpe_block->register_count; i++) {
B
Bob Moore 已提交
351

L
Linus Torvalds 已提交
352 353 354 355 356 357
			/* Get the next status/enable pair */

			gpe_register_info = &gpe_block->register_info[i];

			/* Read the Status Register */

L
Len Brown 已提交
358
			status =
359 360
			    acpi_hw_read(&status_reg,
					 &gpe_register_info->status_address);
L
Len Brown 已提交
361
			if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
362 363 364 365 366
				goto unlock_and_exit;
			}

			/* Read the Enable Register */

L
Len Brown 已提交
367
			status =
368 369
			    acpi_hw_read(&enable_reg,
					 &gpe_register_info->enable_address);
L
Len Brown 已提交
370
			if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
371 372 373
				goto unlock_and_exit;
			}

L
Len Brown 已提交
374 375 376 377
			ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS,
					  "Read GPE Register at GPE%X: Status=%02X, Enable=%02X\n",
					  gpe_register_info->base_gpe_number,
					  status_reg, enable_reg));
L
Linus Torvalds 已提交
378

R
Robert Moore 已提交
379
			/* Check if there is anything active at all in this register */
L
Linus Torvalds 已提交
380 381 382

			enabled_status_byte = (u8) (status_reg & enable_reg);
			if (!enabled_status_byte) {
B
Bob Moore 已提交
383

L
Linus Torvalds 已提交
384 385 386 387 388 389 390 391
				/* No active GPEs in this register, move on */

				continue;
			}

			/* Now look at the individual GPEs in this byte register */

			for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
B
Bob Moore 已提交
392

L
Linus Torvalds 已提交
393 394
				/* Examine one GPE bit */

395
				if (enabled_status_byte & (1 << j)) {
L
Linus Torvalds 已提交
396 397 398 399
					/*
					 * Found an active GPE. Dispatch the event to a handler
					 * or method.
					 */
L
Len Brown 已提交
400 401
					int_status |=
					    acpi_ev_gpe_dispatch(&gpe_block->
402
						event_info[((acpi_size) i * ACPI_GPE_REGISTER_WIDTH) + j], j + gpe_register_info->base_gpe_number);
L
Linus Torvalds 已提交
403 404 405 406 407 408 409
				}
			}
		}

		gpe_block = gpe_block->next;
	}

L
Len Brown 已提交
410
      unlock_and_exit:
L
Linus Torvalds 已提交
411

L
Len Brown 已提交
412
	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
L
Linus Torvalds 已提交
413 414 415 416 417 418 419 420 421 422 423
	return (int_status);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_asynch_execute_gpe_method
 *
 * PARAMETERS:  Context (gpe_event_info) - Info for this GPE
 *
 * RETURN:      None
 *
B
Bob Moore 已提交
424 425 426
 * DESCRIPTION: Perform the actual execution of a GPE control method. This
 *              function is called from an invocation of acpi_os_execute and
 *              therefore does NOT execute at interrupt level - so that
L
Linus Torvalds 已提交
427 428 429 430
 *              the control method itself is not executed in the context of
 *              an interrupt handler.
 *
 ******************************************************************************/
431
static void acpi_ev_asynch_enable_gpe(void *context);
L
Linus Torvalds 已提交
432

L
Len Brown 已提交
433
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
L
Linus Torvalds 已提交
434
{
L
Len Brown 已提交
435 436 437
	struct acpi_gpe_event_info *gpe_event_info = (void *)context;
	acpi_status status;
	struct acpi_gpe_event_info local_gpe_event_info;
B
Bob Moore 已提交
438
	struct acpi_evaluate_info *info;
L
Linus Torvalds 已提交
439

B
Bob Moore 已提交
440
	ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method);
L
Linus Torvalds 已提交
441

L
Len Brown 已提交
442 443
	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
	if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
444 445 446 447 448
		return_VOID;
	}

	/* Must revalidate the gpe_number/gpe_block */

L
Len Brown 已提交
449 450
	if (!acpi_ev_valid_gpe_event(gpe_event_info)) {
		status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
L
Linus Torvalds 已提交
451 452 453
		return_VOID;
	}

454
	/* Update the GPE register masks for return to enabled state */
L
Linus Torvalds 已提交
455

456
	(void)acpi_ev_update_gpe_enable_masks(gpe_event_info);
L
Linus Torvalds 已提交
457 458

	/*
459 460
	 * Take a snapshot of the GPE info for this level - we copy the info to
	 * prevent a race condition with remove_handler/remove_block.
L
Linus Torvalds 已提交
461
	 */
L
Len Brown 已提交
462 463
	ACPI_MEMCPY(&local_gpe_event_info, gpe_event_info,
		    sizeof(struct acpi_gpe_event_info));
L
Linus Torvalds 已提交
464

L
Len Brown 已提交
465 466
	status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
	if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
467 468 469 470
		return_VOID;
	}

	/*
471 472
	 * Must check for control method type dispatch one more time to avoid a
	 * race with ev_gpe_install_handler
L
Linus Torvalds 已提交
473
	 */
R
Robert Moore 已提交
474
	if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) ==
L
Len Brown 已提交
475
	    ACPI_GPE_DISPATCH_METHOD) {
L
Linus Torvalds 已提交
476

B
Bob Moore 已提交
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
		/* Allocate the evaluation information block */

		info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
		if (!info) {
			status = AE_NO_MEMORY;
		} else {
			/*
			 * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the _Lxx/_Exx
			 * control method that corresponds to this GPE
			 */
			info->prefix_node =
			    local_gpe_event_info.dispatch.method_node;
			info->flags = ACPI_IGNORE_RETURN_VALUE;

			status = acpi_ns_evaluate(info);
			ACPI_FREE(info);
		}

L
Len Brown 已提交
495
		if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
496
			ACPI_EXCEPTION((AE_INFO, status,
B
Bob Moore 已提交
497
					"while evaluating GPE method [%4.4s]",
B
Bob Moore 已提交
498 499
					acpi_ut_get_node_name
					(local_gpe_event_info.dispatch.
B
Bob Moore 已提交
500
					 method_node)));
L
Linus Torvalds 已提交
501 502
		}
	}
503 504 505 506 507
	/* Defer enabling of GPE until all notify handlers are done */
	acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_asynch_enable_gpe,
				gpe_event_info);
	return_VOID;
}
L
Linus Torvalds 已提交
508

509 510 511 512 513
static void acpi_ev_asynch_enable_gpe(void *context)
{
	struct acpi_gpe_event_info *gpe_event_info = context;
	acpi_status status;
	if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
L
Len Brown 已提交
514
	    ACPI_GPE_LEVEL_TRIGGERED) {
L
Linus Torvalds 已提交
515
		/*
516 517
		 * GPE is level-triggered, we clear the GPE status bit after handling
		 * the event.
L
Linus Torvalds 已提交
518
		 */
519
		status = acpi_hw_clear_gpe(gpe_event_info);
L
Len Brown 已提交
520
		if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
521 522 523 524 525
			return_VOID;
		}
	}

	/* Enable this GPE */
526
	(void)acpi_hw_write_gpe_enable_reg(gpe_event_info);
L
Linus Torvalds 已提交
527 528 529 530 531 532 533
	return_VOID;
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ev_gpe_dispatch
 *
R
Robert Moore 已提交
534
 * PARAMETERS:  gpe_event_info  - Info for this GPE
L
Linus Torvalds 已提交
535 536 537 538 539 540 541 542 543 544 545 546
 *              gpe_number      - Number relative to the parent GPE block
 *
 * RETURN:      INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
 *
 * DESCRIPTION: Dispatch a General Purpose Event to either a function (e.g. EC)
 *              or method (e.g. _Lxx/_Exx) handler.
 *
 *              This function executes at interrupt level.
 *
 ******************************************************************************/

u32
L
Len Brown 已提交
547
acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
L
Linus Torvalds 已提交
548
{
L
Len Brown 已提交
549
	acpi_status status;
L
Linus Torvalds 已提交
550

B
Bob Moore 已提交
551
	ACPI_FUNCTION_TRACE(ev_gpe_dispatch);
L
Linus Torvalds 已提交
552

553
	acpi_os_gpe_count(gpe_number);
554

L
Linus Torvalds 已提交
555
	/*
556
	 * If edge-triggered, clear the GPE status bit now. Note that
L
Linus Torvalds 已提交
557 558
	 * level-triggered events are cleared after the GPE is serviced.
	 */
R
Robert Moore 已提交
559
	if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
L
Len Brown 已提交
560 561 562
	    ACPI_GPE_EDGE_TRIGGERED) {
		status = acpi_hw_clear_gpe(gpe_event_info);
		if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
563
			ACPI_EXCEPTION((AE_INFO, status,
564
					"Unable to clear GPE[0x%2X]",
B
Bob Moore 已提交
565
					gpe_number));
B
Bob Moore 已提交
566
			return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
L
Linus Torvalds 已提交
567 568 569 570
		}
	}

	/*
571 572 573 574 575
	 * Dispatch the GPE to either an installed handler, or the control method
	 * associated with this GPE (_Lxx or _Exx). If a handler exists, we invoke
	 * it and do not attempt to run the method. If there is neither a handler
	 * nor a method, we disable this GPE to prevent further such pointless
	 * events from firing.
L
Linus Torvalds 已提交
576 577 578 579 580 581
	 */
	switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
	case ACPI_GPE_DISPATCH_HANDLER:

		/*
		 * Invoke the installed handler (at interrupt level)
582 583
		 * Ignore return status for now.
		 * TBD: leave GPE disabled on error?
L
Linus Torvalds 已提交
584
		 */
L
Len Brown 已提交
585 586 587 588
		(void)gpe_event_info->dispatch.handler->address(gpe_event_info->
								dispatch.
								handler->
								context);
L
Linus Torvalds 已提交
589 590 591

		/* It is now safe to clear level-triggered events. */

R
Robert Moore 已提交
592
		if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
L
Len Brown 已提交
593 594 595
		    ACPI_GPE_LEVEL_TRIGGERED) {
			status = acpi_hw_clear_gpe(gpe_event_info);
			if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
596
				ACPI_EXCEPTION((AE_INFO, status,
597
					"Unable to clear GPE[0x%2X]",
B
Bob Moore 已提交
598
						gpe_number));
B
Bob Moore 已提交
599
				return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
L
Linus Torvalds 已提交
600 601 602 603 604 605 606
			}
		}
		break;

	case ACPI_GPE_DISPATCH_METHOD:

		/*
607 608
		 * Disable the GPE, so it doesn't keep firing before the method has a
		 * chance to run (it runs asynchronously with interrupts enabled).
L
Linus Torvalds 已提交
609
		 */
L
Len Brown 已提交
610 611
		status = acpi_ev_disable_gpe(gpe_event_info);
		if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
612
			ACPI_EXCEPTION((AE_INFO, status,
613
					"Unable to disable GPE[0x%2X]",
B
Bob Moore 已提交
614
					gpe_number));
B
Bob Moore 已提交
615
			return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
L
Linus Torvalds 已提交
616 617 618 619 620 621
		}

		/*
		 * Execute the method associated with the GPE
		 * NOTE: Level-triggered GPEs are cleared after the method completes.
		 */
B
Bob Moore 已提交
622 623 624
		status = acpi_os_execute(OSL_GPE_HANDLER,
					 acpi_ev_asynch_execute_gpe_method,
					 gpe_event_info);
L
Len Brown 已提交
625
		if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
626
			ACPI_EXCEPTION((AE_INFO, status,
627
					"Unable to queue handler for GPE[0x%2X] - event disabled",
B
Bob Moore 已提交
628
					gpe_number));
L
Linus Torvalds 已提交
629 630 631 632 633
		}
		break;

	default:

634 635 636 637 638
		/*
		 * No handler or method to run!
		 * 03/2010: This case should no longer be possible. We will not allow
		 * a GPE to be enabled if it has no handler or method.
		 */
B
Bob Moore 已提交
639
		ACPI_ERROR((AE_INFO,
640
			    "No handler or method for GPE[0x%2X], disabling event",
B
Bob Moore 已提交
641
			    gpe_number));
L
Linus Torvalds 已提交
642 643

		/*
644 645
		 * Disable the GPE. The GPE will remain disabled a handler
		 * is installed or ACPICA is restarted.
L
Linus Torvalds 已提交
646
		 */
L
Len Brown 已提交
647 648
		status = acpi_ev_disable_gpe(gpe_event_info);
		if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
649
			ACPI_EXCEPTION((AE_INFO, status,
650
					"Unable to disable GPE[0x%2X]",
B
Bob Moore 已提交
651
					gpe_number));
B
Bob Moore 已提交
652
			return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
L
Linus Torvalds 已提交
653 654 655 656
		}
		break;
	}

B
Bob Moore 已提交
657
	return_UINT32(ACPI_INTERRUPT_HANDLED);
L
Linus Torvalds 已提交
658
}