nvme: explicitly disable APST on quirked devices
authorKai-Heng Feng <kai.heng.feng@canonical.com>
Mon, 26 Jun 2017 20:39:54 +0000 (16:39 -0400)
committerJens Axboe <axboe@kernel.dk>
Wed, 28 Jun 2017 14:14:13 +0000 (08:14 -0600)
A user reports APST is enabled, even when the NVMe is quirked or with
option "default_ps_max_latency_us=0".

The current logic will not set APST if the device is quirked. But the
NVMe in question will enable APST automatically.

Separate the logic "apst is supported" and "to enable apst", so we can
use the latter one to explicitly disable APST at initialiaztion.

BugLink: https://bugs.launchpad.net/bugs/1699004
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
Reviewed-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Keith Busch <keith.busch@intel.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
drivers/nvme/host/core.c
drivers/nvme/host/nvme.h

index 822743139547646adccb6e69676616d8afb13904..9c03655ac2a90c05b418e4968778f0665a1abd17 100644 (file)
@@ -1549,7 +1549,7 @@ static void nvme_configure_apst(struct nvme_ctrl *ctrl)
        if (!table)
                return;
 
-       if (ctrl->ps_max_latency_us == 0) {
+       if (!ctrl->apst_enabled || ctrl->ps_max_latency_us == 0) {
                /* Turn off APST. */
                apste = 0;
                dev_dbg(ctrl->device, "APST disabled\n");
@@ -1716,7 +1716,7 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
        u64 cap;
        int ret, page_shift;
        u32 max_hw_sectors;
-       u8 prev_apsta;
+       bool prev_apst_enabled;
 
        ret = ctrl->ops->reg_read32(ctrl, NVME_REG_VS, &ctrl->vs);
        if (ret) {
@@ -1784,16 +1784,17 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
        ctrl->kas = le16_to_cpu(id->kas);
 
        ctrl->npss = id->npss;
-       prev_apsta = ctrl->apsta;
+       ctrl->apsta = id->apsta;
+       prev_apst_enabled = ctrl->apst_enabled;
        if (ctrl->quirks & NVME_QUIRK_NO_APST) {
                if (force_apst && id->apsta) {
                        dev_warn(ctrl->device, "forcibly allowing APST due to nvme_core.force_apst -- use at your own risk\n");
-                       ctrl->apsta = 1;
+                       ctrl->apst_enabled = true;
                } else {
-                       ctrl->apsta = 0;
+                       ctrl->apst_enabled = false;
                }
        } else {
-               ctrl->apsta = id->apsta;
+               ctrl->apst_enabled = id->apsta;
        }
        memcpy(ctrl->psd, id->psd, sizeof(ctrl->psd));
 
@@ -1823,9 +1824,9 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
 
        kfree(id);
 
-       if (ctrl->apsta && !prev_apsta)
+       if (ctrl->apst_enabled && !prev_apst_enabled)
                dev_pm_qos_expose_latency_tolerance(ctrl->device);
-       else if (!ctrl->apsta && prev_apsta)
+       else if (!ctrl->apst_enabled && prev_apst_enabled)
                dev_pm_qos_hide_latency_tolerance(ctrl->device);
 
        nvme_configure_apst(ctrl);
index 1363ccbacf0a47af53fd8061684bfd521917782d..b74f954eac66ccd3ba9dae14cf81226f4b27e756 100644 (file)
@@ -167,6 +167,7 @@ struct nvme_ctrl {
 
        /* Power saving configuration */
        u64 ps_max_latency_us;
+       bool apst_enabled;
 
        u32 hmpre;
        u32 hmmin;