Commit 60df5de9 authored by Christoph Hellwig's avatar Christoph Hellwig
Browse files

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: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarNiklas Cassel <niklas.cassel@wdc.com>
parent 53fe2a30
Loading
Loading
Loading
Loading
+69 −80
Original line number Diff line number Diff line
@@ -2181,28 +2181,28 @@ static int nvme_configure_acre(struct nvme_ctrl *ctrl)
	return ret;
}

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.
 * 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.
 *
	 * 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.
 * Users can set ps_max_latency_us to zero to turn off APST.
 */

	unsigned apste;
static int nvme_configure_apst(struct nvme_ctrl *ctrl)
{
	struct nvme_feat_auto_pst *table;
	unsigned apste = 0;
	u64 max_lat_us = 0;
	__le64 target = 0;
	int max_ps = -1;
	int state;
	int ret;

	/*
@@ -2223,17 +2223,15 @@ static int nvme_configure_apst(struct nvme_ctrl *ctrl)

	if (!ctrl->apst_enabled || ctrl->ps_max_latency_us == 0) {
		/* Turn off APST. */
		apste = 0;
		dev_dbg(ctrl->device, "APST disabled\n");
	} else {
		__le64 target = cpu_to_le64(0);
		int state;
		goto done;
	}

	/*
	 * 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.
	 * 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;
@@ -2242,64 +2240,55 @@ static int nvme_configure_apst(struct nvme_ctrl *ctrl)
			table->entries[state] = target;

		/*
			 * Don't allow transitions to the deepest state
			 * if it's quirked off.
		 * 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?
		 * 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))
		if (!(ctrl->psd[state].flags & NVME_PS_FLAGS_NON_OP_STATE))
			continue;

			exit_latency_us =
				(u64)le32_to_cpu(ctrl->psd[state].exit_lat);
		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 +
		total_latency_us = exit_latency_us +
			le32_to_cpu(ctrl->psd[state].entry_lat);

		/*
			 * This state is good.  Use it as the APST idle
			 * target for higher power states.
		 * This state is good.  Use it as the APST idle 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));

		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;
	}

		apste = 1;

		if (max_ps == -1) {
	if (max_ps == -1)
		dev_dbg(ctrl->device, "APST enabled but no non-operational states are available\n");
		} else {
	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,
				table, sizeof(*table), NULL);
	if (ret)
		dev_err(ctrl->device, "failed to set APST feature (%d)\n", ret);

	kfree(table);
	return ret;
}