hwmon: occ: Add sysfs interface
Subsystems (2)
PATCH 2/7 hwmon: occ: Add sysfs interface
From: "Edward A. James" <[email protected]>
Add a generic mechanism to expose the sensors provided by the OCC in sysfs.
--- Documentation/hwmon/occ | 48 +++++ drivers/hwmon/occ/Makefile | 2 +- drivers/hwmon/occ/occ_sysfs.c | 492 ++++++++++++++++++++++++++++++++++++++++++ drivers/hwmon/occ/occ_sysfs.h | 52 +++++ 4 files changed, 593 insertions(+), 1 deletion(-) create mode 100644 drivers/hwmon/occ/occ_sysfs.c create mode 100644 drivers/hwmon/occ/occ_sysfs.h
Documentation/hwmon/occ +48 -0
@@ -25,6 +25,54 @@ Currently, all versions of the OCC support four types of sensor data: power, temperature, frequency, and "caps," which indicate limits and thresholds used internally on the OCC. +sysfs Entries +------------- + +The OCC driver uses the hwmon sysfs framework to provide data to userspace. + +The driver exports two sysfs files for each frequency, temperature, and power +sensor. These are "input" and "label". The input file contains the value of the +sensor. The label file contains the sensor id. The sensor id is the unique +internal OCC identifier. Sensor ids may be provided by the OCC specification. +The names of these files will be in the following format: + <sensor type><sensor index>_input + <sensor type><sensor index>_label +Sensor types will be one of "temp", "freq", or "power". The sensor index is +an index to differentiate different sensor files. For example, a single +temperature sensor will have two sysfs files: temp1_input and temp1_label. + +Caps sensors are exported differently. For each caps sensor, the driver will +export 6 entries: + curr_powercap - current power cap in watts + curr_powerreading - current power output in watts + norm_powercap - power cap without redundant power + max_powercap - maximum power cap that can be set in watts + min_powercap - minimum power cap that can be set in watts + user_powerlimit - power limit specified by the user in watts +In addition, the OCC driver for P9 will export a 7th entry: + user_powerlimit_source - can be one of two values depending on who set + the user_powerlimit. 0x1 - out of band from BMC or host. 0x2 - + in band from other source. +The format for these files is caps<sensor index>_<entry type>. For example, +caps1_curr_powercap. + +The driver also provides a number of sysfs entries through hwmon to better +control the driver and monitor the OCC. + powercap - read or write the OCC user power limit in watts. + name - read the name of the driver + update_interval - read or write the minimum interval for polling the + OCC. + +The driver also exports a single sysfs file through the communication protocol +device (see BMC - Host Communications). The filename is "online" and represents +the status of the OCC with respect to the driver. The OCC can be in one of two +states: OCC polling enabled or OCC polling disabled. The purpose of this file +is to control the behavior of the driver and it's hwmon sysfs entries, not to +infer any information about the state of the physical OCC. Reading the file +returns either a 0 (polling disabled) or 1 (polling enabled). Writing 1 to the +file enables OCC polling in the driver if communications can be established +with the OCC. Writing a 0 to the driver disables OCC polling. + BMC - Host Communications -------------------------
drivers/hwmon/occ/Makefile +1 -1
@@ -1 +1 @@ -obj-$(CONFIG_SENSORS_PPC_OCC) += occ.o +obj-$(CONFIG_SENSORS_PPC_OCC) += occ.o occ_sysfs.o
drivers/hwmon/occ/occ_sysfs.c new file +492 -0
492 lines not on this page · raw message
drivers/hwmon/occ/occ_sysfs.h new file +52 -0
52 lines not on this page · raw message
Signature · 1 line
1.9.1
Quoted 61 lines · On Fri, 2016-12-16 at 14:34 -0600, [email protected] wrote:
Quoted 1 line
From: "Edward A. James" <[email protected]>
Add a generic mechanism to expose the sensors provided by the OCC in sysfs.
Quoted 2 lines
Signed-off-by Edward A. James <[email protected]>Signed-off-by Andrew Jeffery <[email protected]>---
Documentation/hwmon/occ | 48 +++++ drivers/hwmon/occ/Makefile | 2 +-drivers/hwmon/occ/occ_sysfs.c| 492 ++++++++++++++++++++++++++++++++++++++++++drivers/hwmon/occ/occ_sysfs.h| 52 +++++4 files changed, 593 insertions(+), 1 deletion(-)create mode 100644
drivers/hwmon/occ/occ_sysfs.c
create mode 100644drivers/hwmon/occ/occ_sysfs.hDocumentation/hwmon/occ +0
-0@@ -25,6 +25,54 @@ Currently, all versions of the OCC support four types of sensor data: power,temperature, frequency, and "caps," which indicate limits and thresholds used internally on the OCC.
Documentation/hwmon/occ +10
-0+sysfs Entries +------------- + +The OCC driver uses the hwmon sysfs framework to provide data to userspace. + +The driver exports two sysfs files for each frequency, temperature, and power +sensor. These are "input" and "label". The input file contains the value of the +sensor. The label file contains the sensor id. The sensor id is the unique +internal OCC identifier. Sensor ids may be provided by the OCC specification. +The names of these files will be in the following format:Quoted 2 lines
Documentation/hwmon/occ +2
-0+ <sensor type><sensor index>_input + <sensor type><sensor index>_labelDocumentation/hwmon/occ +6
-0+Sensor types will be one of "temp", "freq", or "power". The sensor index is +an index to differentiate different sensor files. For example, a single +temperature sensor will have two sysfs files: temp1_input and temp1_label. + +Caps sensors are exported differently. For each caps sensor, the driver will +export 6 entries:Documentation/hwmon/occ Currently, all versions of the OCC support four types of sensor data: power, · line 51
Quoted 6 lines
Documentation/hwmon/occ +6
-0+ curr_powercap - current power cap in watts + curr_powerreading - current power output in watts + norm_powercap - power cap without redundant power + max_powercap - maximum power cap that can be set in watts + min_powercap - minimum power cap that can be set in watts + user_powerlimit - power limit specified by the user in watts+In addition, the OCC driver for P9 will export a 7th entry:
Quoted 3 lines
Documentation/hwmon/occ +3
-0+ user_powerlimit_source - can be one of two values depending on who set + the user_powerlimit. 0x1 - out of band from BMC or host. 0x2 - + in band from other source.Documentation/hwmon/occ +5
-0+The format for these files is caps<sensor index>_<entry type>. For example, +caps1_curr_powercap. + +The driver also provides a number of sysfs entries through hwmon to better +control the driver and monitor the OCC.Quoted 4 lines
Documentation/hwmon/occ +4
-0+ powercap - read or write the OCC user power limit in watts. + name - read the name of the driver + update_interval - read or write the minimum interval for polling the + OCC.
Documentation/hwmon/occ Currently, all versions of the OCC support four types of sensor data: power, · line 74
Quoted 10 lines
Documentation/hwmon/occ +10
-0+ +The driver also exports a single sysfs file through the communication protocol +device (see BMC - Host Communications). The filename is "online" and represents +the status of the OCC with respect to the driver. The OCC can be in one of two +states: OCC polling enabled or OCC polling disabled. The purpose of this file +is to control the behavior of the driver and it's hwmon sysfs entries, not to +infer any information about the state of the physical OCC. Reading the file +returns either a 0 (polling disabled) or 1 (polling enabled). Writing 1 to the +file enables OCC polling in the driver if communications can be established +with the OCC. Writing a 0 to the driver disables OCC polling.
Again, this is great. There's some overlap with Documentation/hwmon/sysfs-interface, but nothing to worry about.
The rest looks good to me as well.
Quoted 567 lines
+
BMC - Host Communications
-------------------------drivers/hwmon/occ/Makefile +1
-1@@ -1 +1 @@ -obj-$(CONFIG_SENSORS_PPC_OCC) += occ.o +obj-$(CONFIG_SENSORS_PPC_OCC) += occ.o occ_sysfs.odrivers/hwmon/occ/occ_sysfs.c new file +33
-0@@ -0,0 +1,492 @@ +/* +* occ_sysfs.c - OCC sysfs interface +* +* This file contains the methods and data structures for implementing the OCC +* hwmon sysfs entries. +* +* Copyright 2016 IBM Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/jiffies.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/err.h> +#include <linux/mutex.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/device.h> + +#include "occ_sysfs.h" +Quoted 1 line
+#define
MAX_SENSOR_ATTR_LEN32+
Quoted 1 line
+#define
RESP_RETURN_CMD_INVAL0x13drivers/hwmon/occ/occ_sysfs.c new file +2
-0+ +struct sensor_attr_data {Quoted 5 lines
drivers/hwmon/occ/occ_sysfs.c new file +5
-0+enum sensor_type type; +u32 hwmon_index; +u32 attr_id; +char name[MAX_SENSOR_ATTR_LEN ]; +struct device_attribute dev_attr;drivers/hwmon/occ/occ_sysfs.c new file +3
-0+}; + +static ssize_t show_input(struct device *dev,Review
Quoted 1 line
(quoted diff) +1
-0+ struct device_attribute *attr, char *buf)+{
drivers/hwmon/occ/occ_sysfs.c line 53
Quoted 5 lines
drivers/hwmon/occ/occ_sysfs.c new file +5
-0+int val; +struct sensor_attr_data *sdata =container_of (attr, + struct sensor_attr_data, + dev_attr); +struct occ_sysfs *driver =dev_get_drvdata (dev);+
Quoted 4 lines
drivers/hwmon/occ/occ_sysfs.c new file +3
-0+ val =occ_get_sensor_value (driver->occ, sdata->type, + sdata->hwmon_index - 1); +if (sdata->type ==TEMP )drivers/hwmon/occ/occ_sysfs.c line 58
Quoted 1 line
drivers/hwmon/occ/occ_sysfs.c new file +1
-0+ val *=1000 ;/* in millidegree Celsius */ +
Quoted 1 line
(quoted diff) +1
-0+ return snprintf(buf, PAGE_SIZE - 1, "%d\n", val);drivers/hwmon/occ/occ_sysfs.c new file +7
-0+} + +/* show_label provides the OCC sensor id. The sensor id will be either a +* 2-byte (for P8) or 4-byte (for P9) value. The sensor id is a way to +* identify what each sensor represents, according to the OCC specification. +*/ +static ssize_t show_label(struct device *dev,Review
Quoted 1 line
(quoted diff) +1
-0+ struct device_attribute *attr, char *buf)+{
drivers/hwmon/occ/occ_sysfs.c line 53
Quoted 5 lines
drivers/hwmon/occ/occ_sysfs.c new file +5
-0+int val; +struct sensor_attr_data *sdata =container_of (attr, + struct sensor_attr_data, + dev_attr); +struct occ_sysfs *driver =dev_get_drvdata (dev);+
drivers/hwmon/occ/occ_sysfs.c line 77
Quoted 2 lines
drivers/hwmon/occ/occ_sysfs.c new file +2
-0+ val =occ_get_sensor_id (driver->occ, sdata->type, + sdata->hwmon_index -1 );+
Quoted 1 line
(quoted diff) +1
-0+ return snprintf(buf, PAGE_SIZE - 1, "%d\n", val);drivers/hwmon/occ/occ_sysfs.c new file +3
-0+} + +static ssize_t show_caps(struct device *dev,Review
Quoted 1 line
(quoted diff) +1
-0+ struct device_attribute *attr, char *buf)+{
drivers/hwmon/occ/occ_sysfs.c line 90
Quoted 6 lines
drivers/hwmon/occ/occ_sysfs.c new file +6
-0+int val; +struct caps_sensor *sensor; +struct sensor_attr_data *sdata =container_of (attr, + struct sensor_attr_data, + dev_attr); +struct occ_sysfs *driver =dev_get_drvdata (dev);+
drivers/hwmon/occ/occ_sysfs.c line 96
Quoted 5 lines
drivers/hwmon/occ/occ_sysfs.c new file +5
-0+ sensor =occ_get_sensor (driver->occ,CAPS ); +if (!sensor) { + val =-1 ; +return snprintf (buf,PAGE_SIZE -1 ,"%d\n" , val); + }+
drivers/hwmon/occ/occ_sysfs.c line 99
Quoted 2 lines
drivers/hwmon/occ/occ_sysfs.c new file +2
-0+ val =occ_get_caps_value (driver->occ, sensor, sdata->hwmon_index -1 , + sdata->attr_id);+
Quoted 1 line
(quoted diff) +1
-0+ return snprintf(buf, PAGE_SIZE - 1, "%d\n", val);drivers/hwmon/occ/occ_sysfs.c new file +3
-0+} + +static ssize_t show_update_interval(struct device *dev,Review
Quoted 1 line
(quoted diff) +1
-0+ struct device_attribute *attr, char *buf)+{
Review
Quoted 1 line
(quoted diff) +1
-0+ struct occ_sysfs *driver = dev_get_drvdata(dev);+
Quoted 1 line
drivers/hwmon/occ/occ_sysfs.c new file +1
-0+return snprintf (buf,PAGE_SIZE -1 ,"%lu\n" , driver->update_interval);drivers/hwmon/occ/occ_sysfs.c new file +3
-0+} + +static ssize_t store_update_interval(struct device *dev,Review
Quoted 2 lines
(quoted diff) +2
-0+ struct device_attribute *attr, + const char *buf, size_t count)+{
drivers/hwmon/occ/occ_sysfs.c line 118
Quoted 3 lines
drivers/hwmon/occ/occ_sysfs.c new file +3
-0+struct occ_sysfs *driver =dev_get_drvdata (dev); +unsigned long val; +int rc;+
drivers/hwmon/occ/occ_sysfs.c line 122
Quoted 3 lines
drivers/hwmon/occ/occ_sysfs.c new file +3
-0+ rc =kstrtoul (buf,10 , &val); +if (rc) +return rc;+
drivers/hwmon/occ/occ_sysfs.c line 125
Quoted 2 lines
drivers/hwmon/occ/occ_sysfs.c new file +2
-0+ driver->update_interval = val; +occ_set_update_interval (driver->occ, val);+
Quoted 1 line
(quoted diff) +1
-0+ return count;drivers/hwmon/occ/occ_sysfs.c new file +3
-0+} + +static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_update_interval,Quoted 1 line
drivers/hwmon/occ/occ_sysfs.c new file +1
-0+ store_update_interval);drivers/hwmon/occ/occ_sysfs.c new file +2
-0+ +static ssize_t show_name(struct device *dev,Review
Quoted 1 line
(quoted diff) +1
-0+ struct device_attribute *attr, char *buf)+{
Quoted 1 line
drivers/hwmon/occ/occ_sysfs.c new file +1
-0+return snprintf (buf,PAGE_SIZE -1 ,"occ\n" );drivers/hwmon/occ/occ_sysfs.c new file +5
-0+} + +static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); + +static ssize_t show_user_powercap(struct device *dev,Review
Quoted 1 line
(quoted diff) +1
-0+ struct device_attribute *attr, char *buf)+{
Review
Quoted 1 line
(quoted diff) +1
-0+ struct occ_sysfs *driver = dev_get_drvdata(dev);+
Quoted 1 line
drivers/hwmon/occ/occ_sysfs.c new file +1
-0+return snprintf (buf,PAGE_SIZE -1 ,"%u\n" , driver->user_powercap);drivers/hwmon/occ/occ_sysfs.c new file +3
-0+} + +static ssize_t store_user_powercap(struct device *dev,Review
Quoted 2 lines
(quoted diff) +2
-0+ struct device_attribute *attr, + const char *buf, size_t count)+{
drivers/hwmon/occ/occ_sysfs.c line 155
Quoted 3 lines
drivers/hwmon/occ/occ_sysfs.c new file +3
-0+struct occ_sysfs *driver =dev_get_drvdata (dev); +u16 val; +int rc;+
drivers/hwmon/occ/occ_sysfs.c line 159
Quoted 3 lines
drivers/hwmon/occ/occ_sysfs.c new file +3
-0+ rc =kstrtou16 (buf,10 , &val); +if (rc) +return rc;+
drivers/hwmon/occ/occ_sysfs.c line 168
Quoted 8 lines
drivers/hwmon/occ/occ_sysfs.c new file +8
-0+dev_dbg (dev,"set user powercap to: %d\n" , val); + rc =occ_set_user_powercap (driver->occ, val); +if (rc) { +dev_err (dev,"set user powercap failed: 0x%x\n" , rc); +if (rc ==RESP_RETURN_CMD_INVAL ) { +dev_err (dev,"set invalid powercap value: %d\n" , val); +return -EINVAL ; + }+
Review
Quoted 2 lines
(quoted diff) +2
-0+ return rc; + }+
drivers/hwmon/occ/occ_sysfs.c line 173
Quoted 1 line
drivers/hwmon/occ/occ_sysfs.c new file +1
-0+ driver->user_powercap = val;+
Quoted 1 line
(quoted diff) +1
-0+ return count;drivers/hwmon/occ/occ_sysfs.c new file +3
-0+} + +static DEVICE_ATTR(user_powercap, S_IWUSR | S_IRUGO, show_user_powercap,Quoted 1 line
drivers/hwmon/occ/occ_sysfs.c new file +1
-0+ store_user_powercap);drivers/hwmon/occ/occ_sysfs.c new file +2
-0+ +static void deinit_sensor_groups(struct device *dev,drivers/hwmon/occ/occ_sysfs.c line 182
Quoted 1 line
drivers/hwmon/occ/occ_sysfs.c new file +1
-0+ struct sensor_group *sensor_groups)+{
drivers/hwmon/occ/occ_sysfs.c line 184
Quoted 1 line
drivers/hwmon/occ/occ_sysfs.c new file +1
-0+int i;+
Quoted 8 lines
drivers/hwmon/occ/occ_sysfs.c new file +8
-0+for (i =0 ; i <MAX_OCC_SENSOR_TYPE ; i++) { +if (sensor_groups[i].group.attrs) +devm_kfree (dev, sensor_groups[i].group.attrs); +if (sensor_groups[i].sattr) +devm_kfree (dev, sensor_groups[i].sattr); + sensor_groups[i].group.attrs =NULL ; + sensor_groups[i].sattr =NULL ; + }drivers/hwmon/occ/occ_sysfs.c new file +3
-0+} + +static void sensor_attr_init(struct sensor_attr_data *sdata,drivers/hwmon/occ/occ_sysfs.c line 201
Quoted 5 lines
drivers/hwmon/occ/occ_sysfs.c new file +5
-0+ char *sensor_group_name, + char *attr_name, + ssize_t (*show)(struct device *dev, + struct device_attribute *attr, + char *buf))+{
Review
Quoted 1 line
(quoted diff) +1
-0+ sysfs_attr_init(&sdata->dev_attr.attr);+
Quoted 5 lines
drivers/hwmon/occ/occ_sysfs.c new file +5
-0+snprintf (sdata->name,MAX_SENSOR_ATTR_LEN ,"%s%d_%s" , + sensor_group_name, sdata->hwmon_index, attr_name); + sdata->dev_attr.attr.name = sdata->name; + sdata->dev_attr.attr.mode =S_IRUGO ; + sdata->dev_attr.show = show;drivers/hwmon/occ/occ_sysfs.c new file +3
-0+} + +static int create_sensor_group(struct occ_sysfs *driver,drivers/hwmon/occ/occ_sysfs.c line 213
Quoted 1 line
drivers/hwmon/occ/occ_sysfs.c new file +1
-0+ enum sensor_type type, int sensor_num)+{
drivers/hwmon/occ/occ_sysfs.c line 218
Quoted 4 lines
drivers/hwmon/occ/occ_sysfs.c new file +4
-0+struct device *dev = driver->dev; +struct sensor_group *sensor_groups = driver->sensor_groups; +struct sensor_attr_data *sdata; +int rc, i;+
drivers/hwmon/occ/occ_sysfs.c line 227
Quoted 8 lines
drivers/hwmon/occ/occ_sysfs.c new file +8
-0+/* each sensor has 'label' and 'input' attributes */ + sensor_groups[type].group.attrs = +devm_kzalloc (dev,sizeof (struct attribute *) * + sensor_num * 2 + 1, GFP_KERNEL); +if (!sensor_groups[type].group.attrs) { + rc = -ENOMEM ; + goto err; + }+
drivers/hwmon/occ/occ_sysfs.c line 235
Quoted 7 lines
drivers/hwmon/occ/occ_sysfs.c new file +7
-0+ sensor_groups[type].sattr = +devm_kzalloc (dev,sizeof (struct sensor_attr_data ) * + sensor_num * 2, GFP_KERNEL); +if (!sensor_groups[type].sattr) { + rc = -ENOMEM ; + goto err; + }+
drivers/hwmon/occ/occ_sysfs.c line 244
Quoted 8 lines
drivers/hwmon/occ/occ_sysfs.c new file +8
-0+for (i =0 ; i < sensor_num; i++) { + sdata = &sensor_groups[type].sattr[i]; +/* hwmon attributes index starts from 1 */ + sdata->hwmon_index = i +1 ; + sdata->type = type; +sensor_attr_init (sdata, sensor_groups[type].name,"input" , + show_input); + sensor_groups[type].group.attrs[i] = &sdata->dev_attr.attr;+
drivers/hwmon/occ/occ_sysfs.c line 253
Quoted 8 lines
drivers/hwmon/occ/occ_sysfs.c new file +8
-0+ sdata = &sensor_groups[type].sattr[i + sensor_num]; + sdata->hwmon_index = i +1 ; + sdata->type = type; +sensor_attr_init (sdata, sensor_groups[type].name,"label" , + show_label); + sensor_groups[type].group.attrs[i + sensor_num] = + &sdata->dev_attr.attr; + }+
drivers/hwmon/occ/occ_sysfs.c line 257
Quoted 3 lines
drivers/hwmon/occ/occ_sysfs.c new file +3
-0+ rc =sysfs_create_group (&dev->kobj, &sensor_groups[type].group); +if (rc) + goto err;+
Review
Quoted 1 line
(quoted diff) +1
-0+ return 0;+err:
Quoted 2 lines
(quoted diff) +2
-0+ deinit_sensor_groups(dev, sensor_groups); + return rc;drivers/hwmon/occ/occ_sysfs.c new file +3
-0+} + +static void caps_sensor_attr_init(struct sensor_attr_data *sdata,drivers/hwmon/occ/occ_sysfs.c line 267
Quoted 2 lines
drivers/hwmon/occ/occ_sysfs.c new file +2
-0+ char *attr_name, uint32_t hwmon_index, + uint32_t attr_id)+{
drivers/hwmon/occ/occ_sysfs.c line 271
Quoted 3 lines
drivers/hwmon/occ/occ_sysfs.c new file +3
-0+ sdata->type =CAPS ; + sdata->hwmon_index = hwmon_index; + sdata->attr_id = attr_id;+
drivers/hwmon/occ/occ_sysfs.c line 274
Quoted 2 lines
drivers/hwmon/occ/occ_sysfs.c new file +2
-0+snprintf (sdata->name,MAX_SENSOR_ATTR_LEN ,"%s%d_%s" , + "caps", sdata->hwmon_index, attr_name);+
Quoted 4 lines
drivers/hwmon/occ/occ_sysfs.c new file +4
-0+sysfs_attr_init (&sdata->dev_attr.attr); + sdata->dev_attr.attr.name = sdata->name; + sdata->dev_attr.attr.mode =S_IRUGO ; + sdata->dev_attr.show = show_caps;drivers/hwmon/occ/occ_sysfs.c new file +4
-0+} + +static int create_caps_sensor_group (struct occ_sysfs *driver,int sensor_num) +{drivers/hwmon/occ/occ_sysfs.c line 288
Quoted 5 lines
drivers/hwmon/occ/occ_sysfs.c new file +5
-0+struct device *dev = driver->dev; +struct sensor_group *sensor_groups = driver->sensor_groups; +int field_num = driver->num_caps_fields; +struct sensor_attr_data *sdata; +int i, j, rc;+
drivers/hwmon/occ/occ_sysfs.c line 296
Quoted 7 lines
drivers/hwmon/occ/occ_sysfs.c new file +7
-0+ sensor_groups[CAPS ].group.attrs = +devm_kzalloc (dev,sizeof (struct attribute *) * sensor_num * + field_num + 1, GFP_KERNEL); +if (!sensor_groups[CAPS ].group.attrs) { + rc = -ENOMEM ; + goto err; + }+
drivers/hwmon/occ/occ_sysfs.c line 304
Quoted 7 lines
drivers/hwmon/occ/occ_sysfs.c new file +7
-0+ sensor_groups[CAPS ].sattr = +devm_kzalloc (dev,sizeof (struct sensor_attr_data ) * + sensor_num * field_num, GFP_KERNEL); +if (!sensor_groups[CAPS ].sattr) { + rc = -ENOMEM ; + goto err; + }+
drivers/hwmon/occ/occ_sysfs.c line 314
Quoted 9 lines
drivers/hwmon/occ/occ_sysfs.c new file +9
-0+for (j =0 ; j < sensor_num; ++j) { +for (i =0 ; i < field_num; ++i) { + sdata = &sensor_groups[CAPS ].sattr[j * field_num + i]; +caps_sensor_attr_init (sdata, + driver->caps_names[i], j + 1, i); + sensor_groups[CAPS ].group.attrs[j * field_num + i] = + &sdata->dev_attr.attr; + } + }+
drivers/hwmon/occ/occ_sysfs.c line 318
Quoted 3 lines
drivers/hwmon/occ/occ_sysfs.c new file +3
-0+ rc =sysfs_create_group (&dev->kobj, &sensor_groups[CAPS ].group); +if (rc) + goto err;+
Review
Quoted 1 line
(quoted diff) +1
-0+ return rc;+err:
Quoted 2 lines
(quoted diff) +2
-0+ deinit_sensor_groups(dev, sensor_groups); + return rc;drivers/hwmon/occ/occ_sysfs.c new file +4
-0+} + +static void occ_remove_hwmon_attrs (struct occ_sysfs *driver) +{Review
Quoted 1 line
(quoted diff) +1
-0+ struct device *dev = driver->dev;+
Quoted 3 lines
drivers/hwmon/occ/occ_sysfs.c new file +3
-0+device_remove_file (dev, &dev_attr_user_powercap); +device_remove_file (dev, &dev_attr_update_interval); +device_remove_file (dev, &dev_attr_name);drivers/hwmon/occ/occ_sysfs.c new file +4
-0+} + +static int occ_create_hwmon_attrs (struct occ_sysfs *driver) +{drivers/hwmon/occ/occ_sysfs.c line 340
Quoted 4 lines
drivers/hwmon/occ/occ_sysfs.c new file +4
-0+int i, rc, id, sensor_num; +struct device *dev = driver->dev; +struct sensor_group *sensor_groups = driver->sensor_groups; +struct occ_blocks *resp =NULL ;+
drivers/hwmon/occ/occ_sysfs.c line 342
Quoted 1 line
drivers/hwmon/occ/occ_sysfs.c new file +1
-0+occ_get_response_blocks (driver->occ, &resp);+
drivers/hwmon/occ/occ_sysfs.c line 345
Quoted 2 lines
drivers/hwmon/occ/occ_sysfs.c new file +2
-0+for (i =0 ; i <MAX_OCC_SENSOR_TYPE ; ++i) + resp->sensor_block_id[i] =-1 ;+
drivers/hwmon/occ/occ_sysfs.c line 354
Quoted 8 lines
drivers/hwmon/occ/occ_sysfs.c new file +8
-0+/* read sensor data from occ */ + rc =occ_update_device (driver->occ); +if (rc) { +dev_err (dev,"cannot get occ sensor data: %d\n" , rc); +return rc; + } +if (!resp->blocks) +return -ENOMEM ;+
drivers/hwmon/occ/occ_sysfs.c line 358
Quoted 3 lines
drivers/hwmon/occ/occ_sysfs.c new file +3
-0+ rc =device_create_file (dev, &dev_attr_name); +if (rc) + goto error;+
drivers/hwmon/occ/occ_sysfs.c line 362
Quoted 3 lines
drivers/hwmon/occ/occ_sysfs.c new file +3
-0+ rc =device_create_file (dev, &dev_attr_update_interval); +if (rc) + goto error;+
drivers/hwmon/occ/occ_sysfs.c line 369
Quoted 6 lines
drivers/hwmon/occ/occ_sysfs.c new file +6
-0+if (resp->sensor_block_id[CAPS ] >=0 ) { +/* user powercap: only for master OCC */ + rc =device_create_file (dev, &dev_attr_user_powercap); +if (rc) + goto error; + }+
drivers/hwmon/occ/occ_sysfs.c line 374
Quoted 4 lines
drivers/hwmon/occ/occ_sysfs.c new file +4
-0+ sensor_groups[FREQ ].name ="freq" ; + sensor_groups[TEMP ].name ="temp" ; + sensor_groups[POWER ].name ="power" ; + sensor_groups[CAPS ].name ="caps" ;+
drivers/hwmon/occ/occ_sysfs.c line 379
Quoted 4 lines
drivers/hwmon/occ/occ_sysfs.c new file +4
-0+for (i =0 ; i <MAX_OCC_SENSOR_TYPE ; i++) { + id = resp->sensor_block_id[i]; +if (id <0 ) +continue ;+
drivers/hwmon/occ/occ_sysfs.c line 388
Quoted 8 lines
drivers/hwmon/occ/occ_sysfs.c new file +8
-0+ sensor_num = resp->blocks[id].header.sensor_num; +if (i ==CAPS ) + rc =create_caps_sensor_group (driver, sensor_num); +else + rc =create_sensor_group (driver, i, sensor_num); +if (rc) + goto error; + }+
Quoted 1 line
(quoted diff) +1
-0+ return 0;drivers/hwmon/occ/occ_sysfs.c new file +2
-0+ +error:Quoted 3 lines
drivers/hwmon/occ/occ_sysfs.c new file +3
-0+dev_err (dev,"cannot create hwmon attributes: %d\n" , rc); +occ_remove_hwmon_attrs (driver); +return rc;drivers/hwmon/occ/occ_sysfs.c new file +3
-0+} + +static ssize_t show_occ_online(struct device *dev,Review
Quoted 1 line
(quoted diff) +1
-0+ struct device_attribute *attr, char *buf)+{
Review
Quoted 1 line
(quoted diff) +1
-0+ struct occ_sysfs *driver = dev_get_drvdata(dev);+
Quoted 1 line
drivers/hwmon/occ/occ_sysfs.c new file +1
-0+return snprintf (buf,PAGE_SIZE -1 ,"%u\n" , driver->occ_online);drivers/hwmon/occ/occ_sysfs.c new file +3
-0+} + +static ssize_t store_occ_online(struct device *dev,Review
Quoted 2 lines
(quoted diff) +2
-0+ struct device_attribute *attr, + const char *buf, size_t count)+{
drivers/hwmon/occ/occ_sysfs.c line 118
Quoted 3 lines
drivers/hwmon/occ/occ_sysfs.c new file +3
-0+struct occ_sysfs *driver =dev_get_drvdata (dev); +unsigned long val; +int rc;+
drivers/hwmon/occ/occ_sysfs.c line 122
Quoted 3 lines
drivers/hwmon/occ/occ_sysfs.c new file +3
-0+ rc =kstrtoul (buf,10 , &val); +if (rc) +return rc;+
drivers/hwmon/occ/occ_sysfs.c line 420
Quoted 3 lines
drivers/hwmon/occ/occ_sysfs.c new file +3
-0+if (val ==1 ) { +if (driver->occ_online) +return count;+
drivers/hwmon/occ/occ_sysfs.c line 424
Quoted 3 lines
drivers/hwmon/occ/occ_sysfs.c new file +3
-0+ driver->dev =hwmon_device_register (dev); +if (IS_ERR (driver->dev)) +return PTR_ERR (driver->dev);+
drivers/hwmon/occ/occ_sysfs.c line 426
Quoted 1 line
drivers/hwmon/occ/occ_sysfs.c new file +1
-0+dev_set_drvdata (driver->dev, driver);+
drivers/hwmon/occ/occ_sysfs.c line 436
Quoted 9 lines
drivers/hwmon/occ/occ_sysfs.c new file +9
-0+ rc =occ_create_hwmon_attrs (driver); +if (rc) { +hwmon_device_unregister (driver->dev); + driver->dev =NULL ; +return rc; + } + }else if (val ==0 ) { +if (!driver->occ_online) +return count;+
drivers/hwmon/occ/occ_sysfs.c line 442
Quoted 5 lines
drivers/hwmon/occ/occ_sysfs.c new file +5
-0+occ_remove_hwmon_attrs (driver); +hwmon_device_unregister (driver->dev); + driver->dev =NULL ; + }else +return -EINVAL ;+
Quoted 2 lines
drivers/hwmon/occ/occ_sysfs.c new file +2
-0+ driver->occ_online = val; +return count;drivers/hwmon/occ/occ_sysfs.c new file +3
-0+} + +static DEVICE_ATTR(online, S_IWUSR | S_IRUGO, show_occ_online,Quoted 1 line
drivers/hwmon/occ/occ_sysfs.c new file +1
-0+ store_occ_online);drivers/hwmon/occ/occ_sysfs.c new file +2
-0+ +struct occ_sysfs *occ_sysfs_start(struct device *dev, struct occ *occ,drivers/hwmon/occ/occ_sysfs.c line 452
Quoted 1 line
drivers/hwmon/occ/occ_sysfs.c new file +1
-0+ struct occ_sysfs_config *config)+{
drivers/hwmon/occ/occ_sysfs.c line 456
Quoted 3 lines
drivers/hwmon/occ/occ_sysfs.c new file +3
-0+struct occ_sysfs *hwmon =devm_kzalloc (dev,sizeof (struct occ_sysfs ), + GFP_KERNEL); +int rc;+
drivers/hwmon/occ/occ_sysfs.c line 459
Quoted 2 lines
drivers/hwmon/occ/occ_sysfs.c new file +2
-0+if (!hwmon) +return ERR_PTR (-ENOMEM );+
drivers/hwmon/occ/occ_sysfs.c line 463
Quoted 3 lines
drivers/hwmon/occ/occ_sysfs.c new file +3
-0+ hwmon->occ = occ; + hwmon->num_caps_fields = config->num_caps_fields; + hwmon->caps_names = config->caps_names;+
drivers/hwmon/occ/occ_sysfs.c line 465
Quoted 1 line
drivers/hwmon/occ/occ_sysfs.c new file +1
-0+dev_set_drvdata (dev, hwmon);+
drivers/hwmon/occ/occ_sysfs.c line 469
Quoted 3 lines
drivers/hwmon/occ/occ_sysfs.c new file +3
-0+ rc =device_create_file (dev, &dev_attr_online); +if (rc) +return ERR_PTR (rc);+
Quoted 1 line
drivers/hwmon/occ/occ_sysfs.c new file +1
-0+return hwmon;drivers/hwmon/occ/occ_sysfs.c new file +5
-0+} +EXPORT_SYMBOL (occ_sysfs_start); + +int occ_sysfs_stop (struct device *dev,struct occ_sysfs *driver) +{drivers/hwmon/occ/occ_sysfs.c line 480
Quoted 4 lines
drivers/hwmon/occ/occ_sysfs.c new file +4
-0+if (driver->dev) { +occ_remove_hwmon_attrs (driver); +hwmon_device_unregister (driver->dev); + }+
drivers/hwmon/occ/occ_sysfs.c line 482
Quoted 1 line
drivers/hwmon/occ/occ_sysfs.c new file +1
-0+device_remove_file (driver->dev, &dev_attr_online);+
drivers/hwmon/occ/occ_sysfs.c line 484
Quoted 1 line
drivers/hwmon/occ/occ_sysfs.c new file +1
-0+devm_kfree (dev, driver);+
Quoted 1 line
(quoted diff) +1
-0+ return 0;drivers/hwmon/occ/occ_sysfs.c new file +3
-0+} +EXPORT_SYMBOL (occ_sysfs_stop); +Quoted 1 line
+MODULE_AUTHOR("Eddie James <[email protected]>");
drivers/hwmon/occ/occ_sysfs.c new file +2
-0+MODULE_DESCRIPTION ("OCC sysfs driver" ); +MODULE_LICENSE ("GPL" );drivers/hwmon/occ/occ_sysfs.h new file +25
-0@@ -0,0 +1,52 @@ +/* +* occ_sysfs.h - OCC sysfs interface +* +* This file contains the data structures and function prototypes for the OCC +* hwmon sysfs entries. +* +* Copyright 2016 IBM Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#ifndef __OCC_SYSFS_H__ +#define __OCC_SYSFS_H__ + +#include "occ.h" + +struct sensor_group {Quoted 3 lines
drivers/hwmon/occ/occ_sysfs.h new file +3
-0+char *name; +struct sensor_attr_data *sattr; +struct attribute_group group;drivers/hwmon/occ/occ_sysfs.h new file +3
-0+}; + +struct occ_sysfs_config {Quoted 2 lines
(quoted diff) +2
-0+ unsigned int num_caps_fields; + char **caps_names;drivers/hwmon/occ/occ_sysfs.h new file +3
-0+}; + +struct occ_sysfs {drivers/hwmon/occ/occ_sysfs.h line 38
Quoted 2 lines
drivers/hwmon/occ/occ_sysfs.h new file +2
-0+struct device *dev; +struct occ *occ;+
Quoted 6 lines
drivers/hwmon/occ/occ_sysfs.h new file +6
-0+u16 user_powercap; +bool occ_online; +struct sensor_group sensor_groups[MAX_OCC_SENSOR_TYPE ]; +unsigned long update_interval; +unsigned int num_caps_fields; +char **caps_names;drivers/hwmon/occ/occ_sysfs.h new file +3
-0+}; + +struct occ_sysfs *occ_sysfs_start(struct device *dev, struct occ *occ,Quoted 1 line
drivers/hwmon/occ/occ_sysfs.h new file +1
-0+ struct occ_sysfs_config *config);drivers/hwmon/occ/occ_sysfs.h new file +3
-0+int occ_sysfs_stop (struct device *dev,struct occ_sysfs *driver); + +#endif /* __OCC_SYSFS_H__ */