xref: /dpdk/drivers/net/null/rte_eth_null.c (revision 39fd068a27237ff0f825d8efd9ba9ed9a28cacb0)
1b3b413f7SBruce Richardson /*-
2b3b413f7SBruce Richardson  *   BSD LICENSE
3b3b413f7SBruce Richardson  *
4b3b413f7SBruce Richardson  *   Copyright (C) IGEL Co.,Ltd.
5b3b413f7SBruce Richardson  *   All rights reserved.
6b3b413f7SBruce Richardson  *
7b3b413f7SBruce Richardson  *   Redistribution and use in source and binary forms, with or without
8b3b413f7SBruce Richardson  *   modification, are permitted provided that the following conditions
9b3b413f7SBruce Richardson  *   are met:
10b3b413f7SBruce Richardson  *
11b3b413f7SBruce Richardson  *     * Redistributions of source code must retain the above copyright
12b3b413f7SBruce Richardson  *       notice, this list of conditions and the following disclaimer.
13b3b413f7SBruce Richardson  *     * Redistributions in binary form must reproduce the above copyright
14b3b413f7SBruce Richardson  *       notice, this list of conditions and the following disclaimer in
15b3b413f7SBruce Richardson  *       the documentation and/or other materials provided with the
16b3b413f7SBruce Richardson  *       distribution.
17b3b413f7SBruce Richardson  *     * Neither the name of IGEL Co.,Ltd. nor the names of its
18b3b413f7SBruce Richardson  *       contributors may be used to endorse or promote products derived
19b3b413f7SBruce Richardson  *       from this software without specific prior written permission.
20b3b413f7SBruce Richardson  *
21b3b413f7SBruce Richardson  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22b3b413f7SBruce Richardson  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23b3b413f7SBruce Richardson  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24b3b413f7SBruce Richardson  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25b3b413f7SBruce Richardson  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26b3b413f7SBruce Richardson  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27b3b413f7SBruce Richardson  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28b3b413f7SBruce Richardson  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29b3b413f7SBruce Richardson  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30b3b413f7SBruce Richardson  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31b3b413f7SBruce Richardson  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32b3b413f7SBruce Richardson  */
33b3b413f7SBruce Richardson 
34b3b413f7SBruce Richardson #include <rte_mbuf.h>
35b3b413f7SBruce Richardson #include <rte_ethdev.h>
36b3b413f7SBruce Richardson #include <rte_malloc.h>
37b3b413f7SBruce Richardson #include <rte_memcpy.h>
38b3b413f7SBruce Richardson #include <rte_dev.h>
39b3b413f7SBruce Richardson #include <rte_kvargs.h>
401ccec0a8STomasz Kulasek #include <rte_spinlock.h>
41b3b413f7SBruce Richardson 
42ca575279STomasz Kulasek #include "rte_eth_null.h"
43ca575279STomasz Kulasek 
44b3b413f7SBruce Richardson #define ETH_NULL_PACKET_SIZE_ARG	"size"
45b3b413f7SBruce Richardson #define ETH_NULL_PACKET_COPY_ARG	"copy"
46b3b413f7SBruce Richardson 
47b3b413f7SBruce Richardson static unsigned default_packet_size = 64;
48b3b413f7SBruce Richardson static unsigned default_packet_copy;
49b3b413f7SBruce Richardson 
50b3b413f7SBruce Richardson static const char *valid_arguments[] = {
51b3b413f7SBruce Richardson 	ETH_NULL_PACKET_SIZE_ARG,
52b3b413f7SBruce Richardson 	ETH_NULL_PACKET_COPY_ARG,
53b3b413f7SBruce Richardson 	NULL
54b3b413f7SBruce Richardson };
55b3b413f7SBruce Richardson 
56b3b413f7SBruce Richardson struct pmd_internals;
57b3b413f7SBruce Richardson 
58b3b413f7SBruce Richardson struct null_queue {
59b3b413f7SBruce Richardson 	struct pmd_internals *internals;
60b3b413f7SBruce Richardson 
61b3b413f7SBruce Richardson 	struct rte_mempool *mb_pool;
62b3b413f7SBruce Richardson 	struct rte_mbuf *dummy_packet;
63b3b413f7SBruce Richardson 
64b3b413f7SBruce Richardson 	rte_atomic64_t rx_pkts;
65b3b413f7SBruce Richardson 	rte_atomic64_t tx_pkts;
66b3b413f7SBruce Richardson 	rte_atomic64_t err_pkts;
67b3b413f7SBruce Richardson };
68b3b413f7SBruce Richardson 
69b3b413f7SBruce Richardson struct pmd_internals {
70b3b413f7SBruce Richardson 	unsigned packet_size;
71b3b413f7SBruce Richardson 	unsigned packet_copy;
72b3b413f7SBruce Richardson 
73dd7c54a6STomasz Kulasek 	struct null_queue rx_null_queues[RTE_MAX_QUEUES_PER_PORT];
74dd7c54a6STomasz Kulasek 	struct null_queue tx_null_queues[RTE_MAX_QUEUES_PER_PORT];
751ccec0a8STomasz Kulasek 
761ccec0a8STomasz Kulasek 	/** Bit mask of RSS offloads, the bit offset also means flow type */
771ccec0a8STomasz Kulasek 	uint64_t flow_type_rss_offloads;
781ccec0a8STomasz Kulasek 
791ccec0a8STomasz Kulasek 	rte_spinlock_t rss_lock;
801ccec0a8STomasz Kulasek 
811ccec0a8STomasz Kulasek 	uint16_t reta_size;
821ccec0a8STomasz Kulasek 	struct rte_eth_rss_reta_entry64 reta_conf[ETH_RSS_RETA_SIZE_128 /
831ccec0a8STomasz Kulasek 			RTE_RETA_GROUP_SIZE];
841ccec0a8STomasz Kulasek 
851ccec0a8STomasz Kulasek 	uint8_t rss_key[40];                /**< 40-byte hash key. */
86b3b413f7SBruce Richardson };
87b3b413f7SBruce Richardson 
88b3b413f7SBruce Richardson 
89b3b413f7SBruce Richardson static struct ether_addr eth_addr = { .addr_bytes = {0} };
90b3b413f7SBruce Richardson static const char *drivername = "Null PMD";
91b3b413f7SBruce Richardson static struct rte_eth_link pmd_link = {
92*39fd068aSMarc Sune 	.link_speed = ETH_SPEED_NUM_10G,
93b3b413f7SBruce Richardson 	.link_duplex = ETH_LINK_FULL_DUPLEX,
9409419f23SThomas Monjalon 	.link_status = ETH_LINK_DOWN,
95b3b413f7SBruce Richardson };
96b3b413f7SBruce Richardson 
97b3b413f7SBruce Richardson static uint16_t
98b3b413f7SBruce Richardson eth_null_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
99b3b413f7SBruce Richardson {
100b3b413f7SBruce Richardson 	int i;
101b3b413f7SBruce Richardson 	struct null_queue *h = q;
102b3b413f7SBruce Richardson 	unsigned packet_size;
103b3b413f7SBruce Richardson 
104b3b413f7SBruce Richardson 	if ((q == NULL) || (bufs == NULL))
105b3b413f7SBruce Richardson 		return 0;
106b3b413f7SBruce Richardson 
107b3b413f7SBruce Richardson 	packet_size = h->internals->packet_size;
108b3b413f7SBruce Richardson 	for (i = 0; i < nb_bufs; i++) {
109b3b413f7SBruce Richardson 		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
110b3b413f7SBruce Richardson 		if (!bufs[i])
111b3b413f7SBruce Richardson 			break;
112b3b413f7SBruce Richardson 		bufs[i]->data_len = (uint16_t)packet_size;
113b3b413f7SBruce Richardson 		bufs[i]->pkt_len = packet_size;
114b3b413f7SBruce Richardson 		bufs[i]->nb_segs = 1;
115b3b413f7SBruce Richardson 		bufs[i]->next = NULL;
116b3b413f7SBruce Richardson 	}
117b3b413f7SBruce Richardson 
118b3b413f7SBruce Richardson 	rte_atomic64_add(&(h->rx_pkts), i);
119b3b413f7SBruce Richardson 
120b3b413f7SBruce Richardson 	return i;
121b3b413f7SBruce Richardson }
122b3b413f7SBruce Richardson 
123b3b413f7SBruce Richardson static uint16_t
124b3b413f7SBruce Richardson eth_null_copy_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
125b3b413f7SBruce Richardson {
126b3b413f7SBruce Richardson 	int i;
127b3b413f7SBruce Richardson 	struct null_queue *h = q;
128b3b413f7SBruce Richardson 	unsigned packet_size;
129b3b413f7SBruce Richardson 
130b3b413f7SBruce Richardson 	if ((q == NULL) || (bufs == NULL))
131b3b413f7SBruce Richardson 		return 0;
132b3b413f7SBruce Richardson 
133b3b413f7SBruce Richardson 	packet_size = h->internals->packet_size;
134b3b413f7SBruce Richardson 	for (i = 0; i < nb_bufs; i++) {
135b3b413f7SBruce Richardson 		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
136b3b413f7SBruce Richardson 		if (!bufs[i])
137b3b413f7SBruce Richardson 			break;
138b3b413f7SBruce Richardson 		rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *), h->dummy_packet,
139b3b413f7SBruce Richardson 					packet_size);
140b3b413f7SBruce Richardson 		bufs[i]->data_len = (uint16_t)packet_size;
141b3b413f7SBruce Richardson 		bufs[i]->pkt_len = packet_size;
142b3b413f7SBruce Richardson 		bufs[i]->nb_segs = 1;
143b3b413f7SBruce Richardson 		bufs[i]->next = NULL;
144b3b413f7SBruce Richardson 	}
145b3b413f7SBruce Richardson 
146b3b413f7SBruce Richardson 	rte_atomic64_add(&(h->rx_pkts), i);
147b3b413f7SBruce Richardson 
148b3b413f7SBruce Richardson 	return i;
149b3b413f7SBruce Richardson }
150b3b413f7SBruce Richardson 
151b3b413f7SBruce Richardson static uint16_t
152b3b413f7SBruce Richardson eth_null_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
153b3b413f7SBruce Richardson {
154b3b413f7SBruce Richardson 	int i;
155b3b413f7SBruce Richardson 	struct null_queue *h = q;
156b3b413f7SBruce Richardson 
157b3b413f7SBruce Richardson 	if ((q == NULL) || (bufs == NULL))
158b3b413f7SBruce Richardson 		return 0;
159b3b413f7SBruce Richardson 
160b3b413f7SBruce Richardson 	for (i = 0; i < nb_bufs; i++)
161b3b413f7SBruce Richardson 		rte_pktmbuf_free(bufs[i]);
162b3b413f7SBruce Richardson 
163b3b413f7SBruce Richardson 	rte_atomic64_add(&(h->tx_pkts), i);
164b3b413f7SBruce Richardson 
165b3b413f7SBruce Richardson 	return i;
166b3b413f7SBruce Richardson }
167b3b413f7SBruce Richardson 
168b3b413f7SBruce Richardson static uint16_t
169b3b413f7SBruce Richardson eth_null_copy_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
170b3b413f7SBruce Richardson {
171b3b413f7SBruce Richardson 	int i;
172b3b413f7SBruce Richardson 	struct null_queue *h = q;
173b3b413f7SBruce Richardson 	unsigned packet_size;
174b3b413f7SBruce Richardson 
175b3b413f7SBruce Richardson 	if ((q == NULL) || (bufs == NULL))
176b3b413f7SBruce Richardson 		return 0;
177b3b413f7SBruce Richardson 
178b3b413f7SBruce Richardson 	packet_size = h->internals->packet_size;
179b3b413f7SBruce Richardson 	for (i = 0; i < nb_bufs; i++) {
180b3b413f7SBruce Richardson 		rte_memcpy(h->dummy_packet, rte_pktmbuf_mtod(bufs[i], void *),
181b3b413f7SBruce Richardson 					packet_size);
182b3b413f7SBruce Richardson 		rte_pktmbuf_free(bufs[i]);
183b3b413f7SBruce Richardson 	}
184b3b413f7SBruce Richardson 
185b3b413f7SBruce Richardson 	rte_atomic64_add(&(h->tx_pkts), i);
186b3b413f7SBruce Richardson 
187b3b413f7SBruce Richardson 	return i;
188b3b413f7SBruce Richardson }
189b3b413f7SBruce Richardson 
190b3b413f7SBruce Richardson static int
191c9634e44SFerruh Yigit eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
192c9634e44SFerruh Yigit {
193dd7c54a6STomasz Kulasek 	return 0;
194dd7c54a6STomasz Kulasek }
195b3b413f7SBruce Richardson 
196b3b413f7SBruce Richardson static int
197b3b413f7SBruce Richardson eth_dev_start(struct rte_eth_dev *dev)
198b3b413f7SBruce Richardson {
199b3b413f7SBruce Richardson 	if (dev == NULL)
200b3b413f7SBruce Richardson 		return -EINVAL;
201b3b413f7SBruce Richardson 
20209419f23SThomas Monjalon 	dev->data->dev_link.link_status = ETH_LINK_UP;
203b3b413f7SBruce Richardson 	return 0;
204b3b413f7SBruce Richardson }
205b3b413f7SBruce Richardson 
206b3b413f7SBruce Richardson static void
207b3b413f7SBruce Richardson eth_dev_stop(struct rte_eth_dev *dev)
208b3b413f7SBruce Richardson {
209b3b413f7SBruce Richardson 	if (dev == NULL)
210b3b413f7SBruce Richardson 		return;
211b3b413f7SBruce Richardson 
21209419f23SThomas Monjalon 	dev->data->dev_link.link_status = ETH_LINK_DOWN;
213b3b413f7SBruce Richardson }
214b3b413f7SBruce Richardson 
215b3b413f7SBruce Richardson static int
216b3b413f7SBruce Richardson eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
217b3b413f7SBruce Richardson 		uint16_t nb_rx_desc __rte_unused,
218b3b413f7SBruce Richardson 		unsigned int socket_id __rte_unused,
219b3b413f7SBruce Richardson 		const struct rte_eth_rxconf *rx_conf __rte_unused,
220b3b413f7SBruce Richardson 		struct rte_mempool *mb_pool)
221b3b413f7SBruce Richardson {
222b3b413f7SBruce Richardson 	struct rte_mbuf *dummy_packet;
223b3b413f7SBruce Richardson 	struct pmd_internals *internals;
224b3b413f7SBruce Richardson 	unsigned packet_size;
225b3b413f7SBruce Richardson 
226b3b413f7SBruce Richardson 	if ((dev == NULL) || (mb_pool == NULL))
227b3b413f7SBruce Richardson 		return -EINVAL;
228b3b413f7SBruce Richardson 
229dd7c54a6STomasz Kulasek 	internals = dev->data->dev_private;
230dd7c54a6STomasz Kulasek 
231c9634e44SFerruh Yigit 	if (rx_queue_id >= dev->data->nb_rx_queues)
232b3b413f7SBruce Richardson 		return -ENODEV;
233b3b413f7SBruce Richardson 
234b3b413f7SBruce Richardson 	packet_size = internals->packet_size;
235b3b413f7SBruce Richardson 
236b3b413f7SBruce Richardson 	internals->rx_null_queues[rx_queue_id].mb_pool = mb_pool;
237b3b413f7SBruce Richardson 	dev->data->rx_queues[rx_queue_id] =
238b3b413f7SBruce Richardson 		&internals->rx_null_queues[rx_queue_id];
239b3b413f7SBruce Richardson 	dummy_packet = rte_zmalloc_socket(NULL,
240c9634e44SFerruh Yigit 			packet_size, 0, dev->data->numa_node);
241b3b413f7SBruce Richardson 	if (dummy_packet == NULL)
242b3b413f7SBruce Richardson 		return -ENOMEM;
243b3b413f7SBruce Richardson 
244b3b413f7SBruce Richardson 	internals->rx_null_queues[rx_queue_id].internals = internals;
245b3b413f7SBruce Richardson 	internals->rx_null_queues[rx_queue_id].dummy_packet = dummy_packet;
246b3b413f7SBruce Richardson 
247b3b413f7SBruce Richardson 	return 0;
248b3b413f7SBruce Richardson }
249b3b413f7SBruce Richardson 
250b3b413f7SBruce Richardson static int
251b3b413f7SBruce Richardson eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
252b3b413f7SBruce Richardson 		uint16_t nb_tx_desc __rte_unused,
253b3b413f7SBruce Richardson 		unsigned int socket_id __rte_unused,
254b3b413f7SBruce Richardson 		const struct rte_eth_txconf *tx_conf __rte_unused)
255b3b413f7SBruce Richardson {
256b3b413f7SBruce Richardson 	struct rte_mbuf *dummy_packet;
257b3b413f7SBruce Richardson 	struct pmd_internals *internals;
258b3b413f7SBruce Richardson 	unsigned packet_size;
259b3b413f7SBruce Richardson 
260b3b413f7SBruce Richardson 	if (dev == NULL)
261b3b413f7SBruce Richardson 		return -EINVAL;
262b3b413f7SBruce Richardson 
263dd7c54a6STomasz Kulasek 	internals = dev->data->dev_private;
264dd7c54a6STomasz Kulasek 
265c9634e44SFerruh Yigit 	if (tx_queue_id >= dev->data->nb_tx_queues)
266b3b413f7SBruce Richardson 		return -ENODEV;
267b3b413f7SBruce Richardson 
268b3b413f7SBruce Richardson 	packet_size = internals->packet_size;
269b3b413f7SBruce Richardson 
270b3b413f7SBruce Richardson 	dev->data->tx_queues[tx_queue_id] =
271b3b413f7SBruce Richardson 		&internals->tx_null_queues[tx_queue_id];
272b3b413f7SBruce Richardson 	dummy_packet = rte_zmalloc_socket(NULL,
273c9634e44SFerruh Yigit 			packet_size, 0, dev->data->numa_node);
274b3b413f7SBruce Richardson 	if (dummy_packet == NULL)
275b3b413f7SBruce Richardson 		return -ENOMEM;
276b3b413f7SBruce Richardson 
277b3b413f7SBruce Richardson 	internals->tx_null_queues[tx_queue_id].internals = internals;
278b3b413f7SBruce Richardson 	internals->tx_null_queues[tx_queue_id].dummy_packet = dummy_packet;
279b3b413f7SBruce Richardson 
280b3b413f7SBruce Richardson 	return 0;
281b3b413f7SBruce Richardson }
282b3b413f7SBruce Richardson 
283b3b413f7SBruce Richardson 
284b3b413f7SBruce Richardson static void
285b3b413f7SBruce Richardson eth_dev_info(struct rte_eth_dev *dev,
286b3b413f7SBruce Richardson 		struct rte_eth_dev_info *dev_info)
287b3b413f7SBruce Richardson {
288b3b413f7SBruce Richardson 	struct pmd_internals *internals;
289b3b413f7SBruce Richardson 
290b3b413f7SBruce Richardson 	if ((dev == NULL) || (dev_info == NULL))
291b3b413f7SBruce Richardson 		return;
292b3b413f7SBruce Richardson 
293b3b413f7SBruce Richardson 	internals = dev->data->dev_private;
294b3b413f7SBruce Richardson 	dev_info->driver_name = drivername;
295b3b413f7SBruce Richardson 	dev_info->max_mac_addrs = 1;
296b3b413f7SBruce Richardson 	dev_info->max_rx_pktlen = (uint32_t)-1;
297dd7c54a6STomasz Kulasek 	dev_info->max_rx_queues = RTE_DIM(internals->rx_null_queues);
298dd7c54a6STomasz Kulasek 	dev_info->max_tx_queues = RTE_DIM(internals->tx_null_queues);
299b3b413f7SBruce Richardson 	dev_info->min_rx_bufsize = 0;
300b3b413f7SBruce Richardson 	dev_info->pci_dev = NULL;
3011ccec0a8STomasz Kulasek 	dev_info->reta_size = internals->reta_size;
3021ccec0a8STomasz Kulasek 	dev_info->flow_type_rss_offloads = internals->flow_type_rss_offloads;
303b3b413f7SBruce Richardson }
304b3b413f7SBruce Richardson 
305b3b413f7SBruce Richardson static void
306b3b413f7SBruce Richardson eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats)
307b3b413f7SBruce Richardson {
308b3b413f7SBruce Richardson 	unsigned i, num_stats;
309b3b413f7SBruce Richardson 	unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
310b3b413f7SBruce Richardson 	const struct pmd_internals *internal;
311b3b413f7SBruce Richardson 
312b3b413f7SBruce Richardson 	if ((dev == NULL) || (igb_stats == NULL))
313b3b413f7SBruce Richardson 		return;
314b3b413f7SBruce Richardson 
315b3b413f7SBruce Richardson 	internal = dev->data->dev_private;
316b3b413f7SBruce Richardson 	num_stats = RTE_MIN((unsigned)RTE_ETHDEV_QUEUE_STAT_CNTRS,
317c9634e44SFerruh Yigit 			RTE_MIN(dev->data->nb_rx_queues,
318b34141b2SBruce Richardson 				RTE_DIM(internal->rx_null_queues)));
319b3b413f7SBruce Richardson 	for (i = 0; i < num_stats; i++) {
320b3b413f7SBruce Richardson 		igb_stats->q_ipackets[i] =
321b3b413f7SBruce Richardson 			internal->rx_null_queues[i].rx_pkts.cnt;
322b3b413f7SBruce Richardson 		rx_total += igb_stats->q_ipackets[i];
323b3b413f7SBruce Richardson 	}
324b3b413f7SBruce Richardson 
325b3b413f7SBruce Richardson 	num_stats = RTE_MIN((unsigned)RTE_ETHDEV_QUEUE_STAT_CNTRS,
326c9634e44SFerruh Yigit 			RTE_MIN(dev->data->nb_tx_queues,
327b34141b2SBruce Richardson 				RTE_DIM(internal->tx_null_queues)));
328b3b413f7SBruce Richardson 	for (i = 0; i < num_stats; i++) {
329b3b413f7SBruce Richardson 		igb_stats->q_opackets[i] =
330b3b413f7SBruce Richardson 			internal->tx_null_queues[i].tx_pkts.cnt;
331b3b413f7SBruce Richardson 		igb_stats->q_errors[i] =
332b3b413f7SBruce Richardson 			internal->tx_null_queues[i].err_pkts.cnt;
333b3b413f7SBruce Richardson 		tx_total += igb_stats->q_opackets[i];
334b3b413f7SBruce Richardson 		tx_err_total += igb_stats->q_errors[i];
335b3b413f7SBruce Richardson 	}
336b3b413f7SBruce Richardson 
337b3b413f7SBruce Richardson 	igb_stats->ipackets = rx_total;
338b3b413f7SBruce Richardson 	igb_stats->opackets = tx_total;
339b3b413f7SBruce Richardson 	igb_stats->oerrors = tx_err_total;
340b3b413f7SBruce Richardson }
341b3b413f7SBruce Richardson 
342b3b413f7SBruce Richardson static void
343b3b413f7SBruce Richardson eth_stats_reset(struct rte_eth_dev *dev)
344b3b413f7SBruce Richardson {
345b3b413f7SBruce Richardson 	unsigned i;
346b3b413f7SBruce Richardson 	struct pmd_internals *internal;
347b3b413f7SBruce Richardson 
348b3b413f7SBruce Richardson 	if (dev == NULL)
349b3b413f7SBruce Richardson 		return;
350b3b413f7SBruce Richardson 
351b3b413f7SBruce Richardson 	internal = dev->data->dev_private;
352b34141b2SBruce Richardson 	for (i = 0; i < RTE_DIM(internal->rx_null_queues); i++)
353b3b413f7SBruce Richardson 		internal->rx_null_queues[i].rx_pkts.cnt = 0;
354b34141b2SBruce Richardson 	for (i = 0; i < RTE_DIM(internal->tx_null_queues); i++) {
355b3b413f7SBruce Richardson 		internal->tx_null_queues[i].tx_pkts.cnt = 0;
356b3b413f7SBruce Richardson 		internal->tx_null_queues[i].err_pkts.cnt = 0;
357b3b413f7SBruce Richardson 	}
358b3b413f7SBruce Richardson }
359b3b413f7SBruce Richardson 
360b3b413f7SBruce Richardson static void
361b3b413f7SBruce Richardson eth_queue_release(void *q)
362b3b413f7SBruce Richardson {
363b3b413f7SBruce Richardson 	struct null_queue *nq;
364b3b413f7SBruce Richardson 
365b3b413f7SBruce Richardson 	if (q == NULL)
366b3b413f7SBruce Richardson 		return;
367b3b413f7SBruce Richardson 
368b3b413f7SBruce Richardson 	nq = q;
369b3b413f7SBruce Richardson 	rte_free(nq->dummy_packet);
370b3b413f7SBruce Richardson }
371b3b413f7SBruce Richardson 
372b3b413f7SBruce Richardson static int
373b3b413f7SBruce Richardson eth_link_update(struct rte_eth_dev *dev __rte_unused,
374b3b413f7SBruce Richardson 		int wait_to_complete __rte_unused) { return 0; }
375b3b413f7SBruce Richardson 
3761ccec0a8STomasz Kulasek static int
3771ccec0a8STomasz Kulasek eth_rss_reta_update(struct rte_eth_dev *dev,
3781ccec0a8STomasz Kulasek 		struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size)
3791ccec0a8STomasz Kulasek {
3801ccec0a8STomasz Kulasek 	int i, j;
3811ccec0a8STomasz Kulasek 	struct pmd_internals *internal = dev->data->dev_private;
3821ccec0a8STomasz Kulasek 
3831ccec0a8STomasz Kulasek 	if (reta_size != internal->reta_size)
3841ccec0a8STomasz Kulasek 		return -EINVAL;
3851ccec0a8STomasz Kulasek 
3861ccec0a8STomasz Kulasek 	rte_spinlock_lock(&internal->rss_lock);
3871ccec0a8STomasz Kulasek 
3881ccec0a8STomasz Kulasek 	/* Copy RETA table */
3891ccec0a8STomasz Kulasek 	for (i = 0; i < (internal->reta_size / RTE_RETA_GROUP_SIZE); i++) {
3901ccec0a8STomasz Kulasek 		internal->reta_conf[i].mask = reta_conf[i].mask;
3911ccec0a8STomasz Kulasek 		for (j = 0; j < RTE_RETA_GROUP_SIZE; j++)
3921ccec0a8STomasz Kulasek 			if ((reta_conf[i].mask >> j) & 0x01)
3931ccec0a8STomasz Kulasek 				internal->reta_conf[i].reta[j] = reta_conf[i].reta[j];
3941ccec0a8STomasz Kulasek 	}
3951ccec0a8STomasz Kulasek 
3961ccec0a8STomasz Kulasek 	rte_spinlock_unlock(&internal->rss_lock);
3971ccec0a8STomasz Kulasek 
3981ccec0a8STomasz Kulasek 	return 0;
3991ccec0a8STomasz Kulasek }
4001ccec0a8STomasz Kulasek 
4011ccec0a8STomasz Kulasek static int
4021ccec0a8STomasz Kulasek eth_rss_reta_query(struct rte_eth_dev *dev,
4031ccec0a8STomasz Kulasek 		struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size)
4041ccec0a8STomasz Kulasek {
4051ccec0a8STomasz Kulasek 	int i, j;
4061ccec0a8STomasz Kulasek 	struct pmd_internals *internal = dev->data->dev_private;
4071ccec0a8STomasz Kulasek 
4081ccec0a8STomasz Kulasek 	if (reta_size != internal->reta_size)
4091ccec0a8STomasz Kulasek 		return -EINVAL;
4101ccec0a8STomasz Kulasek 
4111ccec0a8STomasz Kulasek 	rte_spinlock_lock(&internal->rss_lock);
4121ccec0a8STomasz Kulasek 
4131ccec0a8STomasz Kulasek 	/* Copy RETA table */
4141ccec0a8STomasz Kulasek 	for (i = 0; i < (internal->reta_size / RTE_RETA_GROUP_SIZE); i++) {
4151ccec0a8STomasz Kulasek 		for (j = 0; j < RTE_RETA_GROUP_SIZE; j++)
4161ccec0a8STomasz Kulasek 			if ((reta_conf[i].mask >> j) & 0x01)
4171ccec0a8STomasz Kulasek 				reta_conf[i].reta[j] = internal->reta_conf[i].reta[j];
4181ccec0a8STomasz Kulasek 	}
4191ccec0a8STomasz Kulasek 
4201ccec0a8STomasz Kulasek 	rte_spinlock_unlock(&internal->rss_lock);
4211ccec0a8STomasz Kulasek 
4221ccec0a8STomasz Kulasek 	return 0;
4231ccec0a8STomasz Kulasek }
4241ccec0a8STomasz Kulasek 
4251ccec0a8STomasz Kulasek static int
4261ccec0a8STomasz Kulasek eth_rss_hash_update(struct rte_eth_dev *dev, struct rte_eth_rss_conf *rss_conf)
4271ccec0a8STomasz Kulasek {
4281ccec0a8STomasz Kulasek 	struct pmd_internals *internal = dev->data->dev_private;
4291ccec0a8STomasz Kulasek 
4301ccec0a8STomasz Kulasek 	rte_spinlock_lock(&internal->rss_lock);
4311ccec0a8STomasz Kulasek 
4321ccec0a8STomasz Kulasek 	if ((rss_conf->rss_hf & internal->flow_type_rss_offloads) != 0)
4331ccec0a8STomasz Kulasek 		dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf =
4341ccec0a8STomasz Kulasek 				rss_conf->rss_hf & internal->flow_type_rss_offloads;
4351ccec0a8STomasz Kulasek 
4361ccec0a8STomasz Kulasek 	if (rss_conf->rss_key)
4371ccec0a8STomasz Kulasek 		rte_memcpy(internal->rss_key, rss_conf->rss_key, 40);
4381ccec0a8STomasz Kulasek 
4391ccec0a8STomasz Kulasek 	rte_spinlock_unlock(&internal->rss_lock);
4401ccec0a8STomasz Kulasek 
4411ccec0a8STomasz Kulasek 	return 0;
4421ccec0a8STomasz Kulasek }
4431ccec0a8STomasz Kulasek 
4441ccec0a8STomasz Kulasek static int
4451ccec0a8STomasz Kulasek eth_rss_hash_conf_get(struct rte_eth_dev *dev,
4461ccec0a8STomasz Kulasek 		struct rte_eth_rss_conf *rss_conf)
4471ccec0a8STomasz Kulasek {
4481ccec0a8STomasz Kulasek 	struct pmd_internals *internal = dev->data->dev_private;
4491ccec0a8STomasz Kulasek 
4501ccec0a8STomasz Kulasek 	rte_spinlock_lock(&internal->rss_lock);
4511ccec0a8STomasz Kulasek 
4521ccec0a8STomasz Kulasek 	rss_conf->rss_hf = dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf;
4531ccec0a8STomasz Kulasek 	if (rss_conf->rss_key)
4541ccec0a8STomasz Kulasek 		rte_memcpy(rss_conf->rss_key, internal->rss_key, 40);
4551ccec0a8STomasz Kulasek 
4561ccec0a8STomasz Kulasek 	rte_spinlock_unlock(&internal->rss_lock);
4571ccec0a8STomasz Kulasek 
4581ccec0a8STomasz Kulasek 	return 0;
4591ccec0a8STomasz Kulasek }
4601ccec0a8STomasz Kulasek 
461b3b413f7SBruce Richardson static const struct eth_dev_ops ops = {
462b3b413f7SBruce Richardson 	.dev_start = eth_dev_start,
463b3b413f7SBruce Richardson 	.dev_stop = eth_dev_stop,
464b3b413f7SBruce Richardson 	.dev_configure = eth_dev_configure,
465b3b413f7SBruce Richardson 	.dev_infos_get = eth_dev_info,
466b3b413f7SBruce Richardson 	.rx_queue_setup = eth_rx_queue_setup,
467b3b413f7SBruce Richardson 	.tx_queue_setup = eth_tx_queue_setup,
468b3b413f7SBruce Richardson 	.rx_queue_release = eth_queue_release,
469b3b413f7SBruce Richardson 	.tx_queue_release = eth_queue_release,
470b3b413f7SBruce Richardson 	.link_update = eth_link_update,
471b3b413f7SBruce Richardson 	.stats_get = eth_stats_get,
472b3b413f7SBruce Richardson 	.stats_reset = eth_stats_reset,
4731ccec0a8STomasz Kulasek 	.reta_update = eth_rss_reta_update,
4741ccec0a8STomasz Kulasek 	.reta_query = eth_rss_reta_query,
4751ccec0a8STomasz Kulasek 	.rss_hash_update = eth_rss_hash_update,
4761ccec0a8STomasz Kulasek 	.rss_hash_conf_get = eth_rss_hash_conf_get
477b3b413f7SBruce Richardson };
478b3b413f7SBruce Richardson 
479ca575279STomasz Kulasek int
480b3b413f7SBruce Richardson eth_dev_null_create(const char *name,
481b3b413f7SBruce Richardson 		const unsigned numa_node,
482b3b413f7SBruce Richardson 		unsigned packet_size,
483b3b413f7SBruce Richardson 		unsigned packet_copy)
484b3b413f7SBruce Richardson {
485b3b413f7SBruce Richardson 	const unsigned nb_rx_queues = 1;
486b3b413f7SBruce Richardson 	const unsigned nb_tx_queues = 1;
487b3b413f7SBruce Richardson 	struct rte_eth_dev_data *data = NULL;
488b3b413f7SBruce Richardson 	struct pmd_internals *internals = NULL;
489b3b413f7SBruce Richardson 	struct rte_eth_dev *eth_dev = NULL;
490b3b413f7SBruce Richardson 
4911ccec0a8STomasz Kulasek 	static const uint8_t default_rss_key[40] = {
4921ccec0a8STomasz Kulasek 		0x6D, 0x5A, 0x56, 0xDA, 0x25, 0x5B, 0x0E, 0xC2, 0x41, 0x67, 0x25, 0x3D,
4931ccec0a8STomasz Kulasek 		0x43, 0xA3, 0x8F, 0xB0, 0xD0, 0xCA, 0x2B, 0xCB, 0xAE, 0x7B, 0x30, 0xB4,
4941ccec0a8STomasz Kulasek 		0x77, 0xCB, 0x2D, 0xA3, 0x80, 0x30, 0xF2, 0x0C, 0x6A, 0x42, 0xB7, 0x3B,
4951ccec0a8STomasz Kulasek 		0xBE, 0xAC, 0x01, 0xFA
4961ccec0a8STomasz Kulasek 	};
4971ccec0a8STomasz Kulasek 
498b3b413f7SBruce Richardson 	if (name == NULL)
499b3b413f7SBruce Richardson 		return -EINVAL;
500b3b413f7SBruce Richardson 
501b3b413f7SBruce Richardson 	RTE_LOG(INFO, PMD, "Creating null ethdev on numa socket %u\n",
502b3b413f7SBruce Richardson 			numa_node);
503b3b413f7SBruce Richardson 
504b3b413f7SBruce Richardson 	/* now do all data allocation - for eth_dev structure, dummy pci driver
505b3b413f7SBruce Richardson 	 * and internal (private) data
506b3b413f7SBruce Richardson 	 */
507b3b413f7SBruce Richardson 	data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node);
508b3b413f7SBruce Richardson 	if (data == NULL)
509b3b413f7SBruce Richardson 		goto error;
510b3b413f7SBruce Richardson 
511b3b413f7SBruce Richardson 	internals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node);
512b3b413f7SBruce Richardson 	if (internals == NULL)
513b3b413f7SBruce Richardson 		goto error;
514b3b413f7SBruce Richardson 
515b3b413f7SBruce Richardson 	/* reserve an ethdev entry */
516b3b413f7SBruce Richardson 	eth_dev = rte_eth_dev_allocate(name, RTE_ETH_DEV_VIRTUAL);
517b3b413f7SBruce Richardson 	if (eth_dev == NULL)
518b3b413f7SBruce Richardson 		goto error;
519b3b413f7SBruce Richardson 
520b3b413f7SBruce Richardson 	/* now put it all together
521b3b413f7SBruce Richardson 	 * - store queue data in internals,
5228fb9e2bbSBernard Iremonger 	 * - store numa_node info in ethdev data
5238fb9e2bbSBernard Iremonger 	 * - point eth_dev_data to internals
524b3b413f7SBruce Richardson 	 * - and point eth_dev structure to new eth_dev_data structure
525b3b413f7SBruce Richardson 	 */
526b3b413f7SBruce Richardson 	/* NOTE: we'll replace the data element, of originally allocated eth_dev
527b3b413f7SBruce Richardson 	 * so the nulls are local per-process */
528b3b413f7SBruce Richardson 
529b3b413f7SBruce Richardson 	internals->packet_size = packet_size;
530b3b413f7SBruce Richardson 	internals->packet_copy = packet_copy;
531b3b413f7SBruce Richardson 
5321ccec0a8STomasz Kulasek 	internals->flow_type_rss_offloads =  ETH_RSS_PROTO_MASK;
5331ccec0a8STomasz Kulasek 	internals->reta_size = RTE_DIM(internals->reta_conf) * RTE_RETA_GROUP_SIZE;
5341ccec0a8STomasz Kulasek 
5351ccec0a8STomasz Kulasek 	rte_memcpy(internals->rss_key, default_rss_key, 40);
5361ccec0a8STomasz Kulasek 
537b3b413f7SBruce Richardson 	data->dev_private = internals;
538b3b413f7SBruce Richardson 	data->port_id = eth_dev->data->port_id;
539b3b413f7SBruce Richardson 	data->nb_rx_queues = (uint16_t)nb_rx_queues;
540b3b413f7SBruce Richardson 	data->nb_tx_queues = (uint16_t)nb_tx_queues;
541b3b413f7SBruce Richardson 	data->dev_link = pmd_link;
542b3b413f7SBruce Richardson 	data->mac_addrs = &eth_addr;
543b3b413f7SBruce Richardson 	strncpy(data->name, eth_dev->data->name, strlen(eth_dev->data->name));
544b3b413f7SBruce Richardson 
545b3b413f7SBruce Richardson 	eth_dev->data = data;
546b3b413f7SBruce Richardson 	eth_dev->dev_ops = &ops;
5476799cfe4SBernard Iremonger 
548c92db8aeSTomasz Kulasek 	TAILQ_INIT(&eth_dev->link_intr_cbs);
549b3b413f7SBruce Richardson 
5508fb9e2bbSBernard Iremonger 	eth_dev->driver = NULL;
551c9634e44SFerruh Yigit 	data->dev_flags = RTE_ETH_DEV_DETACHABLE;
552c9634e44SFerruh Yigit 	data->kdrv = RTE_KDRV_NONE;
553c9634e44SFerruh Yigit 	data->drv_name = drivername;
554c9634e44SFerruh Yigit 	data->numa_node = numa_node;
5558fb9e2bbSBernard Iremonger 
556b3b413f7SBruce Richardson 	/* finally assign rx and tx ops */
557b3b413f7SBruce Richardson 	if (packet_copy) {
558b3b413f7SBruce Richardson 		eth_dev->rx_pkt_burst = eth_null_copy_rx;
559b3b413f7SBruce Richardson 		eth_dev->tx_pkt_burst = eth_null_copy_tx;
560b3b413f7SBruce Richardson 	} else {
561b3b413f7SBruce Richardson 		eth_dev->rx_pkt_burst = eth_null_rx;
562b3b413f7SBruce Richardson 		eth_dev->tx_pkt_burst = eth_null_tx;
563b3b413f7SBruce Richardson 	}
564b3b413f7SBruce Richardson 
565b3b413f7SBruce Richardson 	return 0;
566b3b413f7SBruce Richardson 
567b3b413f7SBruce Richardson error:
568b3b413f7SBruce Richardson 	rte_free(data);
569b3b413f7SBruce Richardson 	rte_free(internals);
570b3b413f7SBruce Richardson 
571b3b413f7SBruce Richardson 	return -1;
572b3b413f7SBruce Richardson }
573b3b413f7SBruce Richardson 
574b3b413f7SBruce Richardson static inline int
575b3b413f7SBruce Richardson get_packet_size_arg(const char *key __rte_unused,
576b3b413f7SBruce Richardson 		const char *value, void *extra_args)
577b3b413f7SBruce Richardson {
578b3b413f7SBruce Richardson 	const char *a = value;
579b3b413f7SBruce Richardson 	unsigned *packet_size = extra_args;
580b3b413f7SBruce Richardson 
581b3b413f7SBruce Richardson 	if ((value == NULL) || (extra_args == NULL))
582b3b413f7SBruce Richardson 		return -EINVAL;
583b3b413f7SBruce Richardson 
584b3b413f7SBruce Richardson 	*packet_size = (unsigned)strtoul(a, NULL, 0);
585b3b413f7SBruce Richardson 	if (*packet_size == UINT_MAX)
586b3b413f7SBruce Richardson 		return -1;
587b3b413f7SBruce Richardson 
588b3b413f7SBruce Richardson 	return 0;
589b3b413f7SBruce Richardson }
590b3b413f7SBruce Richardson 
591b3b413f7SBruce Richardson static inline int
592b3b413f7SBruce Richardson get_packet_copy_arg(const char *key __rte_unused,
593b3b413f7SBruce Richardson 		const char *value, void *extra_args)
594b3b413f7SBruce Richardson {
595b3b413f7SBruce Richardson 	const char *a = value;
596b3b413f7SBruce Richardson 	unsigned *packet_copy = extra_args;
597b3b413f7SBruce Richardson 
598b3b413f7SBruce Richardson 	if ((value == NULL) || (extra_args == NULL))
599b3b413f7SBruce Richardson 		return -EINVAL;
600b3b413f7SBruce Richardson 
601b3b413f7SBruce Richardson 	*packet_copy = (unsigned)strtoul(a, NULL, 0);
602b3b413f7SBruce Richardson 	if (*packet_copy == UINT_MAX)
603b3b413f7SBruce Richardson 		return -1;
604b3b413f7SBruce Richardson 
605b3b413f7SBruce Richardson 	return 0;
606b3b413f7SBruce Richardson }
607b3b413f7SBruce Richardson 
608b3b413f7SBruce Richardson static int
609b3b413f7SBruce Richardson rte_pmd_null_devinit(const char *name, const char *params)
610b3b413f7SBruce Richardson {
611b3b413f7SBruce Richardson 	unsigned numa_node;
612b3b413f7SBruce Richardson 	unsigned packet_size = default_packet_size;
613b3b413f7SBruce Richardson 	unsigned packet_copy = default_packet_copy;
614b3b413f7SBruce Richardson 	struct rte_kvargs *kvlist = NULL;
615b3b413f7SBruce Richardson 	int ret;
616b3b413f7SBruce Richardson 
617b3b413f7SBruce Richardson 	if (name == NULL)
618b3b413f7SBruce Richardson 		return -EINVAL;
619b3b413f7SBruce Richardson 
620b3b413f7SBruce Richardson 	RTE_LOG(INFO, PMD, "Initializing pmd_null for %s\n", name);
621b3b413f7SBruce Richardson 
622b3b413f7SBruce Richardson 	numa_node = rte_socket_id();
623b3b413f7SBruce Richardson 
624b3b413f7SBruce Richardson 	if (params != NULL) {
625b3b413f7SBruce Richardson 		kvlist = rte_kvargs_parse(params, valid_arguments);
626b3b413f7SBruce Richardson 		if (kvlist == NULL)
627b3b413f7SBruce Richardson 			return -1;
628b3b413f7SBruce Richardson 
629b3b413f7SBruce Richardson 		if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_SIZE_ARG) == 1) {
630b3b413f7SBruce Richardson 
631b3b413f7SBruce Richardson 			ret = rte_kvargs_process(kvlist,
632b3b413f7SBruce Richardson 					ETH_NULL_PACKET_SIZE_ARG,
633b3b413f7SBruce Richardson 					&get_packet_size_arg, &packet_size);
634b3b413f7SBruce Richardson 			if (ret < 0)
635b3b413f7SBruce Richardson 				goto free_kvlist;
636b3b413f7SBruce Richardson 		}
637b3b413f7SBruce Richardson 
638b3b413f7SBruce Richardson 		if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_COPY_ARG) == 1) {
639b3b413f7SBruce Richardson 
640b3b413f7SBruce Richardson 			ret = rte_kvargs_process(kvlist,
641b3b413f7SBruce Richardson 					ETH_NULL_PACKET_COPY_ARG,
642b3b413f7SBruce Richardson 					&get_packet_copy_arg, &packet_copy);
643b3b413f7SBruce Richardson 			if (ret < 0)
644b3b413f7SBruce Richardson 				goto free_kvlist;
645b3b413f7SBruce Richardson 		}
646b3b413f7SBruce Richardson 	}
647b3b413f7SBruce Richardson 
648b3b413f7SBruce Richardson 	RTE_LOG(INFO, PMD, "Configure pmd_null: packet size is %d, "
649b3b413f7SBruce Richardson 			"packet copy is %s\n", packet_size,
650b3b413f7SBruce Richardson 			packet_copy ? "enabled" : "disabled");
651b3b413f7SBruce Richardson 
652b3b413f7SBruce Richardson 	ret = eth_dev_null_create(name, numa_node, packet_size, packet_copy);
653b3b413f7SBruce Richardson 
654b3b413f7SBruce Richardson free_kvlist:
655b3b413f7SBruce Richardson 	if (kvlist)
656b3b413f7SBruce Richardson 		rte_kvargs_free(kvlist);
657b3b413f7SBruce Richardson 	return ret;
658b3b413f7SBruce Richardson }
659b3b413f7SBruce Richardson 
660b3b413f7SBruce Richardson static int
661b3b413f7SBruce Richardson rte_pmd_null_devuninit(const char *name)
662b3b413f7SBruce Richardson {
663b3b413f7SBruce Richardson 	struct rte_eth_dev *eth_dev = NULL;
664b3b413f7SBruce Richardson 
665b3b413f7SBruce Richardson 	if (name == NULL)
666b3b413f7SBruce Richardson 		return -EINVAL;
667b3b413f7SBruce Richardson 
668b3b413f7SBruce Richardson 	RTE_LOG(INFO, PMD, "Closing null ethdev on numa socket %u\n",
669b3b413f7SBruce Richardson 			rte_socket_id());
670b3b413f7SBruce Richardson 
6716799cfe4SBernard Iremonger 	/* find the ethdev entry */
672b3b413f7SBruce Richardson 	eth_dev = rte_eth_dev_allocated(name);
673b3b413f7SBruce Richardson 	if (eth_dev == NULL)
674b3b413f7SBruce Richardson 		return -1;
675b3b413f7SBruce Richardson 
676b3b413f7SBruce Richardson 	rte_free(eth_dev->data->dev_private);
677b3b413f7SBruce Richardson 	rte_free(eth_dev->data);
678b3b413f7SBruce Richardson 
679b3b413f7SBruce Richardson 	rte_eth_dev_release_port(eth_dev);
680b3b413f7SBruce Richardson 
681b3b413f7SBruce Richardson 	return 0;
682b3b413f7SBruce Richardson }
683b3b413f7SBruce Richardson 
684b3b413f7SBruce Richardson static struct rte_driver pmd_null_drv = {
685b3b413f7SBruce Richardson 	.name = "eth_null",
686b3b413f7SBruce Richardson 	.type = PMD_VDEV,
687b3b413f7SBruce Richardson 	.init = rte_pmd_null_devinit,
688b3b413f7SBruce Richardson 	.uninit = rte_pmd_null_devuninit,
689b3b413f7SBruce Richardson };
690b3b413f7SBruce Richardson 
691b3b413f7SBruce Richardson PMD_REGISTER_DRIVER(pmd_null_drv);
692