Received: by 2002:ac0:a581:0:0:0:0:0 with SMTP id m1-v6csp895229imm; Wed, 4 Jul 2018 07:47:42 -0700 (PDT) X-Google-Smtp-Source: AAOMgpeAqA/BZLCdbisWs/2xZaV7g55wVnEcs+2Y/mSbo7qaSW3A5hViyxGiX7LEbDnvuWShfiJk X-Received: by 2002:a62:2ad1:: with SMTP id q200-v6mr2536040pfq.70.1530715662140; Wed, 04 Jul 2018 07:47:42 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1530715662; cv=none; d=google.com; s=arc-20160816; b=eRCKDhmrhOhhRc3YG1u4TB2SsTo+7s3kS/MWeTFmOpnqpYEY70OoqogEemdJYnxmA5 BD6rXfO63nCUoS+l5XEk5lN87p99OQX2lWtpG//KIEVD0L8VLathaaRQc0CIvRvKVrEP hwFIlIB6IH4ag0C2fXRkoC099uI7CIDmSb9CQ8TpChLqVcCbj4q3Mf79tDC/Aq97Kd6K DuEqJd8R/89MjQTyORqd+weBvuJBSHXIoPt6kYoa53ytE10GPbsGTTQcNl2qxMBDzO+E HDuW3ZOPmz8GM4HxepD/PqAZAOH7amsFFzf34qRjf53Xgi40qKE7G5/QiUXlxglXMLnx Ktkg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding :content-language:in-reply-to:mime-version:user-agent:date :message-id:from:references:cc:to:subject:dkim-signature :arc-authentication-results; bh=7ixOLyWCxKpRcbfuX536ApNxYArWf8i6qVKT8olG+e4=; b=YwXvM3KfiL03CH/NZkJsAkkRvHDNi6R/v6j4ZsoMqrmBWcQvC2lwzxVnT8b1Xxy7Bh xm8VpQML9xaSxRap2xD1fMS8AhKJRn6IXd0yNROYKJoap0bWFY8zYg2ACIWyC/SE5MSg JVk2VvGmpw7QdaGfNZsXnOCbIzRs9LkHpNYOmW8g0kIdlSBRp2zXEW4+gCwHQBxSg2Pb IIBX02Nmq7WzOAVzB6B3iHECXDHKD87/lLe308Gma7wk2hc4mQJXoTXQDGunqux1vD/J 85CCflqkuMztoBKw+TQfY91QESXCOmMwSj0Z1EIZO8FVCE6A9y47YfuDkUj1/nbBxIpG 105g== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@gmail.com header.s=20161025 header.b=ks6oMSlG; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 184-v6si3481557pgj.421.2018.07.04.07.47.27; Wed, 04 Jul 2018 07:47:42 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=fail header.i=@gmail.com header.s=20161025 header.b=ks6oMSlG; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753143AbeGDOqj (ORCPT + 99 others); Wed, 4 Jul 2018 10:46:39 -0400 Received: from mail-pl0-f65.google.com ([209.85.160.65]:44646 "EHLO mail-pl0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753061AbeGDOqg (ORCPT ); Wed, 4 Jul 2018 10:46:36 -0400 Received: by mail-pl0-f65.google.com with SMTP id m16-v6so2738886pls.11; Wed, 04 Jul 2018 07:46:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:subject:to:cc:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-language:content-transfer-encoding; bh=7ixOLyWCxKpRcbfuX536ApNxYArWf8i6qVKT8olG+e4=; b=ks6oMSlG/4eYgobX9F5G6XbwR2THc++pou4XZJLk/FaOettCsmW23aqv6dRalNAab3 GI0QSFlYzAoI3ixHphz+hRcfS92zaD7kG39xeF4R5yxODvRZODfgkHWVquTQtbukyf2+ FmAYuPeMof0yVgjGLHcP2VZZMOpUCv2CaYLumxX//R8ZPTTwKg9bsV4npzZRwKrwZ1Yo OdHcS7fojsMpT6dRboP6mn0bjlCFitVW2Hz1nvjouHmczcNw4abkl5IEGZaC7S+kPVBM CanM37G6y682w5KU4yDV54hAeEt9rrFxMPeo2GEuw0AZnjApZBibPOIECmQbQAya/8BU rLmQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:subject:to:cc:references:from:message-id :date:user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=7ixOLyWCxKpRcbfuX536ApNxYArWf8i6qVKT8olG+e4=; b=h4zS7mtLYeBUHu7nob5iQBIwlsb42dpGL1AF0ZMLDhbK1WIvr2UXBQG+shexJBYiV5 4cEZHzMywXBynmfEYHpeiVGRX49F7c4nLpEVKSfOXQvPfsEwl+j2z5vIdUFjqsDiimnH ysm/E0gqX3K+woDj4j6jFlfqyrWvu39JpRI+6xTSrRs8aDXfRDBAJZOiqWtZekrU0hgF CuYOVDivtai3SPh2N7YoQ/8uM5tVP2ZFN2EsxTuuVMryM0ZJ1VgfwzymrGlCcxj6ATbP qFuHucq1xMNC8C3i9bWoGpKMel7/+qyEM0ah/OUpbwkUl7aYwdBo9P1sDDPr11R+J70k SYUg== X-Gm-Message-State: APt69E2D8GgVf2ysOr6sbyHIVMkSWN4f3wt00cLInJB2wAFwa3lztjz3 OdAGVhQeJ+bRXZXRAkvmvpojAw== X-Received: by 2002:a17:902:1007:: with SMTP id b7-v6mr2380167pla.277.1530715595609; Wed, 04 Jul 2018 07:46:35 -0700 (PDT) Received: from server.roeck-us.net (108-223-40-66.lightspeed.sntcca.sbcglobal.net. [108.223.40.66]) by smtp.gmail.com with ESMTPSA id r16-v6sm1029370pfe.173.2018.07.04.07.46.33 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 04 Jul 2018 07:46:34 -0700 (PDT) Subject: Re: [PATCH v2 2/2] hwmon: ibmpowernv: Add attributes to enable/disable sensor groups To: Shilpasri G Bhat , mpe@ellerman.id.au Cc: linuxppc-dev@lists.ozlabs.org, linux-hwmon@vger.kernel.org, linux-kernel@vger.kernel.org, ego@linux.vnet.ibm.com References: <1530695793-4584-1-git-send-email-shilpa.bhat@linux.vnet.ibm.com> <1530695793-4584-3-git-send-email-shilpa.bhat@linux.vnet.ibm.com> From: Guenter Roeck Message-ID: Date: Wed, 4 Jul 2018 07:46:32 -0700 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.8.0 MIME-Version: 1.0 In-Reply-To: <1530695793-4584-3-git-send-email-shilpa.bhat@linux.vnet.ibm.com> Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 07/04/2018 02:16 AM, Shilpasri G Bhat wrote: > On-Chip-Controller(OCC) is an embedded micro-processor in POWER9 chip > which measures various system and chip level sensors. These sensors > comprises of environmental sensors (like power, temperature, current > and voltage) and performance sensors (like utilization, frequency). > All these sensors are copied to main memory at a regular interval of > 100ms. OCC provides a way to select a group of sensors that is copied > to the main memory to increase the update frequency of selected sensor > groups. When a sensor-group is disabled, OCC will not copy it to main > memory and those sensors read 0 values. > > This patch provides support for enabling/disabling the sensor groups > like power, temperature, current and voltage. This patch adds new > per-senor sysfs attribute to disable and enable them. > > Signed-off-by: Shilpasri G Bhat > --- > Changes from v1: > - Add per-sensor 'enable' attribute > - Return -ENODATA when sensor is disabled > > Documentation/hwmon/sysfs-interface | 22 +++ > drivers/hwmon/ibmpowernv.c | 281 +++++++++++++++++++++++++++++++----- > 2 files changed, 264 insertions(+), 39 deletions(-) > > diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface > index fc337c3..38ab05c 100644 > --- a/Documentation/hwmon/sysfs-interface > +++ b/Documentation/hwmon/sysfs-interface Separate patch please. > @@ -184,6 +184,11 @@ vrm Voltage Regulator Module version number. > Affects the way the driver calculates the CPU core reference > voltage from the vid pins. > > +in[0-*]_enable Enable or disable the sensor > + 1 : Enable > + 0 : Disable > + RW > + > Also see the Alarms section for status flags associated with voltages. > > > @@ -409,6 +414,12 @@ temp_reset_history > Reset temp_lowest and temp_highest for all sensors > WO > > +temp[1-*]_enable > + Enable or disable the sensor > + 1 : Enable > + 0 : Disable > + RW > + > Some chips measure temperature using external thermistors and an ADC, and > report the temperature measurement as a voltage. Converting this voltage > back to a temperature (or the other way around for limits) requires > @@ -468,6 +479,12 @@ curr_reset_history > Reset currX_lowest and currX_highest for all sensors > WO > > +curr[1-*]_enable > + Enable or disable the sensor > + 1 : Enable > + 0 : Disable > + RW > + > Also see the Alarms section for status flags associated with currents. > > ********* > @@ -566,6 +583,11 @@ power[1-*]_crit Critical maximum power. > Unit: microWatt > RW > > +power[1-*]_enable Enable or disable the sensor > + 1 : Enable > + 0 : Disable > + RW > + > Also see the Alarms section for status flags associated with power readings. > Any reason for excluding fan, energy, humidity ? > ********** > diff --git a/drivers/hwmon/ibmpowernv.c b/drivers/hwmon/ibmpowernv.c > index f829dad..61e04cf 100644 > --- a/drivers/hwmon/ibmpowernv.c > +++ b/drivers/hwmon/ibmpowernv.c > @@ -90,8 +90,28 @@ struct sensor_data { > char label[MAX_LABEL_LEN]; > char name[MAX_ATTR_LEN]; > struct device_attribute dev_attr; > + struct sensor_group_data *sgdata; > + struct sensor_data *sdata[3]; > + bool enable; > }; > > +static struct sensor_group_data { > + u32 gid; > + u32 nr_phandle; > + u32 nr_sensor; > + enum sensors type; > + const __be32 *phandles; > + struct sensor_data **sensors; > + bool enable; > +} *sg_data; > + > +/* > + * To synchronise writes to struct sensor_data.enable and > + * struct sensor_group_data.enable > + */ > +DEFINE_MUTEX(sensor_groups_mutex); Not as global variable, please. > +static int nr_sensor_groups; > + Do those have to be static variables ? Why not in struct platform_data ? > struct platform_data { > const struct attribute_group *attr_groups[MAX_SENSOR_TYPE + 1]; > u32 sensors_count; /* Total count of sensors from each group */ > @@ -105,6 +125,9 @@ static ssize_t show_sensor(struct device *dev, struct device_attribute *devattr, > ssize_t ret; > u64 x; > > + if (sdata->sgdata && !sdata->enable) > + return -ENODATA; > + This return code should be documented in the ABI. > ret = opal_get_sensor_data_u64(sdata->id, &x); > > if (ret) > @@ -120,6 +143,74 @@ static ssize_t show_sensor(struct device *dev, struct device_attribute *devattr, > return sprintf(buf, "%llu\n", x); > } > > +static ssize_t show_enable(struct device *dev, > + struct device_attribute *devattr, char *buf) > +{ > + struct sensor_data *sdata = container_of(devattr, struct sensor_data, > + dev_attr); > + > + return sprintf(buf, "%u\n", sdata->enable); > +} > + > +static ssize_t store_enable(struct device *dev, > + struct device_attribute *devattr, > + const char *buf, size_t count) > +{ > + struct sensor_data *sdata = container_of(devattr, struct sensor_data, > + dev_attr); > + struct sensor_group_data *sg = sdata->sgdata; > + u32 data; > + int ret, i; > + bool send_command; > + > + ret = kstrtoint(buf, 0, &data); Use kstrtobool(), please. Then you won't need the additional range check below. > + if (ret) > + return ret; > + > + if (data != 0 && data != 1) > + return -EIO; This is not an IO error. > + > + ret = mutex_lock_interruptible(&sensor_groups_mutex); > + if (ret) > + return ret; > + > + sdata->enable = data; > + if ((data && sg->enable) || (!data && !sg->enable)) { > + send_command = false; If data is bool you can use a simple comparison. > + } else if (data && !sg->enable) { !sg->enable is unnecessary. > + /* Enable if first sensor in the group */ > + send_command = true; > + } else if (!data && sg->enable) { This if statement is always true and thus unnecessary. Overall, you could use send_command = data != sg->enable; if (send_command && !data) { for (...) { > + /* Disable if last sensor in the group */ > + send_command = true; > + for (i = 0; i < sg->nr_sensor; i++) { > + struct sensor_data *sd = sg->sensors[i]; > + > + if (sd->enable) { > + send_command = false; > + break; > + } This is weird. So there are situations where a request to disable a sensor is accepted, but effectively ignored ? Shouldn't that return, say, -EBUSY ? > + } > + } > + > + if (send_command) { > + ret = sensor_group_enable(sg->gid, data); > + if (!ret) > + sg->enable = data; > + } > + > + if (!ret) { > + for (i = 0; i < ARRAY_SIZE(sdata->sdata); i++) > + sdata->sdata[i]->enable = data; > + ret = count; > + } else { > + ret = -EIO; No overriding error codes, please. > + } > + > + mutex_unlock(&sensor_groups_mutex); > + return ret; > +} > + > static ssize_t show_label(struct device *dev, struct device_attribute *devattr, > char *buf) > { > @@ -292,6 +383,90 @@ static u32 get_sensor_hwmon_index(struct sensor_data *sdata, > return ++sensor_groups[sdata->type].hwmon_index; > } > > +static int init_sensor_group_data(struct platform_device *pdev) > +{ > + struct device_node *sensor_groups, *sg; > + enum sensors type; > + int count = 0, ret = 0; > + > + sensor_groups = of_find_node_by_path("/ibm,opal/sensor-groups"); > + if (!sensor_groups) > + return ret; > + > + for_each_child_of_node(sensor_groups, sg) { > + type = get_sensor_type(sg); > + if (type != MAX_SENSOR_TYPE) > + nr_sensor_groups++; > + } > + > + if (!nr_sensor_groups) > + goto out; > + > + sg_data = devm_kzalloc(&pdev->dev, nr_sensor_groups * sizeof(*sg_data), > + GFP_KERNEL); > + if (!sg_data) { > + ret = -ENOMEM; > + goto out; > + } > + > + for_each_child_of_node(sensor_groups, sg) { > + const __be32 *phandles; > + int len, gid; > + > + type = get_sensor_type(sg); > + if (type == MAX_SENSOR_TYPE) > + continue; > + > + if (of_property_read_u32(sg, "sensor-group-id", &gid)) > + continue; > + > + phandles = of_get_property(sg, "sensors", &len); > + if (!phandles) > + continue; > + > + len /= sizeof(u32); > + if (!len) > + continue; > + > + sg_data[count].sensors = devm_kzalloc(&pdev->dev, > + len * sizeof(struct sensor_data *), > + GFP_KERNEL); > + if (!sg_data[count].sensors) { > + ret = -ENOMEM; > + break; Doesn't this result in a missing of_node_put() on sg ? > + } > + > + sg_data[count].nr_sensor = 0; > + sg_data[count].gid = gid; > + sg_data[count].type = type; > + sg_data[count].nr_phandle = len; > + sg_data[count].phandles = phandles; > + sg_data[count++].enable = true; > + } > +out: > + of_node_put(sensor_groups); > + return ret; > +} > + > +static struct sensor_group_data *get_sensor_group(struct device_node *np, > + enum sensors type) > +{ > + int i, j; > + > + for (i = 0; i < nr_sensor_groups; i++) { > + const __be32 *phandles = sg_data[i].phandles; > + > + if (type != sg_data[i].type) > + continue; > + > + for (j = 0; j < sg_data[i].nr_phandle; j++) > + if (be32_to_cpu(phandles[j]) == np->phandle) > + return &sg_data[i]; > + } > + > + return NULL; > +} > + > static int populate_attr_groups(struct platform_device *pdev) > { > struct platform_data *pdata = platform_get_drvdata(pdev); > @@ -299,6 +474,9 @@ static int populate_attr_groups(struct platform_device *pdev) > struct device_node *opal, *np; > enum sensors type; > > + if (init_sensor_group_data(pdev)) > + return -ENOMEM; > + init_sensor_group_data() returns an error code which you should pass on. > opal = of_find_node_by_path("/ibm,opal/sensors"); > for_each_child_of_node(opal, np) { > const char *label; > @@ -313,7 +491,7 @@ static int populate_attr_groups(struct platform_device *pdev) > sensor_groups[type].attr_count++; > > /* > - * add attributes for labels, min and max > + * add attributes for labels, min, max and enable > */ > if (!of_property_read_string(np, "label", &label)) > sensor_groups[type].attr_count++; > @@ -321,6 +499,8 @@ static int populate_attr_groups(struct platform_device *pdev) > sensor_groups[type].attr_count++; > if (of_find_property(np, "sensor-data-max", NULL)) > sensor_groups[type].attr_count++; > + if (get_sensor_group(np, type)) > + sensor_groups[type].attr_count++; > } > > of_node_put(opal); > @@ -344,7 +524,10 @@ static int populate_attr_groups(struct platform_device *pdev) > static void create_hwmon_attr(struct sensor_data *sdata, const char *attr_name, > ssize_t (*show)(struct device *dev, > struct device_attribute *attr, > - char *buf)) > + char *buf), > + ssize_t (*store)(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t count)) > { > snprintf(sdata->name, MAX_ATTR_LEN, "%s%d_%s", > sensor_groups[sdata->type].name, sdata->hwmon_index, > @@ -352,23 +535,34 @@ static void create_hwmon_attr(struct sensor_data *sdata, const char *attr_name, > > 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; > + if (store) { > + sdata->dev_attr.store = store; > + sdata->dev_attr.attr.mode = 0664; > + } else { > + sdata->dev_attr.attr.mode = 0444; > + } > } > > static void populate_sensor(struct sensor_data *sdata, int od, int hd, int sid, > const char *attr_name, enum sensors type, > const struct attribute_group *pgroup, > + struct sensor_group_data *sgdata, > ssize_t (*show)(struct device *dev, > struct device_attribute *attr, > - char *buf)) > + char *buf), > + ssize_t (*store)(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t count)) > { > sdata->id = sid; > sdata->type = type; > sdata->opal_index = od; > sdata->hwmon_index = hd; > - create_hwmon_attr(sdata, attr_name, show); > + create_hwmon_attr(sdata, attr_name, show, store); > pgroup->attrs[sensor_groups[type].attr_count++] = &sdata->dev_attr.attr; > + sdata->enable = true; > + sdata->sgdata = sgdata; > } > > static char *get_max_attr(enum sensors type) > @@ -408,18 +602,17 @@ static int create_device_attrs(struct platform_device *pdev) > u32 count = 0; > int err = 0; > > - opal = of_find_node_by_path("/ibm,opal/sensors"); > sdata = devm_kcalloc(&pdev->dev, > pdata->sensors_count, sizeof(*sdata), > GFP_KERNEL); > - if (!sdata) { > - err = -ENOMEM; > - goto exit_put_node; > - } > + if (!sdata) > + return -ENOMEM; > > + opal = of_find_node_by_path("/ibm,opal/sensors"); > for_each_child_of_node(opal, np) { > + struct sensor_group_data *sgdata; > const char *attr_name; > - u32 opal_index; > + u32 opal_index, hw_id; > const char *label; > > if (np->name == NULL) > @@ -456,14 +649,43 @@ static int create_device_attrs(struct platform_device *pdev) > opal_index = INVALID_INDEX; > } > > - sdata[count].opal_index = opal_index; > - sdata[count].hwmon_index = > - get_sensor_hwmon_index(&sdata[count], sdata, count); > + hw_id = get_sensor_hwmon_index(&sdata[count], sdata, count); > + sgdata = get_sensor_group(np, type); > + populate_sensor(&sdata[count], opal_index, hw_id, sensor_id, > + attr_name, type, pgroups[type], sgdata, > + show_sensor, NULL); > + count++; > + > + if (!of_property_read_u32(np, "sensor-data-max", &sensor_id)) { > + attr_name = get_max_attr(type); > + populate_sensor(&sdata[count], opal_index, hw_id, > + sensor_id, attr_name, type, > + pgroups[type], sgdata, show_sensor, > + NULL); > + count++; > + } > + > + if (!of_property_read_u32(np, "sensor-data-min", &sensor_id)) { > + attr_name = get_min_attr(type); > + populate_sensor(&sdata[count], opal_index, hw_id, > + sensor_id, attr_name, type, > + pgroups[type], sgdata, show_sensor, > + NULL); > + count++; > + } > > - create_hwmon_attr(&sdata[count], attr_name, show_sensor); > + if (sgdata) { > + int i; > > - pgroups[type]->attrs[sensor_groups[type].attr_count++] = > - &sdata[count++].dev_attr.attr; > + sgdata->sensors[sgdata->nr_sensor++] = &sdata[count]; > + populate_sensor(&sdata[count], opal_index, hw_id, > + sgdata->gid, "enable", type, > + pgroups[type], sgdata, show_enable, > + store_enable); > + for (i = 0; i < ARRAY_SIZE(sdata[count].sdata); i++) > + sdata[count].sdata[i] = &sdata[count - i - 1]; > + count++; > + } > > if (!of_property_read_string(np, "label", &label)) { > /* > @@ -474,34 +696,15 @@ static int create_device_attrs(struct platform_device *pdev) > */ > > make_sensor_label(np, &sdata[count], label); > - populate_sensor(&sdata[count], opal_index, > - sdata[count - 1].hwmon_index, > + populate_sensor(&sdata[count], opal_index, hw_id, > sensor_id, "label", type, pgroups[type], > - show_label); > - count++; > - } > - > - if (!of_property_read_u32(np, "sensor-data-max", &sensor_id)) { > - attr_name = get_max_attr(type); > - populate_sensor(&sdata[count], opal_index, > - sdata[count - 1].hwmon_index, > - sensor_id, attr_name, type, > - pgroups[type], show_sensor); > - count++; > - } > - > - if (!of_property_read_u32(np, "sensor-data-min", &sensor_id)) { > - attr_name = get_min_attr(type); > - populate_sensor(&sdata[count], opal_index, > - sdata[count - 1].hwmon_index, > - sensor_id, attr_name, type, > - pgroups[type], show_sensor); > + NULL, show_label, NULL); > count++; > } > } > > -exit_put_node: > of_node_put(opal); > + > return err; > } > >