Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /******************************************************************************
0003  *
0004  * Module Name: evgpeutil - GPE utilities
0005  *
0006  * Copyright (C) 2000 - 2022, Intel Corp.
0007  *
0008  *****************************************************************************/
0009 
0010 #include <acpi/acpi.h>
0011 #include "accommon.h"
0012 #include "acevents.h"
0013 
0014 #define _COMPONENT          ACPI_EVENTS
0015 ACPI_MODULE_NAME("evgpeutil")
0016 
0017 #if (!ACPI_REDUCED_HARDWARE)    /* Entire module */
0018 /*******************************************************************************
0019  *
0020  * FUNCTION:    acpi_ev_walk_gpe_list
0021  *
0022  * PARAMETERS:  gpe_walk_callback   - Routine called for each GPE block
0023  *              context             - Value passed to callback
0024  *
0025  * RETURN:      Status
0026  *
0027  * DESCRIPTION: Walk the GPE lists.
0028  *
0029  ******************************************************************************/
0030 acpi_status
0031 acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback, void *context)
0032 {
0033     struct acpi_gpe_block_info *gpe_block;
0034     struct acpi_gpe_xrupt_info *gpe_xrupt_info;
0035     acpi_status status = AE_OK;
0036     acpi_cpu_flags flags;
0037 
0038     ACPI_FUNCTION_TRACE(ev_walk_gpe_list);
0039 
0040     flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
0041 
0042     /* Walk the interrupt level descriptor list */
0043 
0044     gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
0045     while (gpe_xrupt_info) {
0046 
0047         /* Walk all Gpe Blocks attached to this interrupt level */
0048 
0049         gpe_block = gpe_xrupt_info->gpe_block_list_head;
0050         while (gpe_block) {
0051 
0052             /* One callback per GPE block */
0053 
0054             status =
0055                 gpe_walk_callback(gpe_xrupt_info, gpe_block,
0056                           context);
0057             if (ACPI_FAILURE(status)) {
0058                 if (status == AE_CTRL_END) {    /* Callback abort */
0059                     status = AE_OK;
0060                 }
0061                 goto unlock_and_exit;
0062             }
0063 
0064             gpe_block = gpe_block->next;
0065         }
0066 
0067         gpe_xrupt_info = gpe_xrupt_info->next;
0068     }
0069 
0070 unlock_and_exit:
0071     acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
0072     return_ACPI_STATUS(status);
0073 }
0074 
0075 /*******************************************************************************
0076  *
0077  * FUNCTION:    acpi_ev_get_gpe_device
0078  *
0079  * PARAMETERS:  GPE_WALK_CALLBACK
0080  *
0081  * RETURN:      Status
0082  *
0083  * DESCRIPTION: Matches the input GPE index (0-current_gpe_count) with a GPE
0084  *              block device. NULL if the GPE is one of the FADT-defined GPEs.
0085  *
0086  ******************************************************************************/
0087 
0088 acpi_status
0089 acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
0090                struct acpi_gpe_block_info *gpe_block, void *context)
0091 {
0092     struct acpi_gpe_device_info *info = context;
0093 
0094     /* Increment Index by the number of GPEs in this block */
0095 
0096     info->next_block_base_index += gpe_block->gpe_count;
0097 
0098     if (info->index < info->next_block_base_index) {
0099         /*
0100          * The GPE index is within this block, get the node. Leave the node
0101          * NULL for the FADT-defined GPEs
0102          */
0103         if ((gpe_block->node)->type == ACPI_TYPE_DEVICE) {
0104             info->gpe_device = gpe_block->node;
0105         }
0106 
0107         info->status = AE_OK;
0108         return (AE_CTRL_END);
0109     }
0110 
0111     return (AE_OK);
0112 }
0113 
0114 /*******************************************************************************
0115  *
0116  * FUNCTION:    acpi_ev_get_gpe_xrupt_block
0117  *
0118  * PARAMETERS:  interrupt_number            - Interrupt for a GPE block
0119  *              gpe_xrupt_block             - Where the block is returned
0120  *
0121  * RETURN:      Status
0122  *
0123  * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt
0124  *              block per unique interrupt level used for GPEs. Should be
0125  *              called only when the GPE lists are semaphore locked and not
0126  *              subject to change.
0127  *
0128  ******************************************************************************/
0129 
0130 acpi_status
0131 acpi_ev_get_gpe_xrupt_block(u32 interrupt_number,
0132                 struct acpi_gpe_xrupt_info **gpe_xrupt_block)
0133 {
0134     struct acpi_gpe_xrupt_info *next_gpe_xrupt;
0135     struct acpi_gpe_xrupt_info *gpe_xrupt;
0136     acpi_status status;
0137     acpi_cpu_flags flags;
0138 
0139     ACPI_FUNCTION_TRACE(ev_get_gpe_xrupt_block);
0140 
0141     /* No need for lock since we are not changing any list elements here */
0142 
0143     next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head;
0144     while (next_gpe_xrupt) {
0145         if (next_gpe_xrupt->interrupt_number == interrupt_number) {
0146             *gpe_xrupt_block = next_gpe_xrupt;
0147             return_ACPI_STATUS(AE_OK);
0148         }
0149 
0150         next_gpe_xrupt = next_gpe_xrupt->next;
0151     }
0152 
0153     /* Not found, must allocate a new xrupt descriptor */
0154 
0155     gpe_xrupt = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_xrupt_info));
0156     if (!gpe_xrupt) {
0157         return_ACPI_STATUS(AE_NO_MEMORY);
0158     }
0159 
0160     gpe_xrupt->interrupt_number = interrupt_number;
0161 
0162     /* Install new interrupt descriptor with spin lock */
0163 
0164     flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
0165     if (acpi_gbl_gpe_xrupt_list_head) {
0166         next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head;
0167         while (next_gpe_xrupt->next) {
0168             next_gpe_xrupt = next_gpe_xrupt->next;
0169         }
0170 
0171         next_gpe_xrupt->next = gpe_xrupt;
0172         gpe_xrupt->previous = next_gpe_xrupt;
0173     } else {
0174         acpi_gbl_gpe_xrupt_list_head = gpe_xrupt;
0175     }
0176 
0177     acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
0178 
0179     /* Install new interrupt handler if not SCI_INT */
0180 
0181     if (interrupt_number != acpi_gbl_FADT.sci_interrupt) {
0182         status = acpi_os_install_interrupt_handler(interrupt_number,
0183                                acpi_ev_gpe_xrupt_handler,
0184                                gpe_xrupt);
0185         if (ACPI_FAILURE(status)) {
0186             ACPI_EXCEPTION((AE_INFO, status,
0187                     "Could not install GPE interrupt handler at level 0x%X",
0188                     interrupt_number));
0189             return_ACPI_STATUS(status);
0190         }
0191     }
0192 
0193     *gpe_xrupt_block = gpe_xrupt;
0194     return_ACPI_STATUS(AE_OK);
0195 }
0196 
0197 /*******************************************************************************
0198  *
0199  * FUNCTION:    acpi_ev_delete_gpe_xrupt
0200  *
0201  * PARAMETERS:  gpe_xrupt       - A GPE interrupt info block
0202  *
0203  * RETURN:      Status
0204  *
0205  * DESCRIPTION: Remove and free a gpe_xrupt block. Remove an associated
0206  *              interrupt handler if not the SCI interrupt.
0207  *
0208  ******************************************************************************/
0209 
0210 acpi_status acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt)
0211 {
0212     acpi_status status;
0213     acpi_cpu_flags flags;
0214 
0215     ACPI_FUNCTION_TRACE(ev_delete_gpe_xrupt);
0216 
0217     /* We never want to remove the SCI interrupt handler */
0218 
0219     if (gpe_xrupt->interrupt_number == acpi_gbl_FADT.sci_interrupt) {
0220         gpe_xrupt->gpe_block_list_head = NULL;
0221         return_ACPI_STATUS(AE_OK);
0222     }
0223 
0224     /* Disable this interrupt */
0225 
0226     status =
0227         acpi_os_remove_interrupt_handler(gpe_xrupt->interrupt_number,
0228                          acpi_ev_gpe_xrupt_handler);
0229     if (ACPI_FAILURE(status)) {
0230         return_ACPI_STATUS(status);
0231     }
0232 
0233     /* Unlink the interrupt block with lock */
0234 
0235     flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
0236     if (gpe_xrupt->previous) {
0237         gpe_xrupt->previous->next = gpe_xrupt->next;
0238     } else {
0239         /* No previous, update list head */
0240 
0241         acpi_gbl_gpe_xrupt_list_head = gpe_xrupt->next;
0242     }
0243 
0244     if (gpe_xrupt->next) {
0245         gpe_xrupt->next->previous = gpe_xrupt->previous;
0246     }
0247     acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
0248 
0249     /* Free the block */
0250 
0251     ACPI_FREE(gpe_xrupt);
0252     return_ACPI_STATUS(AE_OK);
0253 }
0254 
0255 /*******************************************************************************
0256  *
0257  * FUNCTION:    acpi_ev_delete_gpe_handlers
0258  *
0259  * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
0260  *              gpe_block           - Gpe Block info
0261  *
0262  * RETURN:      Status
0263  *
0264  * DESCRIPTION: Delete all Handler objects found in the GPE data structs.
0265  *              Used only prior to termination.
0266  *
0267  ******************************************************************************/
0268 
0269 acpi_status
0270 acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
0271                 struct acpi_gpe_block_info *gpe_block,
0272                 void *context)
0273 {
0274     struct acpi_gpe_event_info *gpe_event_info;
0275     struct acpi_gpe_notify_info *notify;
0276     struct acpi_gpe_notify_info *next;
0277     u32 i;
0278     u32 j;
0279 
0280     ACPI_FUNCTION_TRACE(ev_delete_gpe_handlers);
0281 
0282     /* Examine each GPE Register within the block */
0283 
0284     for (i = 0; i < gpe_block->register_count; i++) {
0285 
0286         /* Now look at the individual GPEs in this byte register */
0287 
0288         for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
0289             gpe_event_info = &gpe_block->event_info[((acpi_size)i *
0290                                  ACPI_GPE_REGISTER_WIDTH)
0291                                 + j];
0292 
0293             if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
0294                  ACPI_GPE_DISPATCH_HANDLER) ||
0295                 (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
0296                  ACPI_GPE_DISPATCH_RAW_HANDLER)) {
0297 
0298                 /* Delete an installed handler block */
0299 
0300                 ACPI_FREE(gpe_event_info->dispatch.handler);
0301                 gpe_event_info->dispatch.handler = NULL;
0302                 gpe_event_info->flags &=
0303                     ~ACPI_GPE_DISPATCH_MASK;
0304             } else if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags)
0305                    == ACPI_GPE_DISPATCH_NOTIFY) {
0306 
0307                 /* Delete the implicit notification device list */
0308 
0309                 notify = gpe_event_info->dispatch.notify_list;
0310                 while (notify) {
0311                     next = notify->next;
0312                     ACPI_FREE(notify);
0313                     notify = next;
0314                 }
0315 
0316                 gpe_event_info->dispatch.notify_list = NULL;
0317                 gpe_event_info->flags &=
0318                     ~ACPI_GPE_DISPATCH_MASK;
0319             }
0320         }
0321     }
0322 
0323     return_ACPI_STATUS(AE_OK);
0324 }
0325 
0326 #endif              /* !ACPI_REDUCED_HARDWARE */