brintos

brintos / linux-shallow public Read only

0
0
Text · 13.7 KiB · 58e1890 Raw
502 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: evgpeblk - GPE block creation and initialization.5 *6 * Copyright (C) 2000 - 2023, 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_EVENTS16ACPI_MODULE_NAME("evgpeblk")17#if (!ACPI_REDUCED_HARDWARE)	/* Entire module */18/* Local prototypes */19static acpi_status20acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block,21			  u32 interrupt_number);22 23static acpi_status24acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block);25 26/*******************************************************************************27 *28 * FUNCTION:    acpi_ev_install_gpe_block29 *30 * PARAMETERS:  gpe_block               - New GPE block31 *              interrupt_number        - Xrupt to be associated with this32 *                                        GPE block33 *34 * RETURN:      Status35 *36 * DESCRIPTION: Install new GPE block with mutex support37 *38 ******************************************************************************/39 40static acpi_status41acpi_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_block88 *89 * PARAMETERS:  gpe_block           - Existing GPE block90 *91 * RETURN:      Status92 *93 * DESCRIPTION: Remove a GPE block94 *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_blocks159 *160 * PARAMETERS:  gpe_block   - New GPE block161 *162 * RETURN:      Status163 *164 * DESCRIPTION: Create the register_info and event_info blocks for this GPE block165 *166 ******************************************************************************/167 168static acpi_status169acpi_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(struct186							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 GPEs195	 * per register. Initialization to zeros is sufficient.196	 */197	gpe_event_info = ACPI_ALLOCATE_ZEROED((acpi_size)gpe_block->gpe_count *198					      sizeof(struct199						     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 these214	 * tables is to hide the fact that there are two separate GPE register215	 * sets in a given GPE hardware block, the status registers occupy the216	 * 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 237		/* Init the event_info for each GPE within this register */238 239		for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {240			this_event->gpe_number =241			    (u8) (this_register->base_gpe_number + j);242			this_event->register_info = this_register;243			this_event++;244		}245 246		/* Disable all GPEs within this register */247 248		status = acpi_hw_gpe_write(0x00, &this_register->enable_address);249		if (ACPI_FAILURE(status)) {250			goto error_exit;251		}252 253		/* Clear any pending GPE events within this register */254 255		status = acpi_hw_gpe_write(0xFF, &this_register->status_address);256		if (ACPI_FAILURE(status)) {257			goto error_exit;258		}259 260		this_register++;261	}262 263	return_ACPI_STATUS(AE_OK);264 265error_exit:266	if (gpe_register_info) {267		ACPI_FREE(gpe_register_info);268	}269	if (gpe_event_info) {270		ACPI_FREE(gpe_event_info);271	}272 273	return_ACPI_STATUS(status);274}275 276/*******************************************************************************277 *278 * FUNCTION:    acpi_ev_create_gpe_block279 *280 * PARAMETERS:  gpe_device          - Handle to the parent GPE block281 *              gpe_block_address   - Address and space_ID282 *              register_count      - Number of GPE register pairs in the block283 *              gpe_block_base_number - Starting GPE number for the block284 *              interrupt_number    - H/W interrupt for the block285 *              return_gpe_block    - Where the new block descriptor is returned286 *287 * RETURN:      Status288 *289 * DESCRIPTION: Create and Install a block of GPE registers. All GPEs within290 *              the block are disabled at exit.291 *              Note: Assumes namespace is locked.292 *293 ******************************************************************************/294 295acpi_status296acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,297			 u64 address,298			 u8 space_id,299			 u32 register_count,300			 u16 gpe_block_base_number,301			 u32 interrupt_number,302			 struct acpi_gpe_block_info **return_gpe_block)303{304	acpi_status status;305	struct acpi_gpe_block_info *gpe_block;306	struct acpi_gpe_walk_info walk_info;307 308	ACPI_FUNCTION_TRACE(ev_create_gpe_block);309 310	if (!register_count) {311		return_ACPI_STATUS(AE_OK);312	}313 314	/* Validate the space_ID */315 316	if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&317	    (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {318		ACPI_ERROR((AE_INFO,319			    "Unsupported address space: 0x%X", space_id));320		return_ACPI_STATUS(AE_SUPPORT);321	}322 323	if (space_id == ACPI_ADR_SPACE_SYSTEM_IO) {324		status = acpi_hw_validate_io_block(address,325						   ACPI_GPE_REGISTER_WIDTH,326						   register_count);327		if (ACPI_FAILURE(status))328			return_ACPI_STATUS(status);329	}330 331	/* Allocate a new GPE block */332 333	gpe_block = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_block_info));334	if (!gpe_block) {335		return_ACPI_STATUS(AE_NO_MEMORY);336	}337 338	/* Initialize the new GPE block */339 340	gpe_block->address = address;341	gpe_block->space_id = space_id;342	gpe_block->node = gpe_device;343	gpe_block->gpe_count = (u16)(register_count * ACPI_GPE_REGISTER_WIDTH);344	gpe_block->initialized = FALSE;345	gpe_block->register_count = register_count;346	gpe_block->block_base_number = gpe_block_base_number;347 348	/*349	 * Create the register_info and event_info sub-structures350	 * Note: disables and clears all GPEs in the block351	 */352	status = acpi_ev_create_gpe_info_blocks(gpe_block);353	if (ACPI_FAILURE(status)) {354		ACPI_FREE(gpe_block);355		return_ACPI_STATUS(status);356	}357 358	/* Install the new block in the global lists */359 360	status = acpi_ev_install_gpe_block(gpe_block, interrupt_number);361	if (ACPI_FAILURE(status)) {362		ACPI_FREE(gpe_block->register_info);363		ACPI_FREE(gpe_block->event_info);364		ACPI_FREE(gpe_block);365		return_ACPI_STATUS(status);366	}367 368	acpi_gbl_all_gpes_initialized = FALSE;369 370	/* Find all GPE methods (_Lxx or_Exx) for this block */371 372	walk_info.gpe_block = gpe_block;373	walk_info.gpe_device = gpe_device;374	walk_info.execute_by_owner_id = FALSE;375 376	(void)acpi_ns_walk_namespace(ACPI_TYPE_METHOD, gpe_device,377				     ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK,378				     acpi_ev_match_gpe_method, NULL, &walk_info,379				     NULL);380 381	/* Return the new block */382 383	if (return_gpe_block) {384		(*return_gpe_block) = gpe_block;385	}386 387	ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,388			      "    Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X%s\n",389			      (u32)gpe_block->block_base_number,390			      (u32)(gpe_block->block_base_number +391				    (gpe_block->gpe_count - 1)),392			      gpe_device->name.ascii, gpe_block->register_count,393			      interrupt_number,394			      interrupt_number ==395			      acpi_gbl_FADT.sci_interrupt ? " (SCI)" : ""));396 397	/* Update global count of currently available GPEs */398 399	acpi_current_gpe_count += gpe_block->gpe_count;400	return_ACPI_STATUS(AE_OK);401}402 403/*******************************************************************************404 *405 * FUNCTION:    acpi_ev_initialize_gpe_block406 *407 * PARAMETERS:  acpi_gpe_callback408 *409 * RETURN:      Status410 *411 * DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have412 *              associated methods.413 *              Note: Assumes namespace is locked.414 *415 ******************************************************************************/416 417acpi_status418acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,419			     struct acpi_gpe_block_info *gpe_block,420			     void *context)421{422	acpi_status status;423	struct acpi_gpe_event_info *gpe_event_info;424	u32 gpe_enabled_count;425	u32 gpe_index;426	u32 i;427	u32 j;428	u8 *is_polling_needed = context;429	ACPI_ERROR_ONLY(u32 gpe_number);430 431	ACPI_FUNCTION_TRACE(ev_initialize_gpe_block);432 433	/*434	 * Ignore a null GPE block (e.g., if no GPE block 1 exists), and435	 * any GPE blocks that have been initialized already.436	 */437	if (!gpe_block || gpe_block->initialized) {438		return_ACPI_STATUS(AE_OK);439	}440 441	/*442	 * Enable all GPEs that have a corresponding method and have the443	 * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block444	 * must be enabled via the acpi_enable_gpe() interface.445	 */446	gpe_enabled_count = 0;447 448	for (i = 0; i < gpe_block->register_count; i++) {449		for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {450 451			/* Get the info block for this particular GPE */452 453			gpe_index = (i * ACPI_GPE_REGISTER_WIDTH) + j;454			gpe_event_info = &gpe_block->event_info[gpe_index];455			ACPI_ERROR_ONLY(gpe_number =456					gpe_block->block_base_number +457					gpe_index);458			gpe_event_info->flags |= ACPI_GPE_INITIALIZED;459 460			/*461			 * Ignore GPEs that have no corresponding _Lxx/_Exx method462			 * and GPEs that are used for wakeup463			 */464			if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=465			     ACPI_GPE_DISPATCH_METHOD)466			    || (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {467				continue;468			}469 470			status = acpi_ev_add_gpe_reference(gpe_event_info, FALSE);471			if (ACPI_FAILURE(status)) {472				ACPI_EXCEPTION((AE_INFO, status,473					"Could not enable GPE 0x%02X",474					gpe_number));475				continue;476			}477 478			gpe_event_info->flags |= ACPI_GPE_AUTO_ENABLED;479 480			if (is_polling_needed &&481			    ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) {482				*is_polling_needed = TRUE;483			}484 485			gpe_enabled_count++;486		}487	}488 489	if (gpe_enabled_count) {490		ACPI_INFO(("Enabled %u GPEs in block %02X to %02X",491			   gpe_enabled_count, (u32)gpe_block->block_base_number,492			   (u32)(gpe_block->block_base_number +493				 (gpe_block->gpe_count - 1))));494	}495 496	gpe_block->initialized = TRUE;497 498	return_ACPI_STATUS(AE_OK);499}500 501#endif				/* !ACPI_REDUCED_HARDWARE */502