Add queue initialization and release interface.

Signed-off-by: Yong Zhang <zhang.yong25@zte.com.cn>
---
 drivers/raw/gdtc/gdtc_rawdev.c | 244 +++++++++++++++++++++++++++++++++
 drivers/raw/gdtc/gdtc_rawdev.h |  19 +++
 2 files changed, 263 insertions(+)

diff --git a/drivers/raw/gdtc/gdtc_rawdev.c b/drivers/raw/gdtc/gdtc_rawdev.c
index 6f20ecdad6..c3e59fcdab 100644
--- a/drivers/raw/gdtc/gdtc_rawdev.c
+++ b/drivers/raw/gdtc/gdtc_rawdev.c
@@ -28,10 +28,42 @@
 
 #include "gdtc_rawdev.h"
 
+/*
+ * User define:
+ * ep_id-bit[15:12] vfunc_num-bit[11:4] func_num-bit[3:1] vfunc_active-bit0
+ * host ep_id:5~8   zf ep_id:9
+ */
+#define ZXDH_GDMA_ZF_USER                       0x9000      /* ep4 pf0 */
+#define ZXDH_GDMA_PF_NUM_SHIFT                  1
+#define ZXDH_GDMA_VF_NUM_SHIFT                  4
+#define ZXDH_GDMA_EP_ID_SHIFT                   12
+#define ZXDH_GDMA_VF_EN                         1
+#define ZXDH_GDMA_EPID_OFFSET                   5
+
 /* Register offset */
 #define ZXDH_GDMA_BASE_OFFSET                   0x100000
+#define ZXDH_GDMA_EXT_ADDR_OFFSET               0x218
+#define ZXDH_GDMA_CONTROL_OFFSET                0x230
+#define ZXDH_GDMA_TC_CNT_OFFSET                 0x23c
+#define ZXDH_GDMA_LLI_USER_OFFSET               0x228
+
+#define ZXDH_GDMA_CHAN_FORCE_CLOSE              (1 << 31)
+
+/* TC count & Error interrupt status register */
+#define ZXDH_GDMA_SRC_LLI_ERR                   (1 << 16)
+#define ZXDH_GDMA_SRC_DATA_ERR                  (1 << 17)
+#define ZXDH_GDMA_DST_ADDR_ERR                  (1 << 18)
+#define ZXDH_GDMA_ERR_STATUS                    (1 << 19)
+#define ZXDH_GDMA_ERR_INTR_ENABLE               (1 << 20)
+#define ZXDH_GDMA_TC_CNT_CLEAN                  (1)
 
 #define ZXDH_GDMA_CHAN_SHIFT                    0x80
+#define LOW32_MASK                              0xffffffff
+#define LOW16_MASK                              0xffff
+
+static int zxdh_gdma_queue_init(struct rte_rawdev *dev, uint16_t queue_id);
+static int zxdh_gdma_queue_free(struct rte_rawdev *dev, uint16_t queue_id);
+
 char zxdh_gdma_driver_name[] = "rawdev_zxdh_gdma";
 char dev_name[] = "zxdh_gdma";
 
@@ -41,9 +73,221 @@ zxdh_gdma_rawdev_get_priv(const struct rte_rawdev *rawdev)
     return rawdev->dev_private;
 }
 
+static inline struct zxdh_gdma_queue *
+zxdh_gdma_get_queue(struct rte_rawdev *dev, uint16_t queue_id)
+{
+    struct zxdh_gdma_rawdev *gdmadev = zxdh_gdma_rawdev_get_priv(dev);
+
+    if (queue_id >= ZXDH_GDMA_TOTAL_CHAN_NUM) {
+        ZXDH_PMD_LOG(ERR, "queue id %d is invalid", queue_id);
+        return NULL;
+    }
+
+    return &(gdmadev->vqs[queue_id]);
+}
+
+static void
+zxdh_gdma_write_reg(struct rte_rawdev *dev, uint16_t queue_id, uint32_t offset, uint32_t val)
+{
+    struct zxdh_gdma_rawdev *gdmadev = zxdh_gdma_rawdev_get_priv(dev);
+    uint32_t addr = 0;
+
+    addr = offset + queue_id * ZXDH_GDMA_CHAN_SHIFT;
+    *(uint32_t *)(gdmadev->base_addr + addr) = val;
+}
+
+static int
+zxdh_gdma_rawdev_queue_setup(struct rte_rawdev *dev,
+                uint16_t queue_id,
+                rte_rawdev_obj_t queue_conf,
+                size_t conf_size)
+{
+    struct zxdh_gdma_rawdev *gdmadev = NULL;
+    struct zxdh_gdma_queue *queue = NULL;
+    struct zxdh_gdma_queue_config *qconfig = NULL;
+    struct zxdh_gdma_rbp *rbp = NULL;
+    uint16_t i = 0;
+    uint8_t is_txq = 0;
+    uint32_t src_user = 0;
+    uint32_t dst_user = 0;
+
+    if (dev == NULL)
+        return -EINVAL;
+
+    if ((queue_conf == NULL) || (conf_size != sizeof(struct zxdh_gdma_queue_config)))
+        return -EINVAL;
+
+    gdmadev = zxdh_gdma_rawdev_get_priv(dev);
+    qconfig = (struct zxdh_gdma_queue_config *)queue_conf;
+
+    for (i = 0; i < ZXDH_GDMA_TOTAL_CHAN_NUM; i++) {
+        if (gdmadev->vqs[i].enable == 0)
+            break;
+    }
+    if (i >= ZXDH_GDMA_TOTAL_CHAN_NUM) {
+        ZXDH_PMD_LOG(ERR, "Failed to setup queue, no avail queues");
+        return -1;
+    }
+    queue_id = i;
+    if (zxdh_gdma_queue_init(dev, queue_id) != 0) {
+        ZXDH_PMD_LOG(ERR, "Failed to init queue");
+        return -1;
+    }
+    queue = &(gdmadev->vqs[queue_id]);
+
+    rbp = qconfig->rbp;
+    if ((rbp->srbp != 0) && (rbp->drbp == 0)) {
+        is_txq = 0;
+        dst_user = ZXDH_GDMA_ZF_USER;
+        src_user = ((rbp->spfid << ZXDH_GDMA_PF_NUM_SHIFT) |
+            ((rbp->sportid + ZXDH_GDMA_EPID_OFFSET) << ZXDH_GDMA_EP_ID_SHIFT));
+
+        if (rbp->svfid != 0)
+            src_user |= (ZXDH_GDMA_VF_EN |
+                         ((rbp->svfid - 1) << ZXDH_GDMA_VF_NUM_SHIFT));
+
+        ZXDH_PMD_LOG(DEBUG, "rxq->qidx:%d setup src_user(ep:%d pf:%d vf:%d) success",
+                    queue_id, (uint8_t)rbp->sportid, (uint8_t)rbp->spfid,
+                    (uint8_t)rbp->svfid);
+    } else if ((rbp->srbp == 0) && (rbp->drbp != 0)) {
+        is_txq = 1;
+        src_user = ZXDH_GDMA_ZF_USER;
+        dst_user = ((rbp->dpfid << ZXDH_GDMA_PF_NUM_SHIFT) |
+            ((rbp->dportid + ZXDH_GDMA_EPID_OFFSET) << ZXDH_GDMA_EP_ID_SHIFT));
+
+        if (rbp->dvfid != 0)
+            dst_user |= (ZXDH_GDMA_VF_EN |
+                         ((rbp->dvfid - 1) << ZXDH_GDMA_VF_NUM_SHIFT));
+
+        ZXDH_PMD_LOG(DEBUG, "txq->qidx:%d setup dst_user(ep:%d pf:%d vf:%d) success",
+                    queue_id, (uint8_t)rbp->dportid, (uint8_t)rbp->dpfid,
+                    (uint8_t)rbp->dvfid);
+    } else {
+        ZXDH_PMD_LOG(ERR, "Failed to setup queue, srbp/drbp is invalid");
+        return -EINVAL;
+    }
+    queue->is_txq = is_txq;
+
+    /* setup queue user info */
+    queue->user = (src_user & LOW16_MASK) | (dst_user << 16);
+
+    zxdh_gdma_write_reg(dev, queue_id, ZXDH_GDMA_EXT_ADDR_OFFSET, queue->user);
+    gdmadev->used_num++;
+
+    return queue_id;
+}
+
 static const struct rte_rawdev_ops zxdh_gdma_rawdev_ops = {
+    .queue_setup = zxdh_gdma_rawdev_queue_setup,
 };
 
+static int
+zxdh_gdma_queue_init(struct rte_rawdev *dev, uint16_t queue_id)
+{
+    char name[RTE_MEMZONE_NAMESIZE];
+    struct zxdh_gdma_queue *queue = NULL;
+    const struct rte_memzone *mz = NULL;
+    uint32_t size = 0;
+    int ret = 0;
+
+    queue = zxdh_gdma_get_queue(dev, queue_id);
+    if (queue == NULL)
+        return -EINVAL;
+
+    queue->enable = 1;
+    queue->vq_id  = queue_id;
+    queue->flag   = 0;
+    queue->tc_cnt = 0;
+
+    /* Init sw_ring */
+    queue->sw_ring.job = rte_calloc(NULL, queue->queue_size, sizeof(struct zxdh_gdma_job *), 0);
+    if (queue->sw_ring.job == NULL) {
+        ZXDH_PMD_LOG(ERR, "can not allocate sw_ring");
+        ret = -ENOMEM;
+        goto free_queue;
+    }
+
+    /* Cache up to size-1 job in the ring to prevent overwriting hardware prefetching */
+    queue->sw_ring.free_cnt = queue->queue_size - 1;
+    queue->sw_ring.deq_cnt  = 0;
+    queue->sw_ring.pend_cnt = 0;
+    queue->sw_ring.enq_idx  = 0;
+    queue->sw_ring.deq_idx  = 0;
+    queue->sw_ring.used_idx = 0;
+
+    /* Init ring */
+    snprintf(name, RTE_MEMZONE_NAMESIZE, "gdma_vq%d_ring", queue_id);
+    size = ZXDH_GDMA_RING_SIZE * sizeof(struct zxdh_gdma_buff_desc);
+    mz = rte_memzone_reserve_aligned(name, size, rte_socket_id(),
+                            RTE_MEMZONE_IOVA_CONTIG, size);
+    if (mz == NULL) {
+        if (rte_errno == EEXIST)
+            mz = rte_memzone_lookup(name);
+        if (mz == NULL) {
+            ZXDH_PMD_LOG(ERR, "can not allocate ring %s", name);
+            ret = -ENOMEM;
+            goto free_queue;
+        }
+    }
+    memset(mz->addr, 0, size);
+    queue->ring.ring_mz   = mz;
+    queue->ring.desc      = (struct zxdh_gdma_buff_desc *)(mz->addr);
+    queue->ring.ring_mem  = mz->iova;
+    queue->ring.avail_idx = 0;
+    ZXDH_PMD_LOG(INFO, "queue%u ring phy addr:0x%"PRIx64" virt addr:%p",
+                        queue_id, mz->iova, mz->addr);
+
+    /* Initialize the hardware channel */
+    zxdh_gdma_write_reg(dev, queue_id, ZXDH_GDMA_CONTROL_OFFSET,
+        ZXDH_GDMA_CHAN_FORCE_CLOSE);
+    zxdh_gdma_write_reg(dev, queue_id, ZXDH_GDMA_TC_CNT_OFFSET,
+        ZXDH_GDMA_ERR_INTR_ENABLE | ZXDH_GDMA_ERR_STATUS | ZXDH_GDMA_TC_CNT_CLEAN);
+    zxdh_gdma_write_reg(dev, queue_id, ZXDH_GDMA_LLI_USER_OFFSET,
+        ZXDH_GDMA_ZF_USER);
+
+    return 0;
+
+free_queue:
+    zxdh_gdma_queue_free(dev, queue_id);
+    return ret;
+}
+
+static int
+zxdh_gdma_queue_free(struct rte_rawdev *dev, uint16_t queue_id)
+{
+    struct zxdh_gdma_rawdev *gdmadev = NULL;
+    struct zxdh_gdma_queue *queue = NULL;
+    uint32_t val = 0;
+
+    queue = zxdh_gdma_get_queue(dev, queue_id);
+    if (queue == NULL)
+        return -EINVAL;
+
+    gdmadev = zxdh_gdma_rawdev_get_priv(dev);
+    gdmadev->used_num--;
+
+    /* disable gdma channel */
+    val = ZXDH_GDMA_CHAN_FORCE_CLOSE;
+    zxdh_gdma_write_reg(dev, queue_id, ZXDH_GDMA_CONTROL_OFFSET, val);
+
+    queue->enable           = 0;
+    queue->is_txq           = 0;
+    queue->flag             = 0;
+    queue->user             = 0;
+    queue->tc_cnt           = 0;
+    queue->ring.avail_idx   = 0;
+    queue->sw_ring.free_cnt = 0;
+    queue->sw_ring.deq_cnt  = 0;
+    queue->sw_ring.pend_cnt = 0;
+    queue->sw_ring.enq_idx  = 0;
+    queue->sw_ring.deq_idx  = 0;
+    queue->sw_ring.used_idx = 0;
+    rte_free(queue->sw_ring.job);
+    rte_memzone_free(queue->ring.ring_mz);
+
+    return 0;
+}
+
 static int
 zxdh_gdma_map_resource(struct rte_pci_device *dev)
 {
diff --git a/drivers/raw/gdtc/gdtc_rawdev.h b/drivers/raw/gdtc/gdtc_rawdev.h
index 9f943c49c6..29b169d079 100644
--- a/drivers/raw/gdtc/gdtc_rawdev.h
+++ b/drivers/raw/gdtc/gdtc_rawdev.h
@@ -100,4 +100,23 @@ struct zxdh_gdma_rawdev {
     struct zxdh_gdma_queue vqs[ZXDH_GDMA_TOTAL_CHAN_NUM];
 };
 
+struct zxdh_gdma_rbp {
+    uint32_t use_ultrashort:1;
+    uint32_t enable:1;
+    uint32_t dportid:3;
+    uint32_t dpfid:3;
+    uint32_t dvfid:8; /*using route by port for destination */
+    uint32_t drbp:1;
+    uint32_t sportid:3;
+    uint32_t spfid:3;
+    uint32_t svfid:8;
+    uint32_t srbp:1;
+};
+
+struct zxdh_gdma_queue_config {
+    uint32_t lcore_id;
+    uint32_t flags;
+    struct zxdh_gdma_rbp *rbp;
+};
+
 #endif /* __GDTC_RAWDEV_H__ */
-- 
2.43.0