93e6b1e358dbf04f7d60c9821678df7dd9e63cd1
[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
198         req.emr_cmd = MC_CMD_READ_SENSORS;
199         req.emr_in_buf = payload;
200         req.emr_in_length = MC_CMD_READ_SENSORS_EXT_IN_LEN;
201         req.emr_out_buf = payload;
202         req.emr_out_length = MC_CMD_READ_SENSORS_EXT_OUT_LEN;
203
204         addr_lo = (uint32_t)(EFSYS_MEM_ADDR(esmp) & 0xffffffff);
205         addr_hi = (uint32_t)(EFSYS_MEM_ADDR(esmp) >> 32);
206
207         MCDI_IN_SET_DWORD(req, READ_SENSORS_EXT_IN_DMA_ADDR_LO, addr_lo);
208         MCDI_IN_SET_DWORD(req, READ_SENSORS_EXT_IN_DMA_ADDR_HI, addr_hi);
209         MCDI_IN_SET_DWORD(req, READ_SENSORS_EXT_IN_LENGTH, size);
210
211         efx_mcdi_execute(enp, &req);
212
213         return (req.emr_rc);
214 }
215
216 static  __checkReturn   efx_rc_t
217 efx_mcdi_sensor_info_npages(
218         __in            efx_nic_t *enp,
219         __out           uint32_t *npagesp)
220 {
221         efx_mcdi_req_t req;
222         uint8_t payload[MAX(MC_CMD_SENSOR_INFO_EXT_IN_LEN,
223                             MC_CMD_SENSOR_INFO_OUT_LENMAX)];
224         int page;
225         efx_rc_t rc;
226
227         EFSYS_ASSERT(npagesp != NULL);
228
229         page = 0;
230         do {
231                 (void) memset(payload, 0, sizeof (payload));
232                 req.emr_cmd = MC_CMD_SENSOR_INFO;
233                 req.emr_in_buf = payload;
234                 req.emr_in_length = MC_CMD_SENSOR_INFO_EXT_IN_LEN;
235                 req.emr_out_buf = payload;
236                 req.emr_out_length = MC_CMD_SENSOR_INFO_OUT_LENMAX;
237
238                 MCDI_IN_SET_DWORD(req, SENSOR_INFO_EXT_IN_PAGE, page++);
239
240                 efx_mcdi_execute_quiet(enp, &req);
241
242                 if (req.emr_rc != 0) {
243                         rc = req.emr_rc;
244                         goto fail1;
245                 }
246         } while (MCDI_OUT_DWORD(req, SENSOR_INFO_OUT_MASK) &
247             (1U << MC_CMD_SENSOR_PAGE0_NEXT));
248
249         *npagesp = page;
250
251         return (0);
252
253 fail1:
254         EFSYS_PROBE1(fail1, efx_rc_t, rc);
255
256         return (rc);
257 }
258
259 static  __checkReturn           efx_rc_t
260 efx_mcdi_sensor_info(
261         __in                    efx_nic_t *enp,
262         __out_ecount(npages)    uint32_t *sensor_maskp,
263         __in                    size_t npages)
264 {
265         efx_mcdi_req_t req;
266         uint8_t payload[MAX(MC_CMD_SENSOR_INFO_EXT_IN_LEN,
267                             MC_CMD_SENSOR_INFO_OUT_LENMAX)];
268         uint32_t page;
269         efx_rc_t rc;
270
271         EFSYS_ASSERT(sensor_maskp != NULL);
272
273         if (npages < 1) {
274                 rc = EINVAL;
275                 goto fail1;
276         }
277
278         for (page = 0; page < npages; page++) {
279                 uint32_t mask;
280
281                 (void) memset(payload, 0, sizeof (payload));
282                 req.emr_cmd = MC_CMD_SENSOR_INFO;
283                 req.emr_in_buf = payload;
284                 req.emr_in_length = MC_CMD_SENSOR_INFO_EXT_IN_LEN;
285                 req.emr_out_buf = payload;
286                 req.emr_out_length = MC_CMD_SENSOR_INFO_OUT_LENMAX;
287
288                 MCDI_IN_SET_DWORD(req, SENSOR_INFO_EXT_IN_PAGE, page);
289
290                 efx_mcdi_execute(enp, &req);
291
292                 if (req.emr_rc != 0) {
293                         rc = req.emr_rc;
294                         goto fail2;
295                 }
296
297                 mask = MCDI_OUT_DWORD(req, SENSOR_INFO_OUT_MASK);
298
299                 if ((page != (npages - 1)) &&
300                     ((mask & (1U << MC_CMD_SENSOR_PAGE0_NEXT)) == 0)) {
301                         rc = EINVAL;
302                         goto fail3;
303                 }
304                 sensor_maskp[page] = mask;
305         }
306
307         if (sensor_maskp[npages - 1] & (1U << MC_CMD_SENSOR_PAGE0_NEXT)) {
308                 rc = EINVAL;
309                 goto fail4;
310         }
311
312         return (0);
313
314 fail4:
315         EFSYS_PROBE(fail4);
316 fail3:
317         EFSYS_PROBE(fail3);
318 fail2:
319         EFSYS_PROBE(fail2);
320 fail1:
321         EFSYS_PROBE1(fail1, efx_rc_t, rc);
322
323         return (rc);
324 }
325
326         __checkReturn                   efx_rc_t
327 mcdi_mon_stats_update(
328         __in                            efx_nic_t *enp,
329         __in                            efsys_mem_t *esmp,
330         __inout_ecount(EFX_MON_NSTATS)  efx_mon_stat_value_t *values)
331 {
332         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
333         uint32_t size = encp->enc_mon_stat_dma_buf_size;
334         efx_rc_t rc;
335
336         if ((rc = efx_mcdi_read_sensors(enp, esmp, size)) != 0)
337                 goto fail1;
338
339         EFSYS_DMA_SYNC_FOR_KERNEL(esmp, 0, size);
340
341         mcdi_mon_decode_stats(enp,
342             encp->enc_mcdi_sensor_maskp,
343             encp->enc_mcdi_sensor_mask_size,
344             esmp, NULL, values);
345
346         return (0);
347
348 fail1:
349         EFSYS_PROBE1(fail1, efx_rc_t, rc);
350
351         return (rc);
352 }
353
354         __checkReturn   efx_rc_t
355 mcdi_mon_cfg_build(
356         __in            efx_nic_t *enp)
357 {
358         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
359         uint32_t npages;
360         efx_rc_t rc;
361
362         switch (enp->en_family) {
363 #if EFSYS_OPT_SIENA
364         case EFX_FAMILY_SIENA:
365                 encp->enc_mon_type = EFX_MON_SFC90X0;
366                 break;
367 #endif
368 #if EFSYS_OPT_HUNTINGTON
369         case EFX_FAMILY_HUNTINGTON:
370                 encp->enc_mon_type = EFX_MON_SFC91X0;
371                 break;
372 #endif
373 #if EFSYS_OPT_MEDFORD
374         case EFX_FAMILY_MEDFORD:
375                 encp->enc_mon_type = EFX_MON_SFC92X0;
376                 break;
377 #endif
378 #if EFSYS_OPT_MEDFORD2
379         case EFX_FAMILY_MEDFORD2:
380                 encp->enc_mon_type = EFX_MON_SFC92X0;
381                 break;
382 #endif
383         default:
384                 rc = EINVAL;
385                 goto fail1;
386         }
387
388         /* Get mc sensor mask size */
389         npages = 0;
390         if ((rc = efx_mcdi_sensor_info_npages(enp, &npages)) != 0)
391                 goto fail2;
392
393         encp->enc_mon_stat_dma_buf_size = npages * EFX_MON_STATS_PAGE_SIZE;
394         encp->enc_mcdi_sensor_mask_size = npages * sizeof (uint32_t);
395
396         /* Allocate mc sensor mask */
397         EFSYS_KMEM_ALLOC(enp->en_esip,
398             encp->enc_mcdi_sensor_mask_size,
399             encp->enc_mcdi_sensor_maskp);
400
401         if (encp->enc_mcdi_sensor_maskp == NULL) {
402                 rc = ENOMEM;
403                 goto fail3;
404         }
405
406         /* Read mc sensor mask */
407         if ((rc = efx_mcdi_sensor_info(enp,
408                     encp->enc_mcdi_sensor_maskp,
409                     npages)) != 0)
410                 goto fail4;
411
412         /* Build monitor statistics mask */
413         mcdi_mon_decode_stats(enp,
414             encp->enc_mcdi_sensor_maskp,
415             encp->enc_mcdi_sensor_mask_size,
416             NULL, encp->enc_mon_stat_mask, NULL);
417
418         return (0);
419
420 fail4:
421         EFSYS_PROBE(fail4);
422         EFSYS_KMEM_FREE(enp->en_esip,
423             encp->enc_mcdi_sensor_mask_size,
424             encp->enc_mcdi_sensor_maskp);
425
426 fail3:
427         EFSYS_PROBE(fail3);
428
429 fail2:
430         EFSYS_PROBE(fail2);
431
432 fail1:
433         EFSYS_PROBE1(fail1, efx_rc_t, rc);
434
435         return (rc);
436 }
437
438                         void
439 mcdi_mon_cfg_free(
440         __in            efx_nic_t *enp)
441 {
442         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
443
444         if (encp->enc_mcdi_sensor_maskp != NULL) {
445                 EFSYS_KMEM_FREE(enp->en_esip,
446                     encp->enc_mcdi_sensor_mask_size,
447                     encp->enc_mcdi_sensor_maskp);
448         }
449 }
450
451
452 #endif  /* EFSYS_OPT_MON_STATS */
453
454 #endif  /* EFSYS_OPT_MON_MCDI */