7a3f59a1123da1683ace15f3b7ef540f5d7fbca4
[dpdk.git] / drivers / net / sfc / sfc_port.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2019-2021 Xilinx, Inc.
4  * Copyright(c) 2016-2019 Solarflare Communications Inc.
5  *
6  * This software was jointly developed between OKTET Labs (under contract
7  * for Solarflare) and Solarflare Communications, Inc.
8  */
9
10 #include <rte_bitmap.h>
11
12 #include "efx.h"
13
14 #include "sfc.h"
15 #include "sfc_debug.h"
16 #include "sfc_log.h"
17 #include "sfc_kvargs.h"
18
19 /** Default MAC statistics update period is 1 second */
20 #define SFC_MAC_STATS_UPDATE_PERIOD_MS_DEF      MS_PER_S
21
22 /** The number of microseconds to sleep on attempt to get statistics update */
23 #define SFC_MAC_STATS_UPDATE_RETRY_INTERVAL_US  10
24
25 /** The number of attempts to await arrival of freshly generated statistics */
26 #define SFC_MAC_STATS_UPDATE_NB_ATTEMPTS        50
27
28 /**
29  * Update MAC statistics in the buffer.
30  *
31  * @param       sa              Adapter
32  * @param       force_upload    Flag to upload MAC stats in any case
33  *
34  * @return Status code
35  * @retval      0       Success
36  * @retval      EAGAIN  Try again
37  * @retval      ENOMEM  Memory allocation failure
38  */
39 int
40 sfc_port_update_mac_stats(struct sfc_adapter *sa, boolean_t force_upload)
41 {
42         struct sfc_port *port = &sa->port;
43         efsys_mem_t *esmp = &port->mac_stats_dma_mem;
44         uint32_t *genp = NULL;
45         uint32_t gen_old;
46         unsigned int nb_attempts = 0;
47         int rc;
48
49         SFC_ASSERT(sfc_adapter_is_locked(sa));
50
51         if (sa->state != SFC_ETHDEV_STARTED)
52                 return 0;
53
54         /*
55          * If periodic statistics DMA'ing is off or if not supported,
56          * make a manual request and keep an eye on timer if need be
57          */
58         if (!port->mac_stats_periodic_dma_supported ||
59             (port->mac_stats_update_period_ms == 0) || force_upload) {
60                 if (port->mac_stats_update_period_ms != 0) {
61                         uint64_t timestamp = sfc_get_system_msecs();
62
63                         if ((timestamp -
64                              port->mac_stats_last_request_timestamp) <
65                             port->mac_stats_update_period_ms)
66                                 return 0;
67
68                         port->mac_stats_last_request_timestamp = timestamp;
69                 }
70
71                 rc = efx_mac_stats_upload(sa->nic, esmp);
72                 if (rc != 0)
73                         return rc;
74
75                 genp = &port->mac_stats_update_generation;
76                 gen_old = *genp;
77         }
78
79         do {
80                 if (nb_attempts > 0)
81                         rte_delay_us(SFC_MAC_STATS_UPDATE_RETRY_INTERVAL_US);
82
83                 rc = efx_mac_stats_update(sa->nic, esmp,
84                                           port->mac_stats_buf, genp);
85                 if (rc != 0)
86                         return rc;
87
88         } while ((genp != NULL) && (*genp == gen_old) &&
89                  (++nb_attempts < SFC_MAC_STATS_UPDATE_NB_ATTEMPTS));
90
91         return 0;
92 }
93
94 static void
95 sfc_port_reset_sw_stats(struct sfc_adapter *sa)
96 {
97         struct sfc_port *port = &sa->port;
98
99         /*
100          * Reset diff stats explicitly since check which does not allow
101          * the statistics to grow backward could deny it.
102          */
103         port->ipackets = 0;
104 }
105
106 int
107 sfc_port_reset_mac_stats(struct sfc_adapter *sa)
108 {
109         int rc;
110
111         SFC_ASSERT(sfc_adapter_is_locked(sa));
112
113         rc = efx_mac_stats_clear(sa->nic);
114         if (rc == 0)
115                 sfc_port_reset_sw_stats(sa);
116
117         return rc;
118 }
119
120 static int
121 sfc_port_init_dev_link(struct sfc_adapter *sa)
122 {
123         struct rte_eth_link *dev_link = &sa->eth_dev->data->dev_link;
124         int rc;
125         efx_link_mode_t link_mode;
126         struct rte_eth_link current_link;
127
128         rc = efx_port_poll(sa->nic, &link_mode);
129         if (rc != 0)
130                 return rc;
131
132         sfc_port_link_mode_to_info(link_mode, &current_link);
133
134         EFX_STATIC_ASSERT(sizeof(*dev_link) == sizeof(rte_atomic64_t));
135         rte_atomic64_set((rte_atomic64_t *)dev_link,
136                          *(uint64_t *)&current_link);
137
138         return 0;
139 }
140
141 #if EFSYS_OPT_LOOPBACK
142
143 static efx_link_mode_t
144 sfc_port_phy_caps_to_max_link_speed(uint32_t phy_caps)
145 {
146         if (phy_caps & (1u << EFX_PHY_CAP_100000FDX))
147                 return EFX_LINK_100000FDX;
148         if (phy_caps & (1u << EFX_PHY_CAP_50000FDX))
149                 return EFX_LINK_50000FDX;
150         if (phy_caps & (1u << EFX_PHY_CAP_40000FDX))
151                 return EFX_LINK_40000FDX;
152         if (phy_caps & (1u << EFX_PHY_CAP_25000FDX))
153                 return EFX_LINK_25000FDX;
154         if (phy_caps & (1u << EFX_PHY_CAP_10000FDX))
155                 return EFX_LINK_10000FDX;
156         if (phy_caps & (1u << EFX_PHY_CAP_1000FDX))
157                 return EFX_LINK_1000FDX;
158         return EFX_LINK_UNKNOWN;
159 }
160
161 #endif
162
163 static void
164 sfc_port_fill_mac_stats_info(struct sfc_adapter *sa)
165 {
166         unsigned int mac_stats_nb_supported = 0;
167         struct sfc_port *port = &sa->port;
168         unsigned int stat_idx;
169
170         efx_mac_stats_get_mask(sa->nic, port->mac_stats_mask,
171                                sizeof(port->mac_stats_mask));
172
173         for (stat_idx = 0; stat_idx < EFX_MAC_NSTATS; ++stat_idx) {
174                 if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, stat_idx))
175                         continue;
176
177                 port->mac_stats_by_id[mac_stats_nb_supported] = stat_idx;
178                 mac_stats_nb_supported++;
179         }
180
181         port->mac_stats_nb_supported = mac_stats_nb_supported;
182 }
183
184 int
185 sfc_port_start(struct sfc_adapter *sa)
186 {
187         struct sfc_port *port = &sa->port;
188         int rc;
189         uint32_t phy_adv_cap;
190         const uint32_t phy_pause_caps =
191                 ((1u << EFX_PHY_CAP_PAUSE) | (1u << EFX_PHY_CAP_ASYM));
192
193         sfc_log_init(sa, "entry");
194
195         sfc_log_init(sa, "init filters");
196         rc = efx_filter_init(sa->nic);
197         if (rc != 0)
198                 goto fail_filter_init;
199
200         sfc_log_init(sa, "init port");
201         rc = efx_port_init(sa->nic);
202         if (rc != 0)
203                 goto fail_port_init;
204
205 #if EFSYS_OPT_LOOPBACK
206         if (sa->eth_dev->data->dev_conf.lpbk_mode != 0) {
207                 efx_link_mode_t link_mode;
208
209                 link_mode =
210                         sfc_port_phy_caps_to_max_link_speed(port->phy_adv_cap);
211                 sfc_log_init(sa, "set loopback link_mode=%u type=%u", link_mode,
212                              sa->eth_dev->data->dev_conf.lpbk_mode);
213                 rc = efx_port_loopback_set(sa->nic, link_mode,
214                         sa->eth_dev->data->dev_conf.lpbk_mode);
215                 if (rc != 0)
216                         goto fail_loopback_set;
217         }
218 #endif
219
220         sfc_log_init(sa, "set flow control to %#x autoneg=%u",
221                      port->flow_ctrl, port->flow_ctrl_autoneg);
222         rc = efx_mac_fcntl_set(sa->nic, port->flow_ctrl,
223                                port->flow_ctrl_autoneg);
224         if (rc != 0)
225                 goto fail_mac_fcntl_set;
226
227         /* Preserve pause capabilities set by above efx_mac_fcntl_set()  */
228         efx_phy_adv_cap_get(sa->nic, EFX_PHY_CAP_CURRENT, &phy_adv_cap);
229         SFC_ASSERT((port->phy_adv_cap & phy_pause_caps) == 0);
230         phy_adv_cap = port->phy_adv_cap | (phy_adv_cap & phy_pause_caps);
231
232         /*
233          * No controls for FEC yet. Use default FEC mode.
234          * I.e. advertise everything supported (*_FEC=1), but do not request
235          * anything explicitly (*_FEC_REQUESTED=0).
236          */
237         phy_adv_cap |= port->phy_adv_cap_mask &
238                 (1u << EFX_PHY_CAP_BASER_FEC |
239                  1u << EFX_PHY_CAP_RS_FEC |
240                  1u << EFX_PHY_CAP_25G_BASER_FEC);
241
242         sfc_log_init(sa, "set phy adv caps to %#x", phy_adv_cap);
243         rc = efx_phy_adv_cap_set(sa->nic, phy_adv_cap);
244         if (rc != 0)
245                 goto fail_phy_adv_cap_set;
246
247         sfc_log_init(sa, "set MAC PDU %u", (unsigned int)port->pdu);
248         rc = efx_mac_pdu_set(sa->nic, port->pdu);
249         if (rc != 0)
250                 goto fail_mac_pdu_set;
251
252         if (!sfc_sa2shared(sa)->isolated) {
253                 struct rte_ether_addr *addr = &port->default_mac_addr;
254
255                 sfc_log_init(sa, "set MAC address");
256                 rc = efx_mac_addr_set(sa->nic, addr->addr_bytes);
257                 if (rc != 0)
258                         goto fail_mac_addr_set;
259
260                 sfc_log_init(sa, "set MAC filters");
261                 port->promisc = (sa->eth_dev->data->promiscuous != 0) ?
262                                 B_TRUE : B_FALSE;
263                 port->allmulti = (sa->eth_dev->data->all_multicast != 0) ?
264                                  B_TRUE : B_FALSE;
265                 rc = sfc_set_rx_mode_unchecked(sa);
266                 if (rc != 0)
267                         goto fail_mac_filter_set;
268
269                 sfc_log_init(sa, "set multicast address list");
270                 rc = efx_mac_multicast_list_set(sa->nic, port->mcast_addrs,
271                                                 port->nb_mcast_addrs);
272                 if (rc != 0)
273                         goto fail_mcast_address_list_set;
274         }
275
276         if (port->mac_stats_reset_pending) {
277                 rc = sfc_port_reset_mac_stats(sa);
278                 if (rc != 0)
279                         sfc_err(sa, "statistics reset failed (requested "
280                                     "before the port was started)");
281
282                 port->mac_stats_reset_pending = B_FALSE;
283         }
284
285         sfc_port_fill_mac_stats_info(sa);
286
287         port->mac_stats_update_generation = 0;
288
289         if (port->mac_stats_update_period_ms != 0) {
290                 /*
291                  * Update MAC stats using periodic DMA;
292                  * any positive update interval different from
293                  * 1000 ms can be set only on SFN8xxx provided
294                  * that FW version is 6.2.1.1033 or higher
295                  */
296                 sfc_log_init(sa, "request MAC stats DMA'ing");
297                 rc = efx_mac_stats_periodic(sa->nic, &port->mac_stats_dma_mem,
298                                             port->mac_stats_update_period_ms,
299                                             B_FALSE);
300                 if (rc == 0) {
301                         port->mac_stats_periodic_dma_supported = B_TRUE;
302                 } else if (rc == EOPNOTSUPP) {
303                         port->mac_stats_periodic_dma_supported = B_FALSE;
304                         port->mac_stats_last_request_timestamp = 0;
305                 } else {
306                         goto fail_mac_stats_periodic;
307                 }
308         }
309
310         if ((port->mac_stats_update_period_ms != 0) &&
311             port->mac_stats_periodic_dma_supported) {
312                 /*
313                  * Request an explicit MAC stats upload immediately to
314                  * preclude bogus figures readback if the user decides
315                  * to read stats before periodic DMA is really started
316                  */
317                 rc = efx_mac_stats_upload(sa->nic, &port->mac_stats_dma_mem);
318                 if (rc != 0)
319                         goto fail_mac_stats_upload;
320         }
321
322         sfc_log_init(sa, "disable MAC drain");
323         rc = efx_mac_drain(sa->nic, B_FALSE);
324         if (rc != 0)
325                 goto fail_mac_drain;
326
327         /* Synchronize link status knowledge */
328         rc = sfc_port_init_dev_link(sa);
329         if (rc != 0)
330                 goto fail_port_init_dev_link;
331
332         sfc_log_init(sa, "done");
333         return 0;
334
335 fail_port_init_dev_link:
336         (void)efx_mac_drain(sa->nic, B_TRUE);
337
338 fail_mac_drain:
339 fail_mac_stats_upload:
340         (void)efx_mac_stats_periodic(sa->nic, &port->mac_stats_dma_mem,
341                                      0, B_FALSE);
342
343 fail_mac_stats_periodic:
344 fail_mcast_address_list_set:
345 fail_mac_filter_set:
346 fail_mac_addr_set:
347 fail_mac_pdu_set:
348 fail_phy_adv_cap_set:
349 fail_mac_fcntl_set:
350 #if EFSYS_OPT_LOOPBACK
351 fail_loopback_set:
352 #endif
353         efx_port_fini(sa->nic);
354
355 fail_port_init:
356         efx_filter_fini(sa->nic);
357
358 fail_filter_init:
359         sfc_log_init(sa, "failed %d", rc);
360         return rc;
361 }
362
363 void
364 sfc_port_stop(struct sfc_adapter *sa)
365 {
366         sfc_log_init(sa, "entry");
367
368         efx_mac_drain(sa->nic, B_TRUE);
369
370         (void)efx_mac_stats_periodic(sa->nic, &sa->port.mac_stats_dma_mem,
371                                      0, B_FALSE);
372
373         sfc_port_update_mac_stats(sa, B_TRUE);
374
375         efx_port_fini(sa->nic);
376         efx_filter_fini(sa->nic);
377
378         sfc_log_init(sa, "done");
379 }
380
381 int
382 sfc_port_configure(struct sfc_adapter *sa)
383 {
384         const struct rte_eth_dev_data *dev_data = sa->eth_dev->data;
385         struct sfc_port *port = &sa->port;
386         const struct rte_eth_rxmode *rxmode = &dev_data->dev_conf.rxmode;
387
388         sfc_log_init(sa, "entry");
389
390         if (rxmode->offloads & DEV_RX_OFFLOAD_JUMBO_FRAME)
391                 port->pdu = rxmode->max_rx_pkt_len;
392         else
393                 port->pdu = EFX_MAC_PDU(dev_data->mtu);
394
395         return 0;
396 }
397
398 void
399 sfc_port_close(struct sfc_adapter *sa)
400 {
401         sfc_log_init(sa, "entry");
402 }
403
404 int
405 sfc_port_attach(struct sfc_adapter *sa)
406 {
407         struct sfc_port *port = &sa->port;
408         const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
409         const struct rte_ether_addr *from;
410         uint32_t mac_nstats;
411         size_t mac_stats_size;
412         long kvarg_stats_update_period_ms;
413         int rc;
414
415         sfc_log_init(sa, "entry");
416
417         efx_phy_adv_cap_get(sa->nic, EFX_PHY_CAP_PERM, &port->phy_adv_cap_mask);
418
419         /* Enable flow control by default */
420         port->flow_ctrl = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
421         port->flow_ctrl_autoneg = B_TRUE;
422
423         RTE_BUILD_BUG_ON(sizeof(encp->enc_mac_addr) != sizeof(*from));
424         from = (const struct rte_ether_addr *)(encp->enc_mac_addr);
425         rte_ether_addr_copy(from, &port->default_mac_addr);
426
427         port->max_mcast_addrs = EFX_MAC_MULTICAST_LIST_MAX;
428         port->nb_mcast_addrs = 0;
429         port->mcast_addrs = rte_calloc_socket("mcast_addr_list_buf",
430                                               port->max_mcast_addrs,
431                                               EFX_MAC_ADDR_LEN, 0,
432                                               sa->socket_id);
433         if (port->mcast_addrs == NULL) {
434                 rc = ENOMEM;
435                 goto fail_mcast_addr_list_buf_alloc;
436         }
437
438         rc = ENOMEM;
439         port->mac_stats_buf = rte_calloc_socket("mac_stats_buf", EFX_MAC_NSTATS,
440                                                 sizeof(uint64_t), 0,
441                                                 sa->socket_id);
442         if (port->mac_stats_buf == NULL)
443                 goto fail_mac_stats_buf_alloc;
444
445         mac_nstats = efx_nic_cfg_get(sa->nic)->enc_mac_stats_nstats;
446         mac_stats_size = RTE_ALIGN(mac_nstats * sizeof(uint64_t), EFX_BUF_SIZE);
447         rc = sfc_dma_alloc(sa, "mac_stats", 0, mac_stats_size,
448                            sa->socket_id, &port->mac_stats_dma_mem);
449         if (rc != 0)
450                 goto fail_mac_stats_dma_alloc;
451
452         port->mac_stats_reset_pending = B_FALSE;
453
454         kvarg_stats_update_period_ms = SFC_MAC_STATS_UPDATE_PERIOD_MS_DEF;
455
456         rc = sfc_kvargs_process(sa, SFC_KVARG_STATS_UPDATE_PERIOD_MS,
457                                 sfc_kvarg_long_handler,
458                                 &kvarg_stats_update_period_ms);
459         if ((rc == 0) &&
460             ((kvarg_stats_update_period_ms < 0) ||
461              (kvarg_stats_update_period_ms > UINT16_MAX))) {
462                 sfc_err(sa, "wrong '" SFC_KVARG_STATS_UPDATE_PERIOD_MS "' "
463                             "was set (%ld);", kvarg_stats_update_period_ms);
464                 sfc_err(sa, "it must not be less than 0 "
465                             "or greater than %" PRIu16, UINT16_MAX);
466                 rc = EINVAL;
467                 goto fail_kvarg_stats_update_period_ms;
468         } else if (rc != 0) {
469                 goto fail_kvarg_stats_update_period_ms;
470         }
471
472         port->mac_stats_update_period_ms = kvarg_stats_update_period_ms;
473
474         sfc_log_init(sa, "done");
475         return 0;
476
477 fail_kvarg_stats_update_period_ms:
478         sfc_dma_free(sa, &port->mac_stats_dma_mem);
479
480 fail_mac_stats_dma_alloc:
481         rte_free(port->mac_stats_buf);
482
483 fail_mac_stats_buf_alloc:
484         rte_free(port->mcast_addrs);
485
486 fail_mcast_addr_list_buf_alloc:
487         sfc_log_init(sa, "failed %d", rc);
488         return rc;
489 }
490
491 void
492 sfc_port_detach(struct sfc_adapter *sa)
493 {
494         struct sfc_port *port = &sa->port;
495
496         sfc_log_init(sa, "entry");
497
498         sfc_dma_free(sa, &port->mac_stats_dma_mem);
499         rte_free(port->mac_stats_buf);
500
501         rte_free(port->mcast_addrs);
502
503         sfc_log_init(sa, "done");
504 }
505
506 static boolean_t
507 sfc_get_requested_all_ucast(struct sfc_port *port)
508 {
509         return port->promisc;
510 }
511
512 static boolean_t
513 sfc_get_requested_all_mcast(struct sfc_port *port)
514 {
515         return port->promisc || port->allmulti;
516 }
517
518 int
519 sfc_set_rx_mode_unchecked(struct sfc_adapter *sa)
520 {
521         struct sfc_port *port = &sa->port;
522         boolean_t requested_all_ucast = sfc_get_requested_all_ucast(port);
523         boolean_t requested_all_mcast = sfc_get_requested_all_mcast(port);
524         int rc;
525
526         rc = efx_mac_filter_set(sa->nic, requested_all_ucast, B_TRUE,
527                                 requested_all_mcast, B_TRUE);
528         if (rc != 0)
529                 return rc;
530
531         return 0;
532 }
533
534 int
535 sfc_set_rx_mode(struct sfc_adapter *sa)
536 {
537         struct sfc_port *port = &sa->port;
538         boolean_t old_all_ucast;
539         boolean_t old_all_mcast;
540         boolean_t requested_all_ucast = sfc_get_requested_all_ucast(port);
541         boolean_t requested_all_mcast = sfc_get_requested_all_mcast(port);
542         boolean_t actual_all_ucast;
543         boolean_t actual_all_mcast;
544         int rc;
545
546         efx_mac_filter_get_all_ucast_mcast(sa->nic, &old_all_ucast,
547                                            &old_all_mcast);
548
549         rc = sfc_set_rx_mode_unchecked(sa);
550         if (rc != 0)
551                 return rc;
552
553         efx_mac_filter_get_all_ucast_mcast(sa->nic, &actual_all_ucast,
554                                            &actual_all_mcast);
555
556         if (actual_all_ucast != requested_all_ucast ||
557             actual_all_mcast != requested_all_mcast) {
558                 /*
559                  * MAC filter set succeeded but not all requested modes
560                  * were applied. The rollback is necessary to bring back the
561                  * consistent old state.
562                  */
563                 (void)efx_mac_filter_set(sa->nic, old_all_ucast, B_TRUE,
564                                          old_all_mcast, B_TRUE);
565
566                 return EPERM;
567         }
568
569         return 0;
570 }
571
572 void
573 sfc_port_link_mode_to_info(efx_link_mode_t link_mode,
574                            struct rte_eth_link *link_info)
575 {
576         SFC_ASSERT(link_mode < EFX_LINK_NMODES);
577
578         memset(link_info, 0, sizeof(*link_info));
579         if ((link_mode == EFX_LINK_DOWN) || (link_mode == EFX_LINK_UNKNOWN))
580                 link_info->link_status = ETH_LINK_DOWN;
581         else
582                 link_info->link_status = ETH_LINK_UP;
583
584         switch (link_mode) {
585         case EFX_LINK_10HDX:
586                 link_info->link_speed  = ETH_SPEED_NUM_10M;
587                 link_info->link_duplex = ETH_LINK_HALF_DUPLEX;
588                 break;
589         case EFX_LINK_10FDX:
590                 link_info->link_speed  = ETH_SPEED_NUM_10M;
591                 link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
592                 break;
593         case EFX_LINK_100HDX:
594                 link_info->link_speed  = ETH_SPEED_NUM_100M;
595                 link_info->link_duplex = ETH_LINK_HALF_DUPLEX;
596                 break;
597         case EFX_LINK_100FDX:
598                 link_info->link_speed  = ETH_SPEED_NUM_100M;
599                 link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
600                 break;
601         case EFX_LINK_1000HDX:
602                 link_info->link_speed  = ETH_SPEED_NUM_1G;
603                 link_info->link_duplex = ETH_LINK_HALF_DUPLEX;
604                 break;
605         case EFX_LINK_1000FDX:
606                 link_info->link_speed  = ETH_SPEED_NUM_1G;
607                 link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
608                 break;
609         case EFX_LINK_10000FDX:
610                 link_info->link_speed  = ETH_SPEED_NUM_10G;
611                 link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
612                 break;
613         case EFX_LINK_25000FDX:
614                 link_info->link_speed  = ETH_SPEED_NUM_25G;
615                 link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
616                 break;
617         case EFX_LINK_40000FDX:
618                 link_info->link_speed  = ETH_SPEED_NUM_40G;
619                 link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
620                 break;
621         case EFX_LINK_50000FDX:
622                 link_info->link_speed  = ETH_SPEED_NUM_50G;
623                 link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
624                 break;
625         case EFX_LINK_100000FDX:
626                 link_info->link_speed  = ETH_SPEED_NUM_100G;
627                 link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
628                 break;
629         default:
630                 SFC_ASSERT(B_FALSE);
631                 /* FALLTHROUGH */
632         case EFX_LINK_UNKNOWN:
633         case EFX_LINK_DOWN:
634                 link_info->link_speed  = ETH_SPEED_NUM_NONE;
635                 link_info->link_duplex = 0;
636                 break;
637         }
638
639         link_info->link_autoneg = ETH_LINK_AUTONEG;
640 }
641
642 int
643 sfc_port_get_mac_stats(struct sfc_adapter *sa, struct rte_eth_xstat *xstats,
644                        unsigned int xstats_count, unsigned int *nb_written)
645 {
646         struct sfc_port *port = &sa->port;
647         uint64_t *mac_stats;
648         unsigned int i;
649         int nstats = 0;
650         int ret;
651
652         sfc_adapter_lock(sa);
653
654         ret = sfc_port_update_mac_stats(sa, B_FALSE);
655         if (ret != 0) {
656                 SFC_ASSERT(ret > 0);
657                 ret = -ret;
658                 goto unlock;
659         }
660
661         mac_stats = port->mac_stats_buf;
662
663         for (i = 0; i < EFX_MAC_NSTATS; ++i) {
664                 if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
665                         if (nstats < (int)xstats_count) {
666                                 xstats[nstats].id = nstats;
667                                 xstats[nstats].value = mac_stats[i];
668                                 (*nb_written)++;
669                         }
670                         nstats++;
671                 }
672         }
673         ret = nstats;
674
675 unlock:
676         sfc_adapter_unlock(sa);
677
678         return ret;
679 }
680
681 int
682 sfc_port_get_mac_stats_by_id(struct sfc_adapter *sa, const uint64_t *ids,
683                              uint64_t *values, unsigned int n)
684 {
685         struct sfc_port *port = &sa->port;
686         uint64_t *mac_stats;
687         unsigned int i;
688         int ret;
689         int rc;
690
691         sfc_adapter_lock(sa);
692
693         rc = sfc_port_update_mac_stats(sa, B_FALSE);
694         if (rc != 0) {
695                 SFC_ASSERT(rc > 0);
696                 ret = -rc;
697                 goto unlock;
698         }
699
700         mac_stats = port->mac_stats_buf;
701
702         SFC_ASSERT(port->mac_stats_nb_supported <=
703                    RTE_DIM(port->mac_stats_by_id));
704
705         for (i = 0; i < n; i++) {
706                 if (ids[i] < port->mac_stats_nb_supported)
707                         values[i] = mac_stats[port->mac_stats_by_id[ids[i]]];
708         }
709
710         ret = 0;
711
712 unlock:
713         sfc_adapter_unlock(sa);
714
715         return ret;
716 }