diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -58,6 +58,7 @@ #endif #include #include +#include #include #include #include @@ -106,7 +107,7 @@ int acpi_quirks; /* Supported sleep states. */ -static BOOLEAN acpi_sleep_states[ACPI_S_STATE_COUNT]; +static BOOLEAN acpi_supported_stypes[STYPE_COUNT]; static void acpi_lookup(void *arg, const char *name, device_t *dev); static int acpi_modevent(struct module *mod, int event, void *junk); @@ -157,19 +158,19 @@ 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, int state); +static ACPI_STATUS acpi_EnterSleepState(struct acpi_softc *sc, enum sleep_type stype); 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); -static int acpi_wake_sleep_prep(ACPI_HANDLE handle, int sstate); -static int acpi_wake_run_prep(ACPI_HANDLE handle, int sstate); -static int acpi_wake_prep_walk(int sstate); +static int acpi_wake_sleep_prep(ACPI_HANDLE handle, enum sleep_type stype); +static int acpi_wake_run_prep(ACPI_HANDLE handle, enum sleep_type stype); +static int acpi_wake_prep_walk(enum sleep_type stype); 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, 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 void acpi_system_eventhandler_sleep(void *arg, enum sleep_type stype); +static void acpi_system_eventhandler_wakeup(void *arg, enum sleep_type stype); +static enum sleep_type acpi_sname2stype(const char *sname); +static const char *acpi_stype2sname(enum sleep_type stype); static int acpi_supported_sleep_state_sysctl(SYSCTL_HANDLER_ARGS); static int acpi_sleep_state_sysctl(SYSCTL_HANDLER_ARGS); static int acpi_debug_objects_sysctl(SYSCTL_HANDLER_ARGS); @@ -567,26 +568,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, 0, acpi_sleep_state_sysctl, "A", + &sc->acpi_power_button_stype, 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, 0, acpi_sleep_state_sysctl, "A", + &sc->acpi_sleep_button_stype, 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, 0, acpi_sleep_state_sysctl, "A", + &sc->acpi_lid_switch_stype, 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, 0, acpi_sleep_state_sysctl, "A", ""); + &sc->acpi_standby_stype, 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, 0, acpi_sleep_state_sysctl, "A", ""); + &sc->acpi_suspend_stype, 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"); @@ -624,33 +625,51 @@ sc->acpi_s4bios = 1; #endif - /* Probe all supported sleep states. */ - acpi_sleep_states[ACPI_STATE_S0] = TRUE; - for (state = ACPI_STATE_S1; state < ACPI_S_STATE_COUNT; state++) + /* + * Probe all supported ACPI sleep states. Awake (S0) and suspend-to-idle + * are always supported. + */ + acpi_supported_stypes[STYPE_AWAKE] = TRUE; + acpi_supported_stypes[STYPE_SUSPEND_TO_IDLE] = TRUE; + for (state = ACPI_STATE_S1; state <= ACPI_STATE_S5; state++) if (ACPI_SUCCESS(AcpiEvaluateObject(ACPI_ROOT_OBJECT, __DECONST(char *, AcpiGbl_SleepStateNames[state]), NULL, NULL)) && ACPI_SUCCESS(AcpiGetSleepTypeData(state, &TypeA, &TypeB))) - acpi_sleep_states[state] = TRUE; + acpi_supported_stypes[state] = TRUE; /* * Dispatch the default sleep state to devices. The lid switch is set - * to UNKNOWN by default to avoid surprising users. + * to UNKNOWN by default to avoid surprising users. The suspend button + * prefers STANDBY (S3) over SUSPEND_TO_IDLE at the moment, as + * SUSPEND_TO_IDLE may not work as well at the moment. + */ + sc->acpi_power_button_stype = acpi_supported_stypes[STYPE_POWEROFF] ? + STYPE_POWEROFF : STYPE_UNKNOWN; + sc->acpi_lid_switch_stype = STYPE_UNKNOWN; + sc->acpi_standby_stype = acpi_supported_stypes[STYPE_STANDBY] ? + STYPE_STANDBY : STYPE_UNKNOWN; + sc->acpi_hibernate_stype = acpi_supported_stypes[STYPE_HIBERNATE] ? + STYPE_HIBERNATE : STYPE_UNKNOWN; + sc->acpi_suspend_stype = STYPE_UNKNOWN; + + if (acpi_supported_stypes[STYPE_SUSPEND]) + sc->acpi_suspend_stype = STYPE_SUSPEND; + else if (acpi_supported_stypes[STYPE_SUSPEND_TO_IDLE]) + sc->acpi_suspend_stype = STYPE_SUSPEND_TO_IDLE; + + /* + * Pick the first valid sleep state for the sleep button default. If that + * state was S4 and we support SUSPEND_TO_IDLE, set it to that. */ - 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] ? - ACPI_STATE_S1 : ACPI_STATE_UNKNOWN; - 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_stype = ACPI_STATE_UNKNOWN; for (state = ACPI_STATE_S1; state <= ACPI_STATE_S4; state++) - if (acpi_sleep_states[state]) { - sc->acpi_sleep_button_sx = state; + if (acpi_supported_stypes[state]) { + sc->acpi_sleep_button_stype = state; break; } + if (sc->acpi_sleep_button_stype == STYPE_HIBERNATE && + acpi_supported_stypes[STYPE_SUSPEND_TO_IDLE]) + sc->acpi_sleep_button_stype = STYPE_SUSPEND_TO_IDLE; acpi_enable_fixed_events(sc); @@ -673,7 +692,7 @@ /* Flag our initial states. */ sc->acpi_enabled = TRUE; - sc->acpi_sstate = ACPI_STATE_S0; + sc->acpi_stype = STYPE_AWAKE; sc->acpi_sleep_disabled = TRUE; /* Create the control device */ @@ -711,6 +730,26 @@ return_VALUE (error); } +static int +acpi_stype2sstate(enum sleep_type stype) +{ + + switch (stype) { + case STYPE_AWAKE: + case STYPE_STANDBY: + case STYPE_STANDBY_S2: + case STYPE_SUSPEND: + case STYPE_HIBERNATE: + case STYPE_POWEROFF: + return stype; + case STYPE_SUSPEND_TO_IDLE: + return ACPI_STATE_S3; + case STYPE_COUNT: + case STYPE_UNKNOWN: + return ACPI_STATE_UNKNOWN; + } +} + static void acpi_set_power_children(device_t dev, int state) { @@ -1977,7 +2016,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); + snprintf(sxd, sizeof(sxd), "_S%dD", acpi_stype2sstate(sc->acpi_stype)); 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, @@ -3071,9 +3110,9 @@ { struct acpi_softc *sc = (struct acpi_softc *)context; - if (ACPI_FAILURE(acpi_EnterSleepState(sc, sc->acpi_next_sstate))) + if (ACPI_FAILURE(acpi_EnterSleepState(sc, sc->acpi_next_stype))) device_printf(sc->acpi_dev, "force sleep state S%d failed\n", - sc->acpi_next_sstate); + sc->acpi_next_stype); } static void @@ -3100,24 +3139,23 @@ * acks are in. */ int -acpi_ReqSleepState(struct acpi_softc *sc, int state) +acpi_ReqSleepState(struct acpi_softc *sc, enum sleep_type stype) { #if defined(__amd64__) || defined(__i386__) struct apm_clone_data *clone; ACPI_STATUS status; - if (state < ACPI_STATE_S1 || state > ACPI_S_STATES_MAX) + if (stype < STYPE_AWAKE || stype >= STYPE_COUNT) return (EINVAL); - if (!acpi_sleep_states[state]) + if (!acpi_supported_stypes[stype]) 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 != 0 || suspend_blocked) { + if (rebooting || sc->acpi_next_stype != STYPE_AWAKE || suspend_blocked) return (0); - } /* Wait until sleep is enabled. */ while (sc->acpi_sleep_disabled) { @@ -3126,12 +3164,12 @@ ACPI_LOCK(acpi); - sc->acpi_next_sstate = state; + sc->acpi_next_stype = stype; /* S5 (soft-off) should be entered directly with no waiting. */ - if (state == ACPI_STATE_S5) { + if (stype == STYPE_POWEROFF) { ACPI_UNLOCK(acpi); - status = acpi_EnterSleepState(sc, state); + status = acpi_EnterSleepState(sc, stype); return (ACPI_SUCCESS(status) ? 0 : ENXIO); } @@ -3147,7 +3185,7 @@ /* If devd(8) is not running, immediately enter the sleep state. */ if (!devctl_process_running()) { ACPI_UNLOCK(acpi); - status = acpi_EnterSleepState(sc, state); + status = acpi_EnterSleepState(sc, stype); return (ACPI_SUCCESS(status) ? 0 : ENXIO); } @@ -3162,11 +3200,12 @@ ACPI_UNLOCK(acpi); /* Now notify devd(8) also. */ - acpi_UserNotify("Suspend", ACPI_ROOT_OBJECT, state); + acpi_UserNotify("Suspend", ACPI_ROOT_OBJECT, stype); return (0); #else - /* This platform does not support acpi suspend/resume. */ + device_printf(sc->acpi_dev, "ACPI suspend not supported on this platform" + "(TODO suspend to idle should be, however)\n"); return (EOPNOTSUPP); #endif } @@ -3185,17 +3224,17 @@ struct acpi_softc *sc; int ret, sleeping; - /* If no pending sleep state, return an error. */ + /* If no pending sleep type, return an error. */ ACPI_LOCK(acpi); sc = clone->acpi_sc; - if (sc->acpi_next_sstate == 0) { + if (sc->acpi_next_stype == STYPE_AWAKE) { ACPI_UNLOCK(acpi); return (ENXIO); } /* Caller wants to abort suspend process. */ if (error) { - sc->acpi_next_sstate = 0; + sc->acpi_next_stype = STYPE_AWAKE; callout_stop(&sc->susp_force_to); device_printf(sc->acpi_dev, "listener on %s cancelled the pending suspend\n", @@ -3225,12 +3264,13 @@ ACPI_UNLOCK(acpi); ret = 0; if (sleeping) { - if (ACPI_FAILURE(acpi_EnterSleepState(sc, sc->acpi_next_sstate))) + if (ACPI_FAILURE(acpi_EnterSleepState(sc, sc->acpi_next_stype))) ret = ENODEV; } return (ret); #else - /* This platform does not support acpi suspend/resume. */ + device_printf(sc->acpi_dev, "ACPI suspend not supported on this platform" + "(TODO suspend to idle should be, however)\n"); return (EOPNOTSUPP); #endif } @@ -3269,34 +3309,141 @@ } enum acpi_sleep_state { - ACPI_SS_NONE, - ACPI_SS_GPE_SET, - ACPI_SS_DEV_SUSPEND, - ACPI_SS_SLP_PREP, - ACPI_SS_SLEPT, + ACPI_SS_NONE = 0, + ACPI_SS_GPE_SET = 1 << 0, + ACPI_SS_DEV_SUSPEND = 1 << 1, + ACPI_SS_SPMC_ENTER = 1 << 2, + ACPI_SS_SLP_PREP = 1 << 3, + ACPI_SS_SLEPT = 1 << 4, }; +static void +do_standby(struct acpi_softc *sc, enum acpi_sleep_state *slp_state, + register_t rflags) +{ + ACPI_STATUS status; + + status = AcpiEnterSleepState(STYPE_STANDBY); + intr_restore(rflags); + AcpiLeaveSleepStatePrep(STYPE_STANDBY); + if (ACPI_FAILURE(status)) { + device_printf(sc->acpi_dev, "AcpiEnterSleepState failed - %s\n", + AcpiFormatException(status)); + return; + } + *slp_state |= ACPI_SS_SLEPT; +} + +static void +do_sleep(struct acpi_softc *sc, enum acpi_sleep_state *slp_state, + register_t rflags, int state) +{ + int sleep_result; + ACPI_EVENT_STATUS power_button_status; + + MPASS(state == ACPI_STATE_S3 || state == ACPI_STATE_S4); + + sleep_result = acpi_sleep_machdep(sc, state); + acpi_wakeup_machdep(sc, state, sleep_result, 0); + + if (sleep_result == 1 && state != ACPI_STATE_S4) { + /* + * 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); + } + + if (sleep_result == 1 && state == ACPI_STATE_S3) { + /* + * Prevent misinterpretation 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 corresponding 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(rflags); + + /* 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(); + *slp_state |= ACPI_SS_SLEPT; +} + +static void +do_idle(struct acpi_softc *sc, enum acpi_sleep_state *slp_state, + register_t rflags) +{ + + intr_suspend(); + + /* + * The CPU will exit idle when interrupted, so we want to minimize the + * number of interrupts it can receive while idle. We do this by only + * allowing SCI (system control interrupt) interrupts, which are used by + * the ACPI firmware to send wake GPEs to the OS. + * + * XXX We might still receive other spurious non-wake GPEs from noisy + * devices that can't be disabled, so this will need to end up being a + * suspend-to-idle loop which, when breaking out of idle, will check the + * reason for the wakeup and immediately idle the CPU again if it was not a + * proper wake event. + */ + intr_enable_src(AcpiGbl_FADT.SciInterrupt); + + cpu_idle(0); + + intr_resume(false); + intr_restore(rflags); + *slp_state |= ACPI_SS_SLEPT; +} + /* * Enter the desired system sleep state. * - * Currently we support S1-S5 but S4 is only S4BIOS + * Currently we support S1-S5 and suspend-to-idle, but S4 is only S4BIOS. */ static ACPI_STATUS -acpi_EnterSleepState(struct acpi_softc *sc, int state) +acpi_EnterSleepState(struct acpi_softc *sc, enum sleep_type stype) { - register_t intr; + register_t rflags; ACPI_STATUS status; - ACPI_EVENT_STATUS power_button_status; enum acpi_sleep_state slp_state; - int sleep_result; ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state); - if (state < ACPI_STATE_S1 || state > ACPI_S_STATES_MAX) + if (stype <= STYPE_AWAKE || stype >= STYPE_COUNT) 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); + if (!acpi_supported_stypes[stype]) { + device_printf(sc->acpi_dev, "Sleep type %s not supported on this " + "platform\n", acpi_stype2sname(stype)); return (AE_SUPPORT); } @@ -3308,7 +3455,7 @@ return (status); } - if (state == ACPI_STATE_S5) { + if (stype == STYPE_POWEROFF) { /* * Shut down cleanly and power off. This will call us back through the * shutdown handlers. @@ -3336,17 +3483,17 @@ #endif /* - * Be sure to hold Giant across DEVICE_SUSPEND/RESUME + * Be sure to hold bus topology lock across DEVICE_SUSPEND/RESUME. */ bus_topo_lock(); slp_state = ACPI_SS_NONE; - sc->acpi_sstate = state; + sc->acpi_stype = stype; /* Enable any GPEs as appropriate and requested by the user. */ - acpi_wake_prep_walk(state); - slp_state = ACPI_SS_GPE_SET; + acpi_wake_prep_walk(stype); + slp_state |= ACPI_SS_GPE_SET; /* * Inform all devices that we are going to sleep. If at least one @@ -3357,112 +3504,99 @@ * bus interface does not provide for this. */ if (DEVICE_SUSPEND(root_bus) != 0) { - device_printf(sc->acpi_dev, "device_suspend failed\n"); - goto backout; + device_printf(sc->acpi_dev, "device_suspend failed\n"); + goto backout; } - slp_state = ACPI_SS_DEV_SUSPEND; + slp_state |= ACPI_SS_DEV_SUSPEND; + AcpiOsSleep(1000); - status = AcpiEnterSleepStatePrep(state); - if (ACPI_FAILURE(status)) { - device_printf(sc->acpi_dev, "AcpiEnterSleepStatePrep failed - %s\n", - AcpiFormatException(status)); - goto backout; + if (sc->acpi_spmc_device != NULL) { + MPASS(sc->acpi_spmc_enter != NULL); + if (sc->acpi_spmc_enter(sc->acpi_spmc_device) != 0) + device_printf(sc->acpi_dev, "failed to run SPMC entry\n"); + else + slp_state |= ACPI_SS_SPMC_ENTER; } - slp_state = ACPI_SS_SLP_PREP; + + if (stype != STYPE_SUSPEND_TO_IDLE) { + status = AcpiEnterSleepStatePrep(stype); + if (ACPI_FAILURE(status)) { + device_printf(sc->acpi_dev, "AcpiEnterSleepStatePrep failed - %s\n", + AcpiFormatException(status)); + goto backout; + } + } + slp_state |= ACPI_SS_SLP_PREP; if (sc->acpi_sleep_delay > 0) DELAY(sc->acpi_sleep_delay * 1000000); suspendclock(); - intr = intr_disable(); - if (state != ACPI_STATE_S1) { - sleep_result = acpi_sleep_machdep(sc, state); - acpi_wakeup_machdep(sc, state, sleep_result, 0); - + rflags = intr_disable(); + switch (stype) { + case STYPE_STANDBY: + case STYPE_STANDBY_S2: + do_standby(sc, &slp_state, rflags); + break; + case STYPE_SUSPEND: + case STYPE_HIBERNATE: /* - * 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. + * Can pass suspend/hibernate enum sleep_type, as they are directly + * mapped to ACPI S-states. */ - 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; - } + do_sleep(sc, &slp_state, rflags, stype); + break; + case STYPE_SUSPEND_TO_IDLE: + do_idle(sc, &slp_state, rflags); + break; + case STYPE_AWAKE: + case STYPE_POWEROFF: + case STYPE_COUNT: + case STYPE_UNKNOWN: + __unreachable(); } - slp_state = ACPI_SS_SLEPT; /* * Back out state according to how far along we got in the suspend * process. This handles both the error and success cases. */ backout: - if (slp_state >= ACPI_SS_SLP_PREP) + if (slp_state & ACPI_SS_SLP_PREP) { resumeclock(); - if (slp_state >= ACPI_SS_GPE_SET) { - acpi_wake_prep_walk(state); - sc->acpi_sstate = ACPI_STATE_S0; + slp_state &= ~ACPI_SS_SLP_PREP; + } + if (slp_state & ACPI_SS_GPE_SET) { + acpi_wake_prep_walk(stype); + sc->acpi_stype = STYPE_AWAKE; + slp_state &= ~ACPI_SS_GPE_SET; } - if (slp_state >= ACPI_SS_DEV_SUSPEND) + if (slp_state & ACPI_SS_SPMC_ENTER) { + MPASS(sc->acpi_spmc_device != NULL); + MPASS(sc->acpi_spmc_exit != NULL); + if (sc->acpi_spmc_exit(sc->acpi_spmc_device) != 0) + device_printf(sc->acpi_dev, "failed to run SPMC exit\n"); + slp_state &= ~ACPI_SS_SPMC_ENTER; + } + if (slp_state & ACPI_SS_DEV_SUSPEND) { DEVICE_RESUME(root_bus); - if (slp_state >= ACPI_SS_SLP_PREP) - AcpiLeaveSleepState(state); - if (slp_state >= ACPI_SS_SLEPT) { + slp_state &= ~ACPI_SS_DEV_SUSPEND; + } + if (stype != STYPE_SUSPEND_TO_IDLE && slp_state & ACPI_SS_SLP_PREP) { + AcpiLeaveSleepState(stype); + slp_state &= ~ACPI_SS_SLP_PREP; + } + if (slp_state & ACPI_SS_SLEPT) { #if defined(__i386__) || defined(__amd64__) /* NB: we are still using ACPI timecounter at this point. */ resume_TSC(); #endif acpi_resync_clock(sc); acpi_enable_fixed_events(sc); + slp_state &= ~ACPI_SS_SLEPT; } - sc->acpi_next_sstate = 0; + sc->acpi_next_stype = STYPE_AWAKE; + + MPASS(slp_state == ACPI_SS_NONE); bus_topo_unlock(); @@ -3488,7 +3622,7 @@ /* Run /etc/rc.resume after we are back. */ if (devctl_process_running()) - acpi_UserNotify("Resume", ACPI_ROOT_OBJECT, state); + acpi_UserNotify("Resume", ACPI_ROOT_OBJECT, stype); return_ACPI_STATUS (status); } @@ -3539,8 +3673,9 @@ } static int -acpi_wake_sleep_prep(ACPI_HANDLE handle, int sstate) +acpi_wake_sleep_prep(ACPI_HANDLE handle, enum sleep_type stype) { + int sstate = acpi_stype2sstate(stype); struct acpi_prw_data prw; device_t dev; @@ -3559,22 +3694,23 @@ if (sstate > prw.lowest_wake) { AcpiSetGpeWakeMask(prw.gpe_handle, prw.gpe_bit, ACPI_GPE_DISABLE); if (bootverbose) - device_printf(dev, "wake_prep disabled wake for %s (S%d)\n", - acpi_name(handle), sstate); + device_printf(dev, "wake_prep disabled wake for %s (%s)\n", + acpi_name(handle), acpi_stype2sname(stype)); } else if (dev && (acpi_get_flags(dev) & ACPI_FLAG_WAKE_ENABLED) != 0) { acpi_pwr_wake_enable(handle, 1); acpi_SetInteger(handle, "_PSW", 1); if (bootverbose) - device_printf(dev, "wake_prep enabled for %s (S%d)\n", - acpi_name(handle), sstate); + device_printf(dev, "wake_prep enabled for %s (%s)\n", + acpi_name(handle), acpi_stype2sname(stype)); } return (0); } static int -acpi_wake_run_prep(ACPI_HANDLE handle, int sstate) +acpi_wake_run_prep(ACPI_HANDLE handle, enum sleep_type stype) { + int sstate = acpi_stype2sstate(stype); struct acpi_prw_data prw; device_t dev; @@ -3611,26 +3747,26 @@ static ACPI_STATUS acpi_wake_prep(ACPI_HANDLE handle, UINT32 level, void *context, void **status) { - int sstate; + enum sleep_type stype; /* If suspending, run the sleep prep function, otherwise wake. */ - sstate = *(int *)context; + stype = *(enum sleep_type *)context; if (AcpiGbl_SystemAwakeAndRunning) - acpi_wake_sleep_prep(handle, sstate); + acpi_wake_sleep_prep(handle, stype); else - acpi_wake_run_prep(handle, sstate); + acpi_wake_run_prep(handle, stype); return (AE_OK); } /* Walk the tree rooted at acpi0 to prep devices for suspend/resume. */ static int -acpi_wake_prep_walk(int sstate) +acpi_wake_prep_walk(enum sleep_type stype) { ACPI_HANDLE sb_handle; if (ACPI_SUCCESS(AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &sb_handle))) AcpiWalkNamespace(ACPI_TYPE_DEVICE, sb_handle, 100, - acpi_wake_prep, NULL, &sstate, NULL); + acpi_wake_prep, NULL, &stype, NULL); return (0); } @@ -3789,7 +3925,7 @@ /* System Event Handlers (registered by EVENTHANDLER_REGISTER) */ static void -acpi_system_eventhandler_sleep(void *arg, int state) +acpi_system_eventhandler_sleep(void *arg, enum sleep_type stype) { struct acpi_softc *sc = (struct acpi_softc *)arg; int ret; @@ -3797,23 +3933,27 @@ ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state); /* Check if button action is disabled or unknown. */ - if (state == ACPI_STATE_UNKNOWN) + if (stype == ACPI_STATE_UNKNOWN) return; - /* Request that the system prepare to enter the given suspend state. */ - ret = acpi_ReqSleepState(sc, state); + /* + * Request that the system prepare to enter the given suspend state. We can + * totally pass an ACPI S-state to an enum sleep_type. + */ + ret = acpi_ReqSleepState(sc, stype); if (ret != 0) device_printf(sc->acpi_dev, - "request to enter state S%d failed (err %d)\n", state, ret); + "request to enter state %s failed (err %d)\n", + acpi_stype2sname(stype), ret); return_VOID; } static void -acpi_system_eventhandler_wakeup(void *arg, int state) +acpi_system_eventhandler_wakeup(void *arg, enum sleep_type stype) { - ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state); + ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, stype); /* Currently, nothing to do for wakeup. */ @@ -3827,14 +3967,14 @@ acpi_invoke_sleep_eventhandler(void *context) { - EVENTHANDLER_INVOKE(acpi_sleep_event, *(int *)context); + EVENTHANDLER_INVOKE(acpi_sleep_event, *(enum sleep_type *)context); } static void acpi_invoke_wake_eventhandler(void *context) { - EVENTHANDLER_INVOKE(acpi_wakeup_event, *(int *)context); + EVENTHANDLER_INVOKE(acpi_wakeup_event, *(enum sleep_type *)context); } UINT32 @@ -3845,7 +3985,7 @@ ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER, - acpi_invoke_sleep_eventhandler, &sc->acpi_power_button_sx))) + acpi_invoke_sleep_eventhandler, &sc->acpi_power_button_stype))) return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); return_VALUE (ACPI_INTERRUPT_HANDLED); } @@ -3858,7 +3998,7 @@ ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER, - acpi_invoke_wake_eventhandler, &sc->acpi_power_button_sx))) + acpi_invoke_wake_eventhandler, &sc->acpi_power_button_stype))) return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); return_VALUE (ACPI_INTERRUPT_HANDLED); } @@ -3871,7 +4011,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_stype))) return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); return_VALUE (ACPI_INTERRUPT_HANDLED); } @@ -3884,7 +4024,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_stype))) return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); return_VALUE (ACPI_INTERRUPT_HANDLED); } @@ -4080,7 +4220,8 @@ { struct acpi_softc *sc; struct acpi_ioctl_hook *hp; - int error, state; + int error; + enum sleep_type stype; error = 0; hp = NULL; @@ -4110,9 +4251,9 @@ /* Core system ioctls. */ switch (cmd) { case ACPIIO_REQSLPSTATE: - state = *(int *)addr; - if (state != ACPI_STATE_S5) - return (acpi_ReqSleepState(sc, state)); + stype = *(int *)addr; + if (stype != STYPE_POWEROFF) + return (acpi_ReqSleepState(sc, stype)); device_printf(sc->acpi_dev, "power off via acpi ioctl not supported\n"); error = EOPNOTSUPP; break; @@ -4121,12 +4262,12 @@ error = acpi_AckSleepState(sc->acpi_clone, error); break; case ACPIIO_SETSLPSTATE: /* DEPRECATED */ - state = *(int *)addr; - if (state < ACPI_STATE_S0 || state > ACPI_S_STATES_MAX) + stype = *(int *)addr; + if (stype < STYPE_AWAKE || stype > STYPE_COUNT) return (EINVAL); - if (!acpi_sleep_states[state]) + if (!acpi_supported_stypes[stype]) return (EOPNOTSUPP); - if (ACPI_FAILURE(acpi_SetSleepState(sc, state))) + if (ACPI_FAILURE(acpi_SetSleepState(sc, stype))) error = ENXIO; break; default: @@ -4137,31 +4278,35 @@ return (error); } -static int -acpi_sname2sstate(const char *sname) +static enum sleep_type +acpi_sname2stype(const char *sname) { - int sstate; + enum sleep_type stype; - if (toupper(sname[0]) == 'S') { - sstate = sname[1] - '0'; - if (sstate >= ACPI_STATE_S0 && sstate <= ACPI_STATE_S5 && - sname[2] == '\0') - return (sstate); - } else if (strcasecmp(sname, "NONE") == 0) - return (ACPI_STATE_UNKNOWN); + if (strcasecmp(sname, "NONE") == 0) + return (STYPE_UNKNOWN); + if (strcasecmp(sname, "S0i") == 0) + return (STYPE_SUSPEND_TO_IDLE); + if (toupper(sname[0]) != 'S') + return (-1); + + /* Is regular ACPI S-state. */ + stype = sname[1] - '0'; + if (stype >= ACPI_STATE_S0 && stype <= ACPI_STATE_S5 && + sname[2] == '\0') + return (stype); return (-1); } static const char * -acpi_sstate2sname(int sstate) +acpi_stype2sname(enum sleep_type stype) { - static const char *snames[] = { "S0", "S1", "S2", "S3", "S4", "S5" }; + static const char *snames[STYPE_COUNT] = {"S0", "S1", "S2", "S3", "S4", + "S5", "S0i"}; - if (sstate >= ACPI_STATE_S0 && sstate <= ACPI_STATE_S5) - return (snames[sstate]); - else if (sstate == ACPI_STATE_UNKNOWN) - return ("NONE"); - return (NULL); + if (stype >= STYPE_AWAKE && stype < STYPE_COUNT) + return (snames[stype]); + return ("NONE"); } static int @@ -4169,12 +4314,12 @@ { int error; struct sbuf sb; - UINT8 state; + enum sleep_type stype; sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND); - for (state = ACPI_STATE_S1; state < ACPI_S_STATE_COUNT; state++) - if (acpi_sleep_states[state]) - sbuf_printf(&sb, "%s ", acpi_sstate2sname(state)); + for (stype = STYPE_STANDBY; stype < STYPE_COUNT; stype++) + if (acpi_supported_stypes[stype]) + sbuf_printf(&sb, "%s ", acpi_stype2sname(stype)); sbuf_trim(&sb); sbuf_finish(&sb); error = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); @@ -4185,20 +4330,21 @@ static int acpi_sleep_state_sysctl(SYSCTL_HANDLER_ARGS) { - char sleep_state[10]; - int error, new_state, old_state; + char sleep_type[10]; + int error; + enum sleep_type new_stype, old_stype; - old_state = *(int *)oidp->oid_arg1; - strlcpy(sleep_state, acpi_sstate2sname(old_state), sizeof(sleep_state)); - error = sysctl_handle_string(oidp, sleep_state, sizeof(sleep_state), req); + old_stype = *(enum sleep_type *)oidp->oid_arg1; + strlcpy(sleep_type, acpi_stype2sname(old_stype), sizeof(sleep_type)); + error = sysctl_handle_string(oidp, sleep_type, sizeof(sleep_type), req); if (error == 0 && req->newptr != NULL) { - new_state = acpi_sname2sstate(sleep_state); - if (new_state < ACPI_STATE_S1) + new_stype = acpi_sname2stype(sleep_type); + if (new_stype <= STYPE_AWAKE) return (EINVAL); - if (new_state < ACPI_S_STATE_COUNT && !acpi_sleep_states[new_state]) + if (new_stype < STYPE_COUNT && !acpi_supported_stypes[new_stype]) return (EOPNOTSUPP); - if (new_state != old_state) - *(int *)oidp->oid_arg1 = new_state; + if (new_stype != old_stype) + *(int *)oidp->oid_arg1 = new_stype; } return (error); } @@ -4552,10 +4698,11 @@ static int acpi_pm_func(u_long cmd, void *arg, ...) { - int state, acpi_state; - int error; - struct acpi_softc *sc; - va_list ap; + int power_sstate; + enum sleep_type acpi_stype; + int error; + struct acpi_softc *sc; + va_list ap; error = 0; switch (cmd) { @@ -4567,25 +4714,25 @@ } va_start(ap, arg); - state = va_arg(ap, int); + power_sstate = va_arg(ap, enum sleep_type); va_end(ap); - switch (state) { + switch (power_sstate) { case POWER_SLEEP_STATE_STANDBY: - acpi_state = sc->acpi_standby_sx; + acpi_stype = sc->acpi_standby_stype; break; case POWER_SLEEP_STATE_SUSPEND: - acpi_state = sc->acpi_suspend_sx; + acpi_stype = sc->acpi_suspend_stype; break; case POWER_SLEEP_STATE_HIBERNATE: - acpi_state = ACPI_STATE_S4; + acpi_stype = sc->acpi_hibernate_stype; break; default: error = EINVAL; goto out; } - if (ACPI_FAILURE(acpi_EnterSleepState(sc, acpi_state))) + if (ACPI_FAILURE(acpi_EnterSleepState(sc, acpi_stype))) error = ENXIO; break; default: diff --git a/sys/dev/acpica/acpi_lid.c b/sys/dev/acpica/acpi_lid.c --- a/sys/dev/acpica/acpi_lid.c +++ b/sys/dev/acpica/acpi_lid.c @@ -235,9 +235,9 @@ sc->lid_status ? "opened" : "closed"); if (sc->lid_status == 0) - EVENTHANDLER_INVOKE(acpi_sleep_event, acpi_sc->acpi_lid_switch_sx); + EVENTHANDLER_INVOKE(acpi_sleep_event, acpi_sc->acpi_lid_switch_stype); else - EVENTHANDLER_INVOKE(acpi_wakeup_event, acpi_sc->acpi_lid_switch_sx); + EVENTHANDLER_INVOKE(acpi_wakeup_event, acpi_sc->acpi_lid_switch_stype); out: ACPI_SERIAL_END(lid); diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h --- a/sys/dev/acpica/acpivar.h +++ b/sys/dev/acpica/acpivar.h @@ -47,23 +47,43 @@ #include #include +enum sleep_type { + /* + * Map these with ACPI S-states the best we can. We want to be able to + * assign an S-state to an enum sleep_type. The other way round is + * impossible though, as we support additional non-S-state sleep types. + */ + STYPE_AWAKE = ACPI_STATE_S0, + STYPE_STANDBY = ACPI_STATE_S1, + STYPE_STANDBY_S2 = ACPI_STATE_S2, + STYPE_SUSPEND = ACPI_STATE_S3, + STYPE_HIBERNATE = ACPI_STATE_S4, + STYPE_POWEROFF = ACPI_STATE_S5, + STYPE_SUSPEND_TO_IDLE, + STYPE_COUNT, + STYPE_UNKNOWN = ACPI_STATE_UNKNOWN, +}; + +CTASSERT(STYPE_COUNT == 7); + struct apm_clone_data; struct acpi_softc { device_t acpi_dev; struct cdev *acpi_dev_t; int acpi_enabled; - int acpi_sstate; + enum sleep_type acpi_stype; int acpi_sleep_disabled; struct sysctl_ctx_list acpi_sysctl_ctx; struct sysctl_oid *acpi_sysctl_tree; - int acpi_power_button_sx; - int acpi_sleep_button_sx; - int acpi_lid_switch_sx; + enum sleep_type acpi_power_button_stype; + enum sleep_type acpi_sleep_button_stype; + enum sleep_type acpi_lid_switch_stype; - int acpi_standby_sx; - int acpi_suspend_sx; + enum sleep_type acpi_standby_stype; + enum sleep_type acpi_suspend_stype; + enum sleep_type acpi_hibernate_stype; int acpi_sleep_delay; int acpi_s4bios; @@ -78,7 +98,7 @@ vm_offset_t acpi_wakeaddr; vm_paddr_t acpi_wakephys; - int acpi_next_sstate; /* Next suspend Sx state. */ + enum sleep_type acpi_next_stype; /* Next suspend sleep type. */ struct apm_clone_data *acpi_clone; /* Pseudo-dev for devd(8). */ STAILQ_HEAD(,apm_clone_data) apm_cdevs; /* All apm/apmctl/acpi cdevs. */ struct callout susp_force_to; /* Force suspend if no acks. */ @@ -383,7 +403,7 @@ uint32_t *caps_out, bool query); ACPI_STATUS acpi_OverrideInterruptLevel(UINT32 InterruptNumber); ACPI_STATUS acpi_SetIntrModel(int model); -int acpi_ReqSleepState(struct acpi_softc *sc, int state); +int acpi_ReqSleepState(struct acpi_softc *sc, enum sleep_type stype); int acpi_AckSleepState(struct apm_clone_data *clone, int error); ACPI_STATUS acpi_SetSleepState(struct acpi_softc *sc, int state); int acpi_wake_set_enable(device_t dev, int enable); diff --git a/sys/x86/acpica/acpi_apm.c b/sys/x86/acpica/acpi_apm.c --- a/sys/x86/acpica/acpi_apm.c +++ b/sys/x86/acpica/acpi_apm.c @@ -236,7 +236,7 @@ acpi_sc = clone->acpi_sc; /* We are about to lose a reference so check if suspend should occur */ - if (acpi_sc->acpi_next_sstate != 0 && + if (acpi_sc->acpi_next_stype != STYPE_AWAKE && clone->notify_status != APM_EV_ACKED) acpi_AckSleepState(clone, 0); @@ -284,10 +284,10 @@ case APMIO_SUSPEND: if ((flag & FWRITE) == 0) return (EPERM); - if (acpi_sc->acpi_next_sstate == 0) { - if (acpi_sc->acpi_suspend_sx != ACPI_STATE_S5) { + if (acpi_sc->acpi_next_stype == STYPE_AWAKE) { + if (acpi_sc->acpi_suspend_stype != STYPE_POWEROFF) { error = acpi_ReqSleepState(acpi_sc, - acpi_sc->acpi_suspend_sx); + acpi_sc->acpi_suspend_stype); } else { printf( "power off via apm suspend not supported\n"); @@ -299,10 +299,10 @@ case APMIO_STANDBY: if ((flag & FWRITE) == 0) return (EPERM); - if (acpi_sc->acpi_next_sstate == 0) { - if (acpi_sc->acpi_standby_sx != ACPI_STATE_S5) { + if (acpi_sc->acpi_next_stype == STYPE_AWAKE) { + if (acpi_sc->acpi_standby_stype != STYPE_POWEROFF) { error = acpi_ReqSleepState(acpi_sc, - acpi_sc->acpi_standby_sx); + acpi_sc->acpi_standby_stype); } else { printf( "power off via apm standby not supported\n"); @@ -314,10 +314,10 @@ case APMIO_NEXTEVENT: printf("apm nextevent start\n"); ACPI_LOCK(acpi); - if (acpi_sc->acpi_next_sstate != 0 && clone->notify_status == - APM_EV_NONE) { + if (acpi_sc->acpi_next_stype != STYPE_AWAKE && + clone->notify_status == APM_EV_NONE) { ev_info = (struct apm_event_info *)addr; - if (acpi_sc->acpi_next_sstate <= ACPI_STATE_S3) + if (acpi_sc->acpi_next_stype <= STYPE_SUSPEND) ev_info->type = PMEV_STANDBYREQ; else ev_info->type = PMEV_SUSPENDREQ; @@ -393,7 +393,7 @@ revents = 0; devfs_get_cdevpriv((void **)&clone); ACPI_LOCK(acpi); - if (clone->acpi_sc->acpi_next_sstate) + if (clone->acpi_sc->acpi_next_stype != STYPE_AWAKE) revents |= events & (POLLIN | POLLRDNORM); else selrecord(td, &clone->sel_read); @@ -434,7 +434,7 @@ ACPI_LOCK(acpi); clone = kn->kn_hook; - sleeping = clone->acpi_sc->acpi_next_sstate ? 1 : 0; + sleeping = clone->acpi_sc->acpi_next_stype != STYPE_AWAKE; ACPI_UNLOCK(acpi); return (sleeping); } diff --git a/sys/x86/include/intr_machdep.h b/sys/x86/include/intr_machdep.h --- a/sys/x86/include/intr_machdep.h +++ b/sys/x86/include/intr_machdep.h @@ -152,6 +152,7 @@ int intr_remove_handler(void *cookie); void intr_resume(bool suspend_cancelled); void intr_suspend(void); +void intr_enable_src(u_int irq); void intr_reprogram(void); void intrcnt_add(const char *name, u_long **countp); void nexus_add_irq(u_long irq); diff --git a/sys/x86/x86/intr_machdep.c b/sys/x86/x86/intr_machdep.c --- a/sys/x86/x86/intr_machdep.c +++ b/sys/x86/x86/intr_machdep.c @@ -392,6 +392,15 @@ mtx_unlock(&intrpic_lock); } +void +intr_enable_src(u_int irq) +{ + struct intsrc *is; + + is = interrupt_sources[irq]; + is->is_pic->pic_enable_source(is); +} + static int intr_assign_cpu(void *arg, int cpu) {