Merge tag 'v3.10.54' into linux-linaro-lsk
[firefly-linux-kernel-4.4.55.git] / tools / gator / daemon / Hwmon.cpp
1 /**
2  * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  */
8
9 #include "Hwmon.h"
10
11 #include "libsensors/sensors.h"
12
13 #include "Buffer.h"
14 #include "Counter.h"
15 #include "Logging.h"
16 #include "SessionData.h"
17
18 class HwmonCounter {
19 public:
20         HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, const sensors_feature *feature);
21         ~HwmonCounter();
22
23         HwmonCounter *getNext() const { return next; }
24         int getKey() const { return key; }
25         bool isEnabled() const { return enabled; }
26         const char *getName() const { return name; }
27         const char *getLabel() const { return label; }
28         const char *getTitle() const { return title; }
29         bool isDuplicate() const { return duplicate; }
30         const char *getDisplay() const { return display; }
31         const char *getCounterClass() const { return counter_class; }
32         const char *getUnit() const { return unit; }
33         int getModifier() const { return modifier; }
34
35         void setEnabled(const bool enabled) {
36                 this->enabled = enabled;
37                 // canRead will clear enabled if the counter is not readable
38                 canRead();
39         }
40
41         double read();
42         bool canRead();
43
44 private:
45         void init(const sensors_chip_name *chip, const sensors_feature *feature);
46
47         HwmonCounter *const next;
48         const int key;
49         int polled : 1,
50                 readable : 1,
51                 enabled : 1,
52                 monotonic: 1,
53                 duplicate : 1;
54
55         const sensors_chip_name *chip;
56         const sensors_feature *feature;
57
58         char *name;
59         char *label;
60         const char *title;
61         const char *display;
62         const char *counter_class;
63         const char *unit;
64         int modifier;
65         double previous_value;
66
67         sensors_subfeature_type input;
68
69         // Intentionally unimplemented
70         HwmonCounter(const HwmonCounter &);
71         HwmonCounter &operator=(const HwmonCounter &);
72 };
73
74 HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, const sensors_feature *feature) : next(next), key(getEventKey()), polled(false), readable(false), enabled(false), duplicate(false), chip(chip), feature(feature) {
75
76         int len = sensors_snprintf_chip_name(NULL, 0, chip) + 1;
77         char *chip_name = new char[len];
78         sensors_snprintf_chip_name(chip_name, len, chip);
79
80         len = snprintf(NULL, 0, "hwmon_%s_%d", chip_name, feature->number) + 1;
81         name = new char[len];
82         snprintf(name, len, "hwmon_%s_%d", chip_name, feature->number);
83
84         delete [] chip_name;
85
86         label = sensors_get_label(chip, feature);
87
88         switch (feature->type) {
89         case SENSORS_FEATURE_IN:
90                 title = "Voltage";
91                 input = SENSORS_SUBFEATURE_IN_INPUT;
92                 display = "maximum";
93                 counter_class = "absolute";
94                 unit = "V";
95                 modifier = 1000;
96                 monotonic = false;
97                 break;
98         case SENSORS_FEATURE_FAN:
99                 title = "Fan";
100                 input = SENSORS_SUBFEATURE_FAN_INPUT;
101                 display = "average";
102                 counter_class = "absolute";
103                 unit = "RPM";
104                 modifier = 1;
105                 monotonic = false;
106                 break;
107         case SENSORS_FEATURE_TEMP:
108                 title = "Temperature";
109                 input = SENSORS_SUBFEATURE_TEMP_INPUT;
110                 display = "maximum";
111                 counter_class = "absolute";
112                 unit = "°C";
113                 modifier = 1000;
114                 monotonic = false;
115                 break;
116         case SENSORS_FEATURE_POWER:
117                 title = "Power";
118                 input = SENSORS_SUBFEATURE_POWER_INPUT;
119                 display = "maximum";
120                 counter_class = "absolute";
121                 unit = "W";
122                 modifier = 1000000;
123                 monotonic = false;
124                 break;
125         case SENSORS_FEATURE_ENERGY:
126                 title = "Energy";
127                 input = SENSORS_SUBFEATURE_ENERGY_INPUT;
128                 display = "accumulate";
129                 counter_class = "delta";
130                 unit = "J";
131                 modifier = 1000000;
132                 monotonic = true;
133                 break;
134         case SENSORS_FEATURE_CURR:
135                 title = "Current";
136                 input = SENSORS_SUBFEATURE_CURR_INPUT;
137                 display = "maximum";
138                 counter_class = "absolute";
139                 unit = "A";
140                 modifier = 1000;
141                 monotonic = false;
142                 break;
143         case SENSORS_FEATURE_HUMIDITY:
144                 title = "Humidity";
145                 input = SENSORS_SUBFEATURE_HUMIDITY_INPUT;
146                 display = "average";
147                 counter_class = "absolute";
148                 unit = "%";
149                 modifier = 1000;
150                 monotonic = false;
151                 break;
152         default:
153                 logg->logError(__FILE__, __LINE__, "Unsupported hwmon feature %i", feature->type);
154                 handleException();
155         }
156
157         for (HwmonCounter * counter = next; counter != NULL; counter = counter->getNext()) {
158                 if (strcmp(label, counter->getLabel()) == 0 && strcmp(title, counter->getTitle()) == 0) {
159                         duplicate = true;
160                         counter->duplicate = true;
161                         break;
162                 }
163         }
164 }
165
166 HwmonCounter::~HwmonCounter() {
167         free((void *)label);
168         delete [] name;
169 }
170
171 double HwmonCounter::read() {
172         double value;
173         double result;
174         const sensors_subfeature *subfeature;
175
176         // Keep in sync with canRead
177         subfeature = sensors_get_subfeature(chip, feature, input);
178         if (!subfeature) {
179                 logg->logError(__FILE__, __LINE__, "No input value for hwmon sensor %s", label);
180                 handleException();
181         }
182
183         if (sensors_get_value(chip, subfeature->number, &value) != 0) {
184                 logg->logError(__FILE__, __LINE__, "Can't get input value for hwmon sensor %s", label);
185                 handleException();
186         }
187
188         result = (monotonic ? value - previous_value : value);
189         previous_value = value;
190
191         return result;
192 }
193
194 bool HwmonCounter::canRead() {
195         if (!polled) {
196                 double value;
197                 const sensors_subfeature *subfeature;
198                 bool result = true;
199
200                 subfeature = sensors_get_subfeature(chip, feature, input);
201                 if (!subfeature) {
202                         result = false;
203                 } else {
204                         result = sensors_get_value(chip, subfeature->number, &value) == 0;
205                 }
206
207                 polled = true;
208                 readable = result;
209         }
210
211         enabled &= readable;
212
213         return readable;
214 }
215
216 Hwmon::Hwmon() : counters(NULL) {
217 }
218
219 Hwmon::~Hwmon() {
220         while (counters != NULL) {
221                 HwmonCounter * counter = counters;
222                 counters = counter->getNext();
223                 delete counter;
224         }
225         sensors_cleanup();
226 }
227
228 void Hwmon::setup() {
229         // hwmon does not currently work with perf
230         if (gSessionData->perf.isSetup()) {
231                 return;
232         }
233
234         int err = sensors_init(NULL);
235         if (err) {
236                 logg->logMessage("Failed to initialize libsensors! (%d)", err);
237                 return;
238         }
239         sensors_sysfs_no_scaling = 1;
240
241         int chip_nr = 0;
242         const sensors_chip_name *chip;
243         while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) {
244                 int feature_nr = 0;
245                 const sensors_feature *feature;
246                 while ((feature = sensors_get_features(chip, &feature_nr))) {
247                         counters = new HwmonCounter(counters, chip, feature);
248                 }
249         }
250 }
251
252 HwmonCounter *Hwmon::findCounter(const Counter &counter) const {
253         for (HwmonCounter * hwmonCounter = counters; hwmonCounter != NULL; hwmonCounter = hwmonCounter->getNext()) {
254                 if (hwmonCounter->canRead() && strcmp(hwmonCounter->getName(), counter.getType()) == 0) {
255                         return hwmonCounter;
256                 }
257         }
258
259         return NULL;
260 }
261
262 bool Hwmon::claimCounter(const Counter &counter) const {
263         return findCounter(counter) != NULL;
264 }
265
266 bool Hwmon::countersEnabled() const {
267         for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
268                 if (counter->isEnabled()) {
269                         return true;
270                 }
271         }
272         return false;
273 }
274
275 void Hwmon::resetCounters() {
276         for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
277                 counter->setEnabled(false);
278         }
279 }
280
281 void Hwmon::setupCounter(Counter &counter) {
282         HwmonCounter *const hwmonCounter = findCounter(counter);
283         if (hwmonCounter == NULL) {
284                 counter.setEnabled(false);
285                 return;
286         }
287         hwmonCounter->setEnabled(true);
288         counter.setKey(hwmonCounter->getKey());
289 }
290
291 int Hwmon::writeCounters(mxml_node_t *root) const {
292         int count = 0;
293         for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
294                 if (!counter->canRead()) {
295                         continue;
296                 }
297                 mxml_node_t *node = mxmlNewElement(root, "counter");
298                 mxmlElementSetAttr(node, "name", counter->getName());
299                 ++count;
300         }
301
302         return count;
303 }
304
305 void Hwmon::writeEvents(mxml_node_t *root) const {
306         root = mxmlNewElement(root, "category");
307         mxmlElementSetAttr(root, "name", "hwmon");
308
309         char buf[1024];
310         for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
311                 if (!counter->canRead()) {
312                         continue;
313                 }
314                 mxml_node_t *node = mxmlNewElement(root, "event");
315                 mxmlElementSetAttr(node, "counter", counter->getName());
316                 mxmlElementSetAttr(node, "title", counter->getTitle());
317                 if (counter->isDuplicate()) {
318                         mxmlElementSetAttrf(node, "name", "%s (0x%x)", counter->getLabel(), counter->getKey());
319                 } else {
320                         mxmlElementSetAttr(node, "name", counter->getLabel());
321                 }
322                 mxmlElementSetAttr(node, "display", counter->getDisplay());
323                 mxmlElementSetAttr(node, "class", counter->getCounterClass());
324                 mxmlElementSetAttr(node, "units", counter->getUnit());
325                 if (counter->getModifier() != 1) {
326                         mxmlElementSetAttrf(node, "modifier", "%d", counter->getModifier());
327                 }
328                 if (strcmp(counter->getDisplay(), "average") == 0 || strcmp(counter->getDisplay(), "maximum") == 0) {
329                         mxmlElementSetAttr(node, "average_selection", "yes");
330                 }
331                 snprintf(buf, sizeof(buf), "libsensors %s sensor %s (%s)", counter->getTitle(), counter->getLabel(), counter->getName());
332                 mxmlElementSetAttr(node, "description", buf);
333         }
334 }
335
336 void Hwmon::start() {
337         for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
338                 if (!counter->isEnabled()) {
339                         continue;
340                 }
341                 counter->read();
342         }
343 }
344
345 void Hwmon::read(Buffer * const buffer) {
346         for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
347                 if (!counter->isEnabled()) {
348                         continue;
349                 }
350                 buffer->event(counter->getKey(), counter->read());
351         }
352 }