1 /* 2 * IBM PowerNV platform sensors for temperature/fan/voltage/power 3 * Copyright (C) 2014 IBM 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. 17 */ 18 19 #define DRVNAME "ibmpowernv" 20 #define pr_fmt(fmt) DRVNAME ": " fmt 21 22 #include <linux/init.h> 23 #include <linux/module.h> 24 #include <linux/kernel.h> 25 #include <linux/hwmon.h> 26 #include <linux/hwmon-sysfs.h> 27 #include <linux/of.h> 28 #include <linux/slab.h> 29 30 #include <linux/platform_device.h> 31 #include <asm/opal.h> 32 #include <linux/err.h> 33 #include <asm/cputhreads.h> 34 #include <asm/smp.h> 35 36 #define MAX_ATTR_LEN 32 37 #define MAX_LABEL_LEN 64 38 39 /* Sensor suffix name from DT */ 40 #define DT_FAULT_ATTR_SUFFIX "faulted" 41 #define DT_DATA_ATTR_SUFFIX "data" 42 #define DT_THRESHOLD_ATTR_SUFFIX "thrs" 43 44 /* 45 * Enumerates all the types of sensors in the POWERNV platform and does index 46 * into 'struct sensor_group' 47 */ 48 enum sensors { 49 FAN, 50 TEMP, 51 POWER_SUPPLY, 52 POWER_INPUT, 53 MAX_SENSOR_TYPE, 54 }; 55 56 #define INVALID_INDEX (-1U) 57 58 static struct sensor_group { 59 const char *name; 60 const char *compatible; 61 struct attribute_group group; 62 u32 attr_count; 63 u32 hwmon_index; 64 } sensor_groups[] = { 65 {"fan", "ibm,opal-sensor-cooling-fan"}, 66 {"temp", "ibm,opal-sensor-amb-temp"}, 67 {"in", "ibm,opal-sensor-power-supply"}, 68 {"power", "ibm,opal-sensor-power"} 69 }; 70 71 struct sensor_data { 72 u32 id; /* An opaque id of the firmware for each sensor */ 73 u32 hwmon_index; 74 u32 opal_index; 75 enum sensors type; 76 char label[MAX_LABEL_LEN]; 77 char name[MAX_ATTR_LEN]; 78 struct device_attribute dev_attr; 79 }; 80 81 struct platform_data { 82 const struct attribute_group *attr_groups[MAX_SENSOR_TYPE + 1]; 83 u32 sensors_count; /* Total count of sensors from each group */ 84 }; 85 86 static ssize_t show_sensor(struct device *dev, struct device_attribute *devattr, 87 char *buf) 88 { 89 struct sensor_data *sdata = container_of(devattr, struct sensor_data, 90 dev_attr); 91 ssize_t ret; 92 u32 x; 93 94 ret = opal_get_sensor_data(sdata->id, &x); 95 if (ret) 96 return ret; 97 98 /* Convert temperature to milli-degrees */ 99 if (sdata->type == TEMP) 100 x *= 1000; 101 /* Convert power to micro-watts */ 102 else if (sdata->type == POWER_INPUT) 103 x *= 1000000; 104 105 return sprintf(buf, "%u\n", x); 106 } 107 108 static ssize_t show_label(struct device *dev, struct device_attribute *devattr, 109 char *buf) 110 { 111 struct sensor_data *sdata = container_of(devattr, struct sensor_data, 112 dev_attr); 113 114 return sprintf(buf, "%s\n", sdata->label); 115 } 116 117 static int __init get_logical_cpu(int hwcpu) 118 { 119 int cpu; 120 121 for_each_possible_cpu(cpu) 122 if (get_hard_smp_processor_id(cpu) == hwcpu) 123 return cpu; 124 125 return -ENOENT; 126 } 127 128 static void __init make_sensor_label(struct device_node *np, 129 struct sensor_data *sdata, 130 const char *label) 131 { 132 u32 id; 133 size_t n; 134 135 n = snprintf(sdata->label, sizeof(sdata->label), "%s", label); 136 137 /* 138 * Core temp pretty print 139 */ 140 if (!of_property_read_u32(np, "ibm,pir", &id)) { 141 int cpuid = get_logical_cpu(id); 142 143 if (cpuid >= 0) 144 /* 145 * The digital thermal sensors are associated 146 * with a core. Let's print out the range of 147 * cpu ids corresponding to the hardware 148 * threads of the core. 149 */ 150 n += snprintf(sdata->label + n, 151 sizeof(sdata->label) - n, " %d-%d", 152 cpuid, cpuid + threads_per_core - 1); 153 else 154 n += snprintf(sdata->label + n, 155 sizeof(sdata->label) - n, " phy%d", id); 156 } 157 158 /* 159 * Membuffer pretty print 160 */ 161 if (!of_property_read_u32(np, "ibm,chip-id", &id)) 162 n += snprintf(sdata->label + n, sizeof(sdata->label) - n, 163 " %d", id & 0xffff); 164 } 165 166 static int get_sensor_index_attr(const char *name, u32 *index, char *attr) 167 { 168 char *hash_pos = strchr(name, '#'); 169 char buf[8] = { 0 }; 170 char *dash_pos; 171 u32 copy_len; 172 int err; 173 174 if (!hash_pos) 175 return -EINVAL; 176 177 dash_pos = strchr(hash_pos, '-'); 178 if (!dash_pos) 179 return -EINVAL; 180 181 copy_len = dash_pos - hash_pos - 1; 182 if (copy_len >= sizeof(buf)) 183 return -EINVAL; 184 185 strncpy(buf, hash_pos + 1, copy_len); 186 187 err = kstrtou32(buf, 10, index); 188 if (err) 189 return err; 190 191 strncpy(attr, dash_pos + 1, MAX_ATTR_LEN); 192 193 return 0; 194 } 195 196 static const char *convert_opal_attr_name(enum sensors type, 197 const char *opal_attr) 198 { 199 const char *attr_name = NULL; 200 201 if (!strcmp(opal_attr, DT_FAULT_ATTR_SUFFIX)) { 202 attr_name = "fault"; 203 } else if (!strcmp(opal_attr, DT_DATA_ATTR_SUFFIX)) { 204 attr_name = "input"; 205 } else if (!strcmp(opal_attr, DT_THRESHOLD_ATTR_SUFFIX)) { 206 if (type == TEMP) 207 attr_name = "max"; 208 else if (type == FAN) 209 attr_name = "min"; 210 } 211 212 return attr_name; 213 } 214 215 /* 216 * This function translates the DT node name into the 'hwmon' attribute name. 217 * IBMPOWERNV device node appear like cooling-fan#2-data, amb-temp#1-thrs etc. 218 * which need to be mapped as fan2_input, temp1_max respectively before 219 * populating them inside hwmon device class. 220 */ 221 static const char *parse_opal_node_name(const char *node_name, 222 enum sensors type, u32 *index) 223 { 224 char attr_suffix[MAX_ATTR_LEN]; 225 const char *attr_name; 226 int err; 227 228 err = get_sensor_index_attr(node_name, index, attr_suffix); 229 if (err) 230 return ERR_PTR(err); 231 232 attr_name = convert_opal_attr_name(type, attr_suffix); 233 if (!attr_name) 234 return ERR_PTR(-ENOENT); 235 236 return attr_name; 237 } 238 239 static int get_sensor_type(struct device_node *np) 240 { 241 enum sensors type; 242 const char *str; 243 244 for (type = 0; type < MAX_SENSOR_TYPE; type++) { 245 if (of_device_is_compatible(np, sensor_groups[type].compatible)) 246 return type; 247 } 248 249 /* 250 * Let's check if we have a newer device tree 251 */ 252 if (!of_device_is_compatible(np, "ibm,opal-sensor")) 253 return MAX_SENSOR_TYPE; 254 255 if (of_property_read_string(np, "sensor-type", &str)) 256 return MAX_SENSOR_TYPE; 257 258 for (type = 0; type < MAX_SENSOR_TYPE; type++) 259 if (!strcmp(str, sensor_groups[type].name)) 260 return type; 261 262 return MAX_SENSOR_TYPE; 263 } 264 265 static u32 get_sensor_hwmon_index(struct sensor_data *sdata, 266 struct sensor_data *sdata_table, int count) 267 { 268 int i; 269 270 /* 271 * We don't use the OPAL index on newer device trees 272 */ 273 if (sdata->opal_index != INVALID_INDEX) { 274 for (i = 0; i < count; i++) 275 if (sdata_table[i].opal_index == sdata->opal_index && 276 sdata_table[i].type == sdata->type) 277 return sdata_table[i].hwmon_index; 278 } 279 return ++sensor_groups[sdata->type].hwmon_index; 280 } 281 282 static int populate_attr_groups(struct platform_device *pdev) 283 { 284 struct platform_data *pdata = platform_get_drvdata(pdev); 285 const struct attribute_group **pgroups = pdata->attr_groups; 286 struct device_node *opal, *np; 287 enum sensors type; 288 289 opal = of_find_node_by_path("/ibm,opal/sensors"); 290 for_each_child_of_node(opal, np) { 291 const char *label; 292 293 if (np->name == NULL) 294 continue; 295 296 type = get_sensor_type(np); 297 if (type == MAX_SENSOR_TYPE) 298 continue; 299 300 sensor_groups[type].attr_count++; 301 302 /* 303 * add a new attribute for labels 304 */ 305 if (!of_property_read_string(np, "label", &label)) 306 sensor_groups[type].attr_count++; 307 } 308 309 of_node_put(opal); 310 311 for (type = 0; type < MAX_SENSOR_TYPE; type++) { 312 sensor_groups[type].group.attrs = devm_kzalloc(&pdev->dev, 313 sizeof(struct attribute *) * 314 (sensor_groups[type].attr_count + 1), 315 GFP_KERNEL); 316 if (!sensor_groups[type].group.attrs) 317 return -ENOMEM; 318 319 pgroups[type] = &sensor_groups[type].group; 320 pdata->sensors_count += sensor_groups[type].attr_count; 321 sensor_groups[type].attr_count = 0; 322 } 323 324 return 0; 325 } 326 327 static void create_hwmon_attr(struct sensor_data *sdata, const char *attr_name, 328 ssize_t (*show)(struct device *dev, 329 struct device_attribute *attr, 330 char *buf)) 331 { 332 snprintf(sdata->name, MAX_ATTR_LEN, "%s%d_%s", 333 sensor_groups[sdata->type].name, sdata->hwmon_index, 334 attr_name); 335 336 sysfs_attr_init(&sdata->dev_attr.attr); 337 sdata->dev_attr.attr.name = sdata->name; 338 sdata->dev_attr.attr.mode = S_IRUGO; 339 sdata->dev_attr.show = show; 340 } 341 342 /* 343 * Iterate through the device tree for each child of 'sensors' node, create 344 * a sysfs attribute file, the file is named by translating the DT node name 345 * to the name required by the higher 'hwmon' driver like fan1_input, temp1_max 346 * etc.. 347 */ 348 static int create_device_attrs(struct platform_device *pdev) 349 { 350 struct platform_data *pdata = platform_get_drvdata(pdev); 351 const struct attribute_group **pgroups = pdata->attr_groups; 352 struct device_node *opal, *np; 353 struct sensor_data *sdata; 354 u32 sensor_id; 355 enum sensors type; 356 u32 count = 0; 357 int err = 0; 358 359 opal = of_find_node_by_path("/ibm,opal/sensors"); 360 sdata = devm_kzalloc(&pdev->dev, pdata->sensors_count * sizeof(*sdata), 361 GFP_KERNEL); 362 if (!sdata) { 363 err = -ENOMEM; 364 goto exit_put_node; 365 } 366 367 for_each_child_of_node(opal, np) { 368 const char *attr_name; 369 u32 opal_index; 370 const char *label; 371 372 if (np->name == NULL) 373 continue; 374 375 type = get_sensor_type(np); 376 if (type == MAX_SENSOR_TYPE) 377 continue; 378 379 /* 380 * Newer device trees use a "sensor-data" property 381 * name for input. 382 */ 383 if (of_property_read_u32(np, "sensor-id", &sensor_id) && 384 of_property_read_u32(np, "sensor-data", &sensor_id)) { 385 dev_info(&pdev->dev, 386 "'sensor-id' missing in the node '%s'\n", 387 np->name); 388 continue; 389 } 390 391 sdata[count].id = sensor_id; 392 sdata[count].type = type; 393 394 /* 395 * If we can not parse the node name, it means we are 396 * running on a newer device tree. We can just forget 397 * about the OPAL index and use a defaut value for the 398 * hwmon attribute name 399 */ 400 attr_name = parse_opal_node_name(np->name, type, &opal_index); 401 if (IS_ERR(attr_name)) { 402 attr_name = "input"; 403 opal_index = INVALID_INDEX; 404 } 405 406 sdata[count].opal_index = opal_index; 407 sdata[count].hwmon_index = 408 get_sensor_hwmon_index(&sdata[count], sdata, count); 409 410 create_hwmon_attr(&sdata[count], attr_name, show_sensor); 411 412 pgroups[type]->attrs[sensor_groups[type].attr_count++] = 413 &sdata[count++].dev_attr.attr; 414 415 if (!of_property_read_string(np, "label", &label)) { 416 /* 417 * For the label attribute, we can reuse the 418 * "properties" of the previous "input" 419 * attribute. They are related to the same 420 * sensor. 421 */ 422 sdata[count].type = type; 423 sdata[count].opal_index = sdata[count - 1].opal_index; 424 sdata[count].hwmon_index = sdata[count - 1].hwmon_index; 425 426 make_sensor_label(np, &sdata[count], label); 427 428 create_hwmon_attr(&sdata[count], "label", show_label); 429 430 pgroups[type]->attrs[sensor_groups[type].attr_count++] = 431 &sdata[count++].dev_attr.attr; 432 } 433 } 434 435 exit_put_node: 436 of_node_put(opal); 437 return err; 438 } 439 440 static int ibmpowernv_probe(struct platform_device *pdev) 441 { 442 struct platform_data *pdata; 443 struct device *hwmon_dev; 444 int err; 445 446 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 447 if (!pdata) 448 return -ENOMEM; 449 450 platform_set_drvdata(pdev, pdata); 451 pdata->sensors_count = 0; 452 err = populate_attr_groups(pdev); 453 if (err) 454 return err; 455 456 /* Create sysfs attribute data for each sensor found in the DT */ 457 err = create_device_attrs(pdev); 458 if (err) 459 return err; 460 461 /* Finally, register with hwmon */ 462 hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev, DRVNAME, 463 pdata, 464 pdata->attr_groups); 465 466 return PTR_ERR_OR_ZERO(hwmon_dev); 467 } 468 469 static const struct platform_device_id opal_sensor_driver_ids[] = { 470 { 471 .name = "opal-sensor", 472 }, 473 { } 474 }; 475 MODULE_DEVICE_TABLE(platform, opal_sensor_driver_ids); 476 477 static const struct of_device_id opal_sensor_match[] = { 478 { .compatible = "ibm,opal-sensor" }, 479 { }, 480 }; 481 MODULE_DEVICE_TABLE(of, opal_sensor_match); 482 483 static struct platform_driver ibmpowernv_driver = { 484 .probe = ibmpowernv_probe, 485 .id_table = opal_sensor_driver_ids, 486 .driver = { 487 .name = DRVNAME, 488 .of_match_table = opal_sensor_match, 489 }, 490 }; 491 492 module_platform_driver(ibmpowernv_driver); 493 494 MODULE_AUTHOR("Neelesh Gupta <neelegup@linux.vnet.ibm.com>"); 495 MODULE_DESCRIPTION("IBM POWERNV platform sensors"); 496 MODULE_LICENSE("GPL"); 497