From patchwork Tue Feb 14 20:34:23 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eddie James X-Patchwork-Id: 9572833 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id EF6F860573 for ; Tue, 14 Feb 2017 20:35:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E10D027C2D for ; Tue, 14 Feb 2017 20:35:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D5EA12840E; Tue, 14 Feb 2017 20:35:39 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E880527C2D for ; Tue, 14 Feb 2017 20:35:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755529AbdBNUfi (ORCPT ); Tue, 14 Feb 2017 15:35:38 -0500 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]:38363 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1755442AbdBNUev (ORCPT ); Tue, 14 Feb 2017 15:34:51 -0500 Received: from pps.filterd (m0098414.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.20/8.16.0.20) with SMTP id v1EKXcVa137670 for ; Tue, 14 Feb 2017 15:34:50 -0500 Received: from e32.co.us.ibm.com (e32.co.us.ibm.com [32.97.110.150]) by mx0b-001b2d01.pphosted.com with ESMTP id 28m8a11k10-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Tue, 14 Feb 2017 15:34:50 -0500 Received: from localhost by e32.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 14 Feb 2017 13:34:49 -0700 Received: from d03dlp01.boulder.ibm.com (9.17.202.177) by e32.co.us.ibm.com (192.168.1.132) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Tue, 14 Feb 2017 13:34:44 -0700 Received: from b03cxnp08026.gho.boulder.ibm.com (b03cxnp08026.gho.boulder.ibm.com [9.17.130.18]) by d03dlp01.boulder.ibm.com (Postfix) with ESMTP id DA48D1FF0021; Tue, 14 Feb 2017 13:34:21 -0700 (MST) Received: from b03ledav002.gho.boulder.ibm.com (b03ledav002.gho.boulder.ibm.com [9.17.130.233]) by b03cxnp08026.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id v1EKYikV10158406; Tue, 14 Feb 2017 13:34:44 -0700 Received: from b03ledav002.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 27B4D136046; Tue, 14 Feb 2017 13:34:44 -0700 (MST) Received: from oc3016140333.ibm.com (unknown [9.41.179.225]) by b03ledav002.gho.boulder.ibm.com (Postfix) with ESMTP id 41371136040; Tue, 14 Feb 2017 13:34:43 -0700 (MST) From: Eddie James To: linux@roeck-us.net Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-hwmon@vger.kernel.org, linux-doc@vger.kernel.org, jdelvare@suse.com, corbet@lwn.net, mark.rutland@arm.com, robh+dt@kernel.org, wsa@the-dreams.de, andrew@aj.id.au, benh@kernel.crashing.org, joel@jms.id.au, "Edward A. James" Subject: [PATCH linux v8 6/6] hwmon: occ: Add callbacks for parsing P9 OCC datastructures Date: Tue, 14 Feb 2017 14:34:23 -0600 X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1487104463-4253-1-git-send-email-eajames@linux.vnet.ibm.com> References: <1487104463-4253-1-git-send-email-eajames@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 X-Content-Scanned: Fidelis XPS MAILER x-cbid: 17021420-0004-0000-0000-000011961534 X-IBM-SpamModules-Scores: X-IBM-SpamModules-Versions: BY=3.00006616; HX=3.00000240; KW=3.00000007; PH=3.00000004; SC=3.00000203; SDB=6.00821960; UDB=6.00402063; IPR=6.00599413; BA=6.00005137; NDR=6.00000001; ZLA=6.00000005; ZF=6.00000009; ZB=6.00000000; ZP=6.00000000; ZH=6.00000000; ZU=6.00000002; MB=3.00014282; XFM=3.00000011; UTC=2017-02-14 20:34:48 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 17021420-0005-0000-0000-00007D110289 Message-Id: <1487104463-4253-7-git-send-email-eajames@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2017-02-14_13:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 suspectscore=13 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1612050000 definitions=main-1702140196 Sender: linux-hwmon-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-hwmon@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: "Edward A. James" Add functions to parse the data structures that are specific to the OCC on the POWER9 processor. These are the sensor data structures, including temperature, frequency, power, and "caps." Signed-off-by: Edward A. James Signed-off-by: Andrew Jeffery --- Documentation/hwmon/occ | 3 + drivers/hwmon/occ/Kconfig | 11 ++ drivers/hwmon/occ/Makefile | 2 + drivers/hwmon/occ/occ_p9.c | 320 +++++++++++++++++++++++++++++++++++++++++++++ drivers/hwmon/occ/occ_p9.h | 25 ++++ 5 files changed, 361 insertions(+) create mode 100644 drivers/hwmon/occ/occ_p9.c create mode 100644 drivers/hwmon/occ/occ_p9.h diff --git a/Documentation/hwmon/occ b/Documentation/hwmon/occ index 4ec8842..8fb3f41 100644 --- a/Documentation/hwmon/occ +++ b/Documentation/hwmon/occ @@ -36,6 +36,9 @@ number of data structures, such as command format, response headers, and the like, are also defined in this specification, and are common to both POWER8 and POWER9 OCCs. +There is currently no public P9 OCC specification, and the data structures +defined in the POWER9 OCC driver are subject to change. + sysfs Entries ------------- diff --git a/drivers/hwmon/occ/Kconfig b/drivers/hwmon/occ/Kconfig index d521720..5b8ca27 100644 --- a/drivers/hwmon/occ/Kconfig +++ b/drivers/hwmon/occ/Kconfig @@ -25,4 +25,15 @@ config SENSORS_IBM_OCC_P8_I2C This driver can also be built as a module. If so, the module will be called hwmon_occ_p8. +config SENSORS_IBM_OCC_P9 + tristate "POWER9 OCC hwmon support" + depends on !SENSORS_IBM_OCC_P8_I2C + help + Provide a hwmon sysfs interface for the POWER9 On-Chip Controller, + exposing temperature, frequency, and power measurements. This + interface runs on the service processor, not the POWER CPU. + + This driver can also be built as a module. If so, the module will be + called hwmon_occ_p9. + endif diff --git a/drivers/hwmon/occ/Makefile b/drivers/hwmon/occ/Makefile index 864b044..7b3a612 100644 --- a/drivers/hwmon/occ/Makefile +++ b/drivers/hwmon/occ/Makefile @@ -1,3 +1,5 @@ obj-$(CONFIG_SENSORS_IBM_OCC_P8_I2C) += hwmon_occ_p8.o +obj-$(CONFIG_SENSORS_IBM_OCC_P9) += hwmon_occ_p9.o hwmon_occ_p8-objs := occ.o occ_sysfs.o occ_scom_i2c.o occ_p8.o occ_p8_i2c.o +hwmon_occ_p9-objs := occ.o occ_sysfs.o occ_p9.o diff --git a/drivers/hwmon/occ/occ_p9.c b/drivers/hwmon/occ/occ_p9.c new file mode 100644 index 0000000..646d764 --- /dev/null +++ b/drivers/hwmon/occ/occ_p9.c @@ -0,0 +1,320 @@ +/* + * occ_p9.c - OCC hwmon driver + * + * This file contains the Power9-specific methods and data structures for + * the OCC hwmon driver. + * + * Copyright 2017 IBM Corp. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "occ.h" +#include "occ_p9.h" + +/* P9 OCC sensor data format */ +struct p9_temp_sensor { + u32 sensor_id; + u8 fru_type; + u8 value; +}; + +struct p9_freq_sensor { + u32 sensor_id; + u16 value; +}; + +struct p9_power_sensor { + u32 sensor_id; + u8 function_id; + u8 apss_channel; + u16 reserved; + u32 update_tag; + u64 accumulator; + u16 value; +}; + +struct p9_caps_sensor { + u16 curr_powercap; + u16 curr_powerreading; + u16 norm_powercap; + u16 max_powercap; + u16 min_powercap; + u16 user_powerlimit; + u8 user_powerlimit_source; +}; + +/* value, sensor_id */ +#define FREQ_SENSOR_CONFIG (HWMON_I_INPUT | HWMON_I_LABEL) + +/* value, sensor_id, fru_type */ +#define TEMP_SENSOR_CONFIG (HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_TYPE) + +/* value, sensor_id, accumulator[0], accumulator[1], update_tag, + * (function_id | (appss_channel << 8) + */ +#define POWER_SENSOR_CONFIG \ +( \ + HWMON_P_INPUT | HWMON_P_LABEL | HWMON_P_AVERAGE_MIN | \ + HWMON_P_AVERAGE_MAX | HWMON_P_AVERAGE_INTERVAL | \ + HWMON_P_RESET_HISTORY \ +) + +/* curr_powercap, max_powercap, min_powercap, norm_powercap, user_powerlimit + * user_powerlimit_source + */ +#define CAPS_SENSOR_CONFIG \ +( \ + HWMON_P_CAP | HWMON_P_CAP_MAX | HWMON_P_CAP_MIN | HWMON_P_MAX | \ + HWMON_P_ALARM | HWMON_P_CAP_ALARM \ +) + +static const u32 p9_sensor_hwmon_configs[MAX_OCC_SENSOR_TYPE] = { + FREQ_SENSOR_CONFIG, + TEMP_SENSOR_CONFIG, + POWER_SENSOR_CONFIG, + CAPS_SENSOR_CONFIG, +}; + +void p9_parse_sensor(u8 *data, void *sensor, int sensor_type, int off, + int snum) +{ + switch (sensor_type) { + case FREQ: + { + struct p9_freq_sensor *fs = + &(((struct p9_freq_sensor *)sensor)[snum]); + + fs->sensor_id = be32_to_cpu(get_unaligned((u32 *)&data[off])); + fs->value = be16_to_cpu(get_unaligned((u16 *)&data[off + 4])); + } + break; + case TEMP: + { + struct p9_temp_sensor *ts = + &(((struct p9_temp_sensor *)sensor)[snum]); + + ts->sensor_id = be32_to_cpu(get_unaligned((u32 *)&data[off])); + ts->fru_type = data[off + 4]; + ts->value = data[off + 5]; + } + break; + case POWER: + { + struct p9_power_sensor *ps = + &(((struct p9_power_sensor *)sensor)[snum]); + + ps->sensor_id = be32_to_cpu(get_unaligned((u32 *)&data[off])); + ps->function_id = data[off + 4]; + ps->apss_channel = data[off + 5]; + ps->update_tag = + be32_to_cpu(get_unaligned((u32 *)&data[off + 8])); + ps->accumulator = + be64_to_cpu(get_unaligned((u64 *)&data[off + 12])); + ps->value = be16_to_cpu(get_unaligned((u16 *)&data[off + 20])); + } + break; + case CAPS: + { + struct p9_caps_sensor *cs = + &(((struct p9_caps_sensor *)sensor)[snum]); + + cs->curr_powercap = + be16_to_cpu(get_unaligned((u16 *)&data[off])); + cs->curr_powerreading = + be16_to_cpu(get_unaligned((u16 *)&data[off + 2])); + cs->norm_powercap = + be16_to_cpu(get_unaligned((u16 *)&data[off + 4])); + cs->max_powercap = + be16_to_cpu(get_unaligned((u16 *)&data[off + 6])); + cs->min_powercap = + be16_to_cpu(get_unaligned((u16 *)&data[off + 8])); + cs->user_powerlimit = + be16_to_cpu(get_unaligned((u16 *)&data[off + 10])); + cs->user_powerlimit_source = data[off + 12]; + } + break; + }; +} + +void *p9_alloc_sensor(struct device *dev, int sensor_type, int num_sensors) +{ + switch (sensor_type) { + case FREQ: + return devm_kzalloc(dev, num_sensors * + sizeof(struct p9_freq_sensor), GFP_KERNEL); + case TEMP: + return devm_kzalloc(dev, num_sensors * + sizeof(struct p9_temp_sensor), GFP_KERNEL); + case POWER: + return devm_kzalloc(dev, num_sensors * + sizeof(struct p9_power_sensor), + GFP_KERNEL); + case CAPS: + return devm_kzalloc(dev, num_sensors * + sizeof(struct p9_caps_sensor), GFP_KERNEL); + default: + return NULL; + } +} + +int p9_get_sensor(struct occ *driver, int sensor_type, int sensor_num, + u32 hwmon, long *val) +{ + int rc = 0; + void *sensor; + + if (sensor_type == POWER) { + if (hwmon == hwmon_power_cap || hwmon == hwmon_power_cap_max || + hwmon == hwmon_power_cap_min || hwmon == hwmon_power_max || + hwmon == hwmon_power_alarm || + hwmon == hwmon_power_cap_alarm) + sensor_type = CAPS; + } + + sensor = occ_get_sensor(driver, sensor_type); + if (!sensor) + return -ENODEV; + + switch (sensor_type) { + case FREQ: + { + struct p9_freq_sensor *fs = + &(((struct p9_freq_sensor *)sensor)[sensor_num]); + + switch (hwmon) { + case hwmon_in_input: + *val = fs->value; + break; + case hwmon_in_label: + *val = fs->sensor_id; + break; + default: + rc = -EOPNOTSUPP; + } + } + break; + case TEMP: + { + struct p9_temp_sensor *ts = + &(((struct p9_temp_sensor *)sensor)[sensor_num]); + + switch (hwmon) { + case hwmon_temp_input: + *val = ts->value; + break; + case hwmon_temp_type: + *val = ts->fru_type; + break; + case hwmon_temp_label: + *val = ts->sensor_id; + break; + default: + rc = -EOPNOTSUPP; + } + } + break; + case POWER: + { + struct p9_power_sensor *ps = + &(((struct p9_power_sensor *)sensor)[sensor_num]); + + switch (hwmon) { + case hwmon_power_input: + *val = ps->value; + break; + case hwmon_power_label: + *val = ps->sensor_id; + break; + case hwmon_power_average_min: + *val = ((u32 *)(&ps->accumulator))[0]; + break; + case hwmon_power_average_max: + *val = ((u32 *)(&ps->accumulator))[1]; + break; + case hwmon_power_average_interval: + *val = ps->update_tag; + break; + case hwmon_power_reset_history: + *val = ps->function_id | (ps->apss_channel << 8); + break; + default: + rc = -EOPNOTSUPP; + } + } + break; + case CAPS: + { + struct p9_caps_sensor *cs = + &(((struct p9_caps_sensor *)sensor)[sensor_num]); + + switch (hwmon) { + case hwmon_power_cap: + *val = cs->curr_powercap; + break; + case hwmon_power_cap_max: + *val = cs->max_powercap; + break; + case hwmon_power_cap_min: + *val = cs->min_powercap; + break; + case hwmon_power_max: + *val = cs->norm_powercap; + break; + case hwmon_power_alarm: + *val = cs->user_powerlimit; + break; + case hwmon_power_cap_alarm: + *val = cs->user_powerlimit_source; + break; + default: + rc = -EOPNOTSUPP; + } + } + break; + default: + rc = -EINVAL; + } + + return rc; +} + +static const struct occ_ops p9_ops = { + .parse_sensor = p9_parse_sensor, + .alloc_sensor = p9_alloc_sensor, + .get_sensor = p9_get_sensor, +}; + +static const struct occ_init_data p9_init = { + .command_addr = 0xFFFBE000, + .response_addr = 0xFFFBF000, + .ops = &p9_ops, +}; + +const u32 *p9_get_sensor_hwmon_configs() +{ + return p9_sensor_hwmon_configs; +} + +struct occ *p9_occ_init(struct device *dev, void *bus, + const struct occ_bus_ops *bus_ops) +{ + return occ_init(dev, bus, bus_ops, &p9_init); +} + +MODULE_AUTHOR("Eddie James "); +MODULE_DESCRIPTION("P9 OCC sensors"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/occ/occ_p9.h b/drivers/hwmon/occ/occ_p9.h new file mode 100644 index 0000000..0fd647a --- /dev/null +++ b/drivers/hwmon/occ/occ_p9.h @@ -0,0 +1,25 @@ +/* + * occ_p9.h - OCC hwmon driver + * + * This file contains Power9-specific function prototypes + * + * Copyright 2017 IBM Corp. + * + * 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. + */ + +#ifndef __OCC_P9_H__ +#define __OCC_P9_H__ + +struct device; +struct occ; +struct occ_bus_ops; + +const u32 *p9_get_sensor_hwmon_configs(void); +struct occ *p9_occ_init(struct device *dev, void *bus, + const struct occ_bus_ops *bus_ops); + +#endif /* __OCC_P9_H__ */