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> 40*1ccec0a8STomasz 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 unsigned numa_node; 73b3b413f7SBruce Richardson 74b3b413f7SBruce Richardson unsigned nb_rx_queues; 75b3b413f7SBruce Richardson unsigned nb_tx_queues; 76b3b413f7SBruce Richardson 77dd7c54a6STomasz Kulasek struct null_queue rx_null_queues[RTE_MAX_QUEUES_PER_PORT]; 78dd7c54a6STomasz Kulasek struct null_queue tx_null_queues[RTE_MAX_QUEUES_PER_PORT]; 79*1ccec0a8STomasz Kulasek 80*1ccec0a8STomasz Kulasek /** Bit mask of RSS offloads, the bit offset also means flow type */ 81*1ccec0a8STomasz Kulasek uint64_t flow_type_rss_offloads; 82*1ccec0a8STomasz Kulasek 83*1ccec0a8STomasz Kulasek rte_spinlock_t rss_lock; 84*1ccec0a8STomasz Kulasek 85*1ccec0a8STomasz Kulasek uint16_t reta_size; 86*1ccec0a8STomasz Kulasek struct rte_eth_rss_reta_entry64 reta_conf[ETH_RSS_RETA_SIZE_128 / 87*1ccec0a8STomasz Kulasek RTE_RETA_GROUP_SIZE]; 88*1ccec0a8STomasz Kulasek 89*1ccec0a8STomasz Kulasek uint8_t rss_key[40]; /**< 40-byte hash key. */ 90b3b413f7SBruce Richardson }; 91b3b413f7SBruce Richardson 92b3b413f7SBruce Richardson 93b3b413f7SBruce Richardson static struct ether_addr eth_addr = { .addr_bytes = {0} }; 94b3b413f7SBruce Richardson static const char *drivername = "Null PMD"; 95b3b413f7SBruce Richardson static struct rte_eth_link pmd_link = { 96b3b413f7SBruce Richardson .link_speed = 10000, 97b3b413f7SBruce Richardson .link_duplex = ETH_LINK_FULL_DUPLEX, 98b3b413f7SBruce Richardson .link_status = 0 99b3b413f7SBruce Richardson }; 100b3b413f7SBruce Richardson 101b3b413f7SBruce Richardson static uint16_t 102b3b413f7SBruce Richardson eth_null_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs) 103b3b413f7SBruce Richardson { 104b3b413f7SBruce Richardson int i; 105b3b413f7SBruce Richardson struct null_queue *h = q; 106b3b413f7SBruce Richardson unsigned packet_size; 107b3b413f7SBruce Richardson 108b3b413f7SBruce Richardson if ((q == NULL) || (bufs == NULL)) 109b3b413f7SBruce Richardson return 0; 110b3b413f7SBruce Richardson 111b3b413f7SBruce Richardson packet_size = h->internals->packet_size; 112b3b413f7SBruce Richardson for (i = 0; i < nb_bufs; i++) { 113b3b413f7SBruce Richardson bufs[i] = rte_pktmbuf_alloc(h->mb_pool); 114b3b413f7SBruce Richardson if (!bufs[i]) 115b3b413f7SBruce Richardson break; 116b3b413f7SBruce Richardson bufs[i]->data_len = (uint16_t)packet_size; 117b3b413f7SBruce Richardson bufs[i]->pkt_len = packet_size; 118b3b413f7SBruce Richardson bufs[i]->nb_segs = 1; 119b3b413f7SBruce Richardson bufs[i]->next = NULL; 120b3b413f7SBruce Richardson } 121b3b413f7SBruce Richardson 122b3b413f7SBruce Richardson rte_atomic64_add(&(h->rx_pkts), i); 123b3b413f7SBruce Richardson 124b3b413f7SBruce Richardson return i; 125b3b413f7SBruce Richardson } 126b3b413f7SBruce Richardson 127b3b413f7SBruce Richardson static uint16_t 128b3b413f7SBruce Richardson eth_null_copy_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs) 129b3b413f7SBruce Richardson { 130b3b413f7SBruce Richardson int i; 131b3b413f7SBruce Richardson struct null_queue *h = q; 132b3b413f7SBruce Richardson unsigned packet_size; 133b3b413f7SBruce Richardson 134b3b413f7SBruce Richardson if ((q == NULL) || (bufs == NULL)) 135b3b413f7SBruce Richardson return 0; 136b3b413f7SBruce Richardson 137b3b413f7SBruce Richardson packet_size = h->internals->packet_size; 138b3b413f7SBruce Richardson for (i = 0; i < nb_bufs; i++) { 139b3b413f7SBruce Richardson bufs[i] = rte_pktmbuf_alloc(h->mb_pool); 140b3b413f7SBruce Richardson if (!bufs[i]) 141b3b413f7SBruce Richardson break; 142b3b413f7SBruce Richardson rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *), h->dummy_packet, 143b3b413f7SBruce Richardson packet_size); 144b3b413f7SBruce Richardson bufs[i]->data_len = (uint16_t)packet_size; 145b3b413f7SBruce Richardson bufs[i]->pkt_len = packet_size; 146b3b413f7SBruce Richardson bufs[i]->nb_segs = 1; 147b3b413f7SBruce Richardson bufs[i]->next = NULL; 148b3b413f7SBruce Richardson } 149b3b413f7SBruce Richardson 150b3b413f7SBruce Richardson rte_atomic64_add(&(h->rx_pkts), i); 151b3b413f7SBruce Richardson 152b3b413f7SBruce Richardson return i; 153b3b413f7SBruce Richardson } 154b3b413f7SBruce Richardson 155b3b413f7SBruce Richardson static uint16_t 156b3b413f7SBruce Richardson eth_null_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs) 157b3b413f7SBruce Richardson { 158b3b413f7SBruce Richardson int i; 159b3b413f7SBruce Richardson struct null_queue *h = q; 160b3b413f7SBruce Richardson 161b3b413f7SBruce Richardson if ((q == NULL) || (bufs == NULL)) 162b3b413f7SBruce Richardson return 0; 163b3b413f7SBruce Richardson 164b3b413f7SBruce Richardson for (i = 0; i < nb_bufs; i++) 165b3b413f7SBruce Richardson rte_pktmbuf_free(bufs[i]); 166b3b413f7SBruce Richardson 167b3b413f7SBruce Richardson rte_atomic64_add(&(h->tx_pkts), i); 168b3b413f7SBruce Richardson 169b3b413f7SBruce Richardson return i; 170b3b413f7SBruce Richardson } 171b3b413f7SBruce Richardson 172b3b413f7SBruce Richardson static uint16_t 173b3b413f7SBruce Richardson eth_null_copy_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs) 174b3b413f7SBruce Richardson { 175b3b413f7SBruce Richardson int i; 176b3b413f7SBruce Richardson struct null_queue *h = q; 177b3b413f7SBruce Richardson unsigned packet_size; 178b3b413f7SBruce Richardson 179b3b413f7SBruce Richardson if ((q == NULL) || (bufs == NULL)) 180b3b413f7SBruce Richardson return 0; 181b3b413f7SBruce Richardson 182b3b413f7SBruce Richardson packet_size = h->internals->packet_size; 183b3b413f7SBruce Richardson for (i = 0; i < nb_bufs; i++) { 184b3b413f7SBruce Richardson rte_memcpy(h->dummy_packet, rte_pktmbuf_mtod(bufs[i], void *), 185b3b413f7SBruce Richardson packet_size); 186b3b413f7SBruce Richardson rte_pktmbuf_free(bufs[i]); 187b3b413f7SBruce Richardson } 188b3b413f7SBruce Richardson 189b3b413f7SBruce Richardson rte_atomic64_add(&(h->tx_pkts), i); 190b3b413f7SBruce Richardson 191b3b413f7SBruce Richardson return i; 192b3b413f7SBruce Richardson } 193b3b413f7SBruce Richardson 194b3b413f7SBruce Richardson static int 195dd7c54a6STomasz Kulasek eth_dev_configure(struct rte_eth_dev *dev) { 196dd7c54a6STomasz Kulasek struct pmd_internals *internals; 197dd7c54a6STomasz Kulasek 198dd7c54a6STomasz Kulasek internals = dev->data->dev_private; 199dd7c54a6STomasz Kulasek internals->nb_rx_queues = dev->data->nb_rx_queues; 200dd7c54a6STomasz Kulasek internals->nb_tx_queues = dev->data->nb_tx_queues; 201dd7c54a6STomasz Kulasek 202dd7c54a6STomasz Kulasek return 0; 203dd7c54a6STomasz Kulasek } 204b3b413f7SBruce Richardson 205b3b413f7SBruce Richardson static int 206b3b413f7SBruce Richardson eth_dev_start(struct rte_eth_dev *dev) 207b3b413f7SBruce Richardson { 208b3b413f7SBruce Richardson if (dev == NULL) 209b3b413f7SBruce Richardson return -EINVAL; 210b3b413f7SBruce Richardson 211b3b413f7SBruce Richardson dev->data->dev_link.link_status = 1; 212b3b413f7SBruce Richardson return 0; 213b3b413f7SBruce Richardson } 214b3b413f7SBruce Richardson 215b3b413f7SBruce Richardson static void 216b3b413f7SBruce Richardson eth_dev_stop(struct rte_eth_dev *dev) 217b3b413f7SBruce Richardson { 218b3b413f7SBruce Richardson if (dev == NULL) 219b3b413f7SBruce Richardson return; 220b3b413f7SBruce Richardson 221b3b413f7SBruce Richardson dev->data->dev_link.link_status = 0; 222b3b413f7SBruce Richardson } 223b3b413f7SBruce Richardson 224b3b413f7SBruce Richardson static int 225b3b413f7SBruce Richardson eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id, 226b3b413f7SBruce Richardson uint16_t nb_rx_desc __rte_unused, 227b3b413f7SBruce Richardson unsigned int socket_id __rte_unused, 228b3b413f7SBruce Richardson const struct rte_eth_rxconf *rx_conf __rte_unused, 229b3b413f7SBruce Richardson struct rte_mempool *mb_pool) 230b3b413f7SBruce Richardson { 231b3b413f7SBruce Richardson struct rte_mbuf *dummy_packet; 232b3b413f7SBruce Richardson struct pmd_internals *internals; 233b3b413f7SBruce Richardson unsigned packet_size; 234b3b413f7SBruce Richardson 235b3b413f7SBruce Richardson if ((dev == NULL) || (mb_pool == NULL)) 236b3b413f7SBruce Richardson return -EINVAL; 237b3b413f7SBruce Richardson 238dd7c54a6STomasz Kulasek internals = dev->data->dev_private; 239dd7c54a6STomasz Kulasek 240dd7c54a6STomasz Kulasek if (rx_queue_id >= internals->nb_rx_queues) 241b3b413f7SBruce Richardson return -ENODEV; 242b3b413f7SBruce Richardson 243b3b413f7SBruce Richardson packet_size = internals->packet_size; 244b3b413f7SBruce Richardson 245b3b413f7SBruce Richardson internals->rx_null_queues[rx_queue_id].mb_pool = mb_pool; 246b3b413f7SBruce Richardson dev->data->rx_queues[rx_queue_id] = 247b3b413f7SBruce Richardson &internals->rx_null_queues[rx_queue_id]; 248b3b413f7SBruce Richardson dummy_packet = rte_zmalloc_socket(NULL, 249b3b413f7SBruce Richardson packet_size, 0, internals->numa_node); 250b3b413f7SBruce Richardson if (dummy_packet == NULL) 251b3b413f7SBruce Richardson return -ENOMEM; 252b3b413f7SBruce Richardson 253b3b413f7SBruce Richardson internals->rx_null_queues[rx_queue_id].internals = internals; 254b3b413f7SBruce Richardson internals->rx_null_queues[rx_queue_id].dummy_packet = dummy_packet; 255b3b413f7SBruce Richardson 256b3b413f7SBruce Richardson return 0; 257b3b413f7SBruce Richardson } 258b3b413f7SBruce Richardson 259b3b413f7SBruce Richardson static int 260b3b413f7SBruce Richardson eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id, 261b3b413f7SBruce Richardson uint16_t nb_tx_desc __rte_unused, 262b3b413f7SBruce Richardson unsigned int socket_id __rte_unused, 263b3b413f7SBruce Richardson const struct rte_eth_txconf *tx_conf __rte_unused) 264b3b413f7SBruce Richardson { 265b3b413f7SBruce Richardson struct rte_mbuf *dummy_packet; 266b3b413f7SBruce Richardson struct pmd_internals *internals; 267b3b413f7SBruce Richardson unsigned packet_size; 268b3b413f7SBruce Richardson 269b3b413f7SBruce Richardson if (dev == NULL) 270b3b413f7SBruce Richardson return -EINVAL; 271b3b413f7SBruce Richardson 272dd7c54a6STomasz Kulasek internals = dev->data->dev_private; 273dd7c54a6STomasz Kulasek 274dd7c54a6STomasz Kulasek if (tx_queue_id >= internals->nb_tx_queues) 275b3b413f7SBruce Richardson return -ENODEV; 276b3b413f7SBruce Richardson 277b3b413f7SBruce Richardson packet_size = internals->packet_size; 278b3b413f7SBruce Richardson 279b3b413f7SBruce Richardson dev->data->tx_queues[tx_queue_id] = 280b3b413f7SBruce Richardson &internals->tx_null_queues[tx_queue_id]; 281b3b413f7SBruce Richardson dummy_packet = rte_zmalloc_socket(NULL, 282b3b413f7SBruce Richardson packet_size, 0, internals->numa_node); 283b3b413f7SBruce Richardson if (dummy_packet == NULL) 284b3b413f7SBruce Richardson return -ENOMEM; 285b3b413f7SBruce Richardson 286b3b413f7SBruce Richardson internals->tx_null_queues[tx_queue_id].internals = internals; 287b3b413f7SBruce Richardson internals->tx_null_queues[tx_queue_id].dummy_packet = dummy_packet; 288b3b413f7SBruce Richardson 289b3b413f7SBruce Richardson return 0; 290b3b413f7SBruce Richardson } 291b3b413f7SBruce Richardson 292b3b413f7SBruce Richardson 293b3b413f7SBruce Richardson static void 294b3b413f7SBruce Richardson eth_dev_info(struct rte_eth_dev *dev, 295b3b413f7SBruce Richardson struct rte_eth_dev_info *dev_info) 296b3b413f7SBruce Richardson { 297b3b413f7SBruce Richardson struct pmd_internals *internals; 298b3b413f7SBruce Richardson 299b3b413f7SBruce Richardson if ((dev == NULL) || (dev_info == NULL)) 300b3b413f7SBruce Richardson return; 301b3b413f7SBruce Richardson 302b3b413f7SBruce Richardson internals = dev->data->dev_private; 303b3b413f7SBruce Richardson dev_info->driver_name = drivername; 304b3b413f7SBruce Richardson dev_info->max_mac_addrs = 1; 305b3b413f7SBruce Richardson dev_info->max_rx_pktlen = (uint32_t)-1; 306dd7c54a6STomasz Kulasek dev_info->max_rx_queues = RTE_DIM(internals->rx_null_queues); 307dd7c54a6STomasz Kulasek dev_info->max_tx_queues = RTE_DIM(internals->tx_null_queues); 308b3b413f7SBruce Richardson dev_info->min_rx_bufsize = 0; 309b3b413f7SBruce Richardson dev_info->pci_dev = NULL; 310*1ccec0a8STomasz Kulasek dev_info->reta_size = internals->reta_size; 311*1ccec0a8STomasz Kulasek dev_info->flow_type_rss_offloads = internals->flow_type_rss_offloads; 312b3b413f7SBruce Richardson } 313b3b413f7SBruce Richardson 314b3b413f7SBruce Richardson static void 315b3b413f7SBruce Richardson eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats) 316b3b413f7SBruce Richardson { 317b3b413f7SBruce Richardson unsigned i, num_stats; 318b3b413f7SBruce Richardson unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0; 319b3b413f7SBruce Richardson const struct pmd_internals *internal; 320b3b413f7SBruce Richardson 321b3b413f7SBruce Richardson if ((dev == NULL) || (igb_stats == NULL)) 322b3b413f7SBruce Richardson return; 323b3b413f7SBruce Richardson 324b3b413f7SBruce Richardson internal = dev->data->dev_private; 325b3b413f7SBruce Richardson num_stats = RTE_MIN((unsigned)RTE_ETHDEV_QUEUE_STAT_CNTRS, 326b34141b2SBruce Richardson RTE_MIN(internal->nb_rx_queues, 327b34141b2SBruce Richardson RTE_DIM(internal->rx_null_queues))); 328b3b413f7SBruce Richardson for (i = 0; i < num_stats; i++) { 329b3b413f7SBruce Richardson igb_stats->q_ipackets[i] = 330b3b413f7SBruce Richardson internal->rx_null_queues[i].rx_pkts.cnt; 331b3b413f7SBruce Richardson rx_total += igb_stats->q_ipackets[i]; 332b3b413f7SBruce Richardson } 333b3b413f7SBruce Richardson 334b3b413f7SBruce Richardson num_stats = RTE_MIN((unsigned)RTE_ETHDEV_QUEUE_STAT_CNTRS, 335b34141b2SBruce Richardson RTE_MIN(internal->nb_tx_queues, 336b34141b2SBruce Richardson RTE_DIM(internal->tx_null_queues))); 337b3b413f7SBruce Richardson for (i = 0; i < num_stats; i++) { 338b3b413f7SBruce Richardson igb_stats->q_opackets[i] = 339b3b413f7SBruce Richardson internal->tx_null_queues[i].tx_pkts.cnt; 340b3b413f7SBruce Richardson igb_stats->q_errors[i] = 341b3b413f7SBruce Richardson internal->tx_null_queues[i].err_pkts.cnt; 342b3b413f7SBruce Richardson tx_total += igb_stats->q_opackets[i]; 343b3b413f7SBruce Richardson tx_err_total += igb_stats->q_errors[i]; 344b3b413f7SBruce Richardson } 345b3b413f7SBruce Richardson 346b3b413f7SBruce Richardson igb_stats->ipackets = rx_total; 347b3b413f7SBruce Richardson igb_stats->opackets = tx_total; 348b3b413f7SBruce Richardson igb_stats->oerrors = tx_err_total; 349b3b413f7SBruce Richardson } 350b3b413f7SBruce Richardson 351b3b413f7SBruce Richardson static void 352b3b413f7SBruce Richardson eth_stats_reset(struct rte_eth_dev *dev) 353b3b413f7SBruce Richardson { 354b3b413f7SBruce Richardson unsigned i; 355b3b413f7SBruce Richardson struct pmd_internals *internal; 356b3b413f7SBruce Richardson 357b3b413f7SBruce Richardson if (dev == NULL) 358b3b413f7SBruce Richardson return; 359b3b413f7SBruce Richardson 360b3b413f7SBruce Richardson internal = dev->data->dev_private; 361b34141b2SBruce Richardson for (i = 0; i < RTE_DIM(internal->rx_null_queues); i++) 362b3b413f7SBruce Richardson internal->rx_null_queues[i].rx_pkts.cnt = 0; 363b34141b2SBruce Richardson for (i = 0; i < RTE_DIM(internal->tx_null_queues); i++) { 364b3b413f7SBruce Richardson internal->tx_null_queues[i].tx_pkts.cnt = 0; 365b3b413f7SBruce Richardson internal->tx_null_queues[i].err_pkts.cnt = 0; 366b3b413f7SBruce Richardson } 367b3b413f7SBruce Richardson } 368b3b413f7SBruce Richardson 369b3b413f7SBruce Richardson static struct eth_driver rte_null_pmd = { 370b3b413f7SBruce Richardson .pci_drv = { 371b3b413f7SBruce Richardson .name = "rte_null_pmd", 372b3b413f7SBruce Richardson .drv_flags = RTE_PCI_DRV_DETACHABLE, 373b3b413f7SBruce Richardson }, 374b3b413f7SBruce Richardson }; 375b3b413f7SBruce Richardson 376b3b413f7SBruce Richardson static void 377b3b413f7SBruce Richardson eth_queue_release(void *q) 378b3b413f7SBruce Richardson { 379b3b413f7SBruce Richardson struct null_queue *nq; 380b3b413f7SBruce Richardson 381b3b413f7SBruce Richardson if (q == NULL) 382b3b413f7SBruce Richardson return; 383b3b413f7SBruce Richardson 384b3b413f7SBruce Richardson nq = q; 385b3b413f7SBruce Richardson rte_free(nq->dummy_packet); 386b3b413f7SBruce Richardson } 387b3b413f7SBruce Richardson 388b3b413f7SBruce Richardson static int 389b3b413f7SBruce Richardson eth_link_update(struct rte_eth_dev *dev __rte_unused, 390b3b413f7SBruce Richardson int wait_to_complete __rte_unused) { return 0; } 391b3b413f7SBruce Richardson 392*1ccec0a8STomasz Kulasek static int 393*1ccec0a8STomasz Kulasek eth_rss_reta_update(struct rte_eth_dev *dev, 394*1ccec0a8STomasz Kulasek struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size) 395*1ccec0a8STomasz Kulasek { 396*1ccec0a8STomasz Kulasek int i, j; 397*1ccec0a8STomasz Kulasek struct pmd_internals *internal = dev->data->dev_private; 398*1ccec0a8STomasz Kulasek 399*1ccec0a8STomasz Kulasek if (reta_size != internal->reta_size) 400*1ccec0a8STomasz Kulasek return -EINVAL; 401*1ccec0a8STomasz Kulasek 402*1ccec0a8STomasz Kulasek rte_spinlock_lock(&internal->rss_lock); 403*1ccec0a8STomasz Kulasek 404*1ccec0a8STomasz Kulasek /* Copy RETA table */ 405*1ccec0a8STomasz Kulasek for (i = 0; i < (internal->reta_size / RTE_RETA_GROUP_SIZE); i++) { 406*1ccec0a8STomasz Kulasek internal->reta_conf[i].mask = reta_conf[i].mask; 407*1ccec0a8STomasz Kulasek for (j = 0; j < RTE_RETA_GROUP_SIZE; j++) 408*1ccec0a8STomasz Kulasek if ((reta_conf[i].mask >> j) & 0x01) 409*1ccec0a8STomasz Kulasek internal->reta_conf[i].reta[j] = reta_conf[i].reta[j]; 410*1ccec0a8STomasz Kulasek } 411*1ccec0a8STomasz Kulasek 412*1ccec0a8STomasz Kulasek rte_spinlock_unlock(&internal->rss_lock); 413*1ccec0a8STomasz Kulasek 414*1ccec0a8STomasz Kulasek return 0; 415*1ccec0a8STomasz Kulasek } 416*1ccec0a8STomasz Kulasek 417*1ccec0a8STomasz Kulasek static int 418*1ccec0a8STomasz Kulasek eth_rss_reta_query(struct rte_eth_dev *dev, 419*1ccec0a8STomasz Kulasek struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size) 420*1ccec0a8STomasz Kulasek { 421*1ccec0a8STomasz Kulasek int i, j; 422*1ccec0a8STomasz Kulasek struct pmd_internals *internal = dev->data->dev_private; 423*1ccec0a8STomasz Kulasek 424*1ccec0a8STomasz Kulasek if (reta_size != internal->reta_size) 425*1ccec0a8STomasz Kulasek return -EINVAL; 426*1ccec0a8STomasz Kulasek 427*1ccec0a8STomasz Kulasek rte_spinlock_lock(&internal->rss_lock); 428*1ccec0a8STomasz Kulasek 429*1ccec0a8STomasz Kulasek /* Copy RETA table */ 430*1ccec0a8STomasz Kulasek for (i = 0; i < (internal->reta_size / RTE_RETA_GROUP_SIZE); i++) { 431*1ccec0a8STomasz Kulasek for (j = 0; j < RTE_RETA_GROUP_SIZE; j++) 432*1ccec0a8STomasz Kulasek if ((reta_conf[i].mask >> j) & 0x01) 433*1ccec0a8STomasz Kulasek reta_conf[i].reta[j] = internal->reta_conf[i].reta[j]; 434*1ccec0a8STomasz Kulasek } 435*1ccec0a8STomasz Kulasek 436*1ccec0a8STomasz Kulasek rte_spinlock_unlock(&internal->rss_lock); 437*1ccec0a8STomasz Kulasek 438*1ccec0a8STomasz Kulasek return 0; 439*1ccec0a8STomasz Kulasek } 440*1ccec0a8STomasz Kulasek 441*1ccec0a8STomasz Kulasek static int 442*1ccec0a8STomasz Kulasek eth_rss_hash_update(struct rte_eth_dev *dev, struct rte_eth_rss_conf *rss_conf) 443*1ccec0a8STomasz Kulasek { 444*1ccec0a8STomasz Kulasek struct pmd_internals *internal = dev->data->dev_private; 445*1ccec0a8STomasz Kulasek 446*1ccec0a8STomasz Kulasek rte_spinlock_lock(&internal->rss_lock); 447*1ccec0a8STomasz Kulasek 448*1ccec0a8STomasz Kulasek if ((rss_conf->rss_hf & internal->flow_type_rss_offloads) != 0) 449*1ccec0a8STomasz Kulasek dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf = 450*1ccec0a8STomasz Kulasek rss_conf->rss_hf & internal->flow_type_rss_offloads; 451*1ccec0a8STomasz Kulasek 452*1ccec0a8STomasz Kulasek if (rss_conf->rss_key) 453*1ccec0a8STomasz Kulasek rte_memcpy(internal->rss_key, rss_conf->rss_key, 40); 454*1ccec0a8STomasz Kulasek 455*1ccec0a8STomasz Kulasek rte_spinlock_unlock(&internal->rss_lock); 456*1ccec0a8STomasz Kulasek 457*1ccec0a8STomasz Kulasek return 0; 458*1ccec0a8STomasz Kulasek } 459*1ccec0a8STomasz Kulasek 460*1ccec0a8STomasz Kulasek static int 461*1ccec0a8STomasz Kulasek eth_rss_hash_conf_get(struct rte_eth_dev *dev, 462*1ccec0a8STomasz Kulasek struct rte_eth_rss_conf *rss_conf) 463*1ccec0a8STomasz Kulasek { 464*1ccec0a8STomasz Kulasek struct pmd_internals *internal = dev->data->dev_private; 465*1ccec0a8STomasz Kulasek 466*1ccec0a8STomasz Kulasek rte_spinlock_lock(&internal->rss_lock); 467*1ccec0a8STomasz Kulasek 468*1ccec0a8STomasz Kulasek rss_conf->rss_hf = dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf; 469*1ccec0a8STomasz Kulasek if (rss_conf->rss_key) 470*1ccec0a8STomasz Kulasek rte_memcpy(rss_conf->rss_key, internal->rss_key, 40); 471*1ccec0a8STomasz Kulasek 472*1ccec0a8STomasz Kulasek rte_spinlock_unlock(&internal->rss_lock); 473*1ccec0a8STomasz Kulasek 474*1ccec0a8STomasz Kulasek return 0; 475*1ccec0a8STomasz Kulasek } 476*1ccec0a8STomasz Kulasek 477b3b413f7SBruce Richardson static const struct eth_dev_ops ops = { 478b3b413f7SBruce Richardson .dev_start = eth_dev_start, 479b3b413f7SBruce Richardson .dev_stop = eth_dev_stop, 480b3b413f7SBruce Richardson .dev_configure = eth_dev_configure, 481b3b413f7SBruce Richardson .dev_infos_get = eth_dev_info, 482b3b413f7SBruce Richardson .rx_queue_setup = eth_rx_queue_setup, 483b3b413f7SBruce Richardson .tx_queue_setup = eth_tx_queue_setup, 484b3b413f7SBruce Richardson .rx_queue_release = eth_queue_release, 485b3b413f7SBruce Richardson .tx_queue_release = eth_queue_release, 486b3b413f7SBruce Richardson .link_update = eth_link_update, 487b3b413f7SBruce Richardson .stats_get = eth_stats_get, 488b3b413f7SBruce Richardson .stats_reset = eth_stats_reset, 489*1ccec0a8STomasz Kulasek .reta_update = eth_rss_reta_update, 490*1ccec0a8STomasz Kulasek .reta_query = eth_rss_reta_query, 491*1ccec0a8STomasz Kulasek .rss_hash_update = eth_rss_hash_update, 492*1ccec0a8STomasz Kulasek .rss_hash_conf_get = eth_rss_hash_conf_get 493b3b413f7SBruce Richardson }; 494b3b413f7SBruce Richardson 495ca575279STomasz Kulasek int 496b3b413f7SBruce Richardson eth_dev_null_create(const char *name, 497b3b413f7SBruce Richardson const unsigned numa_node, 498b3b413f7SBruce Richardson unsigned packet_size, 499b3b413f7SBruce Richardson unsigned packet_copy) 500b3b413f7SBruce Richardson { 501b3b413f7SBruce Richardson const unsigned nb_rx_queues = 1; 502b3b413f7SBruce Richardson const unsigned nb_tx_queues = 1; 503b3b413f7SBruce Richardson struct rte_eth_dev_data *data = NULL; 504b3b413f7SBruce Richardson struct rte_pci_device *pci_dev = NULL; 505b3b413f7SBruce Richardson struct pmd_internals *internals = NULL; 506b3b413f7SBruce Richardson struct rte_eth_dev *eth_dev = NULL; 507b3b413f7SBruce Richardson 508*1ccec0a8STomasz Kulasek static const uint8_t default_rss_key[40] = { 509*1ccec0a8STomasz Kulasek 0x6D, 0x5A, 0x56, 0xDA, 0x25, 0x5B, 0x0E, 0xC2, 0x41, 0x67, 0x25, 0x3D, 510*1ccec0a8STomasz Kulasek 0x43, 0xA3, 0x8F, 0xB0, 0xD0, 0xCA, 0x2B, 0xCB, 0xAE, 0x7B, 0x30, 0xB4, 511*1ccec0a8STomasz Kulasek 0x77, 0xCB, 0x2D, 0xA3, 0x80, 0x30, 0xF2, 0x0C, 0x6A, 0x42, 0xB7, 0x3B, 512*1ccec0a8STomasz Kulasek 0xBE, 0xAC, 0x01, 0xFA 513*1ccec0a8STomasz Kulasek }; 514*1ccec0a8STomasz Kulasek 515b3b413f7SBruce Richardson if (name == NULL) 516b3b413f7SBruce Richardson return -EINVAL; 517b3b413f7SBruce Richardson 518b3b413f7SBruce Richardson RTE_LOG(INFO, PMD, "Creating null ethdev on numa socket %u\n", 519b3b413f7SBruce Richardson numa_node); 520b3b413f7SBruce Richardson 521b3b413f7SBruce Richardson /* now do all data allocation - for eth_dev structure, dummy pci driver 522b3b413f7SBruce Richardson * and internal (private) data 523b3b413f7SBruce Richardson */ 524b3b413f7SBruce Richardson data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node); 525b3b413f7SBruce Richardson if (data == NULL) 526b3b413f7SBruce Richardson goto error; 527b3b413f7SBruce Richardson 528b3b413f7SBruce Richardson pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, numa_node); 529b3b413f7SBruce Richardson if (pci_dev == NULL) 530b3b413f7SBruce Richardson goto error; 531b3b413f7SBruce Richardson 532b3b413f7SBruce Richardson internals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node); 533b3b413f7SBruce Richardson if (internals == NULL) 534b3b413f7SBruce Richardson goto error; 535b3b413f7SBruce Richardson 536b3b413f7SBruce Richardson /* reserve an ethdev entry */ 537b3b413f7SBruce Richardson eth_dev = rte_eth_dev_allocate(name, RTE_ETH_DEV_VIRTUAL); 538b3b413f7SBruce Richardson if (eth_dev == NULL) 539b3b413f7SBruce Richardson goto error; 540b3b413f7SBruce Richardson 541b3b413f7SBruce Richardson /* now put it all together 542b3b413f7SBruce Richardson * - store queue data in internals, 543b3b413f7SBruce Richardson * - store numa_node info in pci_driver 544b3b413f7SBruce Richardson * - point eth_dev_data to internals and pci_driver 545b3b413f7SBruce Richardson * - and point eth_dev structure to new eth_dev_data structure 546b3b413f7SBruce Richardson */ 547b3b413f7SBruce Richardson /* NOTE: we'll replace the data element, of originally allocated eth_dev 548b3b413f7SBruce Richardson * so the nulls are local per-process */ 549b3b413f7SBruce Richardson 550b3b413f7SBruce Richardson internals->nb_rx_queues = nb_rx_queues; 551b3b413f7SBruce Richardson internals->nb_tx_queues = nb_tx_queues; 552b3b413f7SBruce Richardson internals->packet_size = packet_size; 553b3b413f7SBruce Richardson internals->packet_copy = packet_copy; 554b3b413f7SBruce Richardson internals->numa_node = numa_node; 555b3b413f7SBruce Richardson 556*1ccec0a8STomasz Kulasek internals->flow_type_rss_offloads = ETH_RSS_PROTO_MASK; 557*1ccec0a8STomasz Kulasek internals->reta_size = RTE_DIM(internals->reta_conf) * RTE_RETA_GROUP_SIZE; 558*1ccec0a8STomasz Kulasek 559*1ccec0a8STomasz Kulasek rte_memcpy(internals->rss_key, default_rss_key, 40); 560*1ccec0a8STomasz Kulasek 561b3b413f7SBruce Richardson pci_dev->numa_node = numa_node; 562c92db8aeSTomasz Kulasek pci_dev->driver = &rte_null_pmd.pci_drv; 563b3b413f7SBruce Richardson 564b3b413f7SBruce Richardson data->dev_private = internals; 565b3b413f7SBruce Richardson data->port_id = eth_dev->data->port_id; 566b3b413f7SBruce Richardson data->nb_rx_queues = (uint16_t)nb_rx_queues; 567b3b413f7SBruce Richardson data->nb_tx_queues = (uint16_t)nb_tx_queues; 568b3b413f7SBruce Richardson data->dev_link = pmd_link; 569b3b413f7SBruce Richardson data->mac_addrs = ð_addr; 570b3b413f7SBruce Richardson strncpy(data->name, eth_dev->data->name, strlen(eth_dev->data->name)); 571b3b413f7SBruce Richardson 572b3b413f7SBruce Richardson eth_dev->data = data; 573b3b413f7SBruce Richardson eth_dev->dev_ops = &ops; 574b3b413f7SBruce Richardson eth_dev->pci_dev = pci_dev; 575b3b413f7SBruce Richardson eth_dev->driver = &rte_null_pmd; 576c92db8aeSTomasz Kulasek TAILQ_INIT(ð_dev->link_intr_cbs); 577b3b413f7SBruce Richardson 578b3b413f7SBruce Richardson /* finally assign rx and tx ops */ 579b3b413f7SBruce Richardson if (packet_copy) { 580b3b413f7SBruce Richardson eth_dev->rx_pkt_burst = eth_null_copy_rx; 581b3b413f7SBruce Richardson eth_dev->tx_pkt_burst = eth_null_copy_tx; 582b3b413f7SBruce Richardson } else { 583b3b413f7SBruce Richardson eth_dev->rx_pkt_burst = eth_null_rx; 584b3b413f7SBruce Richardson eth_dev->tx_pkt_burst = eth_null_tx; 585b3b413f7SBruce Richardson } 586b3b413f7SBruce Richardson 587b3b413f7SBruce Richardson return 0; 588b3b413f7SBruce Richardson 589b3b413f7SBruce Richardson error: 590b3b413f7SBruce Richardson rte_free(data); 591b3b413f7SBruce Richardson rte_free(pci_dev); 592b3b413f7SBruce Richardson rte_free(internals); 593b3b413f7SBruce Richardson 594b3b413f7SBruce Richardson return -1; 595b3b413f7SBruce Richardson } 596b3b413f7SBruce Richardson 597b3b413f7SBruce Richardson static inline int 598b3b413f7SBruce Richardson get_packet_size_arg(const char *key __rte_unused, 599b3b413f7SBruce Richardson const char *value, void *extra_args) 600b3b413f7SBruce Richardson { 601b3b413f7SBruce Richardson const char *a = value; 602b3b413f7SBruce Richardson unsigned *packet_size = extra_args; 603b3b413f7SBruce Richardson 604b3b413f7SBruce Richardson if ((value == NULL) || (extra_args == NULL)) 605b3b413f7SBruce Richardson return -EINVAL; 606b3b413f7SBruce Richardson 607b3b413f7SBruce Richardson *packet_size = (unsigned)strtoul(a, NULL, 0); 608b3b413f7SBruce Richardson if (*packet_size == UINT_MAX) 609b3b413f7SBruce Richardson return -1; 610b3b413f7SBruce Richardson 611b3b413f7SBruce Richardson return 0; 612b3b413f7SBruce Richardson } 613b3b413f7SBruce Richardson 614b3b413f7SBruce Richardson static inline int 615b3b413f7SBruce Richardson get_packet_copy_arg(const char *key __rte_unused, 616b3b413f7SBruce Richardson const char *value, void *extra_args) 617b3b413f7SBruce Richardson { 618b3b413f7SBruce Richardson const char *a = value; 619b3b413f7SBruce Richardson unsigned *packet_copy = extra_args; 620b3b413f7SBruce Richardson 621b3b413f7SBruce Richardson if ((value == NULL) || (extra_args == NULL)) 622b3b413f7SBruce Richardson return -EINVAL; 623b3b413f7SBruce Richardson 624b3b413f7SBruce Richardson *packet_copy = (unsigned)strtoul(a, NULL, 0); 625b3b413f7SBruce Richardson if (*packet_copy == UINT_MAX) 626b3b413f7SBruce Richardson return -1; 627b3b413f7SBruce Richardson 628b3b413f7SBruce Richardson return 0; 629b3b413f7SBruce Richardson } 630b3b413f7SBruce Richardson 631b3b413f7SBruce Richardson static int 632b3b413f7SBruce Richardson rte_pmd_null_devinit(const char *name, const char *params) 633b3b413f7SBruce Richardson { 634b3b413f7SBruce Richardson unsigned numa_node; 635b3b413f7SBruce Richardson unsigned packet_size = default_packet_size; 636b3b413f7SBruce Richardson unsigned packet_copy = default_packet_copy; 637b3b413f7SBruce Richardson struct rte_kvargs *kvlist = NULL; 638b3b413f7SBruce Richardson int ret; 639b3b413f7SBruce Richardson 640b3b413f7SBruce Richardson if (name == NULL) 641b3b413f7SBruce Richardson return -EINVAL; 642b3b413f7SBruce Richardson 643b3b413f7SBruce Richardson RTE_LOG(INFO, PMD, "Initializing pmd_null for %s\n", name); 644b3b413f7SBruce Richardson 645b3b413f7SBruce Richardson numa_node = rte_socket_id(); 646b3b413f7SBruce Richardson 647b3b413f7SBruce Richardson if (params != NULL) { 648b3b413f7SBruce Richardson kvlist = rte_kvargs_parse(params, valid_arguments); 649b3b413f7SBruce Richardson if (kvlist == NULL) 650b3b413f7SBruce Richardson return -1; 651b3b413f7SBruce Richardson 652b3b413f7SBruce Richardson if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_SIZE_ARG) == 1) { 653b3b413f7SBruce Richardson 654b3b413f7SBruce Richardson ret = rte_kvargs_process(kvlist, 655b3b413f7SBruce Richardson ETH_NULL_PACKET_SIZE_ARG, 656b3b413f7SBruce Richardson &get_packet_size_arg, &packet_size); 657b3b413f7SBruce Richardson if (ret < 0) 658b3b413f7SBruce Richardson goto free_kvlist; 659b3b413f7SBruce Richardson } 660b3b413f7SBruce Richardson 661b3b413f7SBruce Richardson if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_COPY_ARG) == 1) { 662b3b413f7SBruce Richardson 663b3b413f7SBruce Richardson ret = rte_kvargs_process(kvlist, 664b3b413f7SBruce Richardson ETH_NULL_PACKET_COPY_ARG, 665b3b413f7SBruce Richardson &get_packet_copy_arg, &packet_copy); 666b3b413f7SBruce Richardson if (ret < 0) 667b3b413f7SBruce Richardson goto free_kvlist; 668b3b413f7SBruce Richardson } 669b3b413f7SBruce Richardson } 670b3b413f7SBruce Richardson 671b3b413f7SBruce Richardson RTE_LOG(INFO, PMD, "Configure pmd_null: packet size is %d, " 672b3b413f7SBruce Richardson "packet copy is %s\n", packet_size, 673b3b413f7SBruce Richardson packet_copy ? "enabled" : "disabled"); 674b3b413f7SBruce Richardson 675b3b413f7SBruce Richardson ret = eth_dev_null_create(name, numa_node, packet_size, packet_copy); 676b3b413f7SBruce Richardson 677b3b413f7SBruce Richardson free_kvlist: 678b3b413f7SBruce Richardson if (kvlist) 679b3b413f7SBruce Richardson rte_kvargs_free(kvlist); 680b3b413f7SBruce Richardson return ret; 681b3b413f7SBruce Richardson } 682b3b413f7SBruce Richardson 683b3b413f7SBruce Richardson static int 684b3b413f7SBruce Richardson rte_pmd_null_devuninit(const char *name) 685b3b413f7SBruce Richardson { 686b3b413f7SBruce Richardson struct rte_eth_dev *eth_dev = NULL; 687b3b413f7SBruce Richardson 688b3b413f7SBruce Richardson if (name == NULL) 689b3b413f7SBruce Richardson return -EINVAL; 690b3b413f7SBruce Richardson 691b3b413f7SBruce Richardson RTE_LOG(INFO, PMD, "Closing null ethdev on numa socket %u\n", 692b3b413f7SBruce Richardson rte_socket_id()); 693b3b413f7SBruce Richardson 694b3b413f7SBruce Richardson /* reserve an ethdev entry */ 695b3b413f7SBruce Richardson eth_dev = rte_eth_dev_allocated(name); 696b3b413f7SBruce Richardson if (eth_dev == NULL) 697b3b413f7SBruce Richardson return -1; 698b3b413f7SBruce Richardson 699b3b413f7SBruce Richardson rte_free(eth_dev->data->dev_private); 700b3b413f7SBruce Richardson rte_free(eth_dev->data); 701b3b413f7SBruce Richardson rte_free(eth_dev->pci_dev); 702b3b413f7SBruce Richardson 703b3b413f7SBruce Richardson rte_eth_dev_release_port(eth_dev); 704b3b413f7SBruce Richardson 705b3b413f7SBruce Richardson return 0; 706b3b413f7SBruce Richardson } 707b3b413f7SBruce Richardson 708b3b413f7SBruce Richardson static struct rte_driver pmd_null_drv = { 709b3b413f7SBruce Richardson .name = "eth_null", 710b3b413f7SBruce Richardson .type = PMD_VDEV, 711b3b413f7SBruce Richardson .init = rte_pmd_null_devinit, 712b3b413f7SBruce Richardson .uninit = rte_pmd_null_devuninit, 713b3b413f7SBruce Richardson }; 714b3b413f7SBruce Richardson 715b3b413f7SBruce Richardson PMD_REGISTER_DRIVER(pmd_null_drv); 716