Skip to content

Commit

Permalink
Make GPE disable more robust
Browse files Browse the repository at this point in the history
Implemented another change for the GPE disable. We now perform a
read-change-write of the enable register instead of simply writing out the
cached enable mask. This will prevent inadvertent enabling of GPEs if a rogue
GPE is received during initialization (before GPE handlers are installed.)

http://bugzilla.kernel.org/show_bug.cgi?id=6217

Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
  • Loading branch information
Bob Moore authored and Andi Kleen committed Jul 16, 2008
1 parent 87dc5e3 commit e38e8a0
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 5 deletions.
18 changes: 14 additions & 4 deletions drivers/acpi/events/evgpe.c
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
return_ACPI_STATUS(status);
}

/* Mark wake-disabled or HW disable, or both */
/* Clear the appropriate enabled flags for this GPE */

switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) {
case ACPI_GPE_TYPE_WAKE:
Expand All @@ -273,13 +273,23 @@ acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
/* Disable the requested runtime GPE */

ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED);

/* fallthrough */
break;

default:
acpi_hw_write_gpe_enable_reg(gpe_event_info);
break;
}

/*
* Even if we don't know the GPE type, make sure that we always
* disable it. low_disable_gpe will just clear the enable bit for this
* GPE and write it. It will not write out the current GPE enable mask,
* since this may inadvertently enable GPEs too early, if a rogue GPE has
* come in during ACPICA initialization - possibly as a result of AML or
* other code that has enabled the GPE.
*/
status = acpi_hw_low_disable_gpe(gpe_event_info);
return_ACPI_STATUS(status);

return_ACPI_STATUS(AE_OK);
}

Expand Down
50 changes: 49 additions & 1 deletion drivers/acpi/hardware/hwgpe.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,54 @@ static acpi_status
acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
struct acpi_gpe_block_info *gpe_block);

/******************************************************************************
*
* FUNCTION: acpi_hw_low_disable_gpe
*
* PARAMETERS: gpe_event_info - Info block for the GPE to be disabled
*
* RETURN: Status
*
* DESCRIPTION: Disable a single GPE in the enable register.
*
******************************************************************************/

acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
{
struct acpi_gpe_register_info *gpe_register_info;
acpi_status status;
u32 enable_mask;

/* Get the info block for the entire GPE register */

gpe_register_info = gpe_event_info->register_info;
if (!gpe_register_info) {
return (AE_NOT_EXIST);
}

/* Get current value of the enable register that contains this GPE */

status = acpi_hw_low_level_read(ACPI_GPE_REGISTER_WIDTH, &enable_mask,
&gpe_register_info->enable_address);
if (ACPI_FAILURE(status)) {
return (status);
}

/* Clear just the bit that corresponds to this GPE */

ACPI_CLEAR_BIT(enable_mask,
((u32) 1 <<
(gpe_event_info->gpe_number -
gpe_register_info->base_gpe_number)));

/* Write the updated enable mask */

status = acpi_hw_low_level_write(ACPI_GPE_REGISTER_WIDTH, enable_mask,
&gpe_register_info->enable_address);

return (status);
}

/******************************************************************************
*
* FUNCTION: acpi_hw_write_gpe_enable_reg
Expand All @@ -68,7 +116,7 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
******************************************************************************/

acpi_status
acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info *gpe_event_info)
acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info * gpe_event_info)
{
struct acpi_gpe_register_info *gpe_register_info;
acpi_status status;
Expand Down
2 changes: 2 additions & 0 deletions include/acpi/achware.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ acpi_status acpi_hw_clear_acpi_status(void);
/*
* hwgpe - GPE support
*/
acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info);

acpi_status
acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info *gpe_event_info);

Expand Down

0 comments on commit e38e8a0

Please sign in to comment.