aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/acpica/hwgpe.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2010-06-08 04:49:08 -0400
committerLen Brown <len.brown@intel.com>2010-06-12 00:44:37 -0400
commitfd247447c1d94a79d5cfc647430784306b3a8323 (patch)
treed3a58bb5e50068f4d9245f0788e7f14ff56ac711 /drivers/acpi/acpica/hwgpe.c
parente4e9a735991c80fb0fc1bd4a13a93681c3c17ce0 (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.c26
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
91acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info) 92acpi_status
93acpi_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