1
2
3
4
5
6
7#include "efx.h"
8#include "efx_impl.h"
9#include "mcdi_mon.h"
10
11#if EFSYS_OPT_MON_MCDI
12
13#if EFSYS_OPT_MON_STATS
14
15
16#define MCDI_MON_PORT_MASK(_emip) (1U << ((_emip)->emi_port - 1))
17
18#define MCDI_STATIC_SENSOR_ASSERT(_field) \
19 EFX_STATIC_ASSERT(MC_CMD_SENSOR_STATE_ ## _field \
20 == EFX_MON_STAT_STATE_ ## _field)
21
22static void
23mcdi_mon_decode_stats(
24 __in efx_nic_t *enp,
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)
30{
31 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
32 efx_mon_stat_portmask_t port_mask;
33 uint16_t sensor;
34 size_t sensor_max;
35 uint32_t stat_mask[(EFX_MON_NSTATS + 31) / 32];
36 uint32_t idx = 0;
37 uint32_t page = 0;
38
39
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);
45
46 sensor_max = 8 * sensor_mask_size;
47
48 EFSYS_ASSERT(emip->emi_port > 0);
49 port_mask = (efx_mon_stat_portmask_t)MCDI_MON_PORT_MASK(emip);
50
51 memset(stat_mask, 0, sizeof (stat_mask));
52
53
54
55
56
57
58
59
60
61
62
63 for (sensor = 0; sensor < sensor_max; ++sensor) {
64 efx_mon_stat_t id;
65 efx_mon_stat_portmask_t stat_portmask = 0;
66 efx_mon_stat_unit_t stat_unit;
67
68 if ((sensor % (MC_CMD_SENSOR_PAGE0_NEXT + 1)) ==
69 MC_CMD_SENSOR_PAGE0_NEXT) {
70
71 page++;
72 continue;
73 }
74
75 if (~(sensor_mask[page]) &
76 (1U << (sensor % (sizeof (sensor_mask[page]) * 8)))) {
77
78 continue;
79 }
80
81
82 idx++;
83
84 if ((efx_mon_mcdi_to_efx_stat(sensor, &id) != B_TRUE) ||
85 (efx_mon_get_stat_portmap(id, &stat_portmask) != B_TRUE)) {
86
87 continue;
88 }
89
90 if ((stat_portmask & port_mask) == 0) {
91
92 continue;
93 }
94
95 EFSYS_ASSERT(id < EFX_MON_NSTATS);
96
97
98
99
100
101
102
103
104
105 stat_mask[id / EFX_MON_MASK_ELEMENT_SIZE] |=
106 (1U << (id % EFX_MON_MASK_ELEMENT_SIZE));
107
108 if (stat != NULL && esmp != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
109 efx_dword_t dword;
110
111
112 EFSYS_MEM_READD(esmp, 4 * (idx - 1), &dword);
113
114
115 stat[id].emsv_value = (uint16_t)EFX_DWORD_FIELD(dword,
116 MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_VALUE);
117
118 stat[id].emsv_state = (uint16_t)EFX_DWORD_FIELD(dword,
119 MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE);
120
121 stat[id].emsv_unit =
122 efx_mon_get_stat_unit(id, &stat_unit) ?
123 stat_unit : EFX_MON_STAT_UNIT_UNKNOWN;
124 }
125 }
126
127 if (stat_maskp != NULL) {
128 memcpy(stat_maskp, stat_mask, sizeof (stat_mask));
129 }
130}
131
132 __checkReturn efx_rc_t
133mcdi_mon_ev(
134 __in efx_nic_t *enp,
135 __in efx_qword_t *eqp,
136 __out efx_mon_stat_t *idp,
137 __out efx_mon_stat_value_t *valuep)
138{
139 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
140 efx_mon_stat_portmask_t port_mask, sensor_port_mask;
141 uint16_t sensor;
142 uint16_t state;
143 uint16_t value;
144 efx_mon_stat_t id;
145 efx_rc_t rc;
146
147 EFSYS_ASSERT(emip->emi_port > 0);
148 port_mask = MCDI_MON_PORT_MASK(emip);
149
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);
153
154
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);
163
164
165 if (!efx_mon_mcdi_to_efx_stat(sensor, &id)) {
166 rc = ENOTSUP;
167 goto fail1;
168 }
169 if (!(efx_mon_get_stat_portmap(id, &sensor_port_mask) &&
170 (port_mask && sensor_port_mask))) {
171 return (ENODEV);
172 }
173 EFSYS_ASSERT(id < EFX_MON_NSTATS);
174
175 *idp = id;
176 valuep->emsv_value = value;
177 valuep->emsv_state = state;
178
179 return (0);
180
181fail1:
182 EFSYS_PROBE1(fail1, efx_rc_t, rc);
183
184 return (rc);
185}
186
187
188static __checkReturn efx_rc_t
189efx_mcdi_read_sensors(
190 __in efx_nic_t *enp,
191 __in efsys_mem_t *esmp,
192 __in uint32_t size)
193{
194 efx_mcdi_req_t req;
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;
198 efx_rc_t rc;
199
200 if (EFSYS_MEM_SIZE(esmp) < size) {
201 rc = EINVAL;
202 goto fail1;
203 }
204
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;
210
211 addr_lo = (uint32_t)(EFSYS_MEM_ADDR(esmp) & 0xffffffff);
212 addr_hi = (uint32_t)(EFSYS_MEM_ADDR(esmp) >> 32);
213
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);
217
218 efx_mcdi_execute(enp, &req);
219
220 return (req.emr_rc);
221
222fail1:
223 EFSYS_PROBE1(fail1, efx_rc_t, rc);
224
225 return (rc);
226}
227
228static __checkReturn efx_rc_t
229efx_mcdi_sensor_info_npages(
230 __in efx_nic_t *enp,
231 __out uint32_t *npagesp)
232{
233 efx_mcdi_req_t req;
234 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SENSOR_INFO_EXT_IN_LEN,
235 MC_CMD_SENSOR_INFO_OUT_LENMAX);
236 int page;
237 efx_rc_t rc;
238
239 EFSYS_ASSERT(npagesp != NULL);
240
241 page = 0;
242 do {
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;
249
250 MCDI_IN_SET_DWORD(req, SENSOR_INFO_EXT_IN_PAGE, page++);
251
252 efx_mcdi_execute_quiet(enp, &req);
253
254 if (req.emr_rc != 0) {
255 rc = req.emr_rc;
256 goto fail1;
257 }
258 } while (MCDI_OUT_DWORD(req, SENSOR_INFO_OUT_MASK) &
259 (1U << MC_CMD_SENSOR_PAGE0_NEXT));
260
261 *npagesp = page;
262
263 return (0);
264
265fail1:
266 EFSYS_PROBE1(fail1, efx_rc_t, rc);
267
268 return (rc);
269}
270
271static __checkReturn efx_rc_t
272efx_mcdi_sensor_info(
273 __in efx_nic_t *enp,
274 __out_ecount(npages) uint32_t *sensor_maskp,
275 __in size_t npages)
276{
277 efx_mcdi_req_t req;
278 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SENSOR_INFO_EXT_IN_LEN,
279 MC_CMD_SENSOR_INFO_OUT_LENMAX);
280 uint32_t page;
281 efx_rc_t rc;
282
283 EFSYS_ASSERT(sensor_maskp != NULL);
284
285 if (npages < 1) {
286 rc = EINVAL;
287 goto fail1;
288 }
289
290 for (page = 0; page < npages; page++) {
291 uint32_t mask;
292
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;
299
300 MCDI_IN_SET_DWORD(req, SENSOR_INFO_EXT_IN_PAGE, page);
301
302 efx_mcdi_execute(enp, &req);
303
304 if (req.emr_rc != 0) {
305 rc = req.emr_rc;
306 goto fail2;
307 }
308
309 mask = MCDI_OUT_DWORD(req, SENSOR_INFO_OUT_MASK);
310
311 if ((page != (npages - 1)) &&
312 ((mask & (1U << MC_CMD_SENSOR_PAGE0_NEXT)) == 0)) {
313 rc = EINVAL;
314 goto fail3;
315 }
316 sensor_maskp[page] = mask;
317 }
318
319 if (sensor_maskp[npages - 1] & (1U << MC_CMD_SENSOR_PAGE0_NEXT)) {
320 rc = EINVAL;
321 goto fail4;
322 }
323
324 return (0);
325
326fail4:
327 EFSYS_PROBE(fail4);
328fail3:
329 EFSYS_PROBE(fail3);
330fail2:
331 EFSYS_PROBE(fail2);
332fail1:
333 EFSYS_PROBE1(fail1, efx_rc_t, rc);
334
335 return (rc);
336}
337
338static __checkReturn efx_rc_t
339efx_mcdi_sensor_info_page(
340 __in efx_nic_t *enp,
341 __in uint32_t page,
342 __out uint32_t *mask_part,
343 __out_ecount((sizeof (*mask_part) * 8) - 1)
344 efx_mon_stat_limits_t *limits)
345{
346 efx_mcdi_req_t req;
347 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SENSOR_INFO_EXT_IN_LEN,
348 MC_CMD_SENSOR_INFO_OUT_LENMAX);
349 efx_rc_t rc;
350 uint32_t mask_copy;
351 efx_dword_t *maskp;
352 efx_qword_t *limit_info;
353
354 EFSYS_ASSERT(mask_part != NULL);
355 EFSYS_ASSERT(limits != NULL);
356
357 memset(limits, 0,
358 ((sizeof (*mask_part) * 8) - 1) * sizeof (efx_mon_stat_limits_t));
359
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;
365
366 MCDI_IN_SET_DWORD(req, SENSOR_INFO_EXT_IN_PAGE, page);
367
368 efx_mcdi_execute(enp, &req);
369
370 rc = req.emr_rc;
371
372 if (rc != 0)
373 goto fail1;
374
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);
379
380 *mask_part = maskp->ed_u32[0];
381 mask_copy = *mask_part;
382
383
384 while (mask_copy) {
385
386 if (mask_copy == (1U << MC_CMD_SENSOR_PAGE0_NEXT)) {
387
388 mask_copy = 0;
389 } else {
390
391 mask_copy = mask_copy & ~(mask_copy ^ (mask_copy - 1));
392
393 limits->emlv_warning_min = EFX_QWORD_FIELD(*limit_info,
394 MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_MIN1);
395
396 limits->emlv_warning_max = EFX_QWORD_FIELD(*limit_info,
397 MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_MAX1);
398
399 limits->emlv_fatal_min = EFX_QWORD_FIELD(*limit_info,
400 MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_MIN2);
401
402 limits->emlv_fatal_max = EFX_QWORD_FIELD(*limit_info,
403 MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF_MAX2);
404
405 limits++;
406 limit_info++;
407 }
408 }
409
410 return (rc);
411
412fail1:
413 EFSYS_PROBE1(fail1, efx_rc_t, rc);
414
415 return (rc);
416}
417
418 __checkReturn efx_rc_t
419mcdi_mon_stats_update(
420 __in efx_nic_t *enp,
421 __in efsys_mem_t *esmp,
422 __inout_ecount(EFX_MON_NSTATS) efx_mon_stat_value_t *values)
423{
424 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
425 uint32_t size = encp->enc_mon_stat_dma_buf_size;
426 efx_rc_t rc;
427
428 if ((rc = efx_mcdi_read_sensors(enp, esmp, size)) != 0)
429 goto fail1;
430
431 EFSYS_DMA_SYNC_FOR_KERNEL(esmp, 0, size);
432
433 mcdi_mon_decode_stats(enp,
434 encp->enc_mcdi_sensor_maskp,
435 encp->enc_mcdi_sensor_mask_size,
436 esmp, NULL, values);
437
438 return (0);
439
440fail1:
441 EFSYS_PROBE1(fail1, efx_rc_t, rc);
442
443 return (rc);
444}
445
446static void
447lowest_set_bit(
448 __in uint32_t input_mask,
449 __out uint32_t *lowest_bit_mask,
450 __out uint32_t *lowest_bit_num
451)
452{
453 uint32_t x;
454 uint32_t set_bit, bit_index;
455
456 x = (input_mask ^ (input_mask - 1));
457 set_bit = (x + 1) >> 1;
458 if (!set_bit)
459 set_bit = (1U << 31U);
460
461 bit_index = 0;
462 if (set_bit & 0xFFFF0000)
463 bit_index += 16;
464 if (set_bit & 0xFF00FF00)
465 bit_index += 8;
466 if (set_bit & 0xF0F0F0F0)
467 bit_index += 4;
468 if (set_bit & 0xCCCCCCCC)
469 bit_index += 2;
470 if (set_bit & 0xAAAAAAAA)
471 bit_index += 1;
472
473 *lowest_bit_mask = set_bit;
474 *lowest_bit_num = bit_index;
475}
476
477 __checkReturn efx_rc_t
478mcdi_mon_limits_update(
479 __in efx_nic_t *enp,
480 __inout_ecount(EFX_MON_NSTATS) efx_mon_stat_limits_t *values)
481{
482 efx_rc_t rc;
483 uint32_t page;
484 uint32_t page_mask;
485 uint32_t limit_index;
486 efx_mon_stat_limits_t limits[sizeof (page_mask) * 8];
487 efx_mon_stat_t stat;
488
489 page = 0;
490 page--;
491 do {
492 page++;
493
494 rc = efx_mcdi_sensor_info_page(enp, page, &page_mask, limits);
495 if (rc != 0)
496 goto fail1;
497
498 limit_index = 0;
499 while (page_mask) {
500 uint32_t set_bit;
501 uint32_t page_index;
502 uint32_t mcdi_index;
503
504 if (page_mask == (1U << MC_CMD_SENSOR_PAGE0_NEXT))
505 break;
506
507 lowest_set_bit(page_mask, &set_bit, &page_index);
508 page_mask = page_mask & ~set_bit;
509
510 mcdi_index =
511 page_index + (sizeof (page_mask) * 8 * page);
512
513
514
515
516
517
518
519 if (!efx_mon_mcdi_to_efx_stat(mcdi_index, &stat))
520 continue;
521
522 values[stat] = limits[limit_index];
523 limit_index++;
524 }
525
526 } while (page_mask & (1U << MC_CMD_SENSOR_PAGE0_NEXT));
527
528 return (rc);
529
530fail1:
531 EFSYS_PROBE1(fail1, efx_rc_t, rc);
532
533 return (rc);
534}
535
536 __checkReturn efx_rc_t
537mcdi_mon_cfg_build(
538 __in efx_nic_t *enp)
539{
540 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
541 uint32_t npages;
542 efx_rc_t rc;
543
544 switch (enp->en_family) {
545#if EFSYS_OPT_SIENA
546 case EFX_FAMILY_SIENA:
547 encp->enc_mon_type = EFX_MON_SFC90X0;
548 break;
549#endif
550#if EFSYS_OPT_HUNTINGTON
551 case EFX_FAMILY_HUNTINGTON:
552 encp->enc_mon_type = EFX_MON_SFC91X0;
553 break;
554#endif
555#if EFSYS_OPT_MEDFORD
556 case EFX_FAMILY_MEDFORD:
557 encp->enc_mon_type = EFX_MON_SFC92X0;
558 break;
559#endif
560#if EFSYS_OPT_MEDFORD2
561 case EFX_FAMILY_MEDFORD2:
562 encp->enc_mon_type = EFX_MON_SFC92X0;
563 break;
564#endif
565 default:
566 rc = EINVAL;
567 goto fail1;
568 }
569
570
571 npages = 0;
572 if ((rc = efx_mcdi_sensor_info_npages(enp, &npages)) != 0)
573 goto fail2;
574
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);
577
578
579 EFSYS_KMEM_ALLOC(enp->en_esip,
580 encp->enc_mcdi_sensor_mask_size,
581 encp->enc_mcdi_sensor_maskp);
582
583 if (encp->enc_mcdi_sensor_maskp == NULL) {
584 rc = ENOMEM;
585 goto fail3;
586 }
587
588
589 if ((rc = efx_mcdi_sensor_info(enp,
590 encp->enc_mcdi_sensor_maskp,
591 npages)) != 0)
592 goto fail4;
593
594
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);
599
600 return (0);
601
602fail4:
603 EFSYS_PROBE(fail4);
604 EFSYS_KMEM_FREE(enp->en_esip,
605 encp->enc_mcdi_sensor_mask_size,
606 encp->enc_mcdi_sensor_maskp);
607
608fail3:
609 EFSYS_PROBE(fail3);
610
611fail2:
612 EFSYS_PROBE(fail2);
613
614fail1:
615 EFSYS_PROBE1(fail1, efx_rc_t, rc);
616
617 return (rc);
618}
619
620 void
621mcdi_mon_cfg_free(
622 __in efx_nic_t *enp)
623{
624 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
625
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);
630 }
631}
632
633
634#endif
635
636#endif
637