From: Gagandeep Singh <[email protected]>

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 <[email protected]>
Signed-off-by: Hemant Agrawal <[email protected]>
---
 doc/guides/nics/dpaa.rst              |  12 +
 drivers/bus/dpaa/bus_dpaa_driver.h    |  11 +-
 drivers/bus/dpaa/dpaa_bus.c           |  87 +++-
 drivers/net/dpaa/dpaa_ethdev.h        |   3 +
 drivers/net/dpaa/dpaa_oldev.c         | 701 ++++++++++++++++++++++++++
 drivers/net/dpaa/meson.build          |  11 +-
 drivers/net/dpaa/rte_pmd_dpaa_oldev.h |  92 ++++
 7 files changed, 905 insertions(+), 12 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/guides/nics/dpaa.rst b/doc/guides/nics/dpaa.rst
index d4b683ba24..d11a30ca2e 100644
--- a/doc/guides/nics/dpaa.rst
+++ b/doc/guides/nics/dpaa.rst
@@ -296,6 +296,18 @@ the ``-a`` EAL option (e.g. ``-a 
dpaa_bus:fm1-mac3,drv_rx_taildrop=64``):
   Provide the kernel Linux interface name for a shared MAC interface when it
   differs from the ``fmX-macY`` style name used by DPDK.
 
+* ``drv_bh_port``
+
+  Name of the back-half port associated with an offline (O/H) port device.
+
+The following bus-level device arguments configure the DPAA bus itself and
+are passed through the EAL bus arguments (e.g. ``--vdev`` / ``-a`` bus
+options, ``bus=dpaa,drv_oldev=1``):
+
+* ``drv_oldev`` (default disabled)
+
+  Enable the DPAA offline (O/H) port device.
+
 FMAN Config
 -----------
 
diff --git a/drivers/bus/dpaa/bus_dpaa_driver.h 
b/drivers/bus/dpaa/bus_dpaa_driver.h
index 4aed83f84d..f58aa47357 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 */
 };
@@ -216,6 +218,13 @@ int rte_dpaa_portal_fq_init(void *arg, struct qman_fq *fq);
 __rte_internal
 int rte_dpaa_portal_fq_close(struct qman_fq *fq);
 
+/**
+ * Return non-zero if the DPAA offline (O/H) port device is enabled through
+ * the "drv_oldev" bus device argument.
+ */
+__rte_internal
+int rte_dpaa_bus_oldev_enabled(void);
+
 /**
  * Cleanup a DPAA Portal
  */
diff --git a/drivers/bus/dpaa/dpaa_bus.c b/drivers/bus/dpaa/dpaa_bus.c
index fe1003a1d9..16892b5247 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,42 @@ 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. "bus=dpaa,drv_oldev=1") and cache the resulting flags
+ * in the bus private structure. Replaces the previous environment-variable
+ * based configuration.
+ */
+static int
+dpaa_bus_parse_bus_args(void)
+{
+       struct rte_devargs *devargs;
+       struct rte_kvargs *kvlist;
+
+       RTE_EAL_DEVARGS_FOREACH("dpaa", devargs) {
+               if (devargs->bus_str == NULL)
+                       continue;
+
+               kvlist = rte_kvargs_parse(devargs->bus_str, NULL);
+               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(rte_dpaa_bus_oldev_enabled)
+int
+rte_dpaa_bus_oldev_enabled(void)
+{
+       return dpaa_bus.oldev_enabled;
+}
+
 RTE_EXPORT_INTERNAL_SYMBOL(per_lcore_dpaa_io)
 RTE_DEFINE_PER_LCORE(struct dpaa_portal *, dpaa_io);
 
@@ -209,6 +251,31 @@ 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;
+
+               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));
@@ -619,7 +686,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;
@@ -627,17 +694,20 @@ rte_dpaa_bus_dev_build(void)
 
        DPAA_BUS_LOG(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);
@@ -690,6 +760,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/net/dpaa/dpaa_ethdev.h b/drivers/net/dpaa/dpaa_ethdev.h
index d3e005b556..8d366830eb 100644
--- a/drivers/net/dpaa/dpaa_ethdev.h
+++ b/drivers/net/dpaa/dpaa_ethdev.h
@@ -116,6 +116,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_oldev.c b/drivers/net/dpaa/dpaa_oldev.c
new file mode 100644
index 0000000000..efe8322fd8
--- /dev/null
+++ b/drivers/net/dpaa/dpaa_oldev.c
@@ -0,0 +1,701 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2020-2026 NXP
+ */
+
+#include <stdio.h>
+#include <sys/ioctl.h>
+
+#include <rte_dpaa_logs.h>
+#include <rte_kvargs.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
+
+static int 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)
+
+
+static int check_fd(void)
+{
+       int ret;
+
+       if (fd >= 0)
+               return 0;
+       ret = pthread_mutex_lock(&fd_init_lock);
+       assert(!ret);
+       /* check again with the lock held */
+       if (fd < 0)
+               fd = open(ASK_PATH, O_RDWR);
+       ret = pthread_mutex_unlock(&fd_init_lock);
+       assert(!ret);
+       return (fd >= 0) ? 0 : -ENODEV;
+}
+
+static uint32_t ask_get_channel_info(struct ask_ctrl_offline_channel *ch_info)
+{
+       int ret = check_fd();
+       if (ret)
+               return ret;
+
+       ret = ioctl(fd, ASK_CTRL_GET_OFFLINE_CHANNEL_INFO, ch_info);
+       if (!ret) {
+               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);
+       } else {
+               DPAA_PMD_ERR("Get channel info ioctl failed with errno: %s",
+                            strerror(errno));
+       }
+
+       return ret;
+}
+
+static int ask_set_fq_info(struct ask_ctrl_dpdk_fq_info_s *fq_info)
+{
+       int ret = check_fd();
+       if (ret)
+               return ret;
+
+       ret = ioctl(fd, ASK_CTRL_SET_DPDK_INFO, fq_info);
+       if (!ret) {
+               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);
+       } else {
+               DPAA_PMD_ERR("Set FQ info ioctl failed with errno: %s",
+                            strerror(errno));
+       }
+
+       return ret;
+}
+
+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, 25.11)
+int rte_pmd_dpaa_ol_set_classif_info(struct rte_pmd_dpaa_uplink_cls_info_s 
*classif_info)
+{
+       int i, ret = check_fd();
+       if (ret)
+               return ret;
+
+       if (classif_info == NULL) {
+               DPAA_PMD_ERR("No classification data available");
+               return -1;
+       }
+
+       ret = ioctl(fd, ASK_CTRL_SET_CLASSIF_INFO, classif_info);
+       if (!ret) {
+               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);
+       } else {
+               DPAA_PMD_ERR("Set classification info ioctl failed with errno: 
%s",
+                            strerror(errno));
+       }
+
+       return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_dpaa_ol_reset_classif_info, 25.11)
+int rte_pmd_dpaa_ol_reset_classif_info(void)
+{
+       struct rte_pmd_dpaa_uplink_cls_info_s classif_info;
+       int ret = 0;
+
+       memset(&classif_info, 0, sizeof(classif_info));
+       ret = check_fd();
+       if (ret)
+               return ret;
+
+       ret = ioctl(fd, ASK_CTRL_RESET_CLASSIF_INFO, &classif_info);
+       if (ret) {
+               DPAA_PMD_ERR("Reset classification info ioctl failed with 
errno: %s",
+                            strerror(errno));
+       } else {
+               DPAA_PMD_DEBUG("Reset classification info successful");
+       }
+
+       return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_dpaa_ol_set_lgw_info, 25.11)
+int rte_pmd_dpaa_ol_set_lgw_info(struct rte_pmd_dpaa_lgw_info_s *lgw_info)
+{
+       int ret = check_fd();
+       if (ret)
+               return ret;
+
+       if (lgw_info == NULL) {
+               DPAA_PMD_ERR("No LGW data available");
+               return -1;
+       }
+       ret = ioctl(fd, ASK_CTRL_SET_LGW_INFO, lgw_info);
+       if (!ret) {
+               DPAA_PMD_DEBUG("Set LGW info successful");
+       } else {
+               DPAA_PMD_ERR("Set LGW info ioctl failed with errno: %s",
+                            strerror(errno));
+       }
+
+       return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_dpaa_ol_reset_lgw_info, 25.11)
+int rte_pmd_dpaa_ol_reset_lgw_info(void)
+{
+       struct rte_pmd_dpaa_lgw_info_s lgw_info;
+       int ret = 0;
+
+       PMD_INIT_FUNC_TRACE();
+
+       memset(&lgw_info, 0, sizeof(lgw_info));
+       ret = check_fd();
+       if (ret)
+               return ret;
+
+       ret = ioctl(fd, ASK_CTRL_RESET_LGW_INFO, &lgw_info);
+       if (ret) {
+               DPAA_PMD_ERR("Reset LGW info ioctl failed with errno: %s",
+                            strerror(errno));
+       } else {
+               DPAA_PMD_DEBUG("Reset LGW info successful");
+       }
+
+       return ret;
+}
+
+static int dpaa_ol_dev_start(struct rte_eth_dev *dev)
+{
+       PMD_INIT_FUNC_TRACE();
+
+       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 int dpaa_ol_dev_close(__rte_unused struct rte_eth_dev *dev)
+{
+       PMD_INIT_FUNC_TRACE();
+
+       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;
+
+       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];
+       struct qman_fq *rxq = &dpaa_intf->rx_queues[queue_idx];
+       struct ask_ctrl_dpdk_fq_info_s fq_info;
+       int ret;
+       struct rte_pktmbuf_pool_private *mbp_priv;
+
+       PMD_INIT_FUNC_TRACE();
+
+       dev->data->tx_queues[queue_idx] = txq;
+
+       if (dpaa_intf->bp_info == NULL || rxq == NULL)
+               return 0;
+
+       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;
+
+/* 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
+
+       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",
+                            DRIVER_OL_BH_PORT);
+               return -1;
+       }
+
+       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();
+
+       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;
+
+#define DPA_ISC_WQ_ID 2
+       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 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 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;
+       }
+
+       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->nb_rx_queues = num_fqs;
+
+       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;
+       }
+
+       ret = dpaa_ol_tx_queue_init(&dpaa_intf->tx_queues[0], 0);
+       if (ret)
+               goto free_tx;
+
+       dpaa_intf->nb_tx_queues = num_fqs;
+
+       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_tx;
+       }
+
+       return 0;
+
+free_tx:
+       rte_free(dpaa_intf->tx_queues);
+       dpaa_intf->tx_queues = NULL;
+       dpaa_intf->nb_tx_queues = 0;
+free_rx:
+       rte_free(dpaa_intf->rx_queues);
+       dpaa_intf->rx_queues = NULL;
+       dpaa_intf->nb_rx_queues = 0;
+       return ret;
+}
+
+static int rte_dpaa_probe(__rte_unused struct rte_dpaa_driver *dpaa_drv,
+                         __rte_unused struct rte_dpaa_device *dpaa_dev)
+{
+       int ret;
+       struct rte_eth_dev *eth_dev;
+
+       PMD_INIT_FUNC_TRACE();
+
+       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;
+       }
+
+       rte_eth_dev_release_port(eth_dev);
+       return ret;
+}
+
+static int rte_dpaa_remove(__rte_unused struct rte_dpaa_device *dpaa_dev)
+{
+       PMD_INIT_FUNC_TRACE();
+
+       return 0;
+}
+
+static struct rte_dpaa_driver rte_dpaa_ol_pmd = {
+               .drv_type = FSL_DPAA_OL,
+               .probe = rte_dpaa_probe,
+               .remove = rte_dpaa_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..d3ae02946b 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-2021 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..6ba61b77b9
--- /dev/null
+++ b/drivers/net/dpaa/rte_pmd_dpaa_oldev.h
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2020-2026 NXP
+ */
+
+#ifndef _RTE_PMD_DPAA_OLDEV_H
+#define _RTE_PMD_DPAA_OLDEV_H
+
+
+#include <stdint.h>
+#include <rte_compat.h>
+
+#define DPA_ISC_IPV4_ADDR_TYPE  0x04
+#define DPA_ISC_IPV6_ADDR_TYPE  0x06
+#define MAX_NUM_PORTS 2
+
+#define DPA_ISC_IPV4_SUBNET_TYPE  0x04
+#define DPA_ISC_IPV6_SUBNET_TYPE  0x06
+#define 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
+
+
+struct ip_addr_s {
+       uint32_t        ip_addr[4];
+};
+
+struct __rte_packed_begin ip_pair_s {
+       struct 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 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 ip_pair_s        addr_pair;
+       uint16_t        gtp_udp_port[MAX_NUM_PORTS]; /* DPDK app listens on 
this GTP 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 lgw_subnet_s subnets[MAX_NUM_SUBNETS];
+       uint8_t         num_subnets;
+       uint8_t         pad[3];
+} __rte_packed_end;
+
+__rte_experimental
+int rte_pmd_dpaa_ol_set_classif_info(struct rte_pmd_dpaa_uplink_cls_info_s 
*cls_info);
+
+__rte_experimental
+int rte_pmd_dpaa_ol_reset_classif_info(void);
+
+__rte_experimental
+int rte_pmd_dpaa_ol_set_lgw_info(struct rte_pmd_dpaa_lgw_info_s *lgw_info);
+
+__rte_experimental
+int rte_pmd_dpaa_ol_reset_lgw_info(void);
+
+#endif
-- 
2.25.1

Reply via email to