/* * 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; }
/** * 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; }
/** * 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); }