1283514Sarybchik/*-
2301388Sarybchik * Copyright (c) 2009-2016 Solarflare Communications Inc.
3283514Sarybchik * All rights reserved.
4283514Sarybchik *
5283514Sarybchik * Redistribution and use in source and binary forms, with or without
6283514Sarybchik * modification, are permitted provided that the following conditions are met:
7283514Sarybchik *
8283514Sarybchik * 1. Redistributions of source code must retain the above copyright notice,
9283514Sarybchik *    this list of conditions and the following disclaimer.
10283514Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice,
11283514Sarybchik *    this list of conditions and the following disclaimer in the documentation
12283514Sarybchik *    and/or other materials provided with the distribution.
13283514Sarybchik *
14283514Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15283514Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16283514Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17283514Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18283514Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19283514Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20283514Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21283514Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22283514Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23283514Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24283514Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25283514Sarybchik *
26283514Sarybchik * The views and conclusions contained in the software and documentation are
27283514Sarybchik * those of the authors and should not be interpreted as representing official
28283514Sarybchik * policies, either expressed or implied, of the FreeBSD Project.
29283514Sarybchik */
30283514Sarybchik
31283514Sarybchik#include <sys/cdefs.h>
32283514Sarybchik__FBSDID("$FreeBSD: stable/10/sys/dev/sfxge/common/mcdi_mon.c 342516 2018-12-26 10:25:01Z arybchik $");
33283514Sarybchik
34283514Sarybchik#include "efx.h"
35283514Sarybchik#include "efx_impl.h"
36342513Sarybchik#include "mcdi_mon.h"
37283514Sarybchik
38283514Sarybchik#if EFSYS_OPT_MON_MCDI
39283514Sarybchik
40283514Sarybchik#if EFSYS_OPT_MON_STATS
41283514Sarybchik
42311061Sarybchik#define	MCDI_MON_NEXT_PAGE  ((uint16_t)0xfffe)
43311061Sarybchik#define	MCDI_MON_INVALID_SENSOR ((uint16_t)0xfffd)
44283514Sarybchik#define	MCDI_MON_PAGE_SIZE 0x20
45283514Sarybchik
46283514Sarybchik/* Bitmasks of valid port(s) for each sensor */
47283514Sarybchik#define	MCDI_MON_PORT_NONE	(0x00)
48283514Sarybchik#define	MCDI_MON_PORT_P1	(0x01)
49283514Sarybchik#define	MCDI_MON_PORT_P2	(0x02)
50283514Sarybchik#define	MCDI_MON_PORT_P3	(0x04)
51283514Sarybchik#define	MCDI_MON_PORT_P4	(0x08)
52283514Sarybchik#define	MCDI_MON_PORT_Px	(0xFFFF)
53283514Sarybchik
54311082Sarybchik/* Get port mask from one-based MCDI port number */
55311082Sarybchik#define	MCDI_MON_PORT_MASK(_emip) (1U << ((_emip)->emi_port - 1))
56311082Sarybchik
57283514Sarybchik/* Entry for MCDI sensor in sensor map */
58283514Sarybchik#define	STAT(portmask, stat)	\
59283514Sarybchik	{ (MCDI_MON_PORT_##portmask), (EFX_MON_STAT_##stat) }
60283514Sarybchik
61283514Sarybchik/* Entry for sensor next page flag in sensor map */
62283514Sarybchik#define	STAT_NEXT_PAGE()	\
63283514Sarybchik	{ MCDI_MON_PORT_NONE, MCDI_MON_NEXT_PAGE }
64283514Sarybchik
65283514Sarybchik/* Placeholder for gaps in the array */
66283514Sarybchik#define	STAT_NO_SENSOR()	\
67283514Sarybchik	{ MCDI_MON_PORT_NONE, MCDI_MON_INVALID_SENSOR }
68283514Sarybchik
69283514Sarybchik/* Map from MC sensors to monitor statistics */
70283514Sarybchikstatic const struct mcdi_sensor_map_s {
71283514Sarybchik	uint16_t	msm_port_mask;
72283514Sarybchik	uint16_t	msm_stat;
73283514Sarybchik} mcdi_sensor_map[] = {
74283514Sarybchik	/* Sensor page 0		MC_CMD_SENSOR_xxx */
75283514Sarybchik	STAT(Px, INT_TEMP),		/* 0x00 CONTROLLER_TEMP */
76283514Sarybchik	STAT(Px, EXT_TEMP),		/* 0x01 PHY_COMMON_TEMP */
77283514Sarybchik	STAT(Px, INT_COOLING),		/* 0x02 CONTROLLER_COOLING */
78283514Sarybchik	STAT(P1, EXT_TEMP),		/* 0x03 PHY0_TEMP */
79283514Sarybchik	STAT(P1, EXT_COOLING),		/* 0x04 PHY0_COOLING */
80283514Sarybchik	STAT(P2, EXT_TEMP),		/* 0x05 PHY1_TEMP */
81283514Sarybchik	STAT(P2, EXT_COOLING),		/* 0x06 PHY1_COOLING */
82283514Sarybchik	STAT(Px, 1V),			/* 0x07 IN_1V0 */
83283514Sarybchik	STAT(Px, 1_2V),			/* 0x08 IN_1V2 */
84283514Sarybchik	STAT(Px, 1_8V),			/* 0x09 IN_1V8 */
85283514Sarybchik	STAT(Px, 2_5V),			/* 0x0a IN_2V5 */
86283514Sarybchik	STAT(Px, 3_3V),			/* 0x0b IN_3V3 */
87283514Sarybchik	STAT(Px, 12V),			/* 0x0c IN_12V0 */
88283514Sarybchik	STAT(Px, 1_2VA),		/* 0x0d IN_1V2A */
89283514Sarybchik	STAT(Px, VREF),			/* 0x0e IN_VREF */
90283514Sarybchik	STAT(Px, VAOE),			/* 0x0f OUT_VAOE */
91283514Sarybchik	STAT(Px, AOE_TEMP),		/* 0x10 AOE_TEMP */
92283514Sarybchik	STAT(Px, PSU_AOE_TEMP),		/* 0x11 PSU_AOE_TEMP */
93283514Sarybchik	STAT(Px, PSU_TEMP),		/* 0x12 PSU_TEMP */
94283514Sarybchik	STAT(Px, FAN0),			/* 0x13 FAN_0 */
95283514Sarybchik	STAT(Px, FAN1),			/* 0x14 FAN_1 */
96283514Sarybchik	STAT(Px, FAN2),			/* 0x15 FAN_2 */
97283514Sarybchik	STAT(Px, FAN3),			/* 0x16 FAN_3 */
98283514Sarybchik	STAT(Px, FAN4),			/* 0x17 FAN_4 */
99283514Sarybchik	STAT(Px, VAOE_IN),		/* 0x18 IN_VAOE */
100283514Sarybchik	STAT(Px, IAOE),			/* 0x19 OUT_IAOE */
101283514Sarybchik	STAT(Px, IAOE_IN),		/* 0x1a IN_IAOE */
102283514Sarybchik	STAT(Px, NIC_POWER),		/* 0x1b NIC_POWER */
103283514Sarybchik	STAT(Px, 0_9V),			/* 0x1c IN_0V9 */
104283514Sarybchik	STAT(Px, I0_9V),		/* 0x1d IN_I0V9 */
105283514Sarybchik	STAT(Px, I1_2V),		/* 0x1e IN_I1V2 */
106283514Sarybchik	STAT_NEXT_PAGE(),		/* 0x1f Next page flag (not a sensor) */
107283514Sarybchik
108283514Sarybchik	/* Sensor page 1		MC_CMD_SENSOR_xxx */
109283514Sarybchik	STAT(Px, 0_9V_ADC),		/* 0x20 IN_0V9_ADC */
110283514Sarybchik	STAT(Px, INT_TEMP2),		/* 0x21 CONTROLLER_2_TEMP */
111283514Sarybchik	STAT(Px, VREG_TEMP),		/* 0x22 VREG_INTERNAL_TEMP */
112283514Sarybchik	STAT(Px, VREG_0_9V_TEMP),	/* 0x23 VREG_0V9_TEMP */
113283514Sarybchik	STAT(Px, VREG_1_2V_TEMP),	/* 0x24 VREG_1V2_TEMP */
114283514Sarybchik	STAT(Px, INT_VPTAT),		/* 0x25 CTRLR. VPTAT */
115283514Sarybchik	STAT(Px, INT_ADC_TEMP),		/* 0x26 CTRLR. INTERNAL_TEMP */
116283514Sarybchik	STAT(Px, EXT_VPTAT),		/* 0x27 CTRLR. VPTAT_EXTADC */
117283514Sarybchik	STAT(Px, EXT_ADC_TEMP),		/* 0x28 CTRLR. INTERNAL_TEMP_EXTADC */
118283514Sarybchik	STAT(Px, AMBIENT_TEMP),		/* 0x29 AMBIENT_TEMP */
119283514Sarybchik	STAT(Px, AIRFLOW),		/* 0x2a AIRFLOW */
120283514Sarybchik	STAT(Px, VDD08D_VSS08D_CSR),	/* 0x2b VDD08D_VSS08D_CSR */
121283514Sarybchik	STAT(Px, VDD08D_VSS08D_CSR_EXTADC), /* 0x2c VDD08D_VSS08D_CSR_EXTADC */
122283514Sarybchik	STAT(Px, HOTPOINT_TEMP),	/* 0x2d HOTPOINT_TEMP */
123283514Sarybchik	STAT(P1, PHY_POWER_SWITCH_PORT0),   /* 0x2e PHY_POWER_SWITCH_PORT0 */
124283514Sarybchik	STAT(P2, PHY_POWER_SWITCH_PORT1),   /* 0x2f PHY_POWER_SWITCH_PORT1 */
125283514Sarybchik	STAT(Px, MUM_VCC),		/* 0x30 MUM_VCC */
126283514Sarybchik	STAT(Px, 0V9_A),		/* 0x31 0V9_A */
127283514Sarybchik	STAT(Px, I0V9_A),		/* 0x32 I0V9_A */
128283514Sarybchik	STAT(Px, 0V9_A_TEMP),		/* 0x33 0V9_A_TEMP */
129283514Sarybchik	STAT(Px, 0V9_B),		/* 0x34 0V9_B */
130283514Sarybchik	STAT(Px, I0V9_B),		/* 0x35 I0V9_B */
131283514Sarybchik	STAT(Px, 0V9_B_TEMP),		/* 0x36 0V9_B_TEMP */
132283514Sarybchik	STAT(Px, CCOM_AVREG_1V2_SUPPLY),  /* 0x37 CCOM_AVREG_1V2_SUPPLY */
133283514Sarybchik	STAT(Px, CCOM_AVREG_1V2_SUPPLY_EXT_ADC),
134283514Sarybchik					/* 0x38 CCOM_AVREG_1V2_SUPPLY_EXT_ADC */
135283514Sarybchik	STAT(Px, CCOM_AVREG_1V8_SUPPLY),  /* 0x39 CCOM_AVREG_1V8_SUPPLY */
136283514Sarybchik	STAT(Px, CCOM_AVREG_1V8_SUPPLY_EXT_ADC),
137283514Sarybchik					/* 0x3a CCOM_AVREG_1V8_SUPPLY_EXT_ADC */
138283514Sarybchik	STAT_NO_SENSOR(),		/* 0x3b (no sensor) */
139283514Sarybchik	STAT_NO_SENSOR(),		/* 0x3c (no sensor) */
140283514Sarybchik	STAT_NO_SENSOR(),		/* 0x3d (no sensor) */
141283514Sarybchik	STAT_NO_SENSOR(),		/* 0x3e (no sensor) */
142283514Sarybchik	STAT_NEXT_PAGE(),		/* 0x3f Next page flag (not a sensor) */
143283514Sarybchik
144283514Sarybchik	/* Sensor page 2		MC_CMD_SENSOR_xxx */
145283514Sarybchik	STAT(Px, CONTROLLER_MASTER_VPTAT),	   /* 0x40 MASTER_VPTAT */
146283514Sarybchik	STAT(Px, CONTROLLER_MASTER_INTERNAL_TEMP), /* 0x41 MASTER_INT_TEMP */
147283514Sarybchik	STAT(Px, CONTROLLER_MASTER_VPTAT_EXT_ADC), /* 0x42 MAST_VPTAT_EXT_ADC */
148283514Sarybchik	STAT(Px, CONTROLLER_MASTER_INTERNAL_TEMP_EXT_ADC),
149283514Sarybchik					/* 0x43 MASTER_INTERNAL_TEMP_EXT_ADC */
150283514Sarybchik	STAT(Px, CONTROLLER_SLAVE_VPTAT),	  /* 0x44 SLAVE_VPTAT */
151283514Sarybchik	STAT(Px, CONTROLLER_SLAVE_INTERNAL_TEMP), /* 0x45 SLAVE_INTERNAL_TEMP */
152283514Sarybchik	STAT(Px, CONTROLLER_SLAVE_VPTAT_EXT_ADC), /* 0x46 SLAVE_VPTAT_EXT_ADC */
153283514Sarybchik	STAT(Px, CONTROLLER_SLAVE_INTERNAL_TEMP_EXT_ADC),
154283514Sarybchik					/* 0x47 SLAVE_INTERNAL_TEMP_EXT_ADC */
155293994Sarybchik	STAT_NO_SENSOR(),		/* 0x48 (no sensor) */
156293994Sarybchik	STAT(Px, SODIMM_VOUT),		/* 0x49 SODIMM_VOUT */
157293994Sarybchik	STAT(Px, SODIMM_0_TEMP),	/* 0x4a SODIMM_0_TEMP */
158293994Sarybchik	STAT(Px, SODIMM_1_TEMP),	/* 0x4b SODIMM_1_TEMP */
159293994Sarybchik	STAT(Px, PHY0_VCC),		/* 0x4c PHY0_VCC */
160293994Sarybchik	STAT(Px, PHY1_VCC),		/* 0x4d PHY1_VCC */
161293994Sarybchik	STAT(Px, CONTROLLER_TDIODE_TEMP), /* 0x4e CONTROLLER_TDIODE_TEMP */
162311056Sarybchik	STAT(Px, BOARD_FRONT_TEMP),	/* 0x4f BOARD_FRONT_TEMP */
163311056Sarybchik	STAT(Px, BOARD_BACK_TEMP),	/* 0x50 BOARD_BACK_TEMP */
164283514Sarybchik};
165283514Sarybchik
166283514Sarybchik#define	MCDI_STATIC_SENSOR_ASSERT(_field)				\
167283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_SENSOR_STATE_ ## _field		\
168283514Sarybchik			    == EFX_MON_STAT_STATE_ ## _field)
169283514Sarybchik
170283514Sarybchikstatic						void
171283514Sarybchikmcdi_mon_decode_stats(
172283514Sarybchik	__in					efx_nic_t *enp,
173311082Sarybchik	__in_bcount(sensor_mask_size)		uint32_t *sensor_mask,
174283514Sarybchik	__in					size_t sensor_mask_size,
175283514Sarybchik	__in_opt				efsys_mem_t *esmp,
176311082Sarybchik	__out_bcount_opt(sensor_mask_size)	uint32_t *stat_maskp,
177293921Sarybchik	__inout_ecount_opt(EFX_MON_NSTATS)	efx_mon_stat_value_t *stat)
178283514Sarybchik{
179283514Sarybchik	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
180283514Sarybchik	uint16_t port_mask;
181283514Sarybchik	uint16_t sensor;
182283514Sarybchik	size_t sensor_max;
183283514Sarybchik	uint32_t stat_mask[(EFX_ARRAY_SIZE(mcdi_sensor_map) + 31) / 32];
184283514Sarybchik	uint32_t idx = 0;
185283514Sarybchik	uint32_t page = 0;
186283514Sarybchik
187283514Sarybchik	/* Assert the MC_CMD_SENSOR and EFX_MON_STATE namespaces agree */
188283514Sarybchik	MCDI_STATIC_SENSOR_ASSERT(OK);
189283514Sarybchik	MCDI_STATIC_SENSOR_ASSERT(WARNING);
190283514Sarybchik	MCDI_STATIC_SENSOR_ASSERT(FATAL);
191283514Sarybchik	MCDI_STATIC_SENSOR_ASSERT(BROKEN);
192283514Sarybchik	MCDI_STATIC_SENSOR_ASSERT(NO_READING);
193283514Sarybchik
194283514Sarybchik	EFX_STATIC_ASSERT(sizeof (stat_mask[0]) * 8 ==
195283514Sarybchik	    EFX_MON_MASK_ELEMENT_SIZE);
196283514Sarybchik	sensor_max =
197283514Sarybchik	    MIN((8 * sensor_mask_size), EFX_ARRAY_SIZE(mcdi_sensor_map));
198283514Sarybchik
199311082Sarybchik	EFSYS_ASSERT(emip->emi_port > 0); /* MCDI port number is one-based */
200311082Sarybchik	port_mask = MCDI_MON_PORT_MASK(emip);
201283514Sarybchik
202283514Sarybchik	memset(stat_mask, 0, sizeof (stat_mask));
203283514Sarybchik
204283514Sarybchik	/*
205283514Sarybchik	 * The MCDI sensor readings in the DMA buffer are a packed array of
206283514Sarybchik	 * MC_CMD_SENSOR_VALUE_ENTRY structures, which only includes entries for
207283514Sarybchik	 * supported sensors (bit set in sensor_mask). The sensor_mask and
208283514Sarybchik	 * sensor readings do not include entries for the per-page NEXT_PAGE
209283514Sarybchik	 * flag.
210283514Sarybchik	 *
211283514Sarybchik	 * sensor_mask may legitimately contain MCDI sensors that the driver
212283514Sarybchik	 * does not understand.
213283514Sarybchik	 */
214283514Sarybchik	for (sensor = 0; sensor < sensor_max; ++sensor) {
215283514Sarybchik		efx_mon_stat_t id = mcdi_sensor_map[sensor].msm_stat;
216283514Sarybchik
217283514Sarybchik		if ((sensor % MCDI_MON_PAGE_SIZE) == MC_CMD_SENSOR_PAGE0_NEXT) {
218283514Sarybchik			EFSYS_ASSERT3U(id, ==, MCDI_MON_NEXT_PAGE);
219283514Sarybchik			page++;
220283514Sarybchik			continue;
221283514Sarybchik		}
222283514Sarybchik		if (~(sensor_mask[page]) & (1U << sensor))
223283514Sarybchik			continue;
224283514Sarybchik		idx++;
225283514Sarybchik
226283514Sarybchik		if ((port_mask & mcdi_sensor_map[sensor].msm_port_mask) == 0)
227283514Sarybchik			continue;
228283514Sarybchik		EFSYS_ASSERT(id < EFX_MON_NSTATS);
229283514Sarybchik
230283514Sarybchik		/*
231283514Sarybchik		 * stat_mask is a bitmask indexed by EFX_MON_* monitor statistic
232283514Sarybchik		 * identifiers from efx_mon_stat_t (without NEXT_PAGE bits).
233283514Sarybchik		 *
234283514Sarybchik		 * If there is an entry in the MCDI sensor to monitor statistic
235283514Sarybchik		 * map then the sensor reading is used for the value of the
236283514Sarybchik		 * monitor statistic.
237283514Sarybchik		 */
238283514Sarybchik		stat_mask[id / EFX_MON_MASK_ELEMENT_SIZE] |=
239283514Sarybchik		    (1U << (id % EFX_MON_MASK_ELEMENT_SIZE));
240283514Sarybchik
241283514Sarybchik		if (stat != NULL && esmp != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
242283514Sarybchik			efx_dword_t dword;
243283514Sarybchik
244283514Sarybchik			/* Get MCDI sensor reading from DMA buffer */
245283514Sarybchik			EFSYS_MEM_READD(esmp, 4 * (idx - 1), &dword);
246283514Sarybchik
247283514Sarybchik			/* Update EFX monitor stat from MCDI sensor reading */
248283514Sarybchik			stat[id].emsv_value = (uint16_t)EFX_DWORD_FIELD(dword,
249283514Sarybchik			    MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_VALUE);
250283514Sarybchik
251283514Sarybchik			stat[id].emsv_state = (uint16_t)EFX_DWORD_FIELD(dword,
252283514Sarybchik			    MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE);
253283514Sarybchik		}
254283514Sarybchik	}
255283514Sarybchik
256283514Sarybchik	if (stat_maskp != NULL) {
257283514Sarybchik		memcpy(stat_maskp, stat_mask, sizeof (stat_mask));
258283514Sarybchik	}
259283514Sarybchik}
260283514Sarybchik
261293927Sarybchik	__checkReturn			efx_rc_t
262283514Sarybchikmcdi_mon_ev(
263283514Sarybchik	__in				efx_nic_t *enp,
264283514Sarybchik	__in				efx_qword_t *eqp,
265283514Sarybchik	__out				efx_mon_stat_t *idp,
266283514Sarybchik	__out				efx_mon_stat_value_t *valuep)
267283514Sarybchik{
268283514Sarybchik	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
269283514Sarybchik	uint16_t port_mask;
270283514Sarybchik	uint16_t sensor;
271283514Sarybchik	uint16_t state;
272283514Sarybchik	uint16_t value;
273283514Sarybchik	efx_mon_stat_t id;
274293927Sarybchik	efx_rc_t rc;
275283514Sarybchik
276311082Sarybchik	EFSYS_ASSERT(emip->emi_port > 0); /* MCDI port number is one-based */
277311082Sarybchik	port_mask = MCDI_MON_PORT_MASK(emip);
278283514Sarybchik
279283514Sarybchik	sensor = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_MONITOR);
280283514Sarybchik	state = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_STATE);
281283514Sarybchik	value = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_VALUE);
282283514Sarybchik
283283514Sarybchik	/* Hardware must support this MCDI sensor */
284342502Sarybchik	EFSYS_ASSERT3U(sensor, <,
285342502Sarybchik	    (8 * enp->en_nic_cfg.enc_mcdi_sensor_mask_size));
286283514Sarybchik	EFSYS_ASSERT((sensor % MCDI_MON_PAGE_SIZE) != MC_CMD_SENSOR_PAGE0_NEXT);
287342502Sarybchik	EFSYS_ASSERT(enp->en_nic_cfg.enc_mcdi_sensor_maskp != NULL);
288342502Sarybchik	EFSYS_ASSERT(
289342502Sarybchik	    (enp->en_nic_cfg.enc_mcdi_sensor_maskp[sensor/MCDI_MON_PAGE_SIZE] &
290342502Sarybchik	    (1U << (sensor % MCDI_MON_PAGE_SIZE))) != 0);
291283514Sarybchik
292283514Sarybchik	/* But we don't have to understand it */
293283514Sarybchik	if (sensor >= EFX_ARRAY_SIZE(mcdi_sensor_map)) {
294283514Sarybchik		rc = ENOTSUP;
295283514Sarybchik		goto fail1;
296283514Sarybchik	}
297283514Sarybchik	id = mcdi_sensor_map[sensor].msm_stat;
298283514Sarybchik	if ((port_mask & mcdi_sensor_map[sensor].msm_port_mask) == 0)
299283514Sarybchik		return (ENODEV);
300283514Sarybchik	EFSYS_ASSERT(id < EFX_MON_NSTATS);
301283514Sarybchik
302283514Sarybchik	*idp = id;
303283514Sarybchik	valuep->emsv_value = value;
304283514Sarybchik	valuep->emsv_state = state;
305283514Sarybchik
306283514Sarybchik	return (0);
307283514Sarybchik
308283514Sarybchikfail1:
309293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
310283514Sarybchik
311283514Sarybchik	return (rc);
312283514Sarybchik}
313283514Sarybchik
314283514Sarybchik
315293927Sarybchikstatic	__checkReturn	efx_rc_t
316283514Sarybchikefx_mcdi_read_sensors(
317283514Sarybchik	__in		efx_nic_t *enp,
318283514Sarybchik	__in		efsys_mem_t *esmp,
319283514Sarybchik	__in		uint32_t size)
320283514Sarybchik{
321283514Sarybchik	efx_mcdi_req_t req;
322342516Sarybchik	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_READ_SENSORS_EXT_IN_LEN,
323342516Sarybchik		MC_CMD_READ_SENSORS_EXT_OUT_LEN);
324283514Sarybchik	uint32_t addr_lo, addr_hi;
325342514Sarybchik	efx_rc_t rc;
326283514Sarybchik
327342514Sarybchik	if (EFSYS_MEM_SIZE(esmp) < size) {
328342514Sarybchik		rc = EINVAL;
329342514Sarybchik		goto fail1;
330342514Sarybchik	}
331342514Sarybchik
332283514Sarybchik	req.emr_cmd = MC_CMD_READ_SENSORS;
333283514Sarybchik	req.emr_in_buf = payload;
334283514Sarybchik	req.emr_in_length = MC_CMD_READ_SENSORS_EXT_IN_LEN;
335283514Sarybchik	req.emr_out_buf = payload;
336283514Sarybchik	req.emr_out_length = MC_CMD_READ_SENSORS_EXT_OUT_LEN;
337283514Sarybchik
338283514Sarybchik	addr_lo = (uint32_t)(EFSYS_MEM_ADDR(esmp) & 0xffffffff);
339283514Sarybchik	addr_hi = (uint32_t)(EFSYS_MEM_ADDR(esmp) >> 32);
340283514Sarybchik
341283514Sarybchik	MCDI_IN_SET_DWORD(req, READ_SENSORS_EXT_IN_DMA_ADDR_LO, addr_lo);
342283514Sarybchik	MCDI_IN_SET_DWORD(req, READ_SENSORS_EXT_IN_DMA_ADDR_HI, addr_hi);
343283514Sarybchik	MCDI_IN_SET_DWORD(req, READ_SENSORS_EXT_IN_LENGTH, size);
344283514Sarybchik
345283514Sarybchik	efx_mcdi_execute(enp, &req);
346283514Sarybchik
347283514Sarybchik	return (req.emr_rc);
348342514Sarybchik
349342514Sarybchikfail1:
350342514Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
351342514Sarybchik
352342514Sarybchik	return (rc);
353283514Sarybchik}
354283514Sarybchik
355293927Sarybchikstatic	__checkReturn	efx_rc_t
356283514Sarybchikefx_mcdi_sensor_info_npages(
357283514Sarybchik	__in		efx_nic_t *enp,
358283514Sarybchik	__out		uint32_t *npagesp)
359283514Sarybchik{
360283514Sarybchik	efx_mcdi_req_t req;
361342516Sarybchik	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SENSOR_INFO_EXT_IN_LEN,
362342516Sarybchik		MC_CMD_SENSOR_INFO_OUT_LENMAX);
363283514Sarybchik	int page;
364293927Sarybchik	efx_rc_t rc;
365283514Sarybchik
366283514Sarybchik	EFSYS_ASSERT(npagesp != NULL);
367283514Sarybchik
368283514Sarybchik	page = 0;
369283514Sarybchik	do {
370283514Sarybchik		(void) memset(payload, 0, sizeof (payload));
371283514Sarybchik		req.emr_cmd = MC_CMD_SENSOR_INFO;
372283514Sarybchik		req.emr_in_buf = payload;
373283514Sarybchik		req.emr_in_length = MC_CMD_SENSOR_INFO_EXT_IN_LEN;
374283514Sarybchik		req.emr_out_buf = payload;
375283514Sarybchik		req.emr_out_length = MC_CMD_SENSOR_INFO_OUT_LENMAX;
376283514Sarybchik
377283514Sarybchik		MCDI_IN_SET_DWORD(req, SENSOR_INFO_EXT_IN_PAGE, page++);
378283514Sarybchik
379283514Sarybchik		efx_mcdi_execute_quiet(enp, &req);
380283514Sarybchik
381283514Sarybchik		if (req.emr_rc != 0) {
382283514Sarybchik			rc = req.emr_rc;
383283514Sarybchik			goto fail1;
384283514Sarybchik		}
385283514Sarybchik	} while (MCDI_OUT_DWORD(req, SENSOR_INFO_OUT_MASK) &
386301398Sarybchik	    (1U << MC_CMD_SENSOR_PAGE0_NEXT));
387283514Sarybchik
388283514Sarybchik	*npagesp = page;
389283514Sarybchik
390283514Sarybchik	return (0);
391283514Sarybchik
392283514Sarybchikfail1:
393293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
394283514Sarybchik
395283514Sarybchik	return (rc);
396283514Sarybchik}
397283514Sarybchik
398293927Sarybchikstatic	__checkReturn		efx_rc_t
399283514Sarybchikefx_mcdi_sensor_info(
400283514Sarybchik	__in			efx_nic_t *enp,
401283514Sarybchik	__out_ecount(npages)	uint32_t *sensor_maskp,
402283514Sarybchik	__in			size_t npages)
403283514Sarybchik{
404283514Sarybchik	efx_mcdi_req_t req;
405342516Sarybchik	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SENSOR_INFO_EXT_IN_LEN,
406342516Sarybchik		MC_CMD_SENSOR_INFO_OUT_LENMAX);
407283514Sarybchik	uint32_t page;
408293927Sarybchik	efx_rc_t rc;
409283514Sarybchik
410283514Sarybchik	EFSYS_ASSERT(sensor_maskp != NULL);
411283514Sarybchik
412342506Sarybchik	if (npages < 1) {
413342506Sarybchik		rc = EINVAL;
414342506Sarybchik		goto fail1;
415342506Sarybchik	}
416342506Sarybchik
417283514Sarybchik	for (page = 0; page < npages; page++) {
418283514Sarybchik		uint32_t mask;
419283514Sarybchik
420283514Sarybchik		(void) memset(payload, 0, sizeof (payload));
421283514Sarybchik		req.emr_cmd = MC_CMD_SENSOR_INFO;
422283514Sarybchik		req.emr_in_buf = payload;
423283514Sarybchik		req.emr_in_length = MC_CMD_SENSOR_INFO_EXT_IN_LEN;
424283514Sarybchik		req.emr_out_buf = payload;
425283514Sarybchik		req.emr_out_length = MC_CMD_SENSOR_INFO_OUT_LENMAX;
426283514Sarybchik
427283514Sarybchik		MCDI_IN_SET_DWORD(req, SENSOR_INFO_EXT_IN_PAGE, page);
428283514Sarybchik
429283514Sarybchik		efx_mcdi_execute(enp, &req);
430283514Sarybchik
431283514Sarybchik		if (req.emr_rc != 0) {
432283514Sarybchik			rc = req.emr_rc;
433342506Sarybchik			goto fail2;
434283514Sarybchik		}
435283514Sarybchik
436283514Sarybchik		mask = MCDI_OUT_DWORD(req, SENSOR_INFO_OUT_MASK);
437283514Sarybchik
438283514Sarybchik		if ((page != (npages - 1)) &&
439283514Sarybchik		    ((mask & (1U << MC_CMD_SENSOR_PAGE0_NEXT)) == 0)) {
440283514Sarybchik			rc = EINVAL;
441342506Sarybchik			goto fail3;
442283514Sarybchik		}
443283514Sarybchik		sensor_maskp[page] = mask;
444283514Sarybchik	}
445283514Sarybchik
446283514Sarybchik	if (sensor_maskp[npages - 1] & (1U << MC_CMD_SENSOR_PAGE0_NEXT)) {
447283514Sarybchik		rc = EINVAL;
448342506Sarybchik		goto fail4;
449283514Sarybchik	}
450283514Sarybchik
451283514Sarybchik	return (0);
452283514Sarybchik
453342506Sarybchikfail4:
454342506Sarybchik	EFSYS_PROBE(fail4);
455283514Sarybchikfail3:
456283514Sarybchik	EFSYS_PROBE(fail3);
457283514Sarybchikfail2:
458283514Sarybchik	EFSYS_PROBE(fail2);
459283514Sarybchikfail1:
460293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
461283514Sarybchik
462283514Sarybchik	return (rc);
463283514Sarybchik}
464283514Sarybchik
465293927Sarybchik	__checkReturn			efx_rc_t
466283514Sarybchikmcdi_mon_stats_update(
467283514Sarybchik	__in				efx_nic_t *enp,
468283514Sarybchik	__in				efsys_mem_t *esmp,
469293921Sarybchik	__inout_ecount(EFX_MON_NSTATS)	efx_mon_stat_value_t *values)
470283514Sarybchik{
471283514Sarybchik	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
472283514Sarybchik	uint32_t size = encp->enc_mon_stat_dma_buf_size;
473293927Sarybchik	efx_rc_t rc;
474283514Sarybchik
475283514Sarybchik	if ((rc = efx_mcdi_read_sensors(enp, esmp, size)) != 0)
476283514Sarybchik		goto fail1;
477283514Sarybchik
478283514Sarybchik	EFSYS_DMA_SYNC_FOR_KERNEL(esmp, 0, size);
479283514Sarybchik
480283514Sarybchik	mcdi_mon_decode_stats(enp,
481283514Sarybchik	    encp->enc_mcdi_sensor_maskp,
482283514Sarybchik	    encp->enc_mcdi_sensor_mask_size,
483283514Sarybchik	    esmp, NULL, values);
484283514Sarybchik
485283514Sarybchik	return (0);
486283514Sarybchik
487283514Sarybchikfail1:
488293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
489283514Sarybchik
490283514Sarybchik	return (rc);
491283514Sarybchik}
492283514Sarybchik
493293927Sarybchik	__checkReturn	efx_rc_t
494283514Sarybchikmcdi_mon_cfg_build(
495283514Sarybchik	__in		efx_nic_t *enp)
496283514Sarybchik{
497283514Sarybchik	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
498283514Sarybchik	uint32_t npages;
499293927Sarybchik	efx_rc_t rc;
500283514Sarybchik
501283514Sarybchik	switch (enp->en_family) {
502283514Sarybchik#if EFSYS_OPT_SIENA
503283514Sarybchik	case EFX_FAMILY_SIENA:
504283514Sarybchik		encp->enc_mon_type = EFX_MON_SFC90X0;
505283514Sarybchik		break;
506283514Sarybchik#endif
507283514Sarybchik#if EFSYS_OPT_HUNTINGTON
508283514Sarybchik	case EFX_FAMILY_HUNTINGTON:
509283514Sarybchik		encp->enc_mon_type = EFX_MON_SFC91X0;
510283514Sarybchik		break;
511283514Sarybchik#endif
512293978Sarybchik#if EFSYS_OPT_MEDFORD
513293978Sarybchik	case EFX_FAMILY_MEDFORD:
514293978Sarybchik		encp->enc_mon_type = EFX_MON_SFC92X0;
515293978Sarybchik		break;
516293978Sarybchik#endif
517283514Sarybchik	default:
518283514Sarybchik		rc = EINVAL;
519283514Sarybchik		goto fail1;
520283514Sarybchik	}
521283514Sarybchik
522283514Sarybchik	/* Get mc sensor mask size */
523283514Sarybchik	npages = 0;
524283514Sarybchik	if ((rc = efx_mcdi_sensor_info_npages(enp, &npages)) != 0)
525283514Sarybchik		goto fail2;
526283514Sarybchik
527283514Sarybchik	encp->enc_mon_stat_dma_buf_size	= npages * EFX_MON_STATS_PAGE_SIZE;
528283514Sarybchik	encp->enc_mcdi_sensor_mask_size = npages * sizeof (uint32_t);
529283514Sarybchik
530283514Sarybchik	/* Allocate mc sensor mask */
531283514Sarybchik	EFSYS_KMEM_ALLOC(enp->en_esip,
532283514Sarybchik	    encp->enc_mcdi_sensor_mask_size,
533283514Sarybchik	    encp->enc_mcdi_sensor_maskp);
534283514Sarybchik
535283514Sarybchik	if (encp->enc_mcdi_sensor_maskp == NULL) {
536283514Sarybchik		rc = ENOMEM;
537283514Sarybchik		goto fail3;
538283514Sarybchik	}
539283514Sarybchik
540283514Sarybchik	/* Read mc sensor mask */
541283514Sarybchik	if ((rc = efx_mcdi_sensor_info(enp,
542283514Sarybchik		    encp->enc_mcdi_sensor_maskp,
543283514Sarybchik		    npages)) != 0)
544283514Sarybchik		goto fail4;
545283514Sarybchik
546283514Sarybchik	/* Build monitor statistics mask */
547283514Sarybchik	mcdi_mon_decode_stats(enp,
548283514Sarybchik	    encp->enc_mcdi_sensor_maskp,
549283514Sarybchik	    encp->enc_mcdi_sensor_mask_size,
550283514Sarybchik	    NULL, encp->enc_mon_stat_mask, NULL);
551283514Sarybchik
552283514Sarybchik	return (0);
553283514Sarybchik
554283514Sarybchikfail4:
555283514Sarybchik	EFSYS_PROBE(fail4);
556283514Sarybchik	EFSYS_KMEM_FREE(enp->en_esip,
557283514Sarybchik	    encp->enc_mcdi_sensor_mask_size,
558283514Sarybchik	    encp->enc_mcdi_sensor_maskp);
559283514Sarybchik
560283514Sarybchikfail3:
561283514Sarybchik	EFSYS_PROBE(fail3);
562283514Sarybchik
563283514Sarybchikfail2:
564283514Sarybchik	EFSYS_PROBE(fail2);
565283514Sarybchik
566283514Sarybchikfail1:
567293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
568283514Sarybchik
569283514Sarybchik	return (rc);
570283514Sarybchik}
571283514Sarybchik
572283514Sarybchik			void
573283514Sarybchikmcdi_mon_cfg_free(
574283514Sarybchik	__in		efx_nic_t *enp)
575283514Sarybchik{
576283514Sarybchik	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
577283514Sarybchik
578283514Sarybchik	if (encp->enc_mcdi_sensor_maskp != NULL) {
579283514Sarybchik		EFSYS_KMEM_FREE(enp->en_esip,
580283514Sarybchik		    encp->enc_mcdi_sensor_mask_size,
581283514Sarybchik		    encp->enc_mcdi_sensor_maskp);
582283514Sarybchik	}
583283514Sarybchik}
584283514Sarybchik
585283514Sarybchik
586283514Sarybchik#endif	/* EFSYS_OPT_MON_STATS */
587283514Sarybchik
588283514Sarybchik#endif	/* EFSYS_OPT_MON_MCDI */
589