From: "Edward A. James" <eajames@xxxxxxxxxx> Create device attributes for additional OCC properties that do not belong as hwmon sensors. These provide additional information as to the state of the processor and system. Signed-off-by: Edward A. James <eajames@xxxxxxxxxx> --- Documentation/ABI/testing/sysfs-driver-occ-hwmon | 65 +++++++++++++ drivers/hwmon/occ/common.c | 114 +++++++++++++++++++++++ drivers/hwmon/occ/common.h | 14 +++ drivers/hwmon/occ/p8_i2c.c | 8 ++ drivers/hwmon/occ/p9_sbe.c | 8 ++ 5 files changed, 209 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-driver-occ-hwmon diff --git a/Documentation/ABI/testing/sysfs-driver-occ-hwmon b/Documentation/ABI/testing/sysfs-driver-occ-hwmon new file mode 100644 index 0000000..ddf6cd7 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-occ-hwmon @@ -0,0 +1,65 @@ +What: /sys/bus/platform/drivers/occ-hwmon/<dev>/occ_active +Date: June 2017 +KernelVersion: 4.14 +Contact: eajames@xxxxxxxxxx +Description: + A read-only attribute that indicates (with a "1" or a "0", + respectively) whether or not this OCC is in the "active" state. + +What: /sys/bus/platform/drivers/occ-hwmon/<dev>/occ_dvfs_ot +Date: June 2017 +KernelVersion: 4.14 +Contact: eajames@xxxxxxxxxx +Description: + A read-only attribute that indicates (with a "1" or a "0", + respectively) whether or not this OCC has limited the processor + frequency due to over-temperature. + +What: /sys/bus/platform/drivers/occ-hwmon/<dev>/occ_dvfs_power +Date: June 2017 +KernelVersion: 4.14 +Contact: eajames@xxxxxxxxxx +Description: + A read-only attribute that indicates (with a "1" or a "0", + respectively) whether or not this OCC has limited the processor + frequency due to power usage. + +What: /sys/bus/platform/drivers/occ-hwmon/<dev>/occ_master +Date: June 2017 +KernelVersion: 4.14 +Contact: eajames@xxxxxxxxxx +Description: + A read-only attribute that indicates (with a "1" or a "0", + respectively) whether or not this OCC is the "master" OCC. + +What: /sys/bus/platform/drivers/occ-hwmon/<dev>/occ_mem_throttle +Date: June 2017 +KernelVersion: 4.14 +Contact: eajames@xxxxxxxxxx +Description: + A read-only attribute that indicates (with a "1" or a "0", + respectively) whether or not the OCC has throttled memory due + to over-temperature. + +What: /sys/bus/platform/drivers/occ-hwmon/<dev>/occ_quick_drop +Date: June 2017 +KernelVersion: 4.14 +Contact: eajames@xxxxxxxxxx +Description: + A read-only attribute that indicates (with a "1" or a "0", + respectively) whether or not this OCC has asserted the "quick + power drop" signal. + +What: /sys/bus/platform/drivers/occ-hwmon/<dev>/occ_status +Date: June 2017 +KernelVersion: 4.14 +Contact: eajames@xxxxxxxxxx +Description: + A read-only attribute that indicates the current OCC state. The + value of the attribute will be one of the following states: + 0: Reserved + 1: Standby + 2: Observation + 3: Active + 4: Safe + 5: Characterization diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c index eb1f1a1..1645776 100644 --- a/drivers/hwmon/occ/common.c +++ b/drivers/hwmon/occ/common.c @@ -993,6 +993,102 @@ static int occ_setup_sensor_attrs(struct occ *occ) return 0; } +static ssize_t occ_show_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int rc; + int val; + struct occ *occ = dev_get_drvdata(dev); + struct occ_poll_response_header *header; + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + + rc = occ_update_response(occ); + if (rc) + return rc; + + header = (struct occ_poll_response_header *)occ->resp.data; + + switch (sattr->index) { + case 0: + val = (header->status & OCC_STAT_MASTER) ? 1 : 0; + break; + case 1: + val = (header->status & OCC_STAT_ACTIVE) ? 1 : 0; + break; + case 2: + val = (header->ext_status & OCC_EXT_STAT_DVFS_OT) ? 1 : 0; + break; + case 3: + val = (header->ext_status & OCC_EXT_STAT_DVFS_POWER) ? 1 : 0; + break; + case 4: + val = (header->ext_status & OCC_EXT_STAT_MEM_THROTTLE) ? 1 : 0; + break; + case 5: + val = (header->ext_status & OCC_EXT_STAT_QUICK_DROP) ? 1 : 0; + break; + case 6: + val = header->occ_state; + break; + default: + return -EINVAL; + } + + return snprintf(buf, PAGE_SIZE - 1, "%d\n", val); +} + +static int occ_create_status_attrs(struct occ *occ) +{ + int rc, i; + struct device *dev = occ->bus_dev; + + occ->status_attrs = devm_kzalloc(dev, sizeof(*occ->status_attrs) * + OCC_NUM_STATUS_ATTRS, GFP_KERNEL); + if (!occ->status_attrs) + return -ENOMEM; + + occ->status_attrs[0] = + (struct sensor_device_attribute)SENSOR_ATTR(occ_master, 0444, + occ_show_status, + NULL, 0); + occ->status_attrs[1] = + (struct sensor_device_attribute)SENSOR_ATTR(occ_active, 0444, + occ_show_status, + NULL, 1); + occ->status_attrs[2] = + (struct sensor_device_attribute)SENSOR_ATTR(occ_dvfs_ot, 0444, + occ_show_status, + NULL, 2); + occ->status_attrs[3] = + (struct sensor_device_attribute)SENSOR_ATTR(occ_dvfs_power, + 0444, + occ_show_status, + NULL, 3); + occ->status_attrs[4] = + (struct sensor_device_attribute)SENSOR_ATTR(occ_mem_throttle, + 0444, + occ_show_status, + NULL, 4); + occ->status_attrs[5] = + (struct sensor_device_attribute)SENSOR_ATTR(occ_quick_drop, + 0444, + occ_show_status, + NULL, 5); + occ->status_attrs[6] = + (struct sensor_device_attribute)SENSOR_ATTR(occ_status, 0444, + occ_show_status, + NULL, 6); + + for (i = 0; i < OCC_NUM_STATUS_ATTRS; ++i) { + rc = device_create_file(dev, &occ->status_attrs[i].dev_attr); + if (rc) + dev_warn(dev, "error %d creating status attr %d\n", rc, + i); + } + + return 0; +} + /* only need to do this once at startup, as OCC won't change sensors on us */ static void occ_parse_poll_response(struct occ *occ) { @@ -1073,5 +1169,23 @@ int occ_setup(struct occ *occ, const char *name) return rc; } + rc = occ_create_status_attrs(occ); + if (rc) { + dev_err(occ->bus_dev, "failed to setup status attrs: %d\n", + rc); + return rc; + } + + return 0; +} + +int occ_shutdown(struct occ *occ) +{ + int i; + + for (i = 0; i < OCC_NUM_STATUS_ATTRS; ++i) + device_remove_file(occ->bus_dev, + &occ->status_attrs[i].dev_attr); + return 0; } diff --git a/drivers/hwmon/occ/common.h b/drivers/hwmon/occ/common.h index 4bcf3ca..dd23eac 100644 --- a/drivers/hwmon/occ/common.h +++ b/drivers/hwmon/occ/common.h @@ -13,6 +13,8 @@ #include <linux/hwmon-sysfs.h> #include <linux/sysfs.h> +#define OCC_NUM_STATUS_ATTRS 7 + #define OCC_RESP_DATA_BYTES 4089 #define OCC_UPDATE_FREQUENCY msecs_to_jiffies(1000) @@ -29,6 +31,14 @@ #define RESP_RETURN_OCC_ERR 0x15 #define RESP_RETURN_STATE 0x16 +/* OCC status bits */ +#define OCC_STAT_MASTER 0x80 +#define OCC_STAT_ACTIVE 0x01 +#define OCC_EXT_STAT_DVFS_OT 0x80 +#define OCC_EXT_STAT_DVFS_POWER 0x40 +#define OCC_EXT_STAT_MEM_THROTTLE 0x20 +#define OCC_EXT_STAT_QUICK_DROP 0x10 + /* Same response format for all OCC versions. * Allocate the largest possible response. */ @@ -119,8 +129,12 @@ struct occ { struct occ_attribute *attrs; struct attribute_group group; const struct attribute_group *groups[2]; + + /* non-hwmon attributes for more OCC properties */ + struct sensor_device_attribute *status_attrs; }; int occ_setup(struct occ *occ, const char *name); +int occ_shutdown(struct occ *occ); #endif /* OCC_COMMON_H */ diff --git a/drivers/hwmon/occ/p8_i2c.c b/drivers/hwmon/occ/p8_i2c.c index d6d70ce..cab4448 100644 --- a/drivers/hwmon/occ/p8_i2c.c +++ b/drivers/hwmon/occ/p8_i2c.c @@ -209,6 +209,13 @@ static int p8_i2c_occ_probe(struct i2c_client *client, return occ_setup(occ, "p8_occ"); } +static int p8_i2c_occ_remove(struct i2c_client *client) +{ + struct occ *occ = dev_get_drvdata(&client->dev); + + return occ_shutdown(occ); +} + static const struct of_device_id p8_i2c_occ_of_match[] = { { .compatible = "ibm,p8-occ-hwmon" }, {} @@ -224,6 +231,7 @@ static int p8_i2c_occ_probe(struct i2c_client *client, .of_match_table = p8_i2c_occ_of_match, }, .probe = p8_i2c_occ_probe, + .remove = p8_i2c_occ_remove, .address_list = p8_i2c_occ_addr, }; diff --git a/drivers/hwmon/occ/p9_sbe.c b/drivers/hwmon/occ/p9_sbe.c index 981c53f..72ee9b4 100644 --- a/drivers/hwmon/occ/p9_sbe.c +++ b/drivers/hwmon/occ/p9_sbe.c @@ -109,6 +109,13 @@ static int p9_sbe_occ_probe(struct platform_device *pdev) return occ_setup(occ, "p9_occ"); } +static int p9_sbe_occ_remove(struct platform_device *pdev) +{ + struct occ *occ = platform_get_drvdata(pdev); + + return occ_shutdown(occ); +} + static const struct of_device_id p9_sbe_occ_of_match[] = { { .compatible = "ibm,p9-occ-hwmon" }, { }, @@ -120,6 +127,7 @@ static int p9_sbe_occ_probe(struct platform_device *pdev) .of_match_table = p9_sbe_occ_of_match, }, .probe = p9_sbe_occ_probe, + .remove = p9_sbe_occ_remove, }; module_platform_driver(p9_sbe_occ_driver); -- 1.8.3.1 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html