Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * NVM Express hardware monitoring support
0004  * Copyright (c) 2019, Guenter Roeck
0005  */
0006 
0007 #include <linux/hwmon.h>
0008 #include <linux/units.h>
0009 #include <asm/unaligned.h>
0010 
0011 #include "nvme.h"
0012 
0013 struct nvme_hwmon_data {
0014     struct nvme_ctrl *ctrl;
0015     struct nvme_smart_log log;
0016     struct mutex read_lock;
0017 };
0018 
0019 static int nvme_get_temp_thresh(struct nvme_ctrl *ctrl, int sensor, bool under,
0020                 long *temp)
0021 {
0022     unsigned int threshold = sensor << NVME_TEMP_THRESH_SELECT_SHIFT;
0023     u32 status;
0024     int ret;
0025 
0026     if (under)
0027         threshold |= NVME_TEMP_THRESH_TYPE_UNDER;
0028 
0029     ret = nvme_get_features(ctrl, NVME_FEAT_TEMP_THRESH, threshold, NULL, 0,
0030                 &status);
0031     if (ret > 0)
0032         return -EIO;
0033     if (ret < 0)
0034         return ret;
0035     *temp = kelvin_to_millicelsius(status & NVME_TEMP_THRESH_MASK);
0036 
0037     return 0;
0038 }
0039 
0040 static int nvme_set_temp_thresh(struct nvme_ctrl *ctrl, int sensor, bool under,
0041                 long temp)
0042 {
0043     unsigned int threshold = sensor << NVME_TEMP_THRESH_SELECT_SHIFT;
0044     int ret;
0045 
0046     temp = millicelsius_to_kelvin(temp);
0047     threshold |= clamp_val(temp, 0, NVME_TEMP_THRESH_MASK);
0048 
0049     if (under)
0050         threshold |= NVME_TEMP_THRESH_TYPE_UNDER;
0051 
0052     ret = nvme_set_features(ctrl, NVME_FEAT_TEMP_THRESH, threshold, NULL, 0,
0053                 NULL);
0054     if (ret > 0)
0055         return -EIO;
0056 
0057     return ret;
0058 }
0059 
0060 static int nvme_hwmon_get_smart_log(struct nvme_hwmon_data *data)
0061 {
0062     return nvme_get_log(data->ctrl, NVME_NSID_ALL, NVME_LOG_SMART, 0,
0063                NVME_CSI_NVM, &data->log, sizeof(data->log), 0);
0064 }
0065 
0066 static int nvme_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
0067                u32 attr, int channel, long *val)
0068 {
0069     struct nvme_hwmon_data *data = dev_get_drvdata(dev);
0070     struct nvme_smart_log *log = &data->log;
0071     int temp;
0072     int err;
0073 
0074     /*
0075      * First handle attributes which don't require us to read
0076      * the smart log.
0077      */
0078     switch (attr) {
0079     case hwmon_temp_max:
0080         return nvme_get_temp_thresh(data->ctrl, channel, false, val);
0081     case hwmon_temp_min:
0082         return nvme_get_temp_thresh(data->ctrl, channel, true, val);
0083     case hwmon_temp_crit:
0084         *val = kelvin_to_millicelsius(data->ctrl->cctemp);
0085         return 0;
0086     default:
0087         break;
0088     }
0089 
0090     mutex_lock(&data->read_lock);
0091     err = nvme_hwmon_get_smart_log(data);
0092     if (err)
0093         goto unlock;
0094 
0095     switch (attr) {
0096     case hwmon_temp_input:
0097         if (!channel)
0098             temp = get_unaligned_le16(log->temperature);
0099         else
0100             temp = le16_to_cpu(log->temp_sensor[channel - 1]);
0101         *val = kelvin_to_millicelsius(temp);
0102         break;
0103     case hwmon_temp_alarm:
0104         *val = !!(log->critical_warning & NVME_SMART_CRIT_TEMPERATURE);
0105         break;
0106     default:
0107         err = -EOPNOTSUPP;
0108         break;
0109     }
0110 unlock:
0111     mutex_unlock(&data->read_lock);
0112     return err;
0113 }
0114 
0115 static int nvme_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
0116                 u32 attr, int channel, long val)
0117 {
0118     struct nvme_hwmon_data *data = dev_get_drvdata(dev);
0119 
0120     switch (attr) {
0121     case hwmon_temp_max:
0122         return nvme_set_temp_thresh(data->ctrl, channel, false, val);
0123     case hwmon_temp_min:
0124         return nvme_set_temp_thresh(data->ctrl, channel, true, val);
0125     default:
0126         break;
0127     }
0128 
0129     return -EOPNOTSUPP;
0130 }
0131 
0132 static const char * const nvme_hwmon_sensor_names[] = {
0133     "Composite",
0134     "Sensor 1",
0135     "Sensor 2",
0136     "Sensor 3",
0137     "Sensor 4",
0138     "Sensor 5",
0139     "Sensor 6",
0140     "Sensor 7",
0141     "Sensor 8",
0142 };
0143 
0144 static int nvme_hwmon_read_string(struct device *dev,
0145                   enum hwmon_sensor_types type, u32 attr,
0146                   int channel, const char **str)
0147 {
0148     *str = nvme_hwmon_sensor_names[channel];
0149     return 0;
0150 }
0151 
0152 static umode_t nvme_hwmon_is_visible(const void *_data,
0153                      enum hwmon_sensor_types type,
0154                      u32 attr, int channel)
0155 {
0156     const struct nvme_hwmon_data *data = _data;
0157 
0158     switch (attr) {
0159     case hwmon_temp_crit:
0160         if (!channel && data->ctrl->cctemp)
0161             return 0444;
0162         break;
0163     case hwmon_temp_max:
0164     case hwmon_temp_min:
0165         if ((!channel && data->ctrl->wctemp) ||
0166             (channel && data->log.temp_sensor[channel - 1])) {
0167             if (data->ctrl->quirks &
0168                 NVME_QUIRK_NO_TEMP_THRESH_CHANGE)
0169                 return 0444;
0170             return 0644;
0171         }
0172         break;
0173     case hwmon_temp_alarm:
0174         if (!channel)
0175             return 0444;
0176         break;
0177     case hwmon_temp_input:
0178     case hwmon_temp_label:
0179         if (!channel || data->log.temp_sensor[channel - 1])
0180             return 0444;
0181         break;
0182     default:
0183         break;
0184     }
0185     return 0;
0186 }
0187 
0188 static const struct hwmon_channel_info *nvme_hwmon_info[] = {
0189     HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
0190     HWMON_CHANNEL_INFO(temp,
0191                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
0192                 HWMON_T_CRIT | HWMON_T_LABEL | HWMON_T_ALARM,
0193                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
0194                 HWMON_T_LABEL,
0195                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
0196                 HWMON_T_LABEL,
0197                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
0198                 HWMON_T_LABEL,
0199                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
0200                 HWMON_T_LABEL,
0201                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
0202                 HWMON_T_LABEL,
0203                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
0204                 HWMON_T_LABEL,
0205                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
0206                 HWMON_T_LABEL,
0207                HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
0208                 HWMON_T_LABEL),
0209     NULL
0210 };
0211 
0212 static const struct hwmon_ops nvme_hwmon_ops = {
0213     .is_visible = nvme_hwmon_is_visible,
0214     .read       = nvme_hwmon_read,
0215     .read_string    = nvme_hwmon_read_string,
0216     .write      = nvme_hwmon_write,
0217 };
0218 
0219 static const struct hwmon_chip_info nvme_hwmon_chip_info = {
0220     .ops    = &nvme_hwmon_ops,
0221     .info   = nvme_hwmon_info,
0222 };
0223 
0224 int nvme_hwmon_init(struct nvme_ctrl *ctrl)
0225 {
0226     struct device *dev = ctrl->device;
0227     struct nvme_hwmon_data *data;
0228     struct device *hwmon;
0229     int err;
0230 
0231     data = kzalloc(sizeof(*data), GFP_KERNEL);
0232     if (!data)
0233         return 0;
0234 
0235     data->ctrl = ctrl;
0236     mutex_init(&data->read_lock);
0237 
0238     err = nvme_hwmon_get_smart_log(data);
0239     if (err) {
0240         dev_warn(dev, "Failed to read smart log (error %d)\n", err);
0241         kfree(data);
0242         return err;
0243     }
0244 
0245     hwmon = hwmon_device_register_with_info(dev, "nvme",
0246                         data, &nvme_hwmon_chip_info,
0247                         NULL);
0248     if (IS_ERR(hwmon)) {
0249         dev_warn(dev, "Failed to instantiate hwmon device\n");
0250         kfree(data);
0251         return PTR_ERR(hwmon);
0252     }
0253     ctrl->hwmon_device = hwmon;
0254     return 0;
0255 }
0256 
0257 void nvme_hwmon_exit(struct nvme_ctrl *ctrl)
0258 {
0259     if (ctrl->hwmon_device) {
0260         struct nvme_hwmon_data *data =
0261             dev_get_drvdata(ctrl->hwmon_device);
0262 
0263         hwmon_device_unregister(ctrl->hwmon_device);
0264         ctrl->hwmon_device = NULL;
0265         kfree(data);
0266     }
0267 }