[go: nahoru, domu]

155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings/****************************************************************************
2f7a6d2c4427790cc8695401576dc594fcce8fc80Ben Hutchings * Driver for Solarflare network controllers and boards
3f7a6d2c4427790cc8695401576dc594fcce8fc80Ben Hutchings * Copyright 2011-2013 Solarflare Communications Inc.
455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings *
555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings * This program is free software; you can redistribute it and/or modify it
655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings * under the terms of the GNU General Public License version 2 as published
755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings * by the Free Software Foundation, incorporated herein by reference.
855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings */
955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
1055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings#include <linux/bitops.h>
1155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings#include <linux/slab.h>
1255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings#include <linux/hwmon.h>
1355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings#include <linux/stat.h>
1455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
1555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings#include "net_driver.h"
1655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings#include "mcdi.h"
1755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings#include "mcdi_pcol.h"
1855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings#include "nic.h"
1955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
2055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchingsenum efx_hwmon_type {
2155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	EFX_HWMON_UNKNOWN,
2255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	EFX_HWMON_TEMP,         /* temperature */
2355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	EFX_HWMON_COOL,         /* cooling device, probably a heatsink */
2438589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	EFX_HWMON_IN,		/* voltage */
2538589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	EFX_HWMON_CURR,		/* current */
2638589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	EFX_HWMON_POWER,	/* power */
272b216cef086a5b564a4415d7f1b6095ea1c2089cEdward Cree	EFX_HWMON_TYPES_COUNT
282b216cef086a5b564a4415d7f1b6095ea1c2089cEdward Cree};
292b216cef086a5b564a4415d7f1b6095ea1c2089cEdward Cree
302b216cef086a5b564a4415d7f1b6095ea1c2089cEdward Creestatic const char *const efx_hwmon_unit[EFX_HWMON_TYPES_COUNT] = {
312b216cef086a5b564a4415d7f1b6095ea1c2089cEdward Cree	[EFX_HWMON_TEMP]  = " degC",
322b216cef086a5b564a4415d7f1b6095ea1c2089cEdward Cree	[EFX_HWMON_COOL]  = " rpm", /* though nonsense for a heatsink */
332b216cef086a5b564a4415d7f1b6095ea1c2089cEdward Cree	[EFX_HWMON_IN]    = " mV",
342b216cef086a5b564a4415d7f1b6095ea1c2089cEdward Cree	[EFX_HWMON_CURR]  = " mA",
352b216cef086a5b564a4415d7f1b6095ea1c2089cEdward Cree	[EFX_HWMON_POWER] = " W",
3655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings};
3755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
3855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchingsstatic const struct {
3955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	const char *label;
4055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	enum efx_hwmon_type hwmon_type;
4155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	int port;
42d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings} efx_mcdi_sensor_type[] = {
4338589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings#define SENSOR(name, label, hwmon_type, port)				\
4438589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	[MC_CMD_SENSOR_##name] = { label, EFX_HWMON_ ## hwmon_type, port }
450cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree	SENSOR(CONTROLLER_TEMP,		"Controller board temp.",   TEMP,  -1),
4638589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	SENSOR(PHY_COMMON_TEMP,		"PHY temp.",		    TEMP,  -1),
470cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree	SENSOR(CONTROLLER_COOLING,	"Controller heat sink",	    COOL,  -1),
4838589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	SENSOR(PHY0_TEMP,		"PHY temp.",		    TEMP,  0),
490cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree	SENSOR(PHY0_COOLING,		"PHY heat sink",	    COOL,  0),
5038589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	SENSOR(PHY1_TEMP,		"PHY temp.",		    TEMP,  1),
510cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree	SENSOR(PHY1_COOLING,		"PHY heat sink",	    COOL,  1),
5238589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	SENSOR(IN_1V0,			"1.0V supply",		    IN,    -1),
5338589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	SENSOR(IN_1V2,			"1.2V supply",		    IN,    -1),
5438589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	SENSOR(IN_1V8,			"1.8V supply",		    IN,    -1),
5538589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	SENSOR(IN_2V5,			"2.5V supply",		    IN,    -1),
5638589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	SENSOR(IN_3V3,			"3.3V supply",		    IN,    -1),
5738589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	SENSOR(IN_12V0,			"12.0V supply",		    IN,    -1),
5838589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	SENSOR(IN_1V2A,			"1.2V analogue supply",	    IN,    -1),
590cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree	SENSOR(IN_VREF,			"Ref. voltage",		    IN,    -1),
600cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree	SENSOR(OUT_VAOE,		"AOE FPGA supply",	    IN,    -1),
610cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree	SENSOR(AOE_TEMP,		"AOE FPGA temp.",	    TEMP,  -1),
620cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree	SENSOR(PSU_AOE_TEMP,		"AOE regulator temp.",	    TEMP,  -1),
630cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree	SENSOR(PSU_TEMP,		"Controller regulator temp.",
640cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree								    TEMP,  -1),
650cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree	SENSOR(FAN_0,			"Fan 0",		    COOL,  -1),
660cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree	SENSOR(FAN_1,			"Fan 1",		    COOL,  -1),
670cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree	SENSOR(FAN_2,			"Fan 2",		    COOL,  -1),
680cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree	SENSOR(FAN_3,			"Fan 3",		    COOL,  -1),
690cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree	SENSOR(FAN_4,			"Fan 4",		    COOL,  -1),
7038589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	SENSOR(IN_VAOE,			"AOE input supply",	    IN,    -1),
7138589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	SENSOR(OUT_IAOE,		"AOE output current",	    CURR,  -1),
7238589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	SENSOR(IN_IAOE,			"AOE input current",	    CURR,  -1),
7338589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	SENSOR(NIC_POWER,		"Board power use",	    POWER, -1),
7438589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	SENSOR(IN_0V9,			"0.9V supply",		    IN,    -1),
750cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree	SENSOR(IN_I0V9,			"0.9V supply current",	    CURR,  -1),
760cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree	SENSOR(IN_I1V2,			"1.2V supply current",	    CURR,  -1),
770cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree	SENSOR(IN_0V9_ADC,		"0.9V supply (ext. ADC)",   IN,    -1),
780cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree	SENSOR(CONTROLLER_2_TEMP,	"Controller board temp. 2", TEMP,  -1),
790cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree	SENSOR(VREG_INTERNAL_TEMP,	"Regulator die temp.",	    TEMP,  -1),
8038589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	SENSOR(VREG_0V9_TEMP,		"0.9V regulator temp.",     TEMP,  -1),
8138589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	SENSOR(VREG_1V2_TEMP,		"1.2V regulator temp.",     TEMP,  -1),
820cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree	SENSOR(CONTROLLER_VPTAT,
830cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree			      "Controller PTAT voltage (int. ADC)", IN,    -1),
840cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree	SENSOR(CONTROLLER_INTERNAL_TEMP,
850cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree				 "Controller die temp. (int. ADC)", TEMP,  -1),
8638589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	SENSOR(CONTROLLER_VPTAT_EXTADC,
870cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree			      "Controller PTAT voltage (ext. ADC)", IN,    -1),
8838589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	SENSOR(CONTROLLER_INTERNAL_TEMP_EXTADC,
890cf7a455d4fed61549098fa8cce37462185c1bf8Edward Cree				 "Controller die temp. (ext. ADC)", TEMP,  -1),
9038589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	SENSOR(AMBIENT_TEMP,		"Ambient temp.",	    TEMP,  -1),
9138589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	SENSOR(AIRFLOW,			"Air flow raw",		    IN,    -1),
928d13a377b8c2bc20a349b98443bb7e7c5970e991Ben Hutchings	SENSOR(VDD08D_VSS08D_CSR,	"0.9V die (int. ADC)",	    IN,    -1),
938d13a377b8c2bc20a349b98443bb7e7c5970e991Ben Hutchings	SENSOR(VDD08D_VSS08D_CSR_EXTADC, "0.9V die (ext. ADC)",	    IN,    -1),
948d13a377b8c2bc20a349b98443bb7e7c5970e991Ben Hutchings	SENSOR(HOTPOINT_TEMP,  "Controller board temp. (hotpoint)", TEMP,  -1),
9555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings#undef SENSOR
9655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings};
9755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
9855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchingsstatic const char *const sensor_status_names[] = {
9955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	[MC_CMD_SENSOR_STATE_OK] = "OK",
10055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	[MC_CMD_SENSOR_STATE_WARNING] = "Warning",
10155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	[MC_CMD_SENSOR_STATE_FATAL] = "Fatal",
10255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	[MC_CMD_SENSOR_STATE_BROKEN] = "Device failure",
1038c4e720f181f251948c52913c74a86f68aed9c50Alexandre Rames	[MC_CMD_SENSOR_STATE_NO_READING] = "No reading",
10455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings};
10555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
10655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchingsvoid efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev)
10755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings{
10855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	unsigned int type, state, value;
1092b216cef086a5b564a4415d7f1b6095ea1c2089cEdward Cree	enum efx_hwmon_type hwmon_type = EFX_HWMON_UNKNOWN;
1102b216cef086a5b564a4415d7f1b6095ea1c2089cEdward Cree	const char *name = NULL, *state_txt, *unit;
11155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
11255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	type = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_MONITOR);
11355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	state = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_STATE);
11455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	value = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_VALUE);
11555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
11655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	/* Deal gracefully with the board having more drivers than we
11755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	 * know about, but do not expect new sensor states. */
1182b216cef086a5b564a4415d7f1b6095ea1c2089cEdward Cree	if (type < ARRAY_SIZE(efx_mcdi_sensor_type)) {
11955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		name = efx_mcdi_sensor_type[type].label;
1202b216cef086a5b564a4415d7f1b6095ea1c2089cEdward Cree		hwmon_type = efx_mcdi_sensor_type[type].hwmon_type;
1212b216cef086a5b564a4415d7f1b6095ea1c2089cEdward Cree	}
12255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	if (!name)
12355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		name = "No sensor name available";
12455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	EFX_BUG_ON_PARANOID(state >= ARRAY_SIZE(sensor_status_names));
12555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	state_txt = sensor_status_names[state];
1262b216cef086a5b564a4415d7f1b6095ea1c2089cEdward Cree	EFX_BUG_ON_PARANOID(hwmon_type >= EFX_HWMON_TYPES_COUNT);
1272b216cef086a5b564a4415d7f1b6095ea1c2089cEdward Cree	unit = efx_hwmon_unit[hwmon_type];
1282b216cef086a5b564a4415d7f1b6095ea1c2089cEdward Cree	if (!unit)
1292b216cef086a5b564a4415d7f1b6095ea1c2089cEdward Cree		unit = "";
13055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
13155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	netif_err(efx, hw, efx->net_dev,
1322b216cef086a5b564a4415d7f1b6095ea1c2089cEdward Cree		  "Sensor %d (%s) reports condition '%s' for value %d%s\n",
1332b216cef086a5b564a4415d7f1b6095ea1c2089cEdward Cree		  type, name, state_txt, value, unit);
13455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings}
13555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
13655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings#ifdef CONFIG_SFC_MCDI_MON
13755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
13855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchingsstruct efx_mcdi_mon_attribute {
13955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	struct device_attribute dev_attr;
14055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	unsigned int index;
14155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	unsigned int type;
142d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings	enum efx_hwmon_type hwmon_type;
14355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	unsigned int limit_value;
14455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	char name[12];
14555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings};
14655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
14755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchingsstatic int efx_mcdi_mon_update(struct efx_nic *efx)
14855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings{
14955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	struct efx_mcdi_mon *hwmon = efx_mcdi_mon(efx);
150d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings	MCDI_DECLARE_BUF(inbuf, MC_CMD_READ_SENSORS_EXT_IN_LEN);
15155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	int rc;
15255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
153d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings	MCDI_SET_QWORD(inbuf, READ_SENSORS_EXT_IN_DMA_ADDR,
154338f74df399d652788cf3bab247257ae90419c7dBen Hutchings		       hwmon->dma_buf.dma_addr);
155d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings	MCDI_SET_DWORD(inbuf, READ_SENSORS_EXT_IN_LENGTH, hwmon->dma_buf.len);
15655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
15755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	rc = efx_mcdi_rpc(efx, MC_CMD_READ_SENSORS,
15855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings			  inbuf, sizeof(inbuf), NULL, 0, NULL);
15955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	if (rc == 0)
16055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		hwmon->last_update = jiffies;
16155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	return rc;
16255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings}
16355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
16455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchingsstatic int efx_mcdi_mon_get_entry(struct device *dev, unsigned int index,
16555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings				  efx_dword_t *entry)
16655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings{
16785493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck	struct efx_nic *efx = dev_get_drvdata(dev->parent);
16855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	struct efx_mcdi_mon *hwmon = efx_mcdi_mon(efx);
16955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	int rc;
17055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
17155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	BUILD_BUG_ON(MC_CMD_READ_SENSORS_OUT_LEN != 0);
17255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
17355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	mutex_lock(&hwmon->update_lock);
17455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
17555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	/* Use cached value if last update was < 1 s ago */
17655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	if (time_before(jiffies, hwmon->last_update + HZ))
17755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		rc = 0;
17855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	else
17955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		rc = efx_mcdi_mon_update(efx);
18055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
18155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	/* Copy out the requested entry */
18255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	*entry = ((efx_dword_t *)hwmon->dma_buf.addr)[index];
18355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
18455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	mutex_unlock(&hwmon->update_lock);
18555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
18655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	return rc;
18755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings}
18855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
18955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchingsstatic ssize_t efx_mcdi_mon_show_value(struct device *dev,
19055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings				       struct device_attribute *attr,
19155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings				       char *buf)
19255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings{
19355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	struct efx_mcdi_mon_attribute *mon_attr =
19455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		container_of(attr, struct efx_mcdi_mon_attribute, dev_attr);
19555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	efx_dword_t entry;
1968c4e720f181f251948c52913c74a86f68aed9c50Alexandre Rames	unsigned int value, state;
19755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	int rc;
19855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
19955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	rc = efx_mcdi_mon_get_entry(dev, mon_attr->index, &entry);
20055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	if (rc)
20155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		return rc;
20255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
2038c4e720f181f251948c52913c74a86f68aed9c50Alexandre Rames	state = EFX_DWORD_FIELD(entry, MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE);
2048c4e720f181f251948c52913c74a86f68aed9c50Alexandre Rames	if (state == MC_CMD_SENSOR_STATE_NO_READING)
2058c4e720f181f251948c52913c74a86f68aed9c50Alexandre Rames		return -EBUSY;
2068c4e720f181f251948c52913c74a86f68aed9c50Alexandre Rames
20755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	value = EFX_DWORD_FIELD(entry, MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_VALUE);
20855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
20938589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	switch (mon_attr->hwmon_type) {
21038589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	case EFX_HWMON_TEMP:
21138589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings		/* Convert temperature from degrees to milli-degrees Celsius */
21255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		value *= 1000;
21338589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings		break;
21438589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	case EFX_HWMON_POWER:
21538589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings		/* Convert power from watts to microwatts */
21638589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings		value *= 1000000;
21738589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings		break;
21838589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	default:
21938589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings		/* No conversion needed */
22038589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings		break;
22138589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	}
22255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
22355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	return sprintf(buf, "%u\n", value);
22455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings}
22555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
22655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchingsstatic ssize_t efx_mcdi_mon_show_limit(struct device *dev,
22755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings				       struct device_attribute *attr,
22855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings				       char *buf)
22955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings{
23055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	struct efx_mcdi_mon_attribute *mon_attr =
23155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		container_of(attr, struct efx_mcdi_mon_attribute, dev_attr);
23255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	unsigned int value;
23355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
23455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	value = mon_attr->limit_value;
23555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
23638589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	switch (mon_attr->hwmon_type) {
23738589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	case EFX_HWMON_TEMP:
23838589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings		/* Convert temperature from degrees to milli-degrees Celsius */
23955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		value *= 1000;
24038589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings		break;
24138589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	case EFX_HWMON_POWER:
24238589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings		/* Convert power from watts to microwatts */
24338589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings		value *= 1000000;
24438589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings		break;
24538589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	default:
24638589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings		/* No conversion needed */
24738589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings		break;
24838589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	}
24955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
25055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	return sprintf(buf, "%u\n", value);
25155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings}
25255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
25355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchingsstatic ssize_t efx_mcdi_mon_show_alarm(struct device *dev,
25455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings				       struct device_attribute *attr,
25555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings				       char *buf)
25655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings{
25755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	struct efx_mcdi_mon_attribute *mon_attr =
25855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		container_of(attr, struct efx_mcdi_mon_attribute, dev_attr);
25955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	efx_dword_t entry;
26055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	int state;
26155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	int rc;
26255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
26355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	rc = efx_mcdi_mon_get_entry(dev, mon_attr->index, &entry);
26455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	if (rc)
26555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		return rc;
26655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
26755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	state = EFX_DWORD_FIELD(entry, MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE);
26855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	return sprintf(buf, "%d\n", state != MC_CMD_SENSOR_STATE_OK);
26955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings}
27055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
27155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchingsstatic ssize_t efx_mcdi_mon_show_label(struct device *dev,
27255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings				       struct device_attribute *attr,
27355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings				       char *buf)
27455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings{
27555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	struct efx_mcdi_mon_attribute *mon_attr =
27655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		container_of(attr, struct efx_mcdi_mon_attribute, dev_attr);
27755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	return sprintf(buf, "%s\n",
27855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		       efx_mcdi_sensor_type[mon_attr->type].label);
27955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings}
28055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
28185493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeckstatic void
28255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchingsefx_mcdi_mon_add_attr(struct efx_nic *efx, const char *name,
28355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		      ssize_t (*reader)(struct device *,
28455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings					struct device_attribute *, char *),
28555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		      unsigned int index, unsigned int type,
28655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		      unsigned int limit_value)
28755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings{
28855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	struct efx_mcdi_mon *hwmon = efx_mcdi_mon(efx);
28955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	struct efx_mcdi_mon_attribute *attr = &hwmon->attrs[hwmon->n_attrs];
29055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
29155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	strlcpy(attr->name, name, sizeof(attr->name));
29255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	attr->index = index;
29355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	attr->type = type;
294d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings	if (type < ARRAY_SIZE(efx_mcdi_sensor_type))
295d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings		attr->hwmon_type = efx_mcdi_sensor_type[type].hwmon_type;
296d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings	else
297d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings		attr->hwmon_type = EFX_HWMON_UNKNOWN;
29855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	attr->limit_value = limit_value;
299a9ec6bd1f7bccdc1304629f8fbb2e02035026307Michal Schmidt	sysfs_attr_init(&attr->dev_attr.attr);
30055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	attr->dev_attr.attr.name = attr->name;
30155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	attr->dev_attr.attr.mode = S_IRUGO;
30255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	attr->dev_attr.show = reader;
30385493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck	hwmon->group.attrs[hwmon->n_attrs++] = &attr->dev_attr.attr;
30455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings}
30555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
30655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchingsint efx_mcdi_mon_probe(struct efx_nic *efx)
30755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings{
30838589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings	unsigned int n_temp = 0, n_cool = 0, n_in = 0, n_curr = 0, n_power = 0;
30955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	struct efx_mcdi_mon *hwmon = efx_mcdi_mon(efx);
310d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings	MCDI_DECLARE_BUF(inbuf, MC_CMD_SENSOR_INFO_EXT_IN_LEN);
31159cfc479b2c8ba344c8497d5c913b6cba2ce3755Ben Hutchings	MCDI_DECLARE_BUF(outbuf, MC_CMD_SENSOR_INFO_OUT_LENMAX);
312d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings	unsigned int n_pages, n_sensors, n_attrs, page;
31355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	size_t outlen;
31455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	char name[12];
31555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	u32 mask;
316d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings	int rc, i, j, type;
31755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
318d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings	/* Find out how many sensors are present */
319d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings	n_sensors = 0;
320d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings	page = 0;
321d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings	do {
322d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings		MCDI_SET_DWORD(inbuf, SENSOR_INFO_EXT_IN_PAGE, page);
32355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
324d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings		rc = efx_mcdi_rpc(efx, MC_CMD_SENSOR_INFO, inbuf, sizeof(inbuf),
325d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings				  outbuf, sizeof(outbuf), &outlen);
326d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings		if (rc)
327d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings			return rc;
328d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings		if (outlen < MC_CMD_SENSOR_INFO_OUT_LENMIN)
329d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings			return -EIO;
330d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings
331d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings		mask = MCDI_DWORD(outbuf, SENSOR_INFO_OUT_MASK);
332d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings		n_sensors += hweight32(mask & ~(1 << MC_CMD_SENSOR_PAGE0_NEXT));
333d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings		++page;
334d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings	} while (mask & (1 << MC_CMD_SENSOR_PAGE0_NEXT));
335d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings	n_pages = page;
336d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings
337d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings	/* Don't create a device if there are none */
338d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings	if (n_sensors == 0)
33955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		return 0;
34055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
341d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings	rc = efx_nic_alloc_buffer(
342d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings		efx, &hwmon->dma_buf,
343d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings		n_sensors * MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_LEN,
344d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings		GFP_KERNEL);
34555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	if (rc)
34655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		return rc;
34755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
34855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	mutex_init(&hwmon->update_lock);
34955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	efx_mcdi_mon_update(efx);
35055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
35155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	/* Allocate space for the maximum possible number of
35285493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck	 * attributes for this set of sensors:
35355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	 * value, min, max, crit, alarm and label for each sensor.
35455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	 */
35585493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck	n_attrs = 6 * n_sensors;
35655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	hwmon->attrs = kcalloc(n_attrs, sizeof(*hwmon->attrs), GFP_KERNEL);
35755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	if (!hwmon->attrs) {
35855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		rc = -ENOMEM;
35955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		goto fail;
36055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	}
36185493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck	hwmon->group.attrs = kcalloc(n_attrs + 1, sizeof(struct attribute *),
36285493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck				     GFP_KERNEL);
36385493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck	if (!hwmon->group.attrs) {
36485493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck		rc = -ENOMEM;
36555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		goto fail;
36655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	}
36755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
368d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings	for (i = 0, j = -1, type = -1; ; i++) {
369d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings		enum efx_hwmon_type hwmon_type;
37055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		const char *hwmon_prefix;
37155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		unsigned hwmon_index;
37255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		u16 min1, max1, min2, max2;
37355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
37455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		/* Find next sensor type or exit if there is none */
375d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings		do {
37655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings			type++;
37755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
378d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings			if ((type % 32) == 0) {
379d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings				page = type / 32;
380d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings				j = -1;
381d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings				if (page == n_pages)
38285493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck					goto hwmon_register;
383d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings
384d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings				MCDI_SET_DWORD(inbuf, SENSOR_INFO_EXT_IN_PAGE,
385d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings					       page);
386d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings				rc = efx_mcdi_rpc(efx, MC_CMD_SENSOR_INFO,
387d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings						  inbuf, sizeof(inbuf),
388d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings						  outbuf, sizeof(outbuf),
389d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings						  &outlen);
390d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings				if (rc)
391d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings					goto fail;
392d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings				if (outlen < MC_CMD_SENSOR_INFO_OUT_LENMIN) {
393d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings					rc = -EIO;
394d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings					goto fail;
395d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings				}
396d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings
397d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings				mask = (MCDI_DWORD(outbuf,
398d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings						   SENSOR_INFO_OUT_MASK) &
399d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings					~(1 << MC_CMD_SENSOR_PAGE0_NEXT));
400d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings
401d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings				/* Check again for short response */
402d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings				if (outlen <
403d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings				    MC_CMD_SENSOR_INFO_OUT_LEN(hweight32(mask))) {
404d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings					rc = -EIO;
405d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings					goto fail;
406d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings				}
407d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings			}
408d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings		} while (!(mask & (1 << type % 32)));
409d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings		j++;
410d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings
411d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings		if (type < ARRAY_SIZE(efx_mcdi_sensor_type)) {
412d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings			hwmon_type = efx_mcdi_sensor_type[type].hwmon_type;
413d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings
414d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings			/* Skip sensors specific to a different port */
415d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings			if (hwmon_type != EFX_HWMON_UNKNOWN &&
416d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings			    efx_mcdi_sensor_type[type].port >= 0 &&
417d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings			    efx_mcdi_sensor_type[type].port !=
418d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings			    efx_port_num(efx))
419d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings				continue;
420d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings		} else {
421d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings			hwmon_type = EFX_HWMON_UNKNOWN;
422d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings		}
42355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
424d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings		switch (hwmon_type) {
42555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		case EFX_HWMON_TEMP:
42655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings			hwmon_prefix = "temp";
42755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings			hwmon_index = ++n_temp; /* 1-based */
42855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings			break;
42955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		case EFX_HWMON_COOL:
43055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings			/* This is likely to be a heatsink, but there
43155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings			 * is no convention for representing cooling
43255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings			 * devices other than fans.
43355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings			 */
43455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings			hwmon_prefix = "fan";
43555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings			hwmon_index = ++n_cool; /* 1-based */
43655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings			break;
43755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		default:
43855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings			hwmon_prefix = "in";
43955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings			hwmon_index = n_in++; /* 0-based */
44055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings			break;
44138589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings		case EFX_HWMON_CURR:
44238589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings			hwmon_prefix = "curr";
44338589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings			hwmon_index = ++n_curr; /* 1-based */
44438589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings			break;
44538589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings		case EFX_HWMON_POWER:
44638589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings			hwmon_prefix = "power";
44738589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings			hwmon_index = ++n_power; /* 1-based */
44838589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings			break;
44955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		}
45055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
45155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		min1 = MCDI_ARRAY_FIELD(outbuf, SENSOR_ENTRY,
452d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings					SENSOR_INFO_ENTRY, j, MIN1);
45355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		max1 = MCDI_ARRAY_FIELD(outbuf, SENSOR_ENTRY,
454d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings					SENSOR_INFO_ENTRY, j, MAX1);
45555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		min2 = MCDI_ARRAY_FIELD(outbuf, SENSOR_ENTRY,
456d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings					SENSOR_INFO_ENTRY, j, MIN2);
45755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		max2 = MCDI_ARRAY_FIELD(outbuf, SENSOR_ENTRY,
458d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings					SENSOR_INFO_ENTRY, j, MAX2);
45955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
46055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		if (min1 != max1) {
46155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings			snprintf(name, sizeof(name), "%s%u_input",
46255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings				 hwmon_prefix, hwmon_index);
46385493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck			efx_mcdi_mon_add_attr(
46455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings				efx, name, efx_mcdi_mon_show_value, i, type, 0);
46555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
46638589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings			if (hwmon_type != EFX_HWMON_POWER) {
46738589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings				snprintf(name, sizeof(name), "%s%u_min",
46838589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings					 hwmon_prefix, hwmon_index);
46985493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck				efx_mcdi_mon_add_attr(
47038589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings					efx, name, efx_mcdi_mon_show_limit,
47138589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings					i, type, min1);
47238589cdcd0e77174ca9de9e11ff22e5c3ae95984Ben Hutchings			}
47355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
47455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings			snprintf(name, sizeof(name), "%s%u_max",
47555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings				 hwmon_prefix, hwmon_index);
47685493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck			efx_mcdi_mon_add_attr(
47755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings				efx, name, efx_mcdi_mon_show_limit,
47855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings				i, type, max1);
47955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
48055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings			if (min2 != max2) {
48155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings				/* Assume max2 is critical value.
48255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings				 * But we have no good way to expose min2.
48355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings				 */
48455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings				snprintf(name, sizeof(name), "%s%u_crit",
48555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings					 hwmon_prefix, hwmon_index);
48685493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck				efx_mcdi_mon_add_attr(
48755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings					efx, name, efx_mcdi_mon_show_limit,
48855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings					i, type, max2);
48955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings			}
49055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		}
49155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
49255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		snprintf(name, sizeof(name), "%s%u_alarm",
49355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings			 hwmon_prefix, hwmon_index);
49485493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck		efx_mcdi_mon_add_attr(
49555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings			efx, name, efx_mcdi_mon_show_alarm, i, type, 0);
49655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
497d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings		if (type < ARRAY_SIZE(efx_mcdi_sensor_type) &&
498d4fbdcfe93928fbcb7374ea490e41f7b69d95380Ben Hutchings		    efx_mcdi_sensor_type[type].label) {
49955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings			snprintf(name, sizeof(name), "%s%u_label",
50055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings				 hwmon_prefix, hwmon_index);
50185493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck			efx_mcdi_mon_add_attr(
50255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings				efx, name, efx_mcdi_mon_show_label, i, type, 0);
50355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		}
50455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	}
50555c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
50685493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeckhwmon_register:
50785493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck	hwmon->groups[0] = &hwmon->group;
50885493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck	hwmon->device = hwmon_device_register_with_groups(&efx->pci_dev->dev,
50985493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck							  KBUILD_MODNAME, NULL,
51085493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck							  hwmon->groups);
51185493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck	if (IS_ERR(hwmon->device)) {
51285493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck		rc = PTR_ERR(hwmon->device);
51385493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck		goto fail;
51485493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck	}
51585493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck
51685493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck	return 0;
51785493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck
51855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchingsfail:
51955c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	efx_mcdi_mon_remove(efx);
52055c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	return rc;
52155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings}
52255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
52355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchingsvoid efx_mcdi_mon_remove(struct efx_nic *efx)
52455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings{
525e847b53e9e3c6f7818fe2fcd1082148423020cccBen Hutchings	struct efx_mcdi_mon *hwmon = efx_mcdi_mon(efx);
52655c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
52755c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	if (hwmon->device)
52855c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings		hwmon_device_unregister(hwmon->device);
52985493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck	kfree(hwmon->attrs);
53085493e6dd42dcaf0eaf0a19f12f1295e35cc3b7fGuenter Roeck	kfree(hwmon->group.attrs);
53155c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings	efx_nic_free_buffer(efx, &hwmon->dma_buf);
53255c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings}
53355c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings
53455c5e0f85dc550f03dc8a0b0097da6af3b4865c5Ben Hutchings#endif /* CONFIG_SFC_MCDI_MON */
535