diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2010-06-08 04:49:08 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2010-06-12 00:44:37 -0400 |
commit | fd247447c1d94a79d5cfc647430784306b3a8323 (patch) | |
tree | d3a58bb5e50068f4d9245f0788e7f14ff56ac711 /drivers/acpi/acpica/hwgpe.c | |
parent | e4e9a735991c80fb0fc1bd4a13a93681c3c17ce0 (diff) |
ACPI / ACPICA: Fix low-level GPE manipulation code
ACPICA uses acpi_ev_enable_gpe() for enabling GPEs at the low level,
which is incorrect, because this function only enables the GPE if the
corresponding bit in its enable register's enable_for_run mask is set.
This causes acpi_set_gpe() to work incorrectly if used for enabling
GPEs that were not previously enabled with acpi_enable_gpe(). As a
result, among other things, wakeup-only GPEs are never enabled by
acpi_enable_wakeup_device(), so the devices that use them are unable
to wake up the system.
To fix this issue remove acpi_ev_enable_gpe() and its counterpart
acpi_ev_disable_gpe() and replace acpi_hw_low_disable_gpe() with
acpi_hw_low_set_gpe() that will be used instead to manipulate GPE
enable bits at the low level. Make the users of acpi_ev_enable_gpe()
and acpi_ev_disable_gpe() call acpi_hw_low_set_gpe() instead and
make sure that GPE enable masks are only updated by acpi_enable_gpe()
and acpi_disable_gpe() when GPE reference counters change from 0
to 1 and from 1 to 0, respectively.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/acpica/hwgpe.c')
-rw-r--r-- | drivers/acpi/acpica/hwgpe.c | 26 |
1 files changed, 21 insertions, 5 deletions
diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index d989b8e786cc..40388e23e103 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c | |||
@@ -78,23 +78,27 @@ u32 acpi_hw_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info, | |||
78 | 78 | ||
79 | /****************************************************************************** | 79 | /****************************************************************************** |
80 | * | 80 | * |
81 | * FUNCTION: acpi_hw_low_disable_gpe | 81 | * FUNCTION: acpi_hw_low_set_gpe |
82 | * | 82 | * |
83 | * PARAMETERS: gpe_event_info - Info block for the GPE to be disabled | 83 | * PARAMETERS: gpe_event_info - Info block for the GPE to be disabled |
84 | * action - Enable or disable | ||
84 | * | 85 | * |
85 | * RETURN: Status | 86 | * RETURN: Status |
86 | * | 87 | * |
87 | * DESCRIPTION: Disable a single GPE in the enable register. | 88 | * DESCRIPTION: Enable or disable a single GPE in its enable register. |
88 | * | 89 | * |
89 | ******************************************************************************/ | 90 | ******************************************************************************/ |
90 | 91 | ||
91 | acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info) | 92 | acpi_status |
93 | acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 action) | ||
92 | { | 94 | { |
93 | struct acpi_gpe_register_info *gpe_register_info; | 95 | struct acpi_gpe_register_info *gpe_register_info; |
94 | acpi_status status; | 96 | acpi_status status; |
95 | u32 enable_mask; | 97 | u32 enable_mask; |
96 | u32 register_bit; | 98 | u32 register_bit; |
97 | 99 | ||
100 | ACPI_FUNCTION_ENTRY(); | ||
101 | |||
98 | /* Get the info block for the entire GPE register */ | 102 | /* Get the info block for the entire GPE register */ |
99 | 103 | ||
100 | gpe_register_info = gpe_event_info->register_info; | 104 | gpe_register_info = gpe_event_info->register_info; |
@@ -109,11 +113,23 @@ acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info) | |||
109 | return (status); | 113 | return (status); |
110 | } | 114 | } |
111 | 115 | ||
112 | /* Clear just the bit that corresponds to this GPE */ | 116 | /* Set ot clear just the bit that corresponds to this GPE */ |
113 | 117 | ||
114 | register_bit = acpi_hw_gpe_register_bit(gpe_event_info, | 118 | register_bit = acpi_hw_gpe_register_bit(gpe_event_info, |
115 | gpe_register_info); | 119 | gpe_register_info); |
116 | ACPI_CLEAR_BIT(enable_mask, register_bit); | 120 | switch (action) { |
121 | case ACPI_GPE_ENABLE: | ||
122 | ACPI_SET_BIT(enable_mask, register_bit); | ||
123 | break; | ||
124 | |||
125 | case ACPI_GPE_DISABLE: | ||
126 | ACPI_CLEAR_BIT(enable_mask, register_bit); | ||
127 | break; | ||
128 | |||
129 | default: | ||
130 | ACPI_ERROR((AE_INFO, "Invalid action\n")); | ||
131 | return (AE_BAD_PARAMETER); | ||
132 | } | ||
117 | 133 | ||
118 | /* Write the updated enable mask */ | 134 | /* Write the updated enable mask */ |
119 | 135 | ||