nvme: Add APST payload overriding

The apst_data tunable allows APST configuration to be adjusted
during controller initialization.  It accepts an array of encoded
integers, each defining specific transition parameters.

Relnotes: YES
Signed-off-by: Alexey Sukhoguzov <sap@eseipi.net>
Reviewed by: imp
Pull Request: https://github.com/freebsd/freebsd-src/pull/1444
This commit is contained in:
Alexey Sukhoguzov 2024-10-30 12:04:49 +01:00 committed by Warner Losh
parent a24932dcec
commit f0d44ee06b
2 changed files with 26 additions and 8 deletions

View file

@ -136,6 +136,18 @@ hw.nvme.apst_enable=1
.Ed
.Pp
The default vendor-provided settings, if any, will be applied.
To override this, set the following tunable:
.Bd -literal -offset indent
hw.nvme.apst_data
.Ed
.Pp
The string must contain up to 32 encoded integers, e.g. "0x6418 0
0 0x3e820".
Each value corresponds to a specific available power state starting
from the lowest, and defines the target state (bits 3..7) to
transition to, as well as the idle time in milliseconds (bits 8..31)
to wait before that transition.
Bits 0..2 must be zero.
.Pp
The
.Xr nvd 4

View file

@ -786,7 +786,7 @@ nvme_ctrlr_configure_apst(struct nvme_controller *ctrlr)
{
struct nvme_completion_poll_status status;
uint64_t *data;
int data_size;
int data_size, i, read_size;
bool enable, error = true;
if (TUNABLE_BOOL_FETCH("hw.nvme.apst_enable", &enable) == 0 ||
@ -796,13 +796,19 @@ nvme_ctrlr_configure_apst(struct nvme_controller *ctrlr)
data_size = 32 * sizeof(*data);
data = malloc(data_size, M_NVME, M_WAITOK | M_ZERO);
status.done = 0;
nvme_ctrlr_cmd_get_feature(ctrlr,
NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION, 0,
data, data_size, nvme_completion_poll_cb, &status);
nvme_completion_poll(&status);
if (nvme_completion_is_error(&status.cpl))
goto out;
if (getenv_array("hw.nvme.apst_data", data, data_size,
&read_size, sizeof(*data), GETENV_UNSIGNED) != 0) {
for (i = 0; i < read_size / sizeof(*data); ++i)
data[i] = htole64(data[i]);
} else {
status.done = 0;
nvme_ctrlr_cmd_get_feature(ctrlr,
NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION, 0,
data, data_size, nvme_completion_poll_cb, &status);
nvme_completion_poll(&status);
if (nvme_completion_is_error(&status.cpl))
goto out;
}
status.done = 0;
nvme_ctrlr_cmd_set_feature(ctrlr,