xref: /dpdk/lib/port/rte_port_sched.c (revision ae67895b507bb6af22263c79ba0d5c374b396485)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2010-2014 Intel Corporation
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson #include <string.h>
599a2dd95SBruce Richardson 
699a2dd95SBruce Richardson #include <rte_malloc.h>
799a2dd95SBruce Richardson 
899a2dd95SBruce Richardson #include "rte_port_sched.h"
999a2dd95SBruce Richardson 
10*ae67895bSDavid Marchand #include "port_log.h"
11*ae67895bSDavid Marchand 
1299a2dd95SBruce Richardson /*
1399a2dd95SBruce Richardson  * Reader
1499a2dd95SBruce Richardson  */
1599a2dd95SBruce Richardson #ifdef RTE_PORT_STATS_COLLECT
1699a2dd95SBruce Richardson 
1799a2dd95SBruce Richardson #define RTE_PORT_SCHED_READER_PKTS_IN_ADD(port, val) \
1899a2dd95SBruce Richardson 	port->stats.n_pkts_in += val
1999a2dd95SBruce Richardson #define RTE_PORT_SCHED_READER_PKTS_DROP_ADD(port, val) \
2099a2dd95SBruce Richardson 	port->stats.n_pkts_drop += val
2199a2dd95SBruce Richardson 
2299a2dd95SBruce Richardson #else
2399a2dd95SBruce Richardson 
2499a2dd95SBruce Richardson #define RTE_PORT_SCHED_READER_PKTS_IN_ADD(port, val)
2599a2dd95SBruce Richardson #define RTE_PORT_SCHED_READER_PKTS_DROP_ADD(port, val)
2699a2dd95SBruce Richardson 
2799a2dd95SBruce Richardson #endif
2899a2dd95SBruce Richardson 
2999a2dd95SBruce Richardson struct rte_port_sched_reader {
3099a2dd95SBruce Richardson 	struct rte_port_in_stats stats;
3199a2dd95SBruce Richardson 
3299a2dd95SBruce Richardson 	struct rte_sched_port *sched;
3399a2dd95SBruce Richardson };
3499a2dd95SBruce Richardson 
3599a2dd95SBruce Richardson static void *
rte_port_sched_reader_create(void * params,int socket_id)3699a2dd95SBruce Richardson rte_port_sched_reader_create(void *params, int socket_id)
3799a2dd95SBruce Richardson {
3899a2dd95SBruce Richardson 	struct rte_port_sched_reader_params *conf =
3999a2dd95SBruce Richardson 			params;
4099a2dd95SBruce Richardson 	struct rte_port_sched_reader *port;
4199a2dd95SBruce Richardson 
4299a2dd95SBruce Richardson 	/* Check input parameters */
4399a2dd95SBruce Richardson 	if ((conf == NULL) ||
4499a2dd95SBruce Richardson 	    (conf->sched == NULL)) {
45*ae67895bSDavid Marchand 		PORT_LOG(ERR, "%s: Invalid params", __func__);
4699a2dd95SBruce Richardson 		return NULL;
4799a2dd95SBruce Richardson 	}
4899a2dd95SBruce Richardson 
4999a2dd95SBruce Richardson 	/* Memory allocation */
5099a2dd95SBruce Richardson 	port = rte_zmalloc_socket("PORT", sizeof(*port),
5199a2dd95SBruce Richardson 			RTE_CACHE_LINE_SIZE, socket_id);
5299a2dd95SBruce Richardson 	if (port == NULL) {
53*ae67895bSDavid Marchand 		PORT_LOG(ERR, "%s: Failed to allocate port", __func__);
5499a2dd95SBruce Richardson 		return NULL;
5599a2dd95SBruce Richardson 	}
5699a2dd95SBruce Richardson 
5799a2dd95SBruce Richardson 	/* Initialization */
5899a2dd95SBruce Richardson 	port->sched = conf->sched;
5999a2dd95SBruce Richardson 
6099a2dd95SBruce Richardson 	return port;
6199a2dd95SBruce Richardson }
6299a2dd95SBruce Richardson 
6399a2dd95SBruce Richardson static int
rte_port_sched_reader_rx(void * port,struct rte_mbuf ** pkts,uint32_t n_pkts)6499a2dd95SBruce Richardson rte_port_sched_reader_rx(void *port, struct rte_mbuf **pkts, uint32_t n_pkts)
6599a2dd95SBruce Richardson {
6699a2dd95SBruce Richardson 	struct rte_port_sched_reader *p = port;
6799a2dd95SBruce Richardson 	uint32_t nb_rx;
6899a2dd95SBruce Richardson 
6999a2dd95SBruce Richardson 	nb_rx = rte_sched_port_dequeue(p->sched, pkts, n_pkts);
7099a2dd95SBruce Richardson 	RTE_PORT_SCHED_READER_PKTS_IN_ADD(p, nb_rx);
7199a2dd95SBruce Richardson 
7299a2dd95SBruce Richardson 	return nb_rx;
7399a2dd95SBruce Richardson }
7499a2dd95SBruce Richardson 
7599a2dd95SBruce Richardson static int
rte_port_sched_reader_free(void * port)7699a2dd95SBruce Richardson rte_port_sched_reader_free(void *port)
7799a2dd95SBruce Richardson {
7899a2dd95SBruce Richardson 	if (port == NULL) {
79*ae67895bSDavid Marchand 		PORT_LOG(ERR, "%s: port is NULL", __func__);
8099a2dd95SBruce Richardson 		return -EINVAL;
8199a2dd95SBruce Richardson 	}
8299a2dd95SBruce Richardson 
8399a2dd95SBruce Richardson 	rte_free(port);
8499a2dd95SBruce Richardson 
8599a2dd95SBruce Richardson 	return 0;
8699a2dd95SBruce Richardson }
8799a2dd95SBruce Richardson 
8899a2dd95SBruce Richardson static int
rte_port_sched_reader_stats_read(void * port,struct rte_port_in_stats * stats,int clear)8999a2dd95SBruce Richardson rte_port_sched_reader_stats_read(void *port,
9099a2dd95SBruce Richardson 		struct rte_port_in_stats *stats, int clear)
9199a2dd95SBruce Richardson {
9299a2dd95SBruce Richardson 	struct rte_port_sched_reader *p =
9399a2dd95SBruce Richardson 		port;
9499a2dd95SBruce Richardson 
9599a2dd95SBruce Richardson 	if (stats != NULL)
9699a2dd95SBruce Richardson 		memcpy(stats, &p->stats, sizeof(p->stats));
9799a2dd95SBruce Richardson 
9899a2dd95SBruce Richardson 	if (clear)
9999a2dd95SBruce Richardson 		memset(&p->stats, 0, sizeof(p->stats));
10099a2dd95SBruce Richardson 
10199a2dd95SBruce Richardson 	return 0;
10299a2dd95SBruce Richardson }
10399a2dd95SBruce Richardson 
10499a2dd95SBruce Richardson /*
10599a2dd95SBruce Richardson  * Writer
10699a2dd95SBruce Richardson  */
10799a2dd95SBruce Richardson #ifdef RTE_PORT_STATS_COLLECT
10899a2dd95SBruce Richardson 
10999a2dd95SBruce Richardson #define RTE_PORT_SCHED_WRITER_STATS_PKTS_IN_ADD(port, val) \
11099a2dd95SBruce Richardson 	port->stats.n_pkts_in += val
11199a2dd95SBruce Richardson #define RTE_PORT_SCHED_WRITER_STATS_PKTS_DROP_ADD(port, val) \
11299a2dd95SBruce Richardson 	port->stats.n_pkts_drop += val
11399a2dd95SBruce Richardson 
11499a2dd95SBruce Richardson #else
11599a2dd95SBruce Richardson 
11699a2dd95SBruce Richardson #define RTE_PORT_SCHED_WRITER_STATS_PKTS_IN_ADD(port, val)
11799a2dd95SBruce Richardson #define RTE_PORT_SCHED_WRITER_STATS_PKTS_DROP_ADD(port, val)
11899a2dd95SBruce Richardson 
11999a2dd95SBruce Richardson #endif
12099a2dd95SBruce Richardson 
12199a2dd95SBruce Richardson struct rte_port_sched_writer {
12299a2dd95SBruce Richardson 	struct rte_port_out_stats stats;
12399a2dd95SBruce Richardson 
12499a2dd95SBruce Richardson 	struct rte_mbuf *tx_buf[2 * RTE_PORT_IN_BURST_SIZE_MAX];
12599a2dd95SBruce Richardson 	struct rte_sched_port *sched;
12699a2dd95SBruce Richardson 	uint32_t tx_burst_sz;
12799a2dd95SBruce Richardson 	uint32_t tx_buf_count;
12899a2dd95SBruce Richardson 	uint64_t bsz_mask;
12999a2dd95SBruce Richardson };
13099a2dd95SBruce Richardson 
13199a2dd95SBruce Richardson static void *
rte_port_sched_writer_create(void * params,int socket_id)13299a2dd95SBruce Richardson rte_port_sched_writer_create(void *params, int socket_id)
13399a2dd95SBruce Richardson {
13499a2dd95SBruce Richardson 	struct rte_port_sched_writer_params *conf =
13599a2dd95SBruce Richardson 			params;
13699a2dd95SBruce Richardson 	struct rte_port_sched_writer *port;
13799a2dd95SBruce Richardson 
13899a2dd95SBruce Richardson 	/* Check input parameters */
13999a2dd95SBruce Richardson 	if ((conf == NULL) ||
14099a2dd95SBruce Richardson 	    (conf->sched == NULL) ||
14199a2dd95SBruce Richardson 	    (conf->tx_burst_sz == 0) ||
14299a2dd95SBruce Richardson 	    (conf->tx_burst_sz > RTE_PORT_IN_BURST_SIZE_MAX) ||
14399a2dd95SBruce Richardson 		(!rte_is_power_of_2(conf->tx_burst_sz))) {
144*ae67895bSDavid Marchand 		PORT_LOG(ERR, "%s: Invalid params", __func__);
14599a2dd95SBruce Richardson 		return NULL;
14699a2dd95SBruce Richardson 	}
14799a2dd95SBruce Richardson 
14899a2dd95SBruce Richardson 	/* Memory allocation */
14999a2dd95SBruce Richardson 	port = rte_zmalloc_socket("PORT", sizeof(*port),
15099a2dd95SBruce Richardson 			RTE_CACHE_LINE_SIZE, socket_id);
15199a2dd95SBruce Richardson 	if (port == NULL) {
152*ae67895bSDavid Marchand 		PORT_LOG(ERR, "%s: Failed to allocate port", __func__);
15399a2dd95SBruce Richardson 		return NULL;
15499a2dd95SBruce Richardson 	}
15599a2dd95SBruce Richardson 
15699a2dd95SBruce Richardson 	/* Initialization */
15799a2dd95SBruce Richardson 	port->sched = conf->sched;
15899a2dd95SBruce Richardson 	port->tx_burst_sz = conf->tx_burst_sz;
15999a2dd95SBruce Richardson 	port->tx_buf_count = 0;
16099a2dd95SBruce Richardson 	port->bsz_mask = 1LLU << (conf->tx_burst_sz - 1);
16199a2dd95SBruce Richardson 
16299a2dd95SBruce Richardson 	return port;
16399a2dd95SBruce Richardson }
16499a2dd95SBruce Richardson 
16599a2dd95SBruce Richardson static int
rte_port_sched_writer_tx(void * port,struct rte_mbuf * pkt)16699a2dd95SBruce Richardson rte_port_sched_writer_tx(void *port, struct rte_mbuf *pkt)
16799a2dd95SBruce Richardson {
16899a2dd95SBruce Richardson 	struct rte_port_sched_writer *p = (struct rte_port_sched_writer *) port;
16999a2dd95SBruce Richardson 
17099a2dd95SBruce Richardson 	p->tx_buf[p->tx_buf_count++] = pkt;
17199a2dd95SBruce Richardson 	RTE_PORT_SCHED_WRITER_STATS_PKTS_IN_ADD(p, 1);
17299a2dd95SBruce Richardson 	if (p->tx_buf_count >= p->tx_burst_sz) {
17399a2dd95SBruce Richardson 		__rte_unused uint32_t nb_tx;
17499a2dd95SBruce Richardson 
17599a2dd95SBruce Richardson 		nb_tx = rte_sched_port_enqueue(p->sched, p->tx_buf, p->tx_buf_count);
17699a2dd95SBruce Richardson 		RTE_PORT_SCHED_WRITER_STATS_PKTS_DROP_ADD(p, p->tx_buf_count - nb_tx);
17799a2dd95SBruce Richardson 		p->tx_buf_count = 0;
17899a2dd95SBruce Richardson 	}
17999a2dd95SBruce Richardson 
18099a2dd95SBruce Richardson 	return 0;
18199a2dd95SBruce Richardson }
18299a2dd95SBruce Richardson 
18399a2dd95SBruce Richardson static int
rte_port_sched_writer_tx_bulk(void * port,struct rte_mbuf ** pkts,uint64_t pkts_mask)18499a2dd95SBruce Richardson rte_port_sched_writer_tx_bulk(void *port,
18599a2dd95SBruce Richardson 		struct rte_mbuf **pkts,
18699a2dd95SBruce Richardson 		uint64_t pkts_mask)
18799a2dd95SBruce Richardson {
18899a2dd95SBruce Richardson 	struct rte_port_sched_writer *p = (struct rte_port_sched_writer *) port;
18999a2dd95SBruce Richardson 	uint64_t bsz_mask = p->bsz_mask;
19099a2dd95SBruce Richardson 	uint32_t tx_buf_count = p->tx_buf_count;
19199a2dd95SBruce Richardson 	uint64_t expr = (pkts_mask & (pkts_mask + 1)) |
19299a2dd95SBruce Richardson 			((pkts_mask & bsz_mask) ^ bsz_mask);
19399a2dd95SBruce Richardson 
19499a2dd95SBruce Richardson 	if (expr == 0) {
19599a2dd95SBruce Richardson 		__rte_unused uint32_t nb_tx;
1963d4e27fdSDavid Marchand 		uint64_t n_pkts = rte_popcount64(pkts_mask);
19799a2dd95SBruce Richardson 
19899a2dd95SBruce Richardson 		if (tx_buf_count) {
19999a2dd95SBruce Richardson 			nb_tx = rte_sched_port_enqueue(p->sched, p->tx_buf,
20099a2dd95SBruce Richardson 				tx_buf_count);
20199a2dd95SBruce Richardson 			RTE_PORT_SCHED_WRITER_STATS_PKTS_DROP_ADD(p, tx_buf_count - nb_tx);
20299a2dd95SBruce Richardson 			p->tx_buf_count = 0;
20399a2dd95SBruce Richardson 		}
20499a2dd95SBruce Richardson 
20599a2dd95SBruce Richardson 		nb_tx = rte_sched_port_enqueue(p->sched, pkts, n_pkts);
20699a2dd95SBruce Richardson 		RTE_PORT_SCHED_WRITER_STATS_PKTS_DROP_ADD(p, n_pkts - nb_tx);
20799a2dd95SBruce Richardson 	} else {
20899a2dd95SBruce Richardson 		for ( ; pkts_mask; ) {
2093d4e27fdSDavid Marchand 			uint32_t pkt_index = rte_ctz64(pkts_mask);
21099a2dd95SBruce Richardson 			uint64_t pkt_mask = 1LLU << pkt_index;
21199a2dd95SBruce Richardson 			struct rte_mbuf *pkt = pkts[pkt_index];
21299a2dd95SBruce Richardson 
21399a2dd95SBruce Richardson 			p->tx_buf[tx_buf_count++] = pkt;
21499a2dd95SBruce Richardson 			RTE_PORT_SCHED_WRITER_STATS_PKTS_IN_ADD(p, 1);
21599a2dd95SBruce Richardson 			pkts_mask &= ~pkt_mask;
21699a2dd95SBruce Richardson 		}
21799a2dd95SBruce Richardson 		p->tx_buf_count = tx_buf_count;
21899a2dd95SBruce Richardson 
21999a2dd95SBruce Richardson 		if (tx_buf_count >= p->tx_burst_sz) {
22099a2dd95SBruce Richardson 			__rte_unused uint32_t nb_tx;
22199a2dd95SBruce Richardson 
22299a2dd95SBruce Richardson 			nb_tx = rte_sched_port_enqueue(p->sched, p->tx_buf,
22399a2dd95SBruce Richardson 				tx_buf_count);
22499a2dd95SBruce Richardson 			RTE_PORT_SCHED_WRITER_STATS_PKTS_DROP_ADD(p, tx_buf_count - nb_tx);
22599a2dd95SBruce Richardson 			p->tx_buf_count = 0;
22699a2dd95SBruce Richardson 		}
22799a2dd95SBruce Richardson 	}
22899a2dd95SBruce Richardson 
22999a2dd95SBruce Richardson 	return 0;
23099a2dd95SBruce Richardson }
23199a2dd95SBruce Richardson 
23299a2dd95SBruce Richardson static int
rte_port_sched_writer_flush(void * port)23399a2dd95SBruce Richardson rte_port_sched_writer_flush(void *port)
23499a2dd95SBruce Richardson {
23599a2dd95SBruce Richardson 	struct rte_port_sched_writer *p = (struct rte_port_sched_writer *) port;
23699a2dd95SBruce Richardson 
23799a2dd95SBruce Richardson 	if (p->tx_buf_count) {
23899a2dd95SBruce Richardson 		__rte_unused uint32_t nb_tx;
23999a2dd95SBruce Richardson 
24099a2dd95SBruce Richardson 		nb_tx = rte_sched_port_enqueue(p->sched, p->tx_buf, p->tx_buf_count);
24199a2dd95SBruce Richardson 		RTE_PORT_SCHED_WRITER_STATS_PKTS_DROP_ADD(p, p->tx_buf_count - nb_tx);
24299a2dd95SBruce Richardson 		p->tx_buf_count = 0;
24399a2dd95SBruce Richardson 	}
24499a2dd95SBruce Richardson 
24599a2dd95SBruce Richardson 	return 0;
24699a2dd95SBruce Richardson }
24799a2dd95SBruce Richardson 
24899a2dd95SBruce Richardson static int
rte_port_sched_writer_free(void * port)24999a2dd95SBruce Richardson rte_port_sched_writer_free(void *port)
25099a2dd95SBruce Richardson {
25199a2dd95SBruce Richardson 	if (port == NULL) {
252*ae67895bSDavid Marchand 		PORT_LOG(ERR, "%s: port is NULL", __func__);
25399a2dd95SBruce Richardson 		return -EINVAL;
25499a2dd95SBruce Richardson 	}
25599a2dd95SBruce Richardson 
25699a2dd95SBruce Richardson 	rte_port_sched_writer_flush(port);
25799a2dd95SBruce Richardson 	rte_free(port);
25899a2dd95SBruce Richardson 
25999a2dd95SBruce Richardson 	return 0;
26099a2dd95SBruce Richardson }
26199a2dd95SBruce Richardson 
26299a2dd95SBruce Richardson static int
rte_port_sched_writer_stats_read(void * port,struct rte_port_out_stats * stats,int clear)26399a2dd95SBruce Richardson rte_port_sched_writer_stats_read(void *port,
26499a2dd95SBruce Richardson 		struct rte_port_out_stats *stats, int clear)
26599a2dd95SBruce Richardson {
26699a2dd95SBruce Richardson 	struct rte_port_sched_writer *p =
26799a2dd95SBruce Richardson 		port;
26899a2dd95SBruce Richardson 
26999a2dd95SBruce Richardson 	if (stats != NULL)
27099a2dd95SBruce Richardson 		memcpy(stats, &p->stats, sizeof(p->stats));
27199a2dd95SBruce Richardson 
27299a2dd95SBruce Richardson 	if (clear)
27399a2dd95SBruce Richardson 		memset(&p->stats, 0, sizeof(p->stats));
27499a2dd95SBruce Richardson 
27599a2dd95SBruce Richardson 	return 0;
27699a2dd95SBruce Richardson }
27799a2dd95SBruce Richardson 
27899a2dd95SBruce Richardson /*
27999a2dd95SBruce Richardson  * Summary of port operations
28099a2dd95SBruce Richardson  */
28199a2dd95SBruce Richardson struct rte_port_in_ops rte_port_sched_reader_ops = {
28299a2dd95SBruce Richardson 	.f_create = rte_port_sched_reader_create,
28399a2dd95SBruce Richardson 	.f_free = rte_port_sched_reader_free,
28499a2dd95SBruce Richardson 	.f_rx = rte_port_sched_reader_rx,
28599a2dd95SBruce Richardson 	.f_stats = rte_port_sched_reader_stats_read,
28699a2dd95SBruce Richardson };
28799a2dd95SBruce Richardson 
28899a2dd95SBruce Richardson struct rte_port_out_ops rte_port_sched_writer_ops = {
28999a2dd95SBruce Richardson 	.f_create = rte_port_sched_writer_create,
29099a2dd95SBruce Richardson 	.f_free = rte_port_sched_writer_free,
29199a2dd95SBruce Richardson 	.f_tx = rte_port_sched_writer_tx,
29299a2dd95SBruce Richardson 	.f_tx_bulk = rte_port_sched_writer_tx_bulk,
29399a2dd95SBruce Richardson 	.f_flush = rte_port_sched_writer_flush,
29499a2dd95SBruce Richardson 	.f_stats = rte_port_sched_writer_stats_read,
29599a2dd95SBruce Richardson };
296