net/sfc: poll MAC stats if periodic DMA is not supported
[dpdk.git] / drivers / net / sfc / sfc_port.c
1 /*-
2  * Copyright (c) 2016 Solarflare Communications Inc.
3  * All rights reserved.
4  *
5  * This software was jointly developed between OKTET Labs (under contract
6  * for Solarflare) and Solarflare Communications, Inc.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright notice,
12  *    this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright notice,
14  *    this list of conditions and the following disclaimer in the documentation
15  *    and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "efx.h"
31
32 #include "sfc.h"
33 #include "sfc_log.h"
34 #include "sfc_kvargs.h"
35
36 /** Default MAC statistics update period is 1 second */
37 #define SFC_MAC_STATS_UPDATE_PERIOD_MS_DEF      MS_PER_S
38
39 /** The number of microseconds to sleep on attempt to get statistics update */
40 #define SFC_MAC_STATS_UPDATE_RETRY_INTERVAL_US  10
41
42 /** The number of attempts to await arrival of freshly generated statistics */
43 #define SFC_MAC_STATS_UPDATE_NB_ATTEMPTS        50
44
45 /**
46  * Update MAC statistics in the buffer.
47  *
48  * @param       sa      Adapter
49  *
50  * @return Status code
51  * @retval      0       Success
52  * @retval      EAGAIN  Try again
53  * @retval      ENOMEM  Memory allocation failure
54  */
55 int
56 sfc_port_update_mac_stats(struct sfc_adapter *sa)
57 {
58         struct sfc_port *port = &sa->port;
59         efsys_mem_t *esmp = &port->mac_stats_dma_mem;
60         uint32_t *genp = NULL;
61         uint32_t gen_old;
62         unsigned int nb_attempts = 0;
63         int rc;
64
65         SFC_ASSERT(rte_spinlock_is_locked(&port->mac_stats_lock));
66
67         if (sa->state != SFC_ADAPTER_STARTED)
68                 return EINVAL;
69
70         /*
71          * If periodic statistics DMA'ing is off or if not supported,
72          * make a manual request and keep an eye on timer if need be
73          */
74         if (!port->mac_stats_periodic_dma_supported ||
75             (port->mac_stats_update_period_ms == 0)) {
76                 if (port->mac_stats_update_period_ms != 0) {
77                         uint64_t timestamp = sfc_get_system_msecs();
78
79                         if ((timestamp -
80                              port->mac_stats_last_request_timestamp) <
81                             port->mac_stats_update_period_ms)
82                                 return 0;
83
84                         port->mac_stats_last_request_timestamp = timestamp;
85                 }
86
87                 rc = efx_mac_stats_upload(sa->nic, esmp);
88                 if (rc != 0)
89                         return rc;
90
91                 genp = &port->mac_stats_update_generation;
92                 gen_old = *genp;
93         }
94
95         do {
96                 if (nb_attempts > 0)
97                         rte_delay_us(SFC_MAC_STATS_UPDATE_RETRY_INTERVAL_US);
98
99                 rc = efx_mac_stats_update(sa->nic, esmp,
100                                           port->mac_stats_buf, genp);
101                 if (rc != 0)
102                         return rc;
103
104         } while ((genp != NULL) && (*genp == gen_old) &&
105                  (++nb_attempts < SFC_MAC_STATS_UPDATE_NB_ATTEMPTS));
106
107         return 0;
108 }
109
110 int
111 sfc_port_reset_mac_stats(struct sfc_adapter *sa)
112 {
113         struct sfc_port *port = &sa->port;
114         int rc;
115
116         rte_spinlock_lock(&port->mac_stats_lock);
117         rc = efx_mac_stats_clear(sa->nic);
118         rte_spinlock_unlock(&port->mac_stats_lock);
119
120         return rc;
121 }
122
123 static int
124 sfc_port_init_dev_link(struct sfc_adapter *sa)
125 {
126         struct rte_eth_link *dev_link = &sa->eth_dev->data->dev_link;
127         int rc;
128         efx_link_mode_t link_mode;
129         struct rte_eth_link current_link;
130
131         rc = efx_port_poll(sa->nic, &link_mode);
132         if (rc != 0)
133                 return rc;
134
135         sfc_port_link_mode_to_info(link_mode, &current_link);
136
137         EFX_STATIC_ASSERT(sizeof(*dev_link) == sizeof(rte_atomic64_t));
138         rte_atomic64_set((rte_atomic64_t *)dev_link,
139                          *(uint64_t *)&current_link);
140
141         return 0;
142 }
143
144 int
145 sfc_port_start(struct sfc_adapter *sa)
146 {
147         struct sfc_port *port = &sa->port;
148         int rc;
149         uint32_t phy_adv_cap;
150         const uint32_t phy_pause_caps =
151                 ((1u << EFX_PHY_CAP_PAUSE) | (1u << EFX_PHY_CAP_ASYM));
152
153         sfc_log_init(sa, "entry");
154
155         sfc_log_init(sa, "init filters");
156         rc = efx_filter_init(sa->nic);
157         if (rc != 0)
158                 goto fail_filter_init;
159
160         sfc_log_init(sa, "init port");
161         rc = efx_port_init(sa->nic);
162         if (rc != 0)
163                 goto fail_port_init;
164
165         sfc_log_init(sa, "set flow control to %#x autoneg=%u",
166                      port->flow_ctrl, port->flow_ctrl_autoneg);
167         rc = efx_mac_fcntl_set(sa->nic, port->flow_ctrl,
168                                port->flow_ctrl_autoneg);
169         if (rc != 0)
170                 goto fail_mac_fcntl_set;
171
172         /* Preserve pause capabilities set by above efx_mac_fcntl_set()  */
173         efx_phy_adv_cap_get(sa->nic, EFX_PHY_CAP_CURRENT, &phy_adv_cap);
174         SFC_ASSERT((port->phy_adv_cap & phy_pause_caps) == 0);
175         phy_adv_cap = port->phy_adv_cap | (phy_adv_cap & phy_pause_caps);
176
177         sfc_log_init(sa, "set phy adv caps to %#x", phy_adv_cap);
178         rc = efx_phy_adv_cap_set(sa->nic, phy_adv_cap);
179         if (rc != 0)
180                 goto fail_phy_adv_cap_set;
181
182         sfc_log_init(sa, "set MAC PDU %u", (unsigned int)port->pdu);
183         rc = efx_mac_pdu_set(sa->nic, port->pdu);
184         if (rc != 0)
185                 goto fail_mac_pdu_set;
186
187         sfc_log_init(sa, "set MAC address");
188         rc = efx_mac_addr_set(sa->nic,
189                               sa->eth_dev->data->mac_addrs[0].addr_bytes);
190         if (rc != 0)
191                 goto fail_mac_addr_set;
192
193         sfc_log_init(sa, "set MAC filters");
194         port->promisc = (sa->eth_dev->data->promiscuous != 0) ?
195                         B_TRUE : B_FALSE;
196         port->allmulti = (sa->eth_dev->data->all_multicast != 0) ?
197                          B_TRUE : B_FALSE;
198         rc = sfc_set_rx_mode(sa);
199         if (rc != 0)
200                 goto fail_mac_filter_set;
201
202         sfc_log_init(sa, "set multicast address list");
203         rc = efx_mac_multicast_list_set(sa->nic, port->mcast_addrs,
204                                         port->nb_mcast_addrs);
205         if (rc != 0)
206                 goto fail_mcast_address_list_set;
207
208         if (port->mac_stats_reset_pending) {
209                 rc = sfc_port_reset_mac_stats(sa);
210                 if (rc != 0)
211                         sfc_err(sa, "statistics reset failed (requested "
212                                     "before the port was started)");
213
214                 port->mac_stats_reset_pending = B_FALSE;
215         }
216
217         efx_mac_stats_get_mask(sa->nic, port->mac_stats_mask,
218                                sizeof(port->mac_stats_mask));
219
220         port->mac_stats_update_generation = 0;
221
222         if (port->mac_stats_update_period_ms != 0) {
223                 /*
224                  * Update MAC stats using periodic DMA;
225                  * any positive update interval different from
226                  * 1000 ms can be set only on SFN8xxx provided
227                  * that FW version is 6.2.1.1033 or higher
228                  */
229                 sfc_log_init(sa, "request MAC stats DMA'ing");
230                 rc = efx_mac_stats_periodic(sa->nic, &port->mac_stats_dma_mem,
231                                             port->mac_stats_update_period_ms,
232                                             B_FALSE);
233                 if (rc == 0) {
234                         port->mac_stats_periodic_dma_supported = B_TRUE;
235                 } else if (rc == EOPNOTSUPP) {
236                         port->mac_stats_periodic_dma_supported = B_FALSE;
237                         port->mac_stats_last_request_timestamp = 0;
238                 } else {
239                         goto fail_mac_stats_periodic;
240                 }
241         }
242
243         sfc_log_init(sa, "disable MAC drain");
244         rc = efx_mac_drain(sa->nic, B_FALSE);
245         if (rc != 0)
246                 goto fail_mac_drain;
247
248         /* Synchronize link status knowledge */
249         rc = sfc_port_init_dev_link(sa);
250         if (rc != 0)
251                 goto fail_port_init_dev_link;
252
253         sfc_log_init(sa, "done");
254         return 0;
255
256 fail_port_init_dev_link:
257         (void)efx_mac_drain(sa->nic, B_TRUE);
258
259 fail_mac_drain:
260         (void)efx_mac_stats_periodic(sa->nic, &port->mac_stats_dma_mem,
261                                      0, B_FALSE);
262
263 fail_mac_stats_periodic:
264 fail_mcast_address_list_set:
265 fail_mac_filter_set:
266 fail_mac_addr_set:
267 fail_mac_pdu_set:
268 fail_phy_adv_cap_set:
269 fail_mac_fcntl_set:
270         efx_port_fini(sa->nic);
271
272 fail_port_init:
273         efx_filter_fini(sa->nic);
274
275 fail_filter_init:
276         sfc_log_init(sa, "failed %d", rc);
277         return rc;
278 }
279
280 void
281 sfc_port_stop(struct sfc_adapter *sa)
282 {
283         sfc_log_init(sa, "entry");
284
285         efx_mac_drain(sa->nic, B_TRUE);
286
287         (void)efx_mac_stats_periodic(sa->nic, &sa->port.mac_stats_dma_mem,
288                                      0, B_FALSE);
289
290         efx_port_fini(sa->nic);
291         efx_filter_fini(sa->nic);
292
293         sfc_log_init(sa, "done");
294 }
295
296 int
297 sfc_port_init(struct sfc_adapter *sa)
298 {
299         const struct rte_eth_dev_data *dev_data = sa->eth_dev->data;
300         struct sfc_port *port = &sa->port;
301         long kvarg_stats_update_period_ms;
302         int rc;
303
304         sfc_log_init(sa, "entry");
305
306         /* Enable flow control by default */
307         port->flow_ctrl = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
308         port->flow_ctrl_autoneg = B_TRUE;
309
310         if (dev_data->dev_conf.rxmode.jumbo_frame)
311                 port->pdu = dev_data->dev_conf.rxmode.max_rx_pkt_len;
312         else
313                 port->pdu = EFX_MAC_PDU(dev_data->mtu);
314
315         port->max_mcast_addrs = EFX_MAC_MULTICAST_LIST_MAX;
316         port->nb_mcast_addrs = 0;
317         port->mcast_addrs = rte_calloc_socket("mcast_addr_list_buf",
318                                               port->max_mcast_addrs,
319                                               EFX_MAC_ADDR_LEN, 0,
320                                               sa->socket_id);
321         if (port->mcast_addrs == NULL) {
322                 rc = ENOMEM;
323                 goto fail_mcast_addr_list_buf_alloc;
324         }
325
326         rte_spinlock_init(&port->mac_stats_lock);
327
328         rc = ENOMEM;
329         port->mac_stats_buf = rte_calloc_socket("mac_stats_buf", EFX_MAC_NSTATS,
330                                                 sizeof(uint64_t), 0,
331                                                 sa->socket_id);
332         if (port->mac_stats_buf == NULL)
333                 goto fail_mac_stats_buf_alloc;
334
335         rc = sfc_dma_alloc(sa, "mac_stats", 0, EFX_MAC_STATS_SIZE,
336                            sa->socket_id, &port->mac_stats_dma_mem);
337         if (rc != 0)
338                 goto fail_mac_stats_dma_alloc;
339
340         port->mac_stats_reset_pending = B_FALSE;
341
342         kvarg_stats_update_period_ms = SFC_MAC_STATS_UPDATE_PERIOD_MS_DEF;
343
344         rc = sfc_kvargs_process(sa, SFC_KVARG_STATS_UPDATE_PERIOD_MS,
345                                 sfc_kvarg_long_handler,
346                                 &kvarg_stats_update_period_ms);
347         if ((rc == 0) &&
348             ((kvarg_stats_update_period_ms < 0) ||
349              (kvarg_stats_update_period_ms > UINT16_MAX))) {
350                 sfc_err(sa, "wrong '" SFC_KVARG_STATS_UPDATE_PERIOD_MS "' "
351                             "was set (%ld);", kvarg_stats_update_period_ms);
352                 sfc_err(sa, "it must not be less than 0 "
353                             "or greater than %" PRIu16, UINT16_MAX);
354                 rc = EINVAL;
355                 goto fail_kvarg_stats_update_period_ms;
356         } else if (rc != 0) {
357                 goto fail_kvarg_stats_update_period_ms;
358         }
359
360         port->mac_stats_update_period_ms = kvarg_stats_update_period_ms;
361
362         sfc_log_init(sa, "done");
363         return 0;
364
365 fail_kvarg_stats_update_period_ms:
366 fail_mac_stats_dma_alloc:
367         rte_free(port->mac_stats_buf);
368 fail_mac_stats_buf_alloc:
369 fail_mcast_addr_list_buf_alloc:
370         sfc_log_init(sa, "failed %d", rc);
371         return rc;
372 }
373
374 void
375 sfc_port_fini(struct sfc_adapter *sa)
376 {
377         struct sfc_port *port = &sa->port;
378
379         sfc_log_init(sa, "entry");
380
381         sfc_dma_free(sa, &port->mac_stats_dma_mem);
382         rte_free(port->mac_stats_buf);
383
384         sfc_log_init(sa, "done");
385 }
386
387 int
388 sfc_set_rx_mode(struct sfc_adapter *sa)
389 {
390         struct sfc_port *port = &sa->port;
391         int rc;
392
393         rc = efx_mac_filter_set(sa->nic, port->promisc, B_TRUE,
394                                 port->promisc || port->allmulti, B_TRUE);
395
396         return rc;
397 }
398
399 void
400 sfc_port_link_mode_to_info(efx_link_mode_t link_mode,
401                            struct rte_eth_link *link_info)
402 {
403         SFC_ASSERT(link_mode < EFX_LINK_NMODES);
404
405         memset(link_info, 0, sizeof(*link_info));
406         if ((link_mode == EFX_LINK_DOWN) || (link_mode == EFX_LINK_UNKNOWN))
407                 link_info->link_status = ETH_LINK_DOWN;
408         else
409                 link_info->link_status = ETH_LINK_UP;
410
411         switch (link_mode) {
412         case EFX_LINK_10HDX:
413                 link_info->link_speed  = ETH_SPEED_NUM_10M;
414                 link_info->link_duplex = ETH_LINK_HALF_DUPLEX;
415                 break;
416         case EFX_LINK_10FDX:
417                 link_info->link_speed  = ETH_SPEED_NUM_10M;
418                 link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
419                 break;
420         case EFX_LINK_100HDX:
421                 link_info->link_speed  = ETH_SPEED_NUM_100M;
422                 link_info->link_duplex = ETH_LINK_HALF_DUPLEX;
423                 break;
424         case EFX_LINK_100FDX:
425                 link_info->link_speed  = ETH_SPEED_NUM_100M;
426                 link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
427                 break;
428         case EFX_LINK_1000HDX:
429                 link_info->link_speed  = ETH_SPEED_NUM_1G;
430                 link_info->link_duplex = ETH_LINK_HALF_DUPLEX;
431                 break;
432         case EFX_LINK_1000FDX:
433                 link_info->link_speed  = ETH_SPEED_NUM_1G;
434                 link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
435                 break;
436         case EFX_LINK_10000FDX:
437                 link_info->link_speed  = ETH_SPEED_NUM_10G;
438                 link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
439                 break;
440         case EFX_LINK_40000FDX:
441                 link_info->link_speed  = ETH_SPEED_NUM_40G;
442                 link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
443                 break;
444         default:
445                 SFC_ASSERT(B_FALSE);
446                 /* FALLTHROUGH */
447         case EFX_LINK_UNKNOWN:
448         case EFX_LINK_DOWN:
449                 link_info->link_speed  = ETH_SPEED_NUM_NONE;
450                 link_info->link_duplex = 0;
451                 break;
452         }
453
454         link_info->link_autoneg = ETH_LINK_AUTONEG;
455 }