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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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