nvme: only consider exit latency when choosing useful non-op power states
authorKai-Heng Feng <kai.heng.feng@canonical.com>
Wed, 7 Jun 2017 07:25:42 +0000 (15:25 +0800)
committerChristoph Hellwig <hch@lst.de>
Wed, 7 Jun 2017 09:08:54 +0000 (11:08 +0200)
When a NVMe is in non-op states, the latency is exlat.
The latency will be enlat + exlat only when the NVMe tries to transit
from operational state right atfer it begins to transit to
non-operational state, which should be a rare case.

Therefore, as Andy Lutomirski suggests, use exlat only when deciding power
states to trainsit to.

Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
drivers/nvme/host/core.c

index 0f9cc0c55e153758b0f16c583870f466f40be808..c07d8d4e18c919b8451287e73fafd21024388594 100644 (file)
@@ -1342,7 +1342,7 @@ static void nvme_configure_apst(struct nvme_ctrl *ctrl)
         * 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 total latency is under
+        * 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
@@ -1387,7 +1387,7 @@ static void nvme_configure_apst(struct nvme_ctrl *ctrl)
                 * lowest-power state, not the number of states.
                 */
                for (state = (int)ctrl->npss; state >= 0; state--) {
-                       u64 total_latency_us, transition_ms;
+                       u64 total_latency_us, exit_latency_us, transition_ms;
 
                        if (target)
                                table->entries[state] = target;
@@ -1408,12 +1408,15 @@ static void nvme_configure_apst(struct nvme_ctrl *ctrl)
                              NVME_PS_FLAGS_NON_OP_STATE))
                                continue;
 
-                       total_latency_us =
-                               (u64)le32_to_cpu(ctrl->psd[state].entry_lat) +
-                               + le32_to_cpu(ctrl->psd[state].exit_lat);
-                       if (total_latency_us > ctrl->ps_max_latency_us)
+                       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 +
+                               le32_to_cpu(ctrl->psd[state].entry_lat);
+
                        /*
                         * This state is good.  Use it as the APST idle
                         * target for higher power states.