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
26#include <sys/cdefs.h>
27__FBSDID("$FreeBSD$");
28
29#include "efsys.h"
30#include "efx.h"
31#include "efx_impl.h"
32
33#if EFSYS_OPT_MON_SIENA
34
35	__checkReturn	int
36siena_mon_reset(
37	__in		efx_nic_t *enp)
38{
39	_NOTE(ARGUNUSED(enp))
40	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
41
42	return (0);
43}
44
45	__checkReturn	int
46siena_mon_reconfigure(
47	__in		efx_nic_t *enp)
48{
49	_NOTE(ARGUNUSED(enp))
50	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
51
52	return (0);
53}
54
55#if EFSYS_OPT_MON_STATS
56
57#define	SIENA_MON_WRONG_PORT (uint16_t)0xffff
58
59static __cs uint16_t __siena_mon_port0_map[] = {
60	EFX_MON_STAT_INT_TEMP,		/* MC_CMD_SENSOR_CONTROLLER_TEMP */
61	EFX_MON_STAT_EXT_TEMP,		/* MC_CMD_SENSOR_PHY_COMMON_TEMP */
62	EFX_MON_STAT_INT_COOLING,	/* MC_CMD_SENSOR_CONTROLLER_COOLING */
63	EFX_MON_STAT_EXT_TEMP,		/* MC_CMD_SENSOR_PHY0_TEMP */
64	EFX_MON_STAT_EXT_COOLING,	/* MC_CMD_SENSOR_PHY0_COOLING */
65	SIENA_MON_WRONG_PORT,		/* MC_CMD_SENSOR_PHY1_TEMP */
66	SIENA_MON_WRONG_PORT,		/* MC_CMD_SENSOR_PHY1_COOLING */
67	EFX_MON_STAT_1V,		/* MC_CMD_SENSOR_IN_1V0 */
68	EFX_MON_STAT_1_2V,		/* MC_CMD_SENSOR_IN_1V2 */
69	EFX_MON_STAT_1_8V,		/* MC_CMD_SENSOR_IN_1V8 */
70	EFX_MON_STAT_2_5V,		/* MC_CMD_SENSOR_IN_2V5 */
71	EFX_MON_STAT_3_3V,		/* MC_CMD_SENSOR_IN_3V3 */
72	EFX_MON_STAT_12V,		/* MC_CMD_SENSOR_IN_12V0 */
73};
74
75static __cs uint16_t __siena_mon_port1_map[] = {
76	EFX_MON_STAT_INT_TEMP,		/* MC_CMD_SENSOR_CONTROLLER_TEMP */
77	EFX_MON_STAT_EXT_TEMP,		/* MC_CMD_SENSOR_PHY_COMMON_TEMP */
78	EFX_MON_STAT_INT_COOLING,	/* MC_CMD_SENSOR_CONTROLLER_COOLING */
79	SIENA_MON_WRONG_PORT,		/* MC_CMD_SENSOR_PHY0_TEMP */
80	SIENA_MON_WRONG_PORT,		/* MC_CMD_SENSOR_PHY0_COOLING */
81	EFX_MON_STAT_EXT_TEMP,		/* MC_CMD_SENSOR_PHY1_TEMP */
82	EFX_MON_STAT_EXT_COOLING,	/* MC_CMD_SENSOR_PHY1_COOLING */
83	EFX_MON_STAT_1V,		/* MC_CMD_SENSOR_IN_1V0 */
84	EFX_MON_STAT_1_2V,		/* MC_CMD_SENSOR_IN_1V2 */
85	EFX_MON_STAT_1_8V,		/* MC_CMD_SENSOR_IN_1V8 */
86	EFX_MON_STAT_2_5V,		/* MC_CMD_SENSOR_IN_2V5 */
87	EFX_MON_STAT_3_3V,		/* MC_CMD_SENSOR_IN_3V3 */
88	EFX_MON_STAT_12V,		/* MC_CMD_SENSOR_IN_12V0 */
89};
90
91#define	SIENA_STATIC_SENSOR_ASSERT(_field)				\
92	EFX_STATIC_ASSERT(MC_CMD_SENSOR_STATE_ ## _field		\
93			    == EFX_MON_STAT_STATE_ ## _field)
94
95					void
96siena_mon_decode_stats(
97	__in				efx_nic_t *enp,
98	__in				uint32_t dmask,
99	__in_opt			efsys_mem_t *esmp,
100	__out_opt			uint32_t *vmaskp,
101	__out_ecount_opt(EFX_MON_NSTATS)	efx_mon_stat_value_t *value)
102{
103	efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
104	uint16_t *sensor_map;
105	uint16_t mc_sensor;
106	size_t mc_sensor_max;
107	uint32_t vmask = 0;
108
109	/* Assert the MC_CMD_SENSOR and EFX_MON_STATE namespaces agree */
110	SIENA_STATIC_SENSOR_ASSERT(OK);
111	SIENA_STATIC_SENSOR_ASSERT(WARNING);
112	SIENA_STATIC_SENSOR_ASSERT(FATAL);
113	SIENA_STATIC_SENSOR_ASSERT(BROKEN);
114
115	EFX_STATIC_ASSERT(sizeof (__siena_mon_port1_map)
116			    == sizeof (__siena_mon_port0_map));
117	mc_sensor_max = EFX_ARRAY_SIZE(__siena_mon_port0_map);
118	sensor_map = (emip->emi_port == 1)
119		? __siena_mon_port0_map
120		: __siena_mon_port1_map;
121
122	/*
123	 * dmask may legitimately contain sensors not understood by the driver
124	 */
125	for (mc_sensor = 0; mc_sensor < mc_sensor_max; ++mc_sensor) {
126		uint16_t efx_sensor = sensor_map[mc_sensor];
127
128		if (efx_sensor == SIENA_MON_WRONG_PORT)
129			continue;
130		EFSYS_ASSERT(efx_sensor < EFX_MON_NSTATS);
131
132		if (~dmask & (1 << mc_sensor))
133			continue;
134
135		vmask |= (1 << efx_sensor);
136		if (value != NULL && esmp != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
137			efx_mon_stat_value_t *emsvp = value + efx_sensor;
138			efx_dword_t dword;
139			EFSYS_MEM_READD(esmp, 4 * mc_sensor, &dword);
140			emsvp->emsv_value =
141				(uint16_t)EFX_DWORD_FIELD(
142					dword,
143					MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_VALUE);
144			emsvp->emsv_state =
145				(uint16_t)EFX_DWORD_FIELD(
146					dword,
147					MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE);
148		}
149	}
150
151	if (vmaskp != NULL)
152		*vmaskp = vmask;
153}
154
155	__checkReturn			int
156siena_mon_ev(
157	__in				efx_nic_t *enp,
158	__in				efx_qword_t *eqp,
159	__out				efx_mon_stat_t *idp,
160	__out				efx_mon_stat_value_t *valuep)
161{
162	efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
163	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
164	uint16_t ev_monitor;
165	uint16_t ev_state;
166	uint16_t ev_value;
167	uint16_t *sensor_map;
168	efx_mon_stat_t id;
169	int rc;
170
171	sensor_map = (emip->emi_port == 1)
172		? __siena_mon_port0_map
173		: __siena_mon_port1_map;
174
175	ev_monitor = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_MONITOR);
176	ev_state = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_STATE);
177	ev_value = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_VALUE);
178
179	/* Hardware must support this statistic */
180	EFSYS_ASSERT((1 << ev_monitor) & encp->enc_siena_mon_stat_mask);
181
182	/* But we don't have to understand it */
183	if (ev_monitor >= EFX_ARRAY_SIZE(__siena_mon_port0_map)) {
184		rc = ENOTSUP;
185		goto fail1;
186	}
187
188	id = sensor_map[ev_monitor];
189	if (id == SIENA_MON_WRONG_PORT)
190		return (ENODEV);
191	EFSYS_ASSERT(id < EFX_MON_NSTATS);
192
193	*idp = id;
194	valuep->emsv_value = ev_value;
195	valuep->emsv_state = ev_state;
196
197	return (0);
198
199fail1:
200	EFSYS_PROBE1(fail1, int, rc);
201
202	return (rc);
203}
204
205	__checkReturn			int
206siena_mon_stats_update(
207	__in				efx_nic_t *enp,
208	__in				efsys_mem_t *esmp,
209	__out_ecount(EFX_MON_NSTATS)	efx_mon_stat_value_t *values)
210{
211	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
212	uint32_t dmask = encp->enc_siena_mon_stat_mask;
213	uint32_t vmask;
214	uint8_t payload[MC_CMD_READ_SENSORS_IN_LEN];
215	efx_mcdi_req_t req;
216	int rc;
217
218	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
219
220	req.emr_cmd = MC_CMD_READ_SENSORS;
221	req.emr_in_buf = payload;
222	req.emr_in_length = sizeof (payload);
223	EFX_STATIC_ASSERT(MC_CMD_READ_SENSORS_OUT_LEN == 0);
224	req.emr_out_buf = NULL;
225	req.emr_out_length = 0;
226
227	MCDI_IN_SET_DWORD(req, READ_SENSORS_IN_DMA_ADDR_LO,
228			    EFSYS_MEM_ADDR(esmp) & 0xffffffff);
229	MCDI_IN_SET_DWORD(req, READ_SENSORS_IN_DMA_ADDR_HI,
230			    EFSYS_MEM_ADDR(esmp) >> 32);
231
232	efx_mcdi_execute(enp, &req);
233
234	if (req.emr_rc != 0) {
235		rc = req.emr_rc;
236		goto fail1;
237	}
238
239	siena_mon_decode_stats(enp, dmask, esmp, &vmask, values);
240	EFSYS_ASSERT(vmask == encp->enc_mon_stat_mask);
241
242	return (0);
243
244fail1:
245	EFSYS_PROBE1(fail1, int, rc);
246
247	return (rc);
248}
249
250#endif	/* EFSYS_OPT_MON_STATS */
251
252#endif	/* EFSYS_OPT_MON_SIENA */
253