From patchwork Thu Jun 13 15:20:36 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Akinobu Mita X-Patchwork-Id: 10992227 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6B45214C0 for ; Thu, 13 Jun 2019 15:21:17 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 58E25205A9 for ; Thu, 13 Jun 2019 15:21:17 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4CF57212BE; Thu, 13 Jun 2019 15:21:17 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CA02F205A9 for ; Thu, 13 Jun 2019 15:21:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732104AbfFMPVP (ORCPT ); Thu, 13 Jun 2019 11:21:15 -0400 Received: from mail-pf1-f193.google.com ([209.85.210.193]:38486 "EHLO mail-pf1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732078AbfFMPUz (ORCPT ); Thu, 13 Jun 2019 11:20:55 -0400 Received: by mail-pf1-f193.google.com with SMTP id a186so12049472pfa.5 for ; Thu, 13 Jun 2019 08:20:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=8OmPO/eHJbUrIaHIx1TwZNS7VwjUu85zkfJ8NN4LaHM=; b=P45WYDk7n3DFpbQgGzihriYhk5YcQjHctVcI0423tKzzQWQ4jf978jTWyrzeA2jaWW Od+JF5SIbrsEIQYT7cDVrNO9vGIVyNKHCAiMA0XX6dLf/OjMBJ/kBtNIbqlwNCTDXmWg vZOHQtSMmuPRZR0ubqReoIt6QBiZ/L3fIiRmsdwDQclDODQCYtbWro3iLSws4yfW/CW0 5lnEQTKAnCajC2t8e9rrVq1YIAN+wHen6gy0DSNYOG11Fcbeng3xxuqgTqORjrHECETw Hb9BlG53+XXgAkDBv43Dp97+F5StNj5KQ29XWpv49QuEV+SLYsgtZWAfLeaXWZTwYTbd zFlg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=8OmPO/eHJbUrIaHIx1TwZNS7VwjUu85zkfJ8NN4LaHM=; b=lQBLybRsAhSQh/s7sBCOAYlXsS+k8KGvx6RawmhD3pi6wQpWw2W4HF+nzAuHpViPDG yZ4EsHwYcUWHUe6NKtHMAyvqI/rp0sFeLLboqEebt7TjSukIF9ZfYMW05Q8AmpRWQstb OyS0DY+DuWFj53ptvCgWcgBa8sxvQBWVPZ6Bfbo7xS8PFsjG2/ZGA1g5wmWmW3FD3OGU HwEm74ayxM9+RtBNpa1EVnVcVSTl8TvLLSHrLf9GESWJ2uXddvPLgxfbSOYdZf/mhOd4 UGUuw2KptazWgN4Oj3L74SLcJEzL47OF1CF0uAmnFOHhzD4VhD2Sq7x+EAmaKN0q5Md1 7G9g== X-Gm-Message-State: APjAAAXBnh0GiztG6pDM4wbGGhQG60ffVN1OHGiJ5mE8bvvVUI4Zvrsl Hw8ohIWxfpUiHtnpUfUl4QE= X-Google-Smtp-Source: APXvYqyFOyby9WANnjddgrH7WxB0cc/U4wmWWqqDVIhsFKKlhiCMshhDja9qc0wLnc/+V2OTxZAmdQ== X-Received: by 2002:a17:90a:a397:: with SMTP id x23mr6302485pjp.118.1560439255098; Thu, 13 Jun 2019 08:20:55 -0700 (PDT) Received: from mita-MS-7A45.lan ([240f:34:212d:1:1b24:991b:df50:ea3f]) by smtp.gmail.com with ESMTPSA id n66sm40988pfn.52.2019.06.13.08.20.53 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 13 Jun 2019 08:20:54 -0700 (PDT) From: Akinobu Mita To: linux-nvme@lists.infradead.org, linux-pm@vger.kernel.org Cc: Keith Busch , Akinobu Mita Subject: [PATCH v4 1/3] nvme: Export get and set features Date: Fri, 14 Jun 2019 00:20:36 +0900 Message-Id: <1560439238-4054-2-git-send-email-akinobu.mita@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1560439238-4054-1-git-send-email-akinobu.mita@gmail.com> References: <1560439238-4054-1-git-send-email-akinobu.mita@gmail.com> Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Keith Busch Future use intends to make use of both, so export these functions. And since their implementation is identical except for the opcode, provide a new function that implement both. [akinobu.mita@gmail.com>: fix line over 80 characters] Signed-off-by: Keith Busch Signed-off-by: Akinobu Mita Reviewed-by: Chaitanya Kulkarni Reviewed-by: Minwoo Im --- drivers/nvme/host/core.c | 24 +++++++++++++++++++++--- drivers/nvme/host/nvme.h | 6 ++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 120fb59..7e3c786 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -1113,15 +1113,15 @@ static struct nvme_id_ns *nvme_identify_ns(struct nvme_ctrl *ctrl, return id; } -static int nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword11, - void *buffer, size_t buflen, u32 *result) +static int nvme_features(struct nvme_ctrl *dev, u8 op, unsigned int fid, + unsigned int dword11, void *buffer, size_t buflen, u32 *result) { struct nvme_command c; union nvme_result res; int ret; memset(&c, 0, sizeof(c)); - c.features.opcode = nvme_admin_set_features; + c.features.opcode = op; c.features.fid = cpu_to_le32(fid); c.features.dword11 = cpu_to_le32(dword11); @@ -1132,6 +1132,24 @@ static int nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword return ret; } +int nvme_set_features(struct nvme_ctrl *dev, unsigned int fid, + unsigned int dword11, void *buffer, size_t buflen, + u32 *result) +{ + return nvme_features(dev, nvme_admin_set_features, fid, dword11, buffer, + buflen, result); +} +EXPORT_SYMBOL_GPL(nvme_set_features); + +int nvme_get_features(struct nvme_ctrl *dev, unsigned int fid, + unsigned int dword11, void *buffer, size_t buflen, + u32 *result) +{ + return nvme_features(dev, nvme_admin_get_features, fid, dword11, buffer, + buflen, result); +} +EXPORT_SYMBOL_GPL(nvme_get_features); + int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count) { u32 q_count = (*count - 1) | ((*count - 1) << 16); diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index 55553d2..038b893 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -459,6 +459,12 @@ int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd, union nvme_result *result, void *buffer, unsigned bufflen, unsigned timeout, int qid, int at_head, blk_mq_req_flags_t flags, bool poll); +int nvme_set_features(struct nvme_ctrl *dev, unsigned int fid, + unsigned int dword11, void *buffer, size_t buflen, + u32 *result); +int nvme_get_features(struct nvme_ctrl *dev, unsigned int fid, + unsigned int dword11, void *buffer, size_t buflen, + u32 *result); int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count); void nvme_stop_keep_alive(struct nvme_ctrl *ctrl); int nvme_reset_ctrl(struct nvme_ctrl *ctrl); From patchwork Thu Jun 13 15:20:37 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Akinobu Mita X-Patchwork-Id: 10992221 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2DCBB15E6 for ; Thu, 13 Jun 2019 15:21:03 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 17A3A205A9 for ; Thu, 13 Jun 2019 15:21:03 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 08CA6212BE; Thu, 13 Jun 2019 15:21:03 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 048A520CCF for ; Thu, 13 Jun 2019 15:21:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732005AbfFMPVA (ORCPT ); Thu, 13 Jun 2019 11:21:00 -0400 Received: from mail-pg1-f195.google.com ([209.85.215.195]:39424 "EHLO mail-pg1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732106AbfFMPU7 (ORCPT ); Thu, 13 Jun 2019 11:20:59 -0400 Received: by mail-pg1-f195.google.com with SMTP id 196so11151895pgc.6 for ; Thu, 13 Jun 2019 08:20:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=miVnfcMW7xeV5A0V6gdNVxHODa/F79LrLk1WU/5vuHs=; b=I+iDOUkMM7ZWb++pibE42R7T7APsoXm+MzUBI1rkaZQqxCmq19FPdbkI+lf3dgcr6G WhkJt/cnzGTYnBuBoYUlCi7nzXO/nhLR5/WtUNhlN+68P6U5U3pLC2lJ+BD49UHS2Uq3 L+t60VZ9pD+9KNK8QdqHgk7nmuLATnGcZQefJeO1Ypr8ezMCrF9Mt7wkJoK30UMY3SgW ju+Ap8y0+1JHjCNEiP8FhyF/xNmVQACZGbfZSnX0fswzpOWUnVqF7k4Sh4bJj6HVP+kv jSTXb2qjhuumYZBLJJWNkIfNOZfDNpPE/1N7l2ksyqWJGNPcnRBuMPRYh4u8j5eXTExq YN7A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=miVnfcMW7xeV5A0V6gdNVxHODa/F79LrLk1WU/5vuHs=; b=jvQuT7OUlXLYssF4GNEMnUU8O5TGPmIKJAdDa3q0BfWlbJk7TevOSg5nFD6QGiI6Q4 gkAA+K5R7bw+th+ZdSZ7PNASnujuLz/V4r6uNXEXqiodjqJyElR1ktczE/cl7dMJ4tYq IV1jSanm0jj30VhCb8kNgDtQKyBIUU44KFmXdkcBb2pEd468plEghPmmez8j/AQat9Dl JH1Npb/teIBM4c9C169q3vmse7S4QNUP/pzR9pQ5/eAQbyHJLi09RJ3OV54yamesue7y 6UqIDE+4Nv3ErlbZ15RXD7lGn5Kc23foxZi9PojzvDYo94IVOqQK5/hKRO4lB74Sy10L EFZg== X-Gm-Message-State: APjAAAXmg88uLJIik1pWf85SuBX6jXMU65TXOzf6ekCbdkwvtp7MrsFG PbH9+Ixd6mUGpTMubgOfj+o= X-Google-Smtp-Source: APXvYqw/6S5xHbIztO1eofywFVL39fbIHsDE59llrTNgSGlLz/7TjZDkOO3jDEMhfceD6qnp3GsvSw== X-Received: by 2002:a63:292:: with SMTP id 140mr29982pgc.88.1560439258644; Thu, 13 Jun 2019 08:20:58 -0700 (PDT) Received: from mita-MS-7A45.lan ([240f:34:212d:1:1b24:991b:df50:ea3f]) by smtp.gmail.com with ESMTPSA id n66sm40988pfn.52.2019.06.13.08.20.55 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 13 Jun 2019 08:20:58 -0700 (PDT) From: Akinobu Mita To: linux-nvme@lists.infradead.org, linux-pm@vger.kernel.org Cc: Akinobu Mita , Zhang Rui , Eduardo Valentin , Daniel Lezcano , Keith Busch , Jens Axboe , Christoph Hellwig , Sagi Grimberg , Minwoo Im , Kenneth Heitke , Chaitanya Kulkarni Subject: [PATCH v4 2/3] nvme: add thermal zone devices Date: Fri, 14 Jun 2019 00:20:37 +0900 Message-Id: <1560439238-4054-3-git-send-email-akinobu.mita@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1560439238-4054-1-git-send-email-akinobu.mita@gmail.com> References: <1560439238-4054-1-git-send-email-akinobu.mita@gmail.com> Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The NVMe controller reports up to nine temperature values in the SMART / Health log page (the composite temperature and temperature sensor 1 through temperature sensor 8). This provides these temperatures via thermal zone devices. Once the controller is identified, the thermal zone devices are created for all implemented temperature sensors including the composite temperature. /sys/class/thermal/thermal_zone[0-*]: |---type: 'nvme-temp' |---temp: Temperature |---trip_point_0_temp: Over temperature threshold The thermal_zone[0-*] contains a 'device' symlink to the corresponding nvme device. On the other hand, the following symlinks to the thermal zone devices are created in the nvme device sysfs directory. - temp0: Composite temperature - temp1: Temperature sensor 1 ... - temp8: Temperature sensor 8 In addition to the standard thermal zone device, this also adds support for registering the DT thermal zone device. Cc: Zhang Rui Cc: Eduardo Valentin Cc: Daniel Lezcano Cc: Keith Busch Cc: Jens Axboe Cc: Christoph Hellwig Cc: Sagi Grimberg Cc: Minwoo Im Cc: Kenneth Heitke Cc: Chaitanya Kulkarni Signed-off-by: Akinobu Mita --- * v4 - add thermal.c to hold thermal zone related code - add 'use_thermal_zone' module parameter - add CONFIG_THERMAL_WRITABLE_TRIPS dependency - add comment about the return value of nvme_thermal_zones_register() - support DT thermal zone device. - use bitmap to iterate over implemented sensors drivers/nvme/host/Kconfig | 1 + drivers/nvme/host/Makefile | 1 + drivers/nvme/host/core.c | 5 + drivers/nvme/host/nvme.h | 35 +++++ drivers/nvme/host/thermal.c | 311 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/nvme.h | 5 + 6 files changed, 358 insertions(+) create mode 100644 drivers/nvme/host/thermal.c diff --git a/drivers/nvme/host/Kconfig b/drivers/nvme/host/Kconfig index ec43ac9..90429f8 100644 --- a/drivers/nvme/host/Kconfig +++ b/drivers/nvme/host/Kconfig @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config NVME_CORE tristate + select THERMAL_WRITABLE_TRIPS if THERMAL config BLK_DEV_NVME tristate "NVM Express block device" diff --git a/drivers/nvme/host/Makefile b/drivers/nvme/host/Makefile index 8a4b671..6018668 100644 --- a/drivers/nvme/host/Makefile +++ b/drivers/nvme/host/Makefile @@ -14,6 +14,7 @@ nvme-core-$(CONFIG_TRACING) += trace.o nvme-core-$(CONFIG_NVME_MULTIPATH) += multipath.o nvme-core-$(CONFIG_NVM) += lightnvm.o nvme-core-$(CONFIG_FAULT_INJECTION_DEBUG_FS) += fault_inject.o +nvme-core-$(CONFIG_THERMAL) += thermal.o nvme-y += pci.o diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 7e3c786..4be339b 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -2696,6 +2696,10 @@ int nvme_init_identify(struct nvme_ctrl *ctrl) if (ret < 0) return ret; + ret = nvme_thermal_zones_register(ctrl); + if (ret) + return ret; + ctrl->identified = true; return 0; @@ -3699,6 +3703,7 @@ void nvme_stop_ctrl(struct nvme_ctrl *ctrl) { nvme_mpath_stop(ctrl); nvme_stop_keep_alive(ctrl); + nvme_thermal_zones_unregister(ctrl); flush_work(&ctrl->async_event_work); cancel_work_sync(&ctrl->fw_act_work); } diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index 038b893..a9c63ea 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -15,6 +15,7 @@ #include #include #include +#include extern unsigned int nvme_io_timeout; #define NVME_IO_TIMEOUT (nvme_io_timeout * HZ) @@ -146,6 +147,13 @@ enum nvme_ctrl_state { NVME_CTRL_DEAD, }; +struct nvme_tz { + struct thermal_zone_params params; + struct thermal_zone_device *dev; + struct thermal_zone_device *of_dev; + unsigned int sensor; +}; + struct nvme_ctrl { bool comp_seen; enum nvme_ctrl_state state; @@ -247,6 +255,15 @@ struct nvme_ctrl { struct page *discard_page; unsigned long discard_page_busy; + +#ifdef CONFIG_THERMAL + /* + * tz[0]: composite temperature + * tz[1-8]: temperature sensor 1 through 8 + */ + struct nvme_tz tz[9]; + DECLARE_BITMAP(tz_enabled, 9); +#endif }; enum nvme_iopolicy { @@ -584,4 +601,22 @@ static inline struct nvme_ns *nvme_get_ns_from_dev(struct device *dev) return dev_to_disk(dev)->private_data; } +#ifdef CONFIG_THERMAL + +int nvme_thermal_zones_register(struct nvme_ctrl *ctrl); +void nvme_thermal_zones_unregister(struct nvme_ctrl *ctrl); + +#else + +static inline int nvme_thermal_zones_register(struct nvme_ctrl *ctrl) +{ + return 0; +} + +static inline void nvme_thermal_zones_unregister(struct nvme_ctrl *ctrl) +{ +} + +#endif /* CONFIG_THERMAL */ + #endif /* _NVME_H */ diff --git a/drivers/nvme/host/thermal.c b/drivers/nvme/host/thermal.c new file mode 100644 index 0000000..18d0e4c --- /dev/null +++ b/drivers/nvme/host/thermal.c @@ -0,0 +1,311 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +#include "nvme.h" + +static bool use_thermal_zone = true; +module_param(use_thermal_zone, bool, 0444); +MODULE_PARM_DESC(use_thermal_zone, + "Export nvme temperature via generic thermal interface"); + +static int nvme_get_temp(struct nvme_ctrl *ctrl, unsigned int sensor, int *temp) +{ + struct nvme_smart_log *log; + int ret; + + BUILD_BUG_ON(ARRAY_SIZE(log->temp_sensor) + 1 != ARRAY_SIZE(ctrl->tz)); + + if (WARN_ON_ONCE(sensor > ARRAY_SIZE(log->temp_sensor))) + return -EINVAL; + + log = kzalloc(sizeof(*log), GFP_KERNEL); + if (!log) + return -ENOMEM; + + ret = nvme_get_log(ctrl, NVME_NSID_ALL, NVME_LOG_SMART, 0, log, + sizeof(*log), 0); + if (ret) { + ret = ret > 0 ? -EINVAL : ret; + goto free_log; + } + + if (sensor) + *temp = le16_to_cpu(log->temp_sensor[sensor - 1]); + else + *temp = get_unaligned_le16(log->temperature); + +free_log: + kfree(log); + + return ret; +} + +#define KELVIN_TO_MILLICELSIUS(t) DECI_KELVIN_TO_MILLICELSIUS((t) * 10) +#define MILLICELSIUS_TO_KELVIN(t) ((MILLICELSIUS_TO_DECI_KELVIN(t) + 5) / 10) + +static int nvme_tz_of_get_temp(void *data, int *temp) +{ + struct nvme_tz *tz = data; + unsigned int sensor = tz->sensor; + struct nvme_ctrl *ctrl = container_of(tz, struct nvme_ctrl, tz[sensor]); + int ret; + + ret = nvme_get_temp(ctrl, sensor, temp); + if (!ret) + *temp = KELVIN_TO_MILLICELSIUS(*temp); + + return ret; +} + +static int nvme_tz_get_temp(struct thermal_zone_device *tzdev, int *temp) +{ + return nvme_tz_of_get_temp(tzdev->devdata, temp); +} + +static int nvme_tz_get_trip_type(struct thermal_zone_device *tzdev, + int trip, enum thermal_trip_type *type) +{ + *type = THERMAL_TRIP_ACTIVE; + + return 0; +} + +static int nvme_get_over_temp_thresh(struct nvme_ctrl *ctrl, + unsigned int sensor, int *temp) +{ + unsigned int threshold = sensor << NVME_TEMP_THRESH_SELECT_SHIFT; + int status; + int ret; + + if (WARN_ON_ONCE(sensor >= ARRAY_SIZE(ctrl->tz))) + return -EINVAL; + + ret = nvme_get_features(ctrl, NVME_FEAT_TEMP_THRESH, threshold, NULL, 0, + &status); + if (!ret) + *temp = status & NVME_TEMP_THRESH_MASK; + + return ret > 0 ? -EINVAL : ret; +} + +static int nvme_set_over_temp_thresh(struct nvme_ctrl *ctrl, + unsigned int sensor, int temp) +{ + unsigned int threshold = sensor << NVME_TEMP_THRESH_SELECT_SHIFT; + int ret; + + if (WARN_ON_ONCE(sensor >= ARRAY_SIZE(ctrl->tz))) + return -EINVAL; + + if (temp > NVME_TEMP_THRESH_MASK) + return -EINVAL; + + threshold |= temp & NVME_TEMP_THRESH_MASK; + + ret = nvme_set_features(ctrl, NVME_FEAT_TEMP_THRESH, threshold, NULL, 0, + NULL); + + return ret > 0 ? -EINVAL : ret; +} + +static int nvme_tz_get_trip_temp(struct thermal_zone_device *tzdev, + int trip, int *temp) +{ + struct nvme_tz *tz = tzdev->devdata; + unsigned int sensor = tz->sensor; + struct nvme_ctrl *ctrl = container_of(tz, struct nvme_ctrl, tz[sensor]); + int ret; + + ret = nvme_get_over_temp_thresh(ctrl, sensor, temp); + if (!ret) + *temp = KELVIN_TO_MILLICELSIUS(*temp); + + return ret; +} + +static int nvme_tz_of_set_trip_temp(void *data, int trip, int temp) +{ + struct nvme_tz *tz = data; + unsigned int sensor = tz->sensor; + struct nvme_ctrl *ctrl = container_of(tz, struct nvme_ctrl, tz[sensor]); + + temp = MILLICELSIUS_TO_KELVIN(temp); + + return nvme_set_over_temp_thresh(ctrl, sensor, temp); +} + +static int nvme_tz_set_trip_temp(struct thermal_zone_device *tzdev, + int trip, int temp) +{ + return nvme_tz_of_set_trip_temp(tzdev->devdata, trip, temp); +} + +static struct thermal_zone_device_ops nvme_tz_ops = { + .get_temp = nvme_tz_get_temp, + .get_trip_type = nvme_tz_get_trip_type, + .get_trip_temp = nvme_tz_get_trip_temp, + .set_trip_temp = nvme_tz_set_trip_temp, +}; + +static struct thermal_zone_of_device_ops nvme_tz_of_ops = { + .get_temp = nvme_tz_of_get_temp, + .set_trip_temp = nvme_tz_of_set_trip_temp, +}; + +static const struct thermal_zone_params nvme_tz_params = { + .governor_name = "user_space", + .no_hwmon = true, +}; + +static int nvme_thermal_zone_register(struct nvme_ctrl *ctrl, + unsigned int sensor) +{ + struct thermal_zone_device *tzdev; + struct nvme_tz *tz = &ctrl->tz[sensor]; + char name[THERMAL_NAME_LENGTH]; + int ret; + + tz->params = nvme_tz_params; + tz->sensor = sensor; + snprintf(name, sizeof(name), "nvme%d_temp%u", ctrl->instance, sensor); + + tzdev = thermal_zone_device_register(name, 1, 1, tz, &nvme_tz_ops, + &tz->params, 0, 0); + if (IS_ERR(tzdev)) { + dev_err(ctrl->device, + "Failed to register thermal zone device: %ld\n", + PTR_ERR(tzdev)); + return PTR_ERR(tzdev); + } + + tz->dev = tzdev; + + snprintf(name, sizeof(name), "temp%d", sensor); + ret = sysfs_create_link(&ctrl->ctrl_device.kobj, &tz->dev->device.kobj, + name); + if (ret) + goto device_unregister; + + ret = sysfs_create_link(&tz->dev->device.kobj, + &ctrl->ctrl_device.kobj, "device"); + if (ret) + goto remove_sensor_link; + + tzdev = thermal_zone_of_sensor_register(ctrl->dev, sensor, tz, + &nvme_tz_of_ops); + if (!IS_ERR(tzdev)) { + tz->of_dev = tzdev; + } else if (PTR_ERR(tzdev) != -ENODEV) { + ret = PTR_ERR(tzdev); + dev_err(ctrl->device, + "Failed to register thermal zone of sensor: %d\n", ret); + goto remove_device_link; + } + + return 0; + +remove_device_link: + sysfs_remove_link(&tz->dev->device.kobj, "device"); +remove_sensor_link: + sysfs_remove_link(&ctrl->ctrl_device.kobj, name); +device_unregister: + thermal_zone_device_unregister(tz->dev); + tz->dev = NULL; + + return ret; +} + +/** + * nvme_thermal_zones_register() - register nvme thermal zone devices + * @ctrl: controller instance + * + * This function creates up to nine thermal zone devices for all implemented + * temperature sensors including the composite temperature. + * Each thermal zone device provides a single trip point temperature that is + * associated with an over temperature threshold. + * A negative value is returned when the device doesn't respond to the host + * and won't be able to continue initialization. + */ +int nvme_thermal_zones_register(struct nvme_ctrl *ctrl) +{ + struct nvme_smart_log *log; + int ret = 0; + int err; + int i; + + if (!use_thermal_zone) + return 0; + + log = kzalloc(sizeof(*log), GFP_KERNEL); + if (!log) + return 0; + + err = nvme_get_log(ctrl, NVME_NSID_ALL, NVME_LOG_SMART, 0, log, + sizeof(*log), 0); + if (err) { + dev_err(ctrl->device, "Failed to get SMART log: %d\n", err); + /* If the device provided a response, then it's non-fatal */ + ret = (err > 0) ? 0 : err; + goto out; + } + + for_each_clear_bit(i, ctrl->tz_enabled, ARRAY_SIZE(ctrl->tz)) { + int temp; + + if (i) + temp = le16_to_cpu(log->temp_sensor[i - 1]); + else + temp = get_unaligned_le16(log->temperature); + + /* + * All implemented temperature sensors report a non-zero value + * in temperature sensor fields in the smart log page. + */ + if (!temp) + continue; + + err = nvme_thermal_zone_register(ctrl, i); + if (err) + goto out; + + __set_bit(i, ctrl->tz_enabled); + } +out: + if (err) + nvme_thermal_zones_unregister(ctrl); + + kfree(log); + + return ret; +} + +/** + * nvme_thermal_zones_unregister() - unregister nvme thermal zone devices + * @ctrl: controller instance + * + * This function removes the registered thermal zone devices and symlinks. + */ +void nvme_thermal_zones_unregister(struct nvme_ctrl *ctrl) +{ + int i; + + for_each_set_bit(i, ctrl->tz_enabled, ARRAY_SIZE(ctrl->tz)) { + struct nvme_tz *tz = &ctrl->tz[i]; + char name[20]; + + thermal_zone_of_sensor_unregister(ctrl->dev, tz->of_dev); + tz->of_dev = NULL; + + sysfs_remove_link(&tz->dev->device.kobj, "device"); + + snprintf(name, sizeof(name), "temp%d", i); + sysfs_remove_link(&ctrl->ctrl_device.kobj, name); + + thermal_zone_device_unregister(tz->dev); + tz->dev = NULL; + + __clear_bit(i, ctrl->tz_enabled); + } +} diff --git a/include/linux/nvme.h b/include/linux/nvme.h index 8028ada..f29728b 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -749,6 +749,11 @@ struct nvme_write_zeroes_cmd { /* Features */ +enum { + NVME_TEMP_THRESH_MASK = 0xffff, + NVME_TEMP_THRESH_SELECT_SHIFT = 16, +}; + struct nvme_feat_auto_pst { __le64 entries[32]; }; From patchwork Thu Jun 13 15:20:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Akinobu Mita X-Patchwork-Id: 10992223 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 72E4D76 for ; Thu, 13 Jun 2019 15:21:06 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 61957212BE for ; Thu, 13 Jun 2019 15:21:06 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 553CE205A9; Thu, 13 Jun 2019 15:21:06 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C0D97205A9 for ; Thu, 13 Jun 2019 15:21:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732486AbfFMPVE (ORCPT ); Thu, 13 Jun 2019 11:21:04 -0400 Received: from mail-pf1-f194.google.com ([209.85.210.194]:40882 "EHLO mail-pf1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732175AbfFMPVD (ORCPT ); Thu, 13 Jun 2019 11:21:03 -0400 Received: by mail-pf1-f194.google.com with SMTP id p184so8759365pfp.7 for ; Thu, 13 Jun 2019 08:21:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=HnfFchC3wMAMcLtgIbxWv9S1iSlr9IyZ2/2qohCAJVA=; b=bA5pUCwh6BISRH4uZm6AxPfTDBlh7uVgQY65L66HTVf6CsQTKHS/LQk8V1bsb/2i+y x7tkXXDhtMjV05dBTodRZZrjy0steNn/xfCTbZjYdddE9jOYLwRkVLxkPFyL0S/MJyyf qn/igkqDZ0nh7juQUqdT7Acqylcr1I01HdlqmQ8TUKq3MZrdv8kRSB7DkdwHZ6OOXN7J 13EQF5YvByiTfptfDCTX0pYs+C2G4z0i6NGLBE3h1vxkILOw+NjOFzaqLFuOOyfLKZFD 72QoUXQPJgJSosT6P60QiNsL7+xyKHRw3uQc76P9WThgsxdrU77am0SBNJiQ8kfGTS0O DJCg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=HnfFchC3wMAMcLtgIbxWv9S1iSlr9IyZ2/2qohCAJVA=; b=Mn6lCdFk/h8dZE027+8WgEOCqsDcWG2YfhwU38xK9VI1DVtKP8Ar2hJ79Cg0vjozv/ IM7rbEHtFT9R8i1l9LF+RGU30pCoQ+9tfF4RV9vbO96fRewVH3mu9SIwIJgcRHnSB0DV NatsWZ+ZycDFktq5Pz5TI4Sbb5dN+hUM3Am6TJgYESgVxYLirI4r6K4dyRGtv4pNYszA hhzpmyOFok2bbsX/vWKu9zbkHVmhtxBfrFEG9xdx5eT8du1oSekafcba/V8PI98IoKiE F2dRQnQXl5W4m/PIHAeKvakCgnAxu9p584hjMQw+BQNMAQ+oA+c650lacngWY16dhlwh Q3NA== X-Gm-Message-State: APjAAAW0l+9/GADCBDl0gRNlALT6XqttF/s7foiN9KWbmiA1KQbYlcf8 iP/6hmJ2awtsTNF3i+wu+jU= X-Google-Smtp-Source: APXvYqwoJfFV3B1i4a1JSo+0079Wyn4XTtUWy/7PFJHRvF2XRC4i5fZ+OyZfEbfMwwB8mJoRgeTmZg== X-Received: by 2002:a17:90a:bf84:: with SMTP id d4mr6069546pjs.124.1560439262506; Thu, 13 Jun 2019 08:21:02 -0700 (PDT) Received: from mita-MS-7A45.lan ([240f:34:212d:1:1b24:991b:df50:ea3f]) by smtp.gmail.com with ESMTPSA id n66sm40988pfn.52.2019.06.13.08.20.59 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 13 Jun 2019 08:21:02 -0700 (PDT) From: Akinobu Mita To: linux-nvme@lists.infradead.org, linux-pm@vger.kernel.org Cc: Akinobu Mita , Zhang Rui , Eduardo Valentin , Daniel Lezcano , Keith Busch , Jens Axboe , Christoph Hellwig , Sagi Grimberg , Minwoo Im , Kenneth Heitke , Chaitanya Kulkarni Subject: [PATCH v4 3/3] nvme: notify thermal framework when temperature threshold events occur Date: Fri, 14 Jun 2019 00:20:38 +0900 Message-Id: <1560439238-4054-4-git-send-email-akinobu.mita@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1560439238-4054-1-git-send-email-akinobu.mita@gmail.com> References: <1560439238-4054-1-git-send-email-akinobu.mita@gmail.com> Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The NVMe controller supports the temperature threshold feature (Feature Identifier 04h) that enables to configure the asynchronous event request command to complete when the temperature is crossed its corresponding temperature threshold. This enables the reporting of asynchronous events from the controller when the temperature reached or exceeded a temperature threshold. In the case of the temperature threshold conditions, this notifies the thermal framework. The main purpose of this is to turn on a fan when overheated without polling the device for the smart log that could prevent the lower power state transitions. Cc: Zhang Rui Cc: Eduardo Valentin Cc: Daniel Lezcano Cc: Keith Busch Cc: Jens Axboe Cc: Christoph Hellwig Cc: Sagi Grimberg Cc: Minwoo Im Cc: Kenneth Heitke Cc: Chaitanya Kulkarni Signed-off-by: Akinobu Mita --- * v4 - support DT thermal zone device. - use bitmap to iterate over implemented sensors drivers/nvme/host/core.c | 14 ++++++++++++++ drivers/nvme/host/nvme.h | 5 +++++ drivers/nvme/host/thermal.c | 12 ++++++++++++ include/linux/nvme.h | 7 +++++++ 4 files changed, 38 insertions(+) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 4be339b..44dadbb 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -1186,6 +1186,9 @@ static void nvme_enable_aen(struct nvme_ctrl *ctrl) u32 result, supported_aens = ctrl->oaes & NVME_AEN_SUPPORTED; int status; + if (IS_ENABLED(CONFIG_THERMAL)) + supported_aens |= NVME_SMART_CRIT_TEMPERATURE; + if (!supported_aens) return; @@ -3561,6 +3564,16 @@ void nvme_remove_namespaces(struct nvme_ctrl *ctrl) } EXPORT_SYMBOL_GPL(nvme_remove_namespaces); +static void nvme_handle_aen_smart(struct nvme_ctrl *ctrl, u32 result) +{ + u32 aer_type = result & NVME_AER_TYPE_MASK; + u32 aer_info = (result >> NVME_AER_INFO_SHIFT) & NVME_AER_INFO_MASK; + + if (aer_type == NVME_AER_SMART && + aer_info == NVME_AER_SMART_TEMP_THRESH) + nvme_thermal_notify_framework(ctrl); +} + static void nvme_aen_uevent(struct nvme_ctrl *ctrl) { char *envp[2] = { NULL, NULL }; @@ -3582,6 +3595,7 @@ static void nvme_async_event_work(struct work_struct *work) struct nvme_ctrl *ctrl = container_of(work, struct nvme_ctrl, async_event_work); + nvme_handle_aen_smart(ctrl, ctrl->aen_result); nvme_aen_uevent(ctrl); ctrl->ops->submit_async_event(ctrl); } diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index a9c63ea..40325b6 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -605,6 +605,7 @@ static inline struct nvme_ns *nvme_get_ns_from_dev(struct device *dev) int nvme_thermal_zones_register(struct nvme_ctrl *ctrl); void nvme_thermal_zones_unregister(struct nvme_ctrl *ctrl); +void nvme_thermal_notify_framework(struct nvme_ctrl *ctrl); #else @@ -617,6 +618,10 @@ static inline void nvme_thermal_zones_unregister(struct nvme_ctrl *ctrl) { } +static inline void nvme_thermal_notify_framework(struct nvme_ctrl *ctrl) +{ +} + #endif /* CONFIG_THERMAL */ #endif /* _NVME_H */ diff --git a/drivers/nvme/host/thermal.c b/drivers/nvme/host/thermal.c index 18d0e4c..b5e835d 100644 --- a/drivers/nvme/host/thermal.c +++ b/drivers/nvme/host/thermal.c @@ -309,3 +309,15 @@ void nvme_thermal_zones_unregister(struct nvme_ctrl *ctrl) __clear_bit(i, ctrl->tz_enabled); } } + +void nvme_thermal_notify_framework(struct nvme_ctrl *ctrl) +{ + int i; + + for_each_set_bit(i, ctrl->tz_enabled, ARRAY_SIZE(ctrl->tz)) { + if (ctrl->tz[i].dev) + thermal_notify_framework(ctrl->tz[i].dev, 0); + if (ctrl->tz[i].of_dev) + thermal_notify_framework(ctrl->tz[i].of_dev, 0); + } +} diff --git a/include/linux/nvme.h b/include/linux/nvme.h index f29728b..069b962 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -476,6 +476,7 @@ enum { }; enum { + NVME_AER_TYPE_MASK = 0x7, NVME_AER_ERROR = 0, NVME_AER_SMART = 1, NVME_AER_NOTICE = 2, @@ -484,6 +485,12 @@ enum { }; enum { + NVME_AER_INFO_SHIFT = 8, + NVME_AER_INFO_MASK = 0xff, + NVME_AER_SMART_TEMP_THRESH = 0x01, +}; + +enum { NVME_AER_NOTICE_NS_CHANGED = 0x00, NVME_AER_NOTICE_FW_ACT_STARTING = 0x01, NVME_AER_NOTICE_ANA = 0x03,