1 /* SPDX-License-Identifier: BSD-3-Clause
3 * Copyright (c) 2009-2018 Solarflare Communications Inc.
11 #if EFSYS_OPT_MON_MCDI
13 #if EFSYS_OPT_MON_STATS
15 /* Get port mask from one-based MCDI port number */
16 #define MCDI_MON_PORT_MASK(_emip) (1U << ((_emip)->emi_port - 1))
18 #define MCDI_STATIC_SENSOR_ASSERT(_field) \
19 EFX_STATIC_ASSERT(MC_CMD_SENSOR_STATE_ ## _field \
20 == EFX_MON_STAT_STATE_ ## _field)
23 mcdi_mon_decode_stats(
25 __in_bcount(sensor_mask_size) uint32_t *sensor_mask,
26 __in size_t sensor_mask_size,
27 __in_opt efsys_mem_t *esmp,
28 __out_bcount_opt(sensor_mask_size) uint32_t *stat_maskp,
29 __inout_ecount_opt(EFX_MON_NSTATS) efx_mon_stat_value_t *stat)
31 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
32 efx_mon_stat_portmask_t port_mask;
35 uint32_t stat_mask[(EFX_MON_NSTATS + 31) / 32];
39 /* Assert the MC_CMD_SENSOR and EFX_MON_STATE namespaces agree */
40 MCDI_STATIC_SENSOR_ASSERT(OK);
41 MCDI_STATIC_SENSOR_ASSERT(WARNING);
42 MCDI_STATIC_SENSOR_ASSERT(FATAL);
43 MCDI_STATIC_SENSOR_ASSERT(BROKEN);
44 MCDI_STATIC_SENSOR_ASSERT(NO_READING);
46 sensor_max = 8 * sensor_mask_size;
48 EFSYS_ASSERT(emip->emi_port > 0); /* MCDI port number is one-based */
49 port_mask = (efx_mon_stat_portmask_t)MCDI_MON_PORT_MASK(emip);
51 memset(stat_mask, 0, sizeof (stat_mask));
54 * The MCDI sensor readings in the DMA buffer are a packed array of
55 * MC_CMD_SENSOR_VALUE_ENTRY structures, which only includes entries for
56 * supported sensors (bit set in sensor_mask). The sensor_mask and
57 * sensor readings do not include entries for the per-page NEXT_PAGE
60 * sensor_mask may legitimately contain MCDI sensors that the driver
61 * does not understand.
63 for (sensor = 0; sensor < sensor_max; ++sensor) {
65 efx_mon_stat_portmask_t stat_portmask = 0;
67 efx_mon_stat_unit_t stat_unit;
69 if ((sensor % (MC_CMD_SENSOR_PAGE0_NEXT + 1)) ==
70 MC_CMD_SENSOR_PAGE0_NEXT) {
73 /* This sensor is one of the page boundary bits. */
76 if (~(sensor_mask[page]) & (1U << sensor))
78 /* This sensor not in DMA buffer */
82 * Valid stat in DMA buffer that we need to increment over, even
83 * if we couldn't look up the id
86 decode_ok = efx_mon_mcdi_to_efx_stat(sensor, &id);
88 decode_ok && efx_mon_get_stat_portmap(id, &stat_portmask);
90 if (!(decode_ok && (stat_portmask & port_mask)))
92 /* Either bad decode, or don't know what port stat is on */
94 EFSYS_ASSERT(id < EFX_MON_NSTATS);
97 * stat_mask is a bitmask indexed by EFX_MON_* monitor statistic
98 * identifiers from efx_mon_stat_t (without NEXT_PAGE bits).
100 * If there is an entry in the MCDI sensor to monitor statistic
101 * map then the sensor reading is used for the value of the
104 stat_mask[id / EFX_MON_MASK_ELEMENT_SIZE] |=
105 (1U << (id % EFX_MON_MASK_ELEMENT_SIZE));
107 if (stat != NULL && esmp != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
110 /* Get MCDI sensor reading from DMA buffer */
111 EFSYS_MEM_READD(esmp, 4 * (idx - 1), &dword);
113 /* Update EFX monitor stat from MCDI sensor reading */
114 stat[id].emsv_value = (uint16_t)EFX_DWORD_FIELD(dword,
115 MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_VALUE);
117 stat[id].emsv_state = (uint16_t)EFX_DWORD_FIELD(dword,
118 MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE);
121 efx_mon_get_stat_unit(id, &stat_unit) ?
122 stat_unit : EFX_MON_STAT_UNIT_UNKNOWN;
126 if (stat_maskp != NULL) {
127 memcpy(stat_maskp, stat_mask, sizeof (stat_mask));
131 __checkReturn efx_rc_t
134 __in efx_qword_t *eqp,
135 __out efx_mon_stat_t *idp,
136 __out efx_mon_stat_value_t *valuep)
138 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
139 efx_mon_stat_portmask_t port_mask, sensor_port_mask;
146 EFSYS_ASSERT(emip->emi_port > 0); /* MCDI port number is one-based */
147 port_mask = MCDI_MON_PORT_MASK(emip);
149 sensor = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_MONITOR);
150 state = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_STATE);
151 value = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_VALUE);
153 /* Hardware must support this MCDI sensor */
154 EFSYS_ASSERT3U(sensor, <,
155 (8 * enp->en_nic_cfg.enc_mcdi_sensor_mask_size));
156 EFSYS_ASSERT((sensor % (MC_CMD_SENSOR_PAGE0_NEXT + 1)) !=
157 MC_CMD_SENSOR_PAGE0_NEXT);
158 EFSYS_ASSERT(enp->en_nic_cfg.enc_mcdi_sensor_maskp != NULL);
159 EFSYS_ASSERT((enp->en_nic_cfg.enc_mcdi_sensor_maskp[
160 sensor / (MC_CMD_SENSOR_PAGE0_NEXT + 1)] &
161 (1U << (sensor % (MC_CMD_SENSOR_PAGE0_NEXT + 1)))) != 0);
163 /* And we need to understand it, to get port-map */
164 if (!efx_mon_mcdi_to_efx_stat(sensor, &id)) {
168 if (!(efx_mon_get_stat_portmap(id, &sensor_port_mask) &&
169 (port_mask && sensor_port_mask))) {
172 EFSYS_ASSERT(id < EFX_MON_NSTATS);
175 valuep->emsv_value = value;
176 valuep->emsv_state = state;
181 EFSYS_PROBE1(fail1, efx_rc_t, rc);
187 static __checkReturn efx_rc_t
188 efx_mcdi_read_sensors(
190 __in efsys_mem_t *esmp,
194 uint8_t payload[MAX(MC_CMD_READ_SENSORS_EXT_IN_LEN,
195 MC_CMD_READ_SENSORS_EXT_OUT_LEN)];
196 uint32_t addr_lo, addr_hi;
199 if (EFSYS_MEM_SIZE(esmp) < size) {
204 req.emr_cmd = MC_CMD_READ_SENSORS;
205 req.emr_in_buf = payload;
206 req.emr_in_length = MC_CMD_READ_SENSORS_EXT_IN_LEN;
207 req.emr_out_buf = payload;
208 req.emr_out_length = MC_CMD_READ_SENSORS_EXT_OUT_LEN;
210 addr_lo = (uint32_t)(EFSYS_MEM_ADDR(esmp) & 0xffffffff);
211 addr_hi = (uint32_t)(EFSYS_MEM_ADDR(esmp) >> 32);
213 MCDI_IN_SET_DWORD(req, READ_SENSORS_EXT_IN_DMA_ADDR_LO, addr_lo);
214 MCDI_IN_SET_DWORD(req, READ_SENSORS_EXT_IN_DMA_ADDR_HI, addr_hi);
215 MCDI_IN_SET_DWORD(req, READ_SENSORS_EXT_IN_LENGTH, size);
217 efx_mcdi_execute(enp, &req);
222 EFSYS_PROBE1(fail1, efx_rc_t, rc);
227 static __checkReturn efx_rc_t
228 efx_mcdi_sensor_info_npages(
230 __out uint32_t *npagesp)
233 uint8_t payload[MAX(MC_CMD_SENSOR_INFO_EXT_IN_LEN,
234 MC_CMD_SENSOR_INFO_OUT_LENMAX)];
238 EFSYS_ASSERT(npagesp != NULL);
242 (void) memset(payload, 0, sizeof (payload));
243 req.emr_cmd = MC_CMD_SENSOR_INFO;
244 req.emr_in_buf = payload;
245 req.emr_in_length = MC_CMD_SENSOR_INFO_EXT_IN_LEN;
246 req.emr_out_buf = payload;
247 req.emr_out_length = MC_CMD_SENSOR_INFO_OUT_LENMAX;
249 MCDI_IN_SET_DWORD(req, SENSOR_INFO_EXT_IN_PAGE, page++);
251 efx_mcdi_execute_quiet(enp, &req);
253 if (req.emr_rc != 0) {
257 } while (MCDI_OUT_DWORD(req, SENSOR_INFO_OUT_MASK) &
258 (1U << MC_CMD_SENSOR_PAGE0_NEXT));
265 EFSYS_PROBE1(fail1, efx_rc_t, rc);
270 static __checkReturn efx_rc_t
271 efx_mcdi_sensor_info(
273 __out_ecount(npages) uint32_t *sensor_maskp,
277 uint8_t payload[MAX(MC_CMD_SENSOR_INFO_EXT_IN_LEN,
278 MC_CMD_SENSOR_INFO_OUT_LENMAX)];
282 EFSYS_ASSERT(sensor_maskp != NULL);
289 for (page = 0; page < npages; page++) {
292 (void) memset(payload, 0, sizeof (payload));
293 req.emr_cmd = MC_CMD_SENSOR_INFO;
294 req.emr_in_buf = payload;
295 req.emr_in_length = MC_CMD_SENSOR_INFO_EXT_IN_LEN;
296 req.emr_out_buf = payload;
297 req.emr_out_length = MC_CMD_SENSOR_INFO_OUT_LENMAX;
299 MCDI_IN_SET_DWORD(req, SENSOR_INFO_EXT_IN_PAGE, page);
301 efx_mcdi_execute(enp, &req);
303 if (req.emr_rc != 0) {
308 mask = MCDI_OUT_DWORD(req, SENSOR_INFO_OUT_MASK);
310 if ((page != (npages - 1)) &&
311 ((mask & (1U << MC_CMD_SENSOR_PAGE0_NEXT)) == 0)) {
315 sensor_maskp[page] = mask;
318 if (sensor_maskp[npages - 1] & (1U << MC_CMD_SENSOR_PAGE0_NEXT)) {
332 EFSYS_PROBE1(fail1, efx_rc_t, rc);
337 __checkReturn efx_rc_t
338 mcdi_mon_stats_update(
340 __in efsys_mem_t *esmp,
341 __inout_ecount(EFX_MON_NSTATS) efx_mon_stat_value_t *values)
343 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
344 uint32_t size = encp->enc_mon_stat_dma_buf_size;
347 if ((rc = efx_mcdi_read_sensors(enp, esmp, size)) != 0)
350 EFSYS_DMA_SYNC_FOR_KERNEL(esmp, 0, size);
352 mcdi_mon_decode_stats(enp,
353 encp->enc_mcdi_sensor_maskp,
354 encp->enc_mcdi_sensor_mask_size,
360 EFSYS_PROBE1(fail1, efx_rc_t, rc);
365 __checkReturn efx_rc_t
369 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
373 switch (enp->en_family) {
375 case EFX_FAMILY_SIENA:
376 encp->enc_mon_type = EFX_MON_SFC90X0;
379 #if EFSYS_OPT_HUNTINGTON
380 case EFX_FAMILY_HUNTINGTON:
381 encp->enc_mon_type = EFX_MON_SFC91X0;
384 #if EFSYS_OPT_MEDFORD
385 case EFX_FAMILY_MEDFORD:
386 encp->enc_mon_type = EFX_MON_SFC92X0;
389 #if EFSYS_OPT_MEDFORD2
390 case EFX_FAMILY_MEDFORD2:
391 encp->enc_mon_type = EFX_MON_SFC92X0;
399 /* Get mc sensor mask size */
401 if ((rc = efx_mcdi_sensor_info_npages(enp, &npages)) != 0)
404 encp->enc_mon_stat_dma_buf_size = npages * EFX_MON_STATS_PAGE_SIZE;
405 encp->enc_mcdi_sensor_mask_size = npages * sizeof (uint32_t);
407 /* Allocate mc sensor mask */
408 EFSYS_KMEM_ALLOC(enp->en_esip,
409 encp->enc_mcdi_sensor_mask_size,
410 encp->enc_mcdi_sensor_maskp);
412 if (encp->enc_mcdi_sensor_maskp == NULL) {
417 /* Read mc sensor mask */
418 if ((rc = efx_mcdi_sensor_info(enp,
419 encp->enc_mcdi_sensor_maskp,
423 /* Build monitor statistics mask */
424 mcdi_mon_decode_stats(enp,
425 encp->enc_mcdi_sensor_maskp,
426 encp->enc_mcdi_sensor_mask_size,
427 NULL, encp->enc_mon_stat_mask, NULL);
433 EFSYS_KMEM_FREE(enp->en_esip,
434 encp->enc_mcdi_sensor_mask_size,
435 encp->enc_mcdi_sensor_maskp);
444 EFSYS_PROBE1(fail1, efx_rc_t, rc);
453 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
455 if (encp->enc_mcdi_sensor_maskp != NULL) {
456 EFSYS_KMEM_FREE(enp->en_esip,
457 encp->enc_mcdi_sensor_mask_size,
458 encp->enc_mcdi_sensor_maskp);
463 #endif /* EFSYS_OPT_MON_STATS */
465 #endif /* EFSYS_OPT_MON_MCDI */