powerpc/64: Save stack pointer when we hard disable interrupts
[linux-2.6-microblaze.git] / drivers / hwmon / ibmpowernv.c
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         CURRENT,
54         ENERGY,
55         MAX_SENSOR_TYPE,
56 };
57
58 #define INVALID_INDEX (-1U)
59
60 /*
61  * 'compatible' string properties for sensor types as defined in old
62  * PowerNV firmware (skiboot). These are ordered as 'enum sensors'.
63  */
64 static const char * const legacy_compatibles[] = {
65         "ibm,opal-sensor-cooling-fan",
66         "ibm,opal-sensor-amb-temp",
67         "ibm,opal-sensor-power-supply",
68         "ibm,opal-sensor-power"
69 };
70
71 static struct sensor_group {
72         const char *name; /* matches property 'sensor-type' */
73         struct attribute_group group;
74         u32 attr_count;
75         u32 hwmon_index;
76 } sensor_groups[] = {
77         { "fan"   },
78         { "temp"  },
79         { "in"    },
80         { "power" },
81         { "curr"  },
82         { "energy" },
83 };
84
85 struct sensor_data {
86         u32 id; /* An opaque id of the firmware for each sensor */
87         u32 hwmon_index;
88         u32 opal_index;
89         enum sensors type;
90         char label[MAX_LABEL_LEN];
91         char name[MAX_ATTR_LEN];
92         struct device_attribute dev_attr;
93 };
94
95 struct platform_data {
96         const struct attribute_group *attr_groups[MAX_SENSOR_TYPE + 1];
97         u32 sensors_count; /* Total count of sensors from each group */
98 };
99
100 static ssize_t show_sensor(struct device *dev, struct device_attribute *devattr,
101                            char *buf)
102 {
103         struct sensor_data *sdata = container_of(devattr, struct sensor_data,
104                                                  dev_attr);
105         ssize_t ret;
106         u64 x;
107
108         ret =  opal_get_sensor_data_u64(sdata->id, &x);
109
110         if (ret)
111                 return ret;
112
113         /* Convert temperature to milli-degrees */
114         if (sdata->type == TEMP)
115                 x *= 1000;
116         /* Convert power to micro-watts */
117         else if (sdata->type == POWER_INPUT)
118                 x *= 1000000;
119
120         return sprintf(buf, "%llu\n", x);
121 }
122
123 static ssize_t show_label(struct device *dev, struct device_attribute *devattr,
124                           char *buf)
125 {
126         struct sensor_data *sdata = container_of(devattr, struct sensor_data,
127                                                  dev_attr);
128
129         return sprintf(buf, "%s\n", sdata->label);
130 }
131
132 static int __init get_logical_cpu(int hwcpu)
133 {
134         int cpu;
135
136         for_each_possible_cpu(cpu)
137                 if (get_hard_smp_processor_id(cpu) == hwcpu)
138                         return cpu;
139
140         return -ENOENT;
141 }
142
143 static void __init make_sensor_label(struct device_node *np,
144                                      struct sensor_data *sdata,
145                                      const char *label)
146 {
147         u32 id;
148         size_t n;
149
150         n = snprintf(sdata->label, sizeof(sdata->label), "%s", label);
151
152         /*
153          * Core temp pretty print
154          */
155         if (!of_property_read_u32(np, "ibm,pir", &id)) {
156                 int cpuid = get_logical_cpu(id);
157
158                 if (cpuid >= 0)
159                         /*
160                          * The digital thermal sensors are associated
161                          * with a core.
162                          */
163                         n += snprintf(sdata->label + n,
164                                       sizeof(sdata->label) - n, " %d",
165                                       cpuid);
166                 else
167                         n += snprintf(sdata->label + n,
168                                       sizeof(sdata->label) - n, " phy%d", id);
169         }
170
171         /*
172          * Membuffer pretty print
173          */
174         if (!of_property_read_u32(np, "ibm,chip-id", &id))
175                 n += snprintf(sdata->label + n, sizeof(sdata->label) - n,
176                               " %d", id & 0xffff);
177 }
178
179 static int get_sensor_index_attr(const char *name, u32 *index, char *attr)
180 {
181         char *hash_pos = strchr(name, '#');
182         char buf[8] = { 0 };
183         char *dash_pos;
184         u32 copy_len;
185         int err;
186
187         if (!hash_pos)
188                 return -EINVAL;
189
190         dash_pos = strchr(hash_pos, '-');
191         if (!dash_pos)
192                 return -EINVAL;
193
194         copy_len = dash_pos - hash_pos - 1;
195         if (copy_len >= sizeof(buf))
196                 return -EINVAL;
197
198         strncpy(buf, hash_pos + 1, copy_len);
199
200         err = kstrtou32(buf, 10, index);
201         if (err)
202                 return err;
203
204         strncpy(attr, dash_pos + 1, MAX_ATTR_LEN);
205
206         return 0;
207 }
208
209 static const char *convert_opal_attr_name(enum sensors type,
210                                           const char *opal_attr)
211 {
212         const char *attr_name = NULL;
213
214         if (!strcmp(opal_attr, DT_FAULT_ATTR_SUFFIX)) {
215                 attr_name = "fault";
216         } else if (!strcmp(opal_attr, DT_DATA_ATTR_SUFFIX)) {
217                 attr_name = "input";
218         } else if (!strcmp(opal_attr, DT_THRESHOLD_ATTR_SUFFIX)) {
219                 if (type == TEMP)
220                         attr_name = "max";
221                 else if (type == FAN)
222                         attr_name = "min";
223         }
224
225         return attr_name;
226 }
227
228 /*
229  * This function translates the DT node name into the 'hwmon' attribute name.
230  * IBMPOWERNV device node appear like cooling-fan#2-data, amb-temp#1-thrs etc.
231  * which need to be mapped as fan2_input, temp1_max respectively before
232  * populating them inside hwmon device class.
233  */
234 static const char *parse_opal_node_name(const char *node_name,
235                                         enum sensors type, u32 *index)
236 {
237         char attr_suffix[MAX_ATTR_LEN];
238         const char *attr_name;
239         int err;
240
241         err = get_sensor_index_attr(node_name, index, attr_suffix);
242         if (err)
243                 return ERR_PTR(err);
244
245         attr_name = convert_opal_attr_name(type, attr_suffix);
246         if (!attr_name)
247                 return ERR_PTR(-ENOENT);
248
249         return attr_name;
250 }
251
252 static int get_sensor_type(struct device_node *np)
253 {
254         enum sensors type;
255         const char *str;
256
257         for (type = 0; type < ARRAY_SIZE(legacy_compatibles); type++) {
258                 if (of_device_is_compatible(np, legacy_compatibles[type]))
259                         return type;
260         }
261
262         /*
263          * Let's check if we have a newer device tree
264          */
265         if (!of_device_is_compatible(np, "ibm,opal-sensor"))
266                 return MAX_SENSOR_TYPE;
267
268         if (of_property_read_string(np, "sensor-type", &str))
269                 return MAX_SENSOR_TYPE;
270
271         for (type = 0; type < MAX_SENSOR_TYPE; type++)
272                 if (!strcmp(str, sensor_groups[type].name))
273                         return type;
274
275         return MAX_SENSOR_TYPE;
276 }
277
278 static u32 get_sensor_hwmon_index(struct sensor_data *sdata,
279                                   struct sensor_data *sdata_table, int count)
280 {
281         int i;
282
283         /*
284          * We don't use the OPAL index on newer device trees
285          */
286         if (sdata->opal_index != INVALID_INDEX) {
287                 for (i = 0; i < count; i++)
288                         if (sdata_table[i].opal_index == sdata->opal_index &&
289                             sdata_table[i].type == sdata->type)
290                                 return sdata_table[i].hwmon_index;
291         }
292         return ++sensor_groups[sdata->type].hwmon_index;
293 }
294
295 static int populate_attr_groups(struct platform_device *pdev)
296 {
297         struct platform_data *pdata = platform_get_drvdata(pdev);
298         const struct attribute_group **pgroups = pdata->attr_groups;
299         struct device_node *opal, *np;
300         enum sensors type;
301
302         opal = of_find_node_by_path("/ibm,opal/sensors");
303         for_each_child_of_node(opal, np) {
304                 const char *label;
305
306                 if (np->name == NULL)
307                         continue;
308
309                 type = get_sensor_type(np);
310                 if (type == MAX_SENSOR_TYPE)
311                         continue;
312
313                 sensor_groups[type].attr_count++;
314
315                 /*
316                  * add attributes for labels, min and max
317                  */
318                 if (!of_property_read_string(np, "label", &label))
319                         sensor_groups[type].attr_count++;
320                 if (of_find_property(np, "sensor-data-min", NULL))
321                         sensor_groups[type].attr_count++;
322                 if (of_find_property(np, "sensor-data-max", NULL))
323                         sensor_groups[type].attr_count++;
324         }
325
326         of_node_put(opal);
327
328         for (type = 0; type < MAX_SENSOR_TYPE; type++) {
329                 sensor_groups[type].group.attrs = devm_kzalloc(&pdev->dev,
330                                         sizeof(struct attribute *) *
331                                         (sensor_groups[type].attr_count + 1),
332                                         GFP_KERNEL);
333                 if (!sensor_groups[type].group.attrs)
334                         return -ENOMEM;
335
336                 pgroups[type] = &sensor_groups[type].group;
337                 pdata->sensors_count += sensor_groups[type].attr_count;
338                 sensor_groups[type].attr_count = 0;
339         }
340
341         return 0;
342 }
343
344 static void create_hwmon_attr(struct sensor_data *sdata, const char *attr_name,
345                               ssize_t (*show)(struct device *dev,
346                                               struct device_attribute *attr,
347                                               char *buf))
348 {
349         snprintf(sdata->name, MAX_ATTR_LEN, "%s%d_%s",
350                  sensor_groups[sdata->type].name, sdata->hwmon_index,
351                  attr_name);
352
353         sysfs_attr_init(&sdata->dev_attr.attr);
354         sdata->dev_attr.attr.name = sdata->name;
355         sdata->dev_attr.attr.mode = S_IRUGO;
356         sdata->dev_attr.show = show;
357 }
358
359 static void populate_sensor(struct sensor_data *sdata, int od, int hd, int sid,
360                             const char *attr_name, enum sensors type,
361                             const struct attribute_group *pgroup,
362                             ssize_t (*show)(struct device *dev,
363                                             struct device_attribute *attr,
364                                             char *buf))
365 {
366         sdata->id = sid;
367         sdata->type = type;
368         sdata->opal_index = od;
369         sdata->hwmon_index = hd;
370         create_hwmon_attr(sdata, attr_name, show);
371         pgroup->attrs[sensor_groups[type].attr_count++] = &sdata->dev_attr.attr;
372 }
373
374 static char *get_max_attr(enum sensors type)
375 {
376         switch (type) {
377         case POWER_INPUT:
378                 return "input_highest";
379         default:
380                 return "highest";
381         }
382 }
383
384 static char *get_min_attr(enum sensors type)
385 {
386         switch (type) {
387         case POWER_INPUT:
388                 return "input_lowest";
389         default:
390                 return "lowest";
391         }
392 }
393
394 /*
395  * Iterate through the device tree for each child of 'sensors' node, create
396  * a sysfs attribute file, the file is named by translating the DT node name
397  * to the name required by the higher 'hwmon' driver like fan1_input, temp1_max
398  * etc..
399  */
400 static int create_device_attrs(struct platform_device *pdev)
401 {
402         struct platform_data *pdata = platform_get_drvdata(pdev);
403         const struct attribute_group **pgroups = pdata->attr_groups;
404         struct device_node *opal, *np;
405         struct sensor_data *sdata;
406         u32 sensor_id;
407         enum sensors type;
408         u32 count = 0;
409         int err = 0;
410
411         opal = of_find_node_by_path("/ibm,opal/sensors");
412         sdata = devm_kzalloc(&pdev->dev, pdata->sensors_count * sizeof(*sdata),
413                              GFP_KERNEL);
414         if (!sdata) {
415                 err = -ENOMEM;
416                 goto exit_put_node;
417         }
418
419         for_each_child_of_node(opal, np) {
420                 const char *attr_name;
421                 u32 opal_index;
422                 const char *label;
423
424                 if (np->name == NULL)
425                         continue;
426
427                 type = get_sensor_type(np);
428                 if (type == MAX_SENSOR_TYPE)
429                         continue;
430
431                 /*
432                  * Newer device trees use a "sensor-data" property
433                  * name for input.
434                  */
435                 if (of_property_read_u32(np, "sensor-id", &sensor_id) &&
436                     of_property_read_u32(np, "sensor-data", &sensor_id)) {
437                         dev_info(&pdev->dev,
438                                  "'sensor-id' missing in the node '%s'\n",
439                                  np->name);
440                         continue;
441                 }
442
443                 sdata[count].id = sensor_id;
444                 sdata[count].type = type;
445
446                 /*
447                  * If we can not parse the node name, it means we are
448                  * running on a newer device tree. We can just forget
449                  * about the OPAL index and use a defaut value for the
450                  * hwmon attribute name
451                  */
452                 attr_name = parse_opal_node_name(np->name, type, &opal_index);
453                 if (IS_ERR(attr_name)) {
454                         attr_name = "input";
455                         opal_index = INVALID_INDEX;
456                 }
457
458                 sdata[count].opal_index = opal_index;
459                 sdata[count].hwmon_index =
460                         get_sensor_hwmon_index(&sdata[count], sdata, count);
461
462                 create_hwmon_attr(&sdata[count], attr_name, show_sensor);
463
464                 pgroups[type]->attrs[sensor_groups[type].attr_count++] =
465                                 &sdata[count++].dev_attr.attr;
466
467                 if (!of_property_read_string(np, "label", &label)) {
468                         /*
469                          * For the label attribute, we can reuse the
470                          * "properties" of the previous "input"
471                          * attribute. They are related to the same
472                          * sensor.
473                          */
474
475                         make_sensor_label(np, &sdata[count], label);
476                         populate_sensor(&sdata[count], opal_index,
477                                         sdata[count - 1].hwmon_index,
478                                         sensor_id, "label", type, pgroups[type],
479                                         show_label);
480                         count++;
481                 }
482
483                 if (!of_property_read_u32(np, "sensor-data-max", &sensor_id)) {
484                         attr_name = get_max_attr(type);
485                         populate_sensor(&sdata[count], opal_index,
486                                         sdata[count - 1].hwmon_index,
487                                         sensor_id, attr_name, type,
488                                         pgroups[type], show_sensor);
489                         count++;
490                 }
491
492                 if (!of_property_read_u32(np, "sensor-data-min", &sensor_id)) {
493                         attr_name = get_min_attr(type);
494                         populate_sensor(&sdata[count], opal_index,
495                                         sdata[count - 1].hwmon_index,
496                                         sensor_id, attr_name, type,
497                                         pgroups[type], show_sensor);
498                         count++;
499                 }
500         }
501
502 exit_put_node:
503         of_node_put(opal);
504         return err;
505 }
506
507 static int ibmpowernv_probe(struct platform_device *pdev)
508 {
509         struct platform_data *pdata;
510         struct device *hwmon_dev;
511         int err;
512
513         pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
514         if (!pdata)
515                 return -ENOMEM;
516
517         platform_set_drvdata(pdev, pdata);
518         pdata->sensors_count = 0;
519         err = populate_attr_groups(pdev);
520         if (err)
521                 return err;
522
523         /* Create sysfs attribute data for each sensor found in the DT */
524         err = create_device_attrs(pdev);
525         if (err)
526                 return err;
527
528         /* Finally, register with hwmon */
529         hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev, DRVNAME,
530                                                            pdata,
531                                                            pdata->attr_groups);
532
533         return PTR_ERR_OR_ZERO(hwmon_dev);
534 }
535
536 static const struct platform_device_id opal_sensor_driver_ids[] = {
537         {
538                 .name = "opal-sensor",
539         },
540         { }
541 };
542 MODULE_DEVICE_TABLE(platform, opal_sensor_driver_ids);
543
544 static const struct of_device_id opal_sensor_match[] = {
545         { .compatible   = "ibm,opal-sensor" },
546         { },
547 };
548 MODULE_DEVICE_TABLE(of, opal_sensor_match);
549
550 static struct platform_driver ibmpowernv_driver = {
551         .probe          = ibmpowernv_probe,
552         .id_table       = opal_sensor_driver_ids,
553         .driver         = {
554                 .name   = DRVNAME,
555                 .of_match_table = opal_sensor_match,
556         },
557 };
558
559 module_platform_driver(ibmpowernv_driver);
560
561 MODULE_AUTHOR("Neelesh Gupta <neelegup@linux.vnet.ibm.com>");
562 MODULE_DESCRIPTION("IBM POWERNV platform sensors");
563 MODULE_LICENSE("GPL");