* [PATCH v2 0/1] DPAA compilation fix ppc64le and riscv
2026-10-27 6:15 [PATCH] bus/dpaa: fix maybe-uninitialized in bman_release_fast Gagandeep Singh
@ 2026-10-27 6:31 ` Gagandeep Singh
0 siblings, 0 replies; 6+ messages in thread
From: Gagandeep Singh @ 2026-10-27 6:31 UTC (permalink / raw)
To: dev; +Cc: david.marchand, hemant.agrawal
V2-changes:
- updated the Author name.
Stephen Hemminger (1):
bus/dpaa: fix maybe-uninitialized in bman_release_fast
drivers/bus/dpaa/base/qbman/bman.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
--
2.25.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 0/1] DPAA compilation fix ppc64le and riscv
@ 2026-10-28 8:51 Gagandeep Singh
2026-10-28 8:51 ` [PATCH v2 1/1] bus/dpaa: fix maybe-uninitialized in bman_release_fast Gagandeep Singh
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Gagandeep Singh @ 2026-10-28 8:51 UTC (permalink / raw)
To: dev; +Cc: hemant.agrawal
V2-changes:
- updated the Author name.
Stephen Hemminger (1):
bus/dpaa: fix maybe-uninitialized in bman_release_fast
drivers/bus/dpaa/base/qbman/bman.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
--
2.25.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 1/1] bus/dpaa: fix maybe-uninitialized in bman_release_fast
2026-10-28 8:51 [PATCH v2 0/1] DPAA compilation fix ppc64le and riscv Gagandeep Singh
@ 2026-10-28 8:51 ` Gagandeep Singh
2026-10-28 8:51 ` [PATCH 1/3] drivers: add offline (O/H) port device support Gagandeep Singh
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Gagandeep Singh @ 2026-10-28 8:51 UTC (permalink / raw)
To: dev; +Cc: hemant.agrawal, jun.yang, Gagandeep Singh, Stephen Hemminger
From: Stephen Hemminger <stephen@networkplumber.org>
The conversion loop is bounded only by num, which is not checked
unless RTE_LIBRTE_DPAA_HWDEBUG is set. GCC on ppc64le and riscv
therefore warns that bm_bufs[0] may be read uninitialized when
copying the first entry into the RCR.
Convert entry 0 unconditionally, as bman_release() does.
Fixes: e55e2e2d0c66 ("bus/dpaa: optimize DPAA multi-entry buffer pool operations")
Cc: jun.yang@nxp.com
Signed-off-by: Gagandeep Singh <g.singh@nxp.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/bus/dpaa/base/qbman/bman.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/bus/dpaa/base/qbman/bman.c b/drivers/bus/dpaa/base/qbman/bman.c
index 2b081cb78a..76e612662f 100644
--- a/drivers/bus/dpaa/base/qbman/bman.c
+++ b/drivers/bus/dpaa/base/qbman/bman.c
@@ -279,7 +279,8 @@ bman_release_fast(struct bman_pool *pool, const uint64_t *bufs,
if (unlikely(!r))
return -EBUSY;
- for (i = 0; i < num; i++)
+ bm_buffer_set64_to_be(&bm_bufs[0], bufs[0]);
+ for (i = 1; i < num; i++)
bm_buffer_set64_to_be(&bm_bufs[i], bufs[i]);
/* bufs[0] overlaps the verb, which bm_rcr_pvb_commit() writes last
--
2.25.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 1/3] drivers: add offline (O/H) port device support
2026-10-28 8:51 [PATCH v2 0/1] DPAA compilation fix ppc64le and riscv Gagandeep Singh
2026-10-28 8:51 ` [PATCH v2 1/1] bus/dpaa: fix maybe-uninitialized in bman_release_fast Gagandeep Singh
@ 2026-10-28 8:51 ` Gagandeep Singh
2026-10-28 8:51 ` [PATCH 2/3] net/dpaa: support non fmX-macY type of shared Ethernet name Gagandeep Singh
2026-10-28 8:51 ` [PATCH 3/3] drivers: add DPAA cgrid cleanup support Gagandeep Singh
3 siblings, 0 replies; 6+ messages in thread
From: Gagandeep Singh @ 2026-10-28 8:51 UTC (permalink / raw)
To: dev; +Cc: hemant.agrawal, Gagandeep Singh
Add support for the DPAA Offline/Host-command (O/H) port, allowing a
single OL port to be used by a DPDK application. The feature is
selected through the 'drv_oldev' bus device argument, and the
associated back-half port is named through the 'drv_bh_port' device
argument.
Signed-off-by: Gagandeep Singh <g.singh@nxp.com>
Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
---
doc/api/doxy-api-index.md | 1 +
doc/guides/nics/dpaa.rst | 27 +
drivers/bus/dpaa/base/fman/fman.c | 19 +
drivers/bus/dpaa/bus_dpaa_driver.h | 4 +-
drivers/bus/dpaa/dpaa_bus.c | 100 ++-
drivers/bus/dpaa/dpaa_bus_base_symbols.c | 1 +
drivers/bus/dpaa/include/fman.h | 6 +-
drivers/bus/dpaa/include/fsl_qman.h | 1 +
drivers/net/dpaa/dpaa_ethdev.h | 3 +
drivers/net/dpaa/dpaa_flow.c | 7 +-
drivers/net/dpaa/dpaa_oldev.c | 875 +++++++++++++++++++++++
drivers/net/dpaa/meson.build | 11 +-
drivers/net/dpaa/rte_pmd_dpaa_oldev.h | 158 ++++
13 files changed, 1197 insertions(+), 16 deletions(-)
create mode 100644 drivers/net/dpaa/dpaa_oldev.c
create mode 100644 drivers/net/dpaa/rte_pmd_dpaa_oldev.h
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 62390f7be3..0bd8e1bbf0 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -53,6 +53,7 @@ The public API headers are grouped by topics:
[cnxk_eventdev](@ref rte_pmd_cnxk_eventdev.h),
[cnxk_mempool](@ref rte_pmd_cnxk_mempool.h),
[dpaa](@ref rte_pmd_dpaa.h),
+ [dpaa_oldev](@ref rte_pmd_dpaa_oldev.h),
[dpaa2](@ref rte_pmd_dpaa2.h),
[mlx5](@ref rte_pmd_mlx5.h),
[dpaa2_mempool](@ref rte_dpaa2_mempool.h),
diff --git a/doc/guides/nics/dpaa.rst b/doc/guides/nics/dpaa.rst
index c6aab46828..667b8c113d 100644
--- a/doc/guides/nics/dpaa.rst
+++ b/doc/guides/nics/dpaa.rst
@@ -276,6 +276,33 @@ Refer to the document :doc:`build_and_test` for details.
and thus disabling hardware based packet handling at driver level,
e.g. ``dpaa:fm1-mac3,recv_err_pkts=1``.
+``drv_bh_port``
+ Name of the back-half port associated with an offline (O/H) port device.
+ It is passed on the offline port device itself, which is named
+ ``oldev1``, e.g. ``-a dpaa_bus:oldev1,drv_bh_port=fm1-mac5``.
+
+The following bus-level device argument configures the DPAA bus itself and
+is passed through the EAL bus arguments. The bus name is ``dpaa_bus``:
+
+``drv_oldev`` (default disabled)
+ Enable the DPAA offline (O/H) port device,
+ e.g. ``-a bus=dpaa_bus,drv_oldev=1``.
+
+ Passing any ``-a`` argument for the DPAA bus switches the bus to
+ allowlist scan mode, so from that point on only the devices named with
+ ``-a`` are probed. Enabling the offline port therefore requires listing
+ the offline port itself and every Ethernet port the application needs,
+ for example::
+
+ -a bus=dpaa_bus,drv_oldev=1 \
+ -a dpaa_bus:oldev1,drv_bh_port=fm1-mac5 \
+ -a dpaa_bus:fm1-mac5 -a dpaa_bus:fm1-mac6
+
+ Omitting ``-a dpaa_bus:oldev1`` leaves the offline port unprobed even
+ though ``drv_oldev=1`` was given, and omitting an ``fmX-macY`` port
+ silently drops that port.
+
+
FMAN Config
-----------
diff --git a/drivers/bus/dpaa/base/fman/fman.c b/drivers/bus/dpaa/base/fman/fman.c
index 67f77265ca..223cd6958d 100644
--- a/drivers/bus/dpaa/base/fman/fman.c
+++ b/drivers/bus/dpaa/base/fman/fman.c
@@ -205,6 +205,9 @@ static void fman_if_vsp_init(struct __fman_if *__if)
size_t lenp;
const uint8_t mac_idx[] = {-1, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1};
+ static_assert(RTE_DIM(mac_idx) == FMAN_MAX_MAC_IDX_NUM,
+ "mac_idx[] out of sync with FMAN_MAX_MAC_IDX_NUM");
+
if (__if->__if.mac_idx <= 8) {
for_each_compatible_node(dev, NULL,
"fsl,fman-port-1g-rx-extended-args") {
@@ -544,6 +547,14 @@ fman_if_init(const struct device_node *dpa_node, int fd)
cell_idx_host = of_read_number(cell_idx,
lenp / sizeof(phandle));
+ if (cell_idx_host >= FMAN_MAX_MAC_IDX_NUM) {
+ FMAN_ERR(-EINVAL,
+ "%s: cell-index(%" PRIu64 ") >= max(%d)",
+ oh_node->full_name, cell_idx_host,
+ FMAN_MAX_MAC_IDX_NUM);
+ goto err;
+ }
+
__if->__if.mac_idx = cell_idx_host;
}
@@ -957,6 +968,14 @@ static int fman_if_init_onic(const struct device_node *dpa_node)
assert(lenp == sizeof(*cell_idx));
cell_idx_host = of_read_number(cell_idx, lenp / sizeof(phandle));
+
+ if (cell_idx_host >= FMAN_MAX_MAC_IDX_NUM) {
+ FMAN_ERR(-EINVAL, "%s: cell-index(%" PRIu64 ") >= max(%d)",
+ tx_oh_node->full_name, cell_idx_host,
+ FMAN_MAX_MAC_IDX_NUM);
+ goto err;
+ }
+
__if->__if.mac_idx = cell_idx_host;
fman_node = of_get_parent(fman_tx_oh_node);
diff --git a/drivers/bus/dpaa/bus_dpaa_driver.h b/drivers/bus/dpaa/bus_dpaa_driver.h
index 4aed83f84d..323a6a7659 100644
--- a/drivers/bus/dpaa/bus_dpaa_driver.h
+++ b/drivers/bus/dpaa/bus_dpaa_driver.h
@@ -69,11 +69,13 @@ struct rte_dpaa_driver;
enum rte_dpaa_type {
FSL_DPAA_ETH = 1,
FSL_DPAA_CRYPTO,
- FSL_DPAA_QDMA
+ FSL_DPAA_QDMA,
+ FSL_DPAA_OL
};
struct dpaa_device_id {
uint8_t fman_id; /**< Fman interface ID, for ETH type device */
+ uint8_t ol_id; /**< OH interface ID, for OH type device */
uint8_t mac_id; /**< Fman MAC interface ID, for ETH type device */
uint16_t dev_id; /**< Device Identifier from DPDK */
};
diff --git a/drivers/bus/dpaa/dpaa_bus.c b/drivers/bus/dpaa/dpaa_bus.c
index 6599958925..7df2b3a97c 100644
--- a/drivers/bus/dpaa/dpaa_bus.c
+++ b/drivers/bus/dpaa/dpaa_bus.c
@@ -34,6 +34,8 @@
#include <bus_driver.h>
#include <rte_mbuf_pool_ops.h>
#include <rte_mbuf_dyn.h>
+#include <rte_kvargs.h>
+#include <rte_devargs.h>
#include <dpaa_of.h>
#include <bus_dpaa_driver.h>
@@ -66,8 +68,12 @@ struct rte_dpaa_bus_private {
uint32_t svr_ver;
uint16_t max_push_rxq_num;
RTE_ATOMIC(uint16_t) push_rxq_num;
+ int oldev_enabled; /**< "drv_oldev" bus devarg */
};
+/* Bus level device argument keys */
+#define DPAA_BUS_ARG_OLDEV "drv_oldev"
+
static struct rte_bus rte_dpaa_bus;
static struct rte_dpaa_bus_private dpaa_bus;
static struct netcfg_info *dpaa_netcfg;
@@ -78,6 +84,44 @@ static pthread_key_t dpaa_portal_key;
struct dpaa_portal *dpaa_portals[RTE_MAX_LCORE] = {NULL};
static int dpaa_bus_global_init;
+/*
+ * Parse the bus-level device arguments (specified through the EAL bus
+ * arguments, e.g. "-a bus=dpaa_bus,drv_oldev=1") and cache the resulting
+ * flags in the bus private structure. Replaces the previous
+ * environment-variable based configuration.
+ *
+ * bus_str holds the whole bus layer including the "bus=" pair, so the
+ * kvargs list is parsed with a key list that accepts it alongside the
+ * DPAA specific keys.
+ */
+static int
+dpaa_bus_parse_bus_args(void)
+{
+ static const char * const bus_arg_keys[] = {
+ RTE_DEVARGS_KEY_BUS,
+ DPAA_BUS_ARG_OLDEV,
+ NULL,
+ };
+ struct rte_devargs *devargs;
+ struct rte_kvargs *kvlist;
+
+ RTE_EAL_DEVARGS_FOREACH(rte_dpaa_bus.name, devargs) {
+ if (devargs->bus_str == NULL)
+ continue;
+
+ kvlist = rte_kvargs_parse(devargs->bus_str, bus_arg_keys);
+ if (kvlist == NULL)
+ continue;
+
+ if (rte_kvargs_count(kvlist, DPAA_BUS_ARG_OLDEV))
+ dpaa_bus.oldev_enabled = 1;
+
+ rte_kvargs_free(kvlist);
+ }
+
+ return 0;
+}
+
RTE_EXPORT_INTERNAL_SYMBOL(per_lcore_dpaa_io)
RTE_DEFINE_PER_LCORE(struct dpaa_portal *, dpaa_io);
@@ -201,7 +245,7 @@ static void dpaa_clean_device_list(void);
static int
dpaa_create_device_list(void)
{
- int i;
+ int i = 0;
int ret;
struct rte_dpaa_device *dev;
struct fm_eth_port_cfg *cfg;
@@ -209,6 +253,34 @@ dpaa_create_device_list(void)
dpaa_bus.device_count = 0;
+ if (!dpaa_netcfg && !dpaa_bus.oldev_enabled)
+ return 0;
+
+ /* Creating OL Device */
+ if (dpaa_bus.oldev_enabled) {
+ dev = calloc(1, sizeof(struct rte_dpaa_device));
+ if (!dev) {
+ DPAA_BUS_ERR("Failed to allocate OL devices");
+ return -ENOMEM;
+ }
+
+ dev->device_type = FSL_DPAA_OL;
+ dev->id.ol_id = 0;
+ dev->id.dev_id = dpaa_bus.device_count;
+
+ /* Create device name */
+ memset(dev->name, 0, RTE_ETH_NAME_MAX_LEN);
+ sprintf(dev->name, "oldev%d", (dev->id.ol_id + 1));
+ DPAA_BUS_INFO("%s oldev added", dev->name);
+ dev->device.name = dev->name;
+ dev->device.devargs = rte_bus_find_devargs(&rte_dpaa_bus, dev->name);
+ if (dev->device.devargs != NULL)
+ DPAA_BUS_INFO("**Devargs matched %s", dev->name);
+
+ dpaa_add_to_device_list(dev);
+ dpaa_bus.device_count++;
+ }
+
/* Creating Ethernet Devices */
for (i = 0; dpaa_netcfg && (i < dpaa_netcfg->num_ethports); i++) {
dev = calloc(1, sizeof(struct rte_dpaa_device));
@@ -513,7 +585,7 @@ rte_dpaa_bus_parse(const char *name, void *out)
}
/* dev_delta points to the dev name (mac/oh/onic). Not valid for
- * dpaa_sec.
+ * dpaa_sec and oldev.
*/
dev_delta = delta + sizeof("fm.-") - 1;
@@ -527,6 +599,10 @@ rte_dpaa_bus_parse(const char *name, void *out)
i < 1 || i > RTE_DPAA_QDMA_DEVICES)
return -EINVAL;
max_name_len = sizeof("dpaa_qdma-.") - 1;
+ } else if (strncmp("oldev", &name[delta], 5) == 0) {
+ if (sscanf(&name[delta], "oldev%u", &i) != 1 || i != 1)
+ return -EINVAL;
+ max_name_len = sizeof("oldev.") - 1;
} else if (strncmp("oh", &name[dev_delta], 2) == 0) {
if (sscanf(&name[delta], "fm%u-oh%u", &i, &j) != 2 ||
i >= 2 || j >= 16)
@@ -624,7 +700,7 @@ rte_dpaa_bus_dev_build(void)
/* Get the interface configurations from device-tree */
dpaa_netcfg = netcfg_acquire();
- if (!dpaa_netcfg) {
+ if (!dpaa_netcfg && !dpaa_bus.oldev_enabled) {
DPAA_BUS_ERR("netcfg failed: /dev/fsl_usdpaa device not available");
DPAA_BUS_WARN("Check if you are using USDPAA based device tree");
return -EINVAL;
@@ -632,17 +708,20 @@ rte_dpaa_bus_dev_build(void)
DPAA_BUS_NOTICE("DPAA Bus Detected");
- if (!dpaa_netcfg->num_ethports) {
- DPAA_BUS_INFO("NO DPDK mapped net interfaces available");
- /* This is not an error */
+ if (!dpaa_bus.oldev_enabled) {
+ if (!dpaa_netcfg->num_ethports) {
+ DPAA_BUS_INFO("NO DPDK mapped net interfaces available");
+ /* This is not an error */
+ }
}
#ifdef RTE_LIBRTE_DPAA_DEBUG_DRIVER
dump_netcfg(dpaa_netcfg, stdout);
#endif
-
- DPAA_BUS_DEBUG("Number of ethernet devices = %d",
+ if (!dpaa_bus.oldev_enabled) {
+ DPAA_BUS_DEBUG("Number of ethernet devices = %d",
dpaa_netcfg->num_ethports);
+ }
ret = dpaa_create_device_list();
if (ret) {
DPAA_BUS_ERR("Unable to create device list. (%d)", ret);
@@ -695,6 +774,11 @@ rte_dpaa_bus_scan(void)
dpaa_bus.detected = 1;
+ /* Parse bus-level device arguments (drv_oldev) before building the
+ * device list.
+ */
+ dpaa_bus_parse_bus_args();
+
/* create the key, supplying a function that'll be invoked
* when a portal affined thread will be deleted.
*/
diff --git a/drivers/bus/dpaa/dpaa_bus_base_symbols.c b/drivers/bus/dpaa/dpaa_bus_base_symbols.c
index 0927e5fe2c..aaa9f9bec2 100644
--- a/drivers/bus/dpaa/dpaa_bus_base_symbols.c
+++ b/drivers/bus/dpaa/dpaa_bus_base_symbols.c
@@ -52,6 +52,7 @@ RTE_EXPORT_INTERNAL_SYMBOL(bman_acquire)
RTE_EXPORT_INTERNAL_SYMBOL(bman_query_free_buffers)
RTE_EXPORT_INTERNAL_SYMBOL(bman_thread_irq)
RTE_EXPORT_INTERNAL_SYMBOL(qman_alloc_fqid_range)
+RTE_EXPORT_INTERNAL_SYMBOL(qman_release_fqid_range)
RTE_EXPORT_INTERNAL_SYMBOL(qman_reserve_fqid_range)
RTE_EXPORT_INTERNAL_SYMBOL(qman_alloc_pool_range)
RTE_EXPORT_INTERNAL_SYMBOL(qman_alloc_cgrid_range)
diff --git a/drivers/bus/dpaa/include/fman.h b/drivers/bus/dpaa/include/fman.h
index f642faf3b3..030c85c284 100644
--- a/drivers/bus/dpaa/include/fman.h
+++ b/drivers/bus/dpaa/include/fman.h
@@ -68,6 +68,11 @@
#define FMAN_RTC_MAX_NUM_OF_PERIODIC_PULSES 4
#define FMAN_RTC_MAX_NUM_OF_EXT_TRIGGERS 3
+/*
+ * Maximum number of MAC/offline port indexes.
+ */
+#define FMAN_MAX_MAC_IDX_NUM 11
+
/* Represents the different flavour of network interface */
enum fman_mac_type {
fman_offline_internal = 0,
@@ -475,7 +480,6 @@ struct __fman_if {
void *qmi_map;
};
-#define MEMMAC_REG_OFFSET(reg) offsetof(struct memac_regs, reg)
#define BMI_RX_REG_OFFSET(reg) offsetof(struct rx_bmi_regs, reg)
#define BMI_TX_REG_OFFSET(reg) offsetof(struct tx_bmi_regs, reg)
diff --git a/drivers/bus/dpaa/include/fsl_qman.h b/drivers/bus/dpaa/include/fsl_qman.h
index 59b41e17f0..b2674ce5d0 100644
--- a/drivers/bus/dpaa/include/fsl_qman.h
+++ b/drivers/bus/dpaa/include/fsl_qman.h
@@ -1895,6 +1895,7 @@ static inline int qman_alloc_fqid(u32 *result)
* This function can also be used to seed the allocator with ranges of FQIDs
* that it can subsequently allocate from.
*/
+__rte_internal
void qman_release_fqid_range(u32 fqid, unsigned int count);
static inline void qman_release_fqid(u32 fqid)
{
diff --git a/drivers/net/dpaa/dpaa_ethdev.h b/drivers/net/dpaa/dpaa_ethdev.h
index 47c8e2b086..7e70bf2ad2 100644
--- a/drivers/net/dpaa/dpaa_ethdev.h
+++ b/drivers/net/dpaa/dpaa_ethdev.h
@@ -114,6 +114,9 @@ enum {
#define DPAA_DEFAULT_RXQ_VSP_ID 1
+/* Device argument to name the offline (O/H) port back-half port */
+#define DRIVER_OL_BH_PORT "drv_bh_port"
+
#define FMC_FILE "/tmp/fmc.bin"
struct dpaa_if_vsp {
diff --git a/drivers/net/dpaa/dpaa_flow.c b/drivers/net/dpaa/dpaa_flow.c
index f77f9f333b..6c519ec975 100644
--- a/drivers/net/dpaa/dpaa_flow.c
+++ b/drivers/net/dpaa/dpaa_flow.c
@@ -32,9 +32,14 @@ return &scheme_params->param.key_ext_and_hash.extract_array[hdr_idx];
SCH_EXT_HDR(scheme_params, hdr_idx).extract_by_hdr_type.full_field
/* FMAN mac indexes mappings (0 is unused, first 8 are for 1G, next for 10G
- * ports).
+ * ports). Indexed by fman_if.mac_idx, which the bus validates against
+ * FMAN_MAX_MAC_IDX_NUM when deriving it from the device tree.
*/
static const uint8_t mac_idx[] = {-1, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1};
+static_assert(RTE_DIM(mac_idx) == FMAN_MAX_MAC_IDX_NUM,
+ "mac_idx[] out of sync with FMAN_MAX_MAC_IDX_NUM");
+
+
/* FM global info */
struct dpaa_fm_info {
diff --git a/drivers/net/dpaa/dpaa_oldev.c b/drivers/net/dpaa/dpaa_oldev.c
new file mode 100644
index 0000000000..750f963543
--- /dev/null
+++ b/drivers/net/dpaa/dpaa_oldev.c
@@ -0,0 +1,875 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2020-2026 NXP
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+
+#include <rte_dpaa_logs.h>
+#include <rte_kvargs.h>
+#include <rte_stdatomic.h>
+
+#include <rte_string_fns.h>
+#include <bus_dpaa_driver.h>
+#include <dpaa_ethdev.h>
+#include <dpaa_rxtx.h>
+#include <dpaa_mempool.h>
+
+#include <eal_export.h>
+#include <fsl_fman.h>
+
+#include "rte_pmd_dpaa_oldev.h"
+
+/* The ol device is a tx are queue pair, which is provided to the kernel through
+ * ioctl calls. It is exposed as a virtual port to the application.
+ * This ASK Device provides IOCTL calls to driver for communicating fqid's,
+ * buffer pool id's and channel id's with kernel.
+ */
+#define ASK_PATH "/dev/cdx_ctrl"
+#define CDX_IOC_MAGIC 0xbe
+
+#define MAX_BH_PORT_NAME_LEN 12
+
+/* Private area reserved by driver.
+ * Aligned with "struct annotations_t". Parse results will be written from
+ * the 17th byte by the HW.
+ */
+#define DPAA_OL_PARSERSLT_START_OFFSET 16
+#define DPAA_OL_DATA_ALIGNMENT 64
+/* Change this value to increase the data offset.
+ * final value will be aligned by DPAA_OL_DATA_ALIGNMENT
+ */
+#define DPAA_OL_MAX_EXTRA_SIZE 0
+#define DPAA_OL_PARSE_RESULT_REQUIRED true
+#define DPAA_OL_TIME_STAMP_REQUIRED false
+#define DPAA_OL_HASH_RESULT_REQUIRED false
+#define DPAA_OL_PCD_INFO_REQUIRED false
+
+/* Work queue ID used for the offline port ingress sequence classifier. */
+#define DPA_ISC_WQ_ID 2
+
+/* Control device descriptor, opened on demand. The fast path reads it
+ * without holding fd_init_lock, so all accesses are atomic.
+ */
+static RTE_ATOMIC(int)ask_fd = -1;
+static pthread_mutex_t fd_init_lock = PTHREAD_MUTEX_INITIALIZER;
+
+struct ask_ctrl_offline_channel {
+ uint32_t channel_id;
+ uint32_t ctx_a_hi_val; /* Setting required flags(B0,A2) while creating
+ * frame queue.
+ */
+ uint32_t ctx_a_lo_val; /* EBD and VSP enable bits */
+ uint32_t ctx_b_val; /* VSP ID */
+};
+
+struct ask_ctrl_dpdk_fq_info_s {
+ uint32_t tx_fq_id; /* DPDK transmits GTP packets using FQ
+ * ID
+ */
+ uint32_t rx_fq_id; /* DPDK receives packets from FMAN */
+ uint16_t buff_size; /* Size of each buffer in DPDPK buffer
+ * pool
+ */
+ uint8_t bp_id; /* DPDK buffer pool id */
+ /* BH port interface name , for testing purpose */
+ uint8_t bh_port_name[MAX_BH_PORT_NAME_LEN];
+ /* below fields are taken from structure t_FmBufferPrefixContent, These
+ * fields are required for VSP creation on DPDK buffer pool ID. These
+ * fields should be set based on expected parameters from FMAN
+ */
+ uint16_t privDataSize; /* Number of bytes to be left at the
+ * beginning of the external buffer;
+ * Note that the private-area will start
+ * from the base of the buffer address.
+ */
+ bool passPrsResult; /* TRUE to pass the parse result to/from
+ * the FM; User may use
+ * FM_PORT_GetBufferPrsResult() in order
+ * to get the parser-result from a
+ * buffer.
+ */
+ bool passTimeStamp; /* < TRUE to pass the timeStamp to/from
+ * the FM User may use
+ * FM_PORT_GetBufferTimeStamp() in order
+ * to get the parser-result from a
+ * buffer.
+ */
+ bool passHashResult; /* TRUE to pass the KG hash result
+ * to/from the FM User may use
+ * FM_PORT_GetBufferHashResult() in
+ * order to get the parser-result from a
+ * buffer.
+ */
+ bool passAllOtherPCDInfo; /* Add all other Internal-Context
+ * information: AD, hash-result, key,
+ * etc.
+ */
+ uint16_t dataAlign; /* 0 to use driver's default alignment
+ * [DEFAULT_FM_SP_bufferPrefixContent_dataAlign],
+ * other value for selecting a data
+ * alignment (must be a power of 2); if
+ * write optimization is used, must be
+ * >= 16.
+ */
+ uint8_t manipExtraSpace; /* Maximum extra size needed (insertion-
+ * size minus removal-size); Note that
+ * this field impacts the size of the
+ * buffer-prefix (i.e. it pushes the
+ * data offset); This field is
+ * irrelevant if DPAA_VERSION==10
+ */
+};
+
+#define ASK_CTRL_GET_OFFLINE_CHANNEL_INFO \
+ _IOWR(CDX_IOC_MAGIC, 8, struct ask_ctrl_offline_channel)
+#define ASK_CTRL_SET_DPDK_INFO \
+ _IOWR(CDX_IOC_MAGIC, 9, struct ask_ctrl_dpdk_fq_info_s)
+#define ASK_CTRL_SET_CLASSIF_INFO \
+ _IOWR(CDX_IOC_MAGIC, 10, struct rte_pmd_dpaa_uplink_cls_info_s)
+#define ASK_CTRL_RESET_CLASSIF_INFO \
+ _IOWR(CDX_IOC_MAGIC, 11, struct rte_pmd_dpaa_uplink_cls_info_s)
+#define ASK_CTRL_SET_LGW_INFO \
+ _IOWR(CDX_IOC_MAGIC, 12, struct rte_pmd_dpaa_lgw_info_s)
+#define ASK_CTRL_RESET_LGW_INFO \
+ _IOWR(CDX_IOC_MAGIC, 13, struct rte_pmd_dpaa_lgw_info_s)
+
+
+/* Return the control device descriptor, opening it on first use. */
+static int check_fd(void)
+{
+ int cur_fd, ret;
+
+ cur_fd = rte_atomic_load_explicit(&ask_fd, rte_memory_order_acquire);
+ if (cur_fd >= 0)
+ return cur_fd;
+
+ ret = pthread_mutex_lock(&fd_init_lock);
+ assert(!ret);
+ /* check again with the lock held */
+ cur_fd = rte_atomic_load_explicit(&ask_fd, rte_memory_order_relaxed);
+ if (cur_fd < 0) {
+ cur_fd = open(ASK_PATH, O_RDWR);
+ if (cur_fd >= 0)
+ rte_atomic_store_explicit(&ask_fd, cur_fd,
+ rte_memory_order_release);
+ }
+ ret = pthread_mutex_unlock(&fd_init_lock);
+ assert(!ret);
+
+ return (cur_fd >= 0) ? cur_fd : -ENODEV;
+}
+
+static int ask_get_channel_info(struct ask_ctrl_offline_channel *ch_info)
+{
+ int ret, fd = check_fd();
+
+ if (fd < 0)
+ return fd;
+
+ ret = ioctl(fd, ASK_CTRL_GET_OFFLINE_CHANNEL_INFO, ch_info);
+ if (ret) {
+ int err = errno;
+
+ /* Save errno first: the log call may overwrite it. */
+ DPAA_PMD_ERR("Get channel info ioctl failed with errno: %s", strerror(err));
+ return -err;
+ }
+
+ DPAA_PMD_DEBUG("Get channel info successful");
+ DPAA_PMD_DEBUG("Channel id: %x", ch_info->channel_id);
+ DPAA_PMD_DEBUG("ctx_a_hi_val: %x", ch_info->ctx_a_hi_val);
+ DPAA_PMD_DEBUG("ctx_a_lo_val: %x", ch_info->ctx_a_lo_val);
+ DPAA_PMD_DEBUG("ctx_b_val: %x", ch_info->ctx_b_val);
+
+ return 0;
+}
+
+static int ask_set_fq_info(struct ask_ctrl_dpdk_fq_info_s *fq_info)
+{
+ int ret, fd = check_fd();
+
+ if (fd < 0)
+ return fd;
+
+ ret = ioctl(fd, ASK_CTRL_SET_DPDK_INFO, fq_info);
+ if (ret) {
+ int err = errno;
+
+ /* Save errno first: the log call may overwrite it. */
+ DPAA_PMD_ERR("Set FQ info ioctl failed with errno: %s", strerror(err));
+ return -err;
+ }
+
+ DPAA_PMD_DEBUG("Set fq info successful");
+ DPAA_PMD_DEBUG("Tx fqid: %x", fq_info->tx_fq_id);
+ DPAA_PMD_DEBUG("Rx fqid: %x", fq_info->rx_fq_id);
+ DPAA_PMD_DEBUG("buff_size: %d", fq_info->buff_size);
+ DPAA_PMD_DEBUG("bp_id: %d", fq_info->bp_id);
+ DPAA_PMD_DEBUG("Backhaul port name: %s", fq_info->bh_port_name);
+
+ return 0;
+}
+
+static int
+dpaa_ol_dev_configure(__rte_unused struct rte_eth_dev *dev)
+{
+ PMD_INIT_FUNC_TRACE();
+
+ return 0;
+}
+
+static int dpaa_ol_dev_info(struct rte_eth_dev *dev,
+ struct rte_eth_dev_info *dev_info)
+{
+ struct dpaa_if *dpaa_intf = dev->data->dev_private;
+
+ PMD_INIT_FUNC_TRACE();
+
+ dev_info->max_rx_queues = dpaa_intf->nb_rx_queues;
+ dev_info->max_tx_queues = dpaa_intf->nb_tx_queues;
+ dev_info->max_rx_pktlen = DPAA_MAX_RX_PKT_LEN;
+ dev_info->max_mac_addrs = DPAA_MAX_MAC_FILTER;
+ dev_info->max_hash_mac_addrs = 0;
+ dev_info->max_vfs = 0;
+
+ dev_info->speed_capa = RTE_ETH_LINK_SPEED_10M_HD |
+ RTE_ETH_LINK_SPEED_10M |
+ RTE_ETH_LINK_SPEED_100M_HD |
+ RTE_ETH_LINK_SPEED_100M |
+ RTE_ETH_LINK_SPEED_1G |
+ RTE_ETH_LINK_SPEED_2_5G |
+ RTE_ETH_LINK_SPEED_10G;
+
+ return 0;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_dpaa_ol_set_classif_info, 26.11)
+int rte_pmd_dpaa_ol_set_classif_info(struct rte_pmd_dpaa_uplink_cls_info_s *classif_info)
+{
+ int i, ret, fd;
+
+ if (classif_info == NULL) {
+ DPAA_PMD_ERR("No classification data available");
+ return -EINVAL;
+ }
+
+ fd = check_fd();
+ if (fd < 0)
+ return fd;
+
+ ret = ioctl(fd, ASK_CTRL_SET_CLASSIF_INFO, classif_info);
+ if (ret) {
+ int err = errno;
+
+ /* Save errno first: the log call may overwrite it. */
+ DPAA_PMD_ERR("Set classification info ioctl failed with errno: %s",
+ strerror(err));
+ return -err;
+ }
+
+ DPAA_PMD_DEBUG("Set classification info successful");
+ for (i = 0; i < classif_info->num_ports; i++) {
+ DPAA_PMD_DEBUG("UDP dest port: %d",
+ classif_info->gtp_udp_port[i]);
+ }
+ DPAA_PMD_DEBUG("Protocol ID: %d", classif_info->gtp_proto_id);
+
+ return 0;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_dpaa_ol_reset_classif_info, 26.11)
+int rte_pmd_dpaa_ol_reset_classif_info(void)
+{
+ struct rte_pmd_dpaa_uplink_cls_info_s classif_info;
+ int ret, fd;
+
+ fd = check_fd();
+ if (fd < 0)
+ return fd;
+
+ memset(&classif_info, 0, sizeof(classif_info));
+
+ ret = ioctl(fd, ASK_CTRL_RESET_CLASSIF_INFO, &classif_info);
+ if (ret) {
+ int err = errno;
+
+ /* Save errno first: the log call may overwrite it. */
+ DPAA_PMD_ERR("Reset classification info ioctl failed with errno: %s",
+ strerror(err));
+ return -err;
+ }
+
+ DPAA_PMD_DEBUG("Reset classification info successful");
+
+ return 0;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_dpaa_ol_set_lgw_info, 26.11)
+int rte_pmd_dpaa_ol_set_lgw_info(struct rte_pmd_dpaa_lgw_info_s *lgw_info)
+{
+ int ret, fd;
+
+ if (lgw_info == NULL) {
+ DPAA_PMD_ERR("No LGW data available");
+ return -EINVAL;
+ }
+
+ fd = check_fd();
+ if (fd < 0)
+ return fd;
+
+ ret = ioctl(fd, ASK_CTRL_SET_LGW_INFO, lgw_info);
+ if (ret) {
+ int err = errno;
+
+ /* Save errno first: the log call may overwrite it. */
+ DPAA_PMD_ERR("Set LGW info ioctl failed with errno: %s", strerror(err));
+ return -err;
+ }
+
+ DPAA_PMD_DEBUG("Set LGW info successful");
+
+ return 0;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_dpaa_ol_reset_lgw_info, 26.11)
+int rte_pmd_dpaa_ol_reset_lgw_info(void)
+{
+ struct rte_pmd_dpaa_lgw_info_s lgw_info;
+ int ret, fd;
+
+ PMD_INIT_FUNC_TRACE();
+
+ fd = check_fd();
+ if (fd < 0)
+ return fd;
+
+ memset(&lgw_info, 0, sizeof(lgw_info));
+
+ ret = ioctl(fd, ASK_CTRL_RESET_LGW_INFO, &lgw_info);
+ if (ret) {
+ int err = errno;
+
+ /* Save errno first: the log call may overwrite it. */
+ DPAA_PMD_ERR("Reset LGW info ioctl failed with errno: %s", strerror(err));
+ return -err;
+ }
+
+ DPAA_PMD_DEBUG("Reset LGW info successful");
+
+ return 0;
+}
+
+static int dpaa_ol_set_fq_info(struct rte_eth_dev *dev);
+
+static int dpaa_ol_dev_start(struct rte_eth_dev *dev)
+{
+ int ret;
+
+ PMD_INIT_FUNC_TRACE();
+
+ /* Hand the Rx/Tx FQIDs and buffer pool to the kernel here rather than
+ * from tx_queue_setup(): ethdev does not order Rx and Tx queue setup,
+ * and testpmd sets Tx up first, so at tx_queue_setup() time the Rx
+ * side may not be configured yet. By dev_start() both are known.
+ */
+ ret = dpaa_ol_set_fq_info(dev);
+ if (ret)
+ return ret;
+
+ dev->tx_pkt_burst = dpaa_eth_queue_tx;
+
+ return 0;
+}
+
+static int dpaa_ol_dev_stop(struct rte_eth_dev *dev)
+{
+ PMD_INIT_FUNC_TRACE();
+
+ dev->tx_pkt_burst = dpaa_eth_tx_drop_all;
+
+ return 0;
+}
+
+static void dpaa_oldev_queues_release(struct dpaa_if *dpaa_intf);
+
+static int dpaa_ol_dev_close(struct rte_eth_dev *dev)
+{
+ struct dpaa_if *dpaa_intf;
+ int cur_fd;
+
+ PMD_INIT_FUNC_TRACE();
+
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ return 0;
+
+ /* Release the driver private rx/tx_queues here so that an application
+ * that only calls rte_eth_dev_close() (without removing the device)
+ * still shuts down the FQs and frees the queue memory.
+ */
+ dpaa_intf = dev->data->dev_private;
+ if (dpaa_intf)
+ dpaa_oldev_queues_release(dpaa_intf);
+
+ cur_fd = rte_atomic_exchange_explicit(&ask_fd, -1,
+ rte_memory_order_acq_rel);
+ if (cur_fd >= 0)
+ close(cur_fd);
+
+ return 0;
+}
+
+static inline void
+dpaa_poll_queue_default_config(struct qm_mcc_initfq *opts)
+{
+ memset(opts, 0, sizeof(struct qm_mcc_initfq));
+ opts->we_mask = QM_INITFQ_WE_CONTEXTA;
+ opts->fqd.fq_ctrl = QM_FQCTRL_AVOIDBLOCK | QM_FQCTRL_CTXASTASHING |
+ QM_FQCTRL_PREFERINCACHE;
+ opts->fqd.context_a.stashing.exclusive = 0;
+ if (dpaa_soc_ver() != SVR_LS1046A_FAMILY)
+ opts->fqd.context_a.stashing.annotation_cl =
+ DPAA_IF_RX_ANNOTATION_STASH;
+ opts->fqd.context_a.stashing.data_cl = DPAA_IF_RX_DATA_STASH;
+ opts->fqd.context_a.stashing.context_cl = DPAA_IF_RX_CONTEXT_STASH;
+}
+
+static
+int dpaa_ol_rx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_idx,
+ __rte_unused uint16_t nb_desc,
+ unsigned int socket_id __rte_unused,
+ __rte_unused const struct rte_eth_rxconf *rx_conf,
+ struct rte_mempool *mp)
+{
+ struct dpaa_if *dpaa_intf = dev->data->dev_private;
+ struct qman_fq *rxq = &dpaa_intf->rx_queues[queue_idx];
+
+ PMD_INIT_FUNC_TRACE();
+
+ if (queue_idx >= dev->data->nb_rx_queues) {
+ rte_errno = EOVERFLOW;
+ DPAA_PMD_ERR("%p: queue index out of range (%u >= %u)",
+ (void *)dev, queue_idx, dev->data->nb_rx_queues);
+ return -rte_errno;
+ }
+
+ dpaa_intf->bp_info = DPAA_MEMPOOL_TO_POOL_INFO(mp);
+ dpaa_intf->valid = 1;
+
+ if (!rte_dpaa_bpid_info) {
+ DPAA_PMD_ERR("BPID info array not initialized");
+ return -ENOMEM;
+ }
+ rxq->bp_array = rte_dpaa_bpid_info;
+ dev->data->rx_queues[queue_idx] = rxq;
+
+ return 0;
+}
+
+/* This API has dependency on RX queue setup */
+static int
+dpaa_ol_get_bh_port_name(struct rte_devargs *devargs, char *val, size_t size)
+{
+ struct rte_kvargs *kvlist;
+ const char *str;
+ int ret;
+
+ if (!devargs)
+ return 0;
+
+ kvlist = rte_kvargs_parse(devargs->args, NULL);
+ if (!kvlist)
+ return 0;
+
+ if (!rte_kvargs_count(kvlist, DRIVER_OL_BH_PORT)) {
+ rte_kvargs_free(kvlist);
+ return 0;
+ }
+
+ str = rte_kvargs_get(kvlist, DRIVER_OL_BH_PORT);
+ if (str == NULL) {
+ rte_kvargs_free(kvlist);
+ return 0;
+ }
+
+ ret = rte_strscpy(val, str, size);
+ rte_kvargs_free(kvlist);
+ if (ret < 0)
+ return ret;
+
+ return 1;
+}
+
+static
+int dpaa_ol_tx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_idx,
+ uint16_t nb_desc __rte_unused,
+ unsigned int socket_id __rte_unused,
+ const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+ struct dpaa_if *dpaa_intf = dev->data->dev_private;
+ struct qman_fq *txq = &dpaa_intf->tx_queues[queue_idx];
+
+ PMD_INIT_FUNC_TRACE();
+
+ dev->data->tx_queues[queue_idx] = txq;
+
+ return 0;
+}
+
+/* Program the Rx/Tx FQIDs and the buffer pool into the kernel. Called from
+ * dev_start(), by which point both the Rx and the Tx queue are set up.
+ */
+static int dpaa_ol_set_fq_info(struct rte_eth_dev *dev)
+{
+ struct dpaa_if *dpaa_intf = dev->data->dev_private;
+ struct ask_ctrl_dpdk_fq_info_s fq_info;
+ struct qman_fq *txq, *rxq;
+ struct rte_pktmbuf_pool_private *mbp_priv;
+ int ret;
+
+ if (dpaa_intf->rx_queues == NULL || dpaa_intf->tx_queues == NULL) {
+ DPAA_PMD_ERR("Rx/Tx queues not allocated");
+ return -EINVAL;
+ }
+
+ if (dpaa_intf->bp_info == NULL) {
+ DPAA_PMD_ERR("Rx queue must be set up before starting the port");
+ return -EINVAL;
+ }
+
+ txq = &dpaa_intf->tx_queues[0];
+ rxq = &dpaa_intf->rx_queues[0];
+ memset(&fq_info, 0, sizeof(fq_info));
+ mbp_priv = (struct rte_pktmbuf_pool_private *)rte_mempool_get_priv(dpaa_intf->bp_info->mp);
+ fq_info.tx_fq_id = txq->fqid;
+ fq_info.rx_fq_id = rxq->fqid;
+ fq_info.buff_size = mbp_priv->mbuf_data_room_size;
+ fq_info.bp_id = dpaa_intf->bp_info->bpid;
+
+ fq_info.privDataSize = DPAA_OL_PARSERSLT_START_OFFSET;
+ fq_info.passPrsResult = DPAA_OL_PARSE_RESULT_REQUIRED;
+ fq_info.passTimeStamp = DPAA_OL_TIME_STAMP_REQUIRED;
+ fq_info.passHashResult = DPAA_OL_HASH_RESULT_REQUIRED;
+ fq_info.passAllOtherPCDInfo = DPAA_OL_PCD_INFO_REQUIRED;
+ fq_info.dataAlign = DPAA_OL_DATA_ALIGNMENT;
+ fq_info.manipExtraSpace = DPAA_OL_MAX_EXTRA_SIZE;
+
+ ret = dpaa_ol_get_bh_port_name(dev->device->devargs,
+ (char *)fq_info.bh_port_name,
+ MAX_BH_PORT_NAME_LEN);
+ if (ret <= 0) {
+ DPAA_PMD_ERR("Offline port \"%s\" devarg not defined or invalid (ret=%d)",
+ DRIVER_OL_BH_PORT, ret);
+ return -EINVAL;
+ }
+
+ ret = ask_set_fq_info(&fq_info);
+ if (ret) {
+ DPAA_PMD_ERR("Set FQ info failed with ret: %d", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dpaa_ol_link_update(struct rte_eth_dev *dev,
+ __rte_unused int wait_to_complete)
+{
+ struct dpaa_if *dpaa_intf = dev->data->dev_private;
+ struct rte_eth_link *link = &dev->data->dev_link;
+
+ PMD_INIT_FUNC_TRACE();
+
+ link->link_status = dpaa_intf->valid;
+ link->link_speed = RTE_ETH_SPEED_NUM_NONE;
+ link->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+ link->link_autoneg = RTE_ETH_LINK_AUTONEG;
+
+ return 0;
+}
+
+static int dpaa_ol_promiscuous_enable(__rte_unused struct rte_eth_dev *dev)
+{
+ PMD_INIT_FUNC_TRACE();
+
+ return 0;
+}
+
+static int dpaa_ol_rx_queue_init(struct qman_fq *fq, uint32_t fqid)
+{
+ int ret;
+ struct qm_mcc_initfq opts = {0};
+ u32 flags = QMAN_FQ_FLAG_DYNAMIC_FQID | QMAN_FQ_FLAG_NO_ENQUEUE;
+
+ if (unlikely(!DPAA_PER_LCORE_PORTAL)) {
+ ret = rte_dpaa_portal_init(NULL);
+ if (ret < 0) {
+ DPAA_PMD_ERR("portal initialization failure");
+ return ret;
+ }
+ }
+
+ ret = qman_create_fq(fqid, flags, fq);
+ if (ret) {
+ DPAA_PMD_ERR("create rx fqid 0x%x failed with ret: %d", fqid,
+ ret);
+ return ret;
+ }
+ fq->is_static = false;
+
+ dpaa_poll_queue_default_config(&opts);
+
+ ret = qman_init_fq(fq, 0, &opts);
+ if (ret)
+ DPAA_PMD_ERR("init rx fqid 0x%x failed with ret:%d", fqid, ret);
+ return ret;
+}
+
+static int dpaa_ol_tx_queue_init(struct qman_fq *fq, uint32_t fqid)
+{
+ int ret;
+ struct qm_mcc_initfq opts = {0};
+ u32 flags = QMAN_FQ_FLAG_DYNAMIC_FQID | QMAN_FQ_FLAG_TO_DCPORTAL;
+ struct ask_ctrl_offline_channel ch_info;
+
+ memset(&ch_info, 0, sizeof(ch_info));
+
+ ret = ask_get_channel_info(&ch_info);
+ if (ret) {
+ DPAA_PMD_ERR("Get channel info failed with ret: %d", ret);
+ return ret;
+ }
+ ret = qman_create_fq(fqid, flags, fq);
+ if (ret) {
+ DPAA_PMD_ERR("Create tx fq failed with ret: %d", ret);
+ return ret;
+ }
+
+ opts.we_mask = QM_INITFQ_WE_DESTWQ |
+ QM_INITFQ_WE_CONTEXTB | QM_INITFQ_WE_CONTEXTA;
+
+ opts.fqd.dest.channel = ch_info.channel_id;
+ opts.fqd.dest.wq = DPA_ISC_WQ_ID;
+ opts.fqd.fq_ctrl = QM_FQCTRL_PREFERINCACHE;
+ opts.fqd.context_b = ch_info.ctx_b_val;
+ opts.fqd.context_a.hi = ch_info.ctx_a_hi_val;
+ opts.fqd.context_a.lo = ch_info.ctx_a_lo_val;
+
+ opts.fqid = fq->fqid;
+ fq->ch_id = ch_info.channel_id;
+ opts.count = 1;
+
+ ret = qman_init_fq(fq, QMAN_INITFQ_FLAG_SCHED, &opts);
+ if (ret)
+ DPAA_PMD_ERR("init tx fqid 0x%x failed %d", fq->fqid, ret);
+ return ret;
+}
+
+static const struct eth_dev_ops dpaa_ol_devops = {
+ .dev_configure = dpaa_ol_dev_configure,
+ .dev_start = dpaa_ol_dev_start,
+ .dev_stop = dpaa_ol_dev_stop,
+ .dev_close = dpaa_ol_dev_close,
+ .dev_infos_get = dpaa_ol_dev_info,
+
+ .rx_queue_setup = dpaa_ol_rx_queue_setup,
+ .tx_queue_setup = dpaa_ol_tx_queue_setup,
+
+ .link_update = dpaa_ol_link_update,
+ .promiscuous_enable = dpaa_ol_promiscuous_enable,
+};
+
+static void dpaa_oldev_queues_release(struct dpaa_if *dpaa_intf)
+{
+ uint16_t i;
+ int ret;
+
+ if (dpaa_intf->tx_queues) {
+ for (i = 0; i < dpaa_intf->nb_tx_queues; i++) {
+ if (!dpaa_intf->tx_queues[i].fqid)
+ continue;
+ ret = qman_shutdown_fq(&dpaa_intf->tx_queues[i]);
+ if (ret) {
+ /* The FQ is still live in QMan, so the FQID
+ * cannot be handed back: qman_alloc_fqid()
+ * could give it to another user while the
+ * hardware still references it. Leaking it
+ * is the safe choice.
+ */
+ DPAA_PMD_WARN("Failed(%d) to shutdown txq%d(0x%x), fqid not released",
+ ret, i, dpaa_intf->tx_queues[i].fqid);
+ continue;
+ }
+ /* The FQ was created with QMAN_FQ_FLAG_DYNAMIC_FQID,
+ * so qman_create_fq() allocated the FQID. Give it
+ * back, otherwise every probe/close cycle leaks one.
+ */
+ qman_release_fqid(dpaa_intf->tx_queues[i].fqid);
+ }
+ rte_free(dpaa_intf->tx_queues);
+ dpaa_intf->tx_queues = NULL;
+ dpaa_intf->nb_tx_queues = 0;
+ }
+
+ if (dpaa_intf->rx_queues) {
+ for (i = 0; i < dpaa_intf->nb_rx_queues; i++) {
+ if (!dpaa_intf->rx_queues[i].fqid)
+ continue;
+ ret = qman_shutdown_fq(&dpaa_intf->rx_queues[i]);
+ if (ret) {
+ /* Same as above: keep the FQID reserved. */
+ DPAA_PMD_WARN("Failed(%d) to shutdown rxq%d(0x%x), fqid not released",
+ ret, i, dpaa_intf->rx_queues[i].fqid);
+ continue;
+ }
+ /* Same as above for the Rx FQs. */
+ qman_release_fqid(dpaa_intf->rx_queues[i].fqid);
+ }
+ rte_free(dpaa_intf->rx_queues);
+ dpaa_intf->rx_queues = NULL;
+ dpaa_intf->nb_rx_queues = 0;
+ }
+}
+
+static int dpaa_oldev_init(struct rte_eth_dev *eth_dev)
+{
+ int num_fqs, ret;
+ struct dpaa_if *dpaa_intf;
+
+ PMD_INIT_FUNC_TRACE();
+
+ num_fqs = DPAA_DEFAULT_NUM_PCD_QUEUES;
+ dpaa_intf = eth_dev->data->dev_private;
+
+ dpaa_intf->rx_queues = rte_zmalloc(NULL,
+ sizeof(struct qman_fq) * num_fqs,
+ MAX_CACHELINE);
+ if (!dpaa_intf->rx_queues) {
+ DPAA_PMD_ERR("Failed to alloc mem for RX queues");
+ return -ENOMEM;
+ }
+ /* Set the count as soon as the array exists so that the release
+ * helper always walks the whole allocation on the error paths.
+ */
+ dpaa_intf->nb_rx_queues = num_fqs;
+
+ ret = dpaa_ol_rx_queue_init(&dpaa_intf->rx_queues[0], 0);
+ if (ret)
+ goto free_rx;
+ dpaa_intf->rx_queues[0].dpaa_intf = dpaa_intf;
+
+ dpaa_intf->tx_queues = rte_zmalloc(NULL,
+ sizeof(struct qman_fq) * num_fqs,
+ MAX_CACHELINE);
+ if (!dpaa_intf->tx_queues) {
+ DPAA_PMD_ERR("Failed to alloc mem for TX queues");
+ ret = -ENOMEM;
+ goto free_rx;
+ }
+ dpaa_intf->nb_tx_queues = num_fqs;
+
+ ret = dpaa_ol_tx_queue_init(&dpaa_intf->tx_queues[0], 0);
+ if (ret)
+ goto free_rx;
+
+ eth_dev->dev_ops = &dpaa_ol_devops;
+ eth_dev->rx_pkt_burst = dpaa_eth_queue_rx;
+ eth_dev->tx_pkt_burst = dpaa_eth_tx_drop_all;
+
+ /* Allocate memory for storing MAC addresses */
+ eth_dev->data->mac_addrs = rte_zmalloc("mac_addr",
+ RTE_ETHER_ADDR_LEN * DPAA_MAX_MAC_FILTER, 0);
+ if (eth_dev->data->mac_addrs == NULL) {
+ DPAA_PMD_ERR("Failed to allocate %d bytes needed to "
+ "store MAC addresses",
+ RTE_ETHER_ADDR_LEN * DPAA_MAX_MAC_FILTER);
+ ret = -ENOMEM;
+ goto free_rx;
+ }
+
+ return 0;
+
+free_rx:
+ dpaa_oldev_queues_release(dpaa_intf);
+ return ret;
+}
+
+static int dpaa_ol_probe(__rte_unused struct rte_dpaa_driver *dpaa_drv,
+ struct rte_dpaa_device *dpaa_dev)
+{
+ int ret;
+ struct rte_eth_dev *eth_dev;
+
+ PMD_INIT_FUNC_TRACE();
+
+ /* The offline port's frame queues are created with dynamic FQIDs and
+ * programmed into the kernel through the control device, all of which
+ * is owned by the primary. A secondary has no way to attach to that
+ * state, so do not advertise the port here rather than run
+ * dpaa_oldev_init() against resources it does not own.
+ */
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
+ DPAA_PMD_WARN("%s: not supported in secondary process",
+ dpaa_dev->device.name);
+ return -ENOTSUP;
+ }
+
+ eth_dev = rte_eth_dev_allocate(dpaa_dev->name);
+ if (!eth_dev)
+ return -ENOMEM;
+ eth_dev->data->dev_private = rte_zmalloc("ethdev private structure",
+ sizeof(struct dpaa_if),
+ RTE_CACHE_LINE_SIZE);
+ if (!eth_dev->data->dev_private) {
+ DPAA_PMD_ERR("Cannot allocate memzone for port data");
+ rte_eth_dev_release_port(eth_dev);
+ return -ENOMEM;
+ }
+
+ eth_dev->device = &dpaa_dev->device;
+
+ ret = dpaa_oldev_init(eth_dev);
+ if (ret == 0) {
+ rte_eth_dev_probing_finish(eth_dev);
+ return 0;
+ }
+
+ /* dpaa_oldev_init() has already released its own allocations. */
+ rte_eth_dev_release_port(eth_dev);
+ return ret;
+}
+
+static int dpaa_ol_remove(struct rte_dpaa_device *dpaa_dev)
+{
+ struct rte_eth_dev *eth_dev;
+
+ PMD_INIT_FUNC_TRACE();
+
+ /* A secondary never probed this device, see dpaa_ol_probe(). */
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ return 0;
+
+ eth_dev = rte_eth_dev_allocated(dpaa_dev->device.name);
+ if (eth_dev == NULL)
+ return 0;
+
+ /* Shut down the FQs and free the driver private rx/tx_queues. This is
+ * idempotent, so it is safe even if the application already called
+ * rte_eth_dev_close() (which runs the same callback).
+ */
+ dpaa_ol_dev_close(eth_dev);
+
+ return rte_eth_dev_release_port(eth_dev);
+}
+
+static struct rte_dpaa_driver rte_dpaa_ol_pmd = {
+ .drv_type = FSL_DPAA_OL,
+ .probe = dpaa_ol_probe,
+ .remove = dpaa_ol_remove,
+};
+
+RTE_PMD_REGISTER_DPAA(ol_dpaa, rte_dpaa_ol_pmd);
+RTE_PMD_REGISTER_PARAM_STRING(ol_dpaa,
+ DRIVER_OL_BH_PORT "=<string>");
diff --git a/drivers/net/dpaa/meson.build b/drivers/net/dpaa/meson.build
index 8d4f69c596..3ec1091197 100644
--- a/drivers/net/dpaa/meson.build
+++ b/drivers/net/dpaa/meson.build
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: BSD-3-Clause
-# Copyright 2018-2020 NXP
+# Copyright 2018-2020,2026 NXP
if not is_linux
build = false
@@ -9,12 +9,13 @@ deps += ['mempool_dpaa']
sources = files(
'dpaa_ethdev.c',
- 'fmlib/fm_lib.c',
- 'fmlib/fm_vsp.c',
'dpaa_flow.c',
- 'dpaa_rxtx.c',
'dpaa_fmc.c',
'dpaa_ptp.c',
+ 'dpaa_oldev.c',
+ 'dpaa_rxtx.c',
+ 'fmlib/fm_lib.c',
+ 'fmlib/fm_vsp.c',
)
cflags += no_wvla_cflag
@@ -24,4 +25,4 @@ if cc.has_argument('-Wno-pointer-arith')
cflags += '-Wno-pointer-arith'
endif
-headers = files('rte_pmd_dpaa.h')
+headers = files('rte_pmd_dpaa.h', 'rte_pmd_dpaa_oldev.h')
diff --git a/drivers/net/dpaa/rte_pmd_dpaa_oldev.h b/drivers/net/dpaa/rte_pmd_dpaa_oldev.h
new file mode 100644
index 0000000000..5ca25efcf2
--- /dev/null
+++ b/drivers/net/dpaa/rte_pmd_dpaa_oldev.h
@@ -0,0 +1,158 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2020-2026 NXP
+ */
+
+#ifndef _RTE_PMD_DPAA_OLDEV_H
+#define _RTE_PMD_DPAA_OLDEV_H
+
+/**
+ * @file rte_pmd_dpaa_oldev.h
+ *
+ * NXP DPAA offline (O/H) port PMD-specific API.
+ *
+ * @warning
+ * @b EXPERIMENTAL:
+ * All functions in this file may be changed or removed without prior notice.
+ *
+ * These APIs configure the classification, local gateway (LGW) and related
+ * uplink information for the DPAA offline port through the kernel control
+ * device.
+ */
+
+#include <stdint.h>
+#include <rte_common.h>
+#include <rte_compat.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DPA_ISC_IPV4_ADDR_TYPE 0x04
+#define DPA_ISC_IPV6_ADDR_TYPE 0x06
+
+#define DPDK_OLDEV_MAX_NUM_PORTS 2
+
+#define DPA_ISC_IPV4_SUBNET_TYPE 0x04
+#define DPA_ISC_IPV6_SUBNET_TYPE 0x06
+#define DPDK_OLDEV_MAX_NUM_SUBNETS 4
+
+/* following macros used for flags field */
+/* this macro should be set when addr pair consisting valid
+ * inner IP address
+ */
+#define DPDK_CLASSIF_INNER_IP 0x1
+
+/* this macro should be set when addr pair consisting static
+ * IP address
+ */
+#define DPDK_CLASSIF_STATIC_IP 0x2
+
+/* macro to indicate telecom application is listening on only
+ * static IP address
+ */
+#define DPDK_TELECOM_LISTEN_ON_ONLY_STATICIP 0x4
+
+/* macro to indicate that telecom application is listening on
+ * both static and inner IP addresses
+ */
+#define DPDK_TELECOM_LISTEN_ON_BOTH_STATIC_INNER_IP 0x8
+
+/* macro to indicate that telecom application is listening on
+ * only inner IP address
+ */
+#define DPDK_TELECOM_LISTEN_ON_ONLY_INNERIP 0x10
+
+/* Holds an IPv4 or IPv6 address; ip_addr[0] is used for IPv4, all four
+ * words for IPv6. The addr_type field in dpa_ip_pair_s selects the version.
+ */
+struct dpa_ip_addr_s {
+ uint32_t ip_addr[4];
+};
+
+struct __rte_packed_begin dpa_ip_pair_s {
+ struct dpa_ip_addr_s static_ip, inner_ip;
+ uint8_t flags;
+ uint8_t addr_type;
+ uint8_t pad[2];
+} __rte_packed_end;
+
+struct __rte_packed_begin dpa_lgw_subnet_s {
+ uint32_t subnet[4];
+ uint8_t mask;
+ uint8_t subnet_type;
+ uint8_t pad[2];
+} __rte_packed_end;
+
+struct rte_pmd_dpaa_uplink_cls_info_s {
+ struct dpa_ip_pair_s addr_pair;
+ /* DPDK app listens on these GTP ports */
+ uint16_t gtp_udp_port[DPDK_OLDEV_MAX_NUM_PORTS];
+ uint8_t gtp_proto_id; /* DPDK app listens on UDP protocol */
+ uint8_t num_ports;
+ uint8_t sec_enabled;
+ uint8_t pad;
+};
+
+struct __rte_packed_begin rte_pmd_dpaa_lgw_info_s {
+ struct dpa_lgw_subnet_s subnets[DPDK_OLDEV_MAX_NUM_SUBNETS];
+ uint8_t num_subnets;
+ uint8_t pad[3];
+} __rte_packed_end;
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Program the uplink classification information for the DPAA offline port.
+ *
+ * @param cls_info
+ * Pointer to the classification information to program. Must not be NULL.
+ * @return
+ * 0 on success, negative value otherwise.
+ */
+__rte_experimental
+int rte_pmd_dpaa_ol_set_classif_info(struct rte_pmd_dpaa_uplink_cls_info_s *cls_info);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Reset the uplink classification information for the DPAA offline port.
+ *
+ * @return
+ * 0 on success, negative value otherwise.
+ */
+__rte_experimental
+int rte_pmd_dpaa_ol_reset_classif_info(void);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Program the local gateway (LGW) information for the DPAA offline port.
+ *
+ * @param lgw_info
+ * Pointer to the LGW information to program. Must not be NULL.
+ * @return
+ * 0 on success, negative value otherwise.
+ */
+__rte_experimental
+int rte_pmd_dpaa_ol_set_lgw_info(struct rte_pmd_dpaa_lgw_info_s *lgw_info);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Reset the local gateway (LGW) information for the DPAA offline port.
+ *
+ * @return
+ * 0 on success, negative value otherwise.
+ */
+__rte_experimental
+int rte_pmd_dpaa_ol_reset_lgw_info(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_PMD_DPAA_OLDEV_H */
--
2.25.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/3] net/dpaa: support non fmX-macY type of shared Ethernet name
2026-10-28 8:51 [PATCH v2 0/1] DPAA compilation fix ppc64le and riscv Gagandeep Singh
2026-10-28 8:51 ` [PATCH v2 1/1] bus/dpaa: fix maybe-uninitialized in bman_release_fast Gagandeep Singh
2026-10-28 8:51 ` [PATCH 1/3] drivers: add offline (O/H) port device support Gagandeep Singh
@ 2026-10-28 8:51 ` Gagandeep Singh
2026-10-28 8:51 ` [PATCH 3/3] drivers: add DPAA cgrid cleanup support Gagandeep Singh
3 siblings, 0 replies; 6+ messages in thread
From: Gagandeep Singh @ 2026-10-28 8:51 UTC (permalink / raw)
To: dev; +Cc: hemant.agrawal
From: Hemant Agrawal <hemant.agrawal@nxp.com>
A shared MAC interface needs the kernel netdev name to read the MTU,
and that name is only the DPDK port name for fmX-macY style netdevs.
Look it up in sysfs under the platform device of the dpa-ethernet node
the port was created from, and fall back to the port name.
Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
---
doc/guides/nics/dpaa.rst | 5 +++
drivers/net/dpaa/dpaa_ethdev.c | 59 +++++++++++++++++++++++++++++++++-
2 files changed, 63 insertions(+), 1 deletion(-)
diff --git a/doc/guides/nics/dpaa.rst b/doc/guides/nics/dpaa.rst
index 667b8c113d..14a14feb3c 100644
--- a/doc/guides/nics/dpaa.rst
+++ b/doc/guides/nics/dpaa.rst
@@ -303,6 +303,11 @@ is passed through the EAL bus arguments. The bus name is ``dpaa_bus``:
silently drops that port.
+* For a shared MAC interface the kernel network interface name is looked up
+ in sysfs from the device tree node the port was created from,
+ so a kernel interface that does not follow
+ the ``fmX-macY`` naming style is handled without extra configuration.
+
FMAN Config
-----------
diff --git a/drivers/net/dpaa/dpaa_ethdev.c b/drivers/net/dpaa/dpaa_ethdev.c
index fe49c7b961..456e3df995 100644
--- a/drivers/net/dpaa/dpaa_ethdev.c
+++ b/drivers/net/dpaa/dpaa_ethdev.c
@@ -15,6 +15,7 @@
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>
+#include <dirent.h>
#include <eal_export.h>
#include <rte_string_fns.h>
@@ -57,6 +58,53 @@
#define DRIVER_RECV_ERR_PKTS "recv_err_pkts"
#define RTE_PRIORITY_103 103
+/*
+ * Get the name of the kernel netdev bound to the same device tree node as
+ * this port. Returns 1 on success, 0 if none was found, negative on error.
+ */
+static int
+dpaa_get_kernel_ifname(const char *node_path, char *name, size_t size)
+{
+ char path[PATH_MAX];
+ const char *node;
+ struct dirent *entry;
+ DIR *dir;
+ int ret;
+
+ if (!node_path || node_path[0] == '\0')
+ return 0;
+
+ /* Platform device name is the last node of the DTS path. */
+ node = strrchr(node_path, '/');
+ node = node ? node + 1 : node_path;
+ if (node[0] == '\0')
+ return 0;
+
+ ret = snprintf(path, sizeof(path),
+ "/sys/bus/platform/devices/%s/net", node);
+ if (ret < 0 || (size_t)ret >= sizeof(path))
+ return -ENAMETOOLONG;
+
+ dir = opendir(path);
+ if (!dir)
+ return 0;
+
+ ret = 0;
+ while ((entry = readdir(dir)) != NULL) {
+ if (entry->d_name[0] == '.')
+ continue;
+ if (rte_strscpy(name, entry->d_name, size) < 0) {
+ ret = -ENAMETOOLONG;
+ break;
+ }
+ ret = 1;
+ break;
+ }
+
+ closedir(dir);
+ return ret;
+}
+
/* Supported Rx offloads */
static uint64_t dev_rx_offloads_sup =
RTE_ETH_RX_OFFLOAD_SCATTER;
@@ -251,6 +299,7 @@ dpaa_eth_dev_configure(struct rte_eth_dev *dev)
int speed, duplex;
int ret, rx_status, socket_fd;
struct ifreq ifr;
+ char sh_if_name[IFNAMSIZ];
PMD_INIT_FUNC_TRACE();
@@ -272,7 +321,15 @@ dpaa_eth_dev_configure(struct rte_eth_dev *dev)
DPAA_PMD_ERR("Cannot open IF socket");
return -errno;
}
- strlcpy(ifr.ifr_name, dpaa_intf->name, IFNAMSIZ);
+
+ /* The DPDK port name matches the netdev only for fmX-macY. */
+ sh_if_name[0] = '\0';
+ ret = dpaa_get_kernel_ifname(__fif->node_path, sh_if_name,
+ sizeof(sh_if_name));
+ if (ret <= 0 || sh_if_name[0] == '\0')
+ strlcpy(ifr.ifr_name, dpaa_intf->name, IFNAMSIZ);
+ else
+ strlcpy(ifr.ifr_name, sh_if_name, IFNAMSIZ);
if (ioctl(socket_fd, SIOCGIFMTU, &ifr) < 0) {
DPAA_PMD_ERR("Cannot get interface mtu");
--
2.25.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 3/3] drivers: add DPAA cgrid cleanup support
2026-10-28 8:51 [PATCH v2 0/1] DPAA compilation fix ppc64le and riscv Gagandeep Singh
` (2 preceding siblings ...)
2026-10-28 8:51 ` [PATCH 2/3] net/dpaa: support non fmX-macY type of shared Ethernet name Gagandeep Singh
@ 2026-10-28 8:51 ` Gagandeep Singh
3 siblings, 0 replies; 6+ messages in thread
From: Gagandeep Singh @ 2026-10-28 8:51 UTC (permalink / raw)
To: dev; +Cc: hemant.agrawal, Jun Yang
From: Jun Yang <jun.yang@nxp.com>
A congestion group must have no member frame queues left when it is
deleted, and its CGRID must be returned to the allocator once the group
is gone. Neither was handled on the net/dpaa close and probe-failure
paths.
This also changes probe behaviour: a qman_create_cgr() failure in
dpaa_rx_queue_init() or dpaa_tx_queue_init() now fails the probe
instead of continuing without tail drop on that queue. The probe error
path deletes one CGR per initialised queue, and a CGR whose creation
failed was never linked into the portal list.
Signed-off-by: Jun Yang <jun.yang@nxp.com>
Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
---
drivers/bus/dpaa/base/qbman/qman.c | 61 ++++++++++++
drivers/bus/dpaa/dpaa_bus_base_symbols.c | 1 +
drivers/bus/dpaa/include/fsl_qman.h | 27 ++++++
drivers/net/dpaa/dpaa_ethdev.c | 117 ++++++++++++++++++++---
4 files changed, 194 insertions(+), 12 deletions(-)
diff --git a/drivers/bus/dpaa/base/qbman/qman.c b/drivers/bus/dpaa/base/qbman/qman.c
index 3c056e4547..fa3387c6bd 100644
--- a/drivers/bus/dpaa/base/qbman/qman.c
+++ b/drivers/bus/dpaa/base/qbman/qman.c
@@ -2993,3 +2993,64 @@ qman_shutdown_fq(struct qman_fq *fq)
out:
return ret;
}
+
+int qman_pending_fq_by_cgrid_range(u32 cgrid_start, u32 cgrid_num,
+ u32 start_fqid, u32 *fqid, u32 *cgrid)
+{
+ struct qman_fq fq = {
+ .fqid = start_fqid ? start_fqid : 1
+ };
+ struct qm_mcr_queryfq_np np;
+ struct qm_fqd fqd;
+ int err;
+
+ /*
+ * Do not use the CGR byte count to decide whether to scan. An FQ is a
+ * member of the group whenever it is scheduled with CGE set and a
+ * matching cgid, whether or not it currently holds any frames, and the
+ * group cannot be deleted while such a member exists. Skipping the
+ * scan for an empty CGR would let an idle stale FQ survive and its
+ * CGRID be released while still referenced. This runs from the device
+ * close path only, so the scan cost is acceptable.
+ *
+ * The whole CGRID range of a port is matched in a single pass, so a
+ * port with many congestion groups does not need one full FQID space
+ * scan per group.
+ */
+ DPAA_BUS_DEBUG("Scanning FQs for cgrid(0x%x..0x%x)",
+ cgrid_start, cgrid_start + cgrid_num - 1);
+
+ /* FQID space is 24 bits wide; stop before wrapping. */
+ for (; fq.fqid <= QMAN_MAX_FQID; fq.fqid++) {
+ err = qman_query_fq_np(&fq, &np);
+ if (err == -ERANGE) {
+ /*
+ * FQID is not implemented on this device, so there is
+ * nothing beyond it either.
+ */
+ break;
+ } else if (err) {
+ DPAA_BUS_WARN("Failed(%d) to Query np FQ(fqid=0x%x)",
+ err, fq.fqid);
+ return err;
+ }
+ if ((np.state & QM_MCR_NP_STATE_MASK) != QM_MCR_NP_STATE_OOS) {
+ err = qman_query_fq(&fq, &fqd);
+ if (err) {
+ DPAA_BUS_WARN("Failed(%d) to Query FQ(fqid=0x%x)",
+ err, fq.fqid);
+ } else if ((fqd.fq_ctrl & QM_FQCTRL_CGE) &&
+ fqd.cgid >= cgrid_start &&
+ fqd.cgid < cgrid_start + cgrid_num) {
+ if (fqid)
+ *fqid = fq.fqid;
+ if (cgrid)
+ *cgrid = fqd.cgid;
+ return 0;
+ }
+ }
+ }
+ DPAA_BUS_DEBUG("No FQ left in cgrid(0x%x..0x%x)",
+ cgrid_start, cgrid_start + cgrid_num - 1);
+ return -ERANGE;
+}
diff --git a/drivers/bus/dpaa/dpaa_bus_base_symbols.c b/drivers/bus/dpaa/dpaa_bus_base_symbols.c
index aaa9f9bec2..4da43f293d 100644
--- a/drivers/bus/dpaa/dpaa_bus_base_symbols.c
+++ b/drivers/bus/dpaa/dpaa_bus_base_symbols.c
@@ -57,6 +57,7 @@ RTE_EXPORT_INTERNAL_SYMBOL(qman_reserve_fqid_range)
RTE_EXPORT_INTERNAL_SYMBOL(qman_alloc_pool_range)
RTE_EXPORT_INTERNAL_SYMBOL(qman_alloc_cgrid_range)
RTE_EXPORT_INTERNAL_SYMBOL(qman_release_cgrid_range)
+RTE_EXPORT_INTERNAL_SYMBOL(qman_pending_fq_by_cgrid_range)
RTE_EXPORT_INTERNAL_SYMBOL(dpaa_intr_enable)
RTE_EXPORT_INTERNAL_SYMBOL(dpaa_intr_disable)
RTE_EXPORT_INTERNAL_SYMBOL(dpaa_get_ioctl_version_number)
diff --git a/drivers/bus/dpaa/include/fsl_qman.h b/drivers/bus/dpaa/include/fsl_qman.h
index b2674ce5d0..6d76722275 100644
--- a/drivers/bus/dpaa/include/fsl_qman.h
+++ b/drivers/bus/dpaa/include/fsl_qman.h
@@ -1284,6 +1284,9 @@ struct qman_cgr {
*/
#define QMAN_FQRN_WAIT_MAX 10000000u
+/* Maximum FQID value: frame queue IDs are 24 bits wide. */
+#define QMAN_MAX_FQID 0x00FFFFFFu
+
/* Flags to qman_create_fq() */
#define QMAN_FQ_FLAG_NO_ENQUEUE 0x00000001 /* can't enqueue */
#define QMAN_FQ_FLAG_NO_MODIFY 0x00000002 /* can only enqueue */
@@ -1916,6 +1919,30 @@ static inline int qman_shutdown_fq_by_fqid(u32 fqid)
return qman_shutdown_fq(&fq);
}
+/**
+ * qman_pending_fq_by_cgrid_range - Find an FQ still attached to a CGR range.
+ *
+ * @cgrid_start: first congestion group id of the range to search for.
+ * @cgrid_num: number of consecutive congestion group ids in the range.
+ * @start_fqid: FQID to begin the scan from (0 or 1 means scan from the
+ * start). A caller shutting down several stale FQs can pass the previously
+ * returned FQID + 1 to resume the scan instead of restarting from the
+ * beginning each time.
+ * @fqid: on success, holds the FQID that is still attached to the range.
+ * @cgrid: on success, holds the congestion group id that FQ belongs to.
+ * May be NULL.
+ *
+ * Matching a whole range in one pass lets a caller with many congestion
+ * groups, such as a port releasing all of its Rx or Tx CGRs, avoid one full
+ * FQID space scan per group.
+ *
+ * Return 0 and set *fqid when a matching FQ is found, -ERANGE when none is
+ * left, or a negative error code on query failure.
+ */
+__rte_internal
+int qman_pending_fq_by_cgrid_range(u32 cgrid_start, u32 cgrid_num,
+ u32 start_fqid, u32 *fqid, u32 *cgrid);
+
/**
* qman_reserve_fqid_range - Reserve the specified range of frame queue IDs
* @fqid: the base FQID of the range to deallocate
diff --git a/drivers/net/dpaa/dpaa_ethdev.c b/drivers/net/dpaa/dpaa_ethdev.c
index 456e3df995..3aa4206476 100644
--- a/drivers/net/dpaa/dpaa_ethdev.c
+++ b/drivers/net/dpaa/dpaa_ethdev.c
@@ -105,6 +105,9 @@ dpaa_get_kernel_ifname(const char *node_path, char *name, size_t size)
return ret;
}
+/* Maximum number of stale frame queues cleaned up per congestion group. */
+#define DPAA_CGR_STALE_FQ_MAX 64
+
/* Supported Rx offloads */
static uint64_t dev_rx_offloads_sup =
RTE_ETH_RX_OFFLOAD_SCATTER;
@@ -576,6 +579,44 @@ static int dpaa_eth_dev_stop(struct rte_eth_dev *dev)
return 0;
}
+/* Shut down any frame queue still linked to this CGR.
+ *
+ * A CGR must have no members left when it is deleted. FQs left behind by a
+ * previous run of the application are not owned by this process, so they can
+ * only be found by asking QMan. There may be more than one, hence the loop.
+ */
+static void
+dpaa_cgr_stale_fq_cleanup(struct rte_eth_dev *dev, uint32_t cgrid_start,
+ uint32_t cgrid_num, const char *dir)
+{
+ uint32_t start_fqid = 1;
+ uint32_t fqid, cgrid;
+ uint32_t loop, max_loop;
+ int ret;
+
+ max_loop = cgrid_num * DPAA_CGR_STALE_FQ_MAX;
+ for (loop = 0; loop < max_loop; loop++) {
+ if (qman_pending_fq_by_cgrid_range(cgrid_start, cgrid_num,
+ start_fqid, &fqid, &cgrid))
+ break;
+ /* Should be FQ not cleaned in previous program. */
+ DPAA_PMD_DEBUG("FQ(fqid=0x%x) with %s cgid=%d is still alive?",
+ fqid, dir, cgrid);
+ ret = qman_shutdown_fq_by_fqid(fqid);
+ if (ret) {
+ DPAA_PMD_WARN("%s: Failed(%d) to shutdown %s cgid=%d's fq(fqid=0x%x)",
+ dev->data->name, ret, dir, cgrid, fqid);
+ /* Do not spin on an FQ that refuses to shut down. */
+ break;
+ }
+ /* Resume the scan past the FQ just handled instead of
+ * restarting from the beginning, which would be O(N^2) for
+ * N stale FQs.
+ */
+ start_fqid = fqid + 1;
+ }
+}
+
static int dpaa_eth_dev_close(struct rte_eth_dev *dev)
{
struct fman_if *fif = dev->process_private;
@@ -585,7 +626,7 @@ static int dpaa_eth_dev_close(struct rte_eth_dev *dev)
struct rte_eth_link *link = &dev->data->dev_link;
struct dpaa_if *dpaa_intf = dev->data->dev_private;
struct qman_fq *fq;
- int loop;
+ uint32_t loop;
int ret;
PMD_INIT_FUNC_TRACE();
@@ -660,6 +701,11 @@ static int dpaa_eth_dev_close(struct rte_eth_dev *dev)
/* Release congestion Groups after releasing FQIDs */
/* Release RX congestion Groups */
if (dpaa_intf->cgr_rx) {
+ /* The CGRIDs are a contiguous range, so one scan of the FQID
+ * space covers all of them.
+ */
+ dpaa_cgr_stale_fq_cleanup(dev, dpaa_intf->cgr_rx[0].cgrid,
+ dpaa_intf->nb_rx_queues, "rx");
for (loop = 0; loop < dpaa_intf->nb_rx_queues; loop++) {
ret = qman_delete_cgr(&dpaa_intf->cgr_rx[loop]);
if (ret) {
@@ -667,12 +713,15 @@ static int dpaa_eth_dev_close(struct rte_eth_dev *dev)
dev->data->name, loop, ret);
}
}
+ qman_release_cgrid_range(dpaa_intf->cgr_rx[0].cgrid, dpaa_intf->nb_rx_queues);
rte_free(dpaa_intf->cgr_rx);
dpaa_intf->cgr_rx = NULL;
}
/* Release TX congestion Groups */
if (dpaa_intf->cgr_tx) {
+ dpaa_cgr_stale_fq_cleanup(dev, dpaa_intf->cgr_tx[0].cgrid,
+ MAX_DPAA_CORES, "tx");
for (loop = 0; loop < MAX_DPAA_CORES; loop++) {
ret = qman_delete_cgr(&dpaa_intf->cgr_tx[loop]);
if (ret) {
@@ -680,6 +729,8 @@ static int dpaa_eth_dev_close(struct rte_eth_dev *dev)
dev->data->name, loop, ret);
}
}
+ qman_release_cgrid_range(dpaa_intf->cgr_tx[0].cgrid,
+ MAX_DPAA_CORES);
rte_free(dpaa_intf->cgr_tx);
dpaa_intf->cgr_tx = NULL;
}
@@ -2030,19 +2081,32 @@ static int dpaa_rx_queue_init(struct qman_fq *fq, struct qman_cgr *cgr_rx,
ret = qman_create_cgr(cgr_rx, QMAN_CGR_FLAG_USE_INIT,
&cgr_opts);
if (ret) {
- DPAA_PMD_WARN(
- "rx taildrop init fail on rx fqid 0x%x(ret=%d)",
+ /* Do not fall back to running without the CGR. The
+ * caller counts one CGR per queue it initialised and
+ * deletes cgr_rx[0..n) on its error path, so a queue
+ * without a CGR would make it delete an object that
+ * was never added to the portal list, whose node is
+ * still zeroed from rte_zmalloc().
+ */
+ DPAA_PMD_ERR("rx taildrop init fail on rx fqid 0x%x(ret=%d)",
fq->fqid, ret);
- goto without_cgr;
+ return ret;
}
opts.we_mask |= QM_INITFQ_WE_CGID;
opts.fqd.cgid = cgr_rx->cgrid;
opts.fqd.fq_ctrl |= QM_FQCTRL_CGE;
}
-without_cgr:
+
ret = qman_init_fq(fq, 0, &opts);
- if (ret)
+ if (ret) {
DPAA_PMD_ERR("init rx fqid 0x%x failed with ret:%d", fqid, ret);
+ /* The caller only counts this CGR once this function returns
+ * success, so its error path will not delete it. Unlink it here
+ * or the portal keeps a pointer into memory the caller frees.
+ */
+ if (cgr_rx)
+ qman_delete_cgr(cgr_rx);
+ }
return ret;
}
@@ -2121,10 +2185,12 @@ static int dpaa_tx_queue_init(struct qman_fq *fq,
ret = qman_create_cgr(cgr_tx, QMAN_CGR_FLAG_USE_INIT,
&cgr_opts);
if (ret) {
- DPAA_PMD_WARN(
- "rx taildrop init fail on rx fqid 0x%x(ret=%d)",
+ /* See the equivalent comment in
+ * dpaa_rx_queue_init().
+ */
+ DPAA_PMD_ERR("tx taildrop init fail on tx fqid 0x%x(ret=%d)",
fq->fqid, ret);
- goto without_cgr;
+ return ret;
}
opts.we_mask |= QM_INITFQ_WE_CGID;
opts.fqd.cgid = cgr_tx->cgrid;
@@ -2132,10 +2198,14 @@ static int dpaa_tx_queue_init(struct qman_fq *fq,
DPAA_PMD_DEBUG("Tx FQ tail drop enabled, threshold = %d",
td_tx_threshold);
}
-without_cgr:
+
ret = qman_init_fq(fq, QMAN_INITFQ_FLAG_SCHED, &opts);
- if (ret)
+ if (ret) {
DPAA_PMD_ERR("init tx fqid 0x%x failed %d", fq->fqid, ret);
+ /* See the equivalent comment in dpaa_rx_queue_init(). */
+ if (cgr_tx)
+ qman_delete_cgr(cgr_tx);
+ }
return ret;
}
@@ -2307,6 +2377,8 @@ dpaa_dev_init(struct rte_eth_dev *eth_dev)
int num_rx_fqs, fqid;
int loop, ret = 0;
int dev_id;
+ int nb_rx_cgr = 0, nb_tx_cgr = 0;
+ bool rx_cgrid_allocated = false, tx_cgrid_allocated = false;
struct rte_dpaa_device *dpaa_device;
struct dpaa_if *dpaa_intf;
struct fm_eth_port_cfg *cfg;
@@ -2428,6 +2500,7 @@ dpaa_dev_init(struct rte_eth_dev *eth_dev)
ret = -EINVAL;
goto free_rx;
}
+ rx_cgrid_allocated = true;
} else {
dpaa_intf->cgr_rx = NULL;
}
@@ -2462,6 +2535,8 @@ dpaa_dev_init(struct rte_eth_dev *eth_dev)
fqid);
if (ret)
goto free_rx;
+ if (dpaa_intf->cgr_rx)
+ nb_rx_cgr++;
dpaa_intf->rx_queues[loop].vsp_id = vsp_id;
dpaa_intf->rx_queues[loop].dpaa_intf = dpaa_intf;
}
@@ -2502,11 +2577,11 @@ dpaa_dev_init(struct rte_eth_dev *eth_dev)
ret = -EINVAL;
goto free_tx;
}
+ tx_cgrid_allocated = true;
} else {
dpaa_intf->cgr_tx = NULL;
}
-
for (loop = 0; loop < MAX_DPAA_CORES; loop++) {
if (dpaa_intf->cgr_tx)
dpaa_intf->cgr_tx[loop].cgrid = cgrid_tx[loop];
@@ -2517,6 +2592,8 @@ dpaa_dev_init(struct rte_eth_dev *eth_dev)
dpaa_intf->cgr_tx ? &dpaa_intf->cgr_tx[loop] : NULL);
if (ret)
goto free_tx;
+ if (dpaa_intf->cgr_tx)
+ nb_tx_cgr++;
if (dpaa_intf->ts_enable) {
ret = dpaa_tx_conf_queue_init(&dpaa_intf->tx_conf_queues[loop]);
@@ -2596,6 +2673,15 @@ dpaa_dev_init(struct rte_eth_dev *eth_dev)
return 0;
free_tx:
+ /* Every created Tx CGR was linked into the QMan portal's cgr_cbs
+ * list by qman_create_cgr(). Delete them before freeing cgr_tx so
+ * the portal does not retain dangling pointers into freed memory,
+ * then release the reserved CGRID range.
+ */
+ for (loop = 0; loop < nb_tx_cgr; loop++)
+ qman_delete_cgr(&dpaa_intf->cgr_tx[loop]);
+ if (tx_cgrid_allocated)
+ qman_release_cgrid_range(cgrid_tx[0], MAX_DPAA_CORES);
rte_free(dpaa_intf->tx_conf_queues);
dpaa_intf->tx_conf_queues = NULL;
rte_free(dpaa_intf->tx_queues);
@@ -2603,8 +2689,15 @@ dpaa_dev_init(struct rte_eth_dev *eth_dev)
dpaa_intf->nb_tx_queues = 0;
free_rx:
+ /* Same as above for the Rx CGRs. */
+ for (loop = 0; loop < nb_rx_cgr; loop++)
+ qman_delete_cgr(&dpaa_intf->cgr_rx[loop]);
+ if (rx_cgrid_allocated)
+ qman_release_cgrid_range(cgrid[0], num_rx_fqs);
rte_free(dpaa_intf->cgr_rx);
+ dpaa_intf->cgr_rx = NULL;
rte_free(dpaa_intf->cgr_tx);
+ dpaa_intf->cgr_tx = NULL;
rte_free(dpaa_intf->rx_queues);
dpaa_intf->rx_queues = NULL;
dpaa_intf->nb_rx_queues = 0;
--
2.25.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-10-28 8:52 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-28 8:51 [PATCH v2 0/1] DPAA compilation fix ppc64le and riscv Gagandeep Singh
2026-10-28 8:51 ` [PATCH v2 1/1] bus/dpaa: fix maybe-uninitialized in bman_release_fast Gagandeep Singh
2026-10-28 8:51 ` [PATCH 1/3] drivers: add offline (O/H) port device support Gagandeep Singh
2026-10-28 8:51 ` [PATCH 2/3] net/dpaa: support non fmX-macY type of shared Ethernet name Gagandeep Singh
2026-10-28 8:51 ` [PATCH 3/3] drivers: add DPAA cgrid cleanup support Gagandeep Singh
-- strict thread matches above, loose matches on Subject: below --
2026-10-27 6:15 [PATCH] bus/dpaa: fix maybe-uninitialized in bman_release_fast Gagandeep Singh
2026-10-27 6:31 ` [PATCH v2 0/1] DPAA compilation fix ppc64le and riscv Gagandeep Singh
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox