684 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: hwgpe - Low level GPE enable/disable/clear functions5 *6 * Copyright (C) 2000 - 2023, Intel Corp.7 *8 *****************************************************************************/9 10#include <acpi/acpi.h>11#include "accommon.h"12#include "acevents.h"13 14#define _COMPONENT ACPI_HARDWARE15ACPI_MODULE_NAME("hwgpe")16#if (!ACPI_REDUCED_HARDWARE) /* Entire module */17/* Local prototypes */18static acpi_status19acpi_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_status24acpi_hw_gpe_enable_write(u8 enable_mask,25 struct acpi_gpe_register_info *gpe_register_info);26 27/******************************************************************************28 *29 * FUNCTION: acpi_hw_gpe_read30 *31 * PARAMETERS: value - Where the value is returned32 * reg - GPE register structure33 *34 * RETURN: Status35 *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_ADDRESSES50 *value = (u64)ACPI_GET8((unsigned long)reg->address);51 return_ACPI_STATUS(AE_OK);52#else53 return acpi_os_read_memory((acpi_physical_address)reg->address,54 value, ACPI_GPE_REGISTER_WIDTH);55#endif56 }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_write71 *72 * PARAMETERS: value - Value to be written73 * reg - GPE register structure74 *75 * RETURN: Status76 *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_ADDRESSES85 ACPI_SET8((unsigned long)reg->address, value);86 return_ACPI_STATUS(AE_OK);87#else88 return acpi_os_write_memory((acpi_physical_address)reg->address,89 value, ACPI_GPE_REGISTER_WIDTH);90#endif91 }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_bit100 *101 * PARAMETERS: gpe_event_info - Info block for the GPE102 *103 * RETURN: Register mask with a one in the GPE bit position104 *105 * DESCRIPTION: Compute the register mask for this GPE. One bit is set in the106 * 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_gpe121 *122 * PARAMETERS: gpe_event_info - Info block for the GPE to be disabled123 * action - Enable or disable124 *125 * RETURN: Status126 *127 * DESCRIPTION: Enable or disable a single GPE in the parent enable register.128 * The enable_mask field of the involved GPE register must be129 * updated by the caller if necessary.130 *131 ******************************************************************************/132 133acpi_status134acpi_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_gpe201 *202 * PARAMETERS: gpe_event_info - Info block for the GPE to be cleared203 *204 * RETURN: Status205 *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 to227 * 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_status239 *240 * PARAMETERS: gpe_event_info - Info block for the GPE to queried241 * event_status - Where the GPE status is returned242 *243 * RETURN: Status244 *245 * DESCRIPTION: Return the status of a single GPE.246 *247 ******************************************************************************/248 249acpi_status250acpi_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_write329 *330 * PARAMETERS: enable_mask - Bit mask to write to the GPE register331 * gpe_register_info - Gpe Register info332 *333 * RETURN: Status334 *335 * DESCRIPTION: Write the enable mask byte to the given GPE register.336 *337 ******************************************************************************/338 339static acpi_status340acpi_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_block355 *356 * PARAMETERS: gpe_xrupt_info - GPE Interrupt info357 * gpe_block - Gpe Block info358 *359 * RETURN: Status360 *361 * DESCRIPTION: Disable all GPEs within a single GPE block362 *363 ******************************************************************************/364 365acpi_status366acpi_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_block392 *393 * PARAMETERS: gpe_xrupt_info - GPE Interrupt info394 * gpe_block - Gpe Block info395 *396 * RETURN: Status397 *398 * DESCRIPTION: Clear status bits for all GPEs within a single GPE block399 *400 ******************************************************************************/401 402acpi_status403acpi_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_block428 *429 * PARAMETERS: gpe_xrupt_info - GPE Interrupt info430 * gpe_block - Gpe Block info431 *432 * RETURN: Status433 *434 * DESCRIPTION: Enable all "runtime" GPEs within a single GPE block. Includes435 * combination wake/run GPEs.436 *437 ******************************************************************************/438 439acpi_status440acpi_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_block476 *477 * PARAMETERS: gpe_xrupt_info - GPE Interrupt info478 * gpe_block - Gpe Block info479 *480 * RETURN: Status481 *482 * DESCRIPTION: Enable all "wake" GPEs within a single GPE block. Includes483 * combination wake/run GPEs.484 *485 ******************************************************************************/486 487static acpi_status488acpi_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 the503 * 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_status526 *527 * PARAMETERS: gpe_xrupt_info - GPE Interrupt info528 * gpe_block - Gpe Block info529 * context - GPE list walk context data530 *531 * RETURN: Success532 *533 * DESCRIPTION: Produce a combined GPE status bits mask for the given block.534 *535 ******************************************************************************/536 537static acpi_status538acpi_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_gpes579 *580 * PARAMETERS: None581 *582 * RETURN: Status583 *584 * DESCRIPTION: Disable and clear all GPEs in all GPE blocks585 *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_gpes601 *602 * PARAMETERS: None603 *604 * RETURN: Status605 *606 * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks607 *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_gpes623 *624 * PARAMETERS: None625 *626 * RETURN: Status627 *628 * DESCRIPTION: Enable all "wakeup" GPEs, in all GPE blocks629 *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_gpes645 *646 * PARAMETERS: gpe_skip_device - GPE devoce of the GPE to skip647 * gpe_skip_number - Number of the GPE to skip648 *649 * RETURN: Combined status of all GPEs650 *651 * DESCRIPTION: Check all enabled GPEs in all GPE blocks, except for the one652 * represented by the "skip" arguments, and return TRUE if the653 * 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