1/*-
2 * Copyright 2009 Solarflare Communications Inc.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25#include "efsys.h"
26#include "efx.h"
27#include "efx_impl.h"
28
29#if EFSYS_OPT_MON_SIENA
30
31	__checkReturn	int
32siena_mon_reset(
33	__in		efx_nic_t *enp)
34{
35	_NOTE(ARGUNUSED(enp))
36	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
37
38	return (0);
39}
40
41	__checkReturn	int
42siena_mon_reconfigure(
43	__in		efx_nic_t *enp)
44{
45	_NOTE(ARGUNUSED(enp))
46	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
47
48	return (0);
49}
50
51#if EFSYS_OPT_MON_STATS
52
53#define	SIENA_MON_WRONG_PORT (uint16_t)0xffff
54
55static __cs uint16_t __siena_mon_port0_map[] = {
56	EFX_MON_STAT_INT_TEMP,		/* MC_CMD_SENSOR_CONTROLLER_TEMP */
57	EFX_MON_STAT_EXT_TEMP,		/* MC_CMD_SENSOR_PHY_COMMON_TEMP */
58	EFX_MON_STAT_INT_COOLING,	/* MC_CMD_SENSOR_CONTROLLER_COOLING */
59	EFX_MON_STAT_EXT_TEMP,		/* MC_CMD_SENSOR_PHY0_TEMP */
60	EFX_MON_STAT_EXT_COOLING,	/* MC_CMD_SENSOR_PHY0_COOLING */
61	SIENA_MON_WRONG_PORT,		/* MC_CMD_SENSOR_PHY1_TEMP */
62	SIENA_MON_WRONG_PORT,		/* MC_CMD_SENSOR_PHY1_COOLING */
63	EFX_MON_STAT_1V,		/* MC_CMD_SENSOR_IN_1V0 */
64	EFX_MON_STAT_1_2V,		/* MC_CMD_SENSOR_IN_1V2 */
65	EFX_MON_STAT_1_8V,		/* MC_CMD_SENSOR_IN_1V8 */
66	EFX_MON_STAT_2_5V,		/* MC_CMD_SENSOR_IN_2V5 */
67	EFX_MON_STAT_3_3V,		/* MC_CMD_SENSOR_IN_3V3 */
68	EFX_MON_STAT_12V,		/* MC_CMD_SENSOR_IN_12V0 */
69};
70
71static __cs uint16_t __siena_mon_port1_map[] = {
72	EFX_MON_STAT_INT_TEMP,		/* MC_CMD_SENSOR_CONTROLLER_TEMP */
73	EFX_MON_STAT_EXT_TEMP,		/* MC_CMD_SENSOR_PHY_COMMON_TEMP */
74	EFX_MON_STAT_INT_COOLING,	/* MC_CMD_SENSOR_CONTROLLER_COOLING */
75	SIENA_MON_WRONG_PORT,		/* MC_CMD_SENSOR_PHY0_TEMP */
76	SIENA_MON_WRONG_PORT,		/* MC_CMD_SENSOR_PHY0_COOLING */
77	EFX_MON_STAT_EXT_TEMP,		/* MC_CMD_SENSOR_PHY1_TEMP */
78	EFX_MON_STAT_EXT_COOLING,	/* MC_CMD_SENSOR_PHY1_COOLING */
79	EFX_MON_STAT_1V,		/* MC_CMD_SENSOR_IN_1V0 */
80	EFX_MON_STAT_1_2V,		/* MC_CMD_SENSOR_IN_1V2 */
81	EFX_MON_STAT_1_8V,		/* MC_CMD_SENSOR_IN_1V8 */
82	EFX_MON_STAT_2_5V,		/* MC_CMD_SENSOR_IN_2V5 */
83	EFX_MON_STAT_3_3V,		/* MC_CMD_SENSOR_IN_3V3 */
84	EFX_MON_STAT_12V,		/* MC_CMD_SENSOR_IN_12V0 */
85};
86
87#define	SIENA_STATIC_SENSOR_ASSERT(_field)				\
88	EFX_STATIC_ASSERT(MC_CMD_SENSOR_STATE_ ## _field		\
89			    == EFX_MON_STAT_STATE_ ## _field)
90
91					void
92siena_mon_decode_stats(
93	__in				efx_nic_t *enp,
94	__in				uint32_t dmask,
95	__in_opt			efsys_mem_t *esmp,
96	__out_opt			uint32_t *vmaskp,
97	__out_ecount_opt(EFX_MON_NSTATS)	efx_mon_stat_value_t *value)
98{
99	efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
100	uint16_t *sensor_map;
101	uint16_t mc_sensor;
102	size_t mc_sensor_max;
103	uint32_t vmask = 0;
104
105	/* Assert the MC_CMD_SENSOR and EFX_MON_STATE namespaces agree */
106	SIENA_STATIC_SENSOR_ASSERT(OK);
107	SIENA_STATIC_SENSOR_ASSERT(WARNING);
108	SIENA_STATIC_SENSOR_ASSERT(FATAL);
109	SIENA_STATIC_SENSOR_ASSERT(BROKEN);
110
111	EFX_STATIC_ASSERT(sizeof (__siena_mon_port1_map)
112			    == sizeof (__siena_mon_port0_map));
113	mc_sensor_max = EFX_ARRAY_SIZE(__siena_mon_port0_map);
114	sensor_map = (emip->emi_port == 1)
115		? __siena_mon_port0_map
116		: __siena_mon_port1_map;
117
118	/*
119	 * dmask may legitimately contain sensors not understood by the driver
120	 */
121	for (mc_sensor = 0; mc_sensor < mc_sensor_max; ++mc_sensor) {
122		uint16_t efx_sensor = sensor_map[mc_sensor];
123
124		if (efx_sensor == SIENA_MON_WRONG_PORT)
125			continue;
126		EFSYS_ASSERT(efx_sensor < EFX_MON_NSTATS);
127
128		if (~dmask & (1 << mc_sensor))
129			continue;
130
131		vmask |= (1 << efx_sensor);
132		if (value != NULL && esmp != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
133			efx_mon_stat_value_t *emsvp = value + efx_sensor;
134			efx_dword_t dword;
135			EFSYS_MEM_READD(esmp, 4 * mc_sensor, &dword);
136			emsvp->emsv_value =
137				(uint16_t)EFX_DWORD_FIELD(
138					dword,
139					MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_VALUE);
140			emsvp->emsv_state =
141				(uint16_t)EFX_DWORD_FIELD(
142					dword,
143					MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE);
144		}
145	}
146
147	if (vmaskp != NULL)
148		*vmaskp = vmask;
149}
150
151	__checkReturn			int
152siena_mon_ev(
153	__in				efx_nic_t *enp,
154	__in				efx_qword_t *eqp,
155	__out				efx_mon_stat_t *idp,
156	__out				efx_mon_stat_value_t *valuep)
157{
158	efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
159	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
160	uint16_t ev_monitor;
161	uint16_t ev_state;
162	uint16_t ev_value;
163	uint16_t *sensor_map;
164	efx_mon_stat_t id;
165	int rc;
166
167	sensor_map = (emip->emi_port == 1)
168		? __siena_mon_port0_map
169		: __siena_mon_port1_map;
170
171	ev_monitor = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_MONITOR);
172	ev_state = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_STATE);
173	ev_value = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_VALUE);
174
175	/* Hardware must support this statistic */
176	EFSYS_ASSERT((1 << ev_monitor) & encp->enc_siena_mon_stat_mask);
177
178	/* But we don't have to understand it */
179	if (ev_monitor >= EFX_ARRAY_SIZE(__siena_mon_port0_map)) {
180		rc = ENOTSUP;
181		goto fail1;
182	}
183
184	id = sensor_map[ev_monitor];
185	if (id == SIENA_MON_WRONG_PORT)
186		return (ENODEV);
187	EFSYS_ASSERT(id < EFX_MON_NSTATS);
188
189	*idp = id;
190	valuep->emsv_value = ev_value;
191	valuep->emsv_state = ev_state;
192
193	return (0);
194
195fail1:
196	EFSYS_PROBE1(fail1, int, rc);
197
198	return (rc);
199}
200
201	__checkReturn			int
202siena_mon_stats_update(
203	__in				efx_nic_t *enp,
204	__in				efsys_mem_t *esmp,
205	__out_ecount(EFX_MON_NSTATS)	efx_mon_stat_value_t *values)
206{
207	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
208	uint32_t dmask = encp->enc_siena_mon_stat_mask;
209	uint32_t vmask;
210	uint8_t payload[MC_CMD_READ_SENSORS_IN_LEN];
211	efx_mcdi_req_t req;
212	int rc;
213
214	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
215
216	req.emr_cmd = MC_CMD_READ_SENSORS;
217	req.emr_in_buf = payload;
218	req.emr_in_length = sizeof (payload);
219	EFX_STATIC_ASSERT(MC_CMD_READ_SENSORS_OUT_LEN == 0);
220	req.emr_out_buf = NULL;
221	req.emr_out_length = 0;
222
223	MCDI_IN_SET_DWORD(req, READ_SENSORS_IN_DMA_ADDR_LO,
224			    EFSYS_MEM_ADDR(esmp) & 0xffffffff);
225	MCDI_IN_SET_DWORD(req, READ_SENSORS_IN_DMA_ADDR_HI,
226			    EFSYS_MEM_ADDR(esmp) >> 32);
227
228	efx_mcdi_execute(enp, &req);
229
230	if (req.emr_rc != 0) {
231		rc = req.emr_rc;
232		goto fail1;
233	}
234
235	siena_mon_decode_stats(enp, dmask, esmp, &vmask, values);
236	EFSYS_ASSERT(vmask == encp->enc_mon_stat_mask);
237
238	return (0);
239
240fail1:
241	EFSYS_PROBE1(fail1, int, rc);
242
243	return (rc);
244}
245
246#endif	/* EFSYS_OPT_MON_STATS */
247
248#endif	/* EFSYS_OPT_MON_SIENA */
249