brintos

brintos / linux-shallow public Read only

0
0
Text · 18.0 KiB · e0c847a Raw
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