]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[mirror_ubuntu-jammy-kernel.git] / drivers / net / ethernet / mellanox / mlxsw / core_hwmon.c
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */
3
4 #include <linux/kernel.h>
5 #include <linux/types.h>
6 #include <linux/device.h>
7 #include <linux/sysfs.h>
8 #include <linux/hwmon.h>
9 #include <linux/err.h>
10 #include <linux/sfp.h>
11
12 #include "core.h"
13 #include "core_env.h"
14
15 #define MLXSW_HWMON_TEMP_SENSOR_MAX_COUNT 127
16 #define MLXSW_HWMON_ATTR_COUNT (MLXSW_HWMON_TEMP_SENSOR_MAX_COUNT * 4 + \
17 MLXSW_MFCR_TACHOS_MAX + MLXSW_MFCR_PWMS_MAX)
18
19 struct mlxsw_hwmon_attr {
20 struct device_attribute dev_attr;
21 struct mlxsw_hwmon *hwmon;
22 unsigned int type_index;
23 char name[32];
24 };
25
26 static int mlxsw_hwmon_get_attr_index(int index, int count)
27 {
28 if (index >= count)
29 return index % count + MLXSW_REG_MTMP_GBOX_INDEX_MIN;
30
31 return index;
32 }
33
34 struct mlxsw_hwmon {
35 struct mlxsw_core *core;
36 const struct mlxsw_bus_info *bus_info;
37 struct device *hwmon_dev;
38 struct attribute_group group;
39 const struct attribute_group *groups[2];
40 struct attribute *attrs[MLXSW_HWMON_ATTR_COUNT + 1];
41 struct mlxsw_hwmon_attr hwmon_attrs[MLXSW_HWMON_ATTR_COUNT];
42 unsigned int attrs_count;
43 u8 sensor_count;
44 u8 module_sensor_max;
45 };
46
47 static ssize_t mlxsw_hwmon_temp_show(struct device *dev,
48 struct device_attribute *attr,
49 char *buf)
50 {
51 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
52 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
53 struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
54 char mtmp_pl[MLXSW_REG_MTMP_LEN];
55 int temp, index;
56 int err;
57
58 index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index,
59 mlxsw_hwmon->module_sensor_max);
60 mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false);
61 err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
62 if (err) {
63 dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n");
64 return err;
65 }
66 mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL);
67 return sprintf(buf, "%d\n", temp);
68 }
69
70 static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev,
71 struct device_attribute *attr,
72 char *buf)
73 {
74 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
75 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
76 struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
77 char mtmp_pl[MLXSW_REG_MTMP_LEN];
78 int temp_max, index;
79 int err;
80
81 index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index,
82 mlxsw_hwmon->module_sensor_max);
83 mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false);
84 err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
85 if (err) {
86 dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n");
87 return err;
88 }
89 mlxsw_reg_mtmp_unpack(mtmp_pl, NULL, &temp_max, NULL);
90 return sprintf(buf, "%d\n", temp_max);
91 }
92
93 static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev,
94 struct device_attribute *attr,
95 const char *buf, size_t len)
96 {
97 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
98 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
99 struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
100 char mtmp_pl[MLXSW_REG_MTMP_LEN];
101 unsigned long val;
102 int index;
103 int err;
104
105 err = kstrtoul(buf, 10, &val);
106 if (err)
107 return err;
108 if (val != 1)
109 return -EINVAL;
110
111 index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index,
112 mlxsw_hwmon->module_sensor_max);
113 mlxsw_reg_mtmp_pack(mtmp_pl, index, true, true);
114 err = mlxsw_reg_write(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
115 if (err) {
116 dev_err(mlxsw_hwmon->bus_info->dev, "Failed to reset temp sensor history\n");
117 return err;
118 }
119 return len;
120 }
121
122 static ssize_t mlxsw_hwmon_fan_rpm_show(struct device *dev,
123 struct device_attribute *attr,
124 char *buf)
125 {
126 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
127 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
128 struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
129 char mfsm_pl[MLXSW_REG_MFSM_LEN];
130 int err;
131
132 mlxsw_reg_mfsm_pack(mfsm_pl, mlwsw_hwmon_attr->type_index);
133 err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mfsm), mfsm_pl);
134 if (err) {
135 dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query fan\n");
136 return err;
137 }
138 return sprintf(buf, "%u\n", mlxsw_reg_mfsm_rpm_get(mfsm_pl));
139 }
140
141 static ssize_t mlxsw_hwmon_fan_fault_show(struct device *dev,
142 struct device_attribute *attr,
143 char *buf)
144 {
145 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
146 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
147 struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
148 char fore_pl[MLXSW_REG_FORE_LEN];
149 bool fault;
150 int err;
151
152 err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(fore), fore_pl);
153 if (err) {
154 dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query fan\n");
155 return err;
156 }
157 mlxsw_reg_fore_unpack(fore_pl, mlwsw_hwmon_attr->type_index, &fault);
158
159 return sprintf(buf, "%u\n", fault);
160 }
161
162 static ssize_t mlxsw_hwmon_pwm_show(struct device *dev,
163 struct device_attribute *attr,
164 char *buf)
165 {
166 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
167 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
168 struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
169 char mfsc_pl[MLXSW_REG_MFSC_LEN];
170 int err;
171
172 mlxsw_reg_mfsc_pack(mfsc_pl, mlwsw_hwmon_attr->type_index, 0);
173 err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mfsc), mfsc_pl);
174 if (err) {
175 dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query PWM\n");
176 return err;
177 }
178 return sprintf(buf, "%u\n",
179 mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl));
180 }
181
182 static ssize_t mlxsw_hwmon_pwm_store(struct device *dev,
183 struct device_attribute *attr,
184 const char *buf, size_t len)
185 {
186 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
187 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
188 struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
189 char mfsc_pl[MLXSW_REG_MFSC_LEN];
190 unsigned long val;
191 int err;
192
193 err = kstrtoul(buf, 10, &val);
194 if (err)
195 return err;
196 if (val > 255)
197 return -EINVAL;
198
199 mlxsw_reg_mfsc_pack(mfsc_pl, mlwsw_hwmon_attr->type_index, val);
200 err = mlxsw_reg_write(mlxsw_hwmon->core, MLXSW_REG(mfsc), mfsc_pl);
201 if (err) {
202 dev_err(mlxsw_hwmon->bus_info->dev, "Failed to write PWM\n");
203 return err;
204 }
205 return len;
206 }
207
208 static ssize_t mlxsw_hwmon_module_temp_show(struct device *dev,
209 struct device_attribute *attr,
210 char *buf)
211 {
212 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
213 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
214 struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
215 char mtmp_pl[MLXSW_REG_MTMP_LEN];
216 u8 module;
217 int temp;
218 int err;
219
220 module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count;
221 mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN + module,
222 false, false);
223 err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
224 if (err)
225 return err;
226 mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL);
227
228 return sprintf(buf, "%d\n", temp);
229 }
230
231 static ssize_t mlxsw_hwmon_module_temp_fault_show(struct device *dev,
232 struct device_attribute *attr,
233 char *buf)
234 {
235 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
236 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
237 struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
238 char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0};
239 u8 module, fault;
240 u16 temp;
241 int err;
242
243 module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count;
244 mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module,
245 1);
246 err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl);
247 if (err) {
248 dev_err(dev, "Failed to query module temperature sensor\n");
249 return err;
250 }
251
252 mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL);
253
254 /* Update status and temperature cache. */
255 switch (temp) {
256 case MLXSW_REG_MTBR_BAD_SENS_INFO:
257 /* Untrusted cable is connected. Reading temperature from its
258 * sensor is faulty.
259 */
260 fault = 1;
261 break;
262 case MLXSW_REG_MTBR_NO_CONN: /* fall-through */
263 case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */
264 case MLXSW_REG_MTBR_INDEX_NA:
265 default:
266 fault = 0;
267 break;
268 }
269
270 return sprintf(buf, "%u\n", fault);
271 }
272
273 static ssize_t
274 mlxsw_hwmon_module_temp_critical_show(struct device *dev,
275 struct device_attribute *attr, char *buf)
276 {
277 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
278 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
279 struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
280 int temp;
281 u8 module;
282 int err;
283
284 module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count;
285 err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module,
286 SFP_TEMP_HIGH_WARN, &temp);
287 if (err) {
288 dev_err(dev, "Failed to query module temperature thresholds\n");
289 return err;
290 }
291
292 return sprintf(buf, "%u\n", temp);
293 }
294
295 static ssize_t
296 mlxsw_hwmon_module_temp_emergency_show(struct device *dev,
297 struct device_attribute *attr,
298 char *buf)
299 {
300 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
301 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
302 struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
303 u8 module;
304 int temp;
305 int err;
306
307 module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count;
308 err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module,
309 SFP_TEMP_HIGH_ALARM, &temp);
310 if (err) {
311 dev_err(dev, "Failed to query module temperature thresholds\n");
312 return err;
313 }
314
315 return sprintf(buf, "%u\n", temp);
316 }
317
318 static ssize_t
319 mlxsw_hwmon_module_temp_label_show(struct device *dev,
320 struct device_attribute *attr,
321 char *buf)
322 {
323 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
324 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
325
326 return sprintf(buf, "front panel %03u\n",
327 mlwsw_hwmon_attr->type_index);
328 }
329
330 static ssize_t
331 mlxsw_hwmon_gbox_temp_label_show(struct device *dev,
332 struct device_attribute *attr,
333 char *buf)
334 {
335 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
336 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
337 struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
338 int index = mlwsw_hwmon_attr->type_index -
339 mlxsw_hwmon->module_sensor_max + 1;
340
341 return sprintf(buf, "gearbox %03u\n", index);
342 }
343
344 enum mlxsw_hwmon_attr_type {
345 MLXSW_HWMON_ATTR_TYPE_TEMP,
346 MLXSW_HWMON_ATTR_TYPE_TEMP_MAX,
347 MLXSW_HWMON_ATTR_TYPE_TEMP_RST,
348 MLXSW_HWMON_ATTR_TYPE_FAN_RPM,
349 MLXSW_HWMON_ATTR_TYPE_FAN_FAULT,
350 MLXSW_HWMON_ATTR_TYPE_PWM,
351 MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE,
352 MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT,
353 MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT,
354 MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG,
355 MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL,
356 MLXSW_HWMON_ATTR_TYPE_TEMP_GBOX_LABEL,
357 };
358
359 static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon,
360 enum mlxsw_hwmon_attr_type attr_type,
361 unsigned int type_index, unsigned int num) {
362 struct mlxsw_hwmon_attr *mlxsw_hwmon_attr;
363 unsigned int attr_index;
364
365 attr_index = mlxsw_hwmon->attrs_count;
366 mlxsw_hwmon_attr = &mlxsw_hwmon->hwmon_attrs[attr_index];
367
368 switch (attr_type) {
369 case MLXSW_HWMON_ATTR_TYPE_TEMP:
370 mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_temp_show;
371 mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
372 snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
373 "temp%u_input", num + 1);
374 break;
375 case MLXSW_HWMON_ATTR_TYPE_TEMP_MAX:
376 mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_temp_max_show;
377 mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
378 snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
379 "temp%u_highest", num + 1);
380 break;
381 case MLXSW_HWMON_ATTR_TYPE_TEMP_RST:
382 mlxsw_hwmon_attr->dev_attr.store = mlxsw_hwmon_temp_rst_store;
383 mlxsw_hwmon_attr->dev_attr.attr.mode = 0200;
384 snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
385 "temp%u_reset_history", num + 1);
386 break;
387 case MLXSW_HWMON_ATTR_TYPE_FAN_RPM:
388 mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_fan_rpm_show;
389 mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
390 snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
391 "fan%u_input", num + 1);
392 break;
393 case MLXSW_HWMON_ATTR_TYPE_FAN_FAULT:
394 mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_fan_fault_show;
395 mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
396 snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
397 "fan%u_fault", num + 1);
398 break;
399 case MLXSW_HWMON_ATTR_TYPE_PWM:
400 mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_pwm_show;
401 mlxsw_hwmon_attr->dev_attr.store = mlxsw_hwmon_pwm_store;
402 mlxsw_hwmon_attr->dev_attr.attr.mode = 0644;
403 snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
404 "pwm%u", num + 1);
405 break;
406 case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE:
407 mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_module_temp_show;
408 mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
409 snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
410 "temp%u_input", num + 1);
411 break;
412 case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT:
413 mlxsw_hwmon_attr->dev_attr.show =
414 mlxsw_hwmon_module_temp_fault_show;
415 mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
416 snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
417 "temp%u_fault", num + 1);
418 break;
419 case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT:
420 mlxsw_hwmon_attr->dev_attr.show =
421 mlxsw_hwmon_module_temp_critical_show;
422 mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
423 snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
424 "temp%u_crit", num + 1);
425 break;
426 case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG:
427 mlxsw_hwmon_attr->dev_attr.show =
428 mlxsw_hwmon_module_temp_emergency_show;
429 mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
430 snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
431 "temp%u_emergency", num + 1);
432 break;
433 case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL:
434 mlxsw_hwmon_attr->dev_attr.show =
435 mlxsw_hwmon_module_temp_label_show;
436 mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
437 snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
438 "temp%u_label", num + 1);
439 break;
440 case MLXSW_HWMON_ATTR_TYPE_TEMP_GBOX_LABEL:
441 mlxsw_hwmon_attr->dev_attr.show =
442 mlxsw_hwmon_gbox_temp_label_show;
443 mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
444 snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
445 "temp%u_label", num + 1);
446 break;
447 default:
448 WARN_ON(1);
449 }
450
451 mlxsw_hwmon_attr->type_index = type_index;
452 mlxsw_hwmon_attr->hwmon = mlxsw_hwmon;
453 mlxsw_hwmon_attr->dev_attr.attr.name = mlxsw_hwmon_attr->name;
454 sysfs_attr_init(&mlxsw_hwmon_attr->dev_attr.attr);
455
456 mlxsw_hwmon->attrs[attr_index] = &mlxsw_hwmon_attr->dev_attr.attr;
457 mlxsw_hwmon->attrs_count++;
458 }
459
460 static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon *mlxsw_hwmon)
461 {
462 char mtcap_pl[MLXSW_REG_MTCAP_LEN] = {0};
463 char mtmp_pl[MLXSW_REG_MTMP_LEN];
464 int i;
465 int err;
466
467 err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtcap), mtcap_pl);
468 if (err) {
469 dev_err(mlxsw_hwmon->bus_info->dev, "Failed to get number of temp sensors\n");
470 return err;
471 }
472 mlxsw_hwmon->sensor_count = mlxsw_reg_mtcap_sensor_count_get(mtcap_pl);
473 for (i = 0; i < mlxsw_hwmon->sensor_count; i++) {
474 mlxsw_reg_mtmp_pack(mtmp_pl, i, true, true);
475 err = mlxsw_reg_write(mlxsw_hwmon->core,
476 MLXSW_REG(mtmp), mtmp_pl);
477 if (err) {
478 dev_err(mlxsw_hwmon->bus_info->dev, "Failed to setup temp sensor number %d\n",
479 i);
480 return err;
481 }
482 mlxsw_hwmon_attr_add(mlxsw_hwmon,
483 MLXSW_HWMON_ATTR_TYPE_TEMP, i, i);
484 mlxsw_hwmon_attr_add(mlxsw_hwmon,
485 MLXSW_HWMON_ATTR_TYPE_TEMP_MAX, i, i);
486 mlxsw_hwmon_attr_add(mlxsw_hwmon,
487 MLXSW_HWMON_ATTR_TYPE_TEMP_RST, i, i);
488 }
489 return 0;
490 }
491
492 static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon)
493 {
494 char mfcr_pl[MLXSW_REG_MFCR_LEN] = {0};
495 enum mlxsw_reg_mfcr_pwm_frequency freq;
496 unsigned int type_index;
497 unsigned int num;
498 u16 tacho_active;
499 u8 pwm_active;
500 int err;
501
502 err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mfcr), mfcr_pl);
503 if (err) {
504 dev_err(mlxsw_hwmon->bus_info->dev, "Failed to get to probe PWMs and Tachometers\n");
505 return err;
506 }
507 mlxsw_reg_mfcr_unpack(mfcr_pl, &freq, &tacho_active, &pwm_active);
508 num = 0;
509 for (type_index = 0; type_index < MLXSW_MFCR_TACHOS_MAX; type_index++) {
510 if (tacho_active & BIT(type_index)) {
511 mlxsw_hwmon_attr_add(mlxsw_hwmon,
512 MLXSW_HWMON_ATTR_TYPE_FAN_RPM,
513 type_index, num);
514 mlxsw_hwmon_attr_add(mlxsw_hwmon,
515 MLXSW_HWMON_ATTR_TYPE_FAN_FAULT,
516 type_index, num++);
517 }
518 }
519 num = 0;
520 for (type_index = 0; type_index < MLXSW_MFCR_PWMS_MAX; type_index++) {
521 if (pwm_active & BIT(type_index))
522 mlxsw_hwmon_attr_add(mlxsw_hwmon,
523 MLXSW_HWMON_ATTR_TYPE_PWM,
524 type_index, num++);
525 }
526 return 0;
527 }
528
529 static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon)
530 {
531 char mgpir_pl[MLXSW_REG_MGPIR_LEN];
532 u8 module_sensor_max;
533 int i, err;
534
535 if (!mlxsw_core_res_query_enabled(mlxsw_hwmon->core))
536 return 0;
537
538 mlxsw_reg_mgpir_pack(mgpir_pl);
539 err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mgpir), mgpir_pl);
540 if (err)
541 return err;
542
543 mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL,
544 &module_sensor_max);
545
546 /* Add extra attributes for module temperature. Sensor index is
547 * assigned to sensor_count value, while all indexed before
548 * sensor_count are already utilized by the sensors connected through
549 * mtmp register by mlxsw_hwmon_temp_init().
550 */
551 mlxsw_hwmon->module_sensor_max = mlxsw_hwmon->sensor_count +
552 module_sensor_max;
553 for (i = mlxsw_hwmon->sensor_count;
554 i < mlxsw_hwmon->module_sensor_max; i++) {
555 mlxsw_hwmon_attr_add(mlxsw_hwmon,
556 MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE, i, i);
557 mlxsw_hwmon_attr_add(mlxsw_hwmon,
558 MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT,
559 i, i);
560 mlxsw_hwmon_attr_add(mlxsw_hwmon,
561 MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT, i,
562 i);
563 mlxsw_hwmon_attr_add(mlxsw_hwmon,
564 MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG,
565 i, i);
566 mlxsw_hwmon_attr_add(mlxsw_hwmon,
567 MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL,
568 i, i);
569 }
570
571 return 0;
572 }
573
574 static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon)
575 {
576 int index, max_index, sensor_index;
577 char mgpir_pl[MLXSW_REG_MGPIR_LEN];
578 char mtmp_pl[MLXSW_REG_MTMP_LEN];
579 u8 gbox_num;
580 int err;
581
582 mlxsw_reg_mgpir_pack(mgpir_pl);
583 err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mgpir), mgpir_pl);
584 if (err)
585 return err;
586
587 mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, NULL, NULL, NULL);
588 if (!gbox_num)
589 return 0;
590
591 index = mlxsw_hwmon->module_sensor_max;
592 max_index = mlxsw_hwmon->module_sensor_max + gbox_num;
593 while (index < max_index) {
594 sensor_index = index % mlxsw_hwmon->module_sensor_max +
595 MLXSW_REG_MTMP_GBOX_INDEX_MIN;
596 mlxsw_reg_mtmp_pack(mtmp_pl, sensor_index, true, true);
597 err = mlxsw_reg_write(mlxsw_hwmon->core,
598 MLXSW_REG(mtmp), mtmp_pl);
599 if (err) {
600 dev_err(mlxsw_hwmon->bus_info->dev, "Failed to setup temp sensor number %d\n",
601 sensor_index);
602 return err;
603 }
604 mlxsw_hwmon_attr_add(mlxsw_hwmon, MLXSW_HWMON_ATTR_TYPE_TEMP,
605 index, index);
606 mlxsw_hwmon_attr_add(mlxsw_hwmon,
607 MLXSW_HWMON_ATTR_TYPE_TEMP_MAX, index,
608 index);
609 mlxsw_hwmon_attr_add(mlxsw_hwmon,
610 MLXSW_HWMON_ATTR_TYPE_TEMP_RST, index,
611 index);
612 mlxsw_hwmon_attr_add(mlxsw_hwmon,
613 MLXSW_HWMON_ATTR_TYPE_TEMP_GBOX_LABEL,
614 index, index);
615 index++;
616 }
617
618 return 0;
619 }
620
621 int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core,
622 const struct mlxsw_bus_info *mlxsw_bus_info,
623 struct mlxsw_hwmon **p_hwmon)
624 {
625 struct mlxsw_hwmon *mlxsw_hwmon;
626 struct device *hwmon_dev;
627 int err;
628
629 mlxsw_hwmon = kzalloc(sizeof(*mlxsw_hwmon), GFP_KERNEL);
630 if (!mlxsw_hwmon)
631 return -ENOMEM;
632 mlxsw_hwmon->core = mlxsw_core;
633 mlxsw_hwmon->bus_info = mlxsw_bus_info;
634
635 err = mlxsw_hwmon_temp_init(mlxsw_hwmon);
636 if (err)
637 goto err_temp_init;
638
639 err = mlxsw_hwmon_fans_init(mlxsw_hwmon);
640 if (err)
641 goto err_fans_init;
642
643 err = mlxsw_hwmon_module_init(mlxsw_hwmon);
644 if (err)
645 goto err_temp_module_init;
646
647 err = mlxsw_hwmon_gearbox_init(mlxsw_hwmon);
648 if (err)
649 goto err_temp_gearbox_init;
650
651 mlxsw_hwmon->groups[0] = &mlxsw_hwmon->group;
652 mlxsw_hwmon->group.attrs = mlxsw_hwmon->attrs;
653
654 hwmon_dev = hwmon_device_register_with_groups(mlxsw_bus_info->dev,
655 "mlxsw", mlxsw_hwmon,
656 mlxsw_hwmon->groups);
657 if (IS_ERR(hwmon_dev)) {
658 err = PTR_ERR(hwmon_dev);
659 goto err_hwmon_register;
660 }
661
662 mlxsw_hwmon->hwmon_dev = hwmon_dev;
663 *p_hwmon = mlxsw_hwmon;
664 return 0;
665
666 err_hwmon_register:
667 err_temp_gearbox_init:
668 err_temp_module_init:
669 err_fans_init:
670 err_temp_init:
671 kfree(mlxsw_hwmon);
672 return err;
673 }
674
675 void mlxsw_hwmon_fini(struct mlxsw_hwmon *mlxsw_hwmon)
676 {
677 hwmon_device_unregister(mlxsw_hwmon->hwmon_dev);
678 kfree(mlxsw_hwmon);
679 }