[PATCH v4-S3 41/65] event/dpaa2: allow event queue link to multiple ports

Prashant Gupta prashant.gupta_3 at nxp.com
Fri Oct 23 15:43:21 CEST 2026


From: Jun Yang <jun.yang at nxp.com>

The event queue previously stored a single owning event port and each
DPCON kept a single channel_index, so a queue could be linked to only
one port and the static dequeue channel could be added to only one
DPIO at a time. This prevented linking the same event queue from
several ports.

Track the DPCON static dequeue channel per DPIO by replacing the
single channel_index with ch_idx[]/dpio_idx[] arrays and a ch_idx_num
count (bounded by DPAA2_DPCON_MAX_CH_IDX_NUM). On link, add a channel
for the linking DPIO and record its index; on unlink, look up the
channel by DPIO index and remove it, compacting the arrays.

Replace the exclusive evq_info->event_port ownership with a per-queue
link_num reference count and a per-port evq_map[] that resolves an
event queue id to its evq_info during enqueue. This drops the old
per-enqueue owner check in favour of a direct map lookup.

Add range checks on event queue id in queue setup and Rx queue attach,
verify the queue index matches its event_queue_id, reject linking a
queue configured as single link when already linked, and return
specific error codes. Lower a couple of noisy messages from ERR/WARN
to WARN/DEBUG. Update the scheduler DPCI receive and drain paths to
the new per-DPIO channel index tracking.

Signed-off-by: Jun Yang <jun.yang at nxp.com>
---
 drivers/bus/fslmc/portal/dpaa2_hw_pvt.h |   6 +-
 drivers/event/dpaa2/dpaa2_eventdev.c    | 207 ++++++++++++++----------
 drivers/event/dpaa2/dpaa2_eventdev.h    |   3 +-
 drivers/event/dpaa2/dpaa2_scheduler.c   |  10 +-
 4 files changed, 140 insertions(+), 86 deletions(-)

diff --git a/drivers/bus/fslmc/portal/dpaa2_hw_pvt.h b/drivers/bus/fslmc/portal/dpaa2_hw_pvt.h
index a0b1d2abfa..f67f2283db 100644
--- a/drivers/bus/fslmc/portal/dpaa2_hw_pvt.h
+++ b/drivers/bus/fslmc/portal/dpaa2_hw_pvt.h
@@ -283,6 +283,8 @@ struct dpaa2_dpci_dev {
 	struct dpaa2_queue *tx_queue;
 };
 
+#define DPAA2_DPCON_MAX_CH_IDX_NUM 16
+
 struct dpaa2_dpcon_dev {
 	TAILQ_ENTRY(dpaa2_dpcon_dev) next;
 	struct fsl_mc_io dpcon;
@@ -291,7 +293,9 @@ struct dpaa2_dpcon_dev {
 	uint32_t dpcon_id;
 	uint16_t qbman_ch_id;
 	uint8_t num_priorities;
-	uint8_t channel_index;
+	uint8_t ch_idx[DPAA2_DPCON_MAX_CH_IDX_NUM];
+	uint16_t dpio_idx[DPAA2_DPCON_MAX_CH_IDX_NUM];
+	uint8_t ch_idx_num;
 };
 
 /* DPCON channel pool, shared by the net rx-interrupt path and the event PMD */
diff --git a/drivers/event/dpaa2/dpaa2_eventdev.c b/drivers/event/dpaa2/dpaa2_eventdev.c
index cd2b00c3c9..4c20e26870 100644
--- a/drivers/event/dpaa2/dpaa2_eventdev.c
+++ b/drivers/event/dpaa2/dpaa2_eventdev.c
@@ -47,14 +47,21 @@ dpaa2_eventdev_attach_eth_rxq(const struct rte_eth_dev *dev,
 	const struct rte_event_eth_rx_adapter_queue_conf *queue_conf)
 {
 	int ret;
-	uint8_t ev_qid = queue_conf->ev.queue_id;
-	uint16_t idx = priv->evq_info[ev_qid].dpni_rxq_num;
-	struct dpaa2_dpcon_dev *dpcon = priv->evq_info[ev_qid].dpcon;
+	uint16_t ev_qid = queue_conf->ev.queue_id, idx;
+	struct dpaa2_dpcon_dev *dpcon;
+
+	if (ev_qid >= priv->max_event_queues) {
+		DPAA2_EVENTDEV_ERR("Invalid event queue ID(%d) >= %d",
+			ev_qid, priv->max_event_queues);
+		return -EINVAL;
+	}
 
+	idx = priv->evq_info[ev_qid].dpni_rxq_num;
 	if (idx >= DPAA2_EVENT_MAX_QUEUE_FLOWS) {
 		DPAA2_EVENTDEV_ERR("Too many flows to attach eventq%d", ev_qid);
 		return -ENOMEM;
 	}
+	dpcon = priv->evq_info[ev_qid].dpcon;
 	ret = dpaa2_eth_eventq_attach(dev, rxq_id, dpcon, queue_conf);
 	if (ret) {
 		DPAA2_EVENTDEV_ERR("Event queue attach failed: err(%d)", ret);
@@ -114,8 +121,6 @@ dpaa2_eventdev_enqueue_burst(void *port, const struct rte_event ev[],
 {
 	struct dpaa2_port *dpaa2_portal = port;
 	struct dpaa2_dpio_dev *dpio_dev;
-	struct rte_eventdev *eventdev = dpaa2_portal->eventdev;
-	struct dpaa2_eventdev *priv = eventdev->data->dev_private;
 	struct dpaa2_eventq *evq_info;
 	uint32_t queue_id, retry_count, loop, frames_to_send, i;
 	struct qbman_swp *swp;
@@ -145,13 +150,13 @@ dpaa2_eventdev_enqueue_burst(void *port, const struct rte_event ev[],
 			event = &ev[num_tx + loop];
 			queue_id = event->queue_id;
 			if (unlikely(queue_id >= DPAA2_EVENT_MAX_QUEUES ||
-				priv->evq_info[queue_id].event_port != dpaa2_portal)) {
-				DPAA2_EVENTDEV_ERR("Event queue%d is not handled by port%d",
+				!dpaa2_portal->evq_map[queue_id])) {
+				DPAA2_EVENTDEV_ERR("Event queue%d not linked to port%d",
 					queue_id, dpaa2_portal->port_id);
 				ret = -EINVAL;
 				goto send_partial;
 			}
-			evq_info = &priv->evq_info[queue_id];
+			evq_info = dpaa2_portal->evq_map[queue_id];
 			if (unlikely(event->sched_type >= DPAA2_EVENTQ_LINK_CONF_MAX ||
 				!evq_info->dpci_txqs[event->sched_type])) {
 				DPAA2_EVENTDEV_ERR("Event sched_type(%d) is not supported",
@@ -606,20 +611,32 @@ dpaa2_eventdev_queue_setup(struct rte_eventdev *dev, uint8_t queue_id,
 			   const struct rte_event_queue_conf *queue_conf)
 {
 	struct dpaa2_eventdev *priv = dev->data->dev_private;
-	struct dpaa2_eventq *evq_info = &priv->evq_info[queue_id];
+	struct dpaa2_eventq *evq_info;
 
 	EVENTDEV_INIT_FUNC_TRACE();
 
+	if (queue_id >= priv->max_event_queues) {
+		DPAA2_EVENTDEV_ERR("Invalid queue ID(%d) >= %d", queue_id,
+			priv->max_event_queues);
+		return -EINVAL;
+	}
+	evq_info = &priv->evq_info[queue_id];
+	if (queue_id != evq_info->event_queue_id) {
+		DPAA2_EVENTDEV_ERR("Queue index(%d) != event queue ID(%d)?",
+			queue_id, evq_info->event_queue_id);
+		return -EACCES;
+	}
+
 	switch (queue_conf->schedule_type) {
 	case RTE_SCHED_TYPE_PARALLEL:
 	case RTE_SCHED_TYPE_ATOMIC:
 		break;
 	default:
-		DPAA2_EVENTDEV_ERR("Schedule type is not supported.");
-		return -1;
+		DPAA2_EVENTDEV_ERR("Schedule type(%d) is not supported.",
+			queue_conf->schedule_type);
+		return -ENOTSUP;
 	}
 	evq_info->event_queue_cfg = queue_conf->event_queue_cfg;
-	evq_info->event_queue_id = queue_id;
 
 	return 0;
 }
@@ -657,40 +674,83 @@ dpaa2_eventdev_port_unlink(struct rte_eventdev *dev, void *port,
 	struct dpaa2_dpio_dev *dpio_dev = NULL;
 	struct dpaa2_eventq *evq_info;
 	struct qbman_swp *swp;
-	uint8_t total_queues[DPAA2_EVENT_MAX_QUEUES];
 	struct dpaa2_eventq *evq_infos[DPAA2_EVENT_MAX_QUEUES];
+	uint16_t pos[DPAA2_DPCON_MAX_CH_IDX_NUM], ch_idx;
 
 	EVENTDEV_INIT_FUNC_TRACE();
 
 	RTE_SET_USED(dev);
-	if (!queues) {
-		queues = total_queues;
+	dpio_dev = dpaa2_portal->dpio_dev;
+	if (!dpio_dev)
+		return 0;
+
+	swp = dpio_dev->sw_portal;
+	if (!queues)
 		nb_unlinks = dpaa2_portal->num_linked_evq;
-		for (i = 0; i < nb_unlinks; i++)
-			queues[i] = dpaa2_portal->evq_info[i]->event_queue_id;
+
+	for (i = 0; i < nb_unlinks; i++) {
+		if (!queues) {
+			evq_info = dpaa2_portal->evq_info[i];
+			goto map_check;
+		}
+		evq_info = NULL;
+		for (j = 0; j < dpaa2_portal->num_linked_evq; j++) {
+			if (queues[i] == dpaa2_portal->evq_info[j]->event_queue_id) {
+				evq_info = dpaa2_portal->evq_info[j];
+				break;
+			}
+		}
+		if (!evq_info) {
+			DPAA2_EVENTDEV_WARN("Event port%d doesn't handle queues[%d](%d)",
+				dpaa2_portal->port_id, i, queues[i]);
+			return -EINVAL;
+		}
+map_check:
+		if (dpaa2_portal->evq_map[evq_info->event_queue_id] != evq_info) {
+			DPAA2_EVENTDEV_ERR("Event queue mapping[%d] mismatch.",
+				evq_info->event_queue_id);
+			return -EINVAL;
+		}
+		for (j = 0; j < evq_info->dpcon->ch_idx_num; j++) {
+			if (evq_info->dpcon->dpio_idx[j] == dpio_dev->index)
+				break;
+		}
+		if (j == evq_info->dpcon->ch_idx_num) {
+			DPAA2_EVENTDEV_ERR("Event queue.%d was NOT attached to dpio.%d.",
+				evq_info->event_queue_id, dpio_dev->index);
+			return -EINVAL;
+		}
+		pos[i] = j;
+		evq_infos[i] = evq_info;
 	}
 
 	for (i = 0; i < nb_unlinks; i++) {
+		evq_info = evq_infos[i];
+		ch_idx = evq_info->dpcon->ch_idx[pos[i]];
+		qbman_swp_push_set(swp, ch_idx, 0);
+		ret = dpio_remove_static_dequeue_channel(dpio_dev->dpio,
+				0, dpio_dev->token, evq_info->dpcon->dpcon_id);
+		if (ret) {
+			DPAA2_EVENTDEV_ERR("Failed(%d) to remove channel (dpio.%d/dpcon.%d)",
+				ret, dpio_dev->index, evq_info->dpcon->dpcon_id);
+			break;
+		}
+		memmove(&evq_info->dpcon->ch_idx[pos[i]],
+			&evq_info->dpcon->ch_idx[pos[i] + 1],
+			evq_info->dpcon->ch_idx_num - (pos[i] + 1));
+		memmove(&evq_info->dpcon->dpio_idx[pos[i]],
+			&evq_info->dpcon->dpio_idx[pos[i] + 1],
+			(evq_info->dpcon->ch_idx_num - (pos[i] + 1)) * sizeof(uint16_t));
+		evq_info->dpcon->ch_idx_num--;
 		for (j = 0; j < dpaa2_portal->num_linked_evq; j++) {
-			evq_info = dpaa2_portal->evq_info[j];
-			if (evq_info && evq_info->event_queue_id == queues[i]) {
-				dpio_dev = dpaa2_portal->dpio_dev;
-				swp = dpio_dev->sw_portal;
-				qbman_swp_push_set(swp, evq_info->dpcon->channel_index, 0);
-				ret = dpio_remove_static_dequeue_channel(dpio_dev->dpio,
-					0, dpio_dev->token, evq_info->dpcon->dpcon_id);
-				if (ret)
-					DPAA2_EVENTDEV_WARN("Failed(%d) to remove channel", ret);
-				evq_info->event_port = NULL;
+			if (dpaa2_portal->evq_info[j] == evq_info) {
 				dpaa2_portal->evq_info[j] = NULL;
-				num++;
 				break;
 			}
 		}
-		if (j == dpaa2_portal->num_linked_evq) {
-			DPAA2_EVENTDEV_WARN("%s: Event port%d doesn't handle queue[%d]:%d",
-				__func__, dpaa2_portal->port_id, i, queues[i]);
-		}
+		dpaa2_portal->evq_map[evq_info->event_queue_id] = NULL;
+		evq_info->link_num--;
+		num++;
 	}
 
 	for (i = 0; i < dpaa2_portal->num_linked_evq; i++) {
@@ -714,75 +774,60 @@ dpaa2_eventdev_port_link(struct rte_eventdev *dev, void *port,
 	uint16_t nb_links)
 {
 	struct dpaa2_eventdev *priv = dev->data->dev_private;
-	struct dpaa2_port *dpaa2_portal = port, *ev_port;
+	struct dpaa2_port *dpaa2_portal = port;
 	struct dpaa2_dpio_dev *dpio_dev = dpaa2_portal->dpio_dev;
 	struct dpaa2_eventq *evq_info;
-	int ret = 0;
 	uint16_t i;
-	uint8_t channel_index;
+	uint8_t ch_idx;
+	int ret = 0;
 
 	EVENTDEV_INIT_FUNC_TRACE();
 
 	RTE_SET_USED(priorities);
 
-	if (dpaa2_portal->num_linked_evq > 0) {
-		ret = rte_event_port_unlink(dev->data->dev_id,
-			dpaa2_portal->port_id, NULL, 0);
-		if (ret)
-			return ret;
-	}
-
 	for (i = 0; i < nb_links; i++) {
+		if (queues[i] >= priv->max_event_queues) {
+			DPAA2_EVENTDEV_ERR("Event port%d: queues[%d](%d) >= %d",
+				dpaa2_portal->port_id, i, queues[i], priv->max_event_queues);
+			break;
+		}
 		evq_info = &priv->evq_info[queues[i]];
-		if (!evq_info->valid) {
-			DPAA2_EVENTDEV_WARN("%s: Event port%d.queue%d is not valid!",
-				__func__, dpaa2_portal->port_id, queues[i]);
-			return -EINVAL;
+		if (evq_info->link_num > 0 &&
+			(evq_info->event_queue_cfg & RTE_EVENT_QUEUE_CFG_SINGLE_LINK)) {
+			DPAA2_EVENTDEV_ERR("Event queue[%d] is configured as single link",
+				queues[i]);
+			break;
 		}
-		if (evq_info->event_port) {
-			ev_port = evq_info->event_port;
-			DPAA2_EVENTDEV_WARN("%s: queue%d is occupied by event port%d",
-				__func__, queues[i], ev_port->port_id);
-			return -ENODEV;
+		if (evq_info->dpcon->ch_idx_num >= DPAA2_DPCON_MAX_CH_IDX_NUM) {
+			DPAA2_EVENTDEV_ERR("Too many channel to be added with dpcon(ID=%d)",
+				evq_info->dpcon->dpcon_id);
+			break;
+		}
+		if (dpaa2_portal->evq_map[queues[i]]) {
+			DPAA2_EVENTDEV_ERR("Event port%d: queue%d already mapped",
+				dpaa2_portal->port_id, queues[i]);
+			break;
 		}
-	}
-
-	for (i = 0; i < nb_links; i++) {
-		evq_info = &priv->evq_info[queues[i]];
 		ret = dpio_add_static_dequeue_channel(dpio_dev->dpio,
 			CMD_PRI_LOW, dpio_dev->token,
-			evq_info->dpcon->dpcon_id, &channel_index);
+			evq_info->dpcon->dpcon_id, &ch_idx);
 		if (ret) {
 			DPAA2_EVENTDEV_ERR("Event port%d.queue%d static dequeue config failed(%d)",
 				dpaa2_portal->port_id, queues[i], ret);
-			goto err;
+			break;
 		}
-
-		qbman_swp_push_set(dpio_dev->sw_portal, channel_index, 1);
-		evq_info->dpcon->channel_index = channel_index;
-
 		dpaa2_portal->evq_info[dpaa2_portal->num_linked_evq] = evq_info;
-		evq_info->event_port = dpaa2_portal;
 		dpaa2_portal->num_linked_evq++;
-	}
+		evq_info->dpcon->ch_idx[evq_info->dpcon->ch_idx_num] = ch_idx;
+		evq_info->dpcon->dpio_idx[evq_info->dpcon->ch_idx_num] = dpio_dev->index;
+		evq_info->dpcon->ch_idx_num++;
+		evq_info->link_num++;
+		dpaa2_portal->evq_map[queues[i]] = evq_info;
 
-err:
-	if (!ret)
-		return nb_links;
-
-	nb_links = i;
-	for (i = 0; i < nb_links; i++) {
-		evq_info = &priv->evq_info[queues[i]];
-		evq_info->event_port = NULL;
-		qbman_swp_push_set(dpio_dev->sw_portal, evq_info->dpcon->channel_index, 0);
-		if (dpio_remove_static_dequeue_channel(dpio_dev->dpio,
-			0, dpio_dev->token, evq_info->dpcon->dpcon_id)) {
-			DPAA2_EVENTDEV_ERR("Event port%d.queue%d remove failed!",
-				dpaa2_portal->port_id, queues[i]);
-		}
-		dpaa2_portal->num_linked_evq--;
+		qbman_swp_push_set(dpio_dev->sw_portal, ch_idx, 1);
 	}
-	return ret;
+
+	return i;
 }
 
 static int
@@ -795,7 +840,7 @@ dpaa2_eventdev_port_setup(struct rte_eventdev *dev, uint8_t port_id,
 	EVENTDEV_INIT_FUNC_TRACE();
 
 	if (dev->data->ports[port_id]) {
-		DPAA2_EVENTDEV_WARN("Event port%d exists!", port_id);
+		DPAA2_EVENTDEV_DEBUG("Event port%d exists!", port_id);
 		dpaa2_eventdev_port_release(dev->data->ports[port_id]);
 	}
 
@@ -1231,7 +1276,7 @@ dpaa2_eventdev_create(const char *name, struct rte_vdev_device *vdev)
 		/** TO DO: order schedule.*/
 
 		evq_info->valid = true;
-		evq_info->event_port = NULL;
+		evq_info->event_queue_id = priv->max_event_queues;
 
 		priv->max_event_queues++;
 		if (priv->max_event_queues >= DPAA2_EVENT_MAX_QUEUES)
diff --git a/drivers/event/dpaa2/dpaa2_eventdev.h b/drivers/event/dpaa2/dpaa2_eventdev.h
index adeb22bda6..c0ce42c83f 100644
--- a/drivers/event/dpaa2/dpaa2_eventdev.h
+++ b/drivers/event/dpaa2/dpaa2_eventdev.h
@@ -54,7 +54,7 @@ enum {
 #define DPAA2_EVENTQ_LINK_CONF_MAX 4 /** Max schedule type + 1.*/
 struct dpaa2_eventq {
 	int valid;
-	void *event_port;
+	uint8_t link_num;
 	/* DPcon device */
 	struct dpaa2_dpcon_dev *dpcon;
 	/* Attached DPCI device */
@@ -80,6 +80,7 @@ struct dpaa2_port {
 	RTE_ATOMIC(uint32_t) flushing;
 
 	struct dpaa2_eventq *evq_info[DPAA2_EVENT_MAX_QUEUES];
+	struct dpaa2_eventq *evq_map[DPAA2_EVENT_MAX_QUEUES];
 	uint8_t port_id;
 	uint8_t num_linked_evq;
 	uint64_t timeout_us;
diff --git a/drivers/event/dpaa2/dpaa2_scheduler.c b/drivers/event/dpaa2/dpaa2_scheduler.c
index 6a4ec04aae..9e58b4253f 100644
--- a/drivers/event/dpaa2/dpaa2_scheduler.c
+++ b/drivers/event/dpaa2/dpaa2_scheduler.c
@@ -196,16 +196,18 @@ dpaa2_scheduler_dpci_recv(struct dpaa2_sch_dev *sch_dev,
 	ret = dpio_add_static_dequeue_channel(dpio_dev->dpio,
 			CMD_PRI_LOW, dpio_dev->token,
 			dpcon_dev->dpcon_id,
-			&dpcon_dev->channel_index);
+			&dpcon_dev->ch_idx[dpcon_dev->ch_idx_num]);
 	if (ret) {
 		DPAA2_EVENTDEV_ERR("Failure(%d) adding dpcon%d to static dq channel",
 			ret, dpcon_dev->dpcon_id);
 		return 0;
 	}
+	dpcon_dev->dpio_idx[dpcon_dev->ch_idx_num] = dpio_dev->index;
 
-	qbman_swp_push_set(swp, dpcon_dev->channel_index, 1);
+	qbman_swp_push_set(swp, dpcon_dev->ch_idx[dpcon_dev->ch_idx_num], 1);
 	sch_dev->linked[cpu] = sch_dev->port_queue_num;
 	sch_dev->dpio_dev[cpu] = dpio_dev;
+	dpcon_dev->ch_idx_num++;
 
 start_dq:
 	while (num_pkts < nb_pkts) {
@@ -562,7 +564,9 @@ dpaa2_scheduler_rx_core_push_drain(struct dpaa2_sch_dev *sch_dev,
 	if (drain_num > 0)
 		DPAA2_EVENTDEV_WARN("Drain %d buffer(s) from core%d", drain_num, core);
 
-	qbman_swp_push_set(dpio_dev->sw_portal, dpcon_dev->channel_index, 0);
+	qbman_swp_push_set(dpio_dev->sw_portal,
+		dpcon_dev->ch_idx[dpcon_dev->ch_idx_num - 1], 0);
+	dpcon_dev->ch_idx_num--;
 	if (attach_num)
 		(*attach_num)++;
 	ret = dpio_remove_static_dequeue_channel(dpio_dev->dpio,
-- 
2.43.0



More information about the dev mailing list