[PATCH linux dev-4.10 v3] drivers/hwmon/occ: Add sysfs_notify on error
Eddie James
eajames at linux.vnet.ibm.com
Fri Jul 7 01:28:21 AEST 2017
From: "Edward A. James" <eajames at us.ibm.com>
For userspace polling, we need to notify sysfs that the state of our
error entry has changed.
Changes since v2:
* don't return empty sysfs file
Signed-off-by: Edward A. James <eajames at us.ibm.com>
---
drivers/hwmon/occ/common.c | 43 +++++++++++++++++++++++++++++--------------
drivers/hwmon/occ/common.h | 4 +++-
drivers/hwmon/occ/p8_i2c.c | 28 ++++++++++++++--------------
drivers/hwmon/occ/p9_sbe.c | 34 ++++++++++++++++------------------
4 files changed, 62 insertions(+), 47 deletions(-)
diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c
index 4e3e411..6663bf3 100644
--- a/drivers/hwmon/occ/common.c
+++ b/drivers/hwmon/occ/common.c
@@ -163,9 +163,22 @@ void occ_parse_poll_response(struct occ *occ)
}
}
+void occ_set_error(struct occ *occ, int error)
+{
+ occ->error_count++;
+ if (occ->error_count > OCC_ERROR_COUNT_THRESHOLD)
+ occ->error = error;
+}
+
+void occ_reset_error(struct occ *occ)
+{
+ occ->error_count = 0;
+ occ->error = 0;
+}
+
int occ_poll(struct occ *occ)
{
- int rc;
+ int rc, error = occ->error;
struct occ_poll_response_header *header;
u16 checksum = occ->poll_cmd_data + 1;
u8 cmd[8];
@@ -181,7 +194,7 @@ int occ_poll(struct occ *occ)
rc = occ->send_cmd(occ, cmd);
if (rc)
- return rc;
+ goto done;
header = (struct occ_poll_response_header *)occ->resp.data;
@@ -197,19 +210,21 @@ int occ_poll(struct occ *occ)
if (header->status & OCC_STAT_MASTER) {
if (hweight8(header->occs_present) !=
- atomic_read(&occ_num_occs)) {
- occ->error = -EXDEV;
- occ->bad_present_count++;
- } else
- occ->bad_present_count = 0;
+ atomic_read(&occ_num_occs))
+ occ->error = -ENXIO;
}
+done:
+ /* notify userspace if we change error state and have an error */
+ if (occ->error != error && occ->error && occ->error_attr_name)
+ sysfs_notify(&occ->bus_dev->kobj, NULL, occ->error_attr_name);
+
return rc;
}
int occ_set_user_power_cap(struct occ *occ, u16 user_power_cap)
{
- int rc;
+ int rc, error = occ->error;
u8 cmd[8];
u16 checksum = 0x24;
__be16 user_power_cap_be;
@@ -239,6 +254,10 @@ int occ_set_user_power_cap(struct occ *occ, u16 user_power_cap)
rc = occ->send_cmd(occ, cmd);
mutex_unlock(&occ->lock);
+ /* notify userspace if we change error state and have an error*/
+ if (occ->error != error && occ->error && occ->error_attr_name)
+ sysfs_notify(&occ->bus_dev->kobj, NULL, occ->error_attr_name);
+
return rc;
}
@@ -260,14 +279,9 @@ int occ_update_response(struct occ *occ)
static ssize_t occ_show_error(struct device *dev,
struct device_attribute *attr, char *buf)
{
- int error = 0;
struct occ *occ = dev_get_drvdata(dev);
- if (occ->error_count > OCC_ERROR_COUNT_THRESHOLD || occ->last_safe ||
- occ->bad_present_count > OCC_ERROR_COUNT_THRESHOLD)
- error = occ->error;
-
- return snprintf(buf, PAGE_SIZE - 1, "%d\n", error);
+ return snprintf(buf, PAGE_SIZE - 1, "%d\n", occ->error);
}
static ssize_t occ_show_status(struct device *dev,
@@ -1152,6 +1166,7 @@ int occ_create_status_attrs(struct occ *occ)
(struct sensor_device_attribute)SENSOR_ATTR(occ_error, 0444,
occ_show_error,
NULL, 0);
+ occ->error_attr_name = occ->status_attrs[7].dev_attr.attr.name;
for (i = 0; i < OCC_NUM_STATUS_ATTRS; ++i) {
rc = device_create_file(dev, &occ->status_attrs[i].dev_attr);
diff --git a/drivers/hwmon/occ/common.h b/drivers/hwmon/occ/common.h
index a5f86c3..acb50bc 100644
--- a/drivers/hwmon/occ/common.h
+++ b/drivers/hwmon/occ/common.h
@@ -103,7 +103,6 @@ struct occ {
int error;
unsigned int error_count;
- unsigned int bad_present_count;
unsigned long last_safe;
unsigned long last_update;
struct mutex lock;
@@ -116,6 +115,7 @@ struct occ {
struct attribute_group group;
const struct attribute_group *groups[2];
struct sensor_device_attribute *status_attrs;
+ const char *error_attr_name;
u8 poll_cmd_data;
int (*send_cmd)(struct occ *occ, u8 *cmd);
@@ -143,6 +143,8 @@ struct occ {
extern atomic_t occ_num_occs;
void occ_parse_poll_response(struct occ *occ);
+void occ_reset_error(struct occ *occ);
+void occ_set_error(struct occ *occ, int error);
int occ_poll(struct occ *occ);
int occ_set_user_power_cap(struct occ *occ, u16 user_power_cap);
int occ_update_response(struct occ *occ);
diff --git a/drivers/hwmon/occ/p8_i2c.c b/drivers/hwmon/occ/p8_i2c.c
index 29233b4..a7b1d4c 100644
--- a/drivers/hwmon/occ/p8_i2c.c
+++ b/drivers/hwmon/occ/p8_i2c.c
@@ -98,7 +98,7 @@ static int p8_i2c_occ_putscom_be(struct i2c_client *client, u32 address,
static int p8_i2c_occ_send_cmd(struct occ *occ, u8 *cmd)
{
- int i, rc;
+ int i, rc, error;
unsigned long start;
u16 data_length;
struct p8_i2c_occ *p8_i2c_occ = to_p8_i2c_occ(occ);
@@ -161,22 +161,18 @@ static int p8_i2c_occ_send_cmd(struct occ *occ, u8 *cmd)
rc = -EFAULT;
}
- occ->error = resp->return_status;
-
if (rc < 0) {
- occ->error_count++;
- dev_warn(&client->dev, "occ bad response:%d\n",
- resp->return_status);
- return rc;
+ error = resp->return_status;
+ dev_warn(&client->dev, "occ bad response:%d\n", error);
+ goto done;
}
data_length = get_unaligned_be16(&resp->data_length_be);
if (data_length > OCC_RESP_DATA_BYTES) {
- occ->error_count++;
- occ->error = -EDOM;
+ rc = -EDOM;
dev_warn(&client->dev, "occ bad data length:%d\n",
data_length);
- return occ->error;
+ goto assign;
}
for (i = 8; i < data_length + 7; i += 8) {
@@ -185,13 +181,17 @@ static int p8_i2c_occ_send_cmd(struct occ *occ, u8 *cmd)
goto err;
}
- occ->error_count = 0;
- return data_length + 7;
+ occ_reset_error(occ);
+ return 0;
err:
- occ->error_count++;
- occ->error = rc;
dev_err(&client->dev, "i2c scom op failed rc:%d\n", rc);
+
+assign:
+ error = rc;
+
+done:
+ occ_set_error(occ, error);
return rc;
}
diff --git a/drivers/hwmon/occ/p9_sbe.c b/drivers/hwmon/occ/p9_sbe.c
index c85f133..db30a2d 100644
--- a/drivers/hwmon/occ/p9_sbe.c
+++ b/drivers/hwmon/occ/p9_sbe.c
@@ -25,7 +25,7 @@ struct p9_sbe_occ {
static int p9_sbe_occ_send_cmd(struct occ *occ, u8 *cmd)
{
- int rc;
+ int rc, error;
unsigned long start;
struct occ_client *client;
struct occ_response *resp = &occ->resp;
@@ -35,9 +35,10 @@ static int p9_sbe_occ_send_cmd(struct occ *occ, u8 *cmd)
retry:
client = occ_drv_open(p9_sbe_occ->sbe, 0);
- if (!client)
- /* don't increment occ error counter */
- return -ENODEV;
+ if (!client) {
+ rc = -ENODEV;
+ goto assign;
+ }
rc = occ_drv_write(client, (const char *)&cmd[1], 7);
if (rc < 0)
@@ -62,7 +63,8 @@ static int p9_sbe_occ_send_cmd(struct occ *occ, u8 *cmd)
}
break;
case RESP_RETURN_SUCCESS:
- rc = 0;
+ occ_reset_error(occ);
+ return 0;
break;
case RESP_RETURN_CMD_INVAL:
case RESP_RETURN_CMD_LEN:
@@ -77,23 +79,19 @@ static int p9_sbe_occ_send_cmd(struct occ *occ, u8 *cmd)
rc = -EFAULT;
}
- occ->error = resp->return_status;
-
- if (rc < 0) {
- occ->error_count++;
- dev_warn(occ->bus_dev, "occ bad response:%d\n",
- resp->return_status);
- return rc;
- }
-
- occ->error_count = 0;
- return 0;
+ error = resp->return_status;
+ dev_warn(occ->bus_dev, "occ bad response:%d\n", error);
+ goto done;
err:
- occ->error_count++;
- occ->error = rc;
occ_drv_release(client);
dev_err(occ->bus_dev, "occ bus op failed rc:%d\n", rc);
+
+assign:
+ error = rc;
+
+done:
+ occ_set_error(occ, error);
return rc;
}
--
1.8.3.1
More information about the openbmc
mailing list