提交 60df5de9 编写于 作者: C Christoph Hellwig

nvme: cleanup nvme_configure_apst

Remove a level of indentation from the main code implementating the table
search by using a goto for the APST not supported case.  Also move the
main comment above the function.
Signed-off-by: NChristoph Hellwig <hch@lst.de>
Reviewed-by: NNiklas Cassel <niklas.cassel@wdc.com>
上级 53fe2a30
...@@ -2181,28 +2181,28 @@ static int nvme_configure_acre(struct nvme_ctrl *ctrl) ...@@ -2181,28 +2181,28 @@ static int nvme_configure_acre(struct nvme_ctrl *ctrl)
return ret; return ret;
} }
/*
* APST (Autonomous Power State Transition) lets us program a table of power
* state transitions that the controller will perform automatically.
* We configure it with a simple heuristic: we are willing to spend at most 2%
* of the time transitioning between power states. Therefore, when running in
* any given state, we will enter the next lower-power non-operational state
* after waiting 50 * (enlat + exlat) microseconds, as long as that state's exit
* latency is under the requested maximum latency.
*
* We will not autonomously enter any non-operational state for which the total
* latency exceeds ps_max_latency_us.
*
* Users can set ps_max_latency_us to zero to turn off APST.
*/
static int nvme_configure_apst(struct nvme_ctrl *ctrl) static int nvme_configure_apst(struct nvme_ctrl *ctrl)
{ {
/*
* APST (Autonomous Power State Transition) lets us program a
* table of power state transitions that the controller will
* perform automatically. We configure it with a simple
* heuristic: we are willing to spend at most 2% of the time
* transitioning between power states. Therefore, when running
* in any given state, we will enter the next lower-power
* non-operational state after waiting 50 * (enlat + exlat)
* microseconds, as long as that state's exit latency is under
* the requested maximum latency.
*
* We will not autonomously enter any non-operational state for
* which the total latency exceeds ps_max_latency_us. Users
* can set ps_max_latency_us to zero to turn off APST.
*/
unsigned apste;
struct nvme_feat_auto_pst *table; struct nvme_feat_auto_pst *table;
unsigned apste = 0;
u64 max_lat_us = 0; u64 max_lat_us = 0;
__le64 target = 0;
int max_ps = -1; int max_ps = -1;
int state;
int ret; int ret;
/* /*
...@@ -2223,83 +2223,72 @@ static int nvme_configure_apst(struct nvme_ctrl *ctrl) ...@@ -2223,83 +2223,72 @@ static int nvme_configure_apst(struct nvme_ctrl *ctrl)
if (!ctrl->apst_enabled || ctrl->ps_max_latency_us == 0) { if (!ctrl->apst_enabled || ctrl->ps_max_latency_us == 0) {
/* Turn off APST. */ /* Turn off APST. */
apste = 0;
dev_dbg(ctrl->device, "APST disabled\n"); dev_dbg(ctrl->device, "APST disabled\n");
} else { goto done;
__le64 target = cpu_to_le64(0); }
int state;
/*
* Walk through all states from lowest- to highest-power.
* According to the spec, lower-numbered states use more
* power. NPSS, despite the name, is the index of the
* lowest-power state, not the number of states.
*/
for (state = (int)ctrl->npss; state >= 0; state--) {
u64 total_latency_us, exit_latency_us, transition_ms;
if (target)
table->entries[state] = target;
/*
* Don't allow transitions to the deepest state
* if it's quirked off.
*/
if (state == ctrl->npss &&
(ctrl->quirks & NVME_QUIRK_NO_DEEPEST_PS))
continue;
/*
* Is this state a useful non-operational state for
* higher-power states to autonomously transition to?
*/
if (!(ctrl->psd[state].flags &
NVME_PS_FLAGS_NON_OP_STATE))
continue;
exit_latency_us =
(u64)le32_to_cpu(ctrl->psd[state].exit_lat);
if (exit_latency_us > ctrl->ps_max_latency_us)
continue;
total_latency_us = /*
exit_latency_us + * Walk through all states from lowest- to highest-power.
le32_to_cpu(ctrl->psd[state].entry_lat); * According to the spec, lower-numbered states use more power. NPSS,
* despite the name, is the index of the lowest-power state, not the
* number of states.
*/
for (state = (int)ctrl->npss; state >= 0; state--) {
u64 total_latency_us, exit_latency_us, transition_ms;
/* if (target)
* This state is good. Use it as the APST idle table->entries[state] = target;
* target for higher power states.
*/
transition_ms = total_latency_us + 19;
do_div(transition_ms, 20);
if (transition_ms > (1 << 24) - 1)
transition_ms = (1 << 24) - 1;
target = cpu_to_le64((state << 3) | /*
(transition_ms << 8)); * Don't allow transitions to the deepest state if it's quirked
* off.
*/
if (state == ctrl->npss &&
(ctrl->quirks & NVME_QUIRK_NO_DEEPEST_PS))
continue;
if (max_ps == -1) /*
max_ps = state; * Is this state a useful non-operational state for higher-power
* states to autonomously transition to?
*/
if (!(ctrl->psd[state].flags & NVME_PS_FLAGS_NON_OP_STATE))
continue;
if (total_latency_us > max_lat_us) exit_latency_us = (u64)le32_to_cpu(ctrl->psd[state].exit_lat);
max_lat_us = total_latency_us; if (exit_latency_us > ctrl->ps_max_latency_us)
} continue;
apste = 1; total_latency_us = exit_latency_us +
le32_to_cpu(ctrl->psd[state].entry_lat);
if (max_ps == -1) { /*
dev_dbg(ctrl->device, "APST enabled but no non-operational states are available\n"); * This state is good. Use it as the APST idle target for
} else { * higher power states.
dev_dbg(ctrl->device, "APST enabled: max PS = %d, max round-trip latency = %lluus, table = %*phN\n", */
max_ps, max_lat_us, (int)sizeof(*table), table); transition_ms = total_latency_us + 19;
} do_div(transition_ms, 20);
if (transition_ms > (1 << 24) - 1)
transition_ms = (1 << 24) - 1;
target = cpu_to_le64((state << 3) | (transition_ms << 8));
if (max_ps == -1)
max_ps = state;
if (total_latency_us > max_lat_us)
max_lat_us = total_latency_us;
} }
if (max_ps == -1)
dev_dbg(ctrl->device, "APST enabled but no non-operational states are available\n");
else
dev_dbg(ctrl->device, "APST enabled: max PS = %d, max round-trip latency = %lluus, table = %*phN\n",
max_ps, max_lat_us, (int)sizeof(*table), table);
apste = 1;
done:
ret = nvme_set_features(ctrl, NVME_FEAT_AUTO_PST, apste, ret = nvme_set_features(ctrl, NVME_FEAT_AUTO_PST, apste,
table, sizeof(*table), NULL); table, sizeof(*table), NULL);
if (ret) if (ret)
dev_err(ctrl->device, "failed to set APST feature (%d)\n", ret); dev_err(ctrl->device, "failed to set APST feature (%d)\n", ret);
kfree(table); kfree(table);
return ret; return ret;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册