aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBob Moore <robert.moore@intel.com>2008-06-12 20:28:55 -0400
committerAndi Kleen <andi@basil.nowhere.org>2008-07-16 17:27:01 -0400
commite38e8a0743b0e996a8a3fbea8908fe75a84f02c7 (patch)
tree93dbf03e5c1eff275742989d9b05cb1892c18fe4
parent87dc5e3218ba3d7a9293f9113f58455747a233ac (diff)
Make GPE disable more robust
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>
-rw-r--r--drivers/acpi/events/evgpe.c18
-rw-r--r--drivers/acpi/hardware/hwgpe.c50
-rw-r--r--include/acpi/achware.h2
3 files changed, 65 insertions, 5 deletions
diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c
index 5354be44f876..e0339d4139a4 100644
--- a/drivers/acpi/events/evgpe.c
+++ b/drivers/acpi/events/evgpe.c
@@ -256,7 +256,7 @@ acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
256 return_ACPI_STATUS(status); 256 return_ACPI_STATUS(status);
257 } 257 }
258 258
259 /* Mark wake-disabled or HW disable, or both */ 259 /* Clear the appropriate enabled flags for this GPE */
260 260
261 switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) { 261 switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) {
262 case ACPI_GPE_TYPE_WAKE: 262 case ACPI_GPE_TYPE_WAKE:
@@ -273,13 +273,23 @@ acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
273 /* Disable the requested runtime GPE */ 273 /* Disable the requested runtime GPE */
274 274
275 ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED); 275 ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED);
276 276 break;
277 /* fallthrough */
278 277
279 default: 278 default:
280 acpi_hw_write_gpe_enable_reg(gpe_event_info); 279 break;
281 } 280 }
282 281
282 /*
283 * Even if we don't know the GPE type, make sure that we always
284 * disable it. low_disable_gpe will just clear the enable bit for this
285 * GPE and write it. It will not write out the current GPE enable mask,
286 * since this may inadvertently enable GPEs too early, if a rogue GPE has
287 * come in during ACPICA initialization - possibly as a result of AML or
288 * other code that has enabled the GPE.
289 */
290 status = acpi_hw_low_disable_gpe(gpe_event_info);
291 return_ACPI_STATUS(status);
292
283 return_ACPI_STATUS(AE_OK); 293 return_ACPI_STATUS(AE_OK);
284} 294}
285 295
diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c
index 14bc4f456ae8..58347d6c43f8 100644
--- a/drivers/acpi/hardware/hwgpe.c
+++ b/drivers/acpi/hardware/hwgpe.c
@@ -55,6 +55,54 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
55 55
56/****************************************************************************** 56/******************************************************************************
57 * 57 *
58 * FUNCTION: acpi_hw_low_disable_gpe
59 *
60 * PARAMETERS: gpe_event_info - Info block for the GPE to be disabled
61 *
62 * RETURN: Status
63 *
64 * DESCRIPTION: Disable a single GPE in the enable register.
65 *
66 ******************************************************************************/
67
68acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
69{
70 struct acpi_gpe_register_info *gpe_register_info;
71 acpi_status status;
72 u32 enable_mask;
73
74 /* Get the info block for the entire GPE register */
75
76 gpe_register_info = gpe_event_info->register_info;
77 if (!gpe_register_info) {
78 return (AE_NOT_EXIST);
79 }
80
81 /* Get current value of the enable register that contains this GPE */
82
83 status = acpi_hw_low_level_read(ACPI_GPE_REGISTER_WIDTH, &enable_mask,
84 &gpe_register_info->enable_address);
85 if (ACPI_FAILURE(status)) {
86 return (status);
87 }
88
89 /* Clear just the bit that corresponds to this GPE */
90
91 ACPI_CLEAR_BIT(enable_mask,
92 ((u32) 1 <<
93 (gpe_event_info->gpe_number -
94 gpe_register_info->base_gpe_number)));
95
96 /* Write the updated enable mask */
97
98 status = acpi_hw_low_level_write(ACPI_GPE_REGISTER_WIDTH, enable_mask,
99 &gpe_register_info->enable_address);
100
101 return (status);
102}
103
104/******************************************************************************
105 *
58 * FUNCTION: acpi_hw_write_gpe_enable_reg 106 * FUNCTION: acpi_hw_write_gpe_enable_reg
59 * 107 *
60 * PARAMETERS: gpe_event_info - Info block for the GPE to be enabled 108 * PARAMETERS: gpe_event_info - Info block for the GPE to be enabled
@@ -68,7 +116,7 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
68 ******************************************************************************/ 116 ******************************************************************************/
69 117
70acpi_status 118acpi_status
71acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info *gpe_event_info) 119acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info * gpe_event_info)
72{ 120{
73 struct acpi_gpe_register_info *gpe_register_info; 121 struct acpi_gpe_register_info *gpe_register_info;
74 acpi_status status; 122 acpi_status status;
diff --git a/include/acpi/achware.h b/include/acpi/achware.h
index d4fb9bbc903c..45e985961f4c 100644
--- a/include/acpi/achware.h
+++ b/include/acpi/achware.h
@@ -87,6 +87,8 @@ acpi_status acpi_hw_clear_acpi_status(void);
87/* 87/*
88 * hwgpe - GPE support 88 * hwgpe - GPE support
89 */ 89 */
90acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info);
91
90acpi_status 92acpi_status
91acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info *gpe_event_info); 93acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info *gpe_event_info);
92 94