Esempio n. 1
0
static u32 acpi_ev_global_lock_handler(void *context)
{
	u8 acquired = FALSE;
	acpi_status status;

	/*
	 * Attempt to get the lock
	 * If we don't get it now, it will be marked pending and we will
	 * take another interrupt when it becomes free.
	 */
	ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired);
	if (acquired) {

		/* Got the lock, now wake all threads waiting for it */

		acpi_gbl_global_lock_acquired = TRUE;

		/* Run the Global Lock thread which will signal all waiting threads */

		status =
		    acpi_os_execute(OSL_GLOBAL_LOCK_HANDLER,
				    acpi_ev_global_lock_thread, context);
		if (ACPI_FAILURE(status)) {
			ACPI_EXCEPTION((AE_INFO, status,
					"Could not queue Global Lock thread"));

			return (ACPI_INTERRUPT_NOT_HANDLED);
		}
	}

	return (ACPI_INTERRUPT_HANDLED);
}
Esempio n. 2
0
static void
acpi_thermal_run (
	void*		data)
{
	struct acpi_thermal *tz = (struct acpi_thermal *)data;
	if (!tz->zombie)
		acpi_os_execute(OSL_GPE_HANDLER,  
			acpi_thermal_check, (void *) data);
}
Esempio n. 3
0
u32
acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
		     struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
{
	acpi_status status;
	u32 return_value;

	ACPI_FUNCTION_TRACE(ev_gpe_dispatch);

	/*
	 * Always disable the GPE so that it does not keep firing before
	 * any asynchronous activity completes (either from the execution
	 * of a GPE method or an asynchronous GPE handler.)
	 *
	 * If there is no handler or method to run, just disable the
	 * GPE and leave it disabled permanently to prevent further such
	 * pointless events from firing.
	 */
	status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
	if (ACPI_FAILURE(status)) {
		ACPI_EXCEPTION((AE_INFO, status,
				"Unable to disable GPE %02X", gpe_number));
		return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
	}

	/*
	 * If edge-triggered, clear the GPE status bit now. Note that
	 * level-triggered events are cleared after the GPE is serviced.
	 */
	if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
	    ACPI_GPE_EDGE_TRIGGERED) {
		status = acpi_hw_clear_gpe(gpe_event_info);
		if (ACPI_FAILURE(status)) {
			ACPI_EXCEPTION((AE_INFO, status,
					"Unable to clear GPE %02X",
					gpe_number));
			(void)acpi_hw_low_set_gpe(gpe_event_info,
						  ACPI_GPE_CONDITIONAL_ENABLE);
			return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
		}
	}

	/*
	 * Dispatch the GPE to either an installed handler or the control
	 * method associated with this GPE (_Lxx or _Exx). If a handler
	 * exists, we invoke it and do not attempt to run the method.
	 * If there is neither a handler nor a method, leave the GPE
	 * disabled.
	 */
	switch (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags)) {
	case ACPI_GPE_DISPATCH_HANDLER:

		/* Invoke the installed handler (at interrupt level) */

		return_value =
		    gpe_event_info->dispatch.handler->address(gpe_device,
							      gpe_number,
							      gpe_event_info->
							      dispatch.handler->
							      context);

		/* If requested, clear (if level-triggered) and reenable the GPE */

		if (return_value & ACPI_REENABLE_GPE) {
			(void)acpi_ev_finish_gpe(gpe_event_info);
		}
		break;

	case ACPI_GPE_DISPATCH_METHOD:
	case ACPI_GPE_DISPATCH_NOTIFY:
		/*
		 * Execute the method associated with the GPE
		 * NOTE: Level-triggered GPEs are cleared after the method completes.
		 */
		status = acpi_os_execute(OSL_GPE_HANDLER,
					 acpi_ev_asynch_execute_gpe_method,
					 gpe_event_info);
		if (ACPI_FAILURE(status)) {
			ACPI_EXCEPTION((AE_INFO, status,
					"Unable to queue handler for GPE %02X - event disabled",
					gpe_number));
		}
		break;

	default:
		/*
		 * No handler or method to run!
		 * 03/2010: This case should no longer be possible. We will not allow
		 * a GPE to be enabled if it has no handler or method.
		 */
		ACPI_ERROR((AE_INFO,
			    "No handler or method for GPE %02X, disabling event",
			    gpe_number));

		break;
	}

	return_UINT32(ACPI_INTERRUPT_HANDLED);
}
Esempio n. 4
0
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
{
	struct acpi_gpe_event_info *gpe_event_info = context;
	acpi_status status = AE_OK;
	struct acpi_evaluate_info *info;
	struct acpi_gpe_notify_info *notify;

	ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method);

	/* Do the correct dispatch - normal method or implicit notify */

	switch (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags)) {
	case ACPI_GPE_DISPATCH_NOTIFY:
		/*
		 * Implicit notify.
		 * Dispatch a DEVICE_WAKE notify to the appropriate handler.
		 * NOTE: the request is queued for execution after this method
		 * completes. The notify handlers are NOT invoked synchronously
		 * from this thread -- because handlers may in turn run other
		 * control methods.
		 *
		 * June 2012: Expand implicit notify mechanism to support
		 * notifies on multiple device objects.
		 */
		notify = gpe_event_info->dispatch.notify_list;
		while (ACPI_SUCCESS(status) && notify) {
			status =
			    acpi_ev_queue_notify_request(notify->device_node,
							 ACPI_NOTIFY_DEVICE_WAKE);

			notify = notify->next;
		}

		break;

	case ACPI_GPE_DISPATCH_METHOD:

		/* Allocate the evaluation information block */

		info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
		if (!info) {
			status = AE_NO_MEMORY;
		} else {
			/*
			 * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the
			 * _Lxx/_Exx control method that corresponds to this GPE
			 */
			info->prefix_node =
			    gpe_event_info->dispatch.method_node;
			info->flags = ACPI_IGNORE_RETURN_VALUE;

			status = acpi_ns_evaluate(info);
			ACPI_FREE(info);
		}

		if (ACPI_FAILURE(status)) {
			ACPI_EXCEPTION((AE_INFO, status,
					"while evaluating GPE method [%4.4s]",
					acpi_ut_get_node_name(gpe_event_info->
							      dispatch.
							      method_node)));
		}
		break;

	default:

		goto error_exit;	/* Should never happen */
	}

	/* Defer enabling of GPE until all notify handlers are done */

	status = acpi_os_execute(OSL_NOTIFY_HANDLER,
				 acpi_ev_asynch_enable_gpe, gpe_event_info);
	if (ACPI_SUCCESS(status)) {
		return_VOID;
	}

error_exit:
	acpi_ev_asynch_enable_gpe(gpe_event_info);
	return_VOID;
}
Esempio n. 5
0
static void acpi_bus_osc_support(void)
{
	u32 capbuf[2];
	struct acpi_osc_context context = {
		.uuid_str = sb_uuid_str,
		.rev = 1,
		.cap.length = 8,
		.cap.pointer = capbuf,
	};
	acpi_handle handle;

	capbuf[OSC_QUERY_DWORD] = OSC_QUERY_ENABLE;
	capbuf[OSC_SUPPORT_DWORD] = OSC_SB_PR3_SUPPORT; /* _PR3 is in use */
	if (IS_ENABLED(CONFIG_ACPI_PROCESSOR_AGGREGATOR))
		capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PAD_SUPPORT;
	if (IS_ENABLED(CONFIG_ACPI_PROCESSOR))
		capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PPC_OST_SUPPORT;

	capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_HOTPLUG_OST_SUPPORT;

	if (!ghes_disable)
		capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_APEI_SUPPORT;
	if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle)))
		return;
	if (ACPI_SUCCESS(acpi_run_osc(handle, &context))) {
		u32 *capbuf_ret = context.ret.pointer;
		if (context.ret.length > OSC_SUPPORT_DWORD)
			osc_sb_apei_support_acked =
				capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_APEI_SUPPORT;
		kfree(context.ret.pointer);
	}
	/* do we need to check other returned cap? Sounds no */
}

/* --------------------------------------------------------------------------
                             Notification Handling
   -------------------------------------------------------------------------- */

/**
 * acpi_bus_notify
 * ---------------
 * Callback for all 'system-level' device notifications (values 0x00-0x7F).
 */
static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
{
	struct acpi_device *adev;
	struct acpi_driver *driver;
	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
	bool hotplug_event = false;

	switch (type) {
	case ACPI_NOTIFY_BUS_CHECK:
		acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
		hotplug_event = true;
		break;

	case ACPI_NOTIFY_DEVICE_CHECK:
		acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
		hotplug_event = true;
		break;

	case ACPI_NOTIFY_DEVICE_WAKE:
		acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_WAKE event\n");
		break;

	case ACPI_NOTIFY_EJECT_REQUEST:
		acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
		hotplug_event = true;
		break;

	case ACPI_NOTIFY_DEVICE_CHECK_LIGHT:
		acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK_LIGHT event\n");
		/* TBD: Exactly what does 'light' mean? */
		break;

	case ACPI_NOTIFY_FREQUENCY_MISMATCH:
		acpi_handle_err(handle, "Device cannot be configured due "
				"to a frequency mismatch\n");
		break;

	case ACPI_NOTIFY_BUS_MODE_MISMATCH:
		acpi_handle_err(handle, "Device cannot be configured due "
				"to a bus mode mismatch\n");
		break;

	case ACPI_NOTIFY_POWER_FAULT:
		acpi_handle_err(handle, "Device has suffered a power fault\n");
		break;

	default:
		acpi_handle_debug(handle, "Unknown event type 0x%x\n", type);
		break;
	}

	adev = acpi_bus_get_acpi_device(handle);
	if (!adev)
		goto err;

	driver = adev->driver;
	if (driver && driver->ops.notify &&
	    (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
		driver->ops.notify(adev, type);

	if (hotplug_event && ACPI_SUCCESS(acpi_hotplug_schedule(adev, type)))
		return;

	acpi_bus_put_acpi_device(adev);
	return;

 err:
	acpi_evaluate_ost(handle, type, ost_code, NULL);
}

static void acpi_device_notify(acpi_handle handle, u32 event, void *data)
{
	struct acpi_device *device = data;

	device->driver->ops.notify(device, event);
}

static void acpi_device_notify_fixed(void *data)
{
	struct acpi_device *device = data;

	/* Fixed hardware devices have no handles */
	acpi_device_notify(NULL, ACPI_FIXED_HARDWARE_EVENT, device);
}

static u32 acpi_device_fixed_event(void *data)
{
	acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_device_notify_fixed, data);
	return ACPI_INTERRUPT_HANDLED;
}
Esempio n. 6
0
u32
acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
{
    acpi_status status;

    ACPI_FUNCTION_TRACE(ev_gpe_dispatch);

    acpi_os_gpe_count(gpe_number);

    /*
     * If edge-triggered, clear the GPE status bit now. Note that
     * level-triggered events are cleared after the GPE is serviced.
     */
    if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
            ACPI_GPE_EDGE_TRIGGERED) {
        status = acpi_hw_clear_gpe(gpe_event_info);
        if (ACPI_FAILURE(status)) {
            ACPI_EXCEPTION((AE_INFO, status,
                            "Unable to clear GPE[%2X]",
                            gpe_number));
            return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
        }
    }

    /*
     * Dispatch the GPE to either an installed handler, or the control method
     * associated with this GPE (_Lxx or _Exx). If a handler exists, we invoke
     * it and do not attempt to run the method. If there is neither a handler
     * nor a method, we disable this GPE to prevent further such pointless
     * events from firing.
     */
    switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
    case ACPI_GPE_DISPATCH_HANDLER:

        /*
         * Invoke the installed handler (at interrupt level)
         * Ignore return status for now.
         * TBD: leave GPE disabled on error?
         */
        (void)gpe_event_info->dispatch.handler->address(gpe_event_info->
                dispatch.
                handler->
                context);

        /* It is now safe to clear level-triggered events. */

        if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
                ACPI_GPE_LEVEL_TRIGGERED) {
            status = acpi_hw_clear_gpe(gpe_event_info);
            if (ACPI_FAILURE(status)) {
                ACPI_EXCEPTION((AE_INFO, status,
                                "Unable to clear GPE[%2X]",
                                gpe_number));
                return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
            }
        }
        break;

    case ACPI_GPE_DISPATCH_METHOD:

        /*
         * Disable the GPE, so it doesn't keep firing before the method has a
         * chance to run (it runs asynchronously with interrupts enabled).
         */
        status = acpi_ev_disable_gpe(gpe_event_info);
        if (ACPI_FAILURE(status)) {
            ACPI_EXCEPTION((AE_INFO, status,
                            "Unable to disable GPE[%2X]",
                            gpe_number));
            return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
        }

        /*
         * Execute the method associated with the GPE
         * NOTE: Level-triggered GPEs are cleared after the method completes.
         */
        status = acpi_os_execute(OSL_GPE_HANDLER,
                                 acpi_ev_asynch_execute_gpe_method,
                                 gpe_event_info);
        if (ACPI_FAILURE(status)) {
            ACPI_EXCEPTION((AE_INFO, status,
                            "Unable to queue handler for GPE[%2X] - event disabled",
                            gpe_number));
        }
        break;

    default:

        /* No handler or method to run! */

        ACPI_ERROR((AE_INFO,
                    "No handler or method for GPE[%2X], disabling event",
                    gpe_number));

        /*
         * Disable the GPE. The GPE will remain disabled until the ACPICA
         * Core Subsystem is restarted, or a handler is installed.
         */
        status = acpi_ev_disable_gpe(gpe_event_info);
        if (ACPI_FAILURE(status)) {
            ACPI_EXCEPTION((AE_INFO, status,
                            "Unable to disable GPE[%2X]",
                            gpe_number));
            return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
        }
        break;
    }

    return_UINT32(ACPI_INTERRUPT_HANDLED);
}
Esempio n. 7
0
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
{
    struct acpi_gpe_event_info *gpe_event_info = (void *)context;
    acpi_status status;
    struct acpi_gpe_event_info local_gpe_event_info;
    struct acpi_evaluate_info *info;

    ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method);

    status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
    if (ACPI_FAILURE(status)) {
        return_VOID;
    }

    /* Must revalidate the gpe_number/gpe_block */

    if (!acpi_ev_valid_gpe_event(gpe_event_info)) {
        status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
        return_VOID;
    }

    /* Set the GPE flags for return to enabled state */

    (void)acpi_ev_enable_gpe(gpe_event_info, FALSE);

    /*
     * Take a snapshot of the GPE info for this level - we copy the info to
     * prevent a race condition with remove_handler/remove_block.
     */
    ACPI_MEMCPY(&local_gpe_event_info, gpe_event_info,
                sizeof(struct acpi_gpe_event_info));

    status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
    if (ACPI_FAILURE(status)) {
        return_VOID;
    }

    /*
     * Must check for control method type dispatch one more time to avoid a
     * race with ev_gpe_install_handler
     */
    if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) ==
            ACPI_GPE_DISPATCH_METHOD) {

        /* Allocate the evaluation information block */

        info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
        if (!info) {
            status = AE_NO_MEMORY;
        } else {
            /*
             * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the _Lxx/_Exx
             * control method that corresponds to this GPE
             */
            info->prefix_node =
                local_gpe_event_info.dispatch.method_node;
            info->flags = ACPI_IGNORE_RETURN_VALUE;

            status = acpi_ns_evaluate(info);
            ACPI_FREE(info);
        }

        if (ACPI_FAILURE(status)) {
            ACPI_EXCEPTION((AE_INFO, status,
                            "while evaluating GPE method [%4.4s]",
                            acpi_ut_get_node_name
                            (local_gpe_event_info.dispatch.
                             method_node)));
        }
    }
    /* Defer enabling of GPE until all notify handlers are done */
    acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_asynch_enable_gpe,
                    gpe_event_info);
    return_VOID;
}
Esempio n. 8
0
acpi_status acpi_initialize_debugger(void)
{
	acpi_status status;

	ACPI_FUNCTION_TRACE(acpi_initialize_debugger);

	/* Init globals */

	acpi_gbl_db_buffer = NULL;
	acpi_gbl_db_filename = NULL;
	acpi_gbl_db_output_to_file = FALSE;

	acpi_gbl_db_debug_level = ACPI_LV_VERBOSITY2;
	acpi_gbl_db_console_debug_level = ACPI_NORMAL_DEFAULT | ACPI_LV_TABLES;
	acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT;

	acpi_gbl_db_opt_no_ini_methods = FALSE;

	acpi_gbl_db_buffer = acpi_os_allocate(ACPI_DEBUG_BUFFER_SIZE);
	if (!acpi_gbl_db_buffer) {
		return_ACPI_STATUS(AE_NO_MEMORY);
	}
	memset(acpi_gbl_db_buffer, 0, ACPI_DEBUG_BUFFER_SIZE);

	/* Initial scope is the root */

	acpi_gbl_db_scope_buf[0] = AML_ROOT_PREFIX;
	acpi_gbl_db_scope_buf[1] = 0;
	acpi_gbl_db_scope_node = acpi_gbl_root_node;

	/* Initialize user commands loop */

	acpi_gbl_db_terminate_loop = FALSE;

	/*
	 * If configured for multi-thread support, the debug executor runs in
	 * a separate thread so that the front end can be in another address
	 * space, environment, or even another machine.
	 */
	if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {

		/* These were created with one unit, grab it */

		status = acpi_os_acquire_mutex(acpi_gbl_db_command_complete,
					       ACPI_WAIT_FOREVER);
		if (ACPI_FAILURE(status)) {
			acpi_os_printf("Could not get debugger mutex\n");
			return_ACPI_STATUS(status);
		}

		status = acpi_os_acquire_mutex(acpi_gbl_db_command_ready,
					       ACPI_WAIT_FOREVER);
		if (ACPI_FAILURE(status)) {
			acpi_os_printf("Could not get debugger mutex\n");
			return_ACPI_STATUS(status);
		}

		/* Create the debug execution thread to execute commands */

		acpi_gbl_db_threads_terminated = FALSE;
		status = acpi_os_execute(OSL_DEBUGGER_MAIN_THREAD,
					 acpi_db_execute_thread, NULL);
		if (ACPI_FAILURE(status)) {
			ACPI_EXCEPTION((AE_INFO, status,
					"Could not start debugger thread"));
			acpi_gbl_db_threads_terminated = TRUE;
			return_ACPI_STATUS(status);
		}
	} else {
		acpi_gbl_db_thread_id = acpi_os_get_thread_id();
	}

	return_ACPI_STATUS(AE_OK);
}
Esempio n. 9
0
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
{
	struct acpi_gpe_event_info *gpe_event_info = context;
	acpi_status status;
	struct acpi_gpe_event_info *local_gpe_event_info;
	struct acpi_evaluate_info *info;
	struct acpi_gpe_notify_info *notify;

	ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method);

	/* Allocate a local GPE block */

	local_gpe_event_info =
	    ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_event_info));
	if (!local_gpe_event_info) {
		ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "while handling a GPE"));
		return_VOID;
	}

	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
	if (ACPI_FAILURE(status)) {
		ACPI_FREE(local_gpe_event_info);
		return_VOID;
	}

	/* Must revalidate the gpe_number/gpe_block */

	if (!acpi_ev_valid_gpe_event(gpe_event_info)) {
		status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
		ACPI_FREE(local_gpe_event_info);
		return_VOID;
	}

	/*
	 * Take a snapshot of the GPE info for this level - we copy the info to
	 * prevent a race condition with remove_handler/remove_block.
	 */
	ACPI_MEMCPY(local_gpe_event_info, gpe_event_info,
		    sizeof(struct acpi_gpe_event_info));

	status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
	if (ACPI_FAILURE(status)) {
		return_VOID;
	}

	/* Do the correct dispatch - normal method or implicit notify */

	switch (local_gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
	case ACPI_GPE_DISPATCH_NOTIFY:

		/*
		 * Implicit notify.
		 * Dispatch a DEVICE_WAKE notify to the appropriate handler.
		 * NOTE: the request is queued for execution after this method
		 * completes. The notify handlers are NOT invoked synchronously
		 * from this thread -- because handlers may in turn run other
		 * control methods.
		 *
		 * June 2012: Expand implicit notify mechanism to support
		 * notifies on multiple device objects.
		 */
		notify = local_gpe_event_info->dispatch.notify_list;
		while (ACPI_SUCCESS(status) && notify) {
			status =
			    acpi_ev_queue_notify_request(notify->device_node,
							 ACPI_NOTIFY_DEVICE_WAKE);

			notify = notify->next;
		}

		break;

	case ACPI_GPE_DISPATCH_METHOD:

		/* Allocate the evaluation information block */

		info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
		if (!info) {
			status = AE_NO_MEMORY;
		} else {
			/*
			 * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the _Lxx/_Exx
			 * control method that corresponds to this GPE
			 */
			info->prefix_node =
			    local_gpe_event_info->dispatch.method_node;
			info->flags = ACPI_IGNORE_RETURN_VALUE;

			status = acpi_ns_evaluate(info);
			ACPI_FREE(info);
		}

		if (ACPI_FAILURE(status)) {
			ACPI_EXCEPTION((AE_INFO, status,
					"while evaluating GPE method [%4.4s]",
					acpi_ut_get_node_name
					(local_gpe_event_info->dispatch.
					 method_node)));
		}

		break;

	default:
		return_VOID;    /* Should never happen */
	}

	/* Defer enabling of GPE until all notify handlers are done */

	status = acpi_os_execute(OSL_NOTIFY_HANDLER,
				 acpi_ev_asynch_enable_gpe,
				 local_gpe_event_info);
	if (ACPI_FAILURE(status)) {
		ACPI_FREE(local_gpe_event_info);
	}
	return_VOID;
}
Esempio n. 10
0
acpi_status
acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
			     u32 notify_value)
{
	union acpi_operand_object *obj_desc;
	union acpi_operand_object *handler_obj = NULL;
	union acpi_generic_state *notify_info;
	acpi_status status = AE_OK;

	ACPI_FUNCTION_NAME(ev_queue_notify_request);

	/*
	 * For value 3 (Ejection Request), some device method may need to be run.
	 * For value 2 (Device Wake) if _PRW exists, the _PS0 method may need
	 *   to be run.
	 * For value 0x80 (Status Change) on the power button or sleep button,
	 *   initiate soft-off or sleep operation?
	 */
	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
			  "Dispatching Notify on [%4.4s] Node %p Value 0x%2.2X (%s)\n",
			  acpi_ut_get_node_name(node), node, notify_value,
			  acpi_ut_get_notify_name(notify_value)));

	/* Get the notify object attached to the NS Node */

	obj_desc = acpi_ns_get_attached_object(node);
	if (obj_desc) {

		/* We have the notify object, Get the right handler */

		switch (node->type) {

			/* Notify allowed only on these types */

		case ACPI_TYPE_DEVICE:
		case ACPI_TYPE_THERMAL:
		case ACPI_TYPE_PROCESSOR:

			if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
				handler_obj =
				    obj_desc->common_notify.system_notify;
			} else {
				handler_obj =
				    obj_desc->common_notify.device_notify;
			}
			break;

		default:

			/* All other types are not supported */

			return (AE_TYPE);
		}
	}

	/*
	 * If there is any handler to run, schedule the dispatcher.
	 * Check for:
	 * 1) Global system notify handler
	 * 2) Global device notify handler
	 * 3) Per-device notify handler
	 */
	if ((acpi_gbl_system_notify.handler &&
	     (notify_value <= ACPI_MAX_SYS_NOTIFY)) ||
	    (acpi_gbl_device_notify.handler &&
	     (notify_value > ACPI_MAX_SYS_NOTIFY)) || handler_obj) {
		notify_info = acpi_ut_create_generic_state();
		if (!notify_info) {
			return (AE_NO_MEMORY);
		}

		if (!handler_obj) {
			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
					  "Executing system notify handler for Notify (%4.4s, %X) "
					  "node %p\n",
					  acpi_ut_get_node_name(node),
					  notify_value, node));
		}

		notify_info->common.descriptor_type =
		    ACPI_DESC_TYPE_STATE_NOTIFY;
		notify_info->notify.node = node;
		notify_info->notify.value = (u16) notify_value;
		notify_info->notify.handler_obj = handler_obj;

		status =
		    acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch,
				    notify_info);
		if (ACPI_FAILURE(status)) {
			acpi_ut_delete_generic_state(notify_info);
		}
	} else {
		/* There is no notify handler (per-device or system) for this device */

		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "No notify handler for Notify (%4.4s, %X) node %p\n",
				  acpi_ut_get_node_name(node), notify_value,
				  node));
	}

	return (status);
}
Esempio n. 11
0
u32
acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
{
	acpi_status status;

	ACPI_FUNCTION_TRACE(ev_gpe_dispatch);

	acpi_os_gpe_count(gpe_number);

	/*
	 * If edge-triggered, clear the GPE status bit now. Note that
	 * level-triggered events are cleared after the GPE is serviced.
	 */
	if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
	    ACPI_GPE_EDGE_TRIGGERED) {
		status = acpi_hw_clear_gpe(gpe_event_info);
		if (ACPI_FAILURE(status)) {
			ACPI_EXCEPTION((AE_INFO, status,
					"Unable to clear GPE[0x%2X]",
					gpe_number));
			return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
		}
	}

	/*
	 * Dispatch the GPE to either any installed handler or control
	 * method associated with this GPE (_Lxx or _Exx). We invoke
	 * the method first in case it has side effects that would be
	 * interfered with if the handler has already altered hardware
	 * state. If there is neither a handler nor a method, we
	 * disable this GPE to prevent further such pointless events
	 * from firing.
	 */
	if (gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD) {
		/*
		 * Disable the GPE, so it doesn't keep firing before the method has a
		 * chance to run (it runs asynchronously with interrupts enabled).
		 */
		status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
		if (ACPI_FAILURE(status)) {
			ACPI_EXCEPTION((AE_INFO, status,
					"Unable to disable GPE[0x%2X]",
					gpe_number));
			return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
		}

		/*
		 * Execute the method associated with the GPE
		 * NOTE: Level-triggered GPEs are cleared after the method completes.
		 */
		status = acpi_os_execute(OSL_GPE_HANDLER,
					 acpi_ev_asynch_execute_gpe_method,
					 gpe_event_info);
		if (ACPI_FAILURE(status)) {
			ACPI_EXCEPTION((AE_INFO, status,
					"Unable to queue handler for GPE[0x%2X] - event disabled",
					gpe_number));
		}
	}

	if (gpe_event_info->flags & ACPI_GPE_DISPATCH_HANDLER) {
		/*
		 * Invoke the installed handler (at interrupt level)
		 * Ignore return status for now.
		 * TBD: leave GPE disabled on error?
		 */
		(void)gpe_event_info->dispatch.handler->address(gpe_event_info->
								dispatch.
								handler->
								context);

		/* It is now safe to clear level-triggered events. */

		if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
		    ACPI_GPE_LEVEL_TRIGGERED) {
			status = acpi_hw_clear_gpe(gpe_event_info);
			if (ACPI_FAILURE(status)) {
				ACPI_EXCEPTION((AE_INFO, status,
					"Unable to clear GPE[0x%2X]",
						gpe_number));
				return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
			}
		}
	}

	if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)) {
		/*
		 * No handler or method to run!
		 * 03/2010: This case should no longer be possible. We will not allow
		 * a GPE to be enabled if it has no handler or method.
		 */
		ACPI_ERROR((AE_INFO,
			    "No handler or method for GPE[0x%2X], disabling event",
			    gpe_number));

		/*
		 * Disable the GPE. The GPE will remain disabled a handler
		 * is installed or ACPICA is restarted.
		 */
		status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
		if (ACPI_FAILURE(status)) {
			ACPI_EXCEPTION((AE_INFO, status,
					"Unable to disable GPE[0x%2X]",
					gpe_number));
			return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
		}
	}

	return_UINT32(ACPI_INTERRUPT_HANDLED);
}
Esempio n. 12
0
acpi_status
acpi_ev_queue_notify_request(struct acpi_namespace_node *node, u32 notify_value)
{
	union acpi_operand_object *obj_desc;
	union acpi_operand_object *handler_list_head = NULL;
	union acpi_generic_state *info;
	u8 handler_list_id = 0;
	acpi_status status = AE_OK;

	ACPI_FUNCTION_NAME(ev_queue_notify_request);

	/* Are Notifies allowed on this object? */

	if (!acpi_ev_is_notify_object(node)) {
		return (AE_TYPE);
	}

	/* Get the correct notify list type (System or Device) */

	if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
		handler_list_id = ACPI_SYSTEM_HANDLER_LIST;
	} else {
		handler_list_id = ACPI_DEVICE_HANDLER_LIST;
	}

	/* Get the notify object attached to the namespace Node */

	obj_desc = acpi_ns_get_attached_object(node);
	if (obj_desc) {

		/* We have an attached object, Get the correct handler list */

		handler_list_head =
		    obj_desc->common_notify.notify_list[handler_list_id];
	}

	/*
	 * If there is no notify handler (Global or Local)
	 * for this object, just ignore the notify
	 */
	if (!acpi_gbl_global_notify[handler_list_id].handler
	    && !handler_list_head) {
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "No notify handler for Notify, ignoring (%4.4s, %X) node %p\n",
				  acpi_ut_get_node_name(node), notify_value,
				  node));

		return (AE_OK);
	}

	/* Setup notify info and schedule the notify dispatcher */

	info = acpi_ut_create_generic_state();
	if (!info) {
		return (AE_NO_MEMORY);
	}

	info->common.descriptor_type = ACPI_DESC_TYPE_STATE_NOTIFY;

	info->notify.node = node;
	info->notify.value = (u16)notify_value;
	info->notify.handler_list_id = handler_list_id;
	info->notify.handler_list_head = handler_list_head;
	info->notify.global = &acpi_gbl_global_notify[handler_list_id];

	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
			  "Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n",
			  acpi_ut_get_node_name(node),
			  acpi_ut_get_type_name(node->type), notify_value,
			  acpi_ut_get_notify_name(notify_value, ACPI_TYPE_ANY),
			  node));

	status = acpi_os_execute(OSL_NOTIFY_HANDLER,
				 acpi_ev_notify_dispatch, info);
	if (ACPI_FAILURE(status)) {
		acpi_ut_delete_generic_state(info);
	}

	return (status);
}
Esempio n. 13
0
u32
acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
{
	acpi_status status;

	ACPI_FUNCTION_TRACE(ev_gpe_dispatch);

	acpi_os_gpe_count(gpe_number);

	
	if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
	    ACPI_GPE_EDGE_TRIGGERED) {
		status = acpi_hw_clear_gpe(gpe_event_info);
		if (ACPI_FAILURE(status)) {
			ACPI_EXCEPTION((AE_INFO, status,
					"Unable to clear GPE[%2X]",
					gpe_number));
			return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
		}
	}

	
	switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
	case ACPI_GPE_DISPATCH_HANDLER:

		
		(void)gpe_event_info->dispatch.handler->address(gpe_event_info->
								dispatch.
								handler->
								context);

		

		if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
		    ACPI_GPE_LEVEL_TRIGGERED) {
			status = acpi_hw_clear_gpe(gpe_event_info);
			if (ACPI_FAILURE(status)) {
				ACPI_EXCEPTION((AE_INFO, status,
						"Unable to clear GPE[%2X]",
						gpe_number));
				return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
			}
		}
		break;

	case ACPI_GPE_DISPATCH_METHOD:

		
		status = acpi_ev_disable_gpe(gpe_event_info);
		if (ACPI_FAILURE(status)) {
			ACPI_EXCEPTION((AE_INFO, status,
					"Unable to disable GPE[%2X]",
					gpe_number));
			return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
		}

		
		status = acpi_os_execute(OSL_GPE_HANDLER,
					 acpi_ev_asynch_execute_gpe_method,
					 gpe_event_info);
		if (ACPI_FAILURE(status)) {
			ACPI_EXCEPTION((AE_INFO, status,
					"Unable to queue handler for GPE[%2X] - event disabled",
					gpe_number));
		}
		break;

	default:

		

		ACPI_ERROR((AE_INFO,
			    "No handler or method for GPE[%2X], disabling event",
			    gpe_number));

		
		status = acpi_ev_disable_gpe(gpe_event_info);
		if (ACPI_FAILURE(status)) {
			ACPI_EXCEPTION((AE_INFO, status,
					"Unable to disable GPE[%2X]",
					gpe_number));
			return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
		}
		break;
	}

	return_UINT32(ACPI_INTERRUPT_HANDLED);
}
Esempio n. 14
0
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
{
	struct acpi_gpe_event_info *gpe_event_info = (void *)context;
	acpi_status status;
	struct acpi_gpe_event_info local_gpe_event_info;
	struct acpi_evaluate_info *info;

	ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method);

	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
	if (ACPI_FAILURE(status)) {
		return_VOID;
	}

	

	if (!acpi_ev_valid_gpe_event(gpe_event_info)) {
		status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
		return_VOID;
	}

	

	(void)acpi_ev_enable_gpe(gpe_event_info, FALSE);

	
	ACPI_MEMCPY(&local_gpe_event_info, gpe_event_info,
		    sizeof(struct acpi_gpe_event_info));

	status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
	if (ACPI_FAILURE(status)) {
		return_VOID;
	}

	
	if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) ==
	    ACPI_GPE_DISPATCH_METHOD) {

		

		info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
		if (!info) {
			status = AE_NO_MEMORY;
		} else {
			
			info->prefix_node =
			    local_gpe_event_info.dispatch.method_node;
			info->flags = ACPI_IGNORE_RETURN_VALUE;

			status = acpi_ns_evaluate(info);
			ACPI_FREE(info);
		}

		if (ACPI_FAILURE(status)) {
			ACPI_EXCEPTION((AE_INFO, status,
					"while evaluating GPE method [%4.4s]",
					acpi_ut_get_node_name
					(local_gpe_event_info.dispatch.
					 method_node)));
		}
	}
	
	acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_asynch_enable_gpe,
				gpe_event_info);
	return_VOID;
}