brintos

brintos / linux-shallow public Read only

0
0
Text · 8.8 KiB · ee3b1ea Raw
327 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: evgpeutil - GPE utilities5 *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_EVENTS15ACPI_MODULE_NAME("evgpeutil")16 17#if (!ACPI_REDUCED_HARDWARE)	/* Entire module */18/*******************************************************************************19 *20 * FUNCTION:    acpi_ev_walk_gpe_list21 *22 * PARAMETERS:  gpe_walk_callback   - Routine called for each GPE block23 *              context             - Value passed to callback24 *25 * RETURN:      Status26 *27 * DESCRIPTION: Walk the GPE lists.28 *29 ******************************************************************************/30acpi_status31acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback, void *context)32{33	struct acpi_gpe_block_info *gpe_block;34	struct acpi_gpe_xrupt_info *gpe_xrupt_info;35	acpi_status status = AE_OK;36	acpi_cpu_flags flags;37 38	ACPI_FUNCTION_TRACE(ev_walk_gpe_list);39 40	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);41 42	/* Walk the interrupt level descriptor list */43 44	gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;45	while (gpe_xrupt_info) {46 47		/* Walk all Gpe Blocks attached to this interrupt level */48 49		gpe_block = gpe_xrupt_info->gpe_block_list_head;50		while (gpe_block) {51 52			/* One callback per GPE block */53 54			status =55			    gpe_walk_callback(gpe_xrupt_info, gpe_block,56					      context);57			if (ACPI_FAILURE(status)) {58				if (status == AE_CTRL_END) {	/* Callback abort */59					status = AE_OK;60				}61				goto unlock_and_exit;62			}63 64			gpe_block = gpe_block->next;65		}66 67		gpe_xrupt_info = gpe_xrupt_info->next;68	}69 70unlock_and_exit:71	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);72	return_ACPI_STATUS(status);73}74 75/*******************************************************************************76 *77 * FUNCTION:    acpi_ev_get_gpe_device78 *79 * PARAMETERS:  GPE_WALK_CALLBACK80 *81 * RETURN:      Status82 *83 * DESCRIPTION: Matches the input GPE index (0-current_gpe_count) with a GPE84 *              block device. NULL if the GPE is one of the FADT-defined GPEs.85 *86 ******************************************************************************/87 88acpi_status89acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,90		       struct acpi_gpe_block_info *gpe_block, void *context)91{92	struct acpi_gpe_device_info *info = context;93 94	/* Increment Index by the number of GPEs in this block */95 96	info->next_block_base_index += gpe_block->gpe_count;97 98	if (info->index < info->next_block_base_index) {99		/*100		 * The GPE index is within this block, get the node. Leave the node101		 * NULL for the FADT-defined GPEs102		 */103		if ((gpe_block->node)->type == ACPI_TYPE_DEVICE) {104			info->gpe_device = gpe_block->node;105		}106 107		info->status = AE_OK;108		return (AE_CTRL_END);109	}110 111	return (AE_OK);112}113 114/*******************************************************************************115 *116 * FUNCTION:    acpi_ev_get_gpe_xrupt_block117 *118 * PARAMETERS:  interrupt_number            - Interrupt for a GPE block119 *              gpe_xrupt_block             - Where the block is returned120 *121 * RETURN:      Status122 *123 * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt124 *              block per unique interrupt level used for GPEs. Should be125 *              called only when the GPE lists are semaphore locked and not126 *              subject to change.127 *128 ******************************************************************************/129 130acpi_status131acpi_ev_get_gpe_xrupt_block(u32 interrupt_number,132			    struct acpi_gpe_xrupt_info **gpe_xrupt_block)133{134	struct acpi_gpe_xrupt_info *next_gpe_xrupt;135	struct acpi_gpe_xrupt_info *gpe_xrupt;136	acpi_status status;137	acpi_cpu_flags flags;138 139	ACPI_FUNCTION_TRACE(ev_get_gpe_xrupt_block);140 141	/* No need for lock since we are not changing any list elements here */142 143	next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head;144	while (next_gpe_xrupt) {145		if (next_gpe_xrupt->interrupt_number == interrupt_number) {146			*gpe_xrupt_block = next_gpe_xrupt;147			return_ACPI_STATUS(AE_OK);148		}149 150		next_gpe_xrupt = next_gpe_xrupt->next;151	}152 153	/* Not found, must allocate a new xrupt descriptor */154 155	gpe_xrupt = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_xrupt_info));156	if (!gpe_xrupt) {157		return_ACPI_STATUS(AE_NO_MEMORY);158	}159 160	gpe_xrupt->interrupt_number = interrupt_number;161 162	/* Install new interrupt descriptor with spin lock */163 164	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);165	if (acpi_gbl_gpe_xrupt_list_head) {166		next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head;167		while (next_gpe_xrupt->next) {168			next_gpe_xrupt = next_gpe_xrupt->next;169		}170 171		next_gpe_xrupt->next = gpe_xrupt;172		gpe_xrupt->previous = next_gpe_xrupt;173	} else {174		acpi_gbl_gpe_xrupt_list_head = gpe_xrupt;175	}176 177	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);178 179	/* Install new interrupt handler if not SCI_INT */180 181	if (interrupt_number != acpi_gbl_FADT.sci_interrupt) {182		status = acpi_os_install_interrupt_handler(interrupt_number,183							   acpi_ev_gpe_xrupt_handler,184							   gpe_xrupt);185		if (ACPI_FAILURE(status)) {186			ACPI_EXCEPTION((AE_INFO, status,187					"Could not install GPE interrupt handler at level 0x%X",188					interrupt_number));189			return_ACPI_STATUS(status);190		}191	}192 193	*gpe_xrupt_block = gpe_xrupt;194	return_ACPI_STATUS(AE_OK);195}196 197/*******************************************************************************198 *199 * FUNCTION:    acpi_ev_delete_gpe_xrupt200 *201 * PARAMETERS:  gpe_xrupt       - A GPE interrupt info block202 *203 * RETURN:      Status204 *205 * DESCRIPTION: Remove and free a gpe_xrupt block. Remove an associated206 *              interrupt handler if not the SCI interrupt.207 *208 ******************************************************************************/209 210acpi_status acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt)211{212	acpi_status status;213	acpi_cpu_flags flags;214 215	ACPI_FUNCTION_TRACE(ev_delete_gpe_xrupt);216 217	/* We never want to remove the SCI interrupt handler */218 219	if (gpe_xrupt->interrupt_number == acpi_gbl_FADT.sci_interrupt) {220		gpe_xrupt->gpe_block_list_head = NULL;221		return_ACPI_STATUS(AE_OK);222	}223 224	/* Disable this interrupt */225 226	status =227	    acpi_os_remove_interrupt_handler(gpe_xrupt->interrupt_number,228					     acpi_ev_gpe_xrupt_handler);229	if (ACPI_FAILURE(status)) {230		return_ACPI_STATUS(status);231	}232 233	/* Unlink the interrupt block with lock */234 235	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);236	if (gpe_xrupt->previous) {237		gpe_xrupt->previous->next = gpe_xrupt->next;238	} else {239		/* No previous, update list head */240 241		acpi_gbl_gpe_xrupt_list_head = gpe_xrupt->next;242	}243 244	if (gpe_xrupt->next) {245		gpe_xrupt->next->previous = gpe_xrupt->previous;246	}247	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);248 249	/* Free the block */250 251	ACPI_FREE(gpe_xrupt);252	return_ACPI_STATUS(AE_OK);253}254 255/*******************************************************************************256 *257 * FUNCTION:    acpi_ev_delete_gpe_handlers258 *259 * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info260 *              gpe_block           - Gpe Block info261 *262 * RETURN:      Status263 *264 * DESCRIPTION: Delete all Handler objects found in the GPE data structs.265 *              Used only prior to termination.266 *267 ******************************************************************************/268 269acpi_status270acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info,271			    struct acpi_gpe_block_info *gpe_block,272			    void *context)273{274	struct acpi_gpe_event_info *gpe_event_info;275	struct acpi_gpe_notify_info *notify;276	struct acpi_gpe_notify_info *next;277	u32 i;278	u32 j;279 280	ACPI_FUNCTION_TRACE(ev_delete_gpe_handlers);281 282	/* Examine each GPE Register within the block */283 284	for (i = 0; i < gpe_block->register_count; i++) {285 286		/* Now look at the individual GPEs in this byte register */287 288		for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {289			gpe_event_info = &gpe_block->event_info[((acpi_size)i *290								 ACPI_GPE_REGISTER_WIDTH)291								+ j];292 293			if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==294			     ACPI_GPE_DISPATCH_HANDLER) ||295			    (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==296			     ACPI_GPE_DISPATCH_RAW_HANDLER)) {297 298				/* Delete an installed handler block */299 300				ACPI_FREE(gpe_event_info->dispatch.handler);301				gpe_event_info->dispatch.handler = NULL;302				gpe_event_info->flags &=303				    ~ACPI_GPE_DISPATCH_MASK;304			} else if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags)305				   == ACPI_GPE_DISPATCH_NOTIFY) {306 307				/* Delete the implicit notification device list */308 309				notify = gpe_event_info->dispatch.notify_list;310				while (notify) {311					next = notify->next;312					ACPI_FREE(notify);313					notify = next;314				}315 316				gpe_event_info->dispatch.notify_list = NULL;317				gpe_event_info->flags &=318				    ~ACPI_GPE_DISPATCH_MASK;319			}320		}321	}322 323	return_ACPI_STATUS(AE_OK);324}325 326#endif				/* !ACPI_REDUCED_HARDWARE */327