net/sfc: add basic statistics
[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
35 /**
36  * Update MAC statistics in the buffer.
37  *
38  * @param       sa      Adapter
39  *
40  * @return Status code
41  * @retval      0       Success
42  * @retval      EAGAIN  Try again
43  * @retval      ENOMEM  Memory allocation failure
44  */
45 int
46 sfc_port_update_mac_stats(struct sfc_adapter *sa)
47 {
48         struct sfc_port *port = &sa->port;
49         int rc;
50
51         SFC_ASSERT(rte_spinlock_is_locked(&port->mac_stats_lock));
52
53         if (sa->state != SFC_ADAPTER_STARTED)
54                 return EINVAL;
55
56         rc = efx_mac_stats_update(sa->nic, &port->mac_stats_dma_mem,
57                                   port->mac_stats_buf, NULL);
58         if (rc != 0)
59                 return rc;
60
61         return 0;
62 }
63
64 int
65 sfc_port_start(struct sfc_adapter *sa)
66 {
67         struct sfc_port *port = &sa->port;
68         int rc;
69
70         sfc_log_init(sa, "entry");
71
72         sfc_log_init(sa, "init filters");
73         rc = efx_filter_init(sa->nic);
74         if (rc != 0)
75                 goto fail_filter_init;
76
77         sfc_log_init(sa, "init port");
78         rc = efx_port_init(sa->nic);
79         if (rc != 0)
80                 goto fail_port_init;
81
82         sfc_log_init(sa, "set MAC PDU %u", (unsigned int)port->pdu);
83         rc = efx_mac_pdu_set(sa->nic, port->pdu);
84         if (rc != 0)
85                 goto fail_mac_pdu_set;
86
87         sfc_log_init(sa, "set MAC address");
88         rc = efx_mac_addr_set(sa->nic,
89                               sa->eth_dev->data->mac_addrs[0].addr_bytes);
90         if (rc != 0)
91                 goto fail_mac_addr_set;
92
93         sfc_log_init(sa, "set MAC filters");
94         rc = efx_mac_filter_set(sa->nic, B_TRUE, B_TRUE, B_TRUE, B_TRUE);
95         if (rc != 0)
96                 goto fail_mac_filter_set;
97
98         efx_mac_stats_get_mask(sa->nic, port->mac_stats_mask,
99                                sizeof(port->mac_stats_mask));
100
101         /* Update MAC stats using periodic DMA.
102          * Common code always uses 1000ms update period, so period_ms
103          * parameter only needs to be non-zero to start updates.
104          */
105         sfc_log_init(sa, "request MAC stats DMA'ing");
106         rc = efx_mac_stats_periodic(sa->nic, &port->mac_stats_dma_mem,
107                                     1000, B_FALSE);
108         if (rc != 0)
109                 goto fail_mac_stats_periodic;
110
111         sfc_log_init(sa, "disable MAC drain");
112         rc = efx_mac_drain(sa->nic, B_FALSE);
113         if (rc != 0)
114                 goto fail_mac_drain;
115
116         sfc_log_init(sa, "done");
117         return 0;
118
119 fail_mac_drain:
120         (void)efx_mac_stats_periodic(sa->nic, &port->mac_stats_dma_mem,
121                                      0, B_FALSE);
122
123 fail_mac_stats_periodic:
124 fail_mac_filter_set:
125 fail_mac_addr_set:
126 fail_mac_pdu_set:
127         efx_port_fini(sa->nic);
128
129 fail_port_init:
130         efx_filter_fini(sa->nic);
131
132 fail_filter_init:
133         sfc_log_init(sa, "failed %d", rc);
134         return rc;
135 }
136
137 void
138 sfc_port_stop(struct sfc_adapter *sa)
139 {
140         sfc_log_init(sa, "entry");
141
142         efx_mac_drain(sa->nic, B_TRUE);
143
144         (void)efx_mac_stats_periodic(sa->nic, &sa->port.mac_stats_dma_mem,
145                                      0, B_FALSE);
146
147         efx_port_fini(sa->nic);
148         efx_filter_fini(sa->nic);
149
150         sfc_log_init(sa, "done");
151 }
152
153 int
154 sfc_port_init(struct sfc_adapter *sa)
155 {
156         const struct rte_eth_dev_data *dev_data = sa->eth_dev->data;
157         struct sfc_port *port = &sa->port;
158         int rc;
159
160         sfc_log_init(sa, "entry");
161
162         /* Enable flow control by default */
163         port->flow_ctrl = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
164         port->flow_ctrl_autoneg = B_TRUE;
165
166         if (dev_data->dev_conf.rxmode.jumbo_frame)
167                 port->pdu = dev_data->dev_conf.rxmode.max_rx_pkt_len;
168         else
169                 port->pdu = EFX_MAC_PDU(dev_data->mtu);
170
171         rte_spinlock_init(&port->mac_stats_lock);
172
173         rc = ENOMEM;
174         port->mac_stats_buf = rte_calloc_socket("mac_stats_buf", EFX_MAC_NSTATS,
175                                                 sizeof(uint64_t), 0,
176                                                 sa->socket_id);
177         if (port->mac_stats_buf == NULL)
178                 goto fail_mac_stats_buf_alloc;
179
180         rc = sfc_dma_alloc(sa, "mac_stats", 0, EFX_MAC_STATS_SIZE,
181                            sa->socket_id, &port->mac_stats_dma_mem);
182         if (rc != 0)
183                 goto fail_mac_stats_dma_alloc;
184
185         sfc_log_init(sa, "done");
186         return 0;
187
188 fail_mac_stats_dma_alloc:
189         rte_free(port->mac_stats_buf);
190 fail_mac_stats_buf_alloc:
191         sfc_log_init(sa, "failed %d", rc);
192         return rc;
193 }
194
195 void
196 sfc_port_fini(struct sfc_adapter *sa)
197 {
198         struct sfc_port *port = &sa->port;
199
200         sfc_log_init(sa, "entry");
201
202         sfc_dma_free(sa, &port->mac_stats_dma_mem);
203         rte_free(port->mac_stats_buf);
204
205         sfc_log_init(sa, "done");
206 }
207
208 void
209 sfc_port_link_mode_to_info(efx_link_mode_t link_mode,
210                            struct rte_eth_link *link_info)
211 {
212         SFC_ASSERT(link_mode < EFX_LINK_NMODES);
213
214         memset(link_info, 0, sizeof(*link_info));
215         if ((link_mode == EFX_LINK_DOWN) || (link_mode == EFX_LINK_UNKNOWN))
216                 link_info->link_status = ETH_LINK_DOWN;
217         else
218                 link_info->link_status = ETH_LINK_UP;
219
220         switch (link_mode) {
221         case EFX_LINK_10HDX:
222                 link_info->link_speed  = ETH_SPEED_NUM_10M;
223                 link_info->link_duplex = ETH_LINK_HALF_DUPLEX;
224                 break;
225         case EFX_LINK_10FDX:
226                 link_info->link_speed  = ETH_SPEED_NUM_10M;
227                 link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
228                 break;
229         case EFX_LINK_100HDX:
230                 link_info->link_speed  = ETH_SPEED_NUM_100M;
231                 link_info->link_duplex = ETH_LINK_HALF_DUPLEX;
232                 break;
233         case EFX_LINK_100FDX:
234                 link_info->link_speed  = ETH_SPEED_NUM_100M;
235                 link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
236                 break;
237         case EFX_LINK_1000HDX:
238                 link_info->link_speed  = ETH_SPEED_NUM_1G;
239                 link_info->link_duplex = ETH_LINK_HALF_DUPLEX;
240                 break;
241         case EFX_LINK_1000FDX:
242                 link_info->link_speed  = ETH_SPEED_NUM_1G;
243                 link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
244                 break;
245         case EFX_LINK_10000FDX:
246                 link_info->link_speed  = ETH_SPEED_NUM_10G;
247                 link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
248                 break;
249         case EFX_LINK_40000FDX:
250                 link_info->link_speed  = ETH_SPEED_NUM_40G;
251                 link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
252                 break;
253         default:
254                 SFC_ASSERT(B_FALSE);
255                 /* FALLTHROUGH */
256         case EFX_LINK_UNKNOWN:
257         case EFX_LINK_DOWN:
258                 link_info->link_speed  = ETH_SPEED_NUM_NONE;
259                 link_info->link_duplex = 0;
260                 break;
261         }
262
263         link_info->link_autoneg = ETH_LINK_AUTONEG;
264 }