patch-2.4.26 linux-2.4.26/drivers/acpi/events/evgpeblk.c
Next file: linux-2.4.26/drivers/acpi/events/evmisc.c
Previous file: linux-2.4.26/drivers/acpi/events/evgpe.c
Back to the patch index
Back to the overall index
- Lines: 376
- Date:
2004-04-14 06:05:28.000000000 -0700
- Orig file:
linux-2.4.25/drivers/acpi/events/evgpeblk.c
- Orig date:
2004-02-18 05:36:31.000000000 -0800
diff -urN linux-2.4.25/drivers/acpi/events/evgpeblk.c linux-2.4.26/drivers/acpi/events/evgpeblk.c
@@ -168,11 +168,11 @@
* information for quick lookup during GPE dispatch
*
* The name of each GPE control method is of the form:
- * "_Lnn" or "_Enn"
- * Where:
- * L - means that the GPE is level triggered
- * E - means that the GPE is edge triggered
- * nn - is the GPE number [in HEX]
+ * "_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]
*
******************************************************************************/
@@ -188,36 +188,41 @@
u32 gpe_number;
char name[ACPI_NAME_SIZE + 1];
u8 type;
- acpi_status status;
ACPI_FUNCTION_TRACE ("ev_save_method_info");
- /* Extract the name from the object and convert to a string */
-
+ /*
+ * _Lxx and _Exx GPE method support
+ *
+ * 1) Extract the name from the object and convert to a string
+ */
ACPI_MOVE_32_TO_32 (name,
&((struct acpi_namespace_node *) obj_handle)->name.integer);
name[ACPI_NAME_SIZE] = 0;
/*
- * Edge/Level determination is based on the 2nd character
- * of the method name
+ * 2) Edge/Level determination is based on the 2nd character
+ * of the method name
+ *
+ * NOTE: Default GPE type is RUNTIME. May be changed later to WAKE if a
+ * _PRW object is found that points to this GPE.
*/
switch (name[1]) {
case 'L':
- type = ACPI_EVENT_LEVEL_TRIGGERED;
+ type = ACPI_GPE_LEVEL_TRIGGERED | ACPI_GPE_TYPE_RUNTIME;
break;
case 'E':
- type = ACPI_EVENT_EDGE_TRIGGERED;
+ type = ACPI_GPE_EDGE_TRIGGERED | ACPI_GPE_TYPE_RUNTIME;
break;
default:
/* Unknown method type, just ignore it! */
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
- "Unknown GPE method type: %s (name not of form _Lnn or _Enn)\n",
+ "Unknown GPE method type: %s (name not of form _Lxx or _Exx)\n",
name));
return_ACPI_STATUS (AE_OK);
}
@@ -229,7 +234,7 @@
/* Conversion failed; invalid method, just ignore it */
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
- "Could not extract GPE number from name: %s (name is not of form _Lnn or _Enn)\n",
+ "Could not extract GPE number from name: %s (name is not of form _Lxx or _Exx)\n",
name));
return_ACPI_STATUS (AE_OK);
}
@@ -255,13 +260,6 @@
gpe_event_info->flags = type;
gpe_event_info->method_node = (struct acpi_namespace_node *) obj_handle;
- /* Enable the GPE (SCIs should be disabled at this point) */
-
- status = acpi_hw_enable_gpe (gpe_event_info);
- if (ACPI_FAILURE (status)) {
- return_ACPI_STATUS (status);
- }
-
ACPI_DEBUG_PRINT ((ACPI_DB_LOAD,
"Registered GPE method %s as GPE number 0x%.2X\n",
name, gpe_number));
@@ -271,6 +269,122 @@
/*******************************************************************************
*
+ * FUNCTION: acpi_ev_get_gpe_type
+ *
+ * PARAMETERS: Callback from walk_namespace
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Called from acpi_walk_namespace. Expects each object to be a
+ * Device. Run the _PRW method. If present, extract the GPE
+ * number and mark the GPE as a WAKE GPE.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ev_get_gpe_type (
+ acpi_handle obj_handle,
+ u32 level,
+ void *info,
+ void **return_value)
+{
+ 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;
+
+
+ ACPI_FUNCTION_TRACE ("ev_get_gpe_type");
+
+
+ /* Check for a _PRW method under this device */
+
+ status = acpi_ut_evaluate_object (obj_handle, METHOD_NAME__PRW,
+ ACPI_BTYPE_PACKAGE, &pkg_desc);
+ if (status == AE_NOT_FOUND) {
+ return_ACPI_STATUS (AE_OK);
+ }
+ else if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* 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;
+
+ /*
+ * The _PRW object must return a package, we are only interested
+ * in the first element
+ */
+ obj_desc = pkg_desc->package.elements[0];
+
+ if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) {
+ /* 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;
+ }
+ else if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_PACKAGE) {
+ /* Package contains a GPE reference and GPE number within a GPE block */
+
+ if ((obj_desc->package.count < 2) ||
+ (ACPI_GET_OBJECT_TYPE (obj_desc->package.elements[0]) != ACPI_TYPE_LOCAL_REFERENCE) ||
+ (ACPI_GET_OBJECT_TYPE (obj_desc->package.elements[1]) != ACPI_TYPE_INTEGER)) {
+ goto cleanup;
+ }
+
+ /* Get GPE block reference and decode */
+
+ target_gpe_device = obj_desc->package.elements[0]->reference.node;
+ gpe_number = (u32) obj_desc->package.elements[1]->integer.value;
+ }
+ else {
+ /* Unknown type, just ignore it */
+
+ goto cleanup;
+ }
+
+ /*
+ * Is this GPE within this block?
+ *
+ * TRUE iff these conditions are true:
+ * 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) &&
+ (gpe_number >= gpe_block->block_base_number) &&
+ (gpe_number < gpe_block->block_base_number + (gpe_block->register_count * 8))) {
+ /* Mark GPE for WAKE but DISABLED (even for wake) */
+
+ gpe_event_info = &gpe_block->event_info[gpe_number - gpe_block->block_base_number];
+ gpe_event_info->flags |= ACPI_GPE_TYPE_WAKE;
+ }
+
+cleanup:
+ acpi_ut_remove_reference (pkg_desc);
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ev_get_gpe_xrupt_block
*
* PARAMETERS: interrupt_level - Interrupt for a GPE block
@@ -695,8 +809,13 @@
struct acpi_gpe_block_info **return_gpe_block)
{
struct acpi_gpe_block_info *gpe_block;
+ struct acpi_gpe_event_info *gpe_event_info;
+ acpi_native_uint i;
+ acpi_native_uint j;
+ u32 wake_gpe_count;
+ u32 gpe_enabled_count;
acpi_status status;
-
+ struct acpi_gpe_walk_info gpe_info;
ACPI_FUNCTION_TRACE ("ev_create_gpe_block");
@@ -737,7 +856,8 @@
/* Dump info about this GPE block */
- ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "GPE %02d to %02d [%4.4s] %d regs at %8.8X%8.8X on int %d\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_INIT,
+ "GPE %02d to %02d [%4.4s] %d regs at %8.8X%8.8X on int %d\n",
gpe_block->block_base_number,
(u32) (gpe_block->block_base_number +
((gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH) -1)),
@@ -752,6 +872,58 @@
ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK, acpi_ev_save_method_info,
gpe_block, NULL);
+ /*
+ * 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.
+ */
+ if (acpi_gbl_leave_wake_gpes_disabled) {
+ /*
+ * 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.)
+ */
+ gpe_info.gpe_block = gpe_block;
+ gpe_info.gpe_device = gpe_device;
+
+ status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ev_get_gpe_type,
+ &gpe_info, NULL);
+ }
+
+ /*
+ * Enable all GPEs in this block that are 1) "runtime" GPEs, and 2) have
+ * a corresponding _Lxx or _Exx method. All other GPEs must be enabled via
+ * the acpi_enable_gpe() external interface.
+ */
+ wake_gpe_count = 0;
+ gpe_enabled_count = 0;
+
+ for (i = 0; i < gpe_block->register_count; i++) {
+ for (j = 0; j < 8; j++) {
+ /* Get the info block for this particular GPE */
+
+ gpe_event_info = &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j];
+ if ((gpe_event_info->method_node) &&
+ ((gpe_event_info->flags & ACPI_GPE_TYPE_MASK) == ACPI_GPE_TYPE_RUNTIME)) {
+ /* Enable this GPE, it is 1) RUNTIME and 2) has an _Lxx or _Exx method */
+
+ status = acpi_hw_enable_gpe (gpe_event_info);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ gpe_enabled_count++;
+ }
+
+ if ((gpe_event_info->flags & ACPI_GPE_TYPE_MASK) == ACPI_GPE_TYPE_WAKE) {
+ wake_gpe_count++;
+ }
+ }
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INIT,
+ "Found %u Wake, Enabled %u Runtime GPEs in this block\n",
+ wake_gpe_count, gpe_enabled_count));
+
/* Return the new block */
if (return_gpe_block) {
@@ -775,27 +947,25 @@
******************************************************************************/
acpi_status
-acpi_ev_gpe_initialize (void)
+acpi_ev_gpe_initialize (
+ void)
{
u32 register_count0 = 0;
u32 register_count1 = 0;
u32 gpe_number_max = 0;
- acpi_handle gpe_device;
acpi_status status;
ACPI_FUNCTION_TRACE ("ev_gpe_initialize");
- /* Get a handle to the predefined _GPE object */
-
- status = acpi_get_handle (NULL, "\\_GPE", &gpe_device);
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
/*
- * Initialize the GPE Blocks defined in the FADT
+ * Initialize the GPE Block(s) defined in the FADT
*
* Why the GPE register block lengths are divided by 2: From the ACPI Spec,
* section "General-Purpose Event Registers", we have:
@@ -829,8 +999,9 @@
/* Install GPE Block 0 */
- status = acpi_ev_create_gpe_block (gpe_device, &acpi_gbl_FADT->xgpe0_blk,
+ status = acpi_ev_create_gpe_block (acpi_gbl_fadt_gpe_device, &acpi_gbl_FADT->xgpe0_blk,
register_count0, 0, acpi_gbl_FADT->sci_int, &acpi_gbl_gpe_fadt_blocks[0]);
+
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR ((
"Could not create GPE Block 0, %s\n",
@@ -861,9 +1032,10 @@
else {
/* Install GPE Block 1 */
- status = acpi_ev_create_gpe_block (gpe_device, &acpi_gbl_FADT->xgpe1_blk,
+ status = acpi_ev_create_gpe_block (acpi_gbl_fadt_gpe_device, &acpi_gbl_FADT->xgpe1_blk,
register_count1, acpi_gbl_FADT->gpe1_base,
acpi_gbl_FADT->sci_int, &acpi_gbl_gpe_fadt_blocks[1]);
+
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR ((
"Could not create GPE Block 1, %s\n",
@@ -885,7 +1057,8 @@
/* GPEs are not required by ACPI, this is OK */
ACPI_REPORT_INFO (("There are no GPE blocks defined in the FADT\n"));
- return_ACPI_STATUS (AE_OK);
+ status = AE_OK;
+ goto cleanup;
}
/* Check for Max GPE number out-of-range */
@@ -893,9 +1066,12 @@
if (gpe_number_max > ACPI_GPE_MAX) {
ACPI_REPORT_ERROR (("Maximum GPE number from FADT is too large: 0x%X\n",
gpe_number_max));
- return_ACPI_STATUS (AE_BAD_VALUE);
+ status = AE_BAD_VALUE;
+ goto cleanup;
}
+cleanup:
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
return_ACPI_STATUS (AE_OK);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)