1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 // Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved
3
4 #include <linux/hwmon.h>
5 #include <linux/bitmap.h>
6 #include <linux/mlx5/device.h>
7 #include <linux/mlx5/mlx5_ifc.h>
8 #include <linux/mlx5/port.h>
9 #include "mlx5_core.h"
10 #include "hwmon.h"
11
12 #define CHANNELS_TYPE_NUM 2 /* chip channel and temp channel */
13 #define CHIP_CONFIG_NUM 1
14
15 /* module 0 is mapped to sensor_index 64 in MTMP register */
16 #define to_mtmp_module_sensor_idx(idx) (64 + (idx))
17
18 /* All temperatures retrieved in units of 0.125C. hwmon framework expect
19 * it in units of millidegrees C. Hence multiply values by 125.
20 */
21 #define mtmp_temp_to_mdeg(temp) ((temp) * 125)
22
23 struct temp_channel_desc {
24 u32 sensor_index;
25 char sensor_name[32];
26 };
27
28 /* chip_channel_config and channel_info arrays must be 0-terminated, hence + 1 */
29 struct mlx5_hwmon {
30 struct mlx5_core_dev *mdev;
31 struct device *hwmon_dev;
32 struct hwmon_channel_info chip_info;
33 u32 chip_channel_config[CHIP_CONFIG_NUM + 1];
34 struct hwmon_channel_info temp_info;
35 u32 *temp_channel_config;
36 const struct hwmon_channel_info *channel_info[CHANNELS_TYPE_NUM + 1];
37 struct hwmon_chip_info chip;
38 struct temp_channel_desc *temp_channel_desc;
39 u32 asic_platform_scount;
40 u32 module_scount;
41 };
42
mlx5_hwmon_query_mtmp(struct mlx5_core_dev * mdev,u32 sensor_index,u32 * mtmp_out)43 static int mlx5_hwmon_query_mtmp(struct mlx5_core_dev *mdev, u32 sensor_index, u32 *mtmp_out)
44 {
45 u32 mtmp_in[MLX5_ST_SZ_DW(mtmp_reg)] = {};
46
47 MLX5_SET(mtmp_reg, mtmp_in, sensor_index, sensor_index);
48
49 return mlx5_core_access_reg(mdev, mtmp_in, sizeof(mtmp_in),
50 mtmp_out, MLX5_ST_SZ_BYTES(mtmp_reg),
51 MLX5_REG_MTMP, 0, 0);
52 }
53
mlx5_hwmon_reset_max_temp(struct mlx5_core_dev * mdev,int sensor_index)54 static int mlx5_hwmon_reset_max_temp(struct mlx5_core_dev *mdev, int sensor_index)
55 {
56 u32 mtmp_out[MLX5_ST_SZ_DW(mtmp_reg)] = {};
57 u32 mtmp_in[MLX5_ST_SZ_DW(mtmp_reg)] = {};
58
59 MLX5_SET(mtmp_reg, mtmp_in, sensor_index, sensor_index);
60 MLX5_SET(mtmp_reg, mtmp_in, mtr, 1);
61
62 return mlx5_core_access_reg(mdev, mtmp_in, sizeof(mtmp_in),
63 mtmp_out, sizeof(mtmp_out),
64 MLX5_REG_MTMP, 0, 0);
65 }
66
mlx5_hwmon_enable_max_temp(struct mlx5_core_dev * mdev,int sensor_index)67 static int mlx5_hwmon_enable_max_temp(struct mlx5_core_dev *mdev, int sensor_index)
68 {
69 u32 mtmp_out[MLX5_ST_SZ_DW(mtmp_reg)] = {};
70 u32 mtmp_in[MLX5_ST_SZ_DW(mtmp_reg)] = {};
71 int err;
72
73 err = mlx5_hwmon_query_mtmp(mdev, sensor_index, mtmp_in);
74 if (err)
75 return err;
76
77 MLX5_SET(mtmp_reg, mtmp_in, mte, 1);
78 return mlx5_core_access_reg(mdev, mtmp_in, sizeof(mtmp_in),
79 mtmp_out, sizeof(mtmp_out),
80 MLX5_REG_MTMP, 0, 1);
81 }
82
mlx5_hwmon_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)83 static int mlx5_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
84 int channel, long *val)
85 {
86 struct mlx5_hwmon *hwmon = dev_get_drvdata(dev);
87 u32 mtmp_out[MLX5_ST_SZ_DW(mtmp_reg)] = {};
88 int err;
89
90 if (type != hwmon_temp)
91 return -EOPNOTSUPP;
92
93 err = mlx5_hwmon_query_mtmp(hwmon->mdev, hwmon->temp_channel_desc[channel].sensor_index,
94 mtmp_out);
95 if (err)
96 return err;
97
98 switch (attr) {
99 case hwmon_temp_input:
100 *val = mtmp_temp_to_mdeg(MLX5_GET(mtmp_reg, mtmp_out, temperature));
101 return 0;
102 case hwmon_temp_highest:
103 *val = mtmp_temp_to_mdeg(MLX5_GET(mtmp_reg, mtmp_out, max_temperature));
104 return 0;
105 case hwmon_temp_crit:
106 *val = mtmp_temp_to_mdeg(MLX5_GET(mtmp_reg, mtmp_out, temp_threshold_hi));
107 return 0;
108 default:
109 return -EOPNOTSUPP;
110 }
111 }
112
mlx5_hwmon_write(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long val)113 static int mlx5_hwmon_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
114 int channel, long val)
115 {
116 struct mlx5_hwmon *hwmon = dev_get_drvdata(dev);
117
118 if (type != hwmon_temp || attr != hwmon_temp_reset_history)
119 return -EOPNOTSUPP;
120
121 return mlx5_hwmon_reset_max_temp(hwmon->mdev,
122 hwmon->temp_channel_desc[channel].sensor_index);
123 }
124
mlx5_hwmon_is_visible(const void * data,enum hwmon_sensor_types type,u32 attr,int channel)125 static umode_t mlx5_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr,
126 int channel)
127 {
128 if (type != hwmon_temp)
129 return 0;
130
131 switch (attr) {
132 case hwmon_temp_input:
133 case hwmon_temp_highest:
134 case hwmon_temp_crit:
135 case hwmon_temp_label:
136 return 0444;
137 case hwmon_temp_reset_history:
138 return 0200;
139 default:
140 return 0;
141 }
142 }
143
mlx5_hwmon_read_string(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,const char ** str)144 static int mlx5_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,
145 int channel, const char **str)
146 {
147 struct mlx5_hwmon *hwmon = dev_get_drvdata(dev);
148
149 if (type != hwmon_temp || attr != hwmon_temp_label)
150 return -EOPNOTSUPP;
151
152 *str = (const char *)hwmon->temp_channel_desc[channel].sensor_name;
153 return 0;
154 }
155
156 static const struct hwmon_ops mlx5_hwmon_ops = {
157 .read = mlx5_hwmon_read,
158 .read_string = mlx5_hwmon_read_string,
159 .is_visible = mlx5_hwmon_is_visible,
160 .write = mlx5_hwmon_write,
161 };
162
mlx5_hwmon_init_channels_names(struct mlx5_hwmon * hwmon)163 static int mlx5_hwmon_init_channels_names(struct mlx5_hwmon *hwmon)
164 {
165 u32 i;
166
167 for (i = 0; i < hwmon->asic_platform_scount + hwmon->module_scount; i++) {
168 u32 mtmp_out[MLX5_ST_SZ_DW(mtmp_reg)] = {};
169 char *sensor_name;
170 int err;
171
172 err = mlx5_hwmon_query_mtmp(hwmon->mdev, hwmon->temp_channel_desc[i].sensor_index,
173 mtmp_out);
174 if (err)
175 return err;
176
177 sensor_name = MLX5_ADDR_OF(mtmp_reg, mtmp_out, sensor_name_hi);
178 if (!*sensor_name) {
179 snprintf(hwmon->temp_channel_desc[i].sensor_name,
180 sizeof(hwmon->temp_channel_desc[i].sensor_name), "sensor%u",
181 hwmon->temp_channel_desc[i].sensor_index);
182 continue;
183 }
184
185 memcpy(&hwmon->temp_channel_desc[i].sensor_name, sensor_name,
186 MLX5_FLD_SZ_BYTES(mtmp_reg, sensor_name_hi) +
187 MLX5_FLD_SZ_BYTES(mtmp_reg, sensor_name_lo));
188 }
189
190 return 0;
191 }
192
mlx5_hwmon_get_module_sensor_index(struct mlx5_core_dev * mdev,u32 * module_index)193 static int mlx5_hwmon_get_module_sensor_index(struct mlx5_core_dev *mdev, u32 *module_index)
194 {
195 int module_num;
196 int err;
197
198 err = mlx5_query_module_num(mdev, &module_num);
199 if (err)
200 return err;
201
202 *module_index = to_mtmp_module_sensor_idx(module_num);
203
204 return 0;
205 }
206
mlx5_hwmon_init_sensors_indexes(struct mlx5_hwmon * hwmon,u64 sensor_map)207 static int mlx5_hwmon_init_sensors_indexes(struct mlx5_hwmon *hwmon, u64 sensor_map)
208 {
209 DECLARE_BITMAP(smap, BITS_PER_TYPE(sensor_map));
210 unsigned long bit_pos;
211 int err = 0;
212 int i = 0;
213
214 bitmap_from_u64(smap, sensor_map);
215
216 for_each_set_bit(bit_pos, smap, BITS_PER_TYPE(sensor_map)) {
217 hwmon->temp_channel_desc[i].sensor_index = bit_pos;
218 i++;
219 }
220
221 if (hwmon->module_scount)
222 err = mlx5_hwmon_get_module_sensor_index(hwmon->mdev,
223 &hwmon->temp_channel_desc[i].sensor_index);
224
225 return err;
226 }
227
mlx5_hwmon_channel_info_init(struct mlx5_hwmon * hwmon)228 static void mlx5_hwmon_channel_info_init(struct mlx5_hwmon *hwmon)
229 {
230 int i;
231
232 hwmon->channel_info[0] = &hwmon->chip_info;
233 hwmon->channel_info[1] = &hwmon->temp_info;
234
235 hwmon->chip_channel_config[0] = HWMON_C_REGISTER_TZ;
236 hwmon->chip_info.config = (const u32 *)hwmon->chip_channel_config;
237 hwmon->chip_info.type = hwmon_chip;
238
239 for (i = 0; i < hwmon->asic_platform_scount + hwmon->module_scount; i++)
240 hwmon->temp_channel_config[i] = HWMON_T_INPUT | HWMON_T_HIGHEST | HWMON_T_CRIT |
241 HWMON_T_RESET_HISTORY | HWMON_T_LABEL;
242
243 hwmon->temp_info.config = (const u32 *)hwmon->temp_channel_config;
244 hwmon->temp_info.type = hwmon_temp;
245 }
246
mlx5_hwmon_is_module_mon_cap(struct mlx5_core_dev * mdev,bool * mon_cap)247 static int mlx5_hwmon_is_module_mon_cap(struct mlx5_core_dev *mdev, bool *mon_cap)
248 {
249 u32 mtmp_out[MLX5_ST_SZ_DW(mtmp_reg)];
250 u32 module_index;
251 int err;
252
253 err = mlx5_hwmon_get_module_sensor_index(mdev, &module_index);
254 if (err)
255 return err;
256
257 err = mlx5_hwmon_query_mtmp(mdev, module_index, mtmp_out);
258 if (err)
259 return err;
260
261 if (MLX5_GET(mtmp_reg, mtmp_out, temperature))
262 *mon_cap = true;
263
264 return 0;
265 }
266
mlx5_hwmon_get_sensors_count(struct mlx5_core_dev * mdev,u32 * asic_platform_scount)267 static int mlx5_hwmon_get_sensors_count(struct mlx5_core_dev *mdev, u32 *asic_platform_scount)
268 {
269 u32 mtcap_out[MLX5_ST_SZ_DW(mtcap_reg)] = {};
270 u32 mtcap_in[MLX5_ST_SZ_DW(mtcap_reg)] = {};
271 int err;
272
273 err = mlx5_core_access_reg(mdev, mtcap_in, sizeof(mtcap_in),
274 mtcap_out, sizeof(mtcap_out),
275 MLX5_REG_MTCAP, 0, 0);
276 if (err)
277 return err;
278
279 *asic_platform_scount = MLX5_GET(mtcap_reg, mtcap_out, sensor_count);
280
281 return 0;
282 }
283
mlx5_hwmon_free(struct mlx5_hwmon * hwmon)284 static void mlx5_hwmon_free(struct mlx5_hwmon *hwmon)
285 {
286 if (!hwmon)
287 return;
288
289 kfree(hwmon->temp_channel_config);
290 kfree(hwmon->temp_channel_desc);
291 kfree(hwmon);
292 }
293
mlx5_hwmon_alloc(struct mlx5_core_dev * mdev)294 static struct mlx5_hwmon *mlx5_hwmon_alloc(struct mlx5_core_dev *mdev)
295 {
296 struct mlx5_hwmon *hwmon;
297 bool mon_cap = false;
298 u32 sensors_count;
299 int err;
300
301 hwmon = kzalloc(sizeof(*mdev->hwmon), GFP_KERNEL);
302 if (!hwmon)
303 return ERR_PTR(-ENOMEM);
304
305 err = mlx5_hwmon_get_sensors_count(mdev, &hwmon->asic_platform_scount);
306 if (err)
307 goto err_free_hwmon;
308
309 /* check if module sensor has thermal mon cap. if yes, allocate channel desc for it */
310 err = mlx5_hwmon_is_module_mon_cap(mdev, &mon_cap);
311 if (err)
312 goto err_free_hwmon;
313
314 hwmon->module_scount = mon_cap ? 1 : 0;
315 sensors_count = hwmon->asic_platform_scount + hwmon->module_scount;
316 hwmon->temp_channel_desc = kcalloc(sensors_count, sizeof(*hwmon->temp_channel_desc),
317 GFP_KERNEL);
318 if (!hwmon->temp_channel_desc) {
319 err = -ENOMEM;
320 goto err_free_hwmon;
321 }
322
323 /* sensors configuration values array, must be 0-terminated hence, + 1 */
324 hwmon->temp_channel_config = kcalloc(sensors_count + 1, sizeof(*hwmon->temp_channel_config),
325 GFP_KERNEL);
326 if (!hwmon->temp_channel_config) {
327 err = -ENOMEM;
328 goto err_free_temp_channel_desc;
329 }
330
331 hwmon->mdev = mdev;
332
333 return hwmon;
334
335 err_free_temp_channel_desc:
336 kfree(hwmon->temp_channel_desc);
337 err_free_hwmon:
338 kfree(hwmon);
339 return ERR_PTR(err);
340 }
341
mlx5_hwmon_dev_init(struct mlx5_hwmon * hwmon)342 static int mlx5_hwmon_dev_init(struct mlx5_hwmon *hwmon)
343 {
344 u32 mtcap_out[MLX5_ST_SZ_DW(mtcap_reg)] = {};
345 u32 mtcap_in[MLX5_ST_SZ_DW(mtcap_reg)] = {};
346 int err;
347 int i;
348
349 err = mlx5_core_access_reg(hwmon->mdev, mtcap_in, sizeof(mtcap_in),
350 mtcap_out, sizeof(mtcap_out),
351 MLX5_REG_MTCAP, 0, 0);
352 if (err)
353 return err;
354
355 mlx5_hwmon_channel_info_init(hwmon);
356 mlx5_hwmon_init_sensors_indexes(hwmon, MLX5_GET64(mtcap_reg, mtcap_out, sensor_map));
357 err = mlx5_hwmon_init_channels_names(hwmon);
358 if (err)
359 return err;
360
361 for (i = 0; i < hwmon->asic_platform_scount + hwmon->module_scount; i++) {
362 err = mlx5_hwmon_enable_max_temp(hwmon->mdev,
363 hwmon->temp_channel_desc[i].sensor_index);
364 if (err)
365 return err;
366 }
367
368 hwmon->chip.ops = &mlx5_hwmon_ops;
369 hwmon->chip.info = (const struct hwmon_channel_info **)hwmon->channel_info;
370
371 return 0;
372 }
373
mlx5_hwmon_dev_register(struct mlx5_core_dev * mdev)374 int mlx5_hwmon_dev_register(struct mlx5_core_dev *mdev)
375 {
376 struct device *dev = mdev->device;
377 struct mlx5_hwmon *hwmon;
378 int err;
379
380 if (!MLX5_CAP_MCAM_REG(mdev, mtmp))
381 return 0;
382
383 hwmon = mlx5_hwmon_alloc(mdev);
384 if (IS_ERR(hwmon))
385 return PTR_ERR(hwmon);
386
387 err = mlx5_hwmon_dev_init(hwmon);
388 if (err)
389 goto err_free_hwmon;
390
391 hwmon->hwmon_dev = hwmon_device_register_with_info(dev, "mlx5",
392 hwmon,
393 &hwmon->chip,
394 NULL);
395 if (IS_ERR(hwmon->hwmon_dev)) {
396 err = PTR_ERR(hwmon->hwmon_dev);
397 goto err_free_hwmon;
398 }
399
400 mdev->hwmon = hwmon;
401 return 0;
402
403 err_free_hwmon:
404 mlx5_hwmon_free(hwmon);
405 return err;
406 }
407
mlx5_hwmon_dev_unregister(struct mlx5_core_dev * mdev)408 void mlx5_hwmon_dev_unregister(struct mlx5_core_dev *mdev)
409 {
410 struct mlx5_hwmon *hwmon = mdev->hwmon;
411
412 if (!hwmon)
413 return;
414
415 hwmon_device_unregister(hwmon->hwmon_dev);
416 mlx5_hwmon_free(hwmon);
417 mdev->hwmon = NULL;
418 }
419