acpi_status acpi_ev_acquire_global_lock(u16 timeout) { acpi_cpu_flags flags; acpi_status status; u8 acquired = FALSE; ACPI_FUNCTION_TRACE(ev_acquire_global_lock); status = acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex->mutex. os_mutex, timeout); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } acpi_gbl_global_lock_handle++; if (acpi_gbl_global_lock_handle == 0) { acpi_gbl_global_lock_handle = 1; } if (!acpi_gbl_global_lock_present) { acpi_gbl_global_lock_acquired = TRUE; return_ACPI_STATUS(AE_OK); } flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock); do { ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired); if (acquired) { acpi_gbl_global_lock_acquired = TRUE; ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Acquired hardware Global Lock\n")); break; } acpi_gbl_global_lock_pending = TRUE; acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags); ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for hardware Global Lock\n")); status = acpi_ex_system_wait_semaphore (acpi_gbl_global_lock_semaphore, ACPI_WAIT_FOREVER); flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock); } while (ACPI_SUCCESS(status)); acpi_gbl_global_lock_pending = FALSE; acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags); return_ACPI_STATUS(status); }
static u32 acpi_ev_global_lock_handler(void *context) { acpi_status status; acpi_cpu_flags flags; flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock); /* * If a request for the global lock is not actually pending, * we are done. This handles "spurious" global lock interrupts * which are possible (and have been seen) with bad BIOSs. */ if (!acpi_gbl_global_lock_pending) { goto cleanup_and_exit; } /* * Send a unit to the global lock semaphore. The actual acquisition * of the global lock will be performed by the waiting thread. */ status = acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore, 1); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Could not signal Global Lock semaphore")); } acpi_gbl_global_lock_pending = FALSE; cleanup_and_exit: acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags); return (ACPI_INTERRUPT_HANDLED); }
/******************************************************************************* * * FUNCTION: acpi_gpe_can_wake * * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 * gpe_number - GPE level within the GPE block * * RETURN: Status * * DESCRIPTION: Set the ACPI_GPE_CAN_WAKE flag for the given GPE. If the GPE * has a corresponding method and is currently enabled, disable it * (GPEs with corresponding methods are enabled unconditionally * during initialization, but GPEs that can wake up are expected * to be initially disabled). * ******************************************************************************/ acpi_status acpi_gpe_can_wake(acpi_handle gpe_device, u32 gpe_number) { acpi_status status = AE_OK; struct acpi_gpe_event_info *gpe_event_info; acpi_cpu_flags flags; ACPI_FUNCTION_TRACE(acpi_gpe_can_wake); flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); /* Ensure that we have a valid GPE number */ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); if (!gpe_event_info) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } if (gpe_event_info->flags & ACPI_GPE_CAN_WAKE) { goto unlock_and_exit; } gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; if (gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD) { (void)acpi_raw_disable_gpe(gpe_event_info); } unlock_and_exit: acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return_ACPI_STATUS(status); }
/******************************************************************************* * * FUNCTION: acpi_get_gpe_status * * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 * gpe_number - GPE level within the GPE block * event_status - Where the current status of the event will * be returned * * RETURN: Status * * DESCRIPTION: Get status of an event (general purpose) * ******************************************************************************/ acpi_status acpi_get_gpe_status(acpi_handle gpe_device, u32 gpe_number, acpi_event_status *event_status) { acpi_status status = AE_OK; struct acpi_gpe_event_info *gpe_event_info; acpi_cpu_flags flags; ACPI_FUNCTION_TRACE(acpi_get_gpe_status); flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); /* Ensure that we have a valid GPE number */ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); if (!gpe_event_info) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Obtain status on the requested GPE number */ status = acpi_hw_get_gpe_status(gpe_event_info, event_status); if (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) *event_status |= ACPI_EVENT_FLAG_HANDLE; unlock_and_exit: acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return_ACPI_STATUS(status); }
/******************************************************************************* * * FUNCTION: acpi_enable_gpe * * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 * gpe_number - GPE level within the GPE block * * RETURN: Status * * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is * hardware-enabled. * ******************************************************************************/ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number) { acpi_status status = AE_BAD_PARAMETER; struct acpi_gpe_event_info *gpe_event_info; acpi_cpu_flags flags; ACPI_FUNCTION_TRACE(acpi_enable_gpe); flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); /* * Ensure that we have a valid GPE number and that there is some way * of handling the GPE (handler or a GPE method). In other words, we * won't allow a valid GPE to be enabled if there is no way to handle it. */ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); if (gpe_event_info) { if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) != ACPI_GPE_DISPATCH_NONE) { status = acpi_ev_add_gpe_reference(gpe_event_info); } else { status = AE_NO_HANDLER; } } acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return_ACPI_STATUS(status); }
acpi_status acpi_hw_clear_acpi_status(void) { acpi_status status; acpi_cpu_flags lock_flags = 0; ACPI_FUNCTION_TRACE(hw_clear_acpi_status); ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n", ACPI_BITMASK_ALL_FIXED_STATUS, ACPI_FORMAT_UINT64(acpi_gbl_xpm1a_status.address))); lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); /* Clear the fixed events in PM1 A/B */ status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS, ACPI_BITMASK_ALL_FIXED_STATUS); acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); if (ACPI_FAILURE(status)) goto exit; /* Clear the GPE Bits in all GPE registers in all GPE blocks */ status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL); exit: return_ACPI_STATUS(status); }
/******************************************************************************* * * FUNCTION: acpi_install_sci_handler * * PARAMETERS: address - Address of the handler * context - Value passed to the handler on each SCI * * RETURN: Status * * DESCRIPTION: Install a handler for a System Control Interrupt. * ******************************************************************************/ acpi_status acpi_install_sci_handler(acpi_sci_handler address, void *context) { struct acpi_sci_handler_info *new_sci_handler; struct acpi_sci_handler_info *sci_handler; acpi_cpu_flags flags; acpi_status status; ACPI_FUNCTION_TRACE(acpi_install_sci_handler); if (!address) { return_ACPI_STATUS(AE_BAD_PARAMETER); } /* Allocate and init a handler object */ new_sci_handler = ACPI_ALLOCATE(sizeof(struct acpi_sci_handler_info)); if (!new_sci_handler) { return_ACPI_STATUS(AE_NO_MEMORY); } new_sci_handler->address = address; new_sci_handler->context = context; status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); if (ACPI_FAILURE(status)) { goto exit; } /* Lock list during installation */ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); sci_handler = acpi_gbl_sci_handler_list; /* Ensure handler does not already exist */ while (sci_handler) { if (address == sci_handler->address) { status = AE_ALREADY_EXISTS; goto unlock_and_exit; } sci_handler = sci_handler->next; } /* Install the new handler into the global list (at head) */ new_sci_handler->next = acpi_gbl_sci_handler_list; acpi_gbl_sci_handler_list = new_sci_handler; unlock_and_exit: acpi_os_release_lock(acpi_gbl_gpe_lock, flags); (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); exit: if (ACPI_FAILURE(status)) { ACPI_FREE(new_sci_handler); } return_ACPI_STATUS(status); }
static u32 acpi_ev_global_lock_handler(void *context) { acpi_status status; acpi_cpu_flags flags; flags = acpi_os_acquire_lock(acpi_ev_global_lock_pending_lock); if (!acpi_ev_global_lock_pending) { goto out; } /* Send a unit to the semaphore */ status = acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore, 1); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Could not signal Global Lock semaphore")); } acpi_ev_global_lock_pending = FALSE; out: acpi_os_release_lock(acpi_ev_global_lock_pending_lock, flags); return (ACPI_INTERRUPT_HANDLED); }
acpi_status acpi_hw_clear_acpi_status(void) { acpi_status status; acpi_cpu_flags lock_flags = 0; ACPI_FUNCTION_TRACE(hw_clear_acpi_status); ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n", ACPI_BITMASK_ALL_FIXED_STATUS, ACPI_FORMAT_UINT64(acpi_gbl_xpm1a_status.address))); lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS, ACPI_BITMASK_ALL_FIXED_STATUS); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL); unlock_and_exit: acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); return_ACPI_STATUS(status); }
acpi_status acpi_set_gpe_wake_mask(acpi_handle gpe_device, u32 gpe_number, u8 action) { acpi_status status = AE_OK; struct acpi_gpe_event_info *gpe_event_info; struct acpi_gpe_register_info *gpe_register_info; acpi_cpu_flags flags; u32 register_bit; ACPI_FUNCTION_TRACE(acpi_set_gpe_wake_mask); flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); /* * Ensure that we have a valid GPE number and that this GPE is in * fact a wake GPE */ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); if (!gpe_event_info) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } if (!(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) { status = AE_TYPE; goto unlock_and_exit; } gpe_register_info = gpe_event_info->register_info; if (!gpe_register_info) { status = AE_NOT_EXIST; goto unlock_and_exit; } register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info, gpe_register_info); /* Perform the action */ switch (action) { case ACPI_GPE_ENABLE: ACPI_SET_BIT(gpe_register_info->enable_for_wake, (u8)register_bit); break; case ACPI_GPE_DISABLE: ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake, (u8)register_bit); break; default: ACPI_ERROR((AE_INFO, "%u, Invalid action", action)); status = AE_BAD_PARAMETER; break; } unlock_and_exit: acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return_ACPI_STATUS(status); }
acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block) { acpi_status status; acpi_cpu_flags flags; ACPI_FUNCTION_TRACE(ev_install_gpe_block); status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Disable all GPEs in this block */ status = acpi_hw_disable_gpe_block(gpe_block->xrupt_block, gpe_block, NULL); if (!gpe_block->previous && !gpe_block->next) { /* This is the last gpe_block on this interrupt */ status = acpi_ev_delete_gpe_xrupt(gpe_block->xrupt_block); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } } else { /* Remove the block on this interrupt with lock */ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); if (gpe_block->previous) { gpe_block->previous->next = gpe_block->next; } else { gpe_block->xrupt_block->gpe_block_list_head = gpe_block->next; } if (gpe_block->next) { gpe_block->next->previous = gpe_block->previous; } acpi_os_release_lock(acpi_gbl_gpe_lock, flags); } acpi_current_gpe_count -= gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH; /* Free the gpe_block */ ACPI_FREE(gpe_block->register_info); ACPI_FREE(gpe_block->event_info); ACPI_FREE(gpe_block); unlock_and_exit: status = acpi_ut_release_mutex(ACPI_MTX_EVENTS); return_ACPI_STATUS(status); }
/******************************************************************************* * * FUNCTION: acpi_setup_gpe_for_wake * * PARAMETERS: wake_device - Device associated with the GPE (via _PRW) * gpe_device - Parent GPE Device. NULL for GPE0/GPE1 * gpe_number - GPE level within the GPE block * * RETURN: Status * * DESCRIPTION: Mark a GPE as having the ability to wake the system. This * interface is intended to be used as the host executes the * _PRW methods (Power Resources for Wake) in the system tables. * Each _PRW appears under a Device Object (The wake_device), and * contains the info for the wake GPE associated with the * wake_device. * ******************************************************************************/ acpi_status acpi_setup_gpe_for_wake(acpi_handle wake_device, acpi_handle gpe_device, u32 gpe_number) { acpi_status status = AE_BAD_PARAMETER; struct acpi_gpe_event_info *gpe_event_info; struct acpi_namespace_node *device_node; acpi_cpu_flags flags; ACPI_FUNCTION_TRACE(acpi_setup_gpe_for_wake); /* Parameter Validation */ if (!wake_device) { /* * By forcing wake_device to be valid, we automatically enable the * implicit notify feature on all hosts. */ return_ACPI_STATUS(AE_BAD_PARAMETER); } /* Validate wake_device is of type Device */ device_node = ACPI_CAST_PTR(struct acpi_namespace_node, wake_device); if (device_node->type != ACPI_TYPE_DEVICE) { return_ACPI_STATUS(AE_BAD_PARAMETER); } flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); /* Ensure that we have a valid GPE number */ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); if (gpe_event_info) { /* * If there is no method or handler for this GPE, then the * wake_device will be notified whenever this GPE fires (aka * "implicit notify") Note: The GPE is assumed to be * level-triggered (for windows compatibility). */ if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_NONE) { gpe_event_info->flags = (ACPI_GPE_DISPATCH_NOTIFY | ACPI_GPE_LEVEL_TRIGGERED); gpe_event_info->dispatch.device_node = device_node; } gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; status = AE_OK; } acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return_ACPI_STATUS(status); }
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context) { struct acpi_gpe_event_info *gpe_event_info = context; acpi_cpu_flags flags; flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); (void)acpi_ev_finish_gpe(gpe_event_info); acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return; }
/******************************************************************************* * * FUNCTION: acpi_remove_sci_handler * * PARAMETERS: address - Address of the handler * * RETURN: Status * * DESCRIPTION: Remove a handler for a System Control Interrupt. * ******************************************************************************/ acpi_status acpi_remove_sci_handler(acpi_sci_handler address) { struct acpi_sci_handler_info *prev_sci_handler; struct acpi_sci_handler_info *next_sci_handler; acpi_cpu_flags flags; acpi_status status; ACPI_FUNCTION_TRACE(acpi_remove_sci_handler); if (!address) { return_ACPI_STATUS(AE_BAD_PARAMETER); } status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Remove the SCI handler with lock */ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); prev_sci_handler = NULL; next_sci_handler = acpi_gbl_sci_handler_list; while (next_sci_handler) { if (next_sci_handler->address == address) { /* Unlink and free the SCI handler info block */ if (prev_sci_handler) { prev_sci_handler->next = next_sci_handler->next; } else { acpi_gbl_sci_handler_list = next_sci_handler->next; } acpi_os_release_lock(acpi_gbl_gpe_lock, flags); ACPI_FREE(next_sci_handler); goto unlock_and_exit; } prev_sci_handler = next_sci_handler; next_sci_handler = next_sci_handler->next; } acpi_os_release_lock(acpi_gbl_gpe_lock, flags); status = AE_NOT_EXIST; unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); return_ACPI_STATUS(status); }
static acpi_status acpi_ev_install_gpe_block ( struct acpi_gpe_block_info *gpe_block, u32 interrupt_level) { struct acpi_gpe_block_info *next_gpe_block; struct acpi_gpe_xrupt_info *gpe_xrupt_block; acpi_status status; ACPI_FUNCTION_TRACE ("ev_install_gpe_block"); status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } gpe_xrupt_block = acpi_ev_get_gpe_xrupt_block (interrupt_level); if (!gpe_xrupt_block) { status = AE_NO_MEMORY; goto unlock_and_exit; } /* Install the new block at the end of the list for this interrupt with lock */ acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); if (gpe_xrupt_block->gpe_block_list_head) { next_gpe_block = gpe_xrupt_block->gpe_block_list_head; while (next_gpe_block->next) { next_gpe_block = next_gpe_block->next; } next_gpe_block->next = gpe_block; gpe_block->previous = next_gpe_block; } else { gpe_xrupt_block->gpe_block_list_head = gpe_block; } gpe_block->xrupt_block = gpe_xrupt_block; acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); unlock_and_exit: status = acpi_ut_release_mutex (ACPI_MTX_EVENTS); return_ACPI_STATUS (status); }
static acpi_status acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt) { acpi_status status; acpi_cpu_flags flags; ACPI_FUNCTION_TRACE(ev_delete_gpe_xrupt); /* We never want to remove the SCI interrupt handler */ if (gpe_xrupt->interrupt_number == acpi_gbl_FADT.sci_interrupt) { gpe_xrupt->gpe_block_list_head = NULL; return_ACPI_STATUS(AE_OK); } /* Disable this interrupt */ status = acpi_os_remove_interrupt_handler(gpe_xrupt->interrupt_number, acpi_ev_gpe_xrupt_handler); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Unlink the interrupt block with lock */ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); if (gpe_xrupt->previous) { gpe_xrupt->previous->next = gpe_xrupt->next; } else { /* No previous, update list head */ acpi_gbl_gpe_xrupt_list_head = gpe_xrupt->next; } if (gpe_xrupt->next) { gpe_xrupt->next->previous = gpe_xrupt->previous; } acpi_os_release_lock(acpi_gbl_gpe_lock, flags); /* Free the block */ ACPI_FREE(gpe_xrupt); return_ACPI_STATUS(AE_OK); }
acpi_status acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback, void *context) { struct acpi_gpe_block_info *gpe_block; struct acpi_gpe_xrupt_info *gpe_xrupt_info; acpi_status status = AE_OK; acpi_cpu_flags flags; ACPI_FUNCTION_TRACE(ev_walk_gpe_list); flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head; while (gpe_xrupt_info) { gpe_block = gpe_xrupt_info->gpe_block_list_head; while (gpe_block) { status = gpe_walk_callback(gpe_xrupt_info, gpe_block, context); if (ACPI_FAILURE(status)) { if (status == AE_CTRL_END) { status = AE_OK; } goto unlock_and_exit; } gpe_block = gpe_block->next; } gpe_xrupt_info = gpe_xrupt_info->next; } unlock_and_exit: acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return_ACPI_STATUS(status); }
/******************************************************************************* * * FUNCTION: acpi_ev_walk_gpe_list * * PARAMETERS: gpe_walk_callback - Routine called for each GPE block * context - Value passed to callback * * RETURN: Status * * DESCRIPTION: Walk the GPE lists. * ******************************************************************************/ acpi_status acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback, void *context) { struct acpi_gpe_block_info *gpe_block; struct acpi_gpe_xrupt_info *gpe_xrupt_info; acpi_status status = AE_OK; acpi_cpu_flags flags; ACPI_FUNCTION_TRACE(ev_walk_gpe_list); flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); /* Walk the interrupt level descriptor list */ gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head; while (gpe_xrupt_info) { /* Walk all Gpe Blocks attached to this interrupt level */ gpe_block = gpe_xrupt_info->gpe_block_list_head; while (gpe_block) { /* One callback per GPE block */ status = gpe_walk_callback(gpe_xrupt_info, gpe_block, context); if (ACPI_FAILURE(status)) { if (status == AE_CTRL_END) { /* Callback abort */ status = AE_OK; } goto unlock_and_exit; } gpe_block = gpe_block->next; } gpe_xrupt_info = gpe_xrupt_info->next; } unlock_and_exit: acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return_ACPI_STATUS(status); }
acpi_status acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt) { acpi_status status; acpi_cpu_flags flags; ACPI_FUNCTION_TRACE(ev_delete_gpe_xrupt); if (gpe_xrupt->interrupt_number == acpi_gbl_FADT.sci_interrupt) { gpe_xrupt->gpe_block_list_head = NULL; return_ACPI_STATUS(AE_OK); } status = acpi_os_remove_interrupt_handler(gpe_xrupt->interrupt_number, acpi_ev_gpe_xrupt_handler); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); if (gpe_xrupt->previous) { gpe_xrupt->previous->next = gpe_xrupt->next; } else { acpi_gbl_gpe_xrupt_list_head = gpe_xrupt->next; } if (gpe_xrupt->next) { gpe_xrupt->next->previous = gpe_xrupt->previous; } acpi_os_release_lock(acpi_gbl_gpe_lock, flags); ACPI_FREE(gpe_xrupt); return_ACPI_STATUS(AE_OK); }
/******************************************************************************* * * FUNCTION: acpi_set_gpe * * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 * gpe_number - GPE level within the GPE block * action - ACPI_GPE_ENABLE or ACPI_GPE_DISABLE * * RETURN: Status * * DESCRIPTION: Enable or disable an individual GPE. This function bypasses * the reference count mechanism used in the acpi_enable_gpe(), * acpi_disable_gpe() interfaces. * This API is typically used by the GPE raw handler mode driver * to switch between the polling mode and the interrupt mode after * the driver has enabled the GPE. * The APIs should be invoked in this order: * acpi_enable_gpe() <- Ensure the reference count > 0 * acpi_set_gpe(ACPI_GPE_DISABLE) <- Enter polling mode * acpi_set_gpe(ACPI_GPE_ENABLE) <- Leave polling mode * acpi_disable_gpe() <- Decrease the reference count * * Note: If a GPE is shared by 2 silicon components, then both the drivers * should support GPE polling mode or disabling the GPE for long period * for one driver may break the other. So use it with care since all * firmware _Lxx/_Exx handlers currently rely on the GPE interrupt mode. * ******************************************************************************/ acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action) { struct acpi_gpe_event_info *gpe_event_info; acpi_status status; acpi_cpu_flags flags; ACPI_FUNCTION_TRACE(acpi_set_gpe); flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); /* Ensure that we have a valid GPE number */ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); if (!gpe_event_info) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Perform the action */ switch (action) { case ACPI_GPE_ENABLE: status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE); gpe_event_info->disable_for_dispatch = FALSE; break; case ACPI_GPE_DISABLE: status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); gpe_event_info->disable_for_dispatch = TRUE; break; default: status = AE_BAD_PARAMETER; break; } unlock_and_exit: acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return_ACPI_STATUS(status); }
static acpi_status acpi_ev_delete_gpe_xrupt ( struct acpi_gpe_xrupt_info *gpe_xrupt) { acpi_status status; ACPI_FUNCTION_TRACE ("ev_delete_gpe_xrupt"); /* We never want to remove the SCI interrupt handler */ if (gpe_xrupt->interrupt_level == acpi_gbl_FADT->sci_int) { gpe_xrupt->gpe_block_list_head = NULL; return_ACPI_STATUS (AE_OK); } /* Disable this interrupt */ status = acpi_os_remove_interrupt_handler (gpe_xrupt->interrupt_level, acpi_ev_gpe_xrupt_handler); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* Unlink the interrupt block with lock */ acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); if (gpe_xrupt->previous) { gpe_xrupt->previous->next = gpe_xrupt->next; } if (gpe_xrupt->next) { gpe_xrupt->next->previous = gpe_xrupt->previous; } acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); /* Free the block */ ACPI_MEM_FREE (gpe_xrupt); return_ACPI_STATUS (AE_OK); }
/******************************************************************************* * * FUNCTION: acpi_disable_gpe * * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 * gpe_number - GPE level within the GPE block * * RETURN: Status * * DESCRIPTION: Remove a reference to a GPE. When the last reference is * removed, only then is the GPE disabled (for runtime GPEs), or * the GPE mask bit disabled (for wake GPEs) * ******************************************************************************/ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number) { acpi_status status = AE_BAD_PARAMETER; struct acpi_gpe_event_info *gpe_event_info; acpi_cpu_flags flags; ACPI_FUNCTION_TRACE(acpi_disable_gpe); flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); /* Ensure that we have a valid GPE number */ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); if (gpe_event_info) { status = acpi_raw_disable_gpe(gpe_event_info) ; } acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return_ACPI_STATUS(status); }
acpi_status acpi_ev_walk_gpe_list ( ACPI_GPE_CALLBACK gpe_walk_callback) { struct acpi_gpe_block_info *gpe_block; struct acpi_gpe_xrupt_info *gpe_xrupt_info; acpi_status status = AE_OK; ACPI_FUNCTION_TRACE ("ev_walk_gpe_list"); acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_ISR); /* Walk the interrupt level descriptor list */ gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head; while (gpe_xrupt_info) { /* Walk all Gpe Blocks attached to this interrupt level */ gpe_block = gpe_xrupt_info->gpe_block_list_head; while (gpe_block) { /* One callback per GPE block */ status = gpe_walk_callback (gpe_xrupt_info, gpe_block); if (ACPI_FAILURE (status)) { goto unlock_and_exit; } gpe_block = gpe_block->next; } gpe_xrupt_info = gpe_xrupt_info->next; } unlock_and_exit: acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_ISR); return_ACPI_STATUS (status); }
/******************************************************************************* * * FUNCTION: acpi_gpe_can_wake * * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 * gpe_number - GPE level within the GPE block * * RETURN: Status * * DESCRIPTION: Set the ACPI_GPE_CAN_WAKE flag for the given GPE. If the GPE * has a corresponding method and is currently enabled, disable it * (GPEs with corresponding methods are enabled unconditionally * during initialization, but GPEs that can wake up are expected * to be initially disabled). * ******************************************************************************/ acpi_status acpi_gpe_can_wake(acpi_handle gpe_device, u32 gpe_number) { acpi_status status = AE_OK; struct acpi_gpe_event_info *gpe_event_info; acpi_cpu_flags flags; ACPI_FUNCTION_TRACE(acpi_gpe_can_wake); flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); /* Ensure that we have a valid GPE number */ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); if (gpe_event_info) { gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; } else { status = AE_BAD_PARAMETER; } acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return_ACPI_STATUS(status); }
/******************************************************************************* * * FUNCTION: acpi_mask_gpe * * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 * gpe_number - GPE level within the GPE block * is_masked - Whether the GPE is masked or not * * RETURN: Status * * DESCRIPTION: Unconditionally mask/unmask the an individual GPE, ex., to * prevent a GPE flooding. * ******************************************************************************/ acpi_status acpi_mask_gpe(acpi_handle gpe_device, u32 gpe_number, u8 is_masked) { struct acpi_gpe_event_info *gpe_event_info; acpi_status status; acpi_cpu_flags flags; ACPI_FUNCTION_TRACE(acpi_mask_gpe); flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); /* Ensure that we have a valid GPE number */ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); if (!gpe_event_info) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } status = acpi_ev_mask_gpe(gpe_event_info, is_masked); unlock_and_exit: acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return_ACPI_STATUS(status); }
u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list) { acpi_status status; struct acpi_gpe_block_info *gpe_block; struct acpi_namespace_node *gpe_device; struct acpi_gpe_register_info *gpe_register_info; struct acpi_gpe_event_info *gpe_event_info; u32 gpe_number; struct acpi_gpe_handler_info *gpe_handler_info; u32 int_status = ACPI_INTERRUPT_NOT_HANDLED; u8 enabled_status_byte; u32 status_reg; u32 enable_reg; acpi_cpu_flags flags; u32 i; u32 j; ACPI_FUNCTION_NAME(ev_gpe_detect); /* Check for the case where there are no GPEs */ if (!gpe_xrupt_list) { return (int_status); } /* * We need to obtain the GPE lock for both the data structs and registers * Note: Not necessary to obtain the hardware lock, since the GPE * registers are owned by the gpe_lock. */ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); /* Examine all GPE blocks attached to this interrupt level */ gpe_block = gpe_xrupt_list->gpe_block_list_head; while (gpe_block) { gpe_device = gpe_block->node; /* * Read all of the 8-bit GPE status and enable registers in this GPE * block, saving all of them. Find all currently active GP events. */ for (i = 0; i < gpe_block->register_count; i++) { /* Get the next status/enable pair */ gpe_register_info = &gpe_block->register_info[i]; /* * Optimization: If there are no GPEs enabled within this * register, we can safely ignore the entire register. */ if (!(gpe_register_info->enable_for_run | gpe_register_info->enable_for_wake)) { ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS, "Ignore disabled registers for GPE %02X-%02X: " "RunEnable=%02X, WakeEnable=%02X\n", gpe_register_info-> base_gpe_number, gpe_register_info-> base_gpe_number + (ACPI_GPE_REGISTER_WIDTH - 1), gpe_register_info-> enable_for_run, gpe_register_info-> enable_for_wake)); continue; } /* Read the Status Register */ status = acpi_hw_read(&status_reg, &gpe_register_info->status_address); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } /* Read the Enable Register */ status = acpi_hw_read(&enable_reg, &gpe_register_info->enable_address); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS, "Read registers for GPE %02X-%02X: Status=%02X, Enable=%02X, " "RunEnable=%02X, WakeEnable=%02X\n", gpe_register_info->base_gpe_number, gpe_register_info->base_gpe_number + (ACPI_GPE_REGISTER_WIDTH - 1), status_reg, enable_reg, gpe_register_info->enable_for_run, gpe_register_info->enable_for_wake)); /* Check if there is anything active at all in this register */ enabled_status_byte = (u8)(status_reg & enable_reg); if (!enabled_status_byte) { /* No active GPEs in this register, move on */ continue; } /* Now look at the individual GPEs in this byte register */ for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { /* Examine one GPE bit */ gpe_event_info = &gpe_block-> event_info[((acpi_size) i * ACPI_GPE_REGISTER_WIDTH) + j]; gpe_number = j + gpe_register_info->base_gpe_number; if (enabled_status_byte & (1 << j)) { /* Invoke global event handler if present */ acpi_gpe_count++; if (acpi_gbl_global_event_handler) { acpi_gbl_global_event_handler (ACPI_EVENT_TYPE_GPE, gpe_device, gpe_number, acpi_gbl_global_event_handler_context); } /* Found an active GPE */ if (ACPI_GPE_DISPATCH_TYPE (gpe_event_info->flags) == ACPI_GPE_DISPATCH_RAW_HANDLER) { /* Dispatch the event to a raw handler */ gpe_handler_info = gpe_event_info->dispatch. handler; /* * There is no protection around the namespace node * and the GPE handler to ensure a safe destruction * because: * 1. The namespace node is expected to always * exist after loading a table. * 2. The GPE handler is expected to be flushed by * acpi_os_wait_events_complete() before the * destruction. */ acpi_os_release_lock (acpi_gbl_gpe_lock, flags); int_status |= gpe_handler_info-> address(gpe_device, gpe_number, gpe_handler_info-> context); flags = acpi_os_acquire_lock (acpi_gbl_gpe_lock); } else { /* * Dispatch the event to a standard handler or * method. */ int_status |= acpi_ev_gpe_dispatch (gpe_device, gpe_event_info, gpe_number); } } } } gpe_block = gpe_block->next; } unlock_and_exit: acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return (int_status); }
/******************************************************************************* * * FUNCTION: acpi_remove_gpe_handler * * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT * defined GPEs) * gpe_number - The event to remove a handler * Address - Address of the handler * * RETURN: Status * * DESCRIPTION: Remove a handler for a General Purpose acpi_event. * ******************************************************************************/ acpi_status acpi_remove_gpe_handler(acpi_handle gpe_device, u32 gpe_number, acpi_event_handler address) { struct acpi_gpe_event_info *gpe_event_info; struct acpi_handler_info *handler; acpi_status status; acpi_cpu_flags flags; ACPI_FUNCTION_TRACE(acpi_remove_gpe_handler); /* Parameter validation */ if (!address) { return_ACPI_STATUS(AE_BAD_PARAMETER); } status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Ensure that we have a valid GPE number */ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); if (!gpe_event_info) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Make sure that a handler is indeed installed */ if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) != ACPI_GPE_DISPATCH_HANDLER) { status = AE_NOT_EXIST; goto unlock_and_exit; } /* Make sure that the installed handler is the same */ if (gpe_event_info->dispatch.handler->address != address) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Disable the GPE before removing the handler */ status = acpi_ev_disable_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } /* Make sure all deferred tasks are completed */ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); acpi_os_wait_events_complete(NULL); status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Remove the handler */ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); handler = gpe_event_info->dispatch.handler; /* Restore Method node (if any), set dispatch flags */ gpe_event_info->dispatch.method_node = handler->method_node; gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK; /* Clear bits */ if (handler->method_node) { gpe_event_info->flags |= ACPI_GPE_DISPATCH_METHOD; } acpi_os_release_lock(acpi_gbl_gpe_lock, flags); /* Now we can free the handler object */ ACPI_FREE(handler); unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); return_ACPI_STATUS(status); }
/******************************************************************************* * * FUNCTION: acpi_install_gpe_handler * * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT * defined GPEs) * gpe_number - The GPE number within the GPE block * Type - Whether this GPE should be treated as an * edge- or level-triggered interrupt. * Address - Address of the handler * Context - Value passed to the handler on each GPE * * RETURN: Status * * DESCRIPTION: Install a handler for a General Purpose Event. * ******************************************************************************/ acpi_status acpi_install_gpe_handler(acpi_handle gpe_device, u32 gpe_number, u32 type, acpi_event_handler address, void *context) { struct acpi_gpe_event_info *gpe_event_info; struct acpi_handler_info *handler; acpi_status status; acpi_cpu_flags flags; ACPI_FUNCTION_TRACE(acpi_install_gpe_handler); /* Parameter validation */ if ((!address) || (type > ACPI_GPE_XRUPT_TYPE_MASK)) { status = AE_BAD_PARAMETER; goto exit; } status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); if (ACPI_FAILURE(status)) { goto exit; } /* Ensure that we have a valid GPE number */ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); if (!gpe_event_info) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Make sure that there isn't a handler there already */ if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_HANDLER) { status = AE_ALREADY_EXISTS; goto unlock_and_exit; } /* Allocate and init handler object */ handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_handler_info)); if (!handler) { status = AE_NO_MEMORY; goto unlock_and_exit; } handler->address = address; handler->context = context; handler->method_node = gpe_event_info->dispatch.method_node; /* Disable the GPE before installing the handler */ status = acpi_ev_disable_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } /* Install the handler */ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); gpe_event_info->dispatch.handler = handler; /* Setup up dispatch flags to indicate handler (vs. method) */ gpe_event_info->flags &= ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); gpe_event_info->flags |= (u8) (type | ACPI_GPE_DISPATCH_HANDLER); acpi_os_release_lock(acpi_gbl_gpe_lock, flags); unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); exit: if (ACPI_FAILURE(status)) ACPI_EXCEPTION((AE_INFO, status, "Installing notify handler failed")); return_ACPI_STATUS(status); }
static struct acpi_gpe_xrupt_info * acpi_ev_get_gpe_xrupt_block ( u32 interrupt_level) { struct acpi_gpe_xrupt_info *next_gpe_xrupt; struct acpi_gpe_xrupt_info *gpe_xrupt; acpi_status status; ACPI_FUNCTION_TRACE ("ev_get_gpe_xrupt_block"); /* No need for spin lock since we are not changing any list elements here */ next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head; while (next_gpe_xrupt) { if (next_gpe_xrupt->interrupt_level == interrupt_level) { return_PTR (next_gpe_xrupt); } next_gpe_xrupt = next_gpe_xrupt->next; } /* Not found, must allocate a new xrupt descriptor */ gpe_xrupt = ACPI_MEM_CALLOCATE (sizeof (struct acpi_gpe_xrupt_info)); if (!gpe_xrupt) { return_PTR (NULL); } gpe_xrupt->interrupt_level = interrupt_level; /* Install new interrupt descriptor with spin lock */ acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); if (acpi_gbl_gpe_xrupt_list_head) { next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head; while (next_gpe_xrupt->next) { next_gpe_xrupt = next_gpe_xrupt->next; } next_gpe_xrupt->next = gpe_xrupt; gpe_xrupt->previous = next_gpe_xrupt; } else { acpi_gbl_gpe_xrupt_list_head = gpe_xrupt; } acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); /* Install new interrupt handler if not SCI_INT */ if (interrupt_level != acpi_gbl_FADT->sci_int) { status = acpi_os_install_interrupt_handler (interrupt_level, acpi_ev_gpe_xrupt_handler, gpe_xrupt); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not install GPE interrupt handler at level 0x%X\n", interrupt_level)); return_PTR (NULL); } } return_PTR (gpe_xrupt); }
static struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 interrupt_number) { struct acpi_gpe_xrupt_info *next_gpe_xrupt; struct acpi_gpe_xrupt_info *gpe_xrupt; acpi_status status; acpi_cpu_flags flags; ACPI_FUNCTION_TRACE(ev_get_gpe_xrupt_block); /* No need for lock since we are not changing any list elements here */ next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head; while (next_gpe_xrupt) { if (next_gpe_xrupt->interrupt_number == interrupt_number) { return_PTR(next_gpe_xrupt); } next_gpe_xrupt = next_gpe_xrupt->next; } /* Not found, must allocate a new xrupt descriptor */ gpe_xrupt = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_xrupt_info)); if (!gpe_xrupt) { return_PTR(NULL); } gpe_xrupt->interrupt_number = interrupt_number; /* Install new interrupt descriptor with spin lock */ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); if (acpi_gbl_gpe_xrupt_list_head) { next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head; while (next_gpe_xrupt->next) { next_gpe_xrupt = next_gpe_xrupt->next; } next_gpe_xrupt->next = gpe_xrupt; gpe_xrupt->previous = next_gpe_xrupt; } else { acpi_gbl_gpe_xrupt_list_head = gpe_xrupt; } acpi_os_release_lock(acpi_gbl_gpe_lock, flags); /* Install new interrupt handler if not SCI_INT */ if (interrupt_number != acpi_gbl_FADT.sci_interrupt) { status = acpi_os_install_interrupt_handler(interrupt_number, acpi_ev_gpe_xrupt_handler, gpe_xrupt); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Could not install GPE interrupt handler at level 0x%X", interrupt_number)); return_PTR(NULL); } } return_PTR(gpe_xrupt); }