hwmon: Add OCC sensor groups
RFC v4 5/6 hwmon: Add OCC sensor groups
From: "Edward A. James" <[email protected]>
Add sensor groups for all frequency, temperature, and power sensors on the OCC. Sysfs attributes for the sensor label and input.
Signed-off-by Edward A. James <[email protected]>
--- drivers/hwmon/occ/power8_occ.c | 203 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 202 insertions(+), 1 deletion(-)
drivers/hwmon/occ/power8_occ.c +202 -1
@@ -53,6 +53,8 @@#define SENSOR_BLOCK_NUM_OFFSET 43#define SENSOR_BLOCK_OFFSET 45 +#define MAX_SENSOR_ATTR_LEN 32 +enum sensor_type {FREQ =0 ,TEMP ,
@@ -124,6 +126,20 @@ struct occ_response {int sensor_block_id[MAX_OCC_SENSOR_TYPE ]; }; +struct sensor_attr_data { +enum sensor_type type; +u32 hwmon_index; +u32 attr_id; +char name[MAX_SENSOR_ATTR_LEN ]; +struct device_attribute dev_attr; +}; + +struct sensor_group { +char *name; +struct sensor_attr_data *sattr; +struct attribute_group group; +}; +struct power8_driver {struct occ_driver *driver;struct device *dev;
@@ -133,6 +149,7 @@ struct power8_driver {struct mutex update_lock;bool valid;struct occ_response occ_response; +struct sensor_group sensor_groups[MAX_OCC_SENSOR_TYPE ]; };static void deinit_occ_resp_buf (struct occ_response *resp)
@@ -560,6 +577,88 @@ static int occ_update_device(struct power8_driver *driver)return rc; } +static void *occ_get_sensor (struct power8_driver *driver, +enum sensor_type t) +{ +int rc; + + rc =occ_update_device (driver); +if (rc !=0 ) { +dev_dbg (driver->dev,"ERROR: cannot get occ sensor data: %d\n" , + rc); +return NULL ; + } + +return occ_get_sensor_by_type (&driver->occ_response, t); +} + +static int occ_get_sensor_value (struct power8_driver *driver, +enum sensor_type t,int index) +{ +void *sensor; + +if (t ==CAPS ) +return -1 ; + + sensor =occ_get_sensor (driver, t); +if (!sensor) +return -1 ; + +if (t ==POWER ) +return ((struct power_sensor *)sensor)[index].value; + +return ((struct occ_sensor *)sensor)[index].value; +} + +static int occ_get_sensor_id (struct power8_driver *driver, +enum sensor_type t,int index) +{ +void *sensor; + +if (t ==CAPS ) +return -1 ; + + sensor =occ_get_sensor (driver, t); +if (!sensor) +return -1 ; + +if (t ==POWER ) +return ((struct power_sensor *)sensor)[index].sensor_id; + +return ((struct occ_sensor *)sensor)[index].sensor_id; +} + +static ssize_t show_input (struct device *dev, +struct device_attribute *attr,char *buf) +{ +int val; +struct sensor_attr_data *sdata =container_of (attr, + struct sensor_attr_data, + dev_attr); +struct power8_driver *driver =dev_get_drvdata (dev); + + val =occ_get_sensor_value (driver, sdata->type, + sdata->hwmon_index -1 ); +if (sdata->type ==TEMP ) + val *=1000 ;/* in millidegree Celsius */ + +return snprintf (buf,PAGE_SIZE -1 ,"%d\n" , val); +} + +static ssize_t show_label (struct device *dev, +struct device_attribute *attr,char *buf) +{ +int val; +struct sensor_attr_data *sdata =container_of (attr, + struct sensor_attr_data, + dev_attr); +struct power8_driver *driver =dev_get_drvdata (dev); + + val =occ_get_sensor_id (driver, sdata->type, sdata->hwmon_index -1 ); + +return snprintf (buf,PAGE_SIZE -1 ,"%d\n" , val); +} +static ssize_t show_update_interval (struct device *dev,struct device_attribute *attr,char *buf) {
@@ -639,6 +738,90 @@ static ssize_t store_user_powercap(struct device *dev, static DEVICE_ATTR(user_powercap, S_IWUSR | S_IRUGO, show_user_powercap, store_user_powercap); +static void deinit_sensor_groups (struct device *dev, +struct sensor_group *sensor_groups) +{ +int cnt; + +for (cnt =0 ; cnt <MAX_OCC_SENSOR_TYPE ; cnt++) { +if (sensor_groups[cnt].group.attrs) +devm_kfree (dev, sensor_groups[cnt].group.attrs); +if (sensor_groups[cnt].sattr) +devm_kfree (dev, sensor_groups[cnt].sattr); + sensor_groups[cnt].group.attrs =NULL ; + sensor_groups[cnt].sattr =NULL ; + } +} + +static void sensor_attr_init (struct sensor_attr_data *sdata, +char *sensor_group_name, +char *attr_name, +ssize_t (*show)(struct device *dev, +struct device_attribute *attr, +char *buf)) +{ +sysfs_attr_init (&sdata->dev_attr.attr); + +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; +} + +static int create_sensor_group (struct power8_driver *driver, +enum sensor_type type,int sensor_num) +{ +struct device *dev = driver->dev; +struct sensor_group *sensor_groups = driver->sensor_groups; +struct sensor_attr_data *sdata; +int rc, cnt; + +/* 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; + } + + 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; + } + +for (cnt =0 ; cnt < sensor_num; cnt++) { + sdata = &sensor_groups[type].sattr[cnt]; +/* hwmon attributes index starts from 1 */ + sdata->hwmon_index = cnt +1 ; + sdata->type = type; +sensor_attr_init (sdata, sensor_groups[type].name,"input" , + show_input); + sensor_groups[type].group.attrs[cnt] = &sdata->dev_attr.attr; + + sdata = &sensor_groups[type].sattr[cnt + sensor_num]; + sdata->hwmon_index = cnt +1 ; + sdata->type = type; +sensor_attr_init (sdata, sensor_groups[type].name,"label" , + show_label); + sensor_groups[type].group.attrs[cnt + sensor_num] = + &sdata->dev_attr.attr; + } + + rc =sysfs_create_group (&dev->kobj, &sensor_groups[type].group); +if (rc) + goto err; + +return 0 ; +err: +deinit_sensor_groups (dev, sensor_groups); +return rc; +} +static void occ_remove_hwmon_attrs (struct power8_driver *driver) {struct device *dev = driver->dev;
@@ -650,8 +833,9 @@ static void occ_remove_hwmon_attrs(struct power8_driver *driver)static int occ_create_hwmon_attrs (struct power8_driver *driver) { -int i, rc; +int i, rc, id, sensor_num;struct device *dev = driver->dev; +struct sensor_group *sensor_groups = driver->sensor_groups;struct occ_response *resp = &driver->occ_response;for (i =0 ; i <MAX_OCC_SENSOR_TYPE ; ++i)
@@ -681,6 +865,23 @@ static int occ_create_hwmon_attrs(struct power8_driver *driver) goto error; } + sensor_groups[FREQ ].name ="freq" ; + sensor_groups[TEMP ].name ="temp" ; + sensor_groups[POWER ].name ="power" ; + sensor_groups[CAPS ].name ="caps" ; + +for (i =0 ; i <MAX_OCC_SENSOR_TYPE ; i++) { + id = resp->sensor_block_id[i]; +if (id <0 ) +continue ; + + sensor_num = resp->blocks[id].sensor_num; +if (i !=CAPS ) + rc =create_sensor_group (driver, i, sensor_num); +if (rc) + goto error; + } +return 0 ; error:
Signature · 1 line
1.9.1