xref: /freebsd-src/sys/dev/sfxge/common/mcdi_mon.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
13c838a9fSAndrew Rybchenko /*-
2929c7febSAndrew Rybchenko  * Copyright (c) 2009-2016 Solarflare Communications Inc.
33c838a9fSAndrew Rybchenko  * All rights reserved.
43c838a9fSAndrew Rybchenko  *
53c838a9fSAndrew Rybchenko  * Redistribution and use in source and binary forms, with or without
63c838a9fSAndrew Rybchenko  * modification, are permitted provided that the following conditions are met:
73c838a9fSAndrew Rybchenko  *
83c838a9fSAndrew Rybchenko  * 1. Redistributions of source code must retain the above copyright notice,
93c838a9fSAndrew Rybchenko  *    this list of conditions and the following disclaimer.
103c838a9fSAndrew Rybchenko  * 2. Redistributions in binary form must reproduce the above copyright notice,
113c838a9fSAndrew Rybchenko  *    this list of conditions and the following disclaimer in the documentation
123c838a9fSAndrew Rybchenko  *    and/or other materials provided with the distribution.
133c838a9fSAndrew Rybchenko  *
143c838a9fSAndrew Rybchenko  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
153c838a9fSAndrew Rybchenko  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
163c838a9fSAndrew Rybchenko  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
173c838a9fSAndrew Rybchenko  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
183c838a9fSAndrew Rybchenko  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
193c838a9fSAndrew Rybchenko  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
203c838a9fSAndrew Rybchenko  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
213c838a9fSAndrew Rybchenko  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
223c838a9fSAndrew Rybchenko  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
233c838a9fSAndrew Rybchenko  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
243c838a9fSAndrew Rybchenko  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
253c838a9fSAndrew Rybchenko  *
263c838a9fSAndrew Rybchenko  * The views and conclusions contained in the software and documentation are
273c838a9fSAndrew Rybchenko  * those of the authors and should not be interpreted as representing official
283c838a9fSAndrew Rybchenko  * policies, either expressed or implied, of the FreeBSD Project.
293c838a9fSAndrew Rybchenko  */
303c838a9fSAndrew Rybchenko 
313c838a9fSAndrew Rybchenko #include <sys/cdefs.h>
323c838a9fSAndrew Rybchenko #include "efx.h"
333c838a9fSAndrew Rybchenko #include "efx_impl.h"
34b288270eSAndrew Rybchenko #include "mcdi_mon.h"
353c838a9fSAndrew Rybchenko 
363c838a9fSAndrew Rybchenko #if EFSYS_OPT_MON_MCDI
373c838a9fSAndrew Rybchenko 
383c838a9fSAndrew Rybchenko #if EFSYS_OPT_MON_STATS
393c838a9fSAndrew Rybchenko 
40b5a84969SAndrew Rybchenko /* Get port mask from one-based MCDI port number */
41b5a84969SAndrew Rybchenko #define	MCDI_MON_PORT_MASK(_emip) (1U << ((_emip)->emi_port - 1))
42b5a84969SAndrew Rybchenko 
433c838a9fSAndrew Rybchenko #define	MCDI_STATIC_SENSOR_ASSERT(_field)				\
443c838a9fSAndrew Rybchenko 	EFX_STATIC_ASSERT(MC_CMD_SENSOR_STATE_ ## _field		\
453c838a9fSAndrew Rybchenko 			    == EFX_MON_STAT_STATE_ ## _field)
463c838a9fSAndrew Rybchenko 
473c838a9fSAndrew Rybchenko static						void
mcdi_mon_decode_stats(__in efx_nic_t * enp,__in_bcount (sensor_mask_size)uint32_t * sensor_mask,__in size_t sensor_mask_size,__in_opt efsys_mem_t * esmp,__out_bcount_opt (sensor_mask_size)uint32_t * stat_maskp,__inout_ecount_opt (EFX_MON_NSTATS)efx_mon_stat_value_t * stat)483c838a9fSAndrew Rybchenko mcdi_mon_decode_stats(
493c838a9fSAndrew Rybchenko 	__in					efx_nic_t *enp,
50b5a84969SAndrew Rybchenko 	__in_bcount(sensor_mask_size)		uint32_t *sensor_mask,
513c838a9fSAndrew Rybchenko 	__in					size_t sensor_mask_size,
523c838a9fSAndrew Rybchenko 	__in_opt				efsys_mem_t *esmp,
53b5a84969SAndrew Rybchenko 	__out_bcount_opt(sensor_mask_size)	uint32_t *stat_maskp,
54536c03c2SAndrew Rybchenko 	__inout_ecount_opt(EFX_MON_NSTATS)	efx_mon_stat_value_t *stat)
553c838a9fSAndrew Rybchenko {
563c838a9fSAndrew Rybchenko 	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
5721b72677SAndrew Rybchenko 	efx_mon_stat_portmask_t port_mask;
583c838a9fSAndrew Rybchenko 	uint16_t sensor;
593c838a9fSAndrew Rybchenko 	size_t sensor_max;
6021b72677SAndrew Rybchenko 	uint32_t stat_mask[(EFX_MON_NSTATS + 31) / 32];
613c838a9fSAndrew Rybchenko 	uint32_t idx = 0;
623c838a9fSAndrew Rybchenko 	uint32_t page = 0;
633c838a9fSAndrew Rybchenko 
643c838a9fSAndrew Rybchenko 	/* Assert the MC_CMD_SENSOR and EFX_MON_STATE namespaces agree */
653c838a9fSAndrew Rybchenko 	MCDI_STATIC_SENSOR_ASSERT(OK);
663c838a9fSAndrew Rybchenko 	MCDI_STATIC_SENSOR_ASSERT(WARNING);
673c838a9fSAndrew Rybchenko 	MCDI_STATIC_SENSOR_ASSERT(FATAL);
683c838a9fSAndrew Rybchenko 	MCDI_STATIC_SENSOR_ASSERT(BROKEN);
693c838a9fSAndrew Rybchenko 	MCDI_STATIC_SENSOR_ASSERT(NO_READING);
703c838a9fSAndrew Rybchenko 
7121b72677SAndrew Rybchenko 	sensor_max = 8 * sensor_mask_size;
723c838a9fSAndrew Rybchenko 
73b5a84969SAndrew Rybchenko 	EFSYS_ASSERT(emip->emi_port > 0); /* MCDI port number is one-based */
7421b72677SAndrew Rybchenko 	port_mask = (efx_mon_stat_portmask_t)MCDI_MON_PORT_MASK(emip);
753c838a9fSAndrew Rybchenko 
763c838a9fSAndrew Rybchenko 	memset(stat_mask, 0, sizeof (stat_mask));
773c838a9fSAndrew Rybchenko 
783c838a9fSAndrew Rybchenko 	/*
793c838a9fSAndrew Rybchenko 	 * The MCDI sensor readings in the DMA buffer are a packed array of
803c838a9fSAndrew Rybchenko 	 * MC_CMD_SENSOR_VALUE_ENTRY structures, which only includes entries for
813c838a9fSAndrew Rybchenko 	 * supported sensors (bit set in sensor_mask). The sensor_mask and
823c838a9fSAndrew Rybchenko 	 * sensor readings do not include entries for the per-page NEXT_PAGE
833c838a9fSAndrew Rybchenko 	 * flag.
843c838a9fSAndrew Rybchenko 	 *
853c838a9fSAndrew Rybchenko 	 * sensor_mask may legitimately contain MCDI sensors that the driver
863c838a9fSAndrew Rybchenko 	 * does not understand.
873c838a9fSAndrew Rybchenko 	 */
883c838a9fSAndrew Rybchenko 	for (sensor = 0; sensor < sensor_max; ++sensor) {
8921b72677SAndrew Rybchenko 		efx_mon_stat_t id;
9021b72677SAndrew Rybchenko 		efx_mon_stat_portmask_t stat_portmask = 0;
9121b72677SAndrew Rybchenko 		boolean_t decode_ok;
9221b72677SAndrew Rybchenko 		efx_mon_stat_unit_t stat_unit;
933c838a9fSAndrew Rybchenko 
9421b72677SAndrew Rybchenko 		if ((sensor % (MC_CMD_SENSOR_PAGE0_NEXT + 1)) ==
9521b72677SAndrew Rybchenko 		    MC_CMD_SENSOR_PAGE0_NEXT) {
963c838a9fSAndrew Rybchenko 			page++;
973c838a9fSAndrew Rybchenko 			continue;
9821b72677SAndrew Rybchenko 			/* This sensor is one of the page boundary bits. */
993c838a9fSAndrew Rybchenko 		}
10021b72677SAndrew Rybchenko 
1013c838a9fSAndrew Rybchenko 		if (~(sensor_mask[page]) & (1U << sensor))
1023c838a9fSAndrew Rybchenko 			continue;
10321b72677SAndrew Rybchenko 		/* This sensor not in DMA buffer */
1043c838a9fSAndrew Rybchenko 
10521b72677SAndrew Rybchenko 		idx++;
10621b72677SAndrew Rybchenko 		/*
10721b72677SAndrew Rybchenko 		 * Valid stat in DMA buffer that we need to increment over, even
10821b72677SAndrew Rybchenko 		 * if we couldn't look up the id
10921b72677SAndrew Rybchenko 		 */
11021b72677SAndrew Rybchenko 
11121b72677SAndrew Rybchenko 		decode_ok = efx_mon_mcdi_to_efx_stat(sensor, &id);
11221b72677SAndrew Rybchenko 		decode_ok =
11321b72677SAndrew Rybchenko 		    decode_ok && efx_mon_get_stat_portmap(id, &stat_portmask);
11421b72677SAndrew Rybchenko 
11521b72677SAndrew Rybchenko 		if (!(decode_ok && (stat_portmask & port_mask)))
1163c838a9fSAndrew Rybchenko 			continue;
11721b72677SAndrew Rybchenko 		/* Either bad decode, or don't know what port stat is on */
11821b72677SAndrew Rybchenko 
1193c838a9fSAndrew Rybchenko 		EFSYS_ASSERT(id < EFX_MON_NSTATS);
1203c838a9fSAndrew Rybchenko 
1213c838a9fSAndrew Rybchenko 		/*
1223c838a9fSAndrew Rybchenko 		 * stat_mask is a bitmask indexed by EFX_MON_* monitor statistic
1233c838a9fSAndrew Rybchenko 		 * identifiers from efx_mon_stat_t (without NEXT_PAGE bits).
1243c838a9fSAndrew Rybchenko 		 *
1253c838a9fSAndrew Rybchenko 		 * If there is an entry in the MCDI sensor to monitor statistic
1263c838a9fSAndrew Rybchenko 		 * map then the sensor reading is used for the value of the
1273c838a9fSAndrew Rybchenko 		 * monitor statistic.
1283c838a9fSAndrew Rybchenko 		 */
1293c838a9fSAndrew Rybchenko 		stat_mask[id / EFX_MON_MASK_ELEMENT_SIZE] |=
1303c838a9fSAndrew Rybchenko 		    (1U << (id % EFX_MON_MASK_ELEMENT_SIZE));
1313c838a9fSAndrew Rybchenko 
1323c838a9fSAndrew Rybchenko 		if (stat != NULL && esmp != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
1333c838a9fSAndrew Rybchenko 			efx_dword_t dword;
1343c838a9fSAndrew Rybchenko 
1353c838a9fSAndrew Rybchenko 			/* Get MCDI sensor reading from DMA buffer */
1363c838a9fSAndrew Rybchenko 			EFSYS_MEM_READD(esmp, 4 * (idx - 1), &dword);
1373c838a9fSAndrew Rybchenko 
1383c838a9fSAndrew Rybchenko 			/* Update EFX monitor stat from MCDI sensor reading */
1393c838a9fSAndrew Rybchenko 			stat[id].emsv_value = (uint16_t)EFX_DWORD_FIELD(dword,
1403c838a9fSAndrew Rybchenko 			    MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_VALUE);
1413c838a9fSAndrew Rybchenko 
1423c838a9fSAndrew Rybchenko 			stat[id].emsv_state = (uint16_t)EFX_DWORD_FIELD(dword,
1433c838a9fSAndrew Rybchenko 			    MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE);
14421b72677SAndrew Rybchenko 
14521b72677SAndrew Rybchenko 			stat[id].emsv_unit =
14621b72677SAndrew Rybchenko 			    efx_mon_get_stat_unit(id, &stat_unit) ?
14721b72677SAndrew Rybchenko 			    stat_unit : EFX_MON_STAT_UNIT_UNKNOWN;
1483c838a9fSAndrew Rybchenko 		}
1493c838a9fSAndrew Rybchenko 	}
1503c838a9fSAndrew Rybchenko 
1513c838a9fSAndrew Rybchenko 	if (stat_maskp != NULL) {
1523c838a9fSAndrew Rybchenko 		memcpy(stat_maskp, stat_mask, sizeof (stat_mask));
1533c838a9fSAndrew Rybchenko 	}
1543c838a9fSAndrew Rybchenko }
1553c838a9fSAndrew Rybchenko 
156460cb568SAndrew Rybchenko 	__checkReturn			efx_rc_t
mcdi_mon_ev(__in efx_nic_t * enp,__in efx_qword_t * eqp,__out efx_mon_stat_t * idp,__out efx_mon_stat_value_t * valuep)1573c838a9fSAndrew Rybchenko mcdi_mon_ev(
1583c838a9fSAndrew Rybchenko 	__in				efx_nic_t *enp,
1593c838a9fSAndrew Rybchenko 	__in				efx_qword_t *eqp,
1603c838a9fSAndrew Rybchenko 	__out				efx_mon_stat_t *idp,
1613c838a9fSAndrew Rybchenko 	__out				efx_mon_stat_value_t *valuep)
1623c838a9fSAndrew Rybchenko {
1633c838a9fSAndrew Rybchenko 	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
16421b72677SAndrew Rybchenko 	efx_mon_stat_portmask_t port_mask, sensor_port_mask;
1653c838a9fSAndrew Rybchenko 	uint16_t sensor;
1663c838a9fSAndrew Rybchenko 	uint16_t state;
1673c838a9fSAndrew Rybchenko 	uint16_t value;
1683c838a9fSAndrew Rybchenko 	efx_mon_stat_t id;
169460cb568SAndrew Rybchenko 	efx_rc_t rc;
1703c838a9fSAndrew Rybchenko 
171b5a84969SAndrew Rybchenko 	EFSYS_ASSERT(emip->emi_port > 0); /* MCDI port number is one-based */
172b5a84969SAndrew Rybchenko 	port_mask = MCDI_MON_PORT_MASK(emip);
1733c838a9fSAndrew Rybchenko 
1743c838a9fSAndrew Rybchenko 	sensor = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_MONITOR);
1753c838a9fSAndrew Rybchenko 	state = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_STATE);
1763c838a9fSAndrew Rybchenko 	value = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_VALUE);
1773c838a9fSAndrew Rybchenko 
1783c838a9fSAndrew Rybchenko 	/* Hardware must support this MCDI sensor */
179cc8d2b23SAndrew Rybchenko 	EFSYS_ASSERT3U(sensor, <,
180cc8d2b23SAndrew Rybchenko 	    (8 * enp->en_nic_cfg.enc_mcdi_sensor_mask_size));
18121b72677SAndrew Rybchenko 	EFSYS_ASSERT((sensor % (MC_CMD_SENSOR_PAGE0_NEXT + 1)) !=
18221b72677SAndrew Rybchenko 	    MC_CMD_SENSOR_PAGE0_NEXT);
183cc8d2b23SAndrew Rybchenko 	EFSYS_ASSERT(enp->en_nic_cfg.enc_mcdi_sensor_maskp != NULL);
18421b72677SAndrew Rybchenko 	EFSYS_ASSERT((enp->en_nic_cfg.enc_mcdi_sensor_maskp[
18521b72677SAndrew Rybchenko 		    sensor / (MC_CMD_SENSOR_PAGE0_NEXT + 1)] &
18621b72677SAndrew Rybchenko 		(1U << (sensor % (MC_CMD_SENSOR_PAGE0_NEXT + 1)))) != 0);
1873c838a9fSAndrew Rybchenko 
18821b72677SAndrew Rybchenko 	/* And we need to understand it, to get port-map */
18921b72677SAndrew Rybchenko 	if (!efx_mon_mcdi_to_efx_stat(sensor, &id)) {
1903c838a9fSAndrew Rybchenko 		rc = ENOTSUP;
1913c838a9fSAndrew Rybchenko 		goto fail1;
1923c838a9fSAndrew Rybchenko 	}
19321b72677SAndrew Rybchenko 	if (!(efx_mon_get_stat_portmap(id, &sensor_port_mask) &&
19421b72677SAndrew Rybchenko 		(port_mask && sensor_port_mask))) {
1953c838a9fSAndrew Rybchenko 		return (ENODEV);
19621b72677SAndrew Rybchenko 	}
1973c838a9fSAndrew Rybchenko 	EFSYS_ASSERT(id < EFX_MON_NSTATS);
1983c838a9fSAndrew Rybchenko 
1993c838a9fSAndrew Rybchenko 	*idp = id;
2003c838a9fSAndrew Rybchenko 	valuep->emsv_value = value;
2013c838a9fSAndrew Rybchenko 	valuep->emsv_state = state;
2023c838a9fSAndrew Rybchenko 
2033c838a9fSAndrew Rybchenko 	return (0);
2043c838a9fSAndrew Rybchenko 
2053c838a9fSAndrew Rybchenko fail1:
206460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2073c838a9fSAndrew Rybchenko 
2083c838a9fSAndrew Rybchenko 	return (rc);
2093c838a9fSAndrew Rybchenko }
2103c838a9fSAndrew Rybchenko 
211460cb568SAndrew Rybchenko static	__checkReturn	efx_rc_t
efx_mcdi_read_sensors(__in efx_nic_t * enp,__in efsys_mem_t * esmp,__in uint32_t size)2123c838a9fSAndrew Rybchenko efx_mcdi_read_sensors(
2133c838a9fSAndrew Rybchenko 	__in		efx_nic_t *enp,
2143c838a9fSAndrew Rybchenko 	__in		efsys_mem_t *esmp,
2153c838a9fSAndrew Rybchenko 	__in		uint32_t size)
2163c838a9fSAndrew Rybchenko {
2173c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
218*315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_READ_SENSORS_EXT_IN_LEN,
219*315bbbaaSAndrew Rybchenko 		MC_CMD_READ_SENSORS_EXT_OUT_LEN);
2203c838a9fSAndrew Rybchenko 	uint32_t addr_lo, addr_hi;
2219d3487a6SAndrew Rybchenko 	efx_rc_t rc;
2229d3487a6SAndrew Rybchenko 
2239d3487a6SAndrew Rybchenko 	if (EFSYS_MEM_SIZE(esmp) < size) {
2249d3487a6SAndrew Rybchenko 		rc = EINVAL;
2259d3487a6SAndrew Rybchenko 		goto fail1;
2269d3487a6SAndrew Rybchenko 	}
2273c838a9fSAndrew Rybchenko 
2283c838a9fSAndrew Rybchenko 	req.emr_cmd = MC_CMD_READ_SENSORS;
2293c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
2303c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_READ_SENSORS_EXT_IN_LEN;
2313c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
2323c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_READ_SENSORS_EXT_OUT_LEN;
2333c838a9fSAndrew Rybchenko 
2343c838a9fSAndrew Rybchenko 	addr_lo = (uint32_t)(EFSYS_MEM_ADDR(esmp) & 0xffffffff);
2353c838a9fSAndrew Rybchenko 	addr_hi = (uint32_t)(EFSYS_MEM_ADDR(esmp) >> 32);
2363c838a9fSAndrew Rybchenko 
2373c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, READ_SENSORS_EXT_IN_DMA_ADDR_LO, addr_lo);
2383c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, READ_SENSORS_EXT_IN_DMA_ADDR_HI, addr_hi);
2393c838a9fSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, READ_SENSORS_EXT_IN_LENGTH, size);
2403c838a9fSAndrew Rybchenko 
2413c838a9fSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
2423c838a9fSAndrew Rybchenko 
2433c838a9fSAndrew Rybchenko 	return (req.emr_rc);
2449d3487a6SAndrew Rybchenko 
2459d3487a6SAndrew Rybchenko fail1:
2469d3487a6SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2479d3487a6SAndrew Rybchenko 
2489d3487a6SAndrew Rybchenko 	return (rc);
2493c838a9fSAndrew Rybchenko }
2503c838a9fSAndrew Rybchenko 
251460cb568SAndrew Rybchenko static	__checkReturn	efx_rc_t
efx_mcdi_sensor_info_npages(__in efx_nic_t * enp,__out uint32_t * npagesp)2523c838a9fSAndrew Rybchenko efx_mcdi_sensor_info_npages(
2533c838a9fSAndrew Rybchenko 	__in		efx_nic_t *enp,
2543c838a9fSAndrew Rybchenko 	__out		uint32_t *npagesp)
2553c838a9fSAndrew Rybchenko {
2563c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
257*315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SENSOR_INFO_EXT_IN_LEN,
258*315bbbaaSAndrew Rybchenko 		MC_CMD_SENSOR_INFO_OUT_LENMAX);
2593c838a9fSAndrew Rybchenko 	int page;
260460cb568SAndrew Rybchenko 	efx_rc_t rc;
2613c838a9fSAndrew Rybchenko 
2623c838a9fSAndrew Rybchenko 	EFSYS_ASSERT(npagesp != NULL);
2633c838a9fSAndrew Rybchenko 
2643c838a9fSAndrew Rybchenko 	page = 0;
2653c838a9fSAndrew Rybchenko 	do {
2663c838a9fSAndrew Rybchenko 		(void) memset(payload, 0, sizeof (payload));
2673c838a9fSAndrew Rybchenko 		req.emr_cmd = MC_CMD_SENSOR_INFO;
2683c838a9fSAndrew Rybchenko 		req.emr_in_buf = payload;
2693c838a9fSAndrew Rybchenko 		req.emr_in_length = MC_CMD_SENSOR_INFO_EXT_IN_LEN;
2703c838a9fSAndrew Rybchenko 		req.emr_out_buf = payload;
2713c838a9fSAndrew Rybchenko 		req.emr_out_length = MC_CMD_SENSOR_INFO_OUT_LENMAX;
2723c838a9fSAndrew Rybchenko 
2733c838a9fSAndrew Rybchenko 		MCDI_IN_SET_DWORD(req, SENSOR_INFO_EXT_IN_PAGE, page++);
2743c838a9fSAndrew Rybchenko 
2753c838a9fSAndrew Rybchenko 		efx_mcdi_execute_quiet(enp, &req);
2763c838a9fSAndrew Rybchenko 
2773c838a9fSAndrew Rybchenko 		if (req.emr_rc != 0) {
2783c838a9fSAndrew Rybchenko 			rc = req.emr_rc;
2793c838a9fSAndrew Rybchenko 			goto fail1;
2803c838a9fSAndrew Rybchenko 		}
2813c838a9fSAndrew Rybchenko 	} while (MCDI_OUT_DWORD(req, SENSOR_INFO_OUT_MASK) &
2822ceb37acSAndrew Rybchenko 	    (1U << MC_CMD_SENSOR_PAGE0_NEXT));
2833c838a9fSAndrew Rybchenko 
2843c838a9fSAndrew Rybchenko 	*npagesp = page;
2853c838a9fSAndrew Rybchenko 
2863c838a9fSAndrew Rybchenko 	return (0);
2873c838a9fSAndrew Rybchenko 
2883c838a9fSAndrew Rybchenko fail1:
289460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2903c838a9fSAndrew Rybchenko 
2913c838a9fSAndrew Rybchenko 	return (rc);
2923c838a9fSAndrew Rybchenko }
2933c838a9fSAndrew Rybchenko 
294460cb568SAndrew Rybchenko static	__checkReturn		efx_rc_t
efx_mcdi_sensor_info(__in efx_nic_t * enp,__out_ecount (npages)uint32_t * sensor_maskp,__in size_t npages)2953c838a9fSAndrew Rybchenko efx_mcdi_sensor_info(
2963c838a9fSAndrew Rybchenko 	__in			efx_nic_t *enp,
2973c838a9fSAndrew Rybchenko 	__out_ecount(npages)	uint32_t *sensor_maskp,
2983c838a9fSAndrew Rybchenko 	__in			size_t npages)
2993c838a9fSAndrew Rybchenko {
3003c838a9fSAndrew Rybchenko 	efx_mcdi_req_t req;
301*315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SENSOR_INFO_EXT_IN_LEN,
302*315bbbaaSAndrew Rybchenko 		MC_CMD_SENSOR_INFO_OUT_LENMAX);
3033c838a9fSAndrew Rybchenko 	uint32_t page;
304460cb568SAndrew Rybchenko 	efx_rc_t rc;
3053c838a9fSAndrew Rybchenko 
3063c838a9fSAndrew Rybchenko 	EFSYS_ASSERT(sensor_maskp != NULL);
3073c838a9fSAndrew Rybchenko 
3089a3efb21SAndrew Rybchenko 	if (npages < 1) {
3099a3efb21SAndrew Rybchenko 		rc = EINVAL;
3109a3efb21SAndrew Rybchenko 		goto fail1;
3119a3efb21SAndrew Rybchenko 	}
3129a3efb21SAndrew Rybchenko 
3133c838a9fSAndrew Rybchenko 	for (page = 0; page < npages; page++) {
3143c838a9fSAndrew Rybchenko 		uint32_t mask;
3153c838a9fSAndrew Rybchenko 
3163c838a9fSAndrew Rybchenko 		(void) memset(payload, 0, sizeof (payload));
3173c838a9fSAndrew Rybchenko 		req.emr_cmd = MC_CMD_SENSOR_INFO;
3183c838a9fSAndrew Rybchenko 		req.emr_in_buf = payload;
3193c838a9fSAndrew Rybchenko 		req.emr_in_length = MC_CMD_SENSOR_INFO_EXT_IN_LEN;
3203c838a9fSAndrew Rybchenko 		req.emr_out_buf = payload;
3213c838a9fSAndrew Rybchenko 		req.emr_out_length = MC_CMD_SENSOR_INFO_OUT_LENMAX;
3223c838a9fSAndrew Rybchenko 
3233c838a9fSAndrew Rybchenko 		MCDI_IN_SET_DWORD(req, SENSOR_INFO_EXT_IN_PAGE, page);
3243c838a9fSAndrew Rybchenko 
3253c838a9fSAndrew Rybchenko 		efx_mcdi_execute(enp, &req);
3263c838a9fSAndrew Rybchenko 
3273c838a9fSAndrew Rybchenko 		if (req.emr_rc != 0) {
3283c838a9fSAndrew Rybchenko 			rc = req.emr_rc;
3299a3efb21SAndrew Rybchenko 			goto fail2;
3303c838a9fSAndrew Rybchenko 		}
3313c838a9fSAndrew Rybchenko 
3323c838a9fSAndrew Rybchenko 		mask = MCDI_OUT_DWORD(req, SENSOR_INFO_OUT_MASK);
3333c838a9fSAndrew Rybchenko 
3343c838a9fSAndrew Rybchenko 		if ((page != (npages - 1)) &&
3353c838a9fSAndrew Rybchenko 		    ((mask & (1U << MC_CMD_SENSOR_PAGE0_NEXT)) == 0)) {
3363c838a9fSAndrew Rybchenko 			rc = EINVAL;
3379a3efb21SAndrew Rybchenko 			goto fail3;
3383c838a9fSAndrew Rybchenko 		}
3393c838a9fSAndrew Rybchenko 		sensor_maskp[page] = mask;
3403c838a9fSAndrew Rybchenko 	}
3413c838a9fSAndrew Rybchenko 
3423c838a9fSAndrew Rybchenko 	if (sensor_maskp[npages - 1] & (1U << MC_CMD_SENSOR_PAGE0_NEXT)) {
3433c838a9fSAndrew Rybchenko 		rc = EINVAL;
3449a3efb21SAndrew Rybchenko 		goto fail4;
3453c838a9fSAndrew Rybchenko 	}
3463c838a9fSAndrew Rybchenko 
3473c838a9fSAndrew Rybchenko 	return (0);
3483c838a9fSAndrew Rybchenko 
3499a3efb21SAndrew Rybchenko fail4:
3509a3efb21SAndrew Rybchenko 	EFSYS_PROBE(fail4);
3513c838a9fSAndrew Rybchenko fail3:
3523c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail3);
3533c838a9fSAndrew Rybchenko fail2:
3543c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
3553c838a9fSAndrew Rybchenko fail1:
356460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
3573c838a9fSAndrew Rybchenko 
3583c838a9fSAndrew Rybchenko 	return (rc);
3593c838a9fSAndrew Rybchenko }
3603c838a9fSAndrew Rybchenko 
361b4d3f02eSAndrew Rybchenko static	__checkReturn		efx_rc_t
362b4d3f02eSAndrew Rybchenko efx_mcdi_sensor_info_page(
363b4d3f02eSAndrew Rybchenko 	__in			efx_nic_t *enp,
364b4d3f02eSAndrew Rybchenko 	__in			uint32_t page,
365b4d3f02eSAndrew Rybchenko 	__out			uint32_t *mask_part,
366b4d3f02eSAndrew Rybchenko 	__out_ecount((sizeof (*mask_part) * 8) - 1)
367b4d3f02eSAndrew Rybchenko 				efx_mon_stat_limits_t *limits)
368b4d3f02eSAndrew Rybchenko {
369b4d3f02eSAndrew Rybchenko 	efx_mcdi_req_t req;
370*315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SENSOR_INFO_EXT_IN_LEN,
371*315bbbaaSAndrew Rybchenko 		MC_CMD_SENSOR_INFO_OUT_LENMAX);
372b4d3f02eSAndrew Rybchenko 	efx_rc_t rc;
373b4d3f02eSAndrew Rybchenko 	uint32_t mask_copy;
374b4d3f02eSAndrew Rybchenko 	efx_dword_t *maskp;
375b4d3f02eSAndrew Rybchenko 	efx_qword_t *limit_info;
376b4d3f02eSAndrew Rybchenko 
377b4d3f02eSAndrew Rybchenko 	EFSYS_ASSERT(mask_part != NULL);
378b4d3f02eSAndrew Rybchenko 	EFSYS_ASSERT(limits != NULL);
379b4d3f02eSAndrew Rybchenko 
380b4d3f02eSAndrew Rybchenko 	memset(limits, 0,
381b4d3f02eSAndrew Rybchenko 	    ((sizeof (*mask_part) * 8) - 1) * sizeof (efx_mon_stat_limits_t));
382b4d3f02eSAndrew Rybchenko 
383b4d3f02eSAndrew Rybchenko 	req.emr_cmd = MC_CMD_SENSOR_INFO;
384b4d3f02eSAndrew Rybchenko 	req.emr_in_buf = payload;
385b4d3f02eSAndrew Rybchenko 	req.emr_in_length = MC_CMD_SENSOR_INFO_EXT_IN_LEN;
386b4d3f02eSAndrew Rybchenko 	req.emr_out_buf = payload;
387b4d3f02eSAndrew Rybchenko 	req.emr_out_length = MC_CMD_SENSOR_INFO_OUT_LENMAX;
388b4d3f02eSAndrew Rybchenko 
389b4d3f02eSAndrew Rybchenko 	MCDI_IN_SET_DWORD(req, SENSOR_INFO_EXT_IN_PAGE, page);
390b4d3f02eSAndrew Rybchenko 
391b4d3f02eSAndrew Rybchenko 	efx_mcdi_execute(enp, &req);
392b4d3f02eSAndrew Rybchenko 
393b4d3f02eSAndrew Rybchenko 	rc = req.emr_rc;
394b4d3f02eSAndrew Rybchenko 
395b4d3f02eSAndrew Rybchenko 	if (rc != 0)
396b4d3f02eSAndrew Rybchenko 		goto fail1;
397b4d3f02eSAndrew Rybchenko 
398b4d3f02eSAndrew Rybchenko 	EFSYS_ASSERT(sizeof (*limit_info) ==
399b4d3f02eSAndrew Rybchenko 	    MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_LEN);
400b4d3f02eSAndrew Rybchenko 	maskp = MCDI_OUT2(req, efx_dword_t, SENSOR_INFO_OUT_MASK);
401b4d3f02eSAndrew Rybchenko 	limit_info = (efx_qword_t *)(maskp + 1);
402b4d3f02eSAndrew Rybchenko 
403b4d3f02eSAndrew Rybchenko 	*mask_part = maskp->ed_u32[0];
404b4d3f02eSAndrew Rybchenko 	mask_copy = *mask_part;
405b4d3f02eSAndrew Rybchenko 
406b4d3f02eSAndrew Rybchenko 	/* Copy an entry for all but the highest bit set. */
407b4d3f02eSAndrew Rybchenko 	while (mask_copy) {
408b4d3f02eSAndrew Rybchenko 		if (mask_copy == (1U << MC_CMD_SENSOR_PAGE0_NEXT)) {
409b4d3f02eSAndrew Rybchenko 			/* Only next page bit set. */
410b4d3f02eSAndrew Rybchenko 			mask_copy = 0;
411b4d3f02eSAndrew Rybchenko 		} else {
412b4d3f02eSAndrew Rybchenko 			/* Clear lowest bit */
413b4d3f02eSAndrew Rybchenko 			mask_copy = mask_copy & ~(mask_copy ^ (mask_copy - 1));
414b4d3f02eSAndrew Rybchenko 			/* And copy out limit entry into buffer */
415b4d3f02eSAndrew Rybchenko 			limits->emlv_warning_min = EFX_QWORD_FIELD(*limit_info,
416b4d3f02eSAndrew Rybchenko 			    MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_MIN1);
417b4d3f02eSAndrew Rybchenko 
418b4d3f02eSAndrew Rybchenko 			limits->emlv_warning_max = EFX_QWORD_FIELD(*limit_info,
419b4d3f02eSAndrew Rybchenko 			    MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_MAX1);
420b4d3f02eSAndrew Rybchenko 
421b4d3f02eSAndrew Rybchenko 			limits->emlv_fatal_min = EFX_QWORD_FIELD(*limit_info,
422b4d3f02eSAndrew Rybchenko 			    MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_MIN2);
423b4d3f02eSAndrew Rybchenko 
424b4d3f02eSAndrew Rybchenko 			limits->emlv_fatal_max = EFX_QWORD_FIELD(*limit_info,
425b4d3f02eSAndrew Rybchenko 			    MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_MAX2);
426b4d3f02eSAndrew Rybchenko 
427b4d3f02eSAndrew Rybchenko 			limits++;
428b4d3f02eSAndrew Rybchenko 			limit_info++;
429b4d3f02eSAndrew Rybchenko 		}
430b4d3f02eSAndrew Rybchenko 	}
431b4d3f02eSAndrew Rybchenko 
432b4d3f02eSAndrew Rybchenko 	return (rc);
433b4d3f02eSAndrew Rybchenko 
434b4d3f02eSAndrew Rybchenko fail1:
435b4d3f02eSAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
436b4d3f02eSAndrew Rybchenko 
437b4d3f02eSAndrew Rybchenko 	return (rc);
438b4d3f02eSAndrew Rybchenko }
439b4d3f02eSAndrew Rybchenko 
440460cb568SAndrew Rybchenko 	__checkReturn			efx_rc_t
mcdi_mon_stats_update(__in efx_nic_t * enp,__in efsys_mem_t * esmp,__inout_ecount (EFX_MON_NSTATS)efx_mon_stat_value_t * values)4413c838a9fSAndrew Rybchenko mcdi_mon_stats_update(
4423c838a9fSAndrew Rybchenko 	__in				efx_nic_t *enp,
4433c838a9fSAndrew Rybchenko 	__in				efsys_mem_t *esmp,
444536c03c2SAndrew Rybchenko 	__inout_ecount(EFX_MON_NSTATS)	efx_mon_stat_value_t *values)
4453c838a9fSAndrew Rybchenko {
4463c838a9fSAndrew Rybchenko 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
4473c838a9fSAndrew Rybchenko 	uint32_t size = encp->enc_mon_stat_dma_buf_size;
448460cb568SAndrew Rybchenko 	efx_rc_t rc;
4493c838a9fSAndrew Rybchenko 
4503c838a9fSAndrew Rybchenko 	if ((rc = efx_mcdi_read_sensors(enp, esmp, size)) != 0)
4513c838a9fSAndrew Rybchenko 		goto fail1;
4523c838a9fSAndrew Rybchenko 
4533c838a9fSAndrew Rybchenko 	EFSYS_DMA_SYNC_FOR_KERNEL(esmp, 0, size);
4543c838a9fSAndrew Rybchenko 
4553c838a9fSAndrew Rybchenko 	mcdi_mon_decode_stats(enp,
4563c838a9fSAndrew Rybchenko 	    encp->enc_mcdi_sensor_maskp,
4573c838a9fSAndrew Rybchenko 	    encp->enc_mcdi_sensor_mask_size,
4583c838a9fSAndrew Rybchenko 	    esmp, NULL, values);
4593c838a9fSAndrew Rybchenko 
4603c838a9fSAndrew Rybchenko 	return (0);
4613c838a9fSAndrew Rybchenko 
4623c838a9fSAndrew Rybchenko fail1:
463460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
4643c838a9fSAndrew Rybchenko 
4653c838a9fSAndrew Rybchenko 	return (rc);
4663c838a9fSAndrew Rybchenko }
4673c838a9fSAndrew Rybchenko 
468b4d3f02eSAndrew Rybchenko static		void
lowest_set_bit(__in uint32_t input_mask,__out uint32_t * lowest_bit_mask,__out uint32_t * lowest_bit_num)469b4d3f02eSAndrew Rybchenko lowest_set_bit(
470b4d3f02eSAndrew Rybchenko 	__in	uint32_t input_mask,
471b4d3f02eSAndrew Rybchenko 	__out	uint32_t *lowest_bit_mask,
472b4d3f02eSAndrew Rybchenko 	__out	uint32_t *lowest_bit_num
473b4d3f02eSAndrew Rybchenko )
474b4d3f02eSAndrew Rybchenko {
475b4d3f02eSAndrew Rybchenko 	uint32_t x;
476b4d3f02eSAndrew Rybchenko 	uint32_t set_bit, bit_index;
477b4d3f02eSAndrew Rybchenko 
478b4d3f02eSAndrew Rybchenko 	x = (input_mask ^ (input_mask - 1));
479b4d3f02eSAndrew Rybchenko 	set_bit = (x + 1) >> 1;
480b4d3f02eSAndrew Rybchenko 	if (!set_bit)
481b4d3f02eSAndrew Rybchenko 		set_bit = (1U << 31U);
482b4d3f02eSAndrew Rybchenko 
483b4d3f02eSAndrew Rybchenko 	bit_index = 0;
484b4d3f02eSAndrew Rybchenko 	if (set_bit & 0xFFFF0000)
485b4d3f02eSAndrew Rybchenko 		bit_index += 16;
486b4d3f02eSAndrew Rybchenko 	if (set_bit & 0xFF00FF00)
487b4d3f02eSAndrew Rybchenko 		bit_index += 8;
488b4d3f02eSAndrew Rybchenko 	if (set_bit & 0xF0F0F0F0)
489b4d3f02eSAndrew Rybchenko 		bit_index += 4;
490b4d3f02eSAndrew Rybchenko 	if (set_bit & 0xCCCCCCCC)
491b4d3f02eSAndrew Rybchenko 		bit_index += 2;
492b4d3f02eSAndrew Rybchenko 	if (set_bit & 0xAAAAAAAA)
493b4d3f02eSAndrew Rybchenko 		bit_index += 1;
494b4d3f02eSAndrew Rybchenko 
495b4d3f02eSAndrew Rybchenko 	*lowest_bit_mask = set_bit;
496b4d3f02eSAndrew Rybchenko 	*lowest_bit_num = bit_index;
497b4d3f02eSAndrew Rybchenko }
498b4d3f02eSAndrew Rybchenko 
499b4d3f02eSAndrew Rybchenko 	__checkReturn			efx_rc_t
mcdi_mon_limits_update(__in efx_nic_t * enp,__inout_ecount (EFX_MON_NSTATS)efx_mon_stat_limits_t * values)500b4d3f02eSAndrew Rybchenko mcdi_mon_limits_update(
501b4d3f02eSAndrew Rybchenko 	__in				efx_nic_t *enp,
502b4d3f02eSAndrew Rybchenko 	__inout_ecount(EFX_MON_NSTATS)	efx_mon_stat_limits_t *values)
503b4d3f02eSAndrew Rybchenko {
504b4d3f02eSAndrew Rybchenko 	efx_rc_t rc;
505b4d3f02eSAndrew Rybchenko 	uint32_t page;
506b4d3f02eSAndrew Rybchenko 	uint32_t page_mask;
507b4d3f02eSAndrew Rybchenko 	uint32_t limit_index;
508b4d3f02eSAndrew Rybchenko 	efx_mon_stat_limits_t limits[sizeof (page_mask) * 8];
509b4d3f02eSAndrew Rybchenko 	efx_mon_stat_t stat;
510b4d3f02eSAndrew Rybchenko 
511b4d3f02eSAndrew Rybchenko 	page = 0;
512b4d3f02eSAndrew Rybchenko 	page--;
513b4d3f02eSAndrew Rybchenko 	do {
514b4d3f02eSAndrew Rybchenko 		page++;
515b4d3f02eSAndrew Rybchenko 
516b4d3f02eSAndrew Rybchenko 		rc = efx_mcdi_sensor_info_page(enp, page, &page_mask, limits);
517b4d3f02eSAndrew Rybchenko 		if (rc != 0)
518b4d3f02eSAndrew Rybchenko 			goto fail1;
519b4d3f02eSAndrew Rybchenko 
520b4d3f02eSAndrew Rybchenko 		limit_index = 0;
521b4d3f02eSAndrew Rybchenko 		while (page_mask) {
522b4d3f02eSAndrew Rybchenko 			uint32_t set_bit;
523b4d3f02eSAndrew Rybchenko 			uint32_t page_index;
524b4d3f02eSAndrew Rybchenko 			uint32_t mcdi_index;
525b4d3f02eSAndrew Rybchenko 
526b4d3f02eSAndrew Rybchenko 			if (page_mask == (1U << MC_CMD_SENSOR_PAGE0_NEXT))
527b4d3f02eSAndrew Rybchenko 				break;
528b4d3f02eSAndrew Rybchenko 
529b4d3f02eSAndrew Rybchenko 			lowest_set_bit(page_mask, &set_bit, &page_index);
530b4d3f02eSAndrew Rybchenko 			page_mask = page_mask & ~set_bit;
531b4d3f02eSAndrew Rybchenko 
532b4d3f02eSAndrew Rybchenko 			mcdi_index =
533b4d3f02eSAndrew Rybchenko 			    page_index + (sizeof (page_mask) * 8 * page);
534b4d3f02eSAndrew Rybchenko 
535b4d3f02eSAndrew Rybchenko 			/*
536b4d3f02eSAndrew Rybchenko 			 * This can fail if MCDI reports newer stats than the
537b4d3f02eSAndrew Rybchenko 			 * drivers understand, or the bit is the next page bit.
538b4d3f02eSAndrew Rybchenko 			 *
539b4d3f02eSAndrew Rybchenko 			 * Driver needs to be tolerant of this.
540b4d3f02eSAndrew Rybchenko 			 */
541b4d3f02eSAndrew Rybchenko 			if (!efx_mon_mcdi_to_efx_stat(mcdi_index, &stat))
542b4d3f02eSAndrew Rybchenko 				continue;
543b4d3f02eSAndrew Rybchenko 
544b4d3f02eSAndrew Rybchenko 			values[stat] = limits[limit_index];
545b4d3f02eSAndrew Rybchenko 			limit_index++;
546b4d3f02eSAndrew Rybchenko 		}
547b4d3f02eSAndrew Rybchenko 
548b4d3f02eSAndrew Rybchenko 	} while (page_mask & (1U << MC_CMD_SENSOR_PAGE0_NEXT));
549b4d3f02eSAndrew Rybchenko 
550b4d3f02eSAndrew Rybchenko 	return (rc);
551b4d3f02eSAndrew Rybchenko 
552b4d3f02eSAndrew Rybchenko fail1:
553b4d3f02eSAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
554b4d3f02eSAndrew Rybchenko 
555b4d3f02eSAndrew Rybchenko 	return (rc);
556b4d3f02eSAndrew Rybchenko }
557b4d3f02eSAndrew Rybchenko 
558460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
mcdi_mon_cfg_build(__in efx_nic_t * enp)5593c838a9fSAndrew Rybchenko mcdi_mon_cfg_build(
5603c838a9fSAndrew Rybchenko 	__in		efx_nic_t *enp)
5613c838a9fSAndrew Rybchenko {
5623c838a9fSAndrew Rybchenko 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
5633c838a9fSAndrew Rybchenko 	uint32_t npages;
564460cb568SAndrew Rybchenko 	efx_rc_t rc;
5653c838a9fSAndrew Rybchenko 
5663c838a9fSAndrew Rybchenko 	switch (enp->en_family) {
5673c838a9fSAndrew Rybchenko #if EFSYS_OPT_SIENA
5683c838a9fSAndrew Rybchenko 	case EFX_FAMILY_SIENA:
5693c838a9fSAndrew Rybchenko 		encp->enc_mon_type = EFX_MON_SFC90X0;
5703c838a9fSAndrew Rybchenko 		break;
5713c838a9fSAndrew Rybchenko #endif
5723c838a9fSAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON
5733c838a9fSAndrew Rybchenko 	case EFX_FAMILY_HUNTINGTON:
5743c838a9fSAndrew Rybchenko 		encp->enc_mon_type = EFX_MON_SFC91X0;
5753c838a9fSAndrew Rybchenko 		break;
5763c838a9fSAndrew Rybchenko #endif
577b13ad4deSAndrew Rybchenko #if EFSYS_OPT_MEDFORD
578b13ad4deSAndrew Rybchenko 	case EFX_FAMILY_MEDFORD:
579b13ad4deSAndrew Rybchenko 		encp->enc_mon_type = EFX_MON_SFC92X0;
580b13ad4deSAndrew Rybchenko 		break;
581b13ad4deSAndrew Rybchenko #endif
582bbefcb4cSAndrew Rybchenko #if EFSYS_OPT_MEDFORD2
583bbefcb4cSAndrew Rybchenko 	case EFX_FAMILY_MEDFORD2:
584bbefcb4cSAndrew Rybchenko 		encp->enc_mon_type = EFX_MON_SFC92X0;
585bbefcb4cSAndrew Rybchenko 		break;
586bbefcb4cSAndrew Rybchenko #endif
5873c838a9fSAndrew Rybchenko 	default:
5883c838a9fSAndrew Rybchenko 		rc = EINVAL;
5893c838a9fSAndrew Rybchenko 		goto fail1;
5903c838a9fSAndrew Rybchenko 	}
5913c838a9fSAndrew Rybchenko 
5923c838a9fSAndrew Rybchenko 	/* Get mc sensor mask size */
5933c838a9fSAndrew Rybchenko 	npages = 0;
5943c838a9fSAndrew Rybchenko 	if ((rc = efx_mcdi_sensor_info_npages(enp, &npages)) != 0)
5953c838a9fSAndrew Rybchenko 		goto fail2;
5963c838a9fSAndrew Rybchenko 
5973c838a9fSAndrew Rybchenko 	encp->enc_mon_stat_dma_buf_size	= npages * EFX_MON_STATS_PAGE_SIZE;
5983c838a9fSAndrew Rybchenko 	encp->enc_mcdi_sensor_mask_size = npages * sizeof (uint32_t);
5993c838a9fSAndrew Rybchenko 
6003c838a9fSAndrew Rybchenko 	/* Allocate mc sensor mask */
6013c838a9fSAndrew Rybchenko 	EFSYS_KMEM_ALLOC(enp->en_esip,
6023c838a9fSAndrew Rybchenko 	    encp->enc_mcdi_sensor_mask_size,
6033c838a9fSAndrew Rybchenko 	    encp->enc_mcdi_sensor_maskp);
6043c838a9fSAndrew Rybchenko 
6053c838a9fSAndrew Rybchenko 	if (encp->enc_mcdi_sensor_maskp == NULL) {
6063c838a9fSAndrew Rybchenko 		rc = ENOMEM;
6073c838a9fSAndrew Rybchenko 		goto fail3;
6083c838a9fSAndrew Rybchenko 	}
6093c838a9fSAndrew Rybchenko 
6103c838a9fSAndrew Rybchenko 	/* Read mc sensor mask */
6113c838a9fSAndrew Rybchenko 	if ((rc = efx_mcdi_sensor_info(enp,
6123c838a9fSAndrew Rybchenko 		    encp->enc_mcdi_sensor_maskp,
6133c838a9fSAndrew Rybchenko 		    npages)) != 0)
6143c838a9fSAndrew Rybchenko 		goto fail4;
6153c838a9fSAndrew Rybchenko 
6163c838a9fSAndrew Rybchenko 	/* Build monitor statistics mask */
6173c838a9fSAndrew Rybchenko 	mcdi_mon_decode_stats(enp,
6183c838a9fSAndrew Rybchenko 	    encp->enc_mcdi_sensor_maskp,
6193c838a9fSAndrew Rybchenko 	    encp->enc_mcdi_sensor_mask_size,
6203c838a9fSAndrew Rybchenko 	    NULL, encp->enc_mon_stat_mask, NULL);
6213c838a9fSAndrew Rybchenko 
6223c838a9fSAndrew Rybchenko 	return (0);
6233c838a9fSAndrew Rybchenko 
6243c838a9fSAndrew Rybchenko fail4:
6253c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail4);
6263c838a9fSAndrew Rybchenko 	EFSYS_KMEM_FREE(enp->en_esip,
6273c838a9fSAndrew Rybchenko 	    encp->enc_mcdi_sensor_mask_size,
6283c838a9fSAndrew Rybchenko 	    encp->enc_mcdi_sensor_maskp);
6293c838a9fSAndrew Rybchenko 
6303c838a9fSAndrew Rybchenko fail3:
6313c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail3);
6323c838a9fSAndrew Rybchenko 
6333c838a9fSAndrew Rybchenko fail2:
6343c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
6353c838a9fSAndrew Rybchenko 
6363c838a9fSAndrew Rybchenko fail1:
637460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
6383c838a9fSAndrew Rybchenko 
6393c838a9fSAndrew Rybchenko 	return (rc);
6403c838a9fSAndrew Rybchenko }
6413c838a9fSAndrew Rybchenko 
6423c838a9fSAndrew Rybchenko 			void
mcdi_mon_cfg_free(__in efx_nic_t * enp)6433c838a9fSAndrew Rybchenko mcdi_mon_cfg_free(
6443c838a9fSAndrew Rybchenko 	__in		efx_nic_t *enp)
6453c838a9fSAndrew Rybchenko {
6463c838a9fSAndrew Rybchenko 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
6473c838a9fSAndrew Rybchenko 
6483c838a9fSAndrew Rybchenko 	if (encp->enc_mcdi_sensor_maskp != NULL) {
6493c838a9fSAndrew Rybchenko 		EFSYS_KMEM_FREE(enp->en_esip,
6503c838a9fSAndrew Rybchenko 		    encp->enc_mcdi_sensor_mask_size,
6513c838a9fSAndrew Rybchenko 		    encp->enc_mcdi_sensor_maskp);
6523c838a9fSAndrew Rybchenko 	}
6533c838a9fSAndrew Rybchenko }
6543c838a9fSAndrew Rybchenko 
6553c838a9fSAndrew Rybchenko #endif	/* EFSYS_OPT_MON_STATS */
6563c838a9fSAndrew Rybchenko 
6573c838a9fSAndrew Rybchenko #endif	/* EFSYS_OPT_MON_MCDI */
658