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 EFX_MCDI_DECLARE_BUF(payload, 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 EFX_MCDI_DECLARE_BUF(payload, 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 EFX_MCDI_DECLARE_BUF(payload, 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 static __checkReturn efx_rc_t
338 efx_mcdi_sensor_info_page(
341 __out uint32_t *mask_part,
342 __out_ecount((sizeof (*mask_part) * 8) - 1)
343 efx_mon_stat_limits_t *limits)
346 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SENSOR_INFO_EXT_IN_LEN,
347 MC_CMD_SENSOR_INFO_OUT_LENMAX);
351 efx_qword_t *limit_info;
353 EFSYS_ASSERT(mask_part != NULL);
354 EFSYS_ASSERT(limits != NULL);
357 ((sizeof (*mask_part) * 8) - 1) * sizeof (efx_mon_stat_limits_t));
359 req.emr_cmd = MC_CMD_SENSOR_INFO;
360 req.emr_in_buf = payload;
361 req.emr_in_length = MC_CMD_SENSOR_INFO_EXT_IN_LEN;
362 req.emr_out_buf = payload;
363 req.emr_out_length = MC_CMD_SENSOR_INFO_OUT_LENMAX;
365 MCDI_IN_SET_DWORD(req, SENSOR_INFO_EXT_IN_PAGE, page);
367 efx_mcdi_execute(enp, &req);
374 EFSYS_ASSERT(sizeof (*limit_info) ==
375 MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_LEN);
376 maskp = MCDI_OUT2(req, efx_dword_t, SENSOR_INFO_OUT_MASK);
377 limit_info = (efx_qword_t *)(maskp + 1);
379 *mask_part = maskp->ed_u32[0];
380 mask_copy = *mask_part;
382 /* Copy an entry for all but the highest bit set. */
385 if (mask_copy == (1U << MC_CMD_SENSOR_PAGE0_NEXT)) {
386 /* Only next page bit set. */
389 /* Clear lowest bit */
390 mask_copy = mask_copy & ~(mask_copy ^ (mask_copy - 1));
391 /* And copy out limit entry into buffer */
392 limits->emlv_warning_min = EFX_QWORD_FIELD(*limit_info,
393 MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_MIN1);
395 limits->emlv_warning_max = EFX_QWORD_FIELD(*limit_info,
396 MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_MAX1);
398 limits->emlv_fatal_min = EFX_QWORD_FIELD(*limit_info,
399 MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_MIN2);
401 limits->emlv_fatal_max = EFX_QWORD_FIELD(*limit_info,
402 MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_MAX2);
412 EFSYS_PROBE1(fail1, efx_rc_t, rc);
417 __checkReturn efx_rc_t
418 mcdi_mon_stats_update(
420 __in efsys_mem_t *esmp,
421 __inout_ecount(EFX_MON_NSTATS) efx_mon_stat_value_t *values)
423 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
424 uint32_t size = encp->enc_mon_stat_dma_buf_size;
427 if ((rc = efx_mcdi_read_sensors(enp, esmp, size)) != 0)
430 EFSYS_DMA_SYNC_FOR_KERNEL(esmp, 0, size);
432 mcdi_mon_decode_stats(enp,
433 encp->enc_mcdi_sensor_maskp,
434 encp->enc_mcdi_sensor_mask_size,
440 EFSYS_PROBE1(fail1, efx_rc_t, rc);
447 __in uint32_t input_mask,
448 __out uint32_t *lowest_bit_mask,
449 __out uint32_t *lowest_bit_num
453 uint32_t set_bit, bit_index;
455 x = (input_mask ^ (input_mask - 1));
456 set_bit = (x + 1) >> 1;
458 set_bit = (1U << 31U);
461 if (set_bit & 0xFFFF0000)
463 if (set_bit & 0xFF00FF00)
465 if (set_bit & 0xF0F0F0F0)
467 if (set_bit & 0xCCCCCCCC)
469 if (set_bit & 0xAAAAAAAA)
472 *lowest_bit_mask = set_bit;
473 *lowest_bit_num = bit_index;
476 __checkReturn efx_rc_t
477 mcdi_mon_limits_update(
479 __inout_ecount(EFX_MON_NSTATS) efx_mon_stat_limits_t *values)
484 uint32_t limit_index;
485 efx_mon_stat_limits_t limits[sizeof (page_mask) * 8];
493 rc = efx_mcdi_sensor_info_page(enp, page, &page_mask, limits);
503 if (page_mask == (1U << MC_CMD_SENSOR_PAGE0_NEXT))
506 lowest_set_bit(page_mask, &set_bit, &page_index);
507 page_mask = page_mask & ~set_bit;
510 page_index + (sizeof (page_mask) * 8 * page);
513 * This can fail if MCDI reports newer stats than the
514 * drivers understand, or the bit is the next page bit.
516 * Driver needs to be tolerant of this.
518 if (!efx_mon_mcdi_to_efx_stat(mcdi_index, &stat))
521 values[stat] = limits[limit_index];
525 } while (page_mask & (1U << MC_CMD_SENSOR_PAGE0_NEXT));
530 EFSYS_PROBE1(fail1, efx_rc_t, rc);
535 __checkReturn efx_rc_t
539 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
543 switch (enp->en_family) {
545 case EFX_FAMILY_SIENA:
546 encp->enc_mon_type = EFX_MON_SFC90X0;
549 #if EFSYS_OPT_HUNTINGTON
550 case EFX_FAMILY_HUNTINGTON:
551 encp->enc_mon_type = EFX_MON_SFC91X0;
554 #if EFSYS_OPT_MEDFORD
555 case EFX_FAMILY_MEDFORD:
556 encp->enc_mon_type = EFX_MON_SFC92X0;
559 #if EFSYS_OPT_MEDFORD2
560 case EFX_FAMILY_MEDFORD2:
561 encp->enc_mon_type = EFX_MON_SFC92X0;
569 /* Get mc sensor mask size */
571 if ((rc = efx_mcdi_sensor_info_npages(enp, &npages)) != 0)
574 encp->enc_mon_stat_dma_buf_size = npages * EFX_MON_STATS_PAGE_SIZE;
575 encp->enc_mcdi_sensor_mask_size = npages * sizeof (uint32_t);
577 /* Allocate mc sensor mask */
578 EFSYS_KMEM_ALLOC(enp->en_esip,
579 encp->enc_mcdi_sensor_mask_size,
580 encp->enc_mcdi_sensor_maskp);
582 if (encp->enc_mcdi_sensor_maskp == NULL) {
587 /* Read mc sensor mask */
588 if ((rc = efx_mcdi_sensor_info(enp,
589 encp->enc_mcdi_sensor_maskp,
593 /* Build monitor statistics mask */
594 mcdi_mon_decode_stats(enp,
595 encp->enc_mcdi_sensor_maskp,
596 encp->enc_mcdi_sensor_mask_size,
597 NULL, encp->enc_mon_stat_mask, NULL);
603 EFSYS_KMEM_FREE(enp->en_esip,
604 encp->enc_mcdi_sensor_mask_size,
605 encp->enc_mcdi_sensor_maskp);
614 EFSYS_PROBE1(fail1, efx_rc_t, rc);
623 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
625 if (encp->enc_mcdi_sensor_maskp != NULL) {
626 EFSYS_KMEM_FREE(enp->en_esip,
627 encp->enc_mcdi_sensor_mask_size,
628 encp->enc_mcdi_sensor_maskp);
633 #endif /* EFSYS_OPT_MON_STATS */
635 #endif /* EFSYS_OPT_MON_MCDI */