Beispiel #1
0
/**
 *	acpi_suspend_enter - Actually enter a sleep state.
 *	@pm_state: ignored
 *
 *	Flush caches and go to sleep. For STR we have to call arch-specific
 *	assembly, which in turn call acpi_enter_sleep_state().
 *	It's unfortunate, but it works. Please fix if you're feeling frisky.
 */
static int acpi_suspend_enter(suspend_state_t pm_state)
{
    acpi_status status = AE_OK;
    unsigned long flags = 0;
    u32 acpi_state = acpi_target_sleep_state;

    ACPI_FLUSH_CPU_CACHE();

    /* Do arch specific saving of state. */
    if (acpi_state == ACPI_STATE_S3) {
        int error = acpi_save_state_mem();

        if (error)
            return error;
    }

    local_irq_save(flags);
    acpi_enable_wakeup_device(acpi_state);
    switch (acpi_state) {
    case ACPI_STATE_S1:
        barrier();
        status = acpi_enter_sleep_state(acpi_state);
        break;

    case ACPI_STATE_S3:
        do_suspend_lowlevel();
        break;
    }

    /* Reprogram control registers and execute _BFS */
    acpi_leave_sleep_state_prep(acpi_state);

    /* ACPI 3.0 specs (P62) says that it's the responsibility
     * of the OSPM to clear the status bit [ implying that the
     * POWER_BUTTON event should not reach userspace ]
     */
    if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3))
        acpi_clear_event(ACPI_EVENT_POWER_BUTTON);

    /*
     * Disable and clear GPE status before interrupt is enabled. Some GPEs
     * (like wakeup GPE) haven't handler, this can avoid such GPE misfire.
     * acpi_leave_sleep_state will reenable specific GPEs later
     */
    acpi_hw_disable_all_gpes();

    local_irq_restore(flags);
    printk(KERN_DEBUG "Back to C!\n");

    /* restore processor state */
    if (acpi_state == ACPI_STATE_S3)
        acpi_restore_state_mem();

    return ACPI_SUCCESS(status) ? 0 : -EFAULT;
}
Beispiel #2
0
static int acpi_pm_enter(suspend_state_t pm_state)
{
	acpi_status status = AE_OK;
	unsigned long flags = 0;
	u32 acpi_state = acpi_suspend_states[pm_state];

	ACPI_FLUSH_CPU_CACHE();

	/* Do arch specific saving of state. */
	if (pm_state > PM_SUSPEND_STANDBY) {
		int error = acpi_save_state_mem();
		if (error)
			return error;
	}

	local_irq_save(flags);
	acpi_enable_wakeup_device(acpi_state);
	switch (pm_state) {
	case PM_SUSPEND_STANDBY:
		barrier();
		status = acpi_enter_sleep_state(acpi_state);
		break;

	case PM_SUSPEND_MEM:
		do_suspend_lowlevel();
		break;

	case PM_SUSPEND_DISK:
		if (acpi_pm_ops.pm_disk_mode == PM_DISK_PLATFORM)
			status = acpi_enter_sleep_state(acpi_state);
		else
			do_suspend_lowlevel_s4bios();
		break;
	case PM_SUSPEND_MAX:
		acpi_power_off();
		break;

	default:
		return -EINVAL;
	}
	local_irq_restore(flags);
	printk(KERN_DEBUG "Back to C!\n");

	/* restore processor state
	 * We should only be here if we're coming back from STR or STD.
	 * And, in the case of the latter, the memory image should have already
	 * been loaded from disk.
	 */
	if (pm_state > PM_SUSPEND_STANDBY)
		acpi_restore_state_mem();

	return ACPI_SUCCESS(status) ? 0 : -EFAULT;
}
Beispiel #3
0
/**
 * acpi_system_save_state - save OS specific state and power down devices
 * @state:	sleep state we're entering.
 *
 * This handles saving all context to memory, and possibly disk.
 * First, we call to the device driver layer to save device state.
 * Once we have that, we save whatevery processor and kernel state we
 * need to memory.
 * If we're entering S4, we then write the memory image to disk.
 *
 * Only then it is safe for us to power down devices, since we may need
 * the disks and upstream buses to write to.
 */
acpi_status
acpi_system_save_state(
	u32			state)
{
	int			error = 0;

	/* Send notification to devices that they will be suspended.
	 * If any device or driver cannot make the transition, either up
	 * or down, we'll get an error back.
	 */
	if (state > ACPI_STATE_S1) {
		error = pm_send_all(PM_SAVE_STATE, (void *)3);
		if (error)
			return AE_ERROR;
	}

	if (state <= ACPI_STATE_S5) {
		/* Tell devices to stop I/O and actually save their state.
		 * It is theoretically possible that something could fail,
		 * so handle that gracefully..
		 */
		if (state > ACPI_STATE_S1 && state != ACPI_STATE_S5) {
			error = pm_send_all(PM_SUSPEND, (void *)3);
			if (error) {
				/* Tell devices to restore state if they have
				 * it saved and to start taking I/O requests.
				 */
				pm_send_all(PM_RESUME, (void *)0);
				return error;
			}
		}
		
		/* flush caches */
		ACPI_FLUSH_CPU_CACHE();

		/* Do arch specific saving of state. */
		if (state > ACPI_STATE_S1) {
			error = acpi_save_state_mem();

			/* TBD: if no s4bios, write codes for
			 * acpi_save_state_disk()...
			 */
#if 0
			if (!error && (state == ACPI_STATE_S4))
				error = acpi_save_state_disk();
#endif
			if (error) {
				pm_send_all(PM_RESUME, (void *)0);
				return error;
			}
		}
	}
	/* disable interrupts
	 * Note that acpi_suspend -- our caller -- will do this once we return.
	 * But, we want it done early, so we don't get any suprises during
	 * the device suspend sequence.
	 */
	ACPI_DISABLE_IRQS();

	/* Unconditionally turn off devices.
	 * Obvious if we enter a sleep state.
	 * If entering S5 (soft off), this should put devices in a
	 * quiescent state.
	 */

	if (state > ACPI_STATE_S1) {
		error = pm_send_all(PM_SUSPEND, (void *)3);

		/* We're pretty screwed if we got an error from this.
		 * We try to recover by simply calling our own restore_state
		 * function; see above for definition.
		 *
		 * If it's S5 though, go through with it anyway..
		 */
		if (error && state != ACPI_STATE_S5)
			acpi_system_restore_state(state);
	}
	return error ? AE_ERROR : AE_OK;
}
Beispiel #4
0
static int acpi_pm_enter(suspend_state_t pm_state)
{
	acpi_status status = AE_OK;
	unsigned long flags = 0;
	u32 acpi_state = acpi_suspend_states[pm_state];

	ACPI_FLUSH_CPU_CACHE();

	/* Do arch specific saving of state. */
	if (pm_state > PM_SUSPEND_STANDBY) {
		int error = acpi_save_state_mem();
		if (error)
			return error;
	}

	local_irq_save(flags);
	acpi_enable_wakeup_device(acpi_state);
	switch (pm_state) {
	case PM_SUSPEND_STANDBY:
		barrier();
		status = acpi_enter_sleep_state(acpi_state);
		break;

	case PM_SUSPEND_MEM:
		if (unlikely(acpi_simulate_suspend_to_ram)) {
			printk(KERN_INFO "ACPI: simulating suspend-to-RAM: "
					 "not calling BIOS.\n");
		} else {
			do_suspend_lowlevel();
		}
		break;

	case PM_SUSPEND_DISK:
		if (acpi_pm_ops.pm_disk_mode == PM_DISK_PLATFORM)
			status = acpi_enter_sleep_state(acpi_state);
		break;
	case PM_SUSPEND_MAX:
		acpi_power_off();
		break;

	default:
		return -EINVAL;
	}

	/* ACPI 3.0 specs (P62) says that it's the responsabilty
	 * of the OSPM to clear the status bit [ implying that the
	 * POWER_BUTTON event should not reach userspace ]
	 */
	if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3))
		acpi_clear_event(ACPI_EVENT_POWER_BUTTON);

	local_irq_restore(flags);
	printk(KERN_DEBUG "Back to C!\n");

	/* restore processor state
	 * We should only be here if we're coming back from STR or STD.
	 * And, in the case of the latter, the memory image should have already
	 * been loaded from disk.
	 */
	if (pm_state > PM_SUSPEND_STANDBY)
		acpi_restore_state_mem();

	return ACPI_SUCCESS(status) ? 0 : -EFAULT;
}