From 989908ce4ccafdbe816408b7970bb63bb4edbecd Mon Sep 17 00:00:00 2001 From: =?utf8?q?Francisco=20Trivi=C3=B1o?= Date: Wed, 3 Aug 2016 01:07:26 +0200 Subject: [PATCH] sif: sif_hwmon: add hwmon interface to export psif chip temperatures MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This commit adds support to export psif chip temperatures via hwmon interface Orabug: 24432362 Signed-off-by: Francisco Triviño Reviewed-by: Knut Omang --- drivers/infiniband/hw/sif/Makefile | 2 +- drivers/infiniband/hw/sif/sif_dev.h | 1 + drivers/infiniband/hw/sif/sif_hwmon.c | 152 ++++++++++++++++++++++++++ drivers/infiniband/hw/sif/sif_hwmon.h | 20 ++++ drivers/infiniband/hw/sif/sif_ireg.c | 3 + 5 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 drivers/infiniband/hw/sif/sif_hwmon.c create mode 100644 drivers/infiniband/hw/sif/sif_hwmon.h diff --git a/drivers/infiniband/hw/sif/Makefile b/drivers/infiniband/hw/sif/Makefile index b4e00159403b..825e82e32f6b 100644 --- a/drivers/infiniband/hw/sif/Makefile +++ b/drivers/infiniband/hw/sif/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_INFINIBAND_SIF) := sif.o sif-y := sif_main.o sif_mmu.o sif_dma.o sif_qp.o sif_sq.o \ sif_cq.o sif_mr.o sif_mw.o sif_fmr.o sif_ah.o sif_pd.o sif_rq.o sif_srq.o \ - sif_tqp.o sif_sndrcv.o sif_base.o sif_hwi.o sif_r3.o sif_vf.o sif_ireg.o sif_defs.o \ + sif_tqp.o sif_sndrcv.o sif_base.o sif_hwi.o sif_r3.o sif_hwmon.o sif_vf.o sif_ireg.o sif_defs.o \ sif_debug.o sif_epsc.o sif_eq.o sif_query.o sif_pqp.o \ sif_verbs.o sif_fwa.o sif_checksum.o sif_spt.o sif_elog.o \ sif_xmmu.o sif_xrc.o sif_mem.o sif_pt.o sif_idr.o version.o diff --git a/drivers/infiniband/hw/sif/sif_dev.h b/drivers/infiniband/hw/sif/sif_dev.h index fb05b0222eff..59d9a2d3b8db 100644 --- a/drivers/infiniband/hw/sif/sif_dev.h +++ b/drivers/infiniband/hw/sif/sif_dev.h @@ -236,6 +236,7 @@ struct sif_compl; /* Declared in sif_cq.h */ struct sif_dev { struct ib_device ib_dev; + struct device *hwmon_dev; struct sif_verbs sv; struct pci_dev *pdev; struct sif_dfs *dfs; /* Optional debugfs info, if enabled in kernel */ diff --git a/drivers/infiniband/hw/sif/sif_hwmon.c b/drivers/infiniband/hw/sif/sif_hwmon.c new file mode 100644 index 000000000000..db3b4c0ed1b5 --- /dev/null +++ b/drivers/infiniband/hw/sif/sif_hwmon.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Author: Francisco Triviño + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * Driver for Oracle Scalable Infiniband Fabric (SIF) Host Channel Adapters + * + * sif_hwmon.c: SIF Hardware Monitoring + */ + +#include "sif_dev.h" +#include "sif_query.h" +#include "sif_defs.h" +#include "psif_hw_setget.h" +#include "sif_hwmon.h" +#include "psif_hw_data.h" +#include +#include + + +enum sif_hwmon_attr_type { + SIF_HWMON_ATTR_TEMP_MAX, + SIF_HWMON_ATTR_TEMP_MAIN, + SIF_HWMON_ATTR_TEMP_EPS, + SIF_HWMON_ATTR_TEMP_IBU, + SIF_HWMON_ATTR_TEMP_PEU, + SIF_HWMON_ATTR_TEMP_TSU, +}; + +static u64 sensor_show(const struct device *device, + struct device_attribute *attr, + char *buf, + int sif_hwmon_attr_temp) +{ + struct sif_dev *sdev = dev_get_drvdata(device); + struct psif_epsc_csr_req req; + struct psif_epsc_csr_rsp rsp; + + /* EPSC supports the new requests starting from v.2.8 */ + if (eps_version_ge(&sdev->es[sdev->mbox_epsc], 2, 8)) { + int ret = 0; + + memset(&req, 0, sizeof(req)); + memset(&rsp, 0, sizeof(rsp)); + req.opcode = EPSC_QUERY; + req.u.query.data.op = EPSC_QUERY_ON_CHIP_TEMP; + ret = sif_epsc_wr(sdev, &req, &rsp); + + if (!ret) { + u16 t = 0; + struct psif_epsc_query_on_chip_temp *temp = + (struct psif_epsc_query_on_chip_temp *)&rsp.data; + switch (sif_hwmon_attr_temp) { + case SIF_HWMON_ATTR_TEMP_MAX: + t = temp->max; + break; + case SIF_HWMON_ATTR_TEMP_MAIN: + t = temp->main; + break; + case SIF_HWMON_ATTR_TEMP_EPS: + t = temp->eps; + break; + case SIF_HWMON_ATTR_TEMP_IBU: + t = temp->ibu; + break; + case SIF_HWMON_ATTR_TEMP_PEU: + t = temp->peu; + break; + case SIF_HWMON_ATTR_TEMP_TSU: + t = temp->tsu; + break; + default: + WARN_ON(1); + } + sprintf(buf, "%u\n", t); + } + else + sif_log(sdev, SIF_INFO, "Failed to query on chip temperature\n"); + } + return strlen(buf); +} + +/* hwmon-sysfs attributes */ +#define SENSOR_DEVICE_SHOW(field) \ +static ssize_t show_sensor_##field(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + return sensor_show(dev, attr, buf, SIF_HWMON_ATTR_TEMP_##field);\ +} + +SENSOR_DEVICE_SHOW(MAX); +SENSOR_DEVICE_SHOW(MAIN); +SENSOR_DEVICE_SHOW(EPS); +SENSOR_DEVICE_SHOW(IBU); +SENSOR_DEVICE_SHOW(PEU); +SENSOR_DEVICE_SHOW(TSU); + + +static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_sensor_MAX, NULL, 1); +static SENSOR_DEVICE_ATTR(temp1_main, S_IRUGO, show_sensor_MAIN, NULL, 1); +static SENSOR_DEVICE_ATTR(temp1_eps, S_IRUGO, show_sensor_EPS, NULL, 1); +static SENSOR_DEVICE_ATTR(temp1_ibu, S_IRUGO, show_sensor_IBU, NULL, 1); +static SENSOR_DEVICE_ATTR(temp1_peu, S_IRUGO, show_sensor_PEU, NULL, 1); +static SENSOR_DEVICE_ATTR(temp1_tsu, S_IRUGO, show_sensor_TSU, NULL, 1); + + +static struct attribute *sif_hwmon_attrs[] = { + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_main.dev_attr.attr, + &sensor_dev_attr_temp1_eps.dev_attr.attr, + &sensor_dev_attr_temp1_ibu.dev_attr.attr, + &sensor_dev_attr_temp1_peu.dev_attr.attr, + &sensor_dev_attr_temp1_tsu.dev_attr.attr, + NULL, +}; + +ATTRIBUTE_GROUPS(sif_hwmon); + +void sif_register_hwmon_dev(struct sif_dev *sdev) +{ + struct device *dev = &sdev->pdev->dev; + struct device *hwmon_dev; + + /* Skip hwmon registration for a VF device */ + if (sdev->is_vf) { + sdev->hwmon_dev = NULL; + return; + } + hwmon_dev = hwmon_device_register_with_groups(dev, sdev->ib_dev.name, + sdev, + sif_hwmon_groups); + if (IS_ERR(hwmon_dev)) { + dev_err(dev, "Cannot register with hwmon, err=%ld\n", + PTR_ERR(hwmon_dev)); + hwmon_dev = NULL; + } + sdev->hwmon_dev = hwmon_dev; +} + +void sif_unregister_hwmon_dev(struct sif_dev *sdev) +{ + struct device *hwmon_dev = sdev->hwmon_dev; + if (hwmon_dev) { + hwmon_device_unregister(hwmon_dev); + sdev->hwmon_dev = NULL; + } +} + diff --git a/drivers/infiniband/hw/sif/sif_hwmon.h b/drivers/infiniband/hw/sif/sif_hwmon.h new file mode 100644 index 000000000000..e65c09361f5d --- /dev/null +++ b/drivers/infiniband/hw/sif/sif_hwmon.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Author: Francisco Triviño + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * Driver for Oracle Scalable Infiniband Fabric (SIF) Host Channel Adapters + * + * sif_hwmon.h: SIF Hardware Monitoring + */ + +#ifndef _SIF_HWMON_H +#define _SIF_HWMON_H + +void sif_register_hwmon_dev(struct sif_dev *sdev); +void sif_unregister_hwmon_dev(struct sif_dev *sdev); + +#endif diff --git a/drivers/infiniband/hw/sif/sif_ireg.c b/drivers/infiniband/hw/sif/sif_ireg.c index 40e312c22c8f..762cf8d5bc8d 100644 --- a/drivers/infiniband/hw/sif/sif_ireg.c +++ b/drivers/infiniband/hw/sif/sif_ireg.c @@ -36,6 +36,7 @@ #include "sif_pd.h" #include "sif_base.h" #include "version.h" +#include "sif_hwmon.h" static ssize_t show_rev(struct device *dev, struct device_attribute *attr, @@ -899,6 +900,7 @@ int sif_register_ib_device(struct sif_dev *sdev) goto err_sysfsreg; } + sif_register_hwmon_dev(sdev); /* Populate the external kernel API (see sif_verbs.h): */ sdev->sv.eps_wr = sif_eps_wr_ex; sdev->sv.create_cq = sif_create_cq; @@ -920,6 +922,7 @@ void sif_unregister_ib_device(struct sif_dev *sdev) { struct ib_device *ibdev = &sdev->ib_dev; + sif_unregister_hwmon_dev(sdev); sdev->registered = false; ib_unregister_device(ibdev); sif_logi(ibdev, SIF_VERBS, "done unregistering device"); -- 2.50.1