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. 147 */ 148 n += snprintf(sdata->label + n, 149 sizeof(sdata->label) - n, " %d", 150 cpuid); 151 else 152 n += snprintf(sdata->label + n, 153 sizeof(sdata->label) - n, " phy%d", id); 154 } 155 156 /* 157 * Membuffer pretty print 158 */ 159 if (!of_property_read_u32(np, "ibm,chip-id", &id)) 160 n += snprintf(sdata->label + n, sizeof(sdata->label) - n, 161 " %d", id & 0xffff); 162 } 163 164 static int get_sensor_index_attr(const char *name, u32 *index, char *attr) 165 { 166 char *hash_pos = strchr(name, '#'); 167 char buf[8] = { 0 }; 168 char *dash_pos; 169 u32 copy_len; 170 int err; 171 172 if (!hash_pos) 173 return -EINVAL; 174 175 dash_pos = strchr(hash_pos, '-'); 176 if (!dash_pos) 177 return -EINVAL; 178 179 copy_len = dash_pos - hash_pos - 1; 180 if (copy_len >= sizeof(buf)) 181 return -EINVAL; 182 183 strncpy(buf, hash_pos + 1, copy_len); 184 185 err = kstrtou32(buf, 10, index); 186 if (err) 187 return err; 188 189 strncpy(attr, dash_pos + 1, MAX_ATTR_LEN); 190 191 return 0; 192 } 193 194 static const char *convert_opal_attr_name(enum sensors type, 195 const char *opal_attr) 196 { 197 const char *attr_name = NULL; 198 199 if (!strcmp(opal_attr, DT_FAULT_ATTR_SUFFIX)) { 200 attr_name = "fault"; 201 } else if (!strcmp(opal_attr, DT_DATA_ATTR_SUFFIX)) { 202 attr_name = "input"; 203 } else if (!strcmp(opal_attr, DT_THRESHOLD_ATTR_SUFFIX)) { 204 if (type == TEMP) 205 attr_name = "max"; 206 else if (type == FAN) 207 attr_name = "min"; 208 } 209 210 return attr_name; 211 } 212 213 /* 214 * This function translates the DT node name into the 'hwmon' attribute name. 215 * IBMPOWERNV device node appear like cooling-fan#2-data, amb-temp#1-thrs etc. 216 * which need to be mapped as fan2_input, temp1_max respectively before 217 * populating them inside hwmon device class. 218 */ 219 static const char *parse_opal_node_name(const char *node_name, 220 enum sensors type, u32 *index) 221 { 222 char attr_suffix[MAX_ATTR_LEN]; 223 const char *attr_name; 224 int err; 225 226 err = get_sensor_index_attr(node_name, index, attr_suffix); 227 if (err) 228 return ERR_PTR(err); 229 230 attr_name = convert_opal_attr_name(type, attr_suffix); 231 if (!attr_name) 232 return ERR_PTR(-ENOENT); 233 234 return attr_name; 235 } 236 237 static int get_sensor_type(struct device_node *np) 238 { 239 enum sensors type; 240 const char *str; 241 242 for (type = 0; type < MAX_SENSOR_TYPE; type++) { 243 if (of_device_is_compatible(np, sensor_groups[type].compatible)) 244 return type; 245 } 246 247 /* 248 * Let's check if we have a newer device tree 249 */ 250 if (!of_device_is_compatible(np, "ibm,opal-sensor")) 251 return MAX_SENSOR_TYPE; 252 253 if (of_property_read_string(np, "sensor-type", &str)) 254 return MAX_SENSOR_TYPE; 255 256 for (type = 0; type < MAX_SENSOR_TYPE; type++) 257 if (!strcmp(str, sensor_groups[type].name)) 258 return type; 259 260 return MAX_SENSOR_TYPE; 261 } 262 263 static u32 get_sensor_hwmon_index(struct sensor_data *sdata, 264 struct sensor_data *sdata_table, int count) 265 { 266 int i; 267 268 /* 269 * We don't use the OPAL index on newer device trees 270 */ 271 if (sdata->opal_index != INVALID_INDEX) { 272 for (i = 0; i < count; i++) 273 if (sdata_table[i].opal_index == sdata->opal_index && 274 sdata_table[i].type == sdata->type) 275 return sdata_table[i].hwmon_index; 276 } 277 return ++sensor_groups[sdata->type].hwmon_index; 278 } 279 280 static int populate_attr_groups(struct platform_device *pdev) 281 { 282 struct platform_data *pdata = platform_get_drvdata(pdev); 283 const struct attribute_group **pgroups = pdata->attr_groups; 284 struct device_node *opal, *np; 285 enum sensors type; 286 287 opal = of_find_node_by_path("/ibm,opal/sensors"); 288 for_each_child_of_node(opal, np) { 289 const char *label; 290 291 if (np->name == NULL) 292 continue; 293 294 type = get_sensor_type(np); 295 if (type == MAX_SENSOR_TYPE) 296 continue; 297 298 sensor_groups[type].attr_count++; 299 300 /* 301 * add a new attribute for labels 302 */ 303 if (!of_property_read_string(np, "label", &label)) 304 sensor_groups[type].attr_count++; 305 } 306 307 of_node_put(opal); 308 309 for (type = 0; type < MAX_SENSOR_TYPE; type++) { 310 sensor_groups[type].group.attrs = devm_kzalloc(&pdev->dev, 311 sizeof(struct attribute *) * 312 (sensor_groups[type].attr_count + 1), 313 GFP_KERNEL); 314 if (!sensor_groups[type].group.attrs) 315 return -ENOMEM; 316 317 pgroups[type] = &sensor_groups[type].group; 318 pdata->sensors_count += sensor_groups[type].attr_count; 319 sensor_groups[type].attr_count = 0; 320 } 321 322 return 0; 323 } 324 325 static void create_hwmon_attr(struct sensor_data *sdata, const char *attr_name, 326 ssize_t (*show)(struct device *dev, 327 struct device_attribute *attr, 328 char *buf)) 329 { 330 snprintf(sdata->name, MAX_ATTR_LEN, "%s%d_%s", 331 sensor_groups[sdata->type].name, sdata->hwmon_index, 332 attr_name); 333 334 sysfs_attr_init(&sdata->dev_attr.attr); 335 sdata->dev_attr.attr.name = sdata->name; 336 sdata->dev_attr.attr.mode = S_IRUGO; 337 sdata->dev_attr.show = show; 338 } 339 340 /* 341 * Iterate through the device tree for each child of 'sensors' node, create 342 * a sysfs attribute file, the file is named by translating the DT node name 343 * to the name required by the higher 'hwmon' driver like fan1_input, temp1_max 344 * etc.. 345 */ 346 static int create_device_attrs(struct platform_device *pdev) 347 { 348 struct platform_data *pdata = platform_get_drvdata(pdev); 349 const struct attribute_group **pgroups = pdata->attr_groups; 350 struct device_node *opal, *np; 351 struct sensor_data *sdata; 352 u32 sensor_id; 353 enum sensors type; 354 u32 count = 0; 355 int err = 0; 356 357 opal = of_find_node_by_path("/ibm,opal/sensors"); 358 sdata = devm_kzalloc(&pdev->dev, pdata->sensors_count * sizeof(*sdata), 359 GFP_KERNEL); 360 if (!sdata) { 361 err = -ENOMEM; 362 goto exit_put_node; 363 } 364 365 for_each_child_of_node(opal, np) { 366 const char *attr_name; 367 u32 opal_index; 368 const char *label; 369 370 if (np->name == NULL) 371 continue; 372 373 type = get_sensor_type(np); 374 if (type == MAX_SENSOR_TYPE) 375 continue; 376 377 /* 378 * Newer device trees use a "sensor-data" property 379 * name for input. 380 */ 381 if (of_property_read_u32(np, "sensor-id", &sensor_id) && 382 of_property_read_u32(np, "sensor-data", &sensor_id)) { 383 dev_info(&pdev->dev, 384 "'sensor-id' missing in the node '%s'\n", 385 np->name); 386 continue; 387 } 388 389 sdata[count].id = sensor_id; 390 sdata[count].type = type; 391 392 /* 393 * If we can not parse the node name, it means we are 394 * running on a newer device tree. We can just forget 395 * about the OPAL index and use a defaut value for the 396 * hwmon attribute name 397 */ 398 attr_name = parse_opal_node_name(np->name, type, &opal_index); 399 if (IS_ERR(attr_name)) { 400 attr_name = "input"; 401 opal_index = INVALID_INDEX; 402 } 403 404 sdata[count].opal_index = opal_index; 405 sdata[count].hwmon_index = 406 get_sensor_hwmon_index(&sdata[count], sdata, count); 407 408 create_hwmon_attr(&sdata[count], attr_name, show_sensor); 409 410 pgroups[type]->attrs[sensor_groups[type].attr_count++] = 411 &sdata[count++].dev_attr.attr; 412 413 if (!of_property_read_string(np, "label", &label)) { 414 /* 415 * For the label attribute, we can reuse the 416 * "properties" of the previous "input" 417 * attribute. They are related to the same 418 * sensor. 419 */ 420 sdata[count].type = type; 421 sdata[count].opal_index = sdata[count - 1].opal_index; 422 sdata[count].hwmon_index = sdata[count - 1].hwmon_index; 423 424 make_sensor_label(np, &sdata[count], label); 425 426 create_hwmon_attr(&sdata[count], "label", show_label); 427 428 pgroups[type]->attrs[sensor_groups[type].attr_count++] = 429 &sdata[count++].dev_attr.attr; 430 } 431 } 432 433 exit_put_node: 434 of_node_put(opal); 435 return err; 436 } 437 438 static int ibmpowernv_probe(struct platform_device *pdev) 439 { 440 struct platform_data *pdata; 441 struct device *hwmon_dev; 442 int err; 443 444 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 445 if (!pdata) 446 return -ENOMEM; 447 448 platform_set_drvdata(pdev, pdata); 449 pdata->sensors_count = 0; 450 err = populate_attr_groups(pdev); 451 if (err) 452 return err; 453 454 /* Create sysfs attribute data for each sensor found in the DT */ 455 err = create_device_attrs(pdev); 456 if (err) 457 return err; 458 459 /* Finally, register with hwmon */ 460 hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev, DRVNAME, 461 pdata, 462 pdata->attr_groups); 463 464 return PTR_ERR_OR_ZERO(hwmon_dev); 465 } 466 467 static const struct platform_device_id opal_sensor_driver_ids[] = { 468 { 469 .name = "opal-sensor", 470 }, 471 { } 472 }; 473 MODULE_DEVICE_TABLE(platform, opal_sensor_driver_ids); 474 475 static const struct of_device_id opal_sensor_match[] = { 476 { .compatible = "ibm,opal-sensor" }, 477 { }, 478 }; 479 MODULE_DEVICE_TABLE(of, opal_sensor_match); 480 481 static struct platform_driver ibmpowernv_driver = { 482 .probe = ibmpowernv_probe, 483 .id_table = opal_sensor_driver_ids, 484 .driver = { 485 .name = DRVNAME, 486 .of_match_table = opal_sensor_match, 487 }, 488 }; 489 490 module_platform_driver(ibmpowernv_driver); 491 492 MODULE_AUTHOR("Neelesh Gupta <neelegup@linux.vnet.ibm.com>"); 493 MODULE_DESCRIPTION("IBM POWERNV platform sensors"); 494 MODULE_LICENSE("GPL"); 495