68bbc575dc190eb00e5c138902f5ffb3deade026
[dpdk.git] / drivers / net / sfc / base / mcdi_mon.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright (c) 2009-2018 Solarflare Communications Inc.
4  * All rights reserved.
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 /* Get port mask from one-based MCDI port number */
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
22 static                                          void
23 mcdi_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         /* 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);
45
46         sensor_max = 8 * sensor_mask_size;
47
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);
50
51         memset(stat_mask, 0, sizeof (stat_mask));
52
53         /*
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
58          * flag.
59          *
60          * sensor_mask may legitimately contain MCDI sensors that the driver
61          * does not understand.
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                 boolean_t decode_ok;
67                 efx_mon_stat_unit_t stat_unit;
68
69                 if ((sensor % (MC_CMD_SENSOR_PAGE0_NEXT + 1)) ==
70                     MC_CMD_SENSOR_PAGE0_NEXT) {
71                         page++;
72                         continue;
73                         /* This sensor is one of the page boundary bits. */
74                 }
75
76                 if (~(sensor_mask[page]) & (1U << sensor))
77                         continue;
78                 /* This sensor not in DMA buffer */
79
80                 idx++;
81                 /*
82                  * Valid stat in DMA buffer that we need to increment over, even
83                  * if we couldn't look up the id
84                  */
85
86                 decode_ok = efx_mon_mcdi_to_efx_stat(sensor, &id);
87                 decode_ok =
88                     decode_ok && efx_mon_get_stat_portmap(id, &stat_portmask);
89
90                 if (!(decode_ok && (stat_portmask & port_mask)))
91                         continue;
92                 /* Either bad decode, or don't know what port stat is on */
93
94                 EFSYS_ASSERT(id < EFX_MON_NSTATS);
95
96                 /*
97                  * stat_mask is a bitmask indexed by EFX_MON_* monitor statistic
98                  * identifiers from efx_mon_stat_t (without NEXT_PAGE bits).
99                  *
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
102                  * monitor statistic.
103                  */
104                 stat_mask[id / EFX_MON_MASK_ELEMENT_SIZE] |=
105                     (1U << (id % EFX_MON_MASK_ELEMENT_SIZE));
106
107                 if (stat != NULL && esmp != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
108                         efx_dword_t dword;
109
110                         /* Get MCDI sensor reading from DMA buffer */
111                         EFSYS_MEM_READD(esmp, 4 * (idx - 1), &dword);
112
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);
116
117                         stat[id].emsv_state = (uint16_t)EFX_DWORD_FIELD(dword,
118                             MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE);
119
120                         stat[id].emsv_unit =
121                             efx_mon_get_stat_unit(id, &stat_unit) ?
122                             stat_unit : EFX_MON_STAT_UNIT_UNKNOWN;
123                 }
124         }
125
126         if (stat_maskp != NULL) {
127                 memcpy(stat_maskp, stat_mask, sizeof (stat_mask));
128         }
129 }
130
131         __checkReturn                   efx_rc_t
132 mcdi_mon_ev(
133         __in                            efx_nic_t *enp,
134         __in                            efx_qword_t *eqp,
135         __out                           efx_mon_stat_t *idp,
136         __out                           efx_mon_stat_value_t *valuep)
137 {
138         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
139         efx_mon_stat_portmask_t port_mask, sensor_port_mask;
140         uint16_t sensor;
141         uint16_t state;
142         uint16_t value;
143         efx_mon_stat_t id;
144         efx_rc_t rc;
145
146         EFSYS_ASSERT(emip->emi_port > 0); /* MCDI port number is one-based */
147         port_mask = MCDI_MON_PORT_MASK(emip);
148
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);
152
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);
162
163         /* And we need to understand it, to get port-map */
164         if (!efx_mon_mcdi_to_efx_stat(sensor, &id)) {
165                 rc = ENOTSUP;
166                 goto fail1;
167         }
168         if (!(efx_mon_get_stat_portmap(id, &sensor_port_mask) &&
169                 (port_mask && sensor_port_mask))) {
170                 return (ENODEV);
171         }
172         EFSYS_ASSERT(id < EFX_MON_NSTATS);
173
174         *idp = id;
175         valuep->emsv_value = value;
176         valuep->emsv_state = state;
177
178         return (0);
179
180 fail1:
181         EFSYS_PROBE1(fail1, efx_rc_t, rc);
182
183         return (rc);
184 }
185
186
187 static  __checkReturn   efx_rc_t
188 efx_mcdi_read_sensors(
189         __in            efx_nic_t *enp,
190         __in            efsys_mem_t *esmp,
191         __in            uint32_t size)
192 {
193         efx_mcdi_req_t req;
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;
197         efx_rc_t rc;
198
199         if (EFSYS_MEM_SIZE(esmp) < size) {
200                 rc = EINVAL;
201                 goto fail1;
202         }
203
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;
209
210         addr_lo = (uint32_t)(EFSYS_MEM_ADDR(esmp) & 0xffffffff);
211         addr_hi = (uint32_t)(EFSYS_MEM_ADDR(esmp) >> 32);
212
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);
216
217         efx_mcdi_execute(enp, &req);
218
219         return (req.emr_rc);
220
221 fail1:
222         EFSYS_PROBE1(fail1, efx_rc_t, rc);
223
224         return (rc);
225 }
226
227 static  __checkReturn   efx_rc_t
228 efx_mcdi_sensor_info_npages(
229         __in            efx_nic_t *enp,
230         __out           uint32_t *npagesp)
231 {
232         efx_mcdi_req_t req;
233         uint8_t payload[MAX(MC_CMD_SENSOR_INFO_EXT_IN_LEN,
234                             MC_CMD_SENSOR_INFO_OUT_LENMAX)];
235         int page;
236         efx_rc_t rc;
237
238         EFSYS_ASSERT(npagesp != NULL);
239
240         page = 0;
241         do {
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;
248
249                 MCDI_IN_SET_DWORD(req, SENSOR_INFO_EXT_IN_PAGE, page++);
250
251                 efx_mcdi_execute_quiet(enp, &req);
252
253                 if (req.emr_rc != 0) {
254                         rc = req.emr_rc;
255                         goto fail1;
256                 }
257         } while (MCDI_OUT_DWORD(req, SENSOR_INFO_OUT_MASK) &
258             (1U << MC_CMD_SENSOR_PAGE0_NEXT));
259
260         *npagesp = page;
261
262         return (0);
263
264 fail1:
265         EFSYS_PROBE1(fail1, efx_rc_t, rc);
266
267         return (rc);
268 }
269
270 static  __checkReturn           efx_rc_t
271 efx_mcdi_sensor_info(
272         __in                    efx_nic_t *enp,
273         __out_ecount(npages)    uint32_t *sensor_maskp,
274         __in                    size_t npages)
275 {
276         efx_mcdi_req_t req;
277         uint8_t payload[MAX(MC_CMD_SENSOR_INFO_EXT_IN_LEN,
278                             MC_CMD_SENSOR_INFO_OUT_LENMAX)];
279         uint32_t page;
280         efx_rc_t rc;
281
282         EFSYS_ASSERT(sensor_maskp != NULL);
283
284         if (npages < 1) {
285                 rc = EINVAL;
286                 goto fail1;
287         }
288
289         for (page = 0; page < npages; page++) {
290                 uint32_t mask;
291
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;
298
299                 MCDI_IN_SET_DWORD(req, SENSOR_INFO_EXT_IN_PAGE, page);
300
301                 efx_mcdi_execute(enp, &req);
302
303                 if (req.emr_rc != 0) {
304                         rc = req.emr_rc;
305                         goto fail2;
306                 }
307
308                 mask = MCDI_OUT_DWORD(req, SENSOR_INFO_OUT_MASK);
309
310                 if ((page != (npages - 1)) &&
311                     ((mask & (1U << MC_CMD_SENSOR_PAGE0_NEXT)) == 0)) {
312                         rc = EINVAL;
313                         goto fail3;
314                 }
315                 sensor_maskp[page] = mask;
316         }
317
318         if (sensor_maskp[npages - 1] & (1U << MC_CMD_SENSOR_PAGE0_NEXT)) {
319                 rc = EINVAL;
320                 goto fail4;
321         }
322
323         return (0);
324
325 fail4:
326         EFSYS_PROBE(fail4);
327 fail3:
328         EFSYS_PROBE(fail3);
329 fail2:
330         EFSYS_PROBE(fail2);
331 fail1:
332         EFSYS_PROBE1(fail1, efx_rc_t, rc);
333
334         return (rc);
335 }
336
337         __checkReturn                   efx_rc_t
338 mcdi_mon_stats_update(
339         __in                            efx_nic_t *enp,
340         __in                            efsys_mem_t *esmp,
341         __inout_ecount(EFX_MON_NSTATS)  efx_mon_stat_value_t *values)
342 {
343         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
344         uint32_t size = encp->enc_mon_stat_dma_buf_size;
345         efx_rc_t rc;
346
347         if ((rc = efx_mcdi_read_sensors(enp, esmp, size)) != 0)
348                 goto fail1;
349
350         EFSYS_DMA_SYNC_FOR_KERNEL(esmp, 0, size);
351
352         mcdi_mon_decode_stats(enp,
353             encp->enc_mcdi_sensor_maskp,
354             encp->enc_mcdi_sensor_mask_size,
355             esmp, NULL, values);
356
357         return (0);
358
359 fail1:
360         EFSYS_PROBE1(fail1, efx_rc_t, rc);
361
362         return (rc);
363 }
364
365         __checkReturn   efx_rc_t
366 mcdi_mon_cfg_build(
367         __in            efx_nic_t *enp)
368 {
369         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
370         uint32_t npages;
371         efx_rc_t rc;
372
373         switch (enp->en_family) {
374 #if EFSYS_OPT_SIENA
375         case EFX_FAMILY_SIENA:
376                 encp->enc_mon_type = EFX_MON_SFC90X0;
377                 break;
378 #endif
379 #if EFSYS_OPT_HUNTINGTON
380         case EFX_FAMILY_HUNTINGTON:
381                 encp->enc_mon_type = EFX_MON_SFC91X0;
382                 break;
383 #endif
384 #if EFSYS_OPT_MEDFORD
385         case EFX_FAMILY_MEDFORD:
386                 encp->enc_mon_type = EFX_MON_SFC92X0;
387                 break;
388 #endif
389 #if EFSYS_OPT_MEDFORD2
390         case EFX_FAMILY_MEDFORD2:
391                 encp->enc_mon_type = EFX_MON_SFC92X0;
392                 break;
393 #endif
394         default:
395                 rc = EINVAL;
396                 goto fail1;
397         }
398
399         /* Get mc sensor mask size */
400         npages = 0;
401         if ((rc = efx_mcdi_sensor_info_npages(enp, &npages)) != 0)
402                 goto fail2;
403
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);
406
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);
411
412         if (encp->enc_mcdi_sensor_maskp == NULL) {
413                 rc = ENOMEM;
414                 goto fail3;
415         }
416
417         /* Read mc sensor mask */
418         if ((rc = efx_mcdi_sensor_info(enp,
419                     encp->enc_mcdi_sensor_maskp,
420                     npages)) != 0)
421                 goto fail4;
422
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);
428
429         return (0);
430
431 fail4:
432         EFSYS_PROBE(fail4);
433         EFSYS_KMEM_FREE(enp->en_esip,
434             encp->enc_mcdi_sensor_mask_size,
435             encp->enc_mcdi_sensor_maskp);
436
437 fail3:
438         EFSYS_PROBE(fail3);
439
440 fail2:
441         EFSYS_PROBE(fail2);
442
443 fail1:
444         EFSYS_PROBE1(fail1, efx_rc_t, rc);
445
446         return (rc);
447 }
448
449                         void
450 mcdi_mon_cfg_free(
451         __in            efx_nic_t *enp)
452 {
453         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
454
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);
459         }
460 }
461
462
463 #endif  /* EFSYS_OPT_MON_STATS */
464
465 #endif  /* EFSYS_OPT_MON_MCDI */