diff options
author | Lv Zheng <lv.zheng@intel.com> | 2016-08-04 04:43:39 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-08-12 21:09:33 -0400 |
commit | 2af52c2bd20c50e80b121e15cd50a579e364485a (patch) | |
tree | 3bc9e680c4c65462569794ce2ce5c269d2767c38 | |
parent | 9556ec4ec1d3575090f1f110c558169c5f0973a9 (diff) |
ACPICA: Events: Introduce acpi_mask_gpe() to implement GPE masking mechanism
ACPICA commit 23a417ca406a527e7ae1710893e59a8b6db30e14
There is a facility in Linux, developers can control the enabling/disabling
of a GPE via /sys/firmware/acpi/interrupts/gpexx. This is mainly for
debugging purposes.
But many users expect to use this facility to implement quirks to mask a
specific GPE when there is a gap in Linux causing this GPE to flood. This
is not working correctly because currently this facility invokes
enabling/disabling counting based GPE driver APIs:
acpi_enable_gpe()/acpi_disable_gpe()
and the GPE drivers can still affect the count to mess up the GPE
masking purposes.
However, most of the IRQ chip designs allow masking/unmasking IRQs via a
masking bit which is different from the enabled bit to achieve the same
purpose. But the GPE hardware doesn't contain such a feature, this brings
the trouble.
In this patch, we introduce a software mechanism to implement the GPE
masking feature, and acpi_mask_gpe() are provided to the OSPMs to
mask/unmask GPEs in the above mentioned situation instead of
acpi_enable_gpe()/acpi_disable_gpe(). ACPICA BZ 1102. Lv Zheng.
Link: https://github.com/acpica/acpica/commit/23a417ca
Link: https://bugs.acpica.org/show_bug.cgi?id=1102
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r-- | drivers/acpi/acpica/acevents.h | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/aclocal.h | 2 | ||||
-rw-r--r-- | drivers/acpi/acpica/evgpe.c | 57 | ||||
-rw-r--r-- | drivers/acpi/acpica/evxfgpe.c | 43 | ||||
-rw-r--r-- | drivers/acpi/acpica/hwgpe.c | 23 | ||||
-rw-r--r-- | include/acpi/acpixf.h | 4 | ||||
-rw-r--r-- | include/acpi/actypes.h | 39 |
7 files changed, 148 insertions, 23 deletions
diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 77af91cf46d4..92fa47c6498c 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h | |||
@@ -86,6 +86,9 @@ acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info); | |||
86 | acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info); | 86 | acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info); |
87 | 87 | ||
88 | acpi_status | 88 | acpi_status |
89 | acpi_ev_mask_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 is_masked); | ||
90 | |||
91 | acpi_status | ||
89 | acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info); | 92 | acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info); |
90 | 93 | ||
91 | acpi_status | 94 | acpi_status |
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 13331d70dea0..dff1207a6078 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h | |||
@@ -484,6 +484,7 @@ struct acpi_gpe_event_info { | |||
484 | u8 flags; /* Misc info about this GPE */ | 484 | u8 flags; /* Misc info about this GPE */ |
485 | u8 gpe_number; /* This GPE */ | 485 | u8 gpe_number; /* This GPE */ |
486 | u8 runtime_count; /* References to a run GPE */ | 486 | u8 runtime_count; /* References to a run GPE */ |
487 | u8 disable_for_dispatch; /* Masked during dispatching */ | ||
487 | }; | 488 | }; |
488 | 489 | ||
489 | /* Information about a GPE register pair, one per each status/enable pair in an array */ | 490 | /* Information about a GPE register pair, one per each status/enable pair in an array */ |
@@ -494,6 +495,7 @@ struct acpi_gpe_register_info { | |||
494 | u16 base_gpe_number; /* Base GPE number for this register */ | 495 | u16 base_gpe_number; /* Base GPE number for this register */ |
495 | u8 enable_for_wake; /* GPEs to keep enabled when sleeping */ | 496 | u8 enable_for_wake; /* GPEs to keep enabled when sleeping */ |
496 | u8 enable_for_run; /* GPEs to keep enabled when running */ | 497 | u8 enable_for_run; /* GPEs to keep enabled when running */ |
498 | u8 mask_for_run; /* GPEs to keep masked when running */ | ||
497 | u8 enable_mask; /* Current mask of enabled GPEs */ | 499 | u8 enable_mask; /* Current mask of enabled GPEs */ |
498 | }; | 500 | }; |
499 | 501 | ||
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index 4b4949ce05bc..bdb10bee13ce 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c | |||
@@ -130,6 +130,60 @@ acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) | |||
130 | 130 | ||
131 | /******************************************************************************* | 131 | /******************************************************************************* |
132 | * | 132 | * |
133 | * FUNCTION: acpi_ev_mask_gpe | ||
134 | * | ||
135 | * PARAMETERS: gpe_event_info - GPE to be blocked/unblocked | ||
136 | * is_masked - Whether the GPE is masked or not | ||
137 | * | ||
138 | * RETURN: Status | ||
139 | * | ||
140 | * DESCRIPTION: Unconditionally mask/unmask a GPE during runtime. | ||
141 | * | ||
142 | ******************************************************************************/ | ||
143 | |||
144 | acpi_status | ||
145 | acpi_ev_mask_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 is_masked) | ||
146 | { | ||
147 | struct acpi_gpe_register_info *gpe_register_info; | ||
148 | u32 register_bit; | ||
149 | |||
150 | ACPI_FUNCTION_TRACE(ev_mask_gpe); | ||
151 | |||
152 | gpe_register_info = gpe_event_info->register_info; | ||
153 | if (!gpe_register_info) { | ||
154 | return_ACPI_STATUS(AE_NOT_EXIST); | ||
155 | } | ||
156 | |||
157 | register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info); | ||
158 | |||
159 | /* Perform the action */ | ||
160 | |||
161 | if (is_masked) { | ||
162 | if (register_bit & gpe_register_info->mask_for_run) { | ||
163 | return_ACPI_STATUS(AE_BAD_PARAMETER); | ||
164 | } | ||
165 | |||
166 | (void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); | ||
167 | ACPI_SET_BIT(gpe_register_info->mask_for_run, (u8)register_bit); | ||
168 | } else { | ||
169 | if (!(register_bit & gpe_register_info->mask_for_run)) { | ||
170 | return_ACPI_STATUS(AE_BAD_PARAMETER); | ||
171 | } | ||
172 | |||
173 | ACPI_CLEAR_BIT(gpe_register_info->mask_for_run, | ||
174 | (u8)register_bit); | ||
175 | if (gpe_event_info->runtime_count | ||
176 | && !gpe_event_info->disable_for_dispatch) { | ||
177 | (void)acpi_hw_low_set_gpe(gpe_event_info, | ||
178 | ACPI_GPE_ENABLE); | ||
179 | } | ||
180 | } | ||
181 | |||
182 | return_ACPI_STATUS(AE_OK); | ||
183 | } | ||
184 | |||
185 | /******************************************************************************* | ||
186 | * | ||
133 | * FUNCTION: acpi_ev_add_gpe_reference | 187 | * FUNCTION: acpi_ev_add_gpe_reference |
134 | * | 188 | * |
135 | * PARAMETERS: gpe_event_info - Add a reference to this GPE | 189 | * PARAMETERS: gpe_event_info - Add a reference to this GPE |
@@ -674,6 +728,7 @@ acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info) | |||
674 | * in the event_info. | 728 | * in the event_info. |
675 | */ | 729 | */ |
676 | (void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_CONDITIONAL_ENABLE); | 730 | (void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_CONDITIONAL_ENABLE); |
731 | gpe_event_info->disable_for_dispatch = FALSE; | ||
677 | return (AE_OK); | 732 | return (AE_OK); |
678 | } | 733 | } |
679 | 734 | ||
@@ -737,6 +792,8 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, | |||
737 | } | 792 | } |
738 | } | 793 | } |
739 | 794 | ||
795 | gpe_event_info->disable_for_dispatch = TRUE; | ||
796 | |||
740 | /* | 797 | /* |
741 | * Dispatch the GPE to either an installed handler or the control | 798 | * Dispatch the GPE to either an installed handler or the control |
742 | * method associated with this GPE (_Lxx or _Exx). If a handler | 799 | * method associated with this GPE (_Lxx or _Exx). If a handler |
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index 17cfef721d00..d7a3b2775505 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c | |||
@@ -235,11 +235,13 @@ acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action) | |||
235 | case ACPI_GPE_ENABLE: | 235 | case ACPI_GPE_ENABLE: |
236 | 236 | ||
237 | status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE); | 237 | status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE); |
238 | gpe_event_info->disable_for_dispatch = FALSE; | ||
238 | break; | 239 | break; |
239 | 240 | ||
240 | case ACPI_GPE_DISABLE: | 241 | case ACPI_GPE_DISABLE: |
241 | 242 | ||
242 | status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); | 243 | status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); |
244 | gpe_event_info->disable_for_dispatch = TRUE; | ||
243 | break; | 245 | break; |
244 | 246 | ||
245 | default: | 247 | default: |
@@ -257,6 +259,47 @@ ACPI_EXPORT_SYMBOL(acpi_set_gpe) | |||
257 | 259 | ||
258 | /******************************************************************************* | 260 | /******************************************************************************* |
259 | * | 261 | * |
262 | * FUNCTION: acpi_mask_gpe | ||
263 | * | ||
264 | * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 | ||
265 | * gpe_number - GPE level within the GPE block | ||
266 | * is_masked - Whether the GPE is masked or not | ||
267 | * | ||
268 | * RETURN: Status | ||
269 | * | ||
270 | * DESCRIPTION: Unconditionally mask/unmask the an individual GPE, ex., to | ||
271 | * prevent a GPE flooding. | ||
272 | * | ||
273 | ******************************************************************************/ | ||
274 | acpi_status acpi_mask_gpe(acpi_handle gpe_device, u32 gpe_number, u8 is_masked) | ||
275 | { | ||
276 | struct acpi_gpe_event_info *gpe_event_info; | ||
277 | acpi_status status; | ||
278 | acpi_cpu_flags flags; | ||
279 | |||
280 | ACPI_FUNCTION_TRACE(acpi_mask_gpe); | ||
281 | |||
282 | flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); | ||
283 | |||
284 | /* Ensure that we have a valid GPE number */ | ||
285 | |||
286 | gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); | ||
287 | if (!gpe_event_info) { | ||
288 | status = AE_BAD_PARAMETER; | ||
289 | goto unlock_and_exit; | ||
290 | } | ||
291 | |||
292 | status = acpi_ev_mask_gpe(gpe_event_info, is_masked); | ||
293 | |||
294 | unlock_and_exit: | ||
295 | acpi_os_release_lock(acpi_gbl_gpe_lock, flags); | ||
296 | return_ACPI_STATUS(status); | ||
297 | } | ||
298 | |||
299 | ACPI_EXPORT_SYMBOL(acpi_mask_gpe) | ||
300 | |||
301 | /******************************************************************************* | ||
302 | * | ||
260 | * FUNCTION: acpi_mark_gpe_for_wake | 303 | * FUNCTION: acpi_mark_gpe_for_wake |
261 | * | 304 | * |
262 | * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 | 305 | * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 |
diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index bdecd5e76e87..76b0e350f5bb 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c | |||
@@ -98,7 +98,7 @@ acpi_status | |||
98 | acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action) | 98 | acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action) |
99 | { | 99 | { |
100 | struct acpi_gpe_register_info *gpe_register_info; | 100 | struct acpi_gpe_register_info *gpe_register_info; |
101 | acpi_status status; | 101 | acpi_status status = AE_OK; |
102 | u32 enable_mask; | 102 | u32 enable_mask; |
103 | u32 register_bit; | 103 | u32 register_bit; |
104 | 104 | ||
@@ -148,9 +148,14 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action) | |||
148 | return (AE_BAD_PARAMETER); | 148 | return (AE_BAD_PARAMETER); |
149 | } | 149 | } |
150 | 150 | ||
151 | /* Write the updated enable mask */ | 151 | if (!(register_bit & gpe_register_info->mask_for_run)) { |
152 | 152 | ||
153 | status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address); | 153 | /* Write the updated enable mask */ |
154 | |||
155 | status = | ||
156 | acpi_hw_write(enable_mask, | ||
157 | &gpe_register_info->enable_address); | ||
158 | } | ||
154 | return (status); | 159 | return (status); |
155 | } | 160 | } |
156 | 161 | ||
@@ -242,6 +247,12 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info *gpe_event_info, | |||
242 | local_event_status |= ACPI_EVENT_FLAG_ENABLED; | 247 | local_event_status |= ACPI_EVENT_FLAG_ENABLED; |
243 | } | 248 | } |
244 | 249 | ||
250 | /* GPE currently masked? (masked for runtime?) */ | ||
251 | |||
252 | if (register_bit & gpe_register_info->mask_for_run) { | ||
253 | local_event_status |= ACPI_EVENT_FLAG_MASKED; | ||
254 | } | ||
255 | |||
245 | /* GPE enabled for wake? */ | 256 | /* GPE enabled for wake? */ |
246 | 257 | ||
247 | if (register_bit & gpe_register_info->enable_for_wake) { | 258 | if (register_bit & gpe_register_info->enable_for_wake) { |
@@ -397,6 +408,7 @@ acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, | |||
397 | u32 i; | 408 | u32 i; |
398 | acpi_status status; | 409 | acpi_status status; |
399 | struct acpi_gpe_register_info *gpe_register_info; | 410 | struct acpi_gpe_register_info *gpe_register_info; |
411 | u8 enable_mask; | ||
400 | 412 | ||
401 | /* NOTE: assumes that all GPEs are currently disabled */ | 413 | /* NOTE: assumes that all GPEs are currently disabled */ |
402 | 414 | ||
@@ -410,9 +422,10 @@ acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, | |||
410 | 422 | ||
411 | /* Enable all "runtime" GPEs in this register */ | 423 | /* Enable all "runtime" GPEs in this register */ |
412 | 424 | ||
425 | enable_mask = gpe_register_info->enable_for_run & | ||
426 | ~gpe_register_info->mask_for_run; | ||
413 | status = | 427 | status = |
414 | acpi_hw_gpe_enable_write(gpe_register_info->enable_for_run, | 428 | acpi_hw_gpe_enable_write(enable_mask, gpe_register_info); |
415 | gpe_register_info); | ||
416 | if (ACPI_FAILURE(status)) { | 429 | if (ACPI_FAILURE(status)) { |
417 | return (status); | 430 | return (status); |
418 | } | 431 | } |
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 875964dea539..c2d4b9c9f8a4 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h | |||
@@ -736,6 +736,10 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status | |||
736 | u32 gpe_number)) | 736 | u32 gpe_number)) |
737 | 737 | ||
738 | ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status | 738 | ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status |
739 | acpi_mask_gpe(acpi_handle gpe_device, | ||
740 | u32 gpe_number, u8 is_masked)) | ||
741 | |||
742 | ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status | ||
739 | acpi_mark_gpe_for_wake(acpi_handle gpe_device, | 743 | acpi_mark_gpe_for_wake(acpi_handle gpe_device, |
740 | u32 gpe_number)) | 744 | u32 gpe_number)) |
741 | 745 | ||
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index cb389efd321c..fa4bd6ad5d24 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h | |||
@@ -732,16 +732,17 @@ typedef u32 acpi_event_type; | |||
732 | * The encoding of acpi_event_status is illustrated below. | 732 | * The encoding of acpi_event_status is illustrated below. |
733 | * Note that a set bit (1) indicates the property is TRUE | 733 | * Note that a set bit (1) indicates the property is TRUE |
734 | * (e.g. if bit 0 is set then the event is enabled). | 734 | * (e.g. if bit 0 is set then the event is enabled). |
735 | * +-------------+-+-+-+-+-+ | 735 | * +-------------+-+-+-+-+-+-+ |
736 | * | Bits 31:5 |4|3|2|1|0| | 736 | * | Bits 31:6 |5|4|3|2|1|0| |
737 | * +-------------+-+-+-+-+-+ | 737 | * +-------------+-+-+-+-+-+-+ |
738 | * | | | | | | | 738 | * | | | | | | | |
739 | * | | | | | +- Enabled? | 739 | * | | | | | | +- Enabled? |
740 | * | | | | +--- Enabled for wake? | 740 | * | | | | | +--- Enabled for wake? |
741 | * | | | +----- Status bit set? | 741 | * | | | | +----- Status bit set? |
742 | * | | +------- Enable bit set? | 742 | * | | | +------- Enable bit set? |
743 | * | +--------- Has a handler? | 743 | * | | +--------- Has a handler? |
744 | * +--------------- <Reserved> | 744 | * | +----------- Masked? |
745 | * +----------------- <Reserved> | ||
745 | */ | 746 | */ |
746 | typedef u32 acpi_event_status; | 747 | typedef u32 acpi_event_status; |
747 | 748 | ||
@@ -751,6 +752,7 @@ typedef u32 acpi_event_status; | |||
751 | #define ACPI_EVENT_FLAG_STATUS_SET (acpi_event_status) 0x04 | 752 | #define ACPI_EVENT_FLAG_STATUS_SET (acpi_event_status) 0x04 |
752 | #define ACPI_EVENT_FLAG_ENABLE_SET (acpi_event_status) 0x08 | 753 | #define ACPI_EVENT_FLAG_ENABLE_SET (acpi_event_status) 0x08 |
753 | #define ACPI_EVENT_FLAG_HAS_HANDLER (acpi_event_status) 0x10 | 754 | #define ACPI_EVENT_FLAG_HAS_HANDLER (acpi_event_status) 0x10 |
755 | #define ACPI_EVENT_FLAG_MASKED (acpi_event_status) 0x20 | ||
754 | #define ACPI_EVENT_FLAG_SET ACPI_EVENT_FLAG_STATUS_SET | 756 | #define ACPI_EVENT_FLAG_SET ACPI_EVENT_FLAG_STATUS_SET |
755 | 757 | ||
756 | /* Actions for acpi_set_gpe, acpi_gpe_wakeup, acpi_hw_low_set_gpe */ | 758 | /* Actions for acpi_set_gpe, acpi_gpe_wakeup, acpi_hw_low_set_gpe */ |
@@ -761,14 +763,15 @@ typedef u32 acpi_event_status; | |||
761 | 763 | ||
762 | /* | 764 | /* |
763 | * GPE info flags - Per GPE | 765 | * GPE info flags - Per GPE |
764 | * +-------+-+-+---+ | 766 | * +---+-+-+-+---+ |
765 | * | 7:5 |4|3|2:0| | 767 | * |7:6|5|4|3|2:0| |
766 | * +-------+-+-+---+ | 768 | * +---+-+-+-+---+ |
767 | * | | | | | 769 | * | | | | | |
768 | * | | | +-- Type of dispatch:to method, handler, notify, or none | 770 | * | | | | +-- Type of dispatch:to method, handler, notify, or none |
769 | * | | +----- Interrupt type: edge or level triggered | 771 | * | | | +----- Interrupt type: edge or level triggered |
770 | * | +------- Is a Wake GPE | 772 | * | | +------- Is a Wake GPE |
771 | * +------------ <Reserved> | 773 | * | +--------- Is GPE masked by the software GPE masking machanism |
774 | * +------------ <Reserved> | ||
772 | */ | 775 | */ |
773 | #define ACPI_GPE_DISPATCH_NONE (u8) 0x00 | 776 | #define ACPI_GPE_DISPATCH_NONE (u8) 0x00 |
774 | #define ACPI_GPE_DISPATCH_METHOD (u8) 0x01 | 777 | #define ACPI_GPE_DISPATCH_METHOD (u8) 0x01 |