net/sfc: implement Rx queue setup release operations
[dpdk.git] / drivers / net / sfc / sfc_rx.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_ev.h"
35 #include "sfc_rx.h"
36
37 static int
38 sfc_rx_qcheck_conf(struct sfc_adapter *sa,
39                    const struct rte_eth_rxconf *rx_conf)
40 {
41         int rc = 0;
42
43         if (rx_conf->rx_thresh.pthresh != 0 ||
44             rx_conf->rx_thresh.hthresh != 0 ||
45             rx_conf->rx_thresh.wthresh != 0) {
46                 sfc_err(sa,
47                         "RxQ prefetch/host/writeback thresholds are not supported");
48                 rc = EINVAL;
49         }
50
51         if (rx_conf->rx_free_thresh != 0) {
52                 sfc_err(sa, "RxQ free threshold is not supported");
53                 rc = EINVAL;
54         }
55
56         if (rx_conf->rx_drop_en == 0) {
57                 sfc_err(sa, "RxQ drop disable is not supported");
58                 rc = EINVAL;
59         }
60
61         if (rx_conf->rx_deferred_start != 0) {
62                 sfc_err(sa, "RxQ deferred start is not supported");
63                 rc = EINVAL;
64         }
65
66         return rc;
67 }
68
69 int
70 sfc_rx_qinit(struct sfc_adapter *sa, unsigned int sw_index,
71              uint16_t nb_rx_desc, unsigned int socket_id,
72              const struct rte_eth_rxconf *rx_conf,
73              struct rte_mempool *mb_pool)
74 {
75         int rc;
76         struct sfc_rxq_info *rxq_info;
77         unsigned int evq_index;
78         struct sfc_evq *evq;
79         struct sfc_rxq *rxq;
80
81         rc = sfc_rx_qcheck_conf(sa, rx_conf);
82         if (rc != 0)
83                 goto fail_bad_conf;
84
85         if (rte_pktmbuf_data_room_size(mb_pool) <= RTE_PKTMBUF_HEADROOM) {
86                 sfc_err(sa, "RxQ %u mbuf is too small, %u vs headroom %u",
87                         sw_index, rte_pktmbuf_data_room_size(mb_pool),
88                         RTE_PKTMBUF_HEADROOM);
89                 goto fail_bad_conf;
90         }
91
92         SFC_ASSERT(sw_index < sa->rxq_count);
93         rxq_info = &sa->rxq_info[sw_index];
94
95         SFC_ASSERT(nb_rx_desc <= rxq_info->max_entries);
96         rxq_info->entries = nb_rx_desc;
97         rxq_info->type = EFX_RXQ_TYPE_DEFAULT;
98
99         evq_index = sfc_evq_index_by_rxq_sw_index(sa, sw_index);
100
101         rc = sfc_ev_qinit(sa, evq_index, rxq_info->entries, socket_id);
102         if (rc != 0)
103                 goto fail_ev_qinit;
104
105         evq = sa->evq_info[evq_index].evq;
106
107         rc = ENOMEM;
108         rxq = rte_zmalloc_socket("sfc-rxq", sizeof(*rxq), RTE_CACHE_LINE_SIZE,
109                                  socket_id);
110         if (rxq == NULL)
111                 goto fail_rxq_alloc;
112
113         rc = sfc_dma_alloc(sa, "rxq", sw_index, EFX_RXQ_SIZE(rxq_info->entries),
114                            socket_id, &rxq->mem);
115         if (rc != 0)
116                 goto fail_dma_alloc;
117
118         rc = ENOMEM;
119         rxq->sw_desc = rte_calloc_socket("sfc-rxq-sw_desc", rxq_info->entries,
120                                          sizeof(*rxq->sw_desc),
121                                          RTE_CACHE_LINE_SIZE, socket_id);
122         if (rxq->sw_desc == NULL)
123                 goto fail_desc_alloc;
124
125         evq->rxq = rxq;
126         rxq->evq = evq;
127         rxq->ptr_mask = rxq_info->entries - 1;
128         rxq->refill_mb_pool = mb_pool;
129         rxq->hw_index = sw_index;
130
131         rxq->state = SFC_RXQ_INITIALIZED;
132
133         rxq_info->rxq = rxq;
134
135         return 0;
136
137 fail_desc_alloc:
138         sfc_dma_free(sa, &rxq->mem);
139
140 fail_dma_alloc:
141         rte_free(rxq);
142
143 fail_rxq_alloc:
144         sfc_ev_qfini(sa, evq_index);
145
146 fail_ev_qinit:
147         rxq_info->entries = 0;
148
149 fail_bad_conf:
150         sfc_log_init(sa, "failed %d", rc);
151         return rc;
152 }
153
154 void
155 sfc_rx_qfini(struct sfc_adapter *sa, unsigned int sw_index)
156 {
157         struct sfc_rxq_info *rxq_info;
158         struct sfc_rxq *rxq;
159
160         SFC_ASSERT(sw_index < sa->rxq_count);
161
162         rxq_info = &sa->rxq_info[sw_index];
163
164         rxq = rxq_info->rxq;
165         SFC_ASSERT(rxq->state == SFC_RXQ_INITIALIZED);
166
167         rxq_info->rxq = NULL;
168         rxq_info->entries = 0;
169
170         rte_free(rxq->sw_desc);
171         sfc_dma_free(sa, &rxq->mem);
172         rte_free(rxq);
173 }
174
175 static int
176 sfc_rx_qinit_info(struct sfc_adapter *sa, unsigned int sw_index)
177 {
178         struct sfc_rxq_info *rxq_info = &sa->rxq_info[sw_index];
179         unsigned int max_entries;
180
181         max_entries = EFX_RXQ_MAXNDESCS;
182         SFC_ASSERT(rte_is_power_of_2(max_entries));
183
184         rxq_info->max_entries = max_entries;
185
186         return 0;
187 }
188
189 static int
190 sfc_rx_check_mode(struct sfc_adapter *sa, struct rte_eth_rxmode *rxmode)
191 {
192         int rc = 0;
193
194         switch (rxmode->mq_mode) {
195         case ETH_MQ_RX_NONE:
196                 /* No special checks are required */
197                 break;
198         default:
199                 sfc_err(sa, "Rx multi-queue mode %u not supported",
200                         rxmode->mq_mode);
201                 rc = EINVAL;
202         }
203
204         if (rxmode->header_split) {
205                 sfc_err(sa, "Header split on Rx not supported");
206                 rc = EINVAL;
207         }
208
209         if (rxmode->hw_vlan_filter) {
210                 sfc_err(sa, "HW VLAN filtering not supported");
211                 rc = EINVAL;
212         }
213
214         if (rxmode->hw_vlan_strip) {
215                 sfc_err(sa, "HW VLAN stripping not supported");
216                 rc = EINVAL;
217         }
218
219         if (rxmode->hw_vlan_extend) {
220                 sfc_err(sa,
221                         "Q-in-Q HW VLAN stripping not supported");
222                 rc = EINVAL;
223         }
224
225         if (!rxmode->hw_strip_crc) {
226                 sfc_warn(sa,
227                          "FCS stripping control not supported - always stripped");
228                 rxmode->hw_strip_crc = 1;
229         }
230
231         if (rxmode->enable_scatter) {
232                 sfc_err(sa, "Scatter on Rx not supported");
233                 rc = EINVAL;
234         }
235
236         if (rxmode->enable_lro) {
237                 sfc_err(sa, "LRO not supported");
238                 rc = EINVAL;
239         }
240
241         return rc;
242 }
243
244 /**
245  * Initialize Rx subsystem.
246  *
247  * Called at device configuration stage when number of receive queues is
248  * specified together with other device level receive configuration.
249  *
250  * It should be used to allocate NUMA-unaware resources.
251  */
252 int
253 sfc_rx_init(struct sfc_adapter *sa)
254 {
255         struct rte_eth_conf *dev_conf = &sa->eth_dev->data->dev_conf;
256         unsigned int sw_index;
257         int rc;
258
259         rc = sfc_rx_check_mode(sa, &dev_conf->rxmode);
260         if (rc != 0)
261                 goto fail_check_mode;
262
263         sa->rxq_count = sa->eth_dev->data->nb_rx_queues;
264
265         rc = ENOMEM;
266         sa->rxq_info = rte_calloc_socket("sfc-rxqs", sa->rxq_count,
267                                          sizeof(struct sfc_rxq_info), 0,
268                                          sa->socket_id);
269         if (sa->rxq_info == NULL)
270                 goto fail_rxqs_alloc;
271
272         for (sw_index = 0; sw_index < sa->rxq_count; ++sw_index) {
273                 rc = sfc_rx_qinit_info(sa, sw_index);
274                 if (rc != 0)
275                         goto fail_rx_qinit_info;
276         }
277
278         return 0;
279
280 fail_rx_qinit_info:
281         rte_free(sa->rxq_info);
282         sa->rxq_info = NULL;
283
284 fail_rxqs_alloc:
285         sa->rxq_count = 0;
286 fail_check_mode:
287         sfc_log_init(sa, "failed %d", rc);
288         return rc;
289 }
290
291 /**
292  * Shutdown Rx subsystem.
293  *
294  * Called at device close stage, for example, before device
295  * reconfiguration or shutdown.
296  */
297 void
298 sfc_rx_fini(struct sfc_adapter *sa)
299 {
300         unsigned int sw_index;
301
302         sw_index = sa->rxq_count;
303         while (sw_index-- > 0) {
304                 if (sa->rxq_info[sw_index].rxq != NULL)
305                         sfc_rx_qfini(sa, sw_index);
306         }
307
308         rte_free(sa->rxq_info);
309         sa->rxq_info = NULL;
310         sa->rxq_count = 0;
311 }