root/drivers/acpi/acpica/evgpeblk.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ACPI_MODULE_NAME
  2. acpi_ev_delete_gpe_block
  3. acpi_ev_create_gpe_info_blocks
  4. acpi_ev_create_gpe_block
  5. acpi_ev_initialize_gpe_block

   1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2 /******************************************************************************
   3  *
   4  * Module Name: evgpeblk - GPE block creation and initialization.
   5  *
   6  * Copyright (C) 2000 - 2019, 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("evgpeblk")
  17 #if (!ACPI_REDUCED_HARDWARE)    /* Entire module */
  18 /* Local prototypes */
  19 static acpi_status
  20 acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block,
  21                           u32 interrupt_number);
  22 
  23 static acpi_status
  24 acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block);
  25 
  26 /*******************************************************************************
  27  *
  28  * FUNCTION:    acpi_ev_install_gpe_block
  29  *
  30  * PARAMETERS:  gpe_block               - New GPE block
  31  *              interrupt_number        - Xrupt to be associated with this
  32  *                                        GPE block
  33  *
  34  * RETURN:      Status
  35  *
  36  * DESCRIPTION: Install new GPE block with mutex support
  37  *
  38  ******************************************************************************/
  39 
  40 static acpi_status
  41 acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block,
  42                           u32 interrupt_number)
  43 {
  44         struct acpi_gpe_block_info *next_gpe_block;
  45         struct acpi_gpe_xrupt_info *gpe_xrupt_block;
  46         acpi_status status;
  47         acpi_cpu_flags flags;
  48 
  49         ACPI_FUNCTION_TRACE(ev_install_gpe_block);
  50 
  51         status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
  52         if (ACPI_FAILURE(status)) {
  53                 return_ACPI_STATUS(status);
  54         }
  55 
  56         status =
  57             acpi_ev_get_gpe_xrupt_block(interrupt_number, &gpe_xrupt_block);
  58         if (ACPI_FAILURE(status)) {
  59                 goto unlock_and_exit;
  60         }
  61 
  62         /* Install the new block at the end of the list with lock */
  63 
  64         flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
  65         if (gpe_xrupt_block->gpe_block_list_head) {
  66                 next_gpe_block = gpe_xrupt_block->gpe_block_list_head;
  67                 while (next_gpe_block->next) {
  68                         next_gpe_block = next_gpe_block->next;
  69                 }
  70 
  71                 next_gpe_block->next = gpe_block;
  72                 gpe_block->previous = next_gpe_block;
  73         } else {
  74                 gpe_xrupt_block->gpe_block_list_head = gpe_block;
  75         }
  76 
  77         gpe_block->xrupt_block = gpe_xrupt_block;
  78         acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
  79 
  80 unlock_and_exit:
  81         (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
  82         return_ACPI_STATUS(status);
  83 }
  84 
  85 /*******************************************************************************
  86  *
  87  * FUNCTION:    acpi_ev_delete_gpe_block
  88  *
  89  * PARAMETERS:  gpe_block           - Existing GPE block
  90  *
  91  * RETURN:      Status
  92  *
  93  * DESCRIPTION: Remove a GPE block
  94  *
  95  ******************************************************************************/
  96 
  97 acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block)
  98 {
  99         acpi_status status;
 100         acpi_cpu_flags flags;
 101 
 102         ACPI_FUNCTION_TRACE(ev_install_gpe_block);
 103 
 104         status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
 105         if (ACPI_FAILURE(status)) {
 106                 return_ACPI_STATUS(status);
 107         }
 108 
 109         /* Disable all GPEs in this block */
 110 
 111         status =
 112             acpi_hw_disable_gpe_block(gpe_block->xrupt_block, gpe_block, NULL);
 113 
 114         if (!gpe_block->previous && !gpe_block->next) {
 115 
 116                 /* This is the last gpe_block on this interrupt */
 117 
 118                 status = acpi_ev_delete_gpe_xrupt(gpe_block->xrupt_block);
 119                 if (ACPI_FAILURE(status)) {
 120                         goto unlock_and_exit;
 121                 }
 122         } else {
 123                 /* Remove the block on this interrupt with lock */
 124 
 125                 flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
 126                 if (gpe_block->previous) {
 127                         gpe_block->previous->next = gpe_block->next;
 128                 } else {
 129                         gpe_block->xrupt_block->gpe_block_list_head =
 130                             gpe_block->next;
 131                 }
 132 
 133                 if (gpe_block->next) {
 134                         gpe_block->next->previous = gpe_block->previous;
 135                 }
 136 
 137                 acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
 138         }
 139 
 140         acpi_current_gpe_count -= gpe_block->gpe_count;
 141 
 142         /* Free the gpe_block */
 143 
 144         ACPI_FREE(gpe_block->register_info);
 145         ACPI_FREE(gpe_block->event_info);
 146         ACPI_FREE(gpe_block);
 147 
 148 unlock_and_exit:
 149         status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
 150         return_ACPI_STATUS(status);
 151 }
 152 
 153 /*******************************************************************************
 154  *
 155  * FUNCTION:    acpi_ev_create_gpe_info_blocks
 156  *
 157  * PARAMETERS:  gpe_block   - New GPE block
 158  *
 159  * RETURN:      Status
 160  *
 161  * DESCRIPTION: Create the register_info and event_info blocks for this GPE block
 162  *
 163  ******************************************************************************/
 164 
 165 static acpi_status
 166 acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
 167 {
 168         struct acpi_gpe_register_info *gpe_register_info = NULL;
 169         struct acpi_gpe_event_info *gpe_event_info = NULL;
 170         struct acpi_gpe_event_info *this_event;
 171         struct acpi_gpe_register_info *this_register;
 172         u32 i;
 173         u32 j;
 174         acpi_status status;
 175 
 176         ACPI_FUNCTION_TRACE(ev_create_gpe_info_blocks);
 177 
 178         /* Allocate the GPE register information block */
 179 
 180         gpe_register_info = ACPI_ALLOCATE_ZEROED((acpi_size)gpe_block->
 181                                                  register_count *
 182                                                  sizeof(struct
 183                                                         acpi_gpe_register_info));
 184         if (!gpe_register_info) {
 185                 ACPI_ERROR((AE_INFO,
 186                             "Could not allocate the GpeRegisterInfo table"));
 187                 return_ACPI_STATUS(AE_NO_MEMORY);
 188         }
 189 
 190         /*
 191          * Allocate the GPE event_info block. There are eight distinct GPEs
 192          * per register. Initialization to zeros is sufficient.
 193          */
 194         gpe_event_info = ACPI_ALLOCATE_ZEROED((acpi_size)gpe_block->gpe_count *
 195                                               sizeof(struct
 196                                                      acpi_gpe_event_info));
 197         if (!gpe_event_info) {
 198                 ACPI_ERROR((AE_INFO,
 199                             "Could not allocate the GpeEventInfo table"));
 200                 status = AE_NO_MEMORY;
 201                 goto error_exit;
 202         }
 203 
 204         /* Save the new Info arrays in the GPE block */
 205 
 206         gpe_block->register_info = gpe_register_info;
 207         gpe_block->event_info = gpe_event_info;
 208 
 209         /*
 210          * Initialize the GPE Register and Event structures. A goal of these
 211          * tables is to hide the fact that there are two separate GPE register
 212          * sets in a given GPE hardware block, the status registers occupy the
 213          * first half, and the enable registers occupy the second half.
 214          */
 215         this_register = gpe_register_info;
 216         this_event = gpe_event_info;
 217 
 218         for (i = 0; i < gpe_block->register_count; i++) {
 219 
 220                 /* Init the register_info for this GPE register (8 GPEs) */
 221 
 222                 this_register->base_gpe_number = (u16)
 223                     (gpe_block->block_base_number +
 224                      (i * ACPI_GPE_REGISTER_WIDTH));
 225 
 226                 this_register->status_address.address = gpe_block->address + i;
 227 
 228                 this_register->enable_address.address =
 229                     gpe_block->address + i + gpe_block->register_count;
 230 
 231                 this_register->status_address.space_id = gpe_block->space_id;
 232                 this_register->enable_address.space_id = gpe_block->space_id;
 233                 this_register->status_address.bit_width =
 234                     ACPI_GPE_REGISTER_WIDTH;
 235                 this_register->enable_address.bit_width =
 236                     ACPI_GPE_REGISTER_WIDTH;
 237                 this_register->status_address.bit_offset = 0;
 238                 this_register->enable_address.bit_offset = 0;
 239 
 240                 /* Init the event_info for each GPE within this register */
 241 
 242                 for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
 243                         this_event->gpe_number =
 244                             (u8) (this_register->base_gpe_number + j);
 245                         this_event->register_info = this_register;
 246                         this_event++;
 247                 }
 248 
 249                 /* Disable all GPEs within this register */
 250 
 251                 status = acpi_hw_write(0x00, &this_register->enable_address);
 252                 if (ACPI_FAILURE(status)) {
 253                         goto error_exit;
 254                 }
 255 
 256                 /* Clear any pending GPE events within this register */
 257 
 258                 status = acpi_hw_write(0xFF, &this_register->status_address);
 259                 if (ACPI_FAILURE(status)) {
 260                         goto error_exit;
 261                 }
 262 
 263                 this_register++;
 264         }
 265 
 266         return_ACPI_STATUS(AE_OK);
 267 
 268 error_exit:
 269         if (gpe_register_info) {
 270                 ACPI_FREE(gpe_register_info);
 271         }
 272         if (gpe_event_info) {
 273                 ACPI_FREE(gpe_event_info);
 274         }
 275 
 276         return_ACPI_STATUS(status);
 277 }
 278 
 279 /*******************************************************************************
 280  *
 281  * FUNCTION:    acpi_ev_create_gpe_block
 282  *
 283  * PARAMETERS:  gpe_device          - Handle to the parent GPE block
 284  *              gpe_block_address   - Address and space_ID
 285  *              register_count      - Number of GPE register pairs in the block
 286  *              gpe_block_base_number - Starting GPE number for the block
 287  *              interrupt_number    - H/W interrupt for the block
 288  *              return_gpe_block    - Where the new block descriptor is returned
 289  *
 290  * RETURN:      Status
 291  *
 292  * DESCRIPTION: Create and Install a block of GPE registers. All GPEs within
 293  *              the block are disabled at exit.
 294  *              Note: Assumes namespace is locked.
 295  *
 296  ******************************************************************************/
 297 
 298 acpi_status
 299 acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
 300                          u64 address,
 301                          u8 space_id,
 302                          u32 register_count,
 303                          u16 gpe_block_base_number,
 304                          u32 interrupt_number,
 305                          struct acpi_gpe_block_info **return_gpe_block)
 306 {
 307         acpi_status status;
 308         struct acpi_gpe_block_info *gpe_block;
 309         struct acpi_gpe_walk_info walk_info;
 310 
 311         ACPI_FUNCTION_TRACE(ev_create_gpe_block);
 312 
 313         if (!register_count) {
 314                 return_ACPI_STATUS(AE_OK);
 315         }
 316 
 317         /* Allocate a new GPE block */
 318 
 319         gpe_block = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_block_info));
 320         if (!gpe_block) {
 321                 return_ACPI_STATUS(AE_NO_MEMORY);
 322         }
 323 
 324         /* Initialize the new GPE block */
 325 
 326         gpe_block->address = address;
 327         gpe_block->space_id = space_id;
 328         gpe_block->node = gpe_device;
 329         gpe_block->gpe_count = (u16)(register_count * ACPI_GPE_REGISTER_WIDTH);
 330         gpe_block->initialized = FALSE;
 331         gpe_block->register_count = register_count;
 332         gpe_block->block_base_number = gpe_block_base_number;
 333 
 334         /*
 335          * Create the register_info and event_info sub-structures
 336          * Note: disables and clears all GPEs in the block
 337          */
 338         status = acpi_ev_create_gpe_info_blocks(gpe_block);
 339         if (ACPI_FAILURE(status)) {
 340                 ACPI_FREE(gpe_block);
 341                 return_ACPI_STATUS(status);
 342         }
 343 
 344         /* Install the new block in the global lists */
 345 
 346         status = acpi_ev_install_gpe_block(gpe_block, interrupt_number);
 347         if (ACPI_FAILURE(status)) {
 348                 ACPI_FREE(gpe_block->register_info);
 349                 ACPI_FREE(gpe_block->event_info);
 350                 ACPI_FREE(gpe_block);
 351                 return_ACPI_STATUS(status);
 352         }
 353 
 354         acpi_gbl_all_gpes_initialized = FALSE;
 355 
 356         /* Find all GPE methods (_Lxx or_Exx) for this block */
 357 
 358         walk_info.gpe_block = gpe_block;
 359         walk_info.gpe_device = gpe_device;
 360         walk_info.execute_by_owner_id = FALSE;
 361 
 362         status = acpi_ns_walk_namespace(ACPI_TYPE_METHOD, gpe_device,
 363                                         ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK,
 364                                         acpi_ev_match_gpe_method, NULL,
 365                                         &walk_info, NULL);
 366 
 367         /* Return the new block */
 368 
 369         if (return_gpe_block) {
 370                 (*return_gpe_block) = gpe_block;
 371         }
 372 
 373         ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
 374                               "    Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X%s\n",
 375                               (u32)gpe_block->block_base_number,
 376                               (u32)(gpe_block->block_base_number +
 377                                     (gpe_block->gpe_count - 1)),
 378                               gpe_device->name.ascii, gpe_block->register_count,
 379                               interrupt_number,
 380                               interrupt_number ==
 381                               acpi_gbl_FADT.sci_interrupt ? " (SCI)" : ""));
 382 
 383         /* Update global count of currently available GPEs */
 384 
 385         acpi_current_gpe_count += gpe_block->gpe_count;
 386         return_ACPI_STATUS(AE_OK);
 387 }
 388 
 389 /*******************************************************************************
 390  *
 391  * FUNCTION:    acpi_ev_initialize_gpe_block
 392  *
 393  * PARAMETERS:  acpi_gpe_callback
 394  *
 395  * RETURN:      Status
 396  *
 397  * DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have
 398  *              associated methods.
 399  *              Note: Assumes namespace is locked.
 400  *
 401  ******************************************************************************/
 402 
 403 acpi_status
 404 acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
 405                              struct acpi_gpe_block_info *gpe_block,
 406                              void *context)
 407 {
 408         acpi_status status;
 409         struct acpi_gpe_event_info *gpe_event_info;
 410         u32 gpe_enabled_count;
 411         u32 gpe_index;
 412         u32 i;
 413         u32 j;
 414         u8 *is_polling_needed = context;
 415         ACPI_ERROR_ONLY(u32 gpe_number);
 416 
 417         ACPI_FUNCTION_TRACE(ev_initialize_gpe_block);
 418 
 419         /*
 420          * Ignore a null GPE block (e.g., if no GPE block 1 exists), and
 421          * any GPE blocks that have been initialized already.
 422          */
 423         if (!gpe_block || gpe_block->initialized) {
 424                 return_ACPI_STATUS(AE_OK);
 425         }
 426 
 427         /*
 428          * Enable all GPEs that have a corresponding method and have the
 429          * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block
 430          * must be enabled via the acpi_enable_gpe() interface.
 431          */
 432         gpe_enabled_count = 0;
 433 
 434         for (i = 0; i < gpe_block->register_count; i++) {
 435                 for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
 436 
 437                         /* Get the info block for this particular GPE */
 438 
 439                         gpe_index = (i * ACPI_GPE_REGISTER_WIDTH) + j;
 440                         gpe_event_info = &gpe_block->event_info[gpe_index];
 441                         ACPI_ERROR_ONLY(gpe_number =
 442                                         gpe_block->block_base_number +
 443                                         gpe_index);
 444                         gpe_event_info->flags |= ACPI_GPE_INITIALIZED;
 445 
 446                         /*
 447                          * Ignore GPEs that have no corresponding _Lxx/_Exx method
 448                          * and GPEs that are used for wakeup
 449                          */
 450                         if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
 451                              ACPI_GPE_DISPATCH_METHOD)
 452                             || (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
 453                                 continue;
 454                         }
 455 
 456                         status = acpi_ev_add_gpe_reference(gpe_event_info, FALSE);
 457                         if (ACPI_FAILURE(status)) {
 458                                 ACPI_EXCEPTION((AE_INFO, status,
 459                                         "Could not enable GPE 0x%02X",
 460                                         gpe_number));
 461                                 continue;
 462                         }
 463 
 464                         gpe_event_info->flags |= ACPI_GPE_AUTO_ENABLED;
 465 
 466                         if (is_polling_needed &&
 467                             ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) {
 468                                 *is_polling_needed = TRUE;
 469                         }
 470 
 471                         gpe_enabled_count++;
 472                 }
 473         }
 474 
 475         if (gpe_enabled_count) {
 476                 ACPI_INFO(("Enabled %u GPEs in block %02X to %02X",
 477                            gpe_enabled_count, (u32)gpe_block->block_base_number,
 478                            (u32)(gpe_block->block_base_number +
 479                                  (gpe_block->gpe_count - 1))));
 480         }
 481 
 482         gpe_block->initialized = TRUE;
 483 
 484         return_ACPI_STATUS(AE_OK);
 485 }
 486 
 487 #endif                          /* !ACPI_REDUCED_HARDWARE */

/* [<][>][^][v][top][bottom][index][help] */