1 /* SPDX-License-Identifier: BSD-3-Clause
3 * Copyright(c) 2019-2020 Xilinx, Inc.
4 * Copyright(c) 2009-2019 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;
66 efx_mon_stat_unit_t stat_unit;
68 if ((sensor % (MC_CMD_SENSOR_PAGE0_NEXT + 1)) ==
69 MC_CMD_SENSOR_PAGE0_NEXT) {
70 /* This sensor is one of the page boundary bits. */
75 if (~(sensor_mask[page]) &
76 (1U << (sensor % (sizeof (sensor_mask[page]) * 8)))) {
77 /* This sensor is not supported. */
81 /* Supported sensor, so it is present in the DMA buffer. */
84 if ((efx_mon_mcdi_to_efx_stat(sensor, &id) != B_TRUE) ||
85 (efx_mon_get_stat_portmap(id, &stat_portmask) != B_TRUE)) {
86 /* The sensor is not known to the driver. */
90 if ((stat_portmask & port_mask) == 0) {
91 /* The sensor is not for this port. */
95 EFSYS_ASSERT(id < EFX_MON_NSTATS);
98 * stat_mask is a bitmask indexed by EFX_MON_* monitor statistic
99 * identifiers from efx_mon_stat_t (without NEXT_PAGE bits).
101 * If there is an entry in the MCDI sensor to monitor statistic
102 * map then the sensor reading is used for the value of the
105 stat_mask[id / EFX_MON_MASK_ELEMENT_SIZE] |=
106 (1U << (id % EFX_MON_MASK_ELEMENT_SIZE));
108 if (stat != NULL && esmp != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
111 /* Get MCDI sensor reading from DMA buffer */
112 EFSYS_MEM_READD(esmp, 4 * (idx - 1), &dword);
114 /* Update EFX monitor stat from MCDI sensor reading */
115 stat[id].emsv_value = (uint16_t)EFX_DWORD_FIELD(dword,
116 MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_VALUE);
118 stat[id].emsv_state = (uint16_t)EFX_DWORD_FIELD(dword,
119 MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE);
122 efx_mon_get_stat_unit(id, &stat_unit) ?
123 stat_unit : EFX_MON_STAT_UNIT_UNKNOWN;
127 if (stat_maskp != NULL) {
128 memcpy(stat_maskp, stat_mask, sizeof (stat_mask));
132 __checkReturn efx_rc_t
135 __in efx_qword_t *eqp,
136 __out efx_mon_stat_t *idp,
137 __out efx_mon_stat_value_t *valuep)
139 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
140 efx_mon_stat_portmask_t port_mask, sensor_port_mask;
147 EFSYS_ASSERT(emip->emi_port > 0); /* MCDI port number is one-based */
148 port_mask = MCDI_MON_PORT_MASK(emip);
150 sensor = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_MONITOR);
151 state = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_STATE);
152 value = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_VALUE);
154 /* Hardware must support this MCDI sensor */
155 EFSYS_ASSERT3U(sensor, <,
156 (8 * enp->en_nic_cfg.enc_mcdi_sensor_mask_size));
157 EFSYS_ASSERT((sensor % (MC_CMD_SENSOR_PAGE0_NEXT + 1)) !=
158 MC_CMD_SENSOR_PAGE0_NEXT);
159 EFSYS_ASSERT(enp->en_nic_cfg.enc_mcdi_sensor_maskp != NULL);
160 EFSYS_ASSERT((enp->en_nic_cfg.enc_mcdi_sensor_maskp[
161 sensor / (MC_CMD_SENSOR_PAGE0_NEXT + 1)] &
162 (1U << (sensor % (MC_CMD_SENSOR_PAGE0_NEXT + 1)))) != 0);
164 /* And we need to understand it, to get port-map */
165 if (!efx_mon_mcdi_to_efx_stat(sensor, &id)) {
169 if (!(efx_mon_get_stat_portmap(id, &sensor_port_mask) &&
170 (port_mask && sensor_port_mask))) {
173 EFSYS_ASSERT(id < EFX_MON_NSTATS);
176 valuep->emsv_value = value;
177 valuep->emsv_state = state;
182 EFSYS_PROBE1(fail1, efx_rc_t, rc);
188 static __checkReturn efx_rc_t
189 efx_mcdi_read_sensors(
191 __in efsys_mem_t *esmp,
195 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_READ_SENSORS_EXT_IN_LEN,
196 MC_CMD_READ_SENSORS_EXT_OUT_LEN);
197 uint32_t addr_lo, addr_hi;
200 if (EFSYS_MEM_SIZE(esmp) < size) {
205 req.emr_cmd = MC_CMD_READ_SENSORS;
206 req.emr_in_buf = payload;
207 req.emr_in_length = MC_CMD_READ_SENSORS_EXT_IN_LEN;
208 req.emr_out_buf = payload;
209 req.emr_out_length = MC_CMD_READ_SENSORS_EXT_OUT_LEN;
211 addr_lo = (uint32_t)(EFSYS_MEM_ADDR(esmp) & 0xffffffff);
212 addr_hi = (uint32_t)(EFSYS_MEM_ADDR(esmp) >> 32);
214 MCDI_IN_SET_DWORD(req, READ_SENSORS_EXT_IN_DMA_ADDR_LO, addr_lo);
215 MCDI_IN_SET_DWORD(req, READ_SENSORS_EXT_IN_DMA_ADDR_HI, addr_hi);
216 MCDI_IN_SET_DWORD(req, READ_SENSORS_EXT_IN_LENGTH, size);
218 efx_mcdi_execute(enp, &req);
223 EFSYS_PROBE1(fail1, efx_rc_t, rc);
228 static __checkReturn efx_rc_t
229 efx_mcdi_sensor_info_npages(
231 __out uint32_t *npagesp)
234 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SENSOR_INFO_EXT_IN_LEN,
235 MC_CMD_SENSOR_INFO_OUT_LENMAX);
239 EFSYS_ASSERT(npagesp != NULL);
243 (void) memset(payload, 0, sizeof (payload));
244 req.emr_cmd = MC_CMD_SENSOR_INFO;
245 req.emr_in_buf = payload;
246 req.emr_in_length = MC_CMD_SENSOR_INFO_EXT_IN_LEN;
247 req.emr_out_buf = payload;
248 req.emr_out_length = MC_CMD_SENSOR_INFO_OUT_LENMAX;
250 MCDI_IN_SET_DWORD(req, SENSOR_INFO_EXT_IN_PAGE, page++);
252 efx_mcdi_execute_quiet(enp, &req);
254 if (req.emr_rc != 0) {
258 } while (MCDI_OUT_DWORD(req, SENSOR_INFO_OUT_MASK) &
259 (1U << MC_CMD_SENSOR_PAGE0_NEXT));
266 EFSYS_PROBE1(fail1, efx_rc_t, rc);
271 static __checkReturn efx_rc_t
272 efx_mcdi_sensor_info(
274 __out_ecount(npages) uint32_t *sensor_maskp,
278 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SENSOR_INFO_EXT_IN_LEN,
279 MC_CMD_SENSOR_INFO_OUT_LENMAX);
283 EFSYS_ASSERT(sensor_maskp != NULL);
290 for (page = 0; page < npages; page++) {
293 (void) memset(payload, 0, sizeof (payload));
294 req.emr_cmd = MC_CMD_SENSOR_INFO;
295 req.emr_in_buf = payload;
296 req.emr_in_length = MC_CMD_SENSOR_INFO_EXT_IN_LEN;
297 req.emr_out_buf = payload;
298 req.emr_out_length = MC_CMD_SENSOR_INFO_OUT_LENMAX;
300 MCDI_IN_SET_DWORD(req, SENSOR_INFO_EXT_IN_PAGE, page);
302 efx_mcdi_execute(enp, &req);
304 if (req.emr_rc != 0) {
309 mask = MCDI_OUT_DWORD(req, SENSOR_INFO_OUT_MASK);
311 if ((page != (npages - 1)) &&
312 ((mask & (1U << MC_CMD_SENSOR_PAGE0_NEXT)) == 0)) {
316 sensor_maskp[page] = mask;
319 if (sensor_maskp[npages - 1] & (1U << MC_CMD_SENSOR_PAGE0_NEXT)) {
333 EFSYS_PROBE1(fail1, efx_rc_t, rc);
338 static __checkReturn efx_rc_t
339 efx_mcdi_sensor_info_page(
342 __out uint32_t *mask_part,
343 __out_ecount((sizeof (*mask_part) * 8) - 1)
344 efx_mon_stat_limits_t *limits)
347 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SENSOR_INFO_EXT_IN_LEN,
348 MC_CMD_SENSOR_INFO_OUT_LENMAX);
352 efx_qword_t *limit_info;
354 EFSYS_ASSERT(mask_part != NULL);
355 EFSYS_ASSERT(limits != NULL);
358 ((sizeof (*mask_part) * 8) - 1) * sizeof (efx_mon_stat_limits_t));
360 req.emr_cmd = MC_CMD_SENSOR_INFO;
361 req.emr_in_buf = payload;
362 req.emr_in_length = MC_CMD_SENSOR_INFO_EXT_IN_LEN;
363 req.emr_out_buf = payload;
364 req.emr_out_length = MC_CMD_SENSOR_INFO_OUT_LENMAX;
366 MCDI_IN_SET_DWORD(req, SENSOR_INFO_EXT_IN_PAGE, page);
368 efx_mcdi_execute(enp, &req);
375 EFSYS_ASSERT(sizeof (*limit_info) ==
376 MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_LEN);
377 maskp = MCDI_OUT2(req, efx_dword_t, SENSOR_INFO_OUT_MASK);
378 limit_info = (efx_qword_t *)(maskp + 1);
380 *mask_part = maskp->ed_u32[0];
381 mask_copy = *mask_part;
383 /* Copy an entry for all but the highest bit set. */
386 if (mask_copy == (1U << MC_CMD_SENSOR_PAGE0_NEXT)) {
387 /* Only next page bit set. */
390 /* Clear lowest bit */
391 mask_copy = mask_copy & ~(mask_copy ^ (mask_copy - 1));
392 /* And copy out limit entry into buffer */
393 limits->emlv_warning_min = EFX_QWORD_FIELD(*limit_info,
394 MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_MIN1);
396 limits->emlv_warning_max = EFX_QWORD_FIELD(*limit_info,
397 MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_MAX1);
399 limits->emlv_fatal_min = EFX_QWORD_FIELD(*limit_info,
400 MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_MIN2);
402 limits->emlv_fatal_max = EFX_QWORD_FIELD(*limit_info,
403 MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_MAX2);
413 EFSYS_PROBE1(fail1, efx_rc_t, rc);
418 __checkReturn efx_rc_t
419 mcdi_mon_stats_update(
421 __in efsys_mem_t *esmp,
422 __inout_ecount(EFX_MON_NSTATS) efx_mon_stat_value_t *values)
424 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
425 uint32_t size = encp->enc_mon_stat_dma_buf_size;
428 if ((rc = efx_mcdi_read_sensors(enp, esmp, size)) != 0)
431 EFSYS_DMA_SYNC_FOR_KERNEL(esmp, 0, size);
433 mcdi_mon_decode_stats(enp,
434 encp->enc_mcdi_sensor_maskp,
435 encp->enc_mcdi_sensor_mask_size,
441 EFSYS_PROBE1(fail1, efx_rc_t, rc);
448 __in uint32_t input_mask,
449 __out uint32_t *lowest_bit_mask,
450 __out uint32_t *lowest_bit_num
454 uint32_t set_bit, bit_index;
456 x = (input_mask ^ (input_mask - 1));
457 set_bit = (x + 1) >> 1;
459 set_bit = (1U << 31U);
462 if (set_bit & 0xFFFF0000)
464 if (set_bit & 0xFF00FF00)
466 if (set_bit & 0xF0F0F0F0)
468 if (set_bit & 0xCCCCCCCC)
470 if (set_bit & 0xAAAAAAAA)
473 *lowest_bit_mask = set_bit;
474 *lowest_bit_num = bit_index;
477 __checkReturn efx_rc_t
478 mcdi_mon_limits_update(
480 __inout_ecount(EFX_MON_NSTATS) efx_mon_stat_limits_t *values)
485 uint32_t limit_index;
486 efx_mon_stat_limits_t limits[sizeof (page_mask) * 8];
494 rc = efx_mcdi_sensor_info_page(enp, page, &page_mask, limits);
504 if (page_mask == (1U << MC_CMD_SENSOR_PAGE0_NEXT))
507 lowest_set_bit(page_mask, &set_bit, &page_index);
508 page_mask = page_mask & ~set_bit;
511 page_index + (sizeof (page_mask) * 8 * page);
514 * This can fail if MCDI reports newer stats than the
515 * drivers understand, or the bit is the next page bit.
517 * Driver needs to be tolerant of this.
519 if (!efx_mon_mcdi_to_efx_stat(mcdi_index, &stat))
522 values[stat] = limits[limit_index];
526 } while (page_mask & (1U << MC_CMD_SENSOR_PAGE0_NEXT));
531 EFSYS_PROBE1(fail1, efx_rc_t, rc);
536 __checkReturn efx_rc_t
540 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
544 switch (enp->en_family) {
546 case EFX_FAMILY_SIENA:
547 encp->enc_mon_type = EFX_MON_SFC90X0;
550 #if EFSYS_OPT_HUNTINGTON
551 case EFX_FAMILY_HUNTINGTON:
552 encp->enc_mon_type = EFX_MON_SFC91X0;
555 #if EFSYS_OPT_MEDFORD
556 case EFX_FAMILY_MEDFORD:
557 encp->enc_mon_type = EFX_MON_SFC92X0;
560 #if EFSYS_OPT_MEDFORD2
561 case EFX_FAMILY_MEDFORD2:
562 encp->enc_mon_type = EFX_MON_SFC92X0;
570 /* Get mc sensor mask size */
572 if ((rc = efx_mcdi_sensor_info_npages(enp, &npages)) != 0)
575 encp->enc_mon_stat_dma_buf_size = npages * EFX_MON_STATS_PAGE_SIZE;
576 encp->enc_mcdi_sensor_mask_size = npages * sizeof (uint32_t);
578 /* Allocate mc sensor mask */
579 EFSYS_KMEM_ALLOC(enp->en_esip,
580 encp->enc_mcdi_sensor_mask_size,
581 encp->enc_mcdi_sensor_maskp);
583 if (encp->enc_mcdi_sensor_maskp == NULL) {
588 /* Read mc sensor mask */
589 if ((rc = efx_mcdi_sensor_info(enp,
590 encp->enc_mcdi_sensor_maskp,
594 /* Build monitor statistics mask */
595 mcdi_mon_decode_stats(enp,
596 encp->enc_mcdi_sensor_maskp,
597 encp->enc_mcdi_sensor_mask_size,
598 NULL, encp->enc_mon_stat_mask, NULL);
604 EFSYS_KMEM_FREE(enp->en_esip,
605 encp->enc_mcdi_sensor_mask_size,
606 encp->enc_mcdi_sensor_maskp);
615 EFSYS_PROBE1(fail1, efx_rc_t, rc);
624 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
626 if (encp->enc_mcdi_sensor_maskp != NULL) {
627 EFSYS_KMEM_FREE(enp->en_esip,
628 encp->enc_mcdi_sensor_mask_size,
629 encp->enc_mcdi_sensor_maskp);
634 #endif /* EFSYS_OPT_MON_STATS */
636 #endif /* EFSYS_OPT_MON_MCDI */