LCOV - code coverage report
Current view: top level - drivers/acpi/acpica - evgpeinit.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 55 98 56.1 %
Date: 2022-04-01 14:35:51 Functions: 2 3 66.7 %
Branches: 12 47 25.5 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
       2                 :            : /******************************************************************************
       3                 :            :  *
       4                 :            :  * Module Name: evgpeinit - System GPE initialization and update
       5                 :            :  *
       6                 :            :  * Copyright (C) 2000 - 2020, Intel Corp.
       7                 :            :  *
       8                 :            :  *****************************************************************************/
       9                 :            : 
      10                 :            : #include <acpi/acpi.h>
      11                 :            : #include "accommon.h"
      12                 :            : #include "acevents.h"
      13                 :            : #include "acnamesp.h"
      14                 :            : 
      15                 :            : #define _COMPONENT          ACPI_EVENTS
      16                 :            : ACPI_MODULE_NAME("evgpeinit")
      17                 :            : #if (!ACPI_REDUCED_HARDWARE)    /* Entire module */
      18                 :            : /*
      19                 :            :  * Note: History of _PRW support in ACPICA
      20                 :            :  *
      21                 :            :  * Originally (2000 - 2010), the GPE initialization code performed a walk of
      22                 :            :  * the entire namespace to execute the _PRW methods and detect all GPEs
      23                 :            :  * capable of waking the system.
      24                 :            :  *
      25                 :            :  * As of 10/2010, the _PRW method execution has been removed since it is
      26                 :            :  * actually unnecessary. The host OS must in fact execute all _PRW methods
      27                 :            :  * in order to identify the device/power-resource dependencies. We now put
      28                 :            :  * the onus on the host OS to identify the wake GPEs as part of this process
      29                 :            :  * and to inform ACPICA of these GPEs via the acpi_setup_gpe_for_wake interface. This
      30                 :            :  * not only reduces the complexity of the ACPICA initialization code, but in
      31                 :            :  * some cases (on systems with very large namespaces) it should reduce the
      32                 :            :  * kernel boot time as well.
      33                 :            :  */
      34                 :            : 
      35                 :            : /*******************************************************************************
      36                 :            :  *
      37                 :            :  * FUNCTION:    acpi_ev_gpe_initialize
      38                 :            :  *
      39                 :            :  * PARAMETERS:  None
      40                 :            :  *
      41                 :            :  * RETURN:      Status
      42                 :            :  *
      43                 :            :  * DESCRIPTION: Initialize the GPE data structures and the FADT GPE 0/1 blocks
      44                 :            :  *
      45                 :            :  ******************************************************************************/
      46                 :         21 : acpi_status acpi_ev_gpe_initialize(void)
      47                 :            : {
      48                 :         21 :         u32 register_count0 = 0;
      49                 :         21 :         u32 register_count1 = 0;
      50                 :         21 :         u32 gpe_number_max = 0;
      51                 :         21 :         acpi_status status;
      52                 :            : 
      53                 :         21 :         ACPI_FUNCTION_TRACE(ev_gpe_initialize);
      54                 :            : 
      55                 :            :         ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
      56                 :         21 :                               "Initializing General Purpose Events (GPEs):\n"));
      57                 :            : 
      58                 :         21 :         status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
      59         [ +  - ]:         21 :         if (ACPI_FAILURE(status)) {
      60                 :            :                 return_ACPI_STATUS(status);
      61                 :            :         }
      62                 :            : 
      63                 :            :         /*
      64                 :            :          * Initialize the GPE Block(s) defined in the FADT
      65                 :            :          *
      66                 :            :          * Why the GPE register block lengths are divided by 2:  From the ACPI
      67                 :            :          * Spec, section "General-Purpose Event Registers", we have:
      68                 :            :          *
      69                 :            :          * "Each register block contains two registers of equal length
      70                 :            :          *  GPEx_STS and GPEx_EN (where x is 0 or 1). The length of the
      71                 :            :          *  GPE0_STS and GPE0_EN registers is equal to half the GPE0_LEN
      72                 :            :          *  The length of the GPE1_STS and GPE1_EN registers is equal to
      73                 :            :          *  half the GPE1_LEN. If a generic register block is not supported
      74                 :            :          *  then its respective block pointer and block length values in the
      75                 :            :          *  FADT table contain zeros. The GPE0_LEN and GPE1_LEN do not need
      76                 :            :          *  to be the same size."
      77                 :            :          */
      78                 :            : 
      79                 :            :         /*
      80                 :            :          * Determine the maximum GPE number for this machine.
      81                 :            :          *
      82                 :            :          * Note: both GPE0 and GPE1 are optional, and either can exist without
      83                 :            :          * the other.
      84                 :            :          *
      85                 :            :          * If EITHER the register length OR the block address are zero, then that
      86                 :            :          * particular block is not supported.
      87                 :            :          */
      88         [ +  - ]:         21 :         if (acpi_gbl_FADT.gpe0_block_length &&
      89         [ +  - ]:         21 :             acpi_gbl_FADT.xgpe0_block.address) {
      90                 :            : 
      91                 :            :                 /* GPE block 0 exists (has both length and address > 0) */
      92                 :            : 
      93                 :         21 :                 register_count0 = (u16)(acpi_gbl_FADT.gpe0_block_length / 2);
      94                 :         21 :                 gpe_number_max =
      95                 :         21 :                     (register_count0 * ACPI_GPE_REGISTER_WIDTH) - 1;
      96                 :            : 
      97                 :            :                 /* Install GPE Block 0 */
      98                 :            : 
      99                 :         21 :                 status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
     100                 :            :                                                   acpi_gbl_FADT.xgpe0_block.
     101                 :            :                                                   address,
     102                 :         21 :                                                   acpi_gbl_FADT.xgpe0_block.
     103                 :            :                                                   space_id, register_count0, 0,
     104                 :         21 :                                                   acpi_gbl_FADT.sci_interrupt,
     105                 :            :                                                   &acpi_gbl_gpe_fadt_blocks[0]);
     106                 :            : 
     107         [ -  + ]:         21 :                 if (ACPI_FAILURE(status)) {
     108                 :          0 :                         ACPI_EXCEPTION((AE_INFO, status,
     109                 :            :                                         "Could not create GPE Block 0"));
     110                 :            :                 }
     111                 :            :         }
     112                 :            : 
     113         [ -  + ]:         21 :         if (acpi_gbl_FADT.gpe1_block_length &&
     114         [ #  # ]:          0 :             acpi_gbl_FADT.xgpe1_block.address) {
     115                 :            : 
     116                 :            :                 /* GPE block 1 exists (has both length and address > 0) */
     117                 :            : 
     118                 :          0 :                 register_count1 = (u16)(acpi_gbl_FADT.gpe1_block_length / 2);
     119                 :            : 
     120                 :            :                 /* Check for GPE0/GPE1 overlap (if both banks exist) */
     121                 :            : 
     122         [ #  # ]:          0 :                 if ((register_count0) &&
     123         [ #  # ]:          0 :                     (gpe_number_max >= acpi_gbl_FADT.gpe1_base)) {
     124                 :          0 :                         ACPI_ERROR((AE_INFO,
     125                 :            :                                     "GPE0 block (GPE 0 to %u) overlaps the GPE1 block "
     126                 :            :                                     "(GPE %u to %u) - Ignoring GPE1",
     127                 :            :                                     gpe_number_max, acpi_gbl_FADT.gpe1_base,
     128                 :            :                                     acpi_gbl_FADT.gpe1_base +
     129                 :            :                                     ((register_count1 *
     130                 :            :                                       ACPI_GPE_REGISTER_WIDTH) - 1)));
     131                 :            : 
     132                 :            :                         /* Ignore GPE1 block by setting the register count to zero */
     133                 :            : 
     134                 :          0 :                         register_count1 = 0;
     135                 :            :                 } else {
     136                 :            :                         /* Install GPE Block 1 */
     137                 :            : 
     138                 :          0 :                         status =
     139                 :          0 :                             acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
     140                 :            :                                                      acpi_gbl_FADT.xgpe1_block.
     141                 :            :                                                      address,
     142                 :          0 :                                                      acpi_gbl_FADT.xgpe1_block.
     143                 :            :                                                      space_id, register_count1,
     144                 :          0 :                                                      acpi_gbl_FADT.gpe1_base,
     145                 :          0 :                                                      acpi_gbl_FADT.
     146                 :            :                                                      sci_interrupt,
     147                 :            :                                                      &acpi_gbl_gpe_fadt_blocks
     148                 :            :                                                      [1]);
     149                 :            : 
     150         [ #  # ]:          0 :                         if (ACPI_FAILURE(status)) {
     151                 :          0 :                                 ACPI_EXCEPTION((AE_INFO, status,
     152                 :            :                                                 "Could not create GPE Block 1"));
     153                 :            :                         }
     154                 :            : 
     155                 :            :                         /*
     156                 :            :                          * GPE0 and GPE1 do not have to be contiguous in the GPE number
     157                 :            :                          * space. However, GPE0 always starts at GPE number zero.
     158                 :            :                          */
     159                 :            :                 }
     160                 :            :         }
     161                 :            : 
     162                 :            :         /* Exit if there are no GPE registers */
     163                 :            : 
     164                 :         21 :         if ((register_count0 + register_count1) == 0) {
     165                 :            : 
     166                 :            :                 /* GPEs are not required by ACPI, this is OK */
     167                 :            : 
     168                 :            :                 ACPI_DEBUG_PRINT((ACPI_DB_INIT,
     169                 :            :                                   "There are no GPE blocks defined in the FADT\n"));
     170                 :            :                 goto cleanup;
     171                 :            :         }
     172                 :            : 
     173                 :            : cleanup:
     174                 :         21 :         (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
     175                 :         21 :         return_ACPI_STATUS(AE_OK);
     176                 :            : }
     177                 :            : 
     178                 :            : /*******************************************************************************
     179                 :            :  *
     180                 :            :  * FUNCTION:    acpi_ev_update_gpes
     181                 :            :  *
     182                 :            :  * PARAMETERS:  table_owner_id      - ID of the newly-loaded ACPI table
     183                 :            :  *
     184                 :            :  * RETURN:      None
     185                 :            :  *
     186                 :            :  * DESCRIPTION: Check for new GPE methods (_Lxx/_Exx) made available as a
     187                 :            :  *              result of a Load() or load_table() operation. If new GPE
     188                 :            :  *              methods have been installed, register the new methods.
     189                 :            :  *
     190                 :            :  ******************************************************************************/
     191                 :            : 
     192                 :          0 : void acpi_ev_update_gpes(acpi_owner_id table_owner_id)
     193                 :            : {
     194                 :          0 :         struct acpi_gpe_xrupt_info *gpe_xrupt_info;
     195                 :          0 :         struct acpi_gpe_block_info *gpe_block;
     196                 :          0 :         struct acpi_gpe_walk_info walk_info;
     197                 :          0 :         acpi_status status = AE_OK;
     198                 :            : 
     199                 :            :         /*
     200                 :            :          * Find any _Lxx/_Exx GPE methods that have just been loaded.
     201                 :            :          *
     202                 :            :          * Any GPEs that correspond to new _Lxx/_Exx methods are immediately
     203                 :            :          * enabled.
     204                 :            :          *
     205                 :            :          * Examine the namespace underneath each gpe_device within the
     206                 :            :          * gpe_block lists.
     207                 :            :          */
     208                 :          0 :         status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
     209         [ #  # ]:          0 :         if (ACPI_FAILURE(status)) {
     210                 :            :                 return;
     211                 :            :         }
     212                 :            : 
     213                 :          0 :         walk_info.count = 0;
     214                 :          0 :         walk_info.owner_id = table_owner_id;
     215                 :          0 :         walk_info.execute_by_owner_id = TRUE;
     216                 :            : 
     217                 :            :         /* Walk the interrupt level descriptor list */
     218                 :            : 
     219                 :          0 :         gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
     220         [ #  # ]:          0 :         while (gpe_xrupt_info) {
     221                 :            : 
     222                 :            :                 /* Walk all Gpe Blocks attached to this interrupt level */
     223                 :            : 
     224                 :          0 :                 gpe_block = gpe_xrupt_info->gpe_block_list_head;
     225         [ #  # ]:          0 :                 while (gpe_block) {
     226                 :          0 :                         walk_info.gpe_block = gpe_block;
     227                 :          0 :                         walk_info.gpe_device = gpe_block->node;
     228                 :            : 
     229                 :          0 :                         status = acpi_ns_walk_namespace(ACPI_TYPE_METHOD,
     230                 :            :                                                         walk_info.gpe_device,
     231                 :            :                                                         ACPI_UINT32_MAX,
     232                 :            :                                                         ACPI_NS_WALK_NO_UNLOCK,
     233                 :            :                                                         acpi_ev_match_gpe_method,
     234                 :            :                                                         NULL, &walk_info, NULL);
     235         [ #  # ]:          0 :                         if (ACPI_FAILURE(status)) {
     236                 :          0 :                                 ACPI_EXCEPTION((AE_INFO, status,
     237                 :            :                                                 "While decoding _Lxx/_Exx methods"));
     238                 :            :                         }
     239                 :            : 
     240                 :          0 :                         gpe_block = gpe_block->next;
     241                 :            :                 }
     242                 :            : 
     243                 :          0 :                 gpe_xrupt_info = gpe_xrupt_info->next;
     244                 :            :         }
     245                 :            : 
     246         [ #  # ]:          0 :         if (walk_info.count) {
     247                 :          0 :                 ACPI_INFO(("Enabled %u new GPEs", walk_info.count));
     248                 :            :         }
     249                 :            : 
     250                 :          0 :         (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
     251                 :          0 :         return;
     252                 :            : }
     253                 :            : 
     254                 :            : /*******************************************************************************
     255                 :            :  *
     256                 :            :  * FUNCTION:    acpi_ev_match_gpe_method
     257                 :            :  *
     258                 :            :  * PARAMETERS:  Callback from walk_namespace
     259                 :            :  *
     260                 :            :  * RETURN:      Status
     261                 :            :  *
     262                 :            :  * DESCRIPTION: Called from acpi_walk_namespace. Expects each object to be a
     263                 :            :  *              control method under the _GPE portion of the namespace.
     264                 :            :  *              Extract the name and GPE type from the object, saving this
     265                 :            :  *              information for quick lookup during GPE dispatch. Allows a
     266                 :            :  *              per-owner_id evaluation if execute_by_owner_id is TRUE in the
     267                 :            :  *              walk_info parameter block.
     268                 :            :  *
     269                 :            :  *              The name of each GPE control method is of the form:
     270                 :            :  *              "_Lxx" or "_Exx", where:
     271                 :            :  *                  L      - means that the GPE is level triggered
     272                 :            :  *                  E      - means that the GPE is edge triggered
     273                 :            :  *                  xx     - is the GPE number [in HEX]
     274                 :            :  *
     275                 :            :  * If walk_info->execute_by_owner_id is TRUE, we only execute examine GPE methods
     276                 :            :  * with that owner.
     277                 :            :  *
     278                 :            :  ******************************************************************************/
     279                 :            : 
     280                 :            : acpi_status
     281                 :         42 : acpi_ev_match_gpe_method(acpi_handle obj_handle,
     282                 :            :                          u32 level, void *context, void **return_value)
     283                 :            : {
     284                 :         42 :         struct acpi_namespace_node *method_node =
     285                 :            :             ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle);
     286                 :         42 :         struct acpi_gpe_walk_info *walk_info =
     287                 :            :             ACPI_CAST_PTR(struct acpi_gpe_walk_info, context);
     288                 :         42 :         struct acpi_gpe_event_info *gpe_event_info;
     289                 :         42 :         acpi_status status;
     290                 :         42 :         u32 gpe_number;
     291                 :         42 :         u8 temp_gpe_number;
     292                 :         42 :         char name[ACPI_NAMESEG_SIZE + 1];
     293                 :         42 :         u8 type;
     294                 :            : 
     295                 :         42 :         ACPI_FUNCTION_TRACE(ev_match_gpe_method);
     296                 :            : 
     297                 :            :         /* Check if requested owner_id matches this owner_id */
     298                 :            : 
     299         [ -  + ]:         42 :         if ((walk_info->execute_by_owner_id) &&
     300         [ #  # ]:          0 :             (method_node->owner_id != walk_info->owner_id)) {
     301                 :            :                 return_ACPI_STATUS(AE_OK);
     302                 :            :         }
     303                 :            : 
     304                 :            :         /*
     305                 :            :          * Match and decode the _Lxx and _Exx GPE method names
     306                 :            :          *
     307                 :            :          * 1) Extract the method name and null terminate it
     308                 :            :          */
     309                 :         42 :         ACPI_MOVE_32_TO_32(name, &method_node->name.integer);
     310                 :         42 :         name[ACPI_NAMESEG_SIZE] = 0;
     311                 :            : 
     312                 :            :         /* 2) Name must begin with an underscore */
     313                 :            : 
     314         [ +  - ]:         42 :         if (name[0] != '_') {
     315                 :            :                 return_ACPI_STATUS(AE_OK);      /* Ignore this method */
     316                 :            :         }
     317                 :            : 
     318                 :            :         /*
     319                 :            :          * 3) Edge/Level determination is based on the 2nd character
     320                 :            :          *    of the method name
     321                 :            :          */
     322      [ +  -  - ]:         42 :         switch (name[1]) {
     323                 :            :         case 'L':
     324                 :            : 
     325                 :            :                 type = ACPI_GPE_LEVEL_TRIGGERED;
     326                 :            :                 break;
     327                 :            : 
     328                 :         42 :         case 'E':
     329                 :            : 
     330                 :         42 :                 type = ACPI_GPE_EDGE_TRIGGERED;
     331                 :         42 :                 break;
     332                 :            : 
     333                 :            :         default:
     334                 :            : 
     335                 :            :                 /* Unknown method type, just ignore it */
     336                 :            : 
     337                 :            :                 ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
     338                 :            :                                   "Ignoring unknown GPE method type: %s "
     339                 :            :                                   "(name not of form _Lxx or _Exx)", name));
     340                 :            :                 return_ACPI_STATUS(AE_OK);
     341                 :            :         }
     342                 :            : 
     343                 :            :         /* 4) The last two characters of the name are the hex GPE Number */
     344                 :            : 
     345                 :         42 :         status = acpi_ut_ascii_to_hex_byte(&name[2], &temp_gpe_number);
     346         [ +  - ]:         42 :         if (ACPI_FAILURE(status)) {
     347                 :            : 
     348                 :            :                 /* Conversion failed; invalid method, just ignore it */
     349                 :            : 
     350                 :            :                 ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
     351                 :            :                                   "Could not extract GPE number from name: %s "
     352                 :            :                                   "(name is not of form _Lxx or _Exx)", name));
     353                 :            :                 return_ACPI_STATUS(AE_OK);
     354                 :            :         }
     355                 :            : 
     356                 :            :         /* Ensure that we have a valid GPE number for this GPE block */
     357                 :            : 
     358                 :         42 :         gpe_number = (u32)temp_gpe_number;
     359                 :         42 :         gpe_event_info =
     360                 :         42 :             acpi_ev_low_get_gpe_info(gpe_number, walk_info->gpe_block);
     361         [ +  - ]:         42 :         if (!gpe_event_info) {
     362                 :            :                 /*
     363                 :            :                  * This gpe_number is not valid for this GPE block, just ignore it.
     364                 :            :                  * However, it may be valid for a different GPE block, since GPE0
     365                 :            :                  * and GPE1 methods both appear under \_GPE.
     366                 :            :                  */
     367                 :            :                 return_ACPI_STATUS(AE_OK);
     368                 :            :         }
     369                 :            : 
     370                 :         42 :         if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
     371         [ +  - ]:         42 :              ACPI_GPE_DISPATCH_HANDLER) ||
     372                 :            :             (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
     373                 :            :              ACPI_GPE_DISPATCH_RAW_HANDLER)) {
     374                 :            : 
     375                 :            :                 /* If there is already a handler, ignore this GPE method */
     376                 :            : 
     377                 :            :                 return_ACPI_STATUS(AE_OK);
     378                 :            :         }
     379                 :            : 
     380         [ -  + ]:         42 :         if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
     381                 :            :             ACPI_GPE_DISPATCH_METHOD) {
     382                 :            :                 /*
     383                 :            :                  * If there is already a method, ignore this method. But check
     384                 :            :                  * for a type mismatch (if both the _Lxx AND _Exx exist)
     385                 :            :                  */
     386         [ #  # ]:          0 :                 if (type != (gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK)) {
     387                 :          0 :                         ACPI_ERROR((AE_INFO,
     388                 :            :                                     "For GPE 0x%.2X, found both _L%2.2X and _E%2.2X methods",
     389                 :            :                                     gpe_number, gpe_number, gpe_number));
     390                 :            :                 }
     391                 :          0 :                 return_ACPI_STATUS(AE_OK);
     392                 :            :         }
     393                 :            : 
     394                 :            :         /* Disable the GPE in case it's been enabled already. */
     395                 :            : 
     396                 :         42 :         (void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
     397                 :            : 
     398                 :            :         /*
     399                 :            :          * Add the GPE information from above to the gpe_event_info block for
     400                 :            :          * use during dispatch of this GPE.
     401                 :            :          */
     402                 :         42 :         gpe_event_info->flags &= ~(ACPI_GPE_DISPATCH_MASK);
     403                 :         42 :         gpe_event_info->flags |= (u8)(type | ACPI_GPE_DISPATCH_METHOD);
     404                 :         42 :         gpe_event_info->dispatch.method_node = method_node;
     405                 :            : 
     406                 :            :         ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
     407                 :            :                           "Registered GPE method %s as GPE number 0x%.2X\n",
     408                 :         42 :                           name, gpe_number));
     409                 :         42 :         return_ACPI_STATUS(AE_OK);
     410                 :            : }
     411                 :            : 
     412                 :            : #endif                          /* !ACPI_REDUCED_HARDWARE */

Generated by: LCOV version 1.14