From patchwork Wed Jan 11 18:10:35 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: eajames.ibm@gmail.com X-Patchwork-Id: 9510975 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 A09AA601E7 for ; Wed, 11 Jan 2017 18:13:03 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7F36028650 for ; Wed, 11 Jan 2017 18:13:03 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7416C28653; Wed, 11 Jan 2017 18:13:03 +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.3 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM, T_DKIM_INVALID autolearn=unavailable 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 C524128650 for ; Wed, 11 Jan 2017 18:13:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S938644AbdAKSL4 (ORCPT ); Wed, 11 Jan 2017 13:11:56 -0500 Received: from mail-it0-f68.google.com ([209.85.214.68]:36831 "EHLO mail-it0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S939173AbdAKSLB (ORCPT ); Wed, 11 Jan 2017 13:11:01 -0500 Received: by mail-it0-f68.google.com with SMTP id o138so3584014ito.3; Wed, 11 Jan 2017 10:11:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=iXagMKpRUNqY7gSwN4JI6PaE3pFtJleZbHPj0YiuHkA=; b=jYO2lWpAHdl39ei0Efmqjb+yd5CFI+RHEaa4OiHLtb9WIcokYYXOFvSmMniiJPZR9M WKMLdhioDVDhGojwDERU5/0yW1T59RCbSfhDVmUJ6KJucroBMi8xl3gYDJPRgWn7LPfh t0LRDtJz8kwqame8MluECv9jZbUw5uQogyU8ivTGFrsqR8bHMYLFoi96nJlBOTGubwV2 D+ET6j+uaoQKJHOqdZ5C123ZX3pD5XX1vzBAjDc2L1j+3zyOPReRdol7IVHjnKbI7EDf nvkvQS9PMFQCcJBOwrN/MOHwiQs2yWl6RJz2dfGyF3zbD3dwXi/bKZBT8HE8HF9Ktiza VEwg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=iXagMKpRUNqY7gSwN4JI6PaE3pFtJleZbHPj0YiuHkA=; b=pyJOq3vmbn/DoUofAPzAo8mOXnpGtRuWJktsrHo0U6o8zBrGfihh6FyPpNBjl14NAF onL1vDAoaETFoHCxC2bYsaVeWclkJaB77CjNoRGFakt7E0z0wa84ErHXcHNqw6BNc4bi VTJfkolslsctSPmLwwRdZCn4nrQ69L4rAjHlx5T/4tORHWWzn71r5n6sR0eaf3QvK51R DzK8biJWQUhYYCKL6Uver9zk62VF4Wvocf8RXwe/JDeNYZzQUiPcBJqErHs/lQF9od8B TMUAJ2OMTvGSEFPUpIVe0YNG7kvme0Wp8oSU8ctoGaYm2PrVLKppDgd1YWqScytThm/r jXJg== X-Gm-Message-State: AIkVDXKs7+EmVt6opxUHEDudp1JOwxupHiieDLMQ+XmRLz7u5lF7koED0atoBcDsDZtPdQ== X-Received: by 10.36.17.133 with SMTP id 127mr6512869itf.31.1484158260234; Wed, 11 Jan 2017 10:11:00 -0800 (PST) Received: from eajames-austin-w350.austin.ibm.com ([32.97.110.55]) by smtp.gmail.com with ESMTPSA id w143sm3415940itc.0.2017.01.11.10.10.57 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 11 Jan 2017 10:10:59 -0800 (PST) From: eajames.ibm@gmail.com To: linux@roeck-us.net Cc: devicetree@vger.kernel.org, jdelvare@suse.com, corbet@lwn.net, linux-doc@vger.kernel.org, linux-hwmon@vger.kernel.org, linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org, mark.rutland@arm.com, robh+dt@kernel.org, wsa@the-dreams.de, andrew@aj.id.au, joel@jms.id.au, benh@kernel.crashing.org, "Edward A. James" Subject: [PATCH linux v2 4/6] hwmon: occ: Add callbacks for parsing P8 OCC datastructures Date: Wed, 11 Jan 2017 12:10:35 -0600 Message-Id: <1484158237-10014-5-git-send-email-eajames.ibm@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1484158237-10014-1-git-send-email-eajames.ibm@gmail.com> References: <1484158237-10014-1-git-send-email-eajames.ibm@gmail.com> 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 POWER8 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 | 9 ++ drivers/hwmon/occ/occ_p8.c | 254 +++++++++++++++++++++++++++++++++++++++++++++ drivers/hwmon/occ/occ_p8.h | 31 ++++++ 3 files changed, 294 insertions(+) create mode 100644 drivers/hwmon/occ/occ_p8.c create mode 100644 drivers/hwmon/occ/occ_p8.h diff --git a/Documentation/hwmon/occ b/Documentation/hwmon/occ index d0bdf06..143951e 100644 --- a/Documentation/hwmon/occ +++ b/Documentation/hwmon/occ @@ -25,6 +25,15 @@ Currently, all versions of the OCC support four types of sensor data: power, temperature, frequency, and "caps," which indicate limits and thresholds used internally on the OCC. +The format for the POWER8 OCC sensor data can be found in the P8 OCC +specification: +github.com/open-power/docs/blob/master/occ/OCC_OpenPwr_FW_Interfaces.pdf +This document provides the details of the OCC sensors: power, frequency, +temperature, and caps. These sensor formats are specific to the POWER8 OCC. A +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. + sysfs Entries ------------- diff --git a/drivers/hwmon/occ/occ_p8.c b/drivers/hwmon/occ/occ_p8.c new file mode 100644 index 0000000..6673da2 --- /dev/null +++ b/drivers/hwmon/occ/occ_p8.c @@ -0,0 +1,254 @@ +/* + * occ_p8.c - OCC hwmon driver + * + * This file contains the Power8-specific methods and data structures for + * the OCC hwmon driver. + * + * Copyright 2016 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. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "occ.h" +#include "occ_p8.h" + +/* P8 OCC sensor data format */ +struct p8_occ_sensor { + u16 sensor_id; + u16 value; +}; + +struct p8_power_sensor { + u16 sensor_id; + u32 update_tag; + u32 accumulator; + u16 value; +}; + +struct p8_caps_sensor { + u16 curr_powercap; + u16 curr_powerreading; + u16 norm_powercap; + u16 max_powercap; + u16 min_powercap; + u16 user_powerlimit; +}; + +static const u32 p8_sensor_hwmon_configs[MAX_OCC_SENSOR_TYPE] = { + HWMON_I_INPUT | HWMON_I_LABEL, /* freq: value | label */ + HWMON_T_INPUT | HWMON_T_LABEL, /* temp: value | label */ + /* power: value | label | accumulator | update_tag */ + HWMON_P_INPUT | HWMON_P_LABEL | HWMON_P_AVERAGE | + HWMON_P_AVERAGE_INTERVAL, + /* caps: curr | max | min | norm | user */ + HWMON_P_CAP | HWMON_P_CAP_MAX | HWMON_P_CAP_MIN | HWMON_P_MAX | + HWMON_P_ALARM, +}; + +void p8_parse_sensor(u8 *data, void *sensor, int sensor_type, int off, + int snum) +{ + switch (sensor_type) { + case FREQ: + case TEMP: + { + struct p8_occ_sensor *os = + &(((struct p8_occ_sensor *)sensor)[snum]); + + os->sensor_id = be16_to_cpu(get_unaligned((u16 *)&data[off])); + os->value = be16_to_cpu(get_unaligned((u16 *)&data[off + 2])); + } + break; + case POWER: + { + struct p8_power_sensor *ps = + &(((struct p8_power_sensor *)sensor)[snum]); + + ps->sensor_id = be16_to_cpu(get_unaligned((u16 *)&data[off])); + ps->update_tag = + be32_to_cpu(get_unaligned((u32 *)&data[off + 2])); + ps->accumulator = + be32_to_cpu(get_unaligned((u32 *)&data[off + 6])); + ps->value = be16_to_cpu(get_unaligned((u16 *)&data[off + 10])); + } + break; + case CAPS: + { + struct p8_caps_sensor *cs = + &(((struct p8_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])); + } + break; + }; +} + +void *p8_alloc_sensor(int sensor_type, int num_sensors) +{ + switch (sensor_type) { + case FREQ: + case TEMP: + return kcalloc(num_sensors, sizeof(struct p8_occ_sensor), + GFP_KERNEL); + case POWER: + return kcalloc(num_sensors, sizeof(struct p8_power_sensor), + GFP_KERNEL); + case CAPS: + return kcalloc(num_sensors, sizeof(struct p8_caps_sensor), + GFP_KERNEL); + default: + return NULL; + } +} + +int p8_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) + sensor_type = CAPS; + } + + sensor = occ_get_sensor(driver, sensor_type); + if (!sensor) + return -ENODEV; + + switch (sensor_type) { + case FREQ: + case TEMP: + { + struct p8_occ_sensor *os = + &(((struct p8_occ_sensor *)sensor)[sensor_num]); + + if (hwmon == hwmon_in_input || hwmon == hwmon_temp_input) + *val = os->value; + else if (hwmon == hwmon_in_label || hwmon == hwmon_temp_label) + *val = os->sensor_id; + else + rc = -EOPNOTSUPP; + } + break; + case POWER: + { + struct p8_power_sensor *ps = + &(((struct p8_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: + *val = ps->accumulator; + break; + case hwmon_power_average_interval: + *val = ps->update_tag; + break; + default: + rc = -EOPNOTSUPP; + } + } + break; + case CAPS: + { + struct p8_caps_sensor *cs = + &(((struct p8_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; + default: + rc = -EOPNOTSUPP; + } + } + break; + default: + rc = -EINVAL; + } + + return rc; +} + +static const struct occ_ops p8_ops = { + .parse_sensor = p8_parse_sensor, + .alloc_sensor = p8_alloc_sensor, + .get_sensor = p8_get_sensor, +}; + +static const struct occ_config p8_config = { + .command_addr = 0xFFFF6000, + .response_addr = 0xFFFF7000, +}; + +const u32 *p8_get_sensor_hwmon_configs() +{ + return p8_sensor_hwmon_configs; +} +EXPORT_SYMBOL(p8_get_sensor_hwmon_configs); + +struct occ *p8_occ_start(struct device *dev, void *bus, + struct occ_bus_ops *bus_ops) +{ + return occ_start(dev, bus, bus_ops, &p8_ops, &p8_config); +} +EXPORT_SYMBOL(p8_occ_start); + +int p8_occ_stop(struct occ *occ) +{ + return occ_stop(occ); +} +EXPORT_SYMBOL(p8_occ_stop); + +MODULE_AUTHOR("Eddie James "); +MODULE_DESCRIPTION("P8 OCC sensors"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/occ/occ_p8.h b/drivers/hwmon/occ/occ_p8.h new file mode 100644 index 0000000..54ce907 --- /dev/null +++ b/drivers/hwmon/occ/occ_p8.h @@ -0,0 +1,31 @@ +/* + * occ_p8.h - OCC hwmon driver + * + * This file contains Power8-specific function prototypes + * + * Copyright 2016 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. + * + * 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. + */ + +#ifndef __OCC_P8_H__ +#define __OCC_P8_H__ + +#include "scom.h" + +struct device; + +const u32 *p8_get_sensor_hwmon_configs(void); +struct occ *p8_occ_start(struct device *dev, void *bus, + struct occ_bus_ops *bus_ops); +int p8_occ_stop(struct occ *occ); + +#endif /* __OCC_P8_H__ */