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