Пример #1
0
/*
 * Acquire a spinlock.
 *
 * handle is a pointer to the spinlock_t.
 * flags is *not* the result of save_flags - it is an ACPI-specific flag variable
 *   that indicates whether we are at interrupt level.
 */
void
acpi_os_acquire_lock (
	acpi_handle	handle,
	u32		flags)
{
	ACPI_FUNCTION_TRACE ("os_acquire_lock");

	ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Acquiring spinlock[%p] from %s level\n", handle,
		((flags & ACPI_NOT_ISR) ? "non-interrupt" : "interrupt")));

	if (flags & ACPI_NOT_ISR)
		ACPI_DISABLE_IRQS();

	spin_lock((spinlock_t *)handle);

	return_VOID;
}
Пример #2
0
/**
 * acpi_system_restore_state - OS-specific restoration of state
 * @state:	sleep state we're exiting
 *
 * Note that if we're coming back from S4, the memory image should have
 * already been loaded from the disk and is already in place.  (Otherwise how
 * else would we be here?).
 */
acpi_status
acpi_system_restore_state(
	u32			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 (state > ACPI_STATE_S1) {
		acpi_restore_state_mem();

		/* Do _early_ resume for irqs.  Required by
		 * ACPI specs.
		 */
		/* TBD: call arch dependant reinitialization of the 
		 * interrupts.
		 */
#ifdef CONFIG_X86
		init_8259A(0);
#endif
		/* wait for power to come back */
		mdelay(1000);

	}

	/* Be really sure that irqs are disabled. */
	ACPI_DISABLE_IRQS();

	/* Wait a little again, just in case... */
	mdelay(1000);

	/* enable interrupts once again */
	ACPI_ENABLE_IRQS();

	/* turn all the devices back on */
	if (state > ACPI_STATE_S1)
		pm_send_all(PM_RESUME, (void *)0);

	return AE_OK;
}
Пример #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;
}
int
acpi_sleep_machdep(struct acpi_softc *sc, int state)
{
	ACPI_STATUS		status;
	struct pmap		*pm;
	int			ret;
	uint32_t		cr3;
	u_long			ef;

	ret = 0;
	if (sc->acpi_wakeaddr == 0)
		return (0);

	AcpiSetFirmwareWakingVector(sc->acpi_wakephys);

	ef = read_eflags();

	/*
	 * Temporarily switch to the kernel pmap because it provides an
	 * identity mapping (setup at boot) for the low physical memory
	 * region containing the wakeup code.
	 */
	pm = kernel_pmap;
	cr3 = rcr3();
#ifdef PAE
	load_cr3(vtophys(pm->pm_pdpt));
#else
	load_cr3(vtophys(pm->pm_pdir));
#endif

	ret_addr = 0;
	ACPI_DISABLE_IRQS();
	if (acpi_savecpu()) {
		/* Execute Sleep */
		intr_suspend();

		p_gdt = (struct region_descriptor *)
				(sc->acpi_wakeaddr + physical_gdt);
		p_gdt->rd_limit = saved_gdt.rd_limit;
		p_gdt->rd_base = vtophys(saved_gdt.rd_base);

		WAKECODE_FIXUP(physical_esp, uint32_t, vtophys(r_esp));
		WAKECODE_FIXUP(previous_cr0, uint32_t, r_cr0);
		WAKECODE_FIXUP(previous_cr2, uint32_t, r_cr2);
		WAKECODE_FIXUP(previous_cr3, uint32_t, r_cr3);
		WAKECODE_FIXUP(previous_cr4, uint32_t, r_cr4);

		WAKECODE_FIXUP(resume_beep, uint32_t, acpi_resume_beep);
		WAKECODE_FIXUP(reset_video, uint32_t, acpi_reset_video);

		WAKECODE_FIXUP(previous_tr,  uint16_t, r_tr);
		WAKECODE_BCOPY(previous_gdt, struct region_descriptor, saved_gdt);
		WAKECODE_FIXUP(previous_ldt, uint16_t, saved_ldt);
		WAKECODE_BCOPY(previous_idt, struct region_descriptor, saved_idt);

		WAKECODE_FIXUP(where_to_recover, void *, acpi_restorecpu);

		WAKECODE_FIXUP(previous_ds,  uint16_t, r_ds);
		WAKECODE_FIXUP(previous_es,  uint16_t, r_es);
		WAKECODE_FIXUP(previous_fs,  uint16_t, r_fs);
		WAKECODE_FIXUP(previous_gs,  uint16_t, r_gs);
		WAKECODE_FIXUP(previous_ss,  uint16_t, r_ss);

		if (bootverbose)
			acpi_printcpu();

		/* Call ACPICA to enter the desired sleep state */
		if (state == ACPI_STATE_S4 && sc->acpi_s4bios)
			status = AcpiEnterSleepStateS4bios();
		else
			status = AcpiEnterSleepState(state);

		if (status != AE_OK) {
			device_printf(sc->acpi_dev,
				"AcpiEnterSleepState failed - %s\n",
				AcpiFormatException(status));
			ret = -1;
			goto out;
		}

		for (;;) ;
	} else {
		/* Execute Wakeup */
		intr_resume();

		if (bootverbose) {
			acpi_savecpu();
			acpi_printcpu();
		}
	}

out:
	load_cr3(cr3);
	write_eflags(ef);

	/* If we beeped, turn it off after a delay. */
	if (acpi_resume_beep)
		timeout(acpi_stop_beep, NULL, 3 * hz);

	return (ret);
}