cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

evgpeutil.c (8970B)


      1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
      2/******************************************************************************
      3 *
      4 * Module Name: evgpeutil - GPE utilities
      5 *
      6 * Copyright (C) 2000 - 2022, Intel Corp.
      7 *
      8 *****************************************************************************/
      9
     10#include <acpi/acpi.h>
     11#include "accommon.h"
     12#include "acevents.h"
     13
     14#define _COMPONENT          ACPI_EVENTS
     15ACPI_MODULE_NAME("evgpeutil")
     16
     17#if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
     18/*******************************************************************************
     19 *
     20 * FUNCTION:    acpi_ev_walk_gpe_list
     21 *
     22 * PARAMETERS:  gpe_walk_callback   - Routine called for each GPE block
     23 *              context             - Value passed to callback
     24 *
     25 * RETURN:      Status
     26 *
     27 * DESCRIPTION: Walk the GPE lists.
     28 *
     29 ******************************************************************************/
     30acpi_status
     31acpi_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_device
     78 *
     79 * PARAMETERS:  GPE_WALK_CALLBACK
     80 *
     81 * RETURN:      Status
     82 *
     83 * DESCRIPTION: Matches the input GPE index (0-current_gpe_count) with a GPE
     84 *              block device. NULL if the GPE is one of the FADT-defined GPEs.
     85 *
     86 ******************************************************************************/
     87
     88acpi_status
     89acpi_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 node
    101		 * NULL for the FADT-defined GPEs
    102		 */
    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_block
    117 *
    118 * PARAMETERS:  interrupt_number            - Interrupt for a GPE block
    119 *              gpe_xrupt_block             - Where the block is returned
    120 *
    121 * RETURN:      Status
    122 *
    123 * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt
    124 *              block per unique interrupt level used for GPEs. Should be
    125 *              called only when the GPE lists are semaphore locked and not
    126 *              subject to change.
    127 *
    128 ******************************************************************************/
    129
    130acpi_status
    131acpi_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_xrupt
    200 *
    201 * PARAMETERS:  gpe_xrupt       - A GPE interrupt info block
    202 *
    203 * RETURN:      Status
    204 *
    205 * DESCRIPTION: Remove and free a gpe_xrupt block. Remove an associated
    206 *              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_handlers
    258 *
    259 * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
    260 *              gpe_block           - Gpe Block info
    261 *
    262 * RETURN:      Status
    263 *
    264 * DESCRIPTION: Delete all Handler objects found in the GPE data structs.
    265 *              Used only prior to termination.
    266 *
    267 ******************************************************************************/
    268
    269acpi_status
    270acpi_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 */