Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2018 Gaƫtan Rivet
3 : : */
4 : :
5 : : #include <eal_export.h>
6 : : #include <rte_debug.h>
7 : :
8 : : #include "rte_ethdev.h"
9 : : #include "rte_ethdev_trace_fp.h"
10 : : #include "ethdev_driver.h"
11 : : #include "ethdev_private.h"
12 : :
13 : : static const char *MZ_RTE_ETH_DEV_DATA = "rte_eth_dev_data";
14 : :
15 : : static const struct rte_memzone *eth_dev_shared_mz;
16 : : struct eth_dev_shared *eth_dev_shared_data;
17 : :
18 : : /* spinlock for eth device callbacks */
19 : : rte_spinlock_t eth_dev_cb_lock = RTE_SPINLOCK_INITIALIZER;
20 : :
21 : : uint16_t
22 : 0 : eth_dev_to_id(const struct rte_eth_dev *dev)
23 : : {
24 [ # # ]: 0 : if (dev == NULL)
25 : : return RTE_MAX_ETHPORTS;
26 : 0 : return dev - rte_eth_devices;
27 : : }
28 : :
29 : : struct rte_eth_dev *
30 : 0 : eth_find_device(const struct rte_eth_dev *start, rte_eth_cmp_t cmp,
31 : : const void *data)
32 : : {
33 : : struct rte_eth_dev *edev;
34 : : ptrdiff_t idx;
35 : :
36 : : /* Avoid Undefined Behaviour */
37 [ # # # # ]: 0 : if (start != NULL &&
38 [ # # ]: 0 : (start < &rte_eth_devices[0] ||
39 : : start > &rte_eth_devices[RTE_MAX_ETHPORTS]))
40 : : return NULL;
41 [ # # ]: 0 : if (start != NULL)
42 : 0 : idx = eth_dev_to_id(start) + 1;
43 : : else
44 : : idx = 0;
45 [ # # ]: 0 : for (; idx < RTE_MAX_ETHPORTS; idx++) {
46 : 0 : edev = &rte_eth_devices[idx];
47 [ # # ]: 0 : if (cmp(edev, data) == 0)
48 : 0 : return edev;
49 : : }
50 : : return NULL;
51 : : }
52 : :
53 : : /* Put new value into list. */
54 : : static int
55 : : rte_eth_devargs_enlist(uint16_t *list, uint16_t *len_list,
56 : : const uint16_t max_list, uint16_t val)
57 : : {
58 : : uint16_t i;
59 : :
60 [ + + + + ]: 200 : for (i = 0; i < *len_list; i++) {
61 [ + - + - ]: 66 : if (list[i] == val)
62 : : return 0;
63 : : }
64 [ + - + - ]: 134 : if (*len_list >= max_list)
65 : : return -1;
66 : 134 : list[(*len_list)++] = val;
67 : : return 0;
68 : : }
69 : :
70 : : /* Parse and enlist a range expression of "min-max" or a single value. */
71 : : static char *
72 : 106 : rte_eth_devargs_process_range(char *str, uint16_t *list, uint16_t *len_list,
73 : : const uint16_t max_list)
74 : : {
75 : : uint16_t lo, hi, val;
76 : 106 : int result, n = 0;
77 : : char *pos = str;
78 : :
79 : 106 : result = sscanf(str, "%hu%n-%hu%n", &lo, &n, &hi, &n);
80 [ + + ]: 106 : if (result == 1) {
81 : 78 : if (rte_eth_devargs_enlist(list, len_list, max_list, lo) != 0)
82 : : return NULL;
83 [ + + ]: 28 : } else if (result == 2) {
84 [ + - ]: 26 : if (lo > hi)
85 : : return NULL;
86 [ + + ]: 82 : for (val = lo; val <= hi; val++) {
87 : : if (rte_eth_devargs_enlist(list, len_list, max_list,
88 : : val) != 0)
89 : : return NULL;
90 : : }
91 : : } else
92 : : return NULL;
93 : 104 : return pos + n;
94 : : }
95 : :
96 : : /*
97 : : * Parse list of values separated by ",".
98 : : * Each value could be a range [min-max] or single number.
99 : : * Examples:
100 : : * 2 - single
101 : : * [1,2,3] - single list
102 : : * [1,3-5,7,9-11] - list with singles and ranges
103 : : */
104 : : static char *
105 : 90 : rte_eth_devargs_process_list(char *str, uint16_t *list, uint16_t *len_list,
106 : : const uint16_t max_list)
107 : : {
108 : : char *pos = str;
109 : :
110 [ + + ]: 90 : if (*pos == '[')
111 : 46 : pos++;
112 : : while (1) {
113 : 106 : pos = rte_eth_devargs_process_range(pos, list, len_list,
114 : : max_list);
115 [ + + ]: 106 : if (pos == NULL)
116 : : return NULL;
117 [ + + ]: 104 : if (*pos != ',') /* end of list */
118 : : break;
119 : 16 : pos++;
120 : : }
121 [ + + + + ]: 88 : if (*str == '[' && *pos != ']')
122 : : return NULL;
123 [ + + ]: 87 : if (*pos == ']')
124 : 44 : pos++;
125 : : return pos;
126 : : }
127 : :
128 : : /*
129 : : * Parse representor ports from a single value or lists.
130 : : *
131 : : * Representor format:
132 : : * #: range or single number of VF representor - legacy
133 : : * [[c#]pf#]vf#: VF port representor/s
134 : : * [[c#]pf#]sf#: SF port representor/s
135 : : * [c#]pf#: PF port representor/s
136 : : *
137 : : * Examples of #:
138 : : * 2 - single
139 : : * [1,2,3] - single list
140 : : * [1,3-5,7,9-11] - list with singles and ranges
141 : : */
142 : : int
143 : 73 : rte_eth_devargs_parse_representor_ports(char *str, void *data)
144 : : {
145 : : struct rte_eth_devargs *eth_da = data;
146 : :
147 [ + + ]: 73 : if (str[0] == 'c') {
148 : 9 : str += 1;
149 : 9 : str = rte_eth_devargs_process_list(str, eth_da->mh_controllers,
150 : : ð_da->nb_mh_controllers,
151 : : RTE_DIM(eth_da->mh_controllers));
152 [ - + ]: 9 : if (str == NULL)
153 : 0 : goto done;
154 : : }
155 : : /* pfX... or (pfX)... */
156 [ + + - + : 73 : if ((str[0] == 'p' && str[1] == 'f') ||
- + ]
157 [ # # # # ]: 0 : (str[0] == '(' && str[1] == 'p' && str[2] == 'f')) {
158 : 26 : eth_da->type = RTE_ETH_REPRESENTOR_PF;
159 [ - + ]: 26 : if (str[0] == '(')
160 : 0 : str++; /* advance past leading "(" */
161 : 26 : str += 2; /* advance past "pf" */
162 : 26 : str = rte_eth_devargs_process_list(str, eth_da->ports,
163 : : ð_da->nb_ports, RTE_DIM(eth_da->ports));
164 [ + + - + ]: 26 : if (str != NULL && str[0] == ')') {
165 : 0 : str++; /* advance past ")" */
166 : 0 : eth_da->flags =
167 : : RTE_ETH_DEVARG_REPRESENTOR_IGNORE_PF;
168 : : }
169 [ + + + + ]: 26 : if (str == NULL || str[0] == '\0')
170 : 12 : goto done;
171 [ + + ]: 47 : } else if (eth_da->nb_mh_controllers > 0) {
172 : : /* 'c' must followed by 'pf'. */
173 : : str = NULL;
174 : 5 : goto done;
175 : : }
176 [ + + + - ]: 56 : if (str[0] == 'v' && str[1] == 'f') {
177 : 38 : eth_da->type = RTE_ETH_REPRESENTOR_VF;
178 : 38 : str += 2;
179 [ + + + - ]: 18 : } else if (str[0] == 's' && str[1] == 'f') {
180 : 3 : eth_da->type = RTE_ETH_REPRESENTOR_SF;
181 : 3 : str += 2;
182 : : } else {
183 : : /* 'pf' must followed by 'vf' or 'sf'. */
184 [ + + ]: 15 : if (eth_da->type == RTE_ETH_REPRESENTOR_PF) {
185 : : str = NULL;
186 : 1 : goto done;
187 : : }
188 : 14 : eth_da->type = RTE_ETH_REPRESENTOR_VF;
189 : : }
190 : 55 : str = rte_eth_devargs_process_list(str, eth_da->representor_ports,
191 : : ð_da->nb_representor_ports,
192 : : RTE_DIM(eth_da->representor_ports));
193 : 67 : done:
194 [ + + ]: 67 : if (str == NULL)
195 : 9 : RTE_ETHDEV_LOG_LINE(ERR, "wrong representor format: %s", str);
196 [ + + ]: 73 : return str == NULL ? -1 : 0;
197 : : }
198 : :
199 : : struct dummy_queue {
200 : : bool rx_warn_once;
201 : : bool tx_warn_once;
202 : : };
203 : : static struct dummy_queue *dummy_queues_array[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
204 : : static struct dummy_queue per_port_queues[RTE_MAX_ETHPORTS];
205 : 303 : RTE_INIT(dummy_queue_init)
206 : : {
207 : : uint16_t port_id;
208 : :
209 [ + + ]: 9999 : for (port_id = 0; port_id < RTE_DIM(per_port_queues); port_id++) {
210 : : unsigned int q;
211 : :
212 [ + + ]: 9938400 : for (q = 0; q < RTE_DIM(dummy_queues_array[port_id]); q++)
213 : 9928704 : dummy_queues_array[port_id][q] = &per_port_queues[port_id];
214 : : }
215 : 303 : }
216 : :
217 : : static uint16_t
218 : 0 : dummy_eth_rx_burst(void *rxq,
219 : : __rte_unused struct rte_mbuf **rx_pkts,
220 : : __rte_unused uint16_t nb_pkts)
221 : : {
222 : : struct dummy_queue *queue = rxq;
223 : : uintptr_t port_id;
224 : :
225 : 0 : port_id = queue - per_port_queues;
226 [ # # # # ]: 0 : if (port_id < RTE_DIM(per_port_queues) && !queue->rx_warn_once) {
227 : 0 : RTE_ETHDEV_LOG_LINE(ERR, "lcore %u called rx_pkt_burst for not ready port %"PRIuPTR,
228 : : rte_lcore_id(), port_id);
229 : 0 : rte_dump_stack();
230 : 0 : queue->rx_warn_once = true;
231 : : }
232 : 0 : rte_errno = ENOTSUP;
233 : 0 : return 0;
234 : : }
235 : :
236 : : static uint16_t
237 : 0 : dummy_eth_tx_burst(void *txq,
238 : : __rte_unused struct rte_mbuf **tx_pkts,
239 : : __rte_unused uint16_t nb_pkts)
240 : : {
241 : : struct dummy_queue *queue = txq;
242 : : uintptr_t port_id;
243 : :
244 : 0 : port_id = queue - per_port_queues;
245 [ # # # # ]: 0 : if (port_id < RTE_DIM(per_port_queues) && !queue->tx_warn_once) {
246 : 0 : RTE_ETHDEV_LOG_LINE(ERR, "lcore %u called tx_pkt_burst for not ready port %"PRIuPTR,
247 : : rte_lcore_id(), port_id);
248 : 0 : rte_dump_stack();
249 : 0 : queue->tx_warn_once = true;
250 : : }
251 : 0 : rte_errno = ENOTSUP;
252 : 0 : return 0;
253 : : }
254 : :
255 : : void
256 : 9794 : eth_dev_fp_ops_reset(struct rte_eth_fp_ops *fpo)
257 : : {
258 : : static RTE_ATOMIC(void *) dummy_data[RTE_MAX_QUEUES_PER_PORT];
259 : 9794 : uintptr_t port_id = fpo - rte_eth_fp_ops;
260 : :
261 : 9794 : per_port_queues[port_id].rx_warn_once = false;
262 : 9794 : per_port_queues[port_id].tx_warn_once = false;
263 : 9794 : *fpo = (struct rte_eth_fp_ops) {
264 : : .rx_pkt_burst = dummy_eth_rx_burst,
265 : : .tx_pkt_burst = dummy_eth_tx_burst,
266 : : .tx_pkt_prepare = rte_eth_tx_pkt_prepare_dummy,
267 : : .rx_queue_count = rte_eth_queue_count_dummy,
268 : : .tx_queue_count = rte_eth_queue_count_dummy,
269 : : .rx_descriptor_status = rte_eth_descriptor_status_dummy,
270 : : .tx_descriptor_status = rte_eth_descriptor_status_dummy,
271 : : .recycle_tx_mbufs_reuse = rte_eth_recycle_tx_mbufs_reuse_dummy,
272 : : .recycle_rx_descriptors_refill = rte_eth_recycle_rx_descriptors_refill_dummy,
273 : : .rxq = {
274 : 9794 : .data = (void **)&dummy_queues_array[port_id],
275 : : .clbk = dummy_data,
276 : : },
277 : : .txq = {
278 : : .data = (void **)&dummy_queues_array[port_id],
279 : : .clbk = dummy_data,
280 : : },
281 : : };
282 : 9794 : }
283 : :
284 : : void
285 : 42 : eth_dev_fp_ops_setup(struct rte_eth_fp_ops *fpo,
286 : : const struct rte_eth_dev *dev)
287 : : {
288 : 42 : fpo->rx_pkt_burst = dev->rx_pkt_burst;
289 : 42 : fpo->tx_pkt_burst = dev->tx_pkt_burst;
290 : 42 : fpo->tx_pkt_prepare = dev->tx_pkt_prepare;
291 : 42 : fpo->rx_queue_count = dev->rx_queue_count;
292 : 42 : fpo->rx_descriptor_status = dev->rx_descriptor_status;
293 : 42 : fpo->tx_queue_count = dev->tx_queue_count;
294 : 42 : fpo->tx_descriptor_status = dev->tx_descriptor_status;
295 : 42 : fpo->recycle_tx_mbufs_reuse = dev->recycle_tx_mbufs_reuse;
296 : 42 : fpo->recycle_rx_descriptors_refill = dev->recycle_rx_descriptors_refill;
297 : :
298 : 42 : fpo->rxq.data = dev->data->rx_queues;
299 : 42 : fpo->rxq.clbk = (void * __rte_atomic *)(uintptr_t)dev->post_rx_burst_cbs;
300 : :
301 : 42 : fpo->txq.data = dev->data->tx_queues;
302 : 42 : fpo->txq.clbk = (void * __rte_atomic *)(uintptr_t)dev->pre_tx_burst_cbs;
303 : 42 : }
304 : :
305 : : RTE_EXPORT_SYMBOL(rte_eth_call_rx_callbacks)
306 : : uint16_t
307 : 10000 : rte_eth_call_rx_callbacks(uint16_t port_id, uint16_t queue_id,
308 : : struct rte_mbuf **rx_pkts, uint16_t nb_rx, uint16_t nb_pkts,
309 : : void *opaque)
310 : : {
311 : : const struct rte_eth_rxtx_callback *cb = opaque;
312 : :
313 [ + + ]: 20000 : while (cb != NULL) {
314 : 10000 : nb_rx = cb->fn.rx(port_id, queue_id, rx_pkts, nb_rx,
315 : 10000 : nb_pkts, cb->param);
316 : 10000 : cb = cb->next;
317 : : }
318 : :
319 : : if (unlikely(nb_rx))
320 : : rte_eth_trace_call_rx_callbacks_nonempty(port_id, queue_id, (void **)rx_pkts,
321 : : nb_rx, nb_pkts);
322 : : else
323 : : rte_eth_trace_call_rx_callbacks_empty(port_id, queue_id, (void **)rx_pkts,
324 : : nb_pkts);
325 : :
326 : 10000 : return nb_rx;
327 : : }
328 : :
329 : : RTE_EXPORT_SYMBOL(rte_eth_call_tx_callbacks)
330 : : uint16_t
331 : 10000 : rte_eth_call_tx_callbacks(uint16_t port_id, uint16_t queue_id,
332 : : struct rte_mbuf **tx_pkts, uint16_t nb_pkts, void *opaque)
333 : : {
334 : : const struct rte_eth_rxtx_callback *cb = opaque;
335 : :
336 [ + + ]: 20000 : while (cb != NULL) {
337 : 10000 : nb_pkts = cb->fn.tx(port_id, queue_id, tx_pkts, nb_pkts,
338 : 10000 : cb->param);
339 : 10000 : cb = cb->next;
340 : : }
341 : :
342 : : rte_eth_trace_call_tx_callbacks(port_id, queue_id, (void **)tx_pkts,
343 : : nb_pkts);
344 : :
345 : 10000 : return nb_pkts;
346 : : }
347 : :
348 : : void *
349 : 170 : eth_dev_shared_data_prepare(void)
350 : : {
351 : : const struct rte_memzone *mz;
352 : :
353 [ + - ]: 170 : if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
354 : : const unsigned int flags = 0;
355 : :
356 [ + + ]: 170 : if (eth_dev_shared_mz != NULL)
357 : 125 : goto out;
358 : :
359 : : /* Allocate port data and ownership shared memory. */
360 : 45 : mz = rte_memzone_reserve(MZ_RTE_ETH_DEV_DATA,
361 : : sizeof(*eth_dev_shared_data),
362 : : SOCKET_ID_ANY, flags);
363 [ - + ]: 45 : if (mz == NULL) {
364 : 0 : RTE_ETHDEV_LOG_LINE(ERR, "Cannot allocate ethdev shared data");
365 : 0 : goto out;
366 : : }
367 : :
368 : 45 : eth_dev_shared_mz = mz;
369 : 45 : eth_dev_shared_data = mz->addr;
370 : 45 : eth_dev_shared_data->allocated_owners = 0;
371 : 45 : eth_dev_shared_data->next_owner_id =
372 : : RTE_ETH_DEV_NO_OWNER + 1;
373 : 45 : eth_dev_shared_data->allocated_ports = 0;
374 : 45 : memset(eth_dev_shared_data->data, 0,
375 : : sizeof(eth_dev_shared_data->data));
376 : : } else {
377 : 0 : mz = rte_memzone_lookup(MZ_RTE_ETH_DEV_DATA);
378 [ # # ]: 0 : if (mz == NULL) {
379 : : /* Clean remaining any traces of a previous shared mem */
380 : 0 : eth_dev_shared_mz = NULL;
381 : 0 : eth_dev_shared_data = NULL;
382 : 0 : RTE_ETHDEV_LOG_LINE(ERR, "Cannot lookup ethdev shared data");
383 : 0 : goto out;
384 : : }
385 [ # # # # ]: 0 : if (mz == eth_dev_shared_mz && mz->addr == eth_dev_shared_data)
386 : 0 : goto out;
387 : :
388 : : /* Shared mem changed in primary process, refresh pointers */
389 : 0 : eth_dev_shared_mz = mz;
390 : 0 : eth_dev_shared_data = mz->addr;
391 : : }
392 : 170 : out:
393 : 170 : return eth_dev_shared_data;
394 : : }
395 : :
396 : : void
397 : 56 : eth_dev_shared_data_release(void)
398 : : {
399 : : RTE_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
400 : :
401 [ + + ]: 56 : if (eth_dev_shared_data->allocated_ports != 0)
402 : : return;
403 [ + - ]: 42 : if (eth_dev_shared_data->allocated_owners != 0)
404 : : return;
405 : :
406 : 42 : rte_memzone_free(eth_dev_shared_mz);
407 : 42 : eth_dev_shared_mz = NULL;
408 : 42 : eth_dev_shared_data = NULL;
409 : : }
410 : :
411 : : void
412 : 81 : eth_dev_rxq_release(struct rte_eth_dev *dev, uint16_t qid)
413 : : {
414 : 81 : void **rxq = dev->data->rx_queues;
415 : :
416 [ + + ]: 81 : if (rxq[qid] == NULL)
417 : : return;
418 : :
419 [ - + ]: 45 : if (dev->dev_ops->rx_queue_release != NULL)
420 : 0 : dev->dev_ops->rx_queue_release(dev, qid);
421 : 45 : rxq[qid] = NULL;
422 : : }
423 : :
424 : : void
425 : 80 : eth_dev_txq_release(struct rte_eth_dev *dev, uint16_t qid)
426 : : {
427 : 80 : void **txq = dev->data->tx_queues;
428 : :
429 [ + + ]: 80 : if (txq[qid] == NULL)
430 : : return;
431 : :
432 [ - + ]: 45 : if (dev->dev_ops->tx_queue_release != NULL)
433 : 0 : dev->dev_ops->tx_queue_release(dev, qid);
434 : 45 : txq[qid] = NULL;
435 : : }
436 : :
437 : : int
438 : 46 : eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
439 : : {
440 : 46 : uint16_t old_nb_queues = dev->data->nb_rx_queues;
441 : : unsigned int i;
442 : :
443 [ + + + + ]: 46 : if (dev->data->rx_queues == NULL && nb_queues != 0) { /* first time configuration */
444 : 32 : dev->data->rx_queues = rte_zmalloc("ethdev->rx_queues",
445 : : sizeof(dev->data->rx_queues[0]) *
446 : : RTE_MAX_QUEUES_PER_PORT,
447 : : RTE_CACHE_LINE_SIZE);
448 [ - + ]: 32 : if (dev->data->rx_queues == NULL) {
449 : 0 : dev->data->nb_rx_queues = 0;
450 : 0 : return -(ENOMEM);
451 : : }
452 [ + + + - ]: 14 : } else if (dev->data->rx_queues != NULL && nb_queues != 0) { /* re-configure */
453 [ + + ]: 18 : for (i = nb_queues; i < old_nb_queues; i++)
454 : 5 : eth_dev_rxq_release(dev, i);
455 : :
456 [ - + - - ]: 1 : } else if (dev->data->rx_queues != NULL && nb_queues == 0) {
457 [ # # ]: 0 : for (i = nb_queues; i < old_nb_queues; i++)
458 : 0 : eth_dev_rxq_release(dev, i);
459 : :
460 : 0 : rte_free(dev->data->rx_queues);
461 : 0 : dev->data->rx_queues = NULL;
462 : : }
463 : 46 : dev->data->nb_rx_queues = nb_queues;
464 : 46 : return 0;
465 : : }
466 : :
467 : : int
468 : 46 : eth_dev_tx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
469 : : {
470 : 46 : uint16_t old_nb_queues = dev->data->nb_tx_queues;
471 : : unsigned int i;
472 : :
473 [ + + + + ]: 46 : if (dev->data->tx_queues == NULL && nb_queues != 0) { /* first time configuration */
474 : 32 : dev->data->tx_queues = rte_zmalloc("ethdev->tx_queues",
475 : : sizeof(dev->data->tx_queues[0]) *
476 : : RTE_MAX_QUEUES_PER_PORT,
477 : : RTE_CACHE_LINE_SIZE);
478 [ - + ]: 32 : if (dev->data->tx_queues == NULL) {
479 : 0 : dev->data->nb_tx_queues = 0;
480 : 0 : return -(ENOMEM);
481 : : }
482 [ + + + - ]: 14 : } else if (dev->data->tx_queues != NULL && nb_queues != 0) { /* re-configure */
483 [ + + ]: 18 : for (i = nb_queues; i < old_nb_queues; i++)
484 : 5 : eth_dev_txq_release(dev, i);
485 : :
486 [ - + - - ]: 1 : } else if (dev->data->tx_queues != NULL && nb_queues == 0) {
487 [ # # ]: 0 : for (i = nb_queues; i < old_nb_queues; i++)
488 : 0 : eth_dev_txq_release(dev, i);
489 : :
490 : 0 : rte_free(dev->data->tx_queues);
491 : 0 : dev->data->tx_queues = NULL;
492 : : }
493 : 46 : dev->data->nb_tx_queues = nb_queues;
494 : 46 : return 0;
495 : : }
496 : :
497 : : int
498 : 42 : eth_stats_qstats_get(uint16_t port_id, struct rte_eth_stats *stats, struct eth_queue_stats *qstats)
499 : : {
500 : : struct rte_eth_dev *dev;
501 : : int ret;
502 : :
503 [ + + ]: 42 : RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
504 : 39 : dev = &rte_eth_devices[port_id];
505 : :
506 [ - + ]: 39 : if (stats == NULL) {
507 : 0 : RTE_ETHDEV_LOG_LINE(ERR, "Cannot get ethdev port %u stats to NULL",
508 : : port_id);
509 : 0 : return -EINVAL;
510 : : }
511 : :
512 : : memset(stats, 0, sizeof(*stats));
513 [ + + ]: 39 : if (qstats != NULL)
514 : : memset(qstats, 0, sizeof(*qstats));
515 : :
516 [ + - ]: 39 : if (dev->dev_ops->stats_get == NULL)
517 : : return -ENOTSUP;
518 : 39 : stats->rx_nombuf = dev->data->rx_mbuf_alloc_failed;
519 : 39 : ret = eth_err(port_id, dev->dev_ops->stats_get(dev, stats, qstats));
520 : :
521 : 39 : return ret;
522 : : }
|