From: Jun Yang <[email protected]> Refactor the per-DQRR-entry receive code into a shared helper (dpaa2_scheduler_swp_mbuf_dq) used by both the fast-path push receive and the new teardown drain, then drain any in-flight packets when the scheduler is destroyed so buffers are not leaked or left stuck in the hardware channel.
For push mode, destroy now walks each lcore that has an active portal: it repeatedly dequeues and frees frames from the software portal (dpaa2_scheduler_dpio_drain), clears the push enable, and removes the DPCON static dequeue channel before the DPCON and DPCI devices are freed. A per-lcore dpio_dev array is added to struct dpaa2_sch_dev so destroy can find the portal that was bound on first receive. For pull mode, destroy repeatedly calls the configured receive path and frees the returned mbufs in bulk until the channel is empty (dpaa2_scheduler_rx_pull_drain). Any nonzero drained count is logged as a warning, and channel-removal errors are propagated as the destroy return value while teardown still completes. Signed-off-by: Jun Yang <[email protected]> --- drivers/event/dpaa2/dpaa2_scheduler.c | 141 +++++++++++++++++++++----- 1 file changed, 117 insertions(+), 24 deletions(-) diff --git a/drivers/event/dpaa2/dpaa2_scheduler.c b/drivers/event/dpaa2/dpaa2_scheduler.c index 51956ac1e5..26e3f50cf7 100644 --- a/drivers/event/dpaa2/dpaa2_scheduler.c +++ b/drivers/event/dpaa2/dpaa2_scheduler.c @@ -43,6 +43,7 @@ struct dpaa2_sch_port_queue { struct dpaa2_sch_dev { struct dpaa2_dpcon_dev *dpcon_dev[RTE_MAX_LCORE]; struct dpaa2_dpci_dev *dpci_dev[RTE_MAX_LCORE]; + struct dpaa2_dpio_dev *dpio_dev[RTE_MAX_LCORE]; uint8_t linked[RTE_MAX_LCORE]; struct dpaa2_sch_port_queue port_queue[DPAA2_SCH_PORT_QUEUE_MAX_NUM]; uint8_t port_queue_num; @@ -86,22 +87,68 @@ dpaa2_qbman_pull_desc_channel_set(struct qbman_pull_desc *pulldesc, iova_storage, 1); } +static inline struct rte_mbuf * +dpaa2_scheduler_swp_mbuf_dq(struct qbman_swp *swp) +{ + const struct qbman_result *dq; + const struct qbman_fd *fd; + struct dpaa2_queue *rxq; + struct dpaa2_dev_priv *priv; + struct rte_mbuf *mbuf; + + dq = qbman_swp_dqrr_next(swp); + if (!dq) + return NULL; + + qbman_swp_prefetch_dqrr_next(swp); + fd = qbman_result_DQ_fd(dq); + rxq = (void *)qbman_result_DQ_fqd_ctx(dq); + priv = rxq->eth_data->dev_private; + if (unlikely(DPAA2_FD_GET_FORMAT(fd) == qbman_fd_sg)) + mbuf = dpaa2_eth_sg_fd_to_mbuf_export(priv, fd); + else + mbuf = dpaa2_eth_fd_to_mbuf_export(priv, fd); + dpaa2_dev_rx_mbuf_flc_offload_export(mbuf, fd); + dpaa2_dev_rx_print_parser_result(priv, fd, mbuf); + qbman_swp_dqrr_consume(swp, dq); + + return mbuf; +} + +static uint32_t +dpaa2_scheduler_dpio_drain(struct dpaa2_dpio_dev *dpio_dev) +{ + struct qbman_swp *swp; + uint32_t num_pkts = 0; + int max_drain = 1000; + struct rte_mbuf *mbuf; + + swp = dpio_dev->sw_portal; + + while (max_drain--) { + mbuf = dpaa2_scheduler_swp_mbuf_dq(swp); + if (!mbuf) + break; + rte_pktmbuf_free(mbuf); + num_pkts++; + rte_delay_ms(1); + } + + return num_pkts; +} + static uint16_t dpaa2_scheduler_dpci_recv(struct dpaa2_sch_dev *sch_dev, struct rte_mbuf **mbuf, uint16_t nb_pkts) { - const struct qbman_result *dq; struct dpaa2_dpcon_dev *dpcon_dev; struct dpaa2_dpci_dev *dpci_dev; struct dpaa2_dpio_dev *dpio_dev; struct qbman_swp *swp; - const struct qbman_fd *fd; - struct dpaa2_queue *rxq; struct dpaa2_sch_port_queue *port_queue; struct rte_event_eth_rx_adapter_queue_conf *queue_conf; uint16_t num_pkts = 0, i = 0; int ret; - struct dpaa2_dev_priv *priv; uint32_t cpu = rte_lcore_id(); if (unlikely(!DPAA2_PER_LCORE_ETHRX_DPIO)) { @@ -158,30 +205,17 @@ dpaa2_scheduler_dpci_recv(struct dpaa2_sch_dev *sch_dev, qbman_swp_push_set(swp, dpcon_dev->channel_index, 1); sch_dev->linked[cpu] = sch_dev->port_queue_num; + sch_dev->dpio_dev[cpu] = dpio_dev; start_dq: - do { - dq = qbman_swp_dqrr_next(swp); - if (!dq) - goto quit; - - qbman_swp_prefetch_dqrr_next(swp); - - fd = qbman_result_DQ_fd(dq); - rxq = (void *)qbman_result_DQ_fqd_ctx(dq); - priv = rxq->eth_data->dev_private; - if (unlikely(DPAA2_FD_GET_FORMAT(fd) == qbman_fd_sg)) - mbuf[num_pkts] = dpaa2_eth_sg_fd_to_mbuf_export(priv, fd); + while (num_pkts < nb_pkts) { + mbuf[num_pkts] = dpaa2_scheduler_swp_mbuf_dq(swp); + if (likely(mbuf[num_pkts])) + num_pkts++; else - mbuf[num_pkts] = dpaa2_eth_fd_to_mbuf_export(priv, fd); - dpaa2_dev_rx_mbuf_flc_offload_export(mbuf[num_pkts], fd); - dpaa2_dev_rx_print_parser_result(priv, fd, mbuf[num_pkts]); - qbman_swp_dqrr_consume(swp, dq); - - num_pkts++; - } while (num_pkts < nb_pkts); + break; + } -quit: return num_pkts; } @@ -490,6 +524,54 @@ int rte_dpaa2_scheduler_start(void *scheduler_handle) return ret; } +static int +dpaa2_scheduler_rx_core_push_drain(struct dpaa2_sch_dev *sch_dev, uint16_t core) +{ + struct dpaa2_dpio_dev *dpio_dev; + struct dpaa2_dpcon_dev *dpcon_dev; + uint16_t drain_num; + int ret; + + if (!sch_dev->dpio_dev[core]) + return 0; + + dpio_dev = sch_dev->dpio_dev[core]; + dpcon_dev = sch_dev->dpcon_dev[core]; + if (!dpcon_dev) + return -ENODEV; + drain_num = dpaa2_scheduler_dpio_drain(dpio_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); + ret = dpio_remove_static_dequeue_channel(dpio_dev->dpio, + 0, dpio_dev->token, dpcon_dev->dpcon_id); + if (ret) + DPAA2_EVENTDEV_ERR("Failed(%d) to remove channel on core%d", ret, core); + + return ret; +} + +static void +dpaa2_scheduler_rx_pull_drain(struct dpaa2_sch_dev *sch_dev) +{ + uint16_t drain_num = 0, rx; + struct rte_mbuf *mbufs[16]; + int max_drain = 1000; + +rx_again: + rx = sch_dev->rx_schedule(sch_dev, mbufs, 16); + rte_pktmbuf_free_bulk(mbufs, rx); + drain_num += rx; + if (rx > 0 && max_drain > 0) { + rte_delay_ms(1); + max_drain--; + goto rx_again; + } + if (drain_num > 0) + DPAA2_EVENTDEV_WARN("Drain %d buffer(s) from scheduler.", drain_num); +} + RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_dpaa2_scheduler_destroy, 26.11) int rte_dpaa2_scheduler_destroy(void *scheduler_handle) { @@ -498,6 +580,17 @@ int rte_dpaa2_scheduler_destroy(void *scheduler_handle) struct dpaa2_dpci_dev *dpci_dev; int32_t ret = 0, _ret, i; + if (sch_dev->sch_mode == RTE_DPAA2_SCH_PUSH) { + /** Make sure all data threads quit.*/ + for (i = 0; i < RTE_MAX_LCORE; i++) { + _ret = dpaa2_scheduler_rx_core_push_drain(sch_dev, i); + if (_ret) + ret = _ret; + } + } else { + dpaa2_scheduler_rx_pull_drain(sch_dev); + } + for (i = 0; i < RTE_MAX_LCORE; i++) { dpcon_dev = sch_dev->dpcon_dev[i]; dpci_dev = sch_dev->dpci_dev[i]; -- 2.43.0

