1227569Sphilip/*-
2227569Sphilip * Copyright 2009 Solarflare Communications Inc.  All rights reserved.
3227569Sphilip *
4227569Sphilip * Redistribution and use in source and binary forms, with or without
5227569Sphilip * modification, are permitted provided that the following conditions
6227569Sphilip * are met:
7227569Sphilip * 1. Redistributions of source code must retain the above copyright
8227569Sphilip *    notice, this list of conditions and the following disclaimer.
9227569Sphilip * 2. Redistributions in binary form must reproduce the above copyright
10227569Sphilip *    notice, this list of conditions and the following disclaimer in the
11227569Sphilip *    documentation and/or other materials provided with the distribution.
12227569Sphilip *
13227569Sphilip * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
14227569Sphilip * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15227569Sphilip * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16227569Sphilip * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17227569Sphilip * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18227569Sphilip * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19227569Sphilip * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20227569Sphilip * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21227569Sphilip * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22227569Sphilip * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23227569Sphilip * SUCH DAMAGE.
24227569Sphilip */
25228100Sphilip
26228100Sphilip#include <sys/cdefs.h>
27228100Sphilip__FBSDID("$FreeBSD$");
28228100Sphilip
29227569Sphilip#include "efsys.h"
30227569Sphilip#include "efx.h"
31227569Sphilip#include "efx_impl.h"
32227569Sphilip
33227569Sphilip#if EFSYS_OPT_MON_SIENA
34227569Sphilip
35227569Sphilip	__checkReturn	int
36227569Sphilipsiena_mon_reset(
37227569Sphilip	__in		efx_nic_t *enp)
38227569Sphilip{
39227569Sphilip	_NOTE(ARGUNUSED(enp))
40227569Sphilip	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
41227569Sphilip
42227569Sphilip	return (0);
43227569Sphilip}
44227569Sphilip
45227569Sphilip	__checkReturn	int
46227569Sphilipsiena_mon_reconfigure(
47227569Sphilip	__in		efx_nic_t *enp)
48227569Sphilip{
49227569Sphilip	_NOTE(ARGUNUSED(enp))
50227569Sphilip	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
51227569Sphilip
52227569Sphilip	return (0);
53227569Sphilip}
54227569Sphilip
55227569Sphilip#if EFSYS_OPT_MON_STATS
56227569Sphilip
57227569Sphilip#define	SIENA_MON_WRONG_PORT (uint16_t)0xffff
58227569Sphilip
59227569Sphilipstatic __cs uint16_t __siena_mon_port0_map[] = {
60227569Sphilip	EFX_MON_STAT_INT_TEMP,		/* MC_CMD_SENSOR_CONTROLLER_TEMP */
61227569Sphilip	EFX_MON_STAT_EXT_TEMP,		/* MC_CMD_SENSOR_PHY_COMMON_TEMP */
62227569Sphilip	EFX_MON_STAT_INT_COOLING,	/* MC_CMD_SENSOR_CONTROLLER_COOLING */
63227569Sphilip	EFX_MON_STAT_EXT_TEMP,		/* MC_CMD_SENSOR_PHY0_TEMP */
64227569Sphilip	EFX_MON_STAT_EXT_COOLING,	/* MC_CMD_SENSOR_PHY0_COOLING */
65227569Sphilip	SIENA_MON_WRONG_PORT,		/* MC_CMD_SENSOR_PHY1_TEMP */
66227569Sphilip	SIENA_MON_WRONG_PORT,		/* MC_CMD_SENSOR_PHY1_COOLING */
67227569Sphilip	EFX_MON_STAT_1V,		/* MC_CMD_SENSOR_IN_1V0 */
68227569Sphilip	EFX_MON_STAT_1_2V,		/* MC_CMD_SENSOR_IN_1V2 */
69227569Sphilip	EFX_MON_STAT_1_8V,		/* MC_CMD_SENSOR_IN_1V8 */
70227569Sphilip	EFX_MON_STAT_2_5V,		/* MC_CMD_SENSOR_IN_2V5 */
71227569Sphilip	EFX_MON_STAT_3_3V,		/* MC_CMD_SENSOR_IN_3V3 */
72227569Sphilip	EFX_MON_STAT_12V,		/* MC_CMD_SENSOR_IN_12V0 */
73227569Sphilip};
74227569Sphilip
75227569Sphilipstatic __cs uint16_t __siena_mon_port1_map[] = {
76227569Sphilip	EFX_MON_STAT_INT_TEMP,		/* MC_CMD_SENSOR_CONTROLLER_TEMP */
77227569Sphilip	EFX_MON_STAT_EXT_TEMP,		/* MC_CMD_SENSOR_PHY_COMMON_TEMP */
78227569Sphilip	EFX_MON_STAT_INT_COOLING,	/* MC_CMD_SENSOR_CONTROLLER_COOLING */
79227569Sphilip	SIENA_MON_WRONG_PORT,		/* MC_CMD_SENSOR_PHY0_TEMP */
80227569Sphilip	SIENA_MON_WRONG_PORT,		/* MC_CMD_SENSOR_PHY0_COOLING */
81227569Sphilip	EFX_MON_STAT_EXT_TEMP,		/* MC_CMD_SENSOR_PHY1_TEMP */
82227569Sphilip	EFX_MON_STAT_EXT_COOLING,	/* MC_CMD_SENSOR_PHY1_COOLING */
83227569Sphilip	EFX_MON_STAT_1V,		/* MC_CMD_SENSOR_IN_1V0 */
84227569Sphilip	EFX_MON_STAT_1_2V,		/* MC_CMD_SENSOR_IN_1V2 */
85227569Sphilip	EFX_MON_STAT_1_8V,		/* MC_CMD_SENSOR_IN_1V8 */
86227569Sphilip	EFX_MON_STAT_2_5V,		/* MC_CMD_SENSOR_IN_2V5 */
87227569Sphilip	EFX_MON_STAT_3_3V,		/* MC_CMD_SENSOR_IN_3V3 */
88227569Sphilip	EFX_MON_STAT_12V,		/* MC_CMD_SENSOR_IN_12V0 */
89227569Sphilip};
90227569Sphilip
91227569Sphilip#define	SIENA_STATIC_SENSOR_ASSERT(_field)				\
92227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_SENSOR_STATE_ ## _field		\
93227569Sphilip			    == EFX_MON_STAT_STATE_ ## _field)
94227569Sphilip
95227569Sphilip					void
96227569Sphilipsiena_mon_decode_stats(
97227569Sphilip	__in				efx_nic_t *enp,
98227569Sphilip	__in				uint32_t dmask,
99227569Sphilip	__in_opt			efsys_mem_t *esmp,
100227569Sphilip	__out_opt			uint32_t *vmaskp,
101227569Sphilip	__out_ecount_opt(EFX_MON_NSTATS)	efx_mon_stat_value_t *value)
102227569Sphilip{
103227569Sphilip	efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
104227569Sphilip	uint16_t *sensor_map;
105227569Sphilip	uint16_t mc_sensor;
106227569Sphilip	size_t mc_sensor_max;
107227569Sphilip	uint32_t vmask = 0;
108227569Sphilip
109227569Sphilip	/* Assert the MC_CMD_SENSOR and EFX_MON_STATE namespaces agree */
110227569Sphilip	SIENA_STATIC_SENSOR_ASSERT(OK);
111227569Sphilip	SIENA_STATIC_SENSOR_ASSERT(WARNING);
112227569Sphilip	SIENA_STATIC_SENSOR_ASSERT(FATAL);
113227569Sphilip	SIENA_STATIC_SENSOR_ASSERT(BROKEN);
114227569Sphilip
115227569Sphilip	EFX_STATIC_ASSERT(sizeof (__siena_mon_port1_map)
116227569Sphilip			    == sizeof (__siena_mon_port0_map));
117227569Sphilip	mc_sensor_max = EFX_ARRAY_SIZE(__siena_mon_port0_map);
118227569Sphilip	sensor_map = (emip->emi_port == 1)
119227569Sphilip		? __siena_mon_port0_map
120227569Sphilip		: __siena_mon_port1_map;
121227569Sphilip
122227569Sphilip	/*
123227569Sphilip	 * dmask may legitimately contain sensors not understood by the driver
124227569Sphilip	 */
125227569Sphilip	for (mc_sensor = 0; mc_sensor < mc_sensor_max; ++mc_sensor) {
126227569Sphilip		uint16_t efx_sensor = sensor_map[mc_sensor];
127227569Sphilip
128227569Sphilip		if (efx_sensor == SIENA_MON_WRONG_PORT)
129227569Sphilip			continue;
130227569Sphilip		EFSYS_ASSERT(efx_sensor < EFX_MON_NSTATS);
131227569Sphilip
132227569Sphilip		if (~dmask & (1 << mc_sensor))
133227569Sphilip			continue;
134227569Sphilip
135227569Sphilip		vmask |= (1 << efx_sensor);
136227569Sphilip		if (value != NULL && esmp != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
137227569Sphilip			efx_mon_stat_value_t *emsvp = value + efx_sensor;
138227569Sphilip			efx_dword_t dword;
139227569Sphilip			EFSYS_MEM_READD(esmp, 4 * mc_sensor, &dword);
140227569Sphilip			emsvp->emsv_value =
141227569Sphilip				(uint16_t)EFX_DWORD_FIELD(
142227569Sphilip					dword,
143227569Sphilip					MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_VALUE);
144227569Sphilip			emsvp->emsv_state =
145227569Sphilip				(uint16_t)EFX_DWORD_FIELD(
146227569Sphilip					dword,
147227569Sphilip					MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE);
148227569Sphilip		}
149227569Sphilip	}
150227569Sphilip
151227569Sphilip	if (vmaskp != NULL)
152227569Sphilip		*vmaskp = vmask;
153227569Sphilip}
154227569Sphilip
155227569Sphilip	__checkReturn			int
156227569Sphilipsiena_mon_ev(
157227569Sphilip	__in				efx_nic_t *enp,
158227569Sphilip	__in				efx_qword_t *eqp,
159227569Sphilip	__out				efx_mon_stat_t *idp,
160227569Sphilip	__out				efx_mon_stat_value_t *valuep)
161227569Sphilip{
162227569Sphilip	efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
163227569Sphilip	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
164227569Sphilip	uint16_t ev_monitor;
165227569Sphilip	uint16_t ev_state;
166227569Sphilip	uint16_t ev_value;
167227569Sphilip	uint16_t *sensor_map;
168227569Sphilip	efx_mon_stat_t id;
169227569Sphilip	int rc;
170227569Sphilip
171227569Sphilip	sensor_map = (emip->emi_port == 1)
172227569Sphilip		? __siena_mon_port0_map
173227569Sphilip		: __siena_mon_port1_map;
174227569Sphilip
175227569Sphilip	ev_monitor = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_MONITOR);
176227569Sphilip	ev_state = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_STATE);
177227569Sphilip	ev_value = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_VALUE);
178227569Sphilip
179227569Sphilip	/* Hardware must support this statistic */
180227569Sphilip	EFSYS_ASSERT((1 << ev_monitor) & encp->enc_siena_mon_stat_mask);
181227569Sphilip
182227569Sphilip	/* But we don't have to understand it */
183227569Sphilip	if (ev_monitor >= EFX_ARRAY_SIZE(__siena_mon_port0_map)) {
184227569Sphilip		rc = ENOTSUP;
185227569Sphilip		goto fail1;
186227569Sphilip	}
187227569Sphilip
188227569Sphilip	id = sensor_map[ev_monitor];
189227569Sphilip	if (id == SIENA_MON_WRONG_PORT)
190227569Sphilip		return (ENODEV);
191227569Sphilip	EFSYS_ASSERT(id < EFX_MON_NSTATS);
192227569Sphilip
193227569Sphilip	*idp = id;
194227569Sphilip	valuep->emsv_value = ev_value;
195227569Sphilip	valuep->emsv_state = ev_state;
196227569Sphilip
197227569Sphilip	return (0);
198227569Sphilip
199227569Sphilipfail1:
200227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
201227569Sphilip
202227569Sphilip	return (rc);
203227569Sphilip}
204227569Sphilip
205227569Sphilip	__checkReturn			int
206227569Sphilipsiena_mon_stats_update(
207227569Sphilip	__in				efx_nic_t *enp,
208227569Sphilip	__in				efsys_mem_t *esmp,
209227569Sphilip	__out_ecount(EFX_MON_NSTATS)	efx_mon_stat_value_t *values)
210227569Sphilip{
211227569Sphilip	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
212227569Sphilip	uint32_t dmask = encp->enc_siena_mon_stat_mask;
213227569Sphilip	uint32_t vmask;
214227569Sphilip	uint8_t payload[MC_CMD_READ_SENSORS_IN_LEN];
215227569Sphilip	efx_mcdi_req_t req;
216227569Sphilip	int rc;
217227569Sphilip
218227569Sphilip	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
219227569Sphilip
220227569Sphilip	req.emr_cmd = MC_CMD_READ_SENSORS;
221227569Sphilip	req.emr_in_buf = payload;
222227569Sphilip	req.emr_in_length = sizeof (payload);
223227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_READ_SENSORS_OUT_LEN == 0);
224227569Sphilip	req.emr_out_buf = NULL;
225227569Sphilip	req.emr_out_length = 0;
226227569Sphilip
227227569Sphilip	MCDI_IN_SET_DWORD(req, READ_SENSORS_IN_DMA_ADDR_LO,
228227569Sphilip			    EFSYS_MEM_ADDR(esmp) & 0xffffffff);
229227569Sphilip	MCDI_IN_SET_DWORD(req, READ_SENSORS_IN_DMA_ADDR_HI,
230227569Sphilip			    EFSYS_MEM_ADDR(esmp) >> 32);
231227569Sphilip
232227569Sphilip	efx_mcdi_execute(enp, &req);
233227569Sphilip
234227569Sphilip	if (req.emr_rc != 0) {
235227569Sphilip		rc = req.emr_rc;
236227569Sphilip		goto fail1;
237227569Sphilip	}
238227569Sphilip
239227569Sphilip	siena_mon_decode_stats(enp, dmask, esmp, &vmask, values);
240227569Sphilip	EFSYS_ASSERT(vmask == encp->enc_mon_stat_mask);
241227569Sphilip
242227569Sphilip	return (0);
243227569Sphilip
244227569Sphilipfail1:
245227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
246227569Sphilip
247227569Sphilip	return (rc);
248227569Sphilip}
249227569Sphilip
250227569Sphilip#endif	/* EFSYS_OPT_MON_STATS */
251227569Sphilip
252227569Sphilip#endif	/* EFSYS_OPT_MON_SIENA */
253