xref: /freebsd/sys/dev/sfxge/common/mcdi_mon.c (revision b9f654b163bce26de79705e77b872427c9f2afa1)
1 /*-
2  * Copyright (c) 2009-2016 Solarflare Communications Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are
27  * those of the authors and should not be interpreted as representing official
28  * policies, either expressed or implied, of the FreeBSD Project.
29  */
30 
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33 
34 #include "efx.h"
35 #include "efx_impl.h"
36 #include "mcdi_mon.h"
37 
38 #if EFSYS_OPT_MON_MCDI
39 
40 #if EFSYS_OPT_MON_STATS
41 
42 /* Get port mask from one-based MCDI port number */
43 #define	MCDI_MON_PORT_MASK(_emip) (1U << ((_emip)->emi_port - 1))
44 
45 #define	MCDI_STATIC_SENSOR_ASSERT(_field)				\
46 	EFX_STATIC_ASSERT(MC_CMD_SENSOR_STATE_ ## _field		\
47 			    == EFX_MON_STAT_STATE_ ## _field)
48 
49 static						void
50 mcdi_mon_decode_stats(
51 	__in					efx_nic_t *enp,
52 	__in_bcount(sensor_mask_size)		uint32_t *sensor_mask,
53 	__in					size_t sensor_mask_size,
54 	__in_opt				efsys_mem_t *esmp,
55 	__out_bcount_opt(sensor_mask_size)	uint32_t *stat_maskp,
56 	__inout_ecount_opt(EFX_MON_NSTATS)	efx_mon_stat_value_t *stat)
57 {
58 	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
59 	efx_mon_stat_portmask_t port_mask;
60 	uint16_t sensor;
61 	size_t sensor_max;
62 	uint32_t stat_mask[(EFX_MON_NSTATS + 31) / 32];
63 	uint32_t idx = 0;
64 	uint32_t page = 0;
65 
66 	/* Assert the MC_CMD_SENSOR and EFX_MON_STATE namespaces agree */
67 	MCDI_STATIC_SENSOR_ASSERT(OK);
68 	MCDI_STATIC_SENSOR_ASSERT(WARNING);
69 	MCDI_STATIC_SENSOR_ASSERT(FATAL);
70 	MCDI_STATIC_SENSOR_ASSERT(BROKEN);
71 	MCDI_STATIC_SENSOR_ASSERT(NO_READING);
72 
73 	sensor_max = 8 * sensor_mask_size;
74 
75 	EFSYS_ASSERT(emip->emi_port > 0); /* MCDI port number is one-based */
76 	port_mask = (efx_mon_stat_portmask_t)MCDI_MON_PORT_MASK(emip);
77 
78 	memset(stat_mask, 0, sizeof (stat_mask));
79 
80 	/*
81 	 * The MCDI sensor readings in the DMA buffer are a packed array of
82 	 * MC_CMD_SENSOR_VALUE_ENTRY structures, which only includes entries for
83 	 * supported sensors (bit set in sensor_mask). The sensor_mask and
84 	 * sensor readings do not include entries for the per-page NEXT_PAGE
85 	 * flag.
86 	 *
87 	 * sensor_mask may legitimately contain MCDI sensors that the driver
88 	 * does not understand.
89 	 */
90 	for (sensor = 0; sensor < sensor_max; ++sensor) {
91 		efx_mon_stat_t id;
92 		efx_mon_stat_portmask_t stat_portmask = 0;
93 		boolean_t decode_ok;
94 		efx_mon_stat_unit_t stat_unit;
95 
96 		if ((sensor % (MC_CMD_SENSOR_PAGE0_NEXT + 1)) ==
97 		    MC_CMD_SENSOR_PAGE0_NEXT) {
98 			page++;
99 			continue;
100 			/* This sensor is one of the page boundary bits. */
101 		}
102 
103 		if (~(sensor_mask[page]) & (1U << sensor))
104 			continue;
105 		/* This sensor not in DMA buffer */
106 
107 		idx++;
108 		/*
109 		 * Valid stat in DMA buffer that we need to increment over, even
110 		 * if we couldn't look up the id
111 		 */
112 
113 		decode_ok = efx_mon_mcdi_to_efx_stat(sensor, &id);
114 		decode_ok =
115 		    decode_ok && efx_mon_get_stat_portmap(id, &stat_portmask);
116 
117 		if (!(decode_ok && (stat_portmask & port_mask)))
118 			continue;
119 		/* Either bad decode, or don't know what port stat is on */
120 
121 		EFSYS_ASSERT(id < EFX_MON_NSTATS);
122 
123 		/*
124 		 * stat_mask is a bitmask indexed by EFX_MON_* monitor statistic
125 		 * identifiers from efx_mon_stat_t (without NEXT_PAGE bits).
126 		 *
127 		 * If there is an entry in the MCDI sensor to monitor statistic
128 		 * map then the sensor reading is used for the value of the
129 		 * monitor statistic.
130 		 */
131 		stat_mask[id / EFX_MON_MASK_ELEMENT_SIZE] |=
132 		    (1U << (id % EFX_MON_MASK_ELEMENT_SIZE));
133 
134 		if (stat != NULL && esmp != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
135 			efx_dword_t dword;
136 
137 			/* Get MCDI sensor reading from DMA buffer */
138 			EFSYS_MEM_READD(esmp, 4 * (idx - 1), &dword);
139 
140 			/* Update EFX monitor stat from MCDI sensor reading */
141 			stat[id].emsv_value = (uint16_t)EFX_DWORD_FIELD(dword,
142 			    MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_VALUE);
143 
144 			stat[id].emsv_state = (uint16_t)EFX_DWORD_FIELD(dword,
145 			    MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE);
146 
147 			stat[id].emsv_unit =
148 			    efx_mon_get_stat_unit(id, &stat_unit) ?
149 			    stat_unit : EFX_MON_STAT_UNIT_UNKNOWN;
150 		}
151 	}
152 
153 	if (stat_maskp != NULL) {
154 		memcpy(stat_maskp, stat_mask, sizeof (stat_mask));
155 	}
156 }
157 
158 	__checkReturn			efx_rc_t
159 mcdi_mon_ev(
160 	__in				efx_nic_t *enp,
161 	__in				efx_qword_t *eqp,
162 	__out				efx_mon_stat_t *idp,
163 	__out				efx_mon_stat_value_t *valuep)
164 {
165 	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
166 	efx_mon_stat_portmask_t port_mask, sensor_port_mask;
167 	uint16_t sensor;
168 	uint16_t state;
169 	uint16_t value;
170 	efx_mon_stat_t id;
171 	efx_rc_t rc;
172 
173 	EFSYS_ASSERT(emip->emi_port > 0); /* MCDI port number is one-based */
174 	port_mask = MCDI_MON_PORT_MASK(emip);
175 
176 	sensor = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_MONITOR);
177 	state = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_STATE);
178 	value = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_VALUE);
179 
180 	/* Hardware must support this MCDI sensor */
181 	EFSYS_ASSERT3U(sensor, <,
182 	    (8 * enp->en_nic_cfg.enc_mcdi_sensor_mask_size));
183 	EFSYS_ASSERT((sensor % (MC_CMD_SENSOR_PAGE0_NEXT + 1)) !=
184 	    MC_CMD_SENSOR_PAGE0_NEXT);
185 	EFSYS_ASSERT(enp->en_nic_cfg.enc_mcdi_sensor_maskp != NULL);
186 	EFSYS_ASSERT((enp->en_nic_cfg.enc_mcdi_sensor_maskp[
187 		    sensor / (MC_CMD_SENSOR_PAGE0_NEXT + 1)] &
188 		(1U << (sensor % (MC_CMD_SENSOR_PAGE0_NEXT + 1)))) != 0);
189 
190 	/* And we need to understand it, to get port-map */
191 	if (!efx_mon_mcdi_to_efx_stat(sensor, &id)) {
192 		rc = ENOTSUP;
193 		goto fail1;
194 	}
195 	if (!(efx_mon_get_stat_portmap(id, &sensor_port_mask) &&
196 		(port_mask && sensor_port_mask))) {
197 		return (ENODEV);
198 	}
199 	EFSYS_ASSERT(id < EFX_MON_NSTATS);
200 
201 	*idp = id;
202 	valuep->emsv_value = value;
203 	valuep->emsv_state = state;
204 
205 	return (0);
206 
207 fail1:
208 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
209 
210 	return (rc);
211 }
212 
213 
214 static	__checkReturn	efx_rc_t
215 efx_mcdi_read_sensors(
216 	__in		efx_nic_t *enp,
217 	__in		efsys_mem_t *esmp,
218 	__in		uint32_t size)
219 {
220 	efx_mcdi_req_t req;
221 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_READ_SENSORS_EXT_IN_LEN,
222 		MC_CMD_READ_SENSORS_EXT_OUT_LEN);
223 	uint32_t addr_lo, addr_hi;
224 	efx_rc_t rc;
225 
226 	if (EFSYS_MEM_SIZE(esmp) < size) {
227 		rc = EINVAL;
228 		goto fail1;
229 	}
230 
231 	req.emr_cmd = MC_CMD_READ_SENSORS;
232 	req.emr_in_buf = payload;
233 	req.emr_in_length = MC_CMD_READ_SENSORS_EXT_IN_LEN;
234 	req.emr_out_buf = payload;
235 	req.emr_out_length = MC_CMD_READ_SENSORS_EXT_OUT_LEN;
236 
237 	addr_lo = (uint32_t)(EFSYS_MEM_ADDR(esmp) & 0xffffffff);
238 	addr_hi = (uint32_t)(EFSYS_MEM_ADDR(esmp) >> 32);
239 
240 	MCDI_IN_SET_DWORD(req, READ_SENSORS_EXT_IN_DMA_ADDR_LO, addr_lo);
241 	MCDI_IN_SET_DWORD(req, READ_SENSORS_EXT_IN_DMA_ADDR_HI, addr_hi);
242 	MCDI_IN_SET_DWORD(req, READ_SENSORS_EXT_IN_LENGTH, size);
243 
244 	efx_mcdi_execute(enp, &req);
245 
246 	return (req.emr_rc);
247 
248 fail1:
249 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
250 
251 	return (rc);
252 }
253 
254 static	__checkReturn	efx_rc_t
255 efx_mcdi_sensor_info_npages(
256 	__in		efx_nic_t *enp,
257 	__out		uint32_t *npagesp)
258 {
259 	efx_mcdi_req_t req;
260 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SENSOR_INFO_EXT_IN_LEN,
261 		MC_CMD_SENSOR_INFO_OUT_LENMAX);
262 	int page;
263 	efx_rc_t rc;
264 
265 	EFSYS_ASSERT(npagesp != NULL);
266 
267 	page = 0;
268 	do {
269 		(void) memset(payload, 0, sizeof (payload));
270 		req.emr_cmd = MC_CMD_SENSOR_INFO;
271 		req.emr_in_buf = payload;
272 		req.emr_in_length = MC_CMD_SENSOR_INFO_EXT_IN_LEN;
273 		req.emr_out_buf = payload;
274 		req.emr_out_length = MC_CMD_SENSOR_INFO_OUT_LENMAX;
275 
276 		MCDI_IN_SET_DWORD(req, SENSOR_INFO_EXT_IN_PAGE, page++);
277 
278 		efx_mcdi_execute_quiet(enp, &req);
279 
280 		if (req.emr_rc != 0) {
281 			rc = req.emr_rc;
282 			goto fail1;
283 		}
284 	} while (MCDI_OUT_DWORD(req, SENSOR_INFO_OUT_MASK) &
285 	    (1U << MC_CMD_SENSOR_PAGE0_NEXT));
286 
287 	*npagesp = page;
288 
289 	return (0);
290 
291 fail1:
292 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
293 
294 	return (rc);
295 }
296 
297 static	__checkReturn		efx_rc_t
298 efx_mcdi_sensor_info(
299 	__in			efx_nic_t *enp,
300 	__out_ecount(npages)	uint32_t *sensor_maskp,
301 	__in			size_t npages)
302 {
303 	efx_mcdi_req_t req;
304 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SENSOR_INFO_EXT_IN_LEN,
305 		MC_CMD_SENSOR_INFO_OUT_LENMAX);
306 	uint32_t page;
307 	efx_rc_t rc;
308 
309 	EFSYS_ASSERT(sensor_maskp != NULL);
310 
311 	if (npages < 1) {
312 		rc = EINVAL;
313 		goto fail1;
314 	}
315 
316 	for (page = 0; page < npages; page++) {
317 		uint32_t mask;
318 
319 		(void) memset(payload, 0, sizeof (payload));
320 		req.emr_cmd = MC_CMD_SENSOR_INFO;
321 		req.emr_in_buf = payload;
322 		req.emr_in_length = MC_CMD_SENSOR_INFO_EXT_IN_LEN;
323 		req.emr_out_buf = payload;
324 		req.emr_out_length = MC_CMD_SENSOR_INFO_OUT_LENMAX;
325 
326 		MCDI_IN_SET_DWORD(req, SENSOR_INFO_EXT_IN_PAGE, page);
327 
328 		efx_mcdi_execute(enp, &req);
329 
330 		if (req.emr_rc != 0) {
331 			rc = req.emr_rc;
332 			goto fail2;
333 		}
334 
335 		mask = MCDI_OUT_DWORD(req, SENSOR_INFO_OUT_MASK);
336 
337 		if ((page != (npages - 1)) &&
338 		    ((mask & (1U << MC_CMD_SENSOR_PAGE0_NEXT)) == 0)) {
339 			rc = EINVAL;
340 			goto fail3;
341 		}
342 		sensor_maskp[page] = mask;
343 	}
344 
345 	if (sensor_maskp[npages - 1] & (1U << MC_CMD_SENSOR_PAGE0_NEXT)) {
346 		rc = EINVAL;
347 		goto fail4;
348 	}
349 
350 	return (0);
351 
352 fail4:
353 	EFSYS_PROBE(fail4);
354 fail3:
355 	EFSYS_PROBE(fail3);
356 fail2:
357 	EFSYS_PROBE(fail2);
358 fail1:
359 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
360 
361 	return (rc);
362 }
363 
364 static	__checkReturn		efx_rc_t
365 efx_mcdi_sensor_info_page(
366 	__in			efx_nic_t *enp,
367 	__in			uint32_t page,
368 	__out			uint32_t *mask_part,
369 	__out_ecount((sizeof (*mask_part) * 8) - 1)
370 				efx_mon_stat_limits_t *limits)
371 {
372 	efx_mcdi_req_t req;
373 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SENSOR_INFO_EXT_IN_LEN,
374 		MC_CMD_SENSOR_INFO_OUT_LENMAX);
375 	efx_rc_t rc;
376 	uint32_t mask_copy;
377 	efx_dword_t *maskp;
378 	efx_qword_t *limit_info;
379 
380 	EFSYS_ASSERT(mask_part != NULL);
381 	EFSYS_ASSERT(limits != NULL);
382 
383 	memset(limits, 0,
384 	    ((sizeof (*mask_part) * 8) - 1) * sizeof (efx_mon_stat_limits_t));
385 
386 	req.emr_cmd = MC_CMD_SENSOR_INFO;
387 	req.emr_in_buf = payload;
388 	req.emr_in_length = MC_CMD_SENSOR_INFO_EXT_IN_LEN;
389 	req.emr_out_buf = payload;
390 	req.emr_out_length = MC_CMD_SENSOR_INFO_OUT_LENMAX;
391 
392 	MCDI_IN_SET_DWORD(req, SENSOR_INFO_EXT_IN_PAGE, page);
393 
394 	efx_mcdi_execute(enp, &req);
395 
396 	rc = req.emr_rc;
397 
398 	if (rc != 0)
399 		goto fail1;
400 
401 	EFSYS_ASSERT(sizeof (*limit_info) ==
402 	    MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_LEN);
403 	maskp = MCDI_OUT2(req, efx_dword_t, SENSOR_INFO_OUT_MASK);
404 	limit_info = (efx_qword_t *)(maskp + 1);
405 
406 	*mask_part = maskp->ed_u32[0];
407 	mask_copy = *mask_part;
408 
409 	/* Copy an entry for all but the highest bit set. */
410 	while (mask_copy) {
411 
412 		if (mask_copy == (1U << MC_CMD_SENSOR_PAGE0_NEXT)) {
413 			/* Only next page bit set. */
414 			mask_copy = 0;
415 		} else {
416 			/* Clear lowest bit */
417 			mask_copy = mask_copy & ~(mask_copy ^ (mask_copy - 1));
418 			/* And copy out limit entry into buffer */
419 			limits->emlv_warning_min = EFX_QWORD_FIELD(*limit_info,
420 			    MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_MIN1);
421 
422 			limits->emlv_warning_max = EFX_QWORD_FIELD(*limit_info,
423 			    MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_MAX1);
424 
425 			limits->emlv_fatal_min = EFX_QWORD_FIELD(*limit_info,
426 			    MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_MIN2);
427 
428 			limits->emlv_fatal_max = EFX_QWORD_FIELD(*limit_info,
429 			    MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_MAX2);
430 
431 			limits++;
432 			limit_info++;
433 		}
434 	}
435 
436 	return (rc);
437 
438 fail1:
439 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
440 
441 	return (rc);
442 }
443 
444 	__checkReturn			efx_rc_t
445 mcdi_mon_stats_update(
446 	__in				efx_nic_t *enp,
447 	__in				efsys_mem_t *esmp,
448 	__inout_ecount(EFX_MON_NSTATS)	efx_mon_stat_value_t *values)
449 {
450 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
451 	uint32_t size = encp->enc_mon_stat_dma_buf_size;
452 	efx_rc_t rc;
453 
454 	if ((rc = efx_mcdi_read_sensors(enp, esmp, size)) != 0)
455 		goto fail1;
456 
457 	EFSYS_DMA_SYNC_FOR_KERNEL(esmp, 0, size);
458 
459 	mcdi_mon_decode_stats(enp,
460 	    encp->enc_mcdi_sensor_maskp,
461 	    encp->enc_mcdi_sensor_mask_size,
462 	    esmp, NULL, values);
463 
464 	return (0);
465 
466 fail1:
467 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
468 
469 	return (rc);
470 }
471 
472 static		void
473 lowest_set_bit(
474 	__in	uint32_t input_mask,
475 	__out	uint32_t *lowest_bit_mask,
476 	__out	uint32_t *lowest_bit_num
477 )
478 {
479 	uint32_t x;
480 	uint32_t set_bit, bit_index;
481 
482 	x = (input_mask ^ (input_mask - 1));
483 	set_bit = (x + 1) >> 1;
484 	if (!set_bit)
485 		set_bit = (1U << 31U);
486 
487 	bit_index = 0;
488 	if (set_bit & 0xFFFF0000)
489 		bit_index += 16;
490 	if (set_bit & 0xFF00FF00)
491 		bit_index += 8;
492 	if (set_bit & 0xF0F0F0F0)
493 		bit_index += 4;
494 	if (set_bit & 0xCCCCCCCC)
495 		bit_index += 2;
496 	if (set_bit & 0xAAAAAAAA)
497 		bit_index += 1;
498 
499 	*lowest_bit_mask = set_bit;
500 	*lowest_bit_num = bit_index;
501 }
502 
503 	__checkReturn			efx_rc_t
504 mcdi_mon_limits_update(
505 	__in				efx_nic_t *enp,
506 	__inout_ecount(EFX_MON_NSTATS)	efx_mon_stat_limits_t *values)
507 {
508 	efx_rc_t rc;
509 	uint32_t page;
510 	uint32_t page_mask;
511 	uint32_t limit_index;
512 	efx_mon_stat_limits_t limits[sizeof (page_mask) * 8];
513 	efx_mon_stat_t stat;
514 
515 	page = 0;
516 	page--;
517 	do {
518 		page++;
519 
520 		rc = efx_mcdi_sensor_info_page(enp, page, &page_mask, limits);
521 		if (rc != 0)
522 			goto fail1;
523 
524 		limit_index = 0;
525 		while (page_mask) {
526 			uint32_t set_bit;
527 			uint32_t page_index;
528 			uint32_t mcdi_index;
529 
530 			if (page_mask == (1U << MC_CMD_SENSOR_PAGE0_NEXT))
531 				break;
532 
533 			lowest_set_bit(page_mask, &set_bit, &page_index);
534 			page_mask = page_mask & ~set_bit;
535 
536 			mcdi_index =
537 			    page_index + (sizeof (page_mask) * 8 * page);
538 
539 			/*
540 			 * This can fail if MCDI reports newer stats than the
541 			 * drivers understand, or the bit is the next page bit.
542 			 *
543 			 * Driver needs to be tolerant of this.
544 			 */
545 			if (!efx_mon_mcdi_to_efx_stat(mcdi_index, &stat))
546 				continue;
547 
548 			values[stat] = limits[limit_index];
549 			limit_index++;
550 		}
551 
552 	} while (page_mask & (1U << MC_CMD_SENSOR_PAGE0_NEXT));
553 
554 	return (rc);
555 
556 fail1:
557 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
558 
559 	return (rc);
560 }
561 
562 	__checkReturn	efx_rc_t
563 mcdi_mon_cfg_build(
564 	__in		efx_nic_t *enp)
565 {
566 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
567 	uint32_t npages;
568 	efx_rc_t rc;
569 
570 	switch (enp->en_family) {
571 #if EFSYS_OPT_SIENA
572 	case EFX_FAMILY_SIENA:
573 		encp->enc_mon_type = EFX_MON_SFC90X0;
574 		break;
575 #endif
576 #if EFSYS_OPT_HUNTINGTON
577 	case EFX_FAMILY_HUNTINGTON:
578 		encp->enc_mon_type = EFX_MON_SFC91X0;
579 		break;
580 #endif
581 #if EFSYS_OPT_MEDFORD
582 	case EFX_FAMILY_MEDFORD:
583 		encp->enc_mon_type = EFX_MON_SFC92X0;
584 		break;
585 #endif
586 #if EFSYS_OPT_MEDFORD2
587 	case EFX_FAMILY_MEDFORD2:
588 		encp->enc_mon_type = EFX_MON_SFC92X0;
589 		break;
590 #endif
591 	default:
592 		rc = EINVAL;
593 		goto fail1;
594 	}
595 
596 	/* Get mc sensor mask size */
597 	npages = 0;
598 	if ((rc = efx_mcdi_sensor_info_npages(enp, &npages)) != 0)
599 		goto fail2;
600 
601 	encp->enc_mon_stat_dma_buf_size	= npages * EFX_MON_STATS_PAGE_SIZE;
602 	encp->enc_mcdi_sensor_mask_size = npages * sizeof (uint32_t);
603 
604 	/* Allocate mc sensor mask */
605 	EFSYS_KMEM_ALLOC(enp->en_esip,
606 	    encp->enc_mcdi_sensor_mask_size,
607 	    encp->enc_mcdi_sensor_maskp);
608 
609 	if (encp->enc_mcdi_sensor_maskp == NULL) {
610 		rc = ENOMEM;
611 		goto fail3;
612 	}
613 
614 	/* Read mc sensor mask */
615 	if ((rc = efx_mcdi_sensor_info(enp,
616 		    encp->enc_mcdi_sensor_maskp,
617 		    npages)) != 0)
618 		goto fail4;
619 
620 	/* Build monitor statistics mask */
621 	mcdi_mon_decode_stats(enp,
622 	    encp->enc_mcdi_sensor_maskp,
623 	    encp->enc_mcdi_sensor_mask_size,
624 	    NULL, encp->enc_mon_stat_mask, NULL);
625 
626 	return (0);
627 
628 fail4:
629 	EFSYS_PROBE(fail4);
630 	EFSYS_KMEM_FREE(enp->en_esip,
631 	    encp->enc_mcdi_sensor_mask_size,
632 	    encp->enc_mcdi_sensor_maskp);
633 
634 fail3:
635 	EFSYS_PROBE(fail3);
636 
637 fail2:
638 	EFSYS_PROBE(fail2);
639 
640 fail1:
641 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
642 
643 	return (rc);
644 }
645 
646 			void
647 mcdi_mon_cfg_free(
648 	__in		efx_nic_t *enp)
649 {
650 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
651 
652 	if (encp->enc_mcdi_sensor_maskp != NULL) {
653 		EFSYS_KMEM_FREE(enp->en_esip,
654 		    encp->enc_mcdi_sensor_mask_size,
655 		    encp->enc_mcdi_sensor_maskp);
656 	}
657 }
658 
659 
660 #endif	/* EFSYS_OPT_MON_STATS */
661 
662 #endif	/* EFSYS_OPT_MON_MCDI */
663