1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2017 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <stdint.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 #include <rte_ethdev.h>
39 #include <rte_ethdev_vdev.h>
40 #include <rte_malloc.h>
41 #include <rte_bus_vdev.h>
42 #include <rte_kvargs.h>
43 #include <rte_errno.h>
44 #include <rte_ring.h>
45 #include <rte_sched.h>
46 #include <rte_tm_driver.h>
47 
48 #include "rte_eth_softnic.h"
49 #include "rte_eth_softnic_internals.h"
50 
51 #define DEV_HARD(p)					\
52 	(&rte_eth_devices[p->hard.port_id])
53 
54 #define PMD_PARAM_SOFT_TM					"soft_tm"
55 #define PMD_PARAM_SOFT_TM_RATE				"soft_tm_rate"
56 #define PMD_PARAM_SOFT_TM_NB_QUEUES			"soft_tm_nb_queues"
57 #define PMD_PARAM_SOFT_TM_QSIZE0			"soft_tm_qsize0"
58 #define PMD_PARAM_SOFT_TM_QSIZE1			"soft_tm_qsize1"
59 #define PMD_PARAM_SOFT_TM_QSIZE2			"soft_tm_qsize2"
60 #define PMD_PARAM_SOFT_TM_QSIZE3			"soft_tm_qsize3"
61 #define PMD_PARAM_SOFT_TM_ENQ_BSZ			"soft_tm_enq_bsz"
62 #define PMD_PARAM_SOFT_TM_DEQ_BSZ			"soft_tm_deq_bsz"
63 
64 #define PMD_PARAM_HARD_NAME					"hard_name"
65 #define PMD_PARAM_HARD_TX_QUEUE_ID			"hard_tx_queue_id"
66 
67 static const char *pmd_valid_args[] = {
68 	PMD_PARAM_SOFT_TM,
69 	PMD_PARAM_SOFT_TM_RATE,
70 	PMD_PARAM_SOFT_TM_NB_QUEUES,
71 	PMD_PARAM_SOFT_TM_QSIZE0,
72 	PMD_PARAM_SOFT_TM_QSIZE1,
73 	PMD_PARAM_SOFT_TM_QSIZE2,
74 	PMD_PARAM_SOFT_TM_QSIZE3,
75 	PMD_PARAM_SOFT_TM_ENQ_BSZ,
76 	PMD_PARAM_SOFT_TM_DEQ_BSZ,
77 	PMD_PARAM_HARD_NAME,
78 	PMD_PARAM_HARD_TX_QUEUE_ID,
79 	NULL
80 };
81 
82 static const struct rte_eth_dev_info pmd_dev_info = {
83 	.min_rx_bufsize = 0,
84 	.max_rx_pktlen = UINT32_MAX,
85 	.max_rx_queues = UINT16_MAX,
86 	.max_tx_queues = UINT16_MAX,
87 	.rx_desc_lim = {
88 		.nb_max = UINT16_MAX,
89 		.nb_min = 0,
90 		.nb_align = 1,
91 	},
92 	.tx_desc_lim = {
93 		.nb_max = UINT16_MAX,
94 		.nb_min = 0,
95 		.nb_align = 1,
96 	},
97 };
98 
99 static void
100 pmd_dev_infos_get(struct rte_eth_dev *dev __rte_unused,
101 	struct rte_eth_dev_info *dev_info)
102 {
103 	memcpy(dev_info, &pmd_dev_info, sizeof(*dev_info));
104 }
105 
106 static int
107 pmd_dev_configure(struct rte_eth_dev *dev)
108 {
109 	struct pmd_internals *p = dev->data->dev_private;
110 	struct rte_eth_dev *hard_dev = DEV_HARD(p);
111 
112 	if (dev->data->nb_rx_queues > hard_dev->data->nb_rx_queues)
113 		return -1;
114 
115 	if (p->params.hard.tx_queue_id >= hard_dev->data->nb_tx_queues)
116 		return -1;
117 
118 	return 0;
119 }
120 
121 static int
122 pmd_rx_queue_setup(struct rte_eth_dev *dev,
123 	uint16_t rx_queue_id,
124 	uint16_t nb_rx_desc __rte_unused,
125 	unsigned int socket_id,
126 	const struct rte_eth_rxconf *rx_conf __rte_unused,
127 	struct rte_mempool *mb_pool __rte_unused)
128 {
129 	struct pmd_internals *p = dev->data->dev_private;
130 
131 	if (p->params.soft.intrusive == 0) {
132 		struct pmd_rx_queue *rxq;
133 
134 		rxq = rte_zmalloc_socket(p->params.soft.name,
135 			sizeof(struct pmd_rx_queue), 0, socket_id);
136 		if (rxq == NULL)
137 			return -ENOMEM;
138 
139 		rxq->hard.port_id = p->hard.port_id;
140 		rxq->hard.rx_queue_id = rx_queue_id;
141 		dev->data->rx_queues[rx_queue_id] = rxq;
142 	} else {
143 		struct rte_eth_dev *hard_dev = DEV_HARD(p);
144 		void *rxq = hard_dev->data->rx_queues[rx_queue_id];
145 
146 		if (rxq == NULL)
147 			return -1;
148 
149 		dev->data->rx_queues[rx_queue_id] = rxq;
150 	}
151 	return 0;
152 }
153 
154 static int
155 pmd_tx_queue_setup(struct rte_eth_dev *dev,
156 	uint16_t tx_queue_id,
157 	uint16_t nb_tx_desc,
158 	unsigned int socket_id,
159 	const struct rte_eth_txconf *tx_conf __rte_unused)
160 {
161 	uint32_t size = RTE_ETH_NAME_MAX_LEN + strlen("_txq") + 4;
162 	char name[size];
163 	struct rte_ring *r;
164 
165 	snprintf(name, sizeof(name), "%s_txq%04x",
166 		dev->data->name, tx_queue_id);
167 	r = rte_ring_create(name, nb_tx_desc, socket_id,
168 		RING_F_SP_ENQ | RING_F_SC_DEQ);
169 	if (r == NULL)
170 		return -1;
171 
172 	dev->data->tx_queues[tx_queue_id] = r;
173 	return 0;
174 }
175 
176 static int
177 pmd_dev_start(struct rte_eth_dev *dev)
178 {
179 	struct pmd_internals *p = dev->data->dev_private;
180 
181 	if (tm_used(dev)) {
182 		int status = tm_start(p);
183 
184 		if (status)
185 			return status;
186 	}
187 
188 	dev->data->dev_link.link_status = ETH_LINK_UP;
189 
190 	if (p->params.soft.intrusive) {
191 		struct rte_eth_dev *hard_dev = DEV_HARD(p);
192 
193 		/* The hard_dev->rx_pkt_burst should be stable by now */
194 		dev->rx_pkt_burst = hard_dev->rx_pkt_burst;
195 	}
196 
197 	return 0;
198 }
199 
200 static void
201 pmd_dev_stop(struct rte_eth_dev *dev)
202 {
203 	struct pmd_internals *p = dev->data->dev_private;
204 
205 	dev->data->dev_link.link_status = ETH_LINK_DOWN;
206 
207 	if (tm_used(dev))
208 		tm_stop(p);
209 }
210 
211 static void
212 pmd_dev_close(struct rte_eth_dev *dev)
213 {
214 	uint32_t i;
215 
216 	/* TX queues */
217 	for (i = 0; i < dev->data->nb_tx_queues; i++)
218 		rte_ring_free((struct rte_ring *)dev->data->tx_queues[i]);
219 }
220 
221 static int
222 pmd_link_update(struct rte_eth_dev *dev __rte_unused,
223 	int wait_to_complete __rte_unused)
224 {
225 	return 0;
226 }
227 
228 static int
229 pmd_tm_ops_get(struct rte_eth_dev *dev, void *arg)
230 {
231 	*(const struct rte_tm_ops **)arg =
232 		(tm_enabled(dev)) ? &pmd_tm_ops : NULL;
233 
234 	return 0;
235 }
236 
237 static const struct eth_dev_ops pmd_ops = {
238 	.dev_configure = pmd_dev_configure,
239 	.dev_start = pmd_dev_start,
240 	.dev_stop = pmd_dev_stop,
241 	.dev_close = pmd_dev_close,
242 	.link_update = pmd_link_update,
243 	.dev_infos_get = pmd_dev_infos_get,
244 	.rx_queue_setup = pmd_rx_queue_setup,
245 	.tx_queue_setup = pmd_tx_queue_setup,
246 	.tm_ops_get = pmd_tm_ops_get,
247 };
248 
249 static uint16_t
250 pmd_rx_pkt_burst(void *rxq,
251 	struct rte_mbuf **rx_pkts,
252 	uint16_t nb_pkts)
253 {
254 	struct pmd_rx_queue *rx_queue = rxq;
255 
256 	return rte_eth_rx_burst(rx_queue->hard.port_id,
257 		rx_queue->hard.rx_queue_id,
258 		rx_pkts,
259 		nb_pkts);
260 }
261 
262 static uint16_t
263 pmd_tx_pkt_burst(void *txq,
264 	struct rte_mbuf **tx_pkts,
265 	uint16_t nb_pkts)
266 {
267 	return (uint16_t)rte_ring_enqueue_burst(txq,
268 		(void **)tx_pkts,
269 		nb_pkts,
270 		NULL);
271 }
272 
273 static __rte_always_inline int
274 run_default(struct rte_eth_dev *dev)
275 {
276 	struct pmd_internals *p = dev->data->dev_private;
277 
278 	/* Persistent context: Read Only (update not required) */
279 	struct rte_mbuf **pkts = p->soft.def.pkts;
280 	uint16_t nb_tx_queues = dev->data->nb_tx_queues;
281 
282 	/* Persistent context: Read - Write (update required) */
283 	uint32_t txq_pos = p->soft.def.txq_pos;
284 	uint32_t pkts_len = p->soft.def.pkts_len;
285 	uint32_t flush_count = p->soft.def.flush_count;
286 
287 	/* Not part of the persistent context */
288 	uint32_t pos;
289 	uint16_t i;
290 
291 	/* Soft device TXQ read, Hard device TXQ write */
292 	for (i = 0; i < nb_tx_queues; i++) {
293 		struct rte_ring *txq = dev->data->tx_queues[txq_pos];
294 
295 		/* Read soft device TXQ burst to packet enqueue buffer */
296 		pkts_len += rte_ring_sc_dequeue_burst(txq,
297 			(void **)&pkts[pkts_len],
298 			DEFAULT_BURST_SIZE,
299 			NULL);
300 
301 		/* Increment soft device TXQ */
302 		txq_pos++;
303 		if (txq_pos >= nb_tx_queues)
304 			txq_pos = 0;
305 
306 		/* Hard device TXQ write when complete burst is available */
307 		if (pkts_len >= DEFAULT_BURST_SIZE) {
308 			for (pos = 0; pos < pkts_len; )
309 				pos += rte_eth_tx_burst(p->hard.port_id,
310 					p->params.hard.tx_queue_id,
311 					&pkts[pos],
312 					(uint16_t)(pkts_len - pos));
313 
314 			pkts_len = 0;
315 			flush_count = 0;
316 			break;
317 		}
318 	}
319 
320 	if (flush_count >= FLUSH_COUNT_THRESHOLD) {
321 		for (pos = 0; pos < pkts_len; )
322 			pos += rte_eth_tx_burst(p->hard.port_id,
323 				p->params.hard.tx_queue_id,
324 				&pkts[pos],
325 				(uint16_t)(pkts_len - pos));
326 
327 		pkts_len = 0;
328 		flush_count = 0;
329 	}
330 
331 	p->soft.def.txq_pos = txq_pos;
332 	p->soft.def.pkts_len = pkts_len;
333 	p->soft.def.flush_count = flush_count + 1;
334 
335 	return 0;
336 }
337 
338 static __rte_always_inline int
339 run_tm(struct rte_eth_dev *dev)
340 {
341 	struct pmd_internals *p = dev->data->dev_private;
342 
343 	/* Persistent context: Read Only (update not required) */
344 	struct rte_sched_port *sched = p->soft.tm.sched;
345 	struct rte_mbuf **pkts_enq = p->soft.tm.pkts_enq;
346 	struct rte_mbuf **pkts_deq = p->soft.tm.pkts_deq;
347 	uint32_t enq_bsz = p->params.soft.tm.enq_bsz;
348 	uint32_t deq_bsz = p->params.soft.tm.deq_bsz;
349 	uint16_t nb_tx_queues = dev->data->nb_tx_queues;
350 
351 	/* Persistent context: Read - Write (update required) */
352 	uint32_t txq_pos = p->soft.tm.txq_pos;
353 	uint32_t pkts_enq_len = p->soft.tm.pkts_enq_len;
354 	uint32_t flush_count = p->soft.tm.flush_count;
355 
356 	/* Not part of the persistent context */
357 	uint32_t pkts_deq_len, pos;
358 	uint16_t i;
359 
360 	/* Soft device TXQ read, TM enqueue */
361 	for (i = 0; i < nb_tx_queues; i++) {
362 		struct rte_ring *txq = dev->data->tx_queues[txq_pos];
363 
364 		/* Read TXQ burst to packet enqueue buffer */
365 		pkts_enq_len += rte_ring_sc_dequeue_burst(txq,
366 			(void **)&pkts_enq[pkts_enq_len],
367 			enq_bsz,
368 			NULL);
369 
370 		/* Increment TXQ */
371 		txq_pos++;
372 		if (txq_pos >= nb_tx_queues)
373 			txq_pos = 0;
374 
375 		/* TM enqueue when complete burst is available */
376 		if (pkts_enq_len >= enq_bsz) {
377 			rte_sched_port_enqueue(sched, pkts_enq, pkts_enq_len);
378 
379 			pkts_enq_len = 0;
380 			flush_count = 0;
381 			break;
382 		}
383 	}
384 
385 	if (flush_count >= FLUSH_COUNT_THRESHOLD) {
386 		if (pkts_enq_len)
387 			rte_sched_port_enqueue(sched, pkts_enq, pkts_enq_len);
388 
389 		pkts_enq_len = 0;
390 		flush_count = 0;
391 	}
392 
393 	p->soft.tm.txq_pos = txq_pos;
394 	p->soft.tm.pkts_enq_len = pkts_enq_len;
395 	p->soft.tm.flush_count = flush_count + 1;
396 
397 	/* TM dequeue, Hard device TXQ write */
398 	pkts_deq_len = rte_sched_port_dequeue(sched, pkts_deq, deq_bsz);
399 
400 	for (pos = 0; pos < pkts_deq_len; )
401 		pos += rte_eth_tx_burst(p->hard.port_id,
402 			p->params.hard.tx_queue_id,
403 			&pkts_deq[pos],
404 			(uint16_t)(pkts_deq_len - pos));
405 
406 	return 0;
407 }
408 
409 int
410 rte_pmd_softnic_run(uint16_t port_id)
411 {
412 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
413 
414 #ifdef RTE_LIBRTE_ETHDEV_DEBUG
415 	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, 0);
416 #endif
417 
418 	return (tm_used(dev)) ? run_tm(dev) : run_default(dev);
419 }
420 
421 static struct ether_addr eth_addr = { .addr_bytes = {0} };
422 
423 static uint32_t
424 eth_dev_speed_max_mbps(uint32_t speed_capa)
425 {
426 	uint32_t rate_mbps[32] = {
427 		ETH_SPEED_NUM_NONE,
428 		ETH_SPEED_NUM_10M,
429 		ETH_SPEED_NUM_10M,
430 		ETH_SPEED_NUM_100M,
431 		ETH_SPEED_NUM_100M,
432 		ETH_SPEED_NUM_1G,
433 		ETH_SPEED_NUM_2_5G,
434 		ETH_SPEED_NUM_5G,
435 		ETH_SPEED_NUM_10G,
436 		ETH_SPEED_NUM_20G,
437 		ETH_SPEED_NUM_25G,
438 		ETH_SPEED_NUM_40G,
439 		ETH_SPEED_NUM_50G,
440 		ETH_SPEED_NUM_56G,
441 		ETH_SPEED_NUM_100G,
442 	};
443 
444 	uint32_t pos = (speed_capa) ? (31 - __builtin_clz(speed_capa)) : 0;
445 	return rate_mbps[pos];
446 }
447 
448 static int
449 default_init(struct pmd_internals *p,
450 	struct pmd_params *params,
451 	int numa_node)
452 {
453 	p->soft.def.pkts = rte_zmalloc_socket(params->soft.name,
454 		2 * DEFAULT_BURST_SIZE * sizeof(struct rte_mbuf *),
455 		0,
456 		numa_node);
457 
458 	if (p->soft.def.pkts == NULL)
459 		return -ENOMEM;
460 
461 	return 0;
462 }
463 
464 static void
465 default_free(struct pmd_internals *p)
466 {
467 	rte_free(p->soft.def.pkts);
468 }
469 
470 static void *
471 pmd_init(struct pmd_params *params, int numa_node)
472 {
473 	struct pmd_internals *p;
474 	int status;
475 
476 	p = rte_zmalloc_socket(params->soft.name,
477 		sizeof(struct pmd_internals),
478 		0,
479 		numa_node);
480 	if (p == NULL)
481 		return NULL;
482 
483 	memcpy(&p->params, params, sizeof(p->params));
484 	rte_eth_dev_get_port_by_name(params->hard.name, &p->hard.port_id);
485 
486 	/* Default */
487 	status = default_init(p, params, numa_node);
488 	if (status) {
489 		free(p->params.hard.name);
490 		rte_free(p);
491 		return NULL;
492 	}
493 
494 	/* Traffic Management (TM)*/
495 	if (params->soft.flags & PMD_FEATURE_TM) {
496 		status = tm_init(p, params, numa_node);
497 		if (status) {
498 			default_free(p);
499 			free(p->params.hard.name);
500 			rte_free(p);
501 			return NULL;
502 		}
503 	}
504 
505 	return p;
506 }
507 
508 static void
509 pmd_free(struct pmd_internals *p)
510 {
511 	if (p->params.soft.flags & PMD_FEATURE_TM)
512 		tm_free(p);
513 
514 	default_free(p);
515 
516 	free(p->params.hard.name);
517 	rte_free(p);
518 }
519 
520 static int
521 pmd_ethdev_register(struct rte_vdev_device *vdev,
522 	struct pmd_params *params,
523 	void *dev_private)
524 {
525 	struct rte_eth_dev_info hard_info;
526 	struct rte_eth_dev *soft_dev;
527 	uint32_t hard_speed;
528 	int numa_node;
529 	uint16_t hard_port_id;
530 
531 	rte_eth_dev_get_port_by_name(params->hard.name, &hard_port_id);
532 	rte_eth_dev_info_get(hard_port_id, &hard_info);
533 	hard_speed = eth_dev_speed_max_mbps(hard_info.speed_capa);
534 	numa_node = rte_eth_dev_socket_id(hard_port_id);
535 
536 	/* Ethdev entry allocation */
537 	soft_dev = rte_eth_dev_allocate(params->soft.name);
538 	if (!soft_dev)
539 		return -ENOMEM;
540 
541 	/* dev */
542 	soft_dev->rx_pkt_burst = (params->soft.intrusive) ?
543 		NULL : /* set up later */
544 		pmd_rx_pkt_burst;
545 	soft_dev->tx_pkt_burst = pmd_tx_pkt_burst;
546 	soft_dev->tx_pkt_prepare = NULL;
547 	soft_dev->dev_ops = &pmd_ops;
548 	soft_dev->device = &vdev->device;
549 
550 	/* dev->data */
551 	soft_dev->data->dev_private = dev_private;
552 	soft_dev->data->dev_link.link_speed = hard_speed;
553 	soft_dev->data->dev_link.link_duplex = ETH_LINK_FULL_DUPLEX;
554 	soft_dev->data->dev_link.link_autoneg = ETH_LINK_FIXED;
555 	soft_dev->data->dev_link.link_status = ETH_LINK_DOWN;
556 	soft_dev->data->mac_addrs = &eth_addr;
557 	soft_dev->data->promiscuous = 1;
558 	soft_dev->data->kdrv = RTE_KDRV_NONE;
559 	soft_dev->data->numa_node = numa_node;
560 
561 	return 0;
562 }
563 
564 static int
565 get_string(const char *key __rte_unused, const char *value, void *extra_args)
566 {
567 	if (!value || !extra_args)
568 		return -EINVAL;
569 
570 	*(char **)extra_args = strdup(value);
571 
572 	if (!*(char **)extra_args)
573 		return -ENOMEM;
574 
575 	return 0;
576 }
577 
578 static int
579 get_uint32(const char *key __rte_unused, const char *value, void *extra_args)
580 {
581 	if (!value || !extra_args)
582 		return -EINVAL;
583 
584 	*(uint32_t *)extra_args = strtoull(value, NULL, 0);
585 
586 	return 0;
587 }
588 
589 static int
590 pmd_parse_args(struct pmd_params *p, const char *name, const char *params)
591 {
592 	struct rte_kvargs *kvlist;
593 	int i, ret;
594 
595 	kvlist = rte_kvargs_parse(params, pmd_valid_args);
596 	if (kvlist == NULL)
597 		return -EINVAL;
598 
599 	/* Set default values */
600 	memset(p, 0, sizeof(*p));
601 	p->soft.name = name;
602 	p->soft.intrusive = INTRUSIVE;
603 	p->soft.tm.rate = 0;
604 	p->soft.tm.nb_queues = SOFTNIC_SOFT_TM_NB_QUEUES;
605 	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
606 		p->soft.tm.qsize[i] = SOFTNIC_SOFT_TM_QUEUE_SIZE;
607 	p->soft.tm.enq_bsz = SOFTNIC_SOFT_TM_ENQ_BSZ;
608 	p->soft.tm.deq_bsz = SOFTNIC_SOFT_TM_DEQ_BSZ;
609 	p->hard.tx_queue_id = SOFTNIC_HARD_TX_QUEUE_ID;
610 
611 	/* SOFT: TM (optional) */
612 	if (rte_kvargs_count(kvlist, PMD_PARAM_SOFT_TM) == 1) {
613 		char *s;
614 
615 		ret = rte_kvargs_process(kvlist, PMD_PARAM_SOFT_TM,
616 			&get_string, &s);
617 		if (ret < 0)
618 			goto out_free;
619 
620 		if (strcmp(s, "on") == 0)
621 			p->soft.flags |= PMD_FEATURE_TM;
622 		else if (strcmp(s, "off") == 0)
623 			p->soft.flags &= ~PMD_FEATURE_TM;
624 		else
625 			ret = -EINVAL;
626 
627 		free(s);
628 		if (ret)
629 			goto out_free;
630 	}
631 
632 	/* SOFT: TM rate (measured in bytes/second) (optional) */
633 	if (rte_kvargs_count(kvlist, PMD_PARAM_SOFT_TM_RATE) == 1) {
634 		ret = rte_kvargs_process(kvlist, PMD_PARAM_SOFT_TM_RATE,
635 			&get_uint32, &p->soft.tm.rate);
636 		if (ret < 0)
637 			goto out_free;
638 
639 		p->soft.flags |= PMD_FEATURE_TM;
640 	}
641 
642 	/* SOFT: TM number of queues (optional) */
643 	if (rte_kvargs_count(kvlist, PMD_PARAM_SOFT_TM_NB_QUEUES) == 1) {
644 		ret = rte_kvargs_process(kvlist, PMD_PARAM_SOFT_TM_NB_QUEUES,
645 			&get_uint32, &p->soft.tm.nb_queues);
646 		if (ret < 0)
647 			goto out_free;
648 
649 		p->soft.flags |= PMD_FEATURE_TM;
650 	}
651 
652 	/* SOFT: TM queue size 0 .. 3 (optional) */
653 	if (rte_kvargs_count(kvlist, PMD_PARAM_SOFT_TM_QSIZE0) == 1) {
654 		uint32_t qsize;
655 
656 		ret = rte_kvargs_process(kvlist, PMD_PARAM_SOFT_TM_QSIZE0,
657 			&get_uint32, &qsize);
658 		if (ret < 0)
659 			goto out_free;
660 
661 		p->soft.tm.qsize[0] = (uint16_t)qsize;
662 		p->soft.flags |= PMD_FEATURE_TM;
663 	}
664 
665 	if (rte_kvargs_count(kvlist, PMD_PARAM_SOFT_TM_QSIZE1) == 1) {
666 		uint32_t qsize;
667 
668 		ret = rte_kvargs_process(kvlist, PMD_PARAM_SOFT_TM_QSIZE1,
669 			&get_uint32, &qsize);
670 		if (ret < 0)
671 			goto out_free;
672 
673 		p->soft.tm.qsize[1] = (uint16_t)qsize;
674 		p->soft.flags |= PMD_FEATURE_TM;
675 	}
676 
677 	if (rte_kvargs_count(kvlist, PMD_PARAM_SOFT_TM_QSIZE2) == 1) {
678 		uint32_t qsize;
679 
680 		ret = rte_kvargs_process(kvlist, PMD_PARAM_SOFT_TM_QSIZE2,
681 			&get_uint32, &qsize);
682 		if (ret < 0)
683 			goto out_free;
684 
685 		p->soft.tm.qsize[2] = (uint16_t)qsize;
686 		p->soft.flags |= PMD_FEATURE_TM;
687 	}
688 
689 	if (rte_kvargs_count(kvlist, PMD_PARAM_SOFT_TM_QSIZE3) == 1) {
690 		uint32_t qsize;
691 
692 		ret = rte_kvargs_process(kvlist, PMD_PARAM_SOFT_TM_QSIZE3,
693 			&get_uint32, &qsize);
694 		if (ret < 0)
695 			goto out_free;
696 
697 		p->soft.tm.qsize[3] = (uint16_t)qsize;
698 		p->soft.flags |= PMD_FEATURE_TM;
699 	}
700 
701 	/* SOFT: TM enqueue burst size (optional) */
702 	if (rte_kvargs_count(kvlist, PMD_PARAM_SOFT_TM_ENQ_BSZ) == 1) {
703 		ret = rte_kvargs_process(kvlist, PMD_PARAM_SOFT_TM_ENQ_BSZ,
704 			&get_uint32, &p->soft.tm.enq_bsz);
705 		if (ret < 0)
706 			goto out_free;
707 
708 		p->soft.flags |= PMD_FEATURE_TM;
709 	}
710 
711 	/* SOFT: TM dequeue burst size (optional) */
712 	if (rte_kvargs_count(kvlist, PMD_PARAM_SOFT_TM_DEQ_BSZ) == 1) {
713 		ret = rte_kvargs_process(kvlist, PMD_PARAM_SOFT_TM_DEQ_BSZ,
714 			&get_uint32, &p->soft.tm.deq_bsz);
715 		if (ret < 0)
716 			goto out_free;
717 
718 		p->soft.flags |= PMD_FEATURE_TM;
719 	}
720 
721 	/* HARD: name (mandatory) */
722 	if (rte_kvargs_count(kvlist, PMD_PARAM_HARD_NAME) == 1) {
723 		ret = rte_kvargs_process(kvlist, PMD_PARAM_HARD_NAME,
724 			&get_string, &p->hard.name);
725 		if (ret < 0)
726 			goto out_free;
727 	} else {
728 		ret = -EINVAL;
729 		goto out_free;
730 	}
731 
732 	/* HARD: tx_queue_id (optional) */
733 	if (rte_kvargs_count(kvlist, PMD_PARAM_HARD_TX_QUEUE_ID) == 1) {
734 		ret = rte_kvargs_process(kvlist, PMD_PARAM_HARD_TX_QUEUE_ID,
735 			&get_uint32, &p->hard.tx_queue_id);
736 		if (ret < 0)
737 			goto out_free;
738 	}
739 
740 out_free:
741 	rte_kvargs_free(kvlist);
742 	return ret;
743 }
744 
745 static int
746 pmd_probe(struct rte_vdev_device *vdev)
747 {
748 	struct pmd_params p;
749 	const char *params;
750 	int status;
751 
752 	struct rte_eth_dev_info hard_info;
753 	uint32_t hard_speed;
754 	uint16_t hard_port_id;
755 	int numa_node;
756 	void *dev_private;
757 
758 	RTE_LOG(INFO, PMD,
759 		"Probing device \"%s\"\n",
760 		rte_vdev_device_name(vdev));
761 
762 	/* Parse input arguments */
763 	params = rte_vdev_device_args(vdev);
764 	if (!params)
765 		return -EINVAL;
766 
767 	status = pmd_parse_args(&p, rte_vdev_device_name(vdev), params);
768 	if (status)
769 		return status;
770 
771 	/* Check input arguments */
772 	if (rte_eth_dev_get_port_by_name(p.hard.name, &hard_port_id))
773 		return -EINVAL;
774 
775 	rte_eth_dev_info_get(hard_port_id, &hard_info);
776 	hard_speed = eth_dev_speed_max_mbps(hard_info.speed_capa);
777 	numa_node = rte_eth_dev_socket_id(hard_port_id);
778 
779 	if (p.hard.tx_queue_id >= hard_info.max_tx_queues)
780 		return -EINVAL;
781 
782 	if (p.soft.flags & PMD_FEATURE_TM) {
783 		status = tm_params_check(&p, hard_speed);
784 
785 		if (status)
786 			return status;
787 	}
788 
789 	/* Allocate and initialize soft ethdev private data */
790 	dev_private = pmd_init(&p, numa_node);
791 	if (dev_private == NULL)
792 		return -ENOMEM;
793 
794 	/* Register soft ethdev */
795 	RTE_LOG(INFO, PMD,
796 		"Creating soft ethdev \"%s\" for hard ethdev \"%s\"\n",
797 		p.soft.name, p.hard.name);
798 
799 	status = pmd_ethdev_register(vdev, &p, dev_private);
800 	if (status) {
801 		pmd_free(dev_private);
802 		return status;
803 	}
804 
805 	return 0;
806 }
807 
808 static int
809 pmd_remove(struct rte_vdev_device *vdev)
810 {
811 	struct rte_eth_dev *dev = NULL;
812 	struct pmd_internals *p;
813 
814 	if (!vdev)
815 		return -EINVAL;
816 
817 	RTE_LOG(INFO, PMD, "Removing device \"%s\"\n",
818 		rte_vdev_device_name(vdev));
819 
820 	/* Find the ethdev entry */
821 	dev = rte_eth_dev_allocated(rte_vdev_device_name(vdev));
822 	if (dev == NULL)
823 		return -ENODEV;
824 	p = dev->data->dev_private;
825 
826 	/* Free device data structures*/
827 	pmd_free(p);
828 	rte_free(dev->data);
829 	rte_eth_dev_release_port(dev);
830 
831 	return 0;
832 }
833 
834 static struct rte_vdev_driver pmd_softnic_drv = {
835 	.probe = pmd_probe,
836 	.remove = pmd_remove,
837 };
838 
839 RTE_PMD_REGISTER_VDEV(net_softnic, pmd_softnic_drv);
840 RTE_PMD_REGISTER_PARAM_STRING(net_softnic,
841 	PMD_PARAM_SOFT_TM	 "=on|off "
842 	PMD_PARAM_SOFT_TM_RATE "=<int> "
843 	PMD_PARAM_SOFT_TM_NB_QUEUES "=<int> "
844 	PMD_PARAM_SOFT_TM_QSIZE0 "=<int> "
845 	PMD_PARAM_SOFT_TM_QSIZE1 "=<int> "
846 	PMD_PARAM_SOFT_TM_QSIZE2 "=<int> "
847 	PMD_PARAM_SOFT_TM_QSIZE3 "=<int> "
848 	PMD_PARAM_SOFT_TM_ENQ_BSZ "=<int> "
849 	PMD_PARAM_SOFT_TM_DEQ_BSZ "=<int> "
850 	PMD_PARAM_HARD_NAME "=<string> "
851 	PMD_PARAM_HARD_TX_QUEUE_ID "=<int>");
852