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 @@ -3309,14 +3309,53 @@ } enum acpi_sleep_state { - 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, + ACPI_SS_NONE = 0, + ACPI_SS_GPE_SET = 1 << 0, + ACPI_SS_DEV_SUSPEND = 1 << 1, + ACPI_SS_SPMC_ENTER = 1 << 2, + ACPI_SS_AMDSMU_ENTER = 1 << 3, + ACPI_SS_SLP_PREP = 1 << 4, + ACPI_SS_SLEPT = 1 << 5, }; +static int +acpi_amdsmu_get_device(struct acpi_softc *sc, device_t *dev) +{ + devclass_t amdsmu_dc = devclass_find("amdsmu"); + + MPASS(dev != NULL); + if (amdsmu_dc == NULL) { + device_printf(sc->acpi_dev, "amdsmu device class not found\n"); + return (ENXIO); + } + *dev = devclass_get_device(amdsmu_dc, 0); + if (*dev == NULL) { + device_printf(sc->acpi_dev, "no amdsmu device found\n"); + return (ENXIO); + } + return (0); +} + +static int +acpi_amdsmu_enter(struct acpi_softc *sc) +{ + device_t amdsmu; + + if (acpi_amdsmu_get_device(sc, &amdsmu) != 0) + return (ENXIO); + return (DEVICE_AMDSMU_ENTER_SLEEP(amdsmu)); +} + +static int +acpi_amdsmu_exit(struct acpi_softc *sc) +{ + device_t amdsmu; + + if (acpi_amdsmu_get_device(sc, &amdsmu) != 0) + return (ENXIO); + return (DEVICE_AMDSMU_EXIT_SLEEP(amdsmu)); +} + static void do_standby(struct acpi_softc *sc, enum acpi_sleep_state *slp_state, register_t rflags) @@ -3517,6 +3556,8 @@ else slp_state |= ACPI_SS_SPMC_ENTER; } + if (acpi_amdsmu_enter(sc) == 0) + slp_state |= ACPI_SS_AMDSMU_ENTER; if (stype != STYPE_SUSPEND_TO_IDLE) { status = AcpiEnterSleepStatePrep(stype); @@ -3570,6 +3611,10 @@ sc->acpi_stype = STYPE_AWAKE; slp_state &= ~ACPI_SS_GPE_SET; } + if (slp_state & ACPI_SS_AMDSMU_ENTER) { + acpi_amdsmu_exit(sc); + slp_state &= ~ACPI_SS_AMDSMU_ENTER; + } if (slp_state & ACPI_SS_SPMC_ENTER) { MPASS(sc->acpi_spmc_device != NULL); MPASS(sc->acpi_spmc_exit != NULL); diff --git a/sys/dev/amdsmu/amdsmu.c b/sys/dev/amdsmu/amdsmu.c --- a/sys/dev/amdsmu/amdsmu.c +++ b/sys/dev/amdsmu/amdsmu.c @@ -44,6 +44,7 @@ enum amdsmu_msg { SMU_MSG_GETSMUVERSION = 0x02, + SMU_MSG_SLEEP_HINT = 0x03, SMU_MSG_LOG_GETDRAM_ADDR_HI = 0x04, SMU_MSG_LOG_GETDRAM_ADDR_LO = 0x05, SMU_MSG_LOG_START = 0x06, @@ -470,6 +471,29 @@ 0, "Total time spent in software DRIPS (SW DRIPS) (us)"); } +static int +amdsmu_enter(device_t dev) +{ + + if (amdsmu_cmd(dev, SMU_MSG_SLEEP_HINT, true, NULL) != 0) { + device_printf(dev, "failed to hint to SMU to enter sleep"); + return (-1); + } + return (0); +} + +static int +amdsmu_exit(device_t dev) +{ + + if (amdsmu_cmd(dev, SMU_MSG_SLEEP_HINT, false, NULL) != 0) { + device_printf(dev, "failed to hint to SMU to exit sleep"); + return (-1); + } + amdsmu_dump_metrics(dev); + return (0); +} + static int amdsmu_attach(device_t dev) { @@ -550,6 +574,8 @@ DEVMETHOD(device_probe, amdsmu_probe), DEVMETHOD(device_attach, amdsmu_attach), DEVMETHOD(device_detach, amdsmu_detach), + DEVMETHOD(device_amdsmu_enter_sleep, amdsmu_enter), + DEVMETHOD(device_amdsmu_exit_sleep, amdsmu_exit), DEVMETHOD_END }; diff --git a/sys/kern/bus_if.m b/sys/kern/bus_if.m --- a/sys/kern/bus_if.m +++ b/sys/kern/bus_if.m @@ -31,7 +31,7 @@ /** * @defgroup BUS bus - KObj methods for drivers of devices with children - * @brief A set of methods required device drivers that support + * @brief A set of methods required for device drivers that support * child devices. * @{ */ diff --git a/sys/kern/device_if.m b/sys/kern/device_if.m --- a/sys/kern/device_if.m +++ b/sys/kern/device_if.m @@ -358,3 +358,34 @@ METHOD void * register { device_t dev; } DEFAULT null_register; + +/** + * @brief Hint to the AMD SMU that we intend to enter sleep. + * + * Must be called by the ACPI sleep routine during s2idle before actually + * idling the CPU but after calling the SPMC entry function, if one was set on + * the ACPI softc. + * + * @param dev the amdsmu device to hint entry to + * + * @retval 0 success + * @retval ETIMEDOUT timed out trying to send a message to the SMU + */ +METHOD int amdsmu_enter_sleep { + device_t dev; +}; + +/** + * @brief Hint to the AMD SMU that we are exiting sleep. + * + * Must be called by the ACPI sleep routine during s2idle after waking the CPU + * but before calling the SPMC exit function, if one was set on the ACPI softc. + * + * @param dev the amdsmu device to hint exit to + * + * @retval 0 success + * @retval ETIMEDOUT timed out trying to send a message to the SMU + */ +METHOD int amdsmu_exit_sleep { + device_t dev; +};