On Thu, Mar 09, 2017 at 05:19:15PM +0530, Shilpasri G Bhat wrote:
> Add support to read power and temperature sensors from OCC inband
> sensors which are copied to main memory by OCC.
>

Is this supposed to be an alternative to the submission from 
Eddie James ? If so, is there a reason to consider such an
alternative ?

Thanks,
Guenter

> Signed-off-by: Shilpasri G Bhat <shilpa.b...@linux.vnet.ibm.com>
> CC: Rob Herring <robh...@kernel.org>
> CC: Mark Rutland <mark.rutl...@arm.com>
> CC: Jean Delvare <jdelv...@suse.com>
> CC: Guenter Roeck <li...@roeck-us.net>
> CC: Jonathan Corbet <cor...@lwn.net>
> CC: devicet...@vger.kernel.org
> CC: linux-hw...@vger.kernel.org
> CC: linux-doc@vger.kernel.org
> ---
>  .../devicetree/bindings/hwmon/ibmpowernv-occ.txt   |   4 +
>  Documentation/hwmon/ibmpowernv-occ                 |  24 ++
>  drivers/hwmon/Kconfig                              |  11 +
>  drivers/hwmon/Makefile                             |   1 +
>  drivers/hwmon/ibmpowernv-occ.c                     | 302 
> +++++++++++++++++++++
>  5 files changed, 342 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/hwmon/ibmpowernv-occ.txt
>  create mode 100644 Documentation/hwmon/ibmpowernv-occ
>  create mode 100644 drivers/hwmon/ibmpowernv-occ.c
> 
> diff --git a/Documentation/devicetree/bindings/hwmon/ibmpowernv-occ.txt 
> b/Documentation/devicetree/bindings/hwmon/ibmpowernv-occ.txt
> new file mode 100644
> index 0000000..d03f744
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/hwmon/ibmpowernv-occ.txt
> @@ -0,0 +1,4 @@
> +IBM POWERNV OCC inband platform sensors
> +
> +Required device-tree property:
> +- compatible: "ibm,p9-occ-inband-sensor"
> diff --git a/Documentation/hwmon/ibmpowernv-occ 
> b/Documentation/hwmon/ibmpowernv-occ
> new file mode 100644
> index 0000000..151028b
> --- /dev/null
> +++ b/Documentation/hwmon/ibmpowernv-occ
> @@ -0,0 +1,24 @@
> +Kernel driver ibmpowernv-occ
> +=============================
> +
> +Supported systems:
> + * P9 server based on POWERNV platform
> +
> +Description
> +------------
> +
> +This driver exports the power and temperature sensors from OCC inband
> +sensors on P9 POWERNV platforms.
> +
> +Sysfs attributes
> +----------------
> +
> +powerX_input         Latest power reading
> +powerX_input_highest Minimum power
> +powerX_input_lowest  Maximum power
> +powerX_label         Sensor name
> +
> +tempX_input          Latest temperature reading
> +tempX_max            Minimum temperature
> +tempX_min            Maximum temperature
> +tempX_label          Sensor name
> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index 0649d53f3..3b1dbb9 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -598,6 +598,17 @@ config SENSORS_IBMPOWERNV
>         This driver can also be built as a module. If so, the module
>         will be called ibmpowernv.
>  
> +config SENSORS_IBMPOWERNV_OCC
> +     tristate "IBM POWERNV OCC Inband platform sensors"
> +     depends on PPC_POWERNV
> +     default y
> +     help
> +       If you say yes here you get support for the temperature/power
> +       OCC inband sensors on your PowerNV platform.
> +
> +       This driver can also be built as a module. If so, the module
> +       will be called ibmpowernv-occ.
> +
>  config SENSORS_IIO_HWMON
>       tristate "Hwmon driver that uses channels specified via iio maps"
>       depends on IIO
> diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
> index 5509edf..0da2207 100644
> --- a/drivers/hwmon/Makefile
> +++ b/drivers/hwmon/Makefile
> @@ -75,6 +75,7 @@ obj-$(CONFIG_SENSORS_I5K_AMB)       += i5k_amb.o
>  obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o
>  obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o
>  obj-$(CONFIG_SENSORS_IBMPOWERNV)+= ibmpowernv.o
> +obj-$(CONFIG_SENSORS_IBMPOWERNV_OCC)+= ibmpowernv-occ.o
>  obj-$(CONFIG_SENSORS_IIO_HWMON) += iio_hwmon.o
>  obj-$(CONFIG_SENSORS_INA209) += ina209.o
>  obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o
> diff --git a/drivers/hwmon/ibmpowernv-occ.c b/drivers/hwmon/ibmpowernv-occ.c
> new file mode 100644
> index 0000000..97b1bbe
> --- /dev/null
> +++ b/drivers/hwmon/ibmpowernv-occ.c
> @@ -0,0 +1,302 @@
> +/*
> + * IBM PowerNV platform OCC inband sensors for temperature/power
> + * Copyright (C) 2017 IBM
> + *
> + * 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.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.
> + */
> +
> +#define DRVNAME              "ibmpowernv_occ"
> +#define pr_fmt(fmt)  DRVNAME ": " fmt
> +
> +#include <linux/module.h>
> +#include <linux/hwmon.h>
> +#include <linux/slab.h>
> +#include <linux/platform_device.h>
> +
> +#include <asm/opal.h>
> +
> +#define MAX_HWMON_ATTR_LEN   32
> +#define MAX_HWMON_LABEL_LEN  (MAX_OCC_SENSOR_NAME_LEN * 2)
> +#define HWMON_ATTRS_PER_SENSOR       16
> +#define TO_MILLI_UNITS(x)    ((x) * 1000)
> +#define TO_MICRO_UNITS(x)    ((x) * 1000000)
> +
> +enum sensors {
> +     TEMP,
> +     POWER,
> +     MAX_SENSOR_TYPE,
> +};
> +
> +static struct sensor_type {
> +     const char *name;
> +     int hwmon_id;
> +} sensor_types[] = {
> +     { "temp"},
> +     { "power"},
> +};
> +
> +static struct sensor_data {
> +     u32 occ_id;
> +     u64 offset;  /* Offset to ping/pong reading buffer */
> +     enum sensors type;
> +     char label[MAX_HWMON_LABEL_LEN];
> +     char name[MAX_HWMON_ATTR_LEN];
> +     struct device_attribute attr;
> +} *sdata;
> +
> +static struct attribute_group sensor_attrs_group;
> +__ATTRIBUTE_GROUPS(sensor_attrs);
> +
> +#define show(file_name)                                                      
> \
> +static ssize_t ibmpowernv_occ_show_##file_name                               
> \
> +(struct device *dev, struct device_attribute *dattr, char *buf)              
> \
> +{                                                                    \
> +     struct sensor_data *sdata = container_of(dattr,                 \
> +                                              struct sensor_data,    \
> +                                              attr);                 \
> +     u64 val;                                                        \
> +     int ret;                                                        \
> +     ret = opal_occ_sensor_get_##file_name(sdata->occ_id,            \
> +                                           sdata->offset,            \
> +                                           &val);                    \
> +     if (ret)                                                        \
> +             return ret;                                             \
> +     if (sdata->type == TEMP)                                        \
> +             val = TO_MILLI_UNITS(val);                              \
> +     else if (sdata->type == POWER)                                  \
> +             val = TO_MICRO_UNITS(val);                              \
> +     return sprintf(buf, "%llu\n", val);                             \
> +}
> +
> +show(sample);
> +show(max);
> +show(min);
> +show(js_min);
> +show(js_max);
> +show(csm_min);
> +show(csm_max);
> +show(prof_min);
> +show(prof_max);
> +
> +static struct sensor_view_groups {
> +     const char *name;
> +     ssize_t (*show_sample)(struct device *dev,
> +                            struct device_attribute *attr,
> +                            char *buf);
> +     ssize_t (*show_min)(struct device *dev,
> +                         struct device_attribute *attr,
> +                         char *buf);
> +     ssize_t (*show_max)(struct device *dev,
> +                         struct device_attribute *attr,
> +                         char *buf);
> +} sensor_views[] = {
> +     {
> +             .name           = "",
> +             .show_sample    = ibmpowernv_occ_show_sample,
> +             .show_min       = ibmpowernv_occ_show_min,
> +             .show_max       = ibmpowernv_occ_show_max
> +     },
> +     {
> +             .name           = "_JS",
> +             .show_sample    = ibmpowernv_occ_show_sample,
> +             .show_min       = ibmpowernv_occ_show_js_min,
> +             .show_max       = ibmpowernv_occ_show_js_max
> +     },
> +     {       .name           = "_CSM",
> +             .show_sample    = ibmpowernv_occ_show_sample,
> +             .show_min       = ibmpowernv_occ_show_csm_min,
> +             .show_max       = ibmpowernv_occ_show_csm_max
> +     },
> +     {       .name           = "_Prof",
> +             .show_sample    = ibmpowernv_occ_show_sample,
> +             .show_min       = ibmpowernv_occ_show_prof_min,
> +             .show_max       = ibmpowernv_occ_show_prof_max
> +     },
> +};
> +
> +static ssize_t ibmpowernv_occ_show_label(struct device *dev,
> +                                      struct device_attribute *dattr,
> +                                      char *buf)
> +{
> +     struct sensor_data *sdata = container_of(dattr, struct sensor_data,
> +                                              attr);
> +
> +     return sprintf(buf, "%s\n", sdata->label);
> +}
> +
> +static int ibmpowernv_occ_get_sensor_type(enum occ_sensor_type type)
> +{
> +     switch (type) {
> +     case OCC_SENSOR_TYPE_POWER:
> +             return POWER;
> +     case OCC_SENSOR_TYPE_TEMPERATURE:
> +             return TEMP;
> +     default:
> +             return MAX_SENSOR_TYPE;
> +     }
> +
> +     return MAX_SENSOR_TYPE;
> +}
> +
> +static void ibmpowernv_occ_add_sdata(struct occ_hwmon_sensor sensor,
> +                                  struct sensor_data *sdata, char *name,
> +                                  int hwmon_id, enum sensors type,
> +                                  ssize_t (*show)(struct device *dev,
> +                                             struct device_attribute *attr,
> +                                             char *buf))
> +{
> +     sdata->type = type;
> +     sdata->occ_id = sensor.occ_id;
> +     sdata->offset = sensor.offset;
> +     snprintf(sdata->name, MAX_HWMON_ATTR_LEN, "%s%d_%s",
> +              sensor_types[type].name, hwmon_id, name);
> +     sysfs_attr_init(&sdata->attr.attr);
> +     sdata->attr.attr.name = sdata->name;
> +     sdata->attr.attr.mode = 0444;
> +     sdata->attr.show = show;
> +}
> +
> +static void ibmpowernv_occ_add_sensor_attrs(struct occ_hwmon_sensor sensor,
> +                                         int index)
> +{
> +     struct attribute **attrs = sensor_attrs_group.attrs;
> +     char attr_str[MAX_HWMON_ATTR_LEN];
> +     enum sensors type = ibmpowernv_occ_get_sensor_type(sensor.type);
> +     int i;
> +
> +     index *= HWMON_ATTRS_PER_SENSOR;
> +     for (i = 0; i < ARRAY_SIZE(sensor_views); i++) {
> +             int hid = ++sensor_types[type].hwmon_id;
> +
> +             /* input */
> +             ibmpowernv_occ_add_sdata(sensor, &sdata[index], "input", hid,
> +                                      type, sensor_views[i].show_sample);
> +             attrs[index] = &sdata[index].attr.attr;
> +             index++;
> +
> +             /* min */
> +             if (type == POWER)
> +                     snprintf(attr_str, MAX_HWMON_ATTR_LEN, "%s",
> +                              "input_lowest");
> +             else
> +                     snprintf(attr_str, MAX_HWMON_ATTR_LEN, "%s", "min");
> +
> +             ibmpowernv_occ_add_sdata(sensor, &sdata[index], attr_str, hid,
> +                                      type, sensor_views[i].show_min);
> +             attrs[index] = &sdata[index].attr.attr;
> +             index++;
> +
> +             /* max */
> +             if (type == POWER)
> +                     snprintf(attr_str, MAX_HWMON_ATTR_LEN, "%s",
> +                              "input_highest");
> +             else
> +                     snprintf(attr_str, MAX_HWMON_ATTR_LEN, "%s", "max");
> +
> +             ibmpowernv_occ_add_sdata(sensor, &sdata[index], attr_str, hid,
> +                                      type, sensor_views[i].show_max);
> +             attrs[index] = &sdata[index].attr.attr;
> +             index++;
> +
> +             /* label */
> +             snprintf(sdata[index].label, MAX_HWMON_LABEL_LEN, "%s%s",
> +                      sensor.name, sensor_views[i].name);
> +             ibmpowernv_occ_add_sdata(sensor, &sdata[index], "label", hid,
> +                                      type, ibmpowernv_occ_show_label);
> +             attrs[index] = &sdata[index].attr.attr;
> +             index++;
> +     }
> +}
> +
> +static int ibmpowernv_occ_add_device_attrs(struct platform_device *pdev)
> +{
> +     struct attribute **attrs;
> +     struct occ_hwmon_sensor *slist = NULL;
> +     int nr_sensors = 0, i;
> +     int ret = -ENOMEM;
> +
> +     slist = opal_occ_sensor_get_hwmon_list(&nr_sensors);
> +     if (!nr_sensors)
> +             return -ENODEV;
> +
> +     if (!slist)
> +             return ret;
> +
> +     sdata = devm_kzalloc(&pdev->dev, nr_sensors * sizeof(*sdata) *
> +                          HWMON_ATTRS_PER_SENSOR, GFP_KERNEL);
> +     if (!sdata)
> +             goto out;
> +
> +     attrs = devm_kzalloc(&pdev->dev, nr_sensors * sizeof(*attrs) *
> +                          HWMON_ATTRS_PER_SENSOR, GFP_KERNEL);
> +     if (!attrs)
> +             goto out;
> +
> +     sensor_attrs_group.attrs = attrs;
> +     for (i = 0; i < nr_sensors; i++)
> +             ibmpowernv_occ_add_sensor_attrs(slist[i], i);
> +
> +     ret = 0;
> +out:
> +     kfree(slist);
> +     return ret;
> +}
> +
> +static int ibmpowernv_occ_probe(struct platform_device *pdev)
> +{
> +     struct device *hwmon_dev;
> +     int err;
> +
> +     err = ibmpowernv_occ_add_device_attrs(pdev);
> +     if (err)
> +             goto out;
> +
> +     hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev, DRVNAME,
> +                                                        NULL,
> +                                                        sensor_attrs_groups);
> +
> +     err = PTR_ERR_OR_ZERO(hwmon_dev);
> +out:
> +     if (err)
> +             pr_warn("Failed to initialize Hwmon OCC inband sensors\n");
> +
> +     return err;
> +}
> +
> +static const struct platform_device_id occ_sensor_ids[] = {
> +     { .name = "occ-inband-sensor" },
> +     { }
> +};
> +MODULE_DEVICE_TABLE(platform, occ_sensor_ids);
> +
> +static const struct of_device_id occ_sensor_of_ids[] = {
> +     { .compatible   = "ibm,p9-occ-inband-sensor" },
> +     { }
> +};
> +MODULE_DEVICE_TABLE(of, occ_sensor_of_ids);
> +
> +static struct platform_driver ibmpowernv_occ_driver = {
> +     .probe          = ibmpowernv_occ_probe,
> +     .id_table       = occ_sensor_ids,
> +     .driver         = {
> +             .name   = DRVNAME,
> +             .of_match_table = occ_sensor_of_ids,
> +     },
> +};
> +
> +module_platform_driver(ibmpowernv_occ_driver);
> +
> +MODULE_AUTHOR("Shilpasri G Bhat <shilpa.b...@linux.vnet.ibm.com>");
> +MODULE_DESCRIPTION("IBM POWERNV platform OCC inband sensors");
> +MODULE_LICENSE("GPL");
> -- 
> 1.8.3.1
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to