Index: sys/dev/acpica/acpi.c =================================================================== --- sys/dev/acpica/acpi.c +++ sys/dev/acpica/acpi.c @@ -54,7 +54,6 @@ #if defined(__i386__) || defined(__amd64__) #include -#include #include #include #include @@ -99,14 +98,6 @@ int num; }; -enum s2idle_enable { - POWER_BUTTON_S2I, - SLEEP_BUTTON_S2I, - LID_SWITCH_S2I, - STANDBY_S2I, - SUSPEND_S2I -}; - static char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL }; /* Global mutex for locking access to the ACPI subsystem. */ @@ -121,7 +112,6 @@ static void acpi_lookup(void *arg, const char *name, device_t *dev); static int acpi_modevent(struct module *mod, int event, void *junk); -static int acpi_parse_pxm(device_t dev); static device_probe_t acpi_probe; static device_attach_t acpi_attach; @@ -152,7 +142,7 @@ static bus_hint_device_unit_t acpi_hint_device_unit; static bus_get_property_t acpi_bus_get_prop; static bus_get_device_path_t acpi_get_device_path; -static bus_get_domain_t acpibus_get_domain_method; +static bus_get_domain_t acpi_get_domain_method; static acpi_id_probe_t acpi_device_id_probe; static acpi_evaluate_object_t acpi_device_eval_obj; @@ -175,7 +165,7 @@ void *context, void **status); static void acpi_sleep_enable(void *arg); static ACPI_STATUS acpi_sleep_disable(struct acpi_softc *sc); -static ACPI_STATUS acpi_EnterSleepState(struct acpi_softc *sc, enum sleep_type stype); +static ACPI_STATUS acpi_EnterSleepState(struct acpi_softc *sc, int state); static void acpi_shutdown_final(void *arg, int howto); static void acpi_enable_fixed_events(struct acpi_softc *sc); static void acpi_resync_clock(struct acpi_softc *sc); @@ -184,9 +174,8 @@ static int acpi_wake_prep_walk(int sstate); static int acpi_wake_sysctl_walk(device_t dev); static int acpi_wake_set_sysctl(SYSCTL_HANDLER_ARGS); -static void acpi_system_eventhandler_sleep(void *arg, enum sleep_type type); -static void acpi_system_eventhandler_wakeup(void *arg, enum sleep_type type); -static int acpi_stype2sstate(enum sleep_type type); +static void acpi_system_eventhandler_sleep(void *arg, int state); +static void acpi_system_eventhandler_wakeup(void *arg, int state); static int acpi_sname2sstate(const char *sname); static const char *acpi_sstate2sname(int sstate); static int acpi_supported_sleep_state_sysctl(SYSCTL_HANDLER_ARGS); @@ -231,7 +220,7 @@ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_hint_device_unit, acpi_hint_device_unit), DEVMETHOD(bus_get_cpus, acpi_get_cpus), - DEVMETHOD(bus_get_domain, acpibus_get_domain_method), + DEVMETHOD(bus_get_domain, acpi_get_domain_method), DEVMETHOD(bus_get_property, acpi_bus_get_prop), DEVMETHOD(bus_get_device_path, acpi_get_device_path), @@ -595,28 +584,26 @@ SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), OID_AUTO, "power_button_state", CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, - &sc->acpi_power_button.sx, POWER_BUTTON_S2I, acpi_sleep_state_sysctl, - "A", "Power button ACPI sleep state."); + &sc->acpi_power_button_sx, 0, acpi_sleep_state_sysctl, "A", + "Power button ACPI sleep state."); SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), OID_AUTO, "sleep_button_state", CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, - &sc->acpi_sleep_button.sx, POWER_BUTTON_S2I, acpi_sleep_state_sysctl, - "A", "Sleep button ACPI sleep state."); + &sc->acpi_sleep_button_sx, 0, acpi_sleep_state_sysctl, "A", + "Sleep button ACPI sleep state."); SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), OID_AUTO, "lid_switch_state", CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, - &sc->acpi_lid_switch.sx, POWER_BUTTON_S2I, acpi_sleep_state_sysctl, "A", + &sc->acpi_lid_switch_sx, 0, acpi_sleep_state_sysctl, "A", "Lid ACPI sleep state. Set to S3 if you want to suspend your laptop when close the Lid."); SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), OID_AUTO, "standby_state", CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, - &sc->acpi_standby.sx, POWER_BUTTON_S2I, acpi_sleep_state_sysctl, "A", - ""); + &sc->acpi_standby_sx, 0, acpi_sleep_state_sysctl, "A", ""); SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), OID_AUTO, "suspend_state", CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, - &sc->acpi_suspend.sx, POWER_BUTTON_S2I, acpi_sleep_state_sysctl, "A", - ""); + &sc->acpi_suspend_sx, 0, acpi_sleep_state_sysctl, "A", ""); SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), OID_AUTO, "sleep_delay", CTLFLAG_RW, &sc->acpi_sleep_delay, 0, "sleep delay in seconds"); @@ -679,19 +666,19 @@ * Dispatch the default sleep state to devices. The lid switch is set * to UNKNOWN by default to avoid surprising users. */ - sc->acpi_power_button.sx = acpi_sleep_states[ACPI_STATE_S5] ? + sc->acpi_power_button_sx = acpi_sleep_states[ACPI_STATE_S5] ? ACPI_STATE_S5 : ACPI_STATE_UNKNOWN; - sc->acpi_lid_switch.sx = ACPI_STATE_UNKNOWN; - sc->acpi_standby.sx = acpi_sleep_states[ACPI_STATE_S1] ? + sc->acpi_lid_switch_sx = ACPI_STATE_UNKNOWN; + sc->acpi_standby_sx = acpi_sleep_states[ACPI_STATE_S1] ? ACPI_STATE_S1 : ACPI_STATE_UNKNOWN; - sc->acpi_suspend.sx = acpi_sleep_states[ACPI_STATE_S3] ? + sc->acpi_suspend_sx = acpi_sleep_states[ACPI_STATE_S3] ? ACPI_STATE_S3 : ACPI_STATE_UNKNOWN; /* Pick the first valid sleep state for the sleep button default. */ - sc->acpi_sleep_button.sx = ACPI_STATE_UNKNOWN; + sc->acpi_sleep_button_sx = ACPI_STATE_UNKNOWN; for (state = ACPI_STATE_S1; state <= ACPI_STATE_S4; state++) if (acpi_sleep_states[state]) { - sc->acpi_sleep_button.sx = state; + sc->acpi_sleep_button_sx = state; break; } @@ -716,8 +703,8 @@ /* Flag our initial states. */ sc->acpi_enabled = TRUE; - sc->acpi_sstate = AWAKE; - sc->acpi_repressed_states.flags |= 1 << ACPI_SLEEP_DISABLED; + sc->acpi_sstate = ACPI_STATE_S0; + sc->acpi_sleep_disabled = TRUE; /* Create the control device */ sc->acpi_dev_t = make_dev(&acpi_cdevsw, 0, UID_ROOT, GID_OPERATOR, 0664, @@ -1318,47 +1305,15 @@ } } -/* - * Fetch the NUMA domain for the given device 'dev'. - * - * If a device has a _PXM method, map that to a NUMA domain. - * Otherwise, pass the request up to the parent. - * If there's no matching domain or the domain cannot be - * determined, return ENOENT. - */ -int -acpi_get_domain_method(device_t dev, device_t child, int *domain) -{ - int d; - - d = acpi_pxm_parse(child); - if (d >= 0) { - *domain = d; - return (0); - } - if (d == -1) - return (ENOENT); - - /* No _PXM node; go up a level */ - return (bus_generic_get_domain(dev, child, domain)); -} - static int -acpibus_get_domain_method(device_t dev, device_t child, int *domain) +acpi_get_domain_method(device_t dev, device_t child, int *domain) { - int error, d; + int error; error = acpi_read_ivar(dev, child, ACPI_IVAR_DOMAIN, (uintptr_t *)domain); if (error == 0 && *domain != ACPI_DEV_DOMAIN_UNKNOWN) return (0); - - d = acpi_parse_pxm(child); - if (d >= 0) { - *domain = d; - acpi_write_ivar(dev, child, ACPI_IVAR_DOMAIN, d); - return (0); - } return (ENOENT); } @@ -2081,10 +2036,7 @@ * Note illegal _S0D is evaluated because some systems expect this. */ sc = device_get_softc(bus); - - snprintf(sxd, sizeof(sxd), "_S%dD", - sc->acpi_sstate != SUSPEND_TO_IDLE ?: SUSPEND); - MPASS(sxd[2] < '4'); /* only up to S3 supported */ + snprintf(sxd, sizeof(sxd), "_S%dD", sc->acpi_sstate); status = acpi_GetInteger(handle, sxd, dstate); if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { device_printf(dev, "failed to get %s on %s: %s\n", sxd, @@ -2391,7 +2343,7 @@ ACPI_HANDLE h; device_t bus, child; char *handle_str; - int order; + int d, order; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); @@ -2499,6 +2451,10 @@ } AcpiOsFree(devinfo); } + + d = acpi_pxm_parse(child); + if (d >= 0) + ad->ad_domain = d; break; } } @@ -3168,8 +3124,7 @@ "warning: acpi_SetSleepState() deprecated, need to update your software\n"); once = 1; } - MPASS(state < ACPI_S_STATES_MAX); - return (acpi_EnterSleepState(sc, (enum sleep_type) state)); + return (acpi_EnterSleepState(sc, state)); } #if defined(__amd64__) || defined(__i386__) @@ -3198,58 +3153,8 @@ acpi_sleep_force_task, sc))) device_printf(sc->acpi_dev, "AcpiOsExecute() for sleeping failed\n"); } - -static enum sleep_type -select_sleep_type(struct acpi_softc *sc, int state) -{ - MPASS(state == ACPI_STATE_S3 || state == ACPI_STATE_S1); - - /* The user explicitly requested */ - if (state == ACPI_STATE_S3 && - sc->acpi_suspend.sx == SUSPEND_TO_IDLE) - return SUSPEND_TO_IDLE; - - if (state == ACPI_STATE_S1 && - sc->acpi_standby.sx == SUSPEND_TO_IDLE) - return SUSPEND_TO_IDLE; - - /* The system supports the HW state, and that's probably best */ - if (acpi_sleep_states[state]) - return (enum sleep_type)state; - - /* idle is the best we can do. */ - device_printf(sc->acpi_dev, - "Requested S%d, but using S0IDLE instead\n", state); - return SUSPEND_TO_IDLE; -} -#else -static enum sleep_type -select_sleep_type(struct acpi_softc *sc) -{ - return AWAKE; -} #endif -/* Given a sleep type and a state, figures out if an error is warranted */ -static int -sanitize_sstate(struct acpi_softc *sc, enum sleep_type stype, int state, - bool acpi_err) -{ - if (stype == SUSPEND_TO_IDLE) - goto out; - - if (state < ACPI_STATE_S1 || state > ACPI_S_STATES_MAX) - return acpi_err ? (AE_BAD_PARAMETER) : (EINVAL); - if (!acpi_sleep_states[state]) { - device_printf(sc->acpi_dev, - "Sleep state S%d not supported by BIOS\n", state); - return acpi_err ? (AE_SUPPORT) : (EOPNOTSUPP); - } - -out: - return acpi_err ? (AE_OK) : (0); -} - /* * Request that the system enter the given suspend state. All /dev/apm * devices and devd(8) will be notified. Userland then has a chance to @@ -3257,40 +3162,38 @@ * acks are in. */ int -acpi_ReqSleepState(struct acpi_softc *sc, enum sleep_type stype) +acpi_ReqSleepState(struct acpi_softc *sc, int state) { #if defined(__amd64__) || defined(__i386__) struct apm_clone_data *clone; ACPI_STATUS status; - int sstate, err; - sstate = acpi_stype2sstate(stype); - - err = sanitize_sstate(sc, stype, sstate, false); - if (err) - return err; + if (state < ACPI_STATE_S1 || state > ACPI_S_STATES_MAX) + return (EINVAL); + if (!acpi_sleep_states[state]) + return (EOPNOTSUPP); /* * If a reboot/shutdown/suspend request is already in progress or * suspend is blocked due to an upcoming shutdown, just return. */ - if (rebooting || sc->acpi_next_sstate != AWAKE || suspend_blocked) { + if (rebooting || sc->acpi_next_sstate != 0 || suspend_blocked) { return (0); } /* Wait until sleep is enabled. */ - while (sc->acpi_repressed_states.flags & (1 <acpi_sleep_disabled) { AcpiOsSleep(1000); } ACPI_LOCK(acpi); - sc->acpi_next_sstate = stype; + sc->acpi_next_sstate = state; /* S5 (soft-off) should be entered directly with no waiting. */ - if (stype == POWEROFF) { + if (state == ACPI_STATE_S5) { ACPI_UNLOCK(acpi); - status = acpi_EnterSleepState(sc, stype); + status = acpi_EnterSleepState(sc, state); return (ACPI_SUCCESS(status) ? 0 : ENXIO); } @@ -3306,7 +3209,7 @@ /* If devd(8) is not running, immediately enter the sleep state. */ if (!devctl_process_running()) { ACPI_UNLOCK(acpi); - status = acpi_EnterSleepState(sc, stype); + status = acpi_EnterSleepState(sc, state); return (ACPI_SUCCESS(status) ? 0 : ENXIO); } @@ -3321,14 +3224,11 @@ ACPI_UNLOCK(acpi); /* Now notify devd(8) also. */ - acpi_UserNotify("Suspend", ACPI_ROOT_OBJECT, stype); + acpi_UserNotify("Suspend", ACPI_ROOT_OBJECT, state); return (0); #else - /* - * This platform does not support acpi suspend/resume. - * TODO: Support s2idle here since it's platform agnostic. - */ + /* This platform does not support acpi suspend/resume. */ return (EOPNOTSUPP); #endif } @@ -3350,14 +3250,14 @@ /* If no pending sleep state, return an error. */ ACPI_LOCK(acpi); sc = clone->acpi_sc; - if (sc->acpi_next_sstate == AWAKE) { + if (sc->acpi_next_sstate == 0) { ACPI_UNLOCK(acpi); return (ENXIO); } /* Caller wants to abort suspend process. */ if (error) { - sc->acpi_next_sstate = AWAKE; + sc->acpi_next_sstate = 0; callout_stop(&sc->susp_force_to); device_printf(sc->acpi_dev, "listener on %s cancelled the pending suspend\n", @@ -3392,10 +3292,7 @@ } return (ret); #else - /* - * This platform does not support acpi suspend/resume. - * TODO: Support s2idle here since it's platform agnostic. - */ + /* This platform does not support acpi suspend/resume. */ return (EOPNOTSUPP); #endif } @@ -3413,20 +3310,24 @@ return; } - atomic_clear_int(&sc->acpi_repressed_states.flags, 1 << ACPI_SLEEP_DISABLED); + sc->acpi_sleep_disabled = FALSE; } static ACPI_STATUS acpi_sleep_disable(struct acpi_softc *sc) { + ACPI_STATUS status; + /* Fail if the system is not fully up and running. */ if (!AcpiGbl_SystemAwakeAndRunning) return (AE_ERROR); - if (atomic_testandset_int(&sc->acpi_repressed_states.flags, ACPI_SLEEP_DISABLED)) - return AE_ERROR; + ACPI_LOCK(acpi); + status = sc->acpi_sleep_disabled ? AE_ERROR : AE_OK; + sc->acpi_sleep_disabled = TRUE; + ACPI_UNLOCK(acpi); - return AE_OK; + return (status); } enum acpi_sleep_state { @@ -3437,119 +3338,29 @@ ACPI_SS_SLEPT, }; -static void -acpi_state_transition_disable(struct acpi_softc *sc) -{ - int tmp; - tmp = atomic_swap_int(&sc->acpi_repressed_states.flags, ~0); - - /* Disallow re-entrancy. Disabling sleep with this is allowed though. */ - if (tmp & ~(1 << ACPI_SLEEP_DISABLED)) { - device_printf(sc->acpi_dev, "Invalid saved power flags"); - tmp &= (1 << ACPI_SLEEP_DISABLED); - } - sc->acpi_repressed_states.saved_flags = tmp; -} - -static void -acpi_state_transition_enable(struct acpi_softc *sc) -{ -#ifdef INVARIANTS - int tmp; - tmp = atomic_swap_int(&sc->acpi_repressed_states.flags, sc->acpi_repressed_states.saved_flags); - MPASS(tmp == ~0); -#else - atomic_store_int(&sc->acpi_repressed_states.flags, sc->sc->acpi_repressed_states.saved_flags); -#endif - - sc->acpi_repressed_states.saved_flags = 0; -} - -BOOLEAN -acpi_PowerTransitionIsEnabled(void) -{ - struct acpi_softc *sc = devclass_get_softc(devclass_find("acpi"), 0); - MPASS(sc != NULL); - return (sc->acpi_repressed_states.flags & (1 << ACPI_POWER_DISABLED)) == 0; -} - -static void -__do_idle(struct acpi_softc *sc) -{ - register_t intr; - - intr = intr_disable(); - intr_suspend(); - /* XXX: Is this actually required? */ - intr_enable_src(acpi_GetSciInterrupt()); - acpi_state_transition_disable(sc); - cpu_idle(0); - acpi_state_transition_enable(sc); - intr_resume(false); - intr_restore(intr); -} - -static void -__do_sleep(struct acpi_softc *sc, int state, enum acpi_sleep_state *pass) -{ - int sleep_result; - register_t intr; - - MPASS(state == ACPI_STATE_S3 || state == ACPI_STATE_S4); - - intr = intr_disable(); - - sleep_result = acpi_sleep_machdep(sc, state); - acpi_wakeup_machdep(sc, state, sleep_result, 0); - - if (sleep_result == 1 && state == ACPI_STATE_S3) { - /* - * XXX According to ACPI specification SCI_EN bit should be restored by - * ACPI platform (BIOS, firmware) to its pre-sleep state. Unfortunately - * some BIOSes fail to do that and that leads to unexpected and serious - * consequences during wake up like a system getting stuck in SMI - * handlers. This hack is picked up from Linux, which claims that it - * follows Windows behavior. - */ - AcpiWriteBitRegister(ACPI_BITREG_SCI_ENABLE, ACPI_ENABLE_EVENT); - } - - intr_restore(intr); - - /* call acpi_wakeup_machdep() again with interrupt enabled */ - acpi_wakeup_machdep(sc, state, sleep_result, 1); - - AcpiLeaveSleepStatePrep(state); - - if (sleep_result == -1) - return; - - /* Re-enable ACPI hardware on wakeup from sleep state 4. */ - if (state == ACPI_STATE_S4) - AcpiEnable(); - - *pass = ACPI_SS_SLEPT; -} - /* * Enter the desired system sleep state. * * Currently we support S1-S5 but S4 is only S4BIOS */ static ACPI_STATUS -acpi_EnterSleepState(struct acpi_softc *sc, enum sleep_type stype) +acpi_EnterSleepState(struct acpi_softc *sc, int state) { + register_t intr; ACPI_STATUS status; + ACPI_EVENT_STATUS power_button_status; enum acpi_sleep_state slp_state; - int state, err; - - ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, stype); + int sleep_result; - state = acpi_stype2sstate(stype); + ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state); - err = sanitize_sstate(sc, stype, state, true); - if (err) - return_ACPI_STATUS (err); + if (state < ACPI_STATE_S1 || state > ACPI_S_STATES_MAX) + return_ACPI_STATUS (AE_BAD_PARAMETER); + if (!acpi_sleep_states[state]) { + device_printf(sc->acpi_dev, "Sleep state S%d not supported by BIOS\n", + state); + return (AE_SUPPORT); + } /* Re-entry once we're suspending is not allowed. */ status = acpi_sleep_disable(sc); @@ -3559,7 +3370,7 @@ return (status); } - if (stype == POWEROFF) { + if (state == ACPI_STATE_S5) { /* * Shut down cleanly and power off. This will call us back through the * shutdown handlers. @@ -3573,11 +3384,18 @@ suspend_all_fs(); EVENTHANDLER_INVOKE(power_suspend); - // XXX s2idle +#ifdef EARLY_AP_STARTUP MPASS(mp_ncpus == 1 || smp_started); thread_lock(curthread); sched_bind(curthread, 0); thread_unlock(curthread); +#else + if (smp_started) { + thread_lock(curthread); + sched_bind(curthread, 0); + thread_unlock(curthread); + } +#endif /* * Be sure to hold Giant across DEVICE_SUSPEND/RESUME @@ -3586,7 +3404,7 @@ slp_state = ACPI_SS_NONE; - sc->acpi_sstate = stype; + sc->acpi_sstate = state; /* Enable any GPEs as appropriate and requested by the user. */ acpi_wake_prep_walk(state); @@ -3606,13 +3424,11 @@ } slp_state = ACPI_SS_DEV_SUSPEND; - if (stype != SUSPEND_TO_IDLE) { - status = AcpiEnterSleepStatePrep(state); - if (ACPI_FAILURE(status)) { - device_printf(sc->acpi_dev, "AcpiEnterSleepStatePrep failed - %s\n", - AcpiFormatException(status)); - goto backout; - } + status = AcpiEnterSleepStatePrep(state); + if (ACPI_FAILURE(status)) { + device_printf(sc->acpi_dev, "AcpiEnterSleepStatePrep failed - %s\n", + AcpiFormatException(status)); + goto backout; } slp_state = ACPI_SS_SLP_PREP; @@ -3620,31 +3436,70 @@ DELAY(sc->acpi_sleep_delay * 1000000); suspendclock(); - switch (stype) { - case STANDBY: - { - register_t intr = intr_disable(); - status = AcpiEnterSleepState(state); - intr_restore(intr); - AcpiLeaveSleepStatePrep(state); - if (ACPI_FAILURE(status)) - device_printf(sc->acpi_dev, "AcpiEnterSleepState failed - %s\n", - AcpiFormatException(status)); - slp_state = ACPI_SS_SLEPT; + intr = intr_disable(); + if (state != ACPI_STATE_S1) { + sleep_result = acpi_sleep_machdep(sc, state); + acpi_wakeup_machdep(sc, state, sleep_result, 0); + + /* + * XXX According to ACPI specification SCI_EN bit should be restored + * by ACPI platform (BIOS, firmware) to its pre-sleep state. + * Unfortunately some BIOSes fail to do that and that leads to + * unexpected and serious consequences during wake up like a system + * getting stuck in SMI handlers. + * This hack is picked up from Linux, which claims that it follows + * Windows behavior. + */ + if (sleep_result == 1 && state != ACPI_STATE_S4) + AcpiWriteBitRegister(ACPI_BITREG_SCI_ENABLE, ACPI_ENABLE_EVENT); + + if (sleep_result == 1 && state == ACPI_STATE_S3) { + /* + * Prevent mis-interpretation of the wakeup by power button + * as a request for power off. + * Ideally we should post an appropriate wakeup event, + * perhaps using acpi_event_power_button_wake or alike. + * + * Clearing of power button status after wakeup is mandated + * by ACPI specification in section "Fixed Power Button". + * + * XXX As of ACPICA 20121114 AcpiGetEventStatus provides + * status as 0/1 corressponding to inactive/active despite + * its type being ACPI_EVENT_STATUS. In other words, + * we should not test for ACPI_EVENT_FLAG_SET for time being. + */ + if (ACPI_SUCCESS(AcpiGetEventStatus(ACPI_EVENT_POWER_BUTTON, + &power_button_status)) && power_button_status != 0) { + AcpiClearEvent(ACPI_EVENT_POWER_BUTTON); + device_printf(sc->acpi_dev, + "cleared fixed power button status\n"); + } + } + + intr_restore(intr); + + /* call acpi_wakeup_machdep() again with interrupt enabled */ + acpi_wakeup_machdep(sc, state, sleep_result, 1); + + AcpiLeaveSleepStatePrep(state); + + if (sleep_result == -1) + goto backout; + + /* Re-enable ACPI hardware on wakeup from sleep state 4. */ + if (state == ACPI_STATE_S4) + AcpiEnable(); + } else { + status = AcpiEnterSleepState(state); + intr_restore(intr); + AcpiLeaveSleepStatePrep(state); + if (ACPI_FAILURE(status)) { + device_printf(sc->acpi_dev, "AcpiEnterSleepState failed - %s\n", + AcpiFormatException(status)); + goto backout; } - break; - case SUSPEND: - case HIBERNATE: - __do_sleep(sc, state, &slp_state); - break; - case SUSPEND_TO_IDLE: - __do_idle(sc); - break; - case AWAKE: - case POWEROFF: - default: - __unreachable(); } + slp_state = ACPI_SS_SLEPT; /* * Back out state according to how far along we got in the suspend @@ -3655,12 +3510,11 @@ resumeclock(); if (slp_state >= ACPI_SS_GPE_SET) { acpi_wake_prep_walk(state); - sc->acpi_sstate = AWAKE; + sc->acpi_sstate = ACPI_STATE_S0; } if (slp_state >= ACPI_SS_DEV_SUSPEND) DEVICE_RESUME(root_bus); - - if (stype != SUSPEND_TO_IDLE && (slp_state >= ACPI_SS_SLP_PREP)) + if (slp_state >= ACPI_SS_SLP_PREP) AcpiLeaveSleepState(state); if (slp_state >= ACPI_SS_SLEPT) { #if defined(__i386__) || defined(__amd64__) @@ -3670,14 +3524,21 @@ acpi_resync_clock(sc); acpi_enable_fixed_events(sc); } - sc->acpi_next_sstate = AWAKE; + sc->acpi_next_sstate = 0; bus_topo_unlock(); - // XXX s2idle +#ifdef EARLY_AP_STARTUP thread_lock(curthread); sched_unbind(curthread); thread_unlock(curthread); +#else + if (smp_started) { + thread_lock(curthread); + sched_unbind(curthread); + thread_unlock(curthread); + } +#endif resume_all_fs(); resume_all_proc(); @@ -3990,42 +3851,33 @@ /* System Event Handlers (registered by EVENTHANDLER_REGISTER) */ static void -acpi_system_eventhandler_sleep(void *arg, enum sleep_type type) +acpi_system_eventhandler_sleep(void *arg, int state) { struct acpi_softc *sc = (struct acpi_softc *)arg; int ret; - ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, type); + ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state); /* Check if button action is disabled or unknown. */ - if (type > SUSPEND_TO_IDLE) - return; - - if (!acpi_PowerTransitionIsEnabled()) + if (state == ACPI_STATE_UNKNOWN) return; /* Request that the system prepare to enter the given suspend state. */ - ret = acpi_ReqSleepState(sc, type); - if (ret != 0) { - char state[2] = { 0 }; - state[0] = type + '0'; + ret = acpi_ReqSleepState(sc, state); + if (ret != 0) device_printf(sc->acpi_dev, - "request to enter state S%s failed (err %d)\n", - type == SUSPEND_TO_IDLE ? "0IDLE" : state, - ret); - } + "request to enter state S%d failed (err %d)\n", state, ret); return_VOID; } static void -acpi_system_eventhandler_wakeup(void *arg, enum sleep_type type) +acpi_system_eventhandler_wakeup(void *arg, int state) { - ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, type); + ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state); /* Currently, nothing to do for wakeup. */ - MPASS(acpi_PowerTransitionIsEnabled()); return_VOID; } @@ -4060,7 +3912,7 @@ #if defined(__amd64__) || defined(__i386__) if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER, - acpi_invoke_sleep_eventhandler, &sc->acpi_power_button.sx))) + acpi_invoke_sleep_eventhandler, &sc->acpi_power_button_sx))) return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); #else shutdown_nice(RB_POWEROFF); @@ -4072,23 +3924,13 @@ UINT32 acpi_event_power_button_wake(void *context) { - ACPI_STATUS status; - ACPI_EVENT_STATUS power_button_status; struct acpi_softc *sc = (struct acpi_softc *)context; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); - status = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_invoke_wake_eventhandler, - &sc->acpi_power_button.sx); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER, + acpi_invoke_wake_eventhandler, &sc->acpi_power_button_sx))) return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); - - status = AcpiGetEventStatus(ACPI_EVENT_POWER_BUTTON, &power_button_status); - if (ACPI_SUCCESS(status) && power_button_status != 0) { - AcpiClearEvent(ACPI_EVENT_POWER_BUTTON); - device_printf(sc->acpi_dev, "cleared fixed power button status\n"); - } - return_VALUE (ACPI_INTERRUPT_HANDLED); } @@ -4100,7 +3942,7 @@ ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER, - acpi_invoke_sleep_eventhandler, &sc->acpi_sleep_button.sx))) + acpi_invoke_sleep_eventhandler, &sc->acpi_sleep_button_sx))) return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); return_VALUE (ACPI_INTERRUPT_HANDLED); } @@ -4113,7 +3955,7 @@ ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER, - acpi_invoke_wake_eventhandler, &sc->acpi_sleep_button.sx))) + acpi_invoke_wake_eventhandler, &sc->acpi_sleep_button_sx))) return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); return_VALUE (ACPI_INTERRUPT_HANDLED); } @@ -4341,7 +4183,7 @@ case ACPIIO_REQSLPSTATE: state = *(int *)addr; if (state != ACPI_STATE_S5) - return (acpi_ReqSleepState(sc, select_sleep_type(sc, state))); + return (acpi_ReqSleepState(sc, state)); device_printf(sc->acpi_dev, "power off via acpi ioctl not supported\n"); error = EOPNOTSUPP; break; @@ -4355,7 +4197,7 @@ return (EINVAL); if (!acpi_sleep_states[state]) return (EOPNOTSUPP); - if (ACPI_FAILURE(acpi_SetSleepState(sc, (enum sleep_type) state))) + if (ACPI_FAILURE(acpi_SetSleepState(sc, state))) error = ENXIO; break; default: @@ -4366,15 +4208,6 @@ return (error); } -static int -acpi_stype2sstate(enum sleep_type type) -{ - if (type == SUSPEND_TO_IDLE) - return ACPI_STATE_UNKNOWN; - - return (int)type; -} - static int acpi_sname2sstate(const char *sname) { @@ -4413,10 +4246,6 @@ for (state = ACPI_STATE_S1; state < ACPI_S_STATE_COUNT; state++) if (acpi_sleep_states[state]) sbuf_printf(&sb, "%s ", acpi_sstate2sname(state)); -#if defined(__i386__) || defined(__amd64__) - sbuf_printf(&sb, "S0IDLE "); -#endif - sbuf_trim(&sb); sbuf_finish(&sb); error = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); @@ -4424,87 +4253,9 @@ return (error); } -static int -update_state(struct sysctl_oid *oidp, int new_state, int old_state) -{ - if (new_state < ACPI_STATE_S1) - return (EINVAL); - if (new_state < ACPI_S_STATE_COUNT && !acpi_sleep_states[new_state]) - return (EOPNOTSUPP); - if (new_state != old_state) - *(int *)oidp->oid_arg1 = new_state; - - return (0); -} - static int acpi_sleep_state_sysctl(SYSCTL_HANDLER_ARGS) { -#if defined(__i386__) || defined(__amd64__) - struct acpi_softc *sc; - char sleep_state[10]; - int error, new_state, old_state; - int *sx, *saved_sx; - - old_state = *(int *)oidp->oid_arg1; - -#define SETUP_VARIABLES(event) do { \ - sc = __containerof(__containerof(arg1, __typeof(sc->acpi_##event), sx), \ - struct acpi_softc, acpi_##event); \ - MPASS(sc); \ - sx = &sc->acpi_##event.sx; \ - MPASS(sx); \ - saved_sx = &sc->acpi_##event.saved_sx; \ - MPASS(saved_sx); \ -} while (0) - - switch (arg2) { - case POWER_BUTTON_S2I: - SETUP_VARIABLES(power_button); - break; - case SLEEP_BUTTON_S2I: - SETUP_VARIABLES(sleep_button); - break; - case LID_SWITCH_S2I: - SETUP_VARIABLES(lid_switch); - break; - case STANDBY_S2I: - SETUP_VARIABLES(standby); - break; - case SUSPEND_S2I: - SETUP_VARIABLES(suspend); - break; - default: - __unreachable(); - }; -#undef SETUP_VARIABLES - - if (*sx == SUSPEND_TO_IDLE) - strlcpy(sleep_state, "S0IDLE", 7); - else - strlcpy(sleep_state, acpi_sstate2sname(old_state), sizeof(sleep_state)); - - error = sysctl_handle_string(oidp, sleep_state, sizeof(sleep_state), req); - if (error || req->newptr == NULL) - return (error); - - if (*sx == acpi_sname2sstate(sleep_state)) - return (0); - - /* When "enabling" s0idle, leave don't touch the default */ - if (!strncasecmp(sleep_state, "s0idle", 6) || - !strncasecmp(sleep_state, "s2idle", 6)) { - *saved_sx = *sx; - *sx = SUSPEND_TO_IDLE; - return (0); - } else { - new_state = acpi_sname2sstate(sleep_state); - error = update_state(oidp, new_state, old_state); - if (!error) - *saved_sx = *sx; - return (error); - } -#else char sleep_state[10]; int error, new_state, old_state; @@ -4513,10 +4264,14 @@ error = sysctl_handle_string(oidp, sleep_state, sizeof(sleep_state), req); if (error == 0 && req->newptr != NULL) { new_state = acpi_sname2sstate(sleep_state); - error = update_state(oidp, new_state, old_state); + if (new_state < ACPI_STATE_S1) + return (EINVAL); + if (new_state < ACPI_S_STATE_COUNT && !acpi_sleep_states[new_state]) + return (EOPNOTSUPP); + if (new_state != old_state) + *(int *)oidp->oid_arg1 = new_state; } return (error); -#endif } /* Inform devctl(4) when we receive a Notify. */ @@ -4887,13 +4642,12 @@ switch (state) { case POWER_SLEEP_STATE_STANDBY: - acpi_state = sc->acpi_standby.sx; + acpi_state = sc->acpi_standby_sx; break; case POWER_SLEEP_STATE_SUSPEND: - acpi_state = sc->acpi_suspend.sx; + acpi_state = sc->acpi_suspend_sx; break; case POWER_SLEEP_STATE_HIBERNATE: - /* FIXME: Needs support for s2idle */ acpi_state = ACPI_STATE_S4; break; default: Index: sys/dev/acpica/acpi_pci.c =================================================================== --- sys/dev/acpica/acpi_pci.c +++ sys/dev/acpica/acpi_pci.c @@ -93,6 +93,7 @@ int state); static void acpi_pci_update_device(ACPI_HANDLE handle, device_t pci_child); static bus_dma_tag_t acpi_pci_get_dma_tag(device_t bus, device_t child); +static int acpi_pci_get_domain(device_t dev, device_t child, int *domain); static device_method_t acpi_pci_methods[] = { /* Device interface */ @@ -108,7 +109,7 @@ DEVMETHOD(bus_get_device_path, acpi_pci_get_device_path), DEVMETHOD(bus_get_cpus, acpi_get_cpus), DEVMETHOD(bus_get_dma_tag, acpi_pci_get_dma_tag), - DEVMETHOD(bus_get_domain, acpi_get_domain_method), + DEVMETHOD(bus_get_domain, acpi_pci_get_domain), /* PCI interface */ DEVMETHOD(pci_alloc_devinfo, acpi_pci_alloc_devinfo), @@ -206,6 +207,31 @@ return (pci_get_device_path_method(bus, child, locator, sb)); } +/* + * Fetch the NUMA domain for the given device 'dev'. + * + * If a device has a _PXM method, map that to a NUMA domain. + * Otherwise, pass the request up to the parent. + * If there's no matching domain or the domain cannot be + * determined, return ENOENT. + */ +static int +acpi_pci_get_domain(device_t dev, device_t child, int *domain) +{ + int d; + + d = acpi_pxm_parse(child); + if (d >= 0) { + *domain = d; + return (0); + } + if (d == -1) + return (ENOENT); + + /* No _PXM node; go up a level */ + return (bus_generic_get_domain(dev, child, domain)); +} + /* * PCI power manangement */ Index: sys/dev/acpica/acpivar.h =================================================================== --- sys/dev/acpica/acpivar.h +++ sys/dev/acpica/acpivar.h @@ -633,7 +633,6 @@ */ int acpi_map_pxm_to_vm_domainid(int pxm); bus_get_cpus_t acpi_get_cpus; -bus_get_domain_t acpi_get_domain_method; #ifdef __aarch64__ /*