ACPICA: Introduce acpi_any_gpe_status_set()
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tue, 11 Feb 2020 16:52:32 +0000 (17:52 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tue, 11 Feb 2020 22:26:15 +0000 (23:26 +0100)
Introduce a new helper function, acpi_any_gpe_status_set(), for
checking the status bits of all enabled GPEs in one go.

It is needed to distinguish spurious SCIs from genuine ones when
deciding whether or not to wake up the system from suspend-to-idle.

Cc: 5.4+ <stable@vger.kernel.org> # 5.4+
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/acpi/acpica/achware.h
drivers/acpi/acpica/evxfgpe.c
drivers/acpi/acpica/hwgpe.c
include/acpi/acpixf.h

index 67f282e9e0af17500dde847bc8d4943a51e877be..6ad0517553d5e8f8386e4945cc562f31eb2dfd66 100644 (file)
@@ -101,6 +101,8 @@ acpi_status acpi_hw_enable_all_runtime_gpes(void);
 
 acpi_status acpi_hw_enable_all_wakeup_gpes(void);
 
+u8 acpi_hw_check_all_gpes(void);
+
 acpi_status
 acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
                                 struct acpi_gpe_block_info *gpe_block,
index 2c39ff2a7406900ea593f6d7f886253410444379..f2de66bfd8a7cd8aea8c91954bf337cf14d4fc63 100644 (file)
@@ -795,6 +795,38 @@ acpi_status acpi_enable_all_wakeup_gpes(void)
 
 ACPI_EXPORT_SYMBOL(acpi_enable_all_wakeup_gpes)
 
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_any_gpe_status_set
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Whether or not the status bit is set for any GPE
+ *
+ * DESCRIPTION: Check the status bits of all enabled GPEs and return TRUE if any
+ *              of them is set or FALSE otherwise.
+ *
+ ******************************************************************************/
+u32 acpi_any_gpe_status_set(void)
+{
+       acpi_status status;
+       u8 ret;
+
+       ACPI_FUNCTION_TRACE(acpi_any_gpe_status_set);
+
+       status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+       if (ACPI_FAILURE(status)) {
+               return (FALSE);
+       }
+
+       ret = acpi_hw_check_all_gpes();
+       (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+
+       return (ret);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_any_gpe_status_set)
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_install_gpe_block
index 1b4252bdcd0b1a6346a1dd1d375c3405ca7266e8..f4c285c2f5956da43d45a31daaa5bc2d3c4d74fe 100644 (file)
@@ -444,6 +444,53 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
        return (AE_OK);
 }
 
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_hw_get_gpe_block_status
+ *
+ * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
+ *              gpe_block           - Gpe Block info
+ *
+ * RETURN:      Success
+ *
+ * DESCRIPTION: Produce a combined GPE status bits mask for the given block.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_hw_get_gpe_block_status(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+                            struct acpi_gpe_block_info *gpe_block,
+                            void *ret_ptr)
+{
+       struct acpi_gpe_register_info *gpe_register_info;
+       u64 in_enable, in_status;
+       acpi_status status;
+       u8 *ret = ret_ptr;
+       u32 i;
+
+       /* Examine each GPE Register within the block */
+
+       for (i = 0; i < gpe_block->register_count; i++) {
+               gpe_register_info = &gpe_block->register_info[i];
+
+               status = acpi_hw_read(&in_enable,
+                                     &gpe_register_info->enable_address);
+               if (ACPI_FAILURE(status)) {
+                       continue;
+               }
+
+               status = acpi_hw_read(&in_status,
+                                     &gpe_register_info->status_address);
+               if (ACPI_FAILURE(status)) {
+                       continue;
+               }
+
+               *ret |= in_enable & in_status;
+       }
+
+       return (AE_OK);
+}
+
 /******************************************************************************
  *
  * FUNCTION:    acpi_hw_disable_all_gpes
@@ -510,4 +557,28 @@ acpi_status acpi_hw_enable_all_wakeup_gpes(void)
        return_ACPI_STATUS(status);
 }
 
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_hw_check_all_gpes
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Combined status of all GPEs
+ *
+ * DESCRIPTION: Check all enabled GPEs in all GPE blocks and return TRUE if the
+ *              status bit is set for at least one of them of FALSE otherwise.
+ *
+ ******************************************************************************/
+
+u8 acpi_hw_check_all_gpes(void)
+{
+       u8 ret = 0;
+
+       ACPI_FUNCTION_TRACE(acpi_hw_check_all_gpes);
+
+       (void)acpi_ev_walk_gpe_list(acpi_hw_get_gpe_block_status, &ret);
+
+       return (ret != 0);
+}
+
 #endif                         /* !ACPI_REDUCED_HARDWARE */
index 00994b1b8681a32f25b3dfaa0e9d4b9755b9f445..5867777bb7d0fb2107080c7026804447f9dab9fb 100644 (file)
@@ -752,6 +752,7 @@ ACPI_HW_DEPENDENT_RETURN_UINT32(u32 acpi_dispatch_gpe(acpi_handle gpe_device, u3
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable_all_gpes(void))
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_runtime_gpes(void))
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_wakeup_gpes(void))
+ACPI_HW_DEPENDENT_RETURN_UINT32(u32 acpi_any_gpe_status_set(void))
 
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
                                acpi_get_gpe_device(u32 gpe_index,