linux/drivers/acpi/acpica/hwgpe.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/******************************************************************************
   3 *
   4 * Module Name: hwgpe - Low level GPE enable/disable/clear functions
   5 *
   6 * Copyright (C) 2000 - 2021, Intel Corp.
   7 *
   8 *****************************************************************************/
   9
  10#include <acpi/acpi.h>
  11#include "accommon.h"
  12#include "acevents.h"
  13
  14#define _COMPONENT          ACPI_HARDWARE
  15ACPI_MODULE_NAME("hwgpe")
  16#if (!ACPI_REDUCED_HARDWARE)    /* Entire module */
  17/* Local prototypes */
  18static acpi_status
  19acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
  20                                struct acpi_gpe_block_info *gpe_block,
  21                                void *context);
  22
  23static acpi_status
  24acpi_hw_gpe_enable_write(u8 enable_mask,
  25                         struct acpi_gpe_register_info *gpe_register_info);
  26
  27/******************************************************************************
  28 *
  29 * FUNCTION:    acpi_hw_gpe_read
  30 *
  31 * PARAMETERS:  value               - Where the value is returned
  32 *              reg                 - GPE register structure
  33 *
  34 * RETURN:      Status
  35 *
  36 * DESCRIPTION: Read from a GPE register in either memory or IO space.
  37 *
  38 * LIMITATIONS: <These limitations also apply to acpi_hw_gpe_write>
  39 *      space_ID must be system_memory or system_IO.
  40 *
  41 ******************************************************************************/
  42
  43acpi_status acpi_hw_gpe_read(u64 *value, struct acpi_gpe_address *reg)
  44{
  45        acpi_status status;
  46        u32 value32;
  47
  48        if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
  49#ifdef ACPI_GPE_USE_LOGICAL_ADDRESSES
  50                *value = (u64)ACPI_GET8((unsigned long)reg->address);
  51                return_ACPI_STATUS(AE_OK);
  52#else
  53                return acpi_os_read_memory((acpi_physical_address)reg->address,
  54                                            value, ACPI_GPE_REGISTER_WIDTH);
  55#endif
  56        }
  57
  58        status = acpi_os_read_port((acpi_io_address)reg->address,
  59                                   &value32, ACPI_GPE_REGISTER_WIDTH);
  60        if (ACPI_FAILURE(status))
  61                return_ACPI_STATUS(status);
  62
  63        *value = (u64)value32;
  64
  65        return_ACPI_STATUS(AE_OK);
  66}
  67
  68/******************************************************************************
  69 *
  70 * FUNCTION:    acpi_hw_gpe_write
  71 *
  72 * PARAMETERS:  value               - Value to be written
  73 *              reg                 - GPE register structure
  74 *
  75 * RETURN:      Status
  76 *
  77 * DESCRIPTION: Write to a GPE register in either memory or IO space.
  78 *
  79 ******************************************************************************/
  80
  81acpi_status acpi_hw_gpe_write(u64 value, struct acpi_gpe_address *reg)
  82{
  83        if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
  84#ifdef ACPI_GPE_USE_LOGICAL_ADDRESSES
  85                ACPI_SET8((unsigned long)reg->address, value);
  86                return_ACPI_STATUS(AE_OK);
  87#else
  88                return acpi_os_write_memory((acpi_physical_address)reg->address,
  89                                            value, ACPI_GPE_REGISTER_WIDTH);
  90#endif
  91        }
  92
  93        return acpi_os_write_port((acpi_io_address)reg->address, (u32)value,
  94                                  ACPI_GPE_REGISTER_WIDTH);
  95}
  96
  97/******************************************************************************
  98 *
  99 * FUNCTION:    acpi_hw_get_gpe_register_bit
 100 *
 101 * PARAMETERS:  gpe_event_info      - Info block for the GPE
 102 *
 103 * RETURN:      Register mask with a one in the GPE bit position
 104 *
 105 * DESCRIPTION: Compute the register mask for this GPE. One bit is set in the
 106 *              correct position for the input GPE.
 107 *
 108 ******************************************************************************/
 109
 110u32 acpi_hw_get_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info)
 111{
 112
 113        return ((u32)1 <<
 114                (gpe_event_info->gpe_number -
 115                 gpe_event_info->register_info->base_gpe_number));
 116}
 117
 118/******************************************************************************
 119 *
 120 * FUNCTION:    acpi_hw_low_set_gpe
 121 *
 122 * PARAMETERS:  gpe_event_info      - Info block for the GPE to be disabled
 123 *              action              - Enable or disable
 124 *
 125 * RETURN:      Status
 126 *
 127 * DESCRIPTION: Enable or disable a single GPE in the parent enable register.
 128 *              The enable_mask field of the involved GPE register must be
 129 *              updated by the caller if necessary.
 130 *
 131 ******************************************************************************/
 132
 133acpi_status
 134acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action)
 135{
 136        struct acpi_gpe_register_info *gpe_register_info;
 137        acpi_status status = AE_OK;
 138        u64 enable_mask;
 139        u32 register_bit;
 140
 141        ACPI_FUNCTION_ENTRY();
 142
 143        /* Get the info block for the entire GPE register */
 144
 145        gpe_register_info = gpe_event_info->register_info;
 146        if (!gpe_register_info) {
 147                return (AE_NOT_EXIST);
 148        }
 149
 150        /* Get current value of the enable register that contains this GPE */
 151
 152        status = acpi_hw_gpe_read(&enable_mask,
 153                                  &gpe_register_info->enable_address);
 154        if (ACPI_FAILURE(status)) {
 155                return (status);
 156        }
 157
 158        /* Set or clear just the bit that corresponds to this GPE */
 159
 160        register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info);
 161        switch (action) {
 162        case ACPI_GPE_CONDITIONAL_ENABLE:
 163
 164                /* Only enable if the corresponding enable_mask bit is set */
 165
 166                if (!(register_bit & gpe_register_info->enable_mask)) {
 167                        return (AE_BAD_PARAMETER);
 168                }
 169
 170                ACPI_FALLTHROUGH;
 171
 172        case ACPI_GPE_ENABLE:
 173
 174                ACPI_SET_BIT(enable_mask, register_bit);
 175                break;
 176
 177        case ACPI_GPE_DISABLE:
 178
 179                ACPI_CLEAR_BIT(enable_mask, register_bit);
 180                break;
 181
 182        default:
 183
 184                ACPI_ERROR((AE_INFO, "Invalid GPE Action, %u", action));
 185                return (AE_BAD_PARAMETER);
 186        }
 187
 188        if (!(register_bit & gpe_register_info->mask_for_run)) {
 189
 190                /* Write the updated enable mask */
 191
 192                status = acpi_hw_gpe_write(enable_mask,
 193                                           &gpe_register_info->enable_address);
 194        }
 195        return (status);
 196}
 197
 198/******************************************************************************
 199 *
 200 * FUNCTION:    acpi_hw_clear_gpe
 201 *
 202 * PARAMETERS:  gpe_event_info      - Info block for the GPE to be cleared
 203 *
 204 * RETURN:      Status
 205 *
 206 * DESCRIPTION: Clear the status bit for a single GPE.
 207 *
 208 ******************************************************************************/
 209
 210acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info *gpe_event_info)
 211{
 212        struct acpi_gpe_register_info *gpe_register_info;
 213        acpi_status status;
 214        u32 register_bit;
 215
 216        ACPI_FUNCTION_ENTRY();
 217
 218        /* Get the info block for the entire GPE register */
 219
 220        gpe_register_info = gpe_event_info->register_info;
 221        if (!gpe_register_info) {
 222                return (AE_NOT_EXIST);
 223        }
 224
 225        /*
 226         * Write a one to the appropriate bit in the status register to
 227         * clear this GPE.
 228         */
 229        register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info);
 230
 231        status = acpi_hw_gpe_write(register_bit,
 232                                   &gpe_register_info->status_address);
 233        return (status);
 234}
 235
 236/******************************************************************************
 237 *
 238 * FUNCTION:    acpi_hw_get_gpe_status
 239 *
 240 * PARAMETERS:  gpe_event_info      - Info block for the GPE to queried
 241 *              event_status        - Where the GPE status is returned
 242 *
 243 * RETURN:      Status
 244 *
 245 * DESCRIPTION: Return the status of a single GPE.
 246 *
 247 ******************************************************************************/
 248
 249acpi_status
 250acpi_hw_get_gpe_status(struct acpi_gpe_event_info *gpe_event_info,
 251                       acpi_event_status *event_status)
 252{
 253        u64 in_byte;
 254        u32 register_bit;
 255        struct acpi_gpe_register_info *gpe_register_info;
 256        acpi_event_status local_event_status = 0;
 257        acpi_status status;
 258
 259        ACPI_FUNCTION_ENTRY();
 260
 261        if (!event_status) {
 262                return (AE_BAD_PARAMETER);
 263        }
 264
 265        /* GPE currently handled? */
 266
 267        if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
 268            ACPI_GPE_DISPATCH_NONE) {
 269                local_event_status |= ACPI_EVENT_FLAG_HAS_HANDLER;
 270        }
 271
 272        /* Get the info block for the entire GPE register */
 273
 274        gpe_register_info = gpe_event_info->register_info;
 275
 276        /* Get the register bitmask for this GPE */
 277
 278        register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info);
 279
 280        /* GPE currently enabled? (enabled for runtime?) */
 281
 282        if (register_bit & gpe_register_info->enable_for_run) {
 283                local_event_status |= ACPI_EVENT_FLAG_ENABLED;
 284        }
 285
 286        /* GPE currently masked? (masked for runtime?) */
 287
 288        if (register_bit & gpe_register_info->mask_for_run) {
 289                local_event_status |= ACPI_EVENT_FLAG_MASKED;
 290        }
 291
 292        /* GPE enabled for wake? */
 293
 294        if (register_bit & gpe_register_info->enable_for_wake) {
 295                local_event_status |= ACPI_EVENT_FLAG_WAKE_ENABLED;
 296        }
 297
 298        /* GPE currently enabled (enable bit == 1)? */
 299
 300        status = acpi_hw_gpe_read(&in_byte, &gpe_register_info->enable_address);
 301        if (ACPI_FAILURE(status)) {
 302                return (status);
 303        }
 304
 305        if (register_bit & in_byte) {
 306                local_event_status |= ACPI_EVENT_FLAG_ENABLE_SET;
 307        }
 308
 309        /* GPE currently active (status bit == 1)? */
 310
 311        status = acpi_hw_gpe_read(&in_byte, &gpe_register_info->status_address);
 312        if (ACPI_FAILURE(status)) {
 313                return (status);
 314        }
 315
 316        if (register_bit & in_byte) {
 317                local_event_status |= ACPI_EVENT_FLAG_STATUS_SET;
 318        }
 319
 320        /* Set return value */
 321
 322        (*event_status) = local_event_status;
 323        return (AE_OK);
 324}
 325
 326/******************************************************************************
 327 *
 328 * FUNCTION:    acpi_hw_gpe_enable_write
 329 *
 330 * PARAMETERS:  enable_mask         - Bit mask to write to the GPE register
 331 *              gpe_register_info   - Gpe Register info
 332 *
 333 * RETURN:      Status
 334 *
 335 * DESCRIPTION: Write the enable mask byte to the given GPE register.
 336 *
 337 ******************************************************************************/
 338
 339static acpi_status
 340acpi_hw_gpe_enable_write(u8 enable_mask,
 341                         struct acpi_gpe_register_info *gpe_register_info)
 342{
 343        acpi_status status;
 344
 345        gpe_register_info->enable_mask = enable_mask;
 346
 347        status = acpi_hw_gpe_write(enable_mask,
 348                                   &gpe_register_info->enable_address);
 349        return (status);
 350}
 351
 352/******************************************************************************
 353 *
 354 * FUNCTION:    acpi_hw_disable_gpe_block
 355 *
 356 * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
 357 *              gpe_block           - Gpe Block info
 358 *
 359 * RETURN:      Status
 360 *
 361 * DESCRIPTION: Disable all GPEs within a single GPE block
 362 *
 363 ******************************************************************************/
 364
 365acpi_status
 366acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
 367                          struct acpi_gpe_block_info *gpe_block, void *context)
 368{
 369        u32 i;
 370        acpi_status status;
 371
 372        /* Examine each GPE Register within the block */
 373
 374        for (i = 0; i < gpe_block->register_count; i++) {
 375
 376                /* Disable all GPEs in this register */
 377
 378                status =
 379                    acpi_hw_gpe_enable_write(0x00,
 380                                             &gpe_block->register_info[i]);
 381                if (ACPI_FAILURE(status)) {
 382                        return (status);
 383                }
 384        }
 385
 386        return (AE_OK);
 387}
 388
 389/******************************************************************************
 390 *
 391 * FUNCTION:    acpi_hw_clear_gpe_block
 392 *
 393 * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
 394 *              gpe_block           - Gpe Block info
 395 *
 396 * RETURN:      Status
 397 *
 398 * DESCRIPTION: Clear status bits for all GPEs within a single GPE block
 399 *
 400 ******************************************************************************/
 401
 402acpi_status
 403acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
 404                        struct acpi_gpe_block_info *gpe_block, void *context)
 405{
 406        u32 i;
 407        acpi_status status;
 408
 409        /* Examine each GPE Register within the block */
 410
 411        for (i = 0; i < gpe_block->register_count; i++) {
 412
 413                /* Clear status on all GPEs in this register */
 414
 415                status = acpi_hw_gpe_write(0xFF,
 416                                           &gpe_block->register_info[i].status_address);
 417                if (ACPI_FAILURE(status)) {
 418                        return (status);
 419                }
 420        }
 421
 422        return (AE_OK);
 423}
 424
 425/******************************************************************************
 426 *
 427 * FUNCTION:    acpi_hw_enable_runtime_gpe_block
 428 *
 429 * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
 430 *              gpe_block           - Gpe Block info
 431 *
 432 * RETURN:      Status
 433 *
 434 * DESCRIPTION: Enable all "runtime" GPEs within a single GPE block. Includes
 435 *              combination wake/run GPEs.
 436 *
 437 ******************************************************************************/
 438
 439acpi_status
 440acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
 441                                 struct acpi_gpe_block_info *gpe_block,
 442                                 void *context)
 443{
 444        u32 i;
 445        acpi_status status;
 446        struct acpi_gpe_register_info *gpe_register_info;
 447        u8 enable_mask;
 448
 449        /* NOTE: assumes that all GPEs are currently disabled */
 450
 451        /* Examine each GPE Register within the block */
 452
 453        for (i = 0; i < gpe_block->register_count; i++) {
 454                gpe_register_info = &gpe_block->register_info[i];
 455                if (!gpe_register_info->enable_for_run) {
 456                        continue;
 457                }
 458
 459                /* Enable all "runtime" GPEs in this register */
 460
 461                enable_mask = gpe_register_info->enable_for_run &
 462                    ~gpe_register_info->mask_for_run;
 463                status =
 464                    acpi_hw_gpe_enable_write(enable_mask, gpe_register_info);
 465                if (ACPI_FAILURE(status)) {
 466                        return (status);
 467                }
 468        }
 469
 470        return (AE_OK);
 471}
 472
 473/******************************************************************************
 474 *
 475 * FUNCTION:    acpi_hw_enable_wakeup_gpe_block
 476 *
 477 * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
 478 *              gpe_block           - Gpe Block info
 479 *
 480 * RETURN:      Status
 481 *
 482 * DESCRIPTION: Enable all "wake" GPEs within a single GPE block. Includes
 483 *              combination wake/run GPEs.
 484 *
 485 ******************************************************************************/
 486
 487static acpi_status
 488acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
 489                                struct acpi_gpe_block_info *gpe_block,
 490                                void *context)
 491{
 492        u32 i;
 493        acpi_status status;
 494        struct acpi_gpe_register_info *gpe_register_info;
 495
 496        /* Examine each GPE Register within the block */
 497
 498        for (i = 0; i < gpe_block->register_count; i++) {
 499                gpe_register_info = &gpe_block->register_info[i];
 500
 501                /*
 502                 * Enable all "wake" GPEs in this register and disable the
 503                 * remaining ones.
 504                 */
 505
 506                status =
 507                    acpi_hw_gpe_enable_write(gpe_register_info->enable_for_wake,
 508                                             gpe_register_info);
 509                if (ACPI_FAILURE(status)) {
 510                        return (status);
 511                }
 512        }
 513
 514        return (AE_OK);
 515}
 516
 517struct acpi_gpe_block_status_context {
 518        struct acpi_gpe_register_info *gpe_skip_register_info;
 519        u8 gpe_skip_mask;
 520        u8 retval;
 521};
 522
 523/******************************************************************************
 524 *
 525 * FUNCTION:    acpi_hw_get_gpe_block_status
 526 *
 527 * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
 528 *              gpe_block           - Gpe Block info
 529 *              context             - GPE list walk context data
 530 *
 531 * RETURN:      Success
 532 *
 533 * DESCRIPTION: Produce a combined GPE status bits mask for the given block.
 534 *
 535 ******************************************************************************/
 536
 537static acpi_status
 538acpi_hw_get_gpe_block_status(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
 539                             struct acpi_gpe_block_info *gpe_block,
 540                             void *context)
 541{
 542        struct acpi_gpe_block_status_context *c = context;
 543        struct acpi_gpe_register_info *gpe_register_info;
 544        u64 in_enable, in_status;
 545        acpi_status status;
 546        u8 ret_mask;
 547        u32 i;
 548
 549        /* Examine each GPE Register within the block */
 550
 551        for (i = 0; i < gpe_block->register_count; i++) {
 552                gpe_register_info = &gpe_block->register_info[i];
 553
 554                status = acpi_hw_gpe_read(&in_enable,
 555                                          &gpe_register_info->enable_address);
 556                if (ACPI_FAILURE(status)) {
 557                        continue;
 558                }
 559
 560                status = acpi_hw_gpe_read(&in_status,
 561                                          &gpe_register_info->status_address);
 562                if (ACPI_FAILURE(status)) {
 563                        continue;
 564                }
 565
 566                ret_mask = in_enable & in_status;
 567                if (ret_mask && c->gpe_skip_register_info == gpe_register_info) {
 568                        ret_mask &= ~c->gpe_skip_mask;
 569                }
 570                c->retval |= ret_mask;
 571        }
 572
 573        return (AE_OK);
 574}
 575
 576/******************************************************************************
 577 *
 578 * FUNCTION:    acpi_hw_disable_all_gpes
 579 *
 580 * PARAMETERS:  None
 581 *
 582 * RETURN:      Status
 583 *
 584 * DESCRIPTION: Disable and clear all GPEs in all GPE blocks
 585 *
 586 ******************************************************************************/
 587
 588acpi_status acpi_hw_disable_all_gpes(void)
 589{
 590        acpi_status status;
 591
 592        ACPI_FUNCTION_TRACE(hw_disable_all_gpes);
 593
 594        status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block, NULL);
 595        return_ACPI_STATUS(status);
 596}
 597
 598/******************************************************************************
 599 *
 600 * FUNCTION:    acpi_hw_enable_all_runtime_gpes
 601 *
 602 * PARAMETERS:  None
 603 *
 604 * RETURN:      Status
 605 *
 606 * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks
 607 *
 608 ******************************************************************************/
 609
 610acpi_status acpi_hw_enable_all_runtime_gpes(void)
 611{
 612        acpi_status status;
 613
 614        ACPI_FUNCTION_TRACE(hw_enable_all_runtime_gpes);
 615
 616        status = acpi_ev_walk_gpe_list(acpi_hw_enable_runtime_gpe_block, NULL);
 617        return_ACPI_STATUS(status);
 618}
 619
 620/******************************************************************************
 621 *
 622 * FUNCTION:    acpi_hw_enable_all_wakeup_gpes
 623 *
 624 * PARAMETERS:  None
 625 *
 626 * RETURN:      Status
 627 *
 628 * DESCRIPTION: Enable all "wakeup" GPEs, in all GPE blocks
 629 *
 630 ******************************************************************************/
 631
 632acpi_status acpi_hw_enable_all_wakeup_gpes(void)
 633{
 634        acpi_status status;
 635
 636        ACPI_FUNCTION_TRACE(hw_enable_all_wakeup_gpes);
 637
 638        status = acpi_ev_walk_gpe_list(acpi_hw_enable_wakeup_gpe_block, NULL);
 639        return_ACPI_STATUS(status);
 640}
 641
 642/******************************************************************************
 643 *
 644 * FUNCTION:    acpi_hw_check_all_gpes
 645 *
 646 * PARAMETERS:  gpe_skip_device      - GPE devoce of the GPE to skip
 647 *              gpe_skip_number      - Number of the GPE to skip
 648 *
 649 * RETURN:      Combined status of all GPEs
 650 *
 651 * DESCRIPTION: Check all enabled GPEs in all GPE blocks, except for the one
 652 *              represented by the "skip" arguments, and return TRUE if the
 653 *              status bit is set for at least one of them of FALSE otherwise.
 654 *
 655 ******************************************************************************/
 656
 657u8 acpi_hw_check_all_gpes(acpi_handle gpe_skip_device, u32 gpe_skip_number)
 658{
 659        struct acpi_gpe_block_status_context context = {
 660                .gpe_skip_register_info = NULL,
 661                .retval = 0,
 662        };
 663        struct acpi_gpe_event_info *gpe_event_info;
 664        acpi_cpu_flags flags;
 665
 666        ACPI_FUNCTION_TRACE(acpi_hw_check_all_gpes);
 667
 668        flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
 669
 670        gpe_event_info = acpi_ev_get_gpe_event_info(gpe_skip_device,
 671                                                    gpe_skip_number);
 672        if (gpe_event_info) {
 673                context.gpe_skip_register_info = gpe_event_info->register_info;
 674                context.gpe_skip_mask = acpi_hw_get_gpe_register_bit(gpe_event_info);
 675        }
 676
 677        acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
 678
 679        (void)acpi_ev_walk_gpe_list(acpi_hw_get_gpe_block_status, &context);
 680        return (context.retval != 0);
 681}
 682
 683#endif                          /* !ACPI_REDUCED_HARDWARE */
 684