From: Chengwen Feng <fengchengwen@huawei.com>
To: <thomas@monjalon.net>
Cc: <dev@dpdk.org>
Subject: [dpdk-dev] [PATCH 2/6] dma/hisilicon: add dmadev instances create and destroy
Date: Sat, 30 Oct 2021 18:36:15 +0800 [thread overview]
Message-ID: <20211030103619.29924-3-fengchengwen@huawei.com> (raw)
In-Reply-To: <20211030103619.29924-1-fengchengwen@huawei.com>
This patch add dmadev instances create during the PCI probe, and
destroy them during the PCI remove. Internal structures and HW
definitions was also included.
Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
doc/guides/dmadevs/hisilicon.rst | 10 ++
drivers/dma/hisilicon/hisi_dmadev.c | 212 +++++++++++++++++++++++++++-
drivers/dma/hisilicon/hisi_dmadev.h | 97 +++++++++++++
3 files changed, 318 insertions(+), 1 deletion(-)
diff --git a/doc/guides/dmadevs/hisilicon.rst b/doc/guides/dmadevs/hisilicon.rst
index 4cbaac4204..65138a8365 100644
--- a/doc/guides/dmadevs/hisilicon.rst
+++ b/doc/guides/dmadevs/hisilicon.rst
@@ -19,3 +19,13 @@ Device Setup
Kunpeng DMA devices will need to be bound to a suitable DPDK-supported
user-space IO driver such as ``vfio-pci`` in order to be used by DPDK.
+
+Device Probing and Initialization
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Once probed successfully, the device will appear as four ``dmadev`` which can be
+accessed using API from the ``rte_dmadev`` library.
+
+The name of the ``dmadev`` created is like "B:D.F-chX", e.g. DMA 0000:7b:00.0
+will create four ``dmadev``, the 1st ``dmadev`` name is "7b:00.0-ch0", and the
+2nd ``dmadev`` name is "7b:00.0-ch1".
diff --git a/drivers/dma/hisilicon/hisi_dmadev.c b/drivers/dma/hisilicon/hisi_dmadev.c
index e6fb8a0fc8..b8369e7e71 100644
--- a/drivers/dma/hisilicon/hisi_dmadev.c
+++ b/drivers/dma/hisilicon/hisi_dmadev.c
@@ -6,7 +6,9 @@
#include <string.h>
#include <rte_bus_pci.h>
+#include <rte_cycles.h>
#include <rte_eal.h>
+#include <rte_io.h>
#include <rte_log.h>
#include <rte_pci.h>
#include <rte_dmadev_pmd.h>
@@ -30,6 +32,141 @@ RTE_LOG_REGISTER_DEFAULT(hisi_dma_logtype, INFO);
#define HISI_DMA_ERR(hw, fmt, args...) \
HISI_DMA_LOG_RAW(hw, ERR, fmt, ## args)
+static uint32_t
+hisi_dma_queue_base(struct hisi_dma_dev *hw)
+{
+ if (hw->reg_layout == HISI_DMA_REG_LAYOUT_HIP08)
+ return HISI_DMA_HIP08_QUEUE_BASE;
+ else
+ return 0;
+}
+
+static void
+hisi_dma_write_reg(void *base, uint32_t off, uint32_t val)
+{
+ rte_write32(rte_cpu_to_le_32(val),
+ (volatile void *)((char *)base + off));
+}
+
+static void
+hisi_dma_write_dev(struct hisi_dma_dev *hw, uint32_t off, uint32_t val)
+{
+ hisi_dma_write_reg(hw->io_base, off, val);
+}
+
+static void
+hisi_dma_write_queue(struct hisi_dma_dev *hw, uint32_t qoff, uint32_t val)
+{
+ uint32_t off = hisi_dma_queue_base(hw) +
+ hw->queue_id * HISI_DMA_QUEUE_REGION_SIZE + qoff;
+ hisi_dma_write_dev(hw, off, val);
+}
+
+static uint32_t
+hisi_dma_read_reg(void *base, uint32_t off)
+{
+ uint32_t val = rte_read32((volatile void *)((char *)base + off));
+ return rte_le_to_cpu_32(val);
+}
+
+static uint32_t
+hisi_dma_read_dev(struct hisi_dma_dev *hw, uint32_t off)
+{
+ return hisi_dma_read_reg(hw->io_base, off);
+}
+
+static uint32_t
+hisi_dma_read_queue(struct hisi_dma_dev *hw, uint32_t qoff)
+{
+ uint32_t off = hisi_dma_queue_base(hw) +
+ hw->queue_id * HISI_DMA_QUEUE_REGION_SIZE + qoff;
+ return hisi_dma_read_dev(hw, off);
+}
+
+static void
+hisi_dma_update_bit(struct hisi_dma_dev *hw, uint32_t off, uint32_t pos,
+ bool set)
+{
+ uint32_t tmp = hisi_dma_read_dev(hw, off);
+ uint32_t mask = 1u << pos;
+ tmp = set ? tmp | mask : tmp & ~mask;
+ hisi_dma_write_dev(hw, off, tmp);
+}
+
+static void
+hisi_dma_update_queue_bit(struct hisi_dma_dev *hw, uint32_t qoff, uint32_t pos,
+ bool set)
+{
+ uint32_t tmp = hisi_dma_read_queue(hw, qoff);
+ uint32_t mask = 1u << pos;
+ tmp = set ? tmp | mask : tmp & ~mask;
+ hisi_dma_write_queue(hw, qoff, tmp);
+}
+
+#define hisi_dma_poll_hw_state(hw, val, cond, sleep_us, timeout_us) ({ \
+ uint32_t timeout = 0; \
+ while (timeout++ <= (timeout_us)) { \
+ (val) = hisi_dma_read_queue(hw, HISI_DMA_QUEUE_FSM_REG); \
+ if (cond) \
+ break; \
+ rte_delay_us(sleep_us); \
+ } \
+ (cond) ? 0 : -ETIME; \
+})
+
+static int
+hisi_dma_reset_hw(struct hisi_dma_dev *hw)
+{
+#define POLL_SLEEP_US 100
+#define POLL_TIMEOUT_US 10000
+
+ uint32_t tmp;
+ int ret;
+
+ hisi_dma_update_queue_bit(hw, HISI_DMA_QUEUE_CTRL0_REG,
+ HISI_DMA_QUEUE_CTRL0_PAUSE_B, true);
+ hisi_dma_update_queue_bit(hw, HISI_DMA_QUEUE_CTRL0_REG,
+ HISI_DMA_QUEUE_CTRL0_EN_B, false);
+
+ ret = hisi_dma_poll_hw_state(hw, tmp,
+ FIELD_GET(HISI_DMA_QUEUE_FSM_STS_M, tmp) != HISI_DMA_STATE_RUN,
+ POLL_SLEEP_US, POLL_TIMEOUT_US);
+ if (ret) {
+ HISI_DMA_ERR(hw, "disable dma timeout!");
+ return ret;
+ }
+
+ hisi_dma_update_queue_bit(hw, HISI_DMA_QUEUE_CTRL1_REG,
+ HISI_DMA_QUEUE_CTRL1_RESET_B, true);
+ hisi_dma_write_queue(hw, HISI_DMA_QUEUE_SQ_TAIL_REG, 0);
+ hisi_dma_write_queue(hw, HISI_DMA_QUEUE_CQ_HEAD_REG, 0);
+ hisi_dma_update_queue_bit(hw, HISI_DMA_QUEUE_CTRL0_REG,
+ HISI_DMA_QUEUE_CTRL0_PAUSE_B, false);
+
+ ret = hisi_dma_poll_hw_state(hw, tmp,
+ FIELD_GET(HISI_DMA_QUEUE_FSM_STS_M, tmp) == HISI_DMA_STATE_IDLE,
+ POLL_SLEEP_US, POLL_TIMEOUT_US);
+ if (ret) {
+ HISI_DMA_ERR(hw, "reset dma timeout!");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void
+hisi_dma_init_gbl(void *pci_bar, uint8_t revision)
+{
+ struct hisi_dma_dev hw;
+
+ memset(&hw, 0, sizeof(hw));
+ hw.io_base = pci_bar;
+
+ if (revision == HISI_DMA_REVISION_HIP08B)
+ hisi_dma_update_bit(&hw, HISI_DMA_HIP08_MODE_REG,
+ HISI_DMA_HIP08_MODE_SEL_B, true);
+}
+
static uint8_t
hisi_dma_reg_layout(uint8_t revision)
{
@@ -49,6 +186,57 @@ hisi_dma_gen_pci_device_name(const struct rte_pci_device *pci_dev,
pci_dev->addr.function);
}
+static void
+hisi_dma_gen_dev_name(const struct rte_pci_device *pci_dev,
+ uint8_t queue_id, char *name, size_t size)
+{
+ memset(name, 0, size);
+ (void)snprintf(name, size, "%x:%x.%x-ch%u",
+ pci_dev->addr.bus, pci_dev->addr.devid,
+ pci_dev->addr.function, queue_id);
+}
+
+static int
+hisi_dma_create(struct rte_pci_device *pci_dev, uint8_t queue_id,
+ uint8_t revision)
+{
+#define REG_PCI_BAR_INDEX 2
+
+ char name[RTE_DEV_NAME_MAX_LEN];
+ struct rte_dma_dev *dev;
+ struct hisi_dma_dev *hw;
+ int ret;
+
+ hisi_dma_gen_dev_name(pci_dev, queue_id, name, sizeof(name));
+ dev = rte_dma_pmd_allocate(name, pci_dev->device.numa_node,
+ sizeof(*hw));
+ if (dev == NULL) {
+ HISI_DMA_LOG(ERR, "%s allocate dmadev fail!", name);
+ return -EINVAL;
+ }
+
+ dev->device = &pci_dev->device;
+
+ hw = dev->data->dev_private;
+ hw->data = dev->data;
+ hw->revision = revision;
+ hw->reg_layout = hisi_dma_reg_layout(revision);
+ hw->io_base = pci_dev->mem_resource[REG_PCI_BAR_INDEX].addr;
+ hw->queue_id = queue_id;
+
+ ret = hisi_dma_reset_hw(hw);
+ if (ret) {
+ HISI_DMA_LOG(ERR, "%s init device fail!", name);
+ (void)rte_dma_pmd_release(name);
+ return -EIO;
+ }
+
+ dev->state = RTE_DMA_DEV_READY;
+ HISI_DMA_LOG(DEBUG, "%s create dmadev success!", name);
+
+ return 0;
+}
+
static int
hisi_dma_check_revision(struct rte_pci_device *pci_dev, const char *name,
uint8_t *out_revision)
@@ -78,6 +266,7 @@ hisi_dma_probe(struct rte_pci_driver *pci_drv __rte_unused,
{
char name[RTE_DEV_NAME_MAX_LEN] = { 0 };
uint8_t revision;
+ uint8_t i;
int ret;
hisi_dma_gen_pci_device_name(pci_dev, name, sizeof(name));
@@ -92,13 +281,34 @@ hisi_dma_probe(struct rte_pci_driver *pci_drv __rte_unused,
return ret;
HISI_DMA_LOG(DEBUG, "%s read PCI revision: 0x%x", name, revision);
+ hisi_dma_init_gbl(pci_dev->mem_resource[2].addr, revision);
+
+ for (i = 0; i < HISI_DMA_MAX_HW_QUEUES; i++) {
+ ret = hisi_dma_create(pci_dev, i, revision);
+ if (ret) {
+ HISI_DMA_LOG(ERR, "%s create dmadev %u failed!",
+ name, i);
+ break;
+ }
+ }
+
return ret;
}
static int
hisi_dma_remove(struct rte_pci_device *pci_dev)
{
- RTE_SET_USED(pci_dev);
+ char name[RTE_DEV_NAME_MAX_LEN];
+ uint8_t i;
+ int ret;
+
+ for (i = 0; i < HISI_DMA_MAX_HW_QUEUES; i++) {
+ hisi_dma_gen_dev_name(pci_dev, i, name, sizeof(name));
+ ret = rte_dma_pmd_release(name);
+ if (ret)
+ return ret;
+ }
+
return 0;
}
diff --git a/drivers/dma/hisilicon/hisi_dmadev.h b/drivers/dma/hisilicon/hisi_dmadev.h
index 114b9dcb5b..50aaa38b72 100644
--- a/drivers/dma/hisilicon/hisi_dmadev.h
+++ b/drivers/dma/hisilicon/hisi_dmadev.h
@@ -5,11 +5,24 @@
#ifndef HISI_DMADEV_H
#define HISI_DMADEV_H
+#include <rte_byteorder.h>
+#include <rte_common.h>
+
+#define BIT(x) (1ul << (x))
+#define BITS_PER_LONG (__SIZEOF_LONG__ * 8)
+#define GENMASK(h, l) \
+ (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
+#define BF_SHF(x) (__builtin_ffsll(x) - 1)
+#define FIELD_GET(mask, reg) \
+ ((typeof(mask))(((reg) & (mask)) >> BF_SHF(mask)))
+
#define PCI_VENDOR_ID_HUAWEI 0x19e5
#define HISI_DMA_DEVICE_ID 0xA122
#define HISI_DMA_PCI_REVISION_ID_REG 0x08
#define HISI_DMA_REVISION_HIP08B 0x21
+#define HISI_DMA_MAX_HW_QUEUES 4
+
/**
* The HIP08B(HiSilicon IP08) and later Chip(e.g. HiSilicon IP09) are DMA iEPs,
* they have the same pci device id but with different pci revision.
@@ -21,4 +34,88 @@ enum {
HISI_DMA_REG_LAYOUT_HIP08
};
+/**
+ * Hardware PCI bar register MAP:
+ *
+ * --------------
+ * | Misc-reg-0 |
+ * | |
+ * -------------- -> Queue base
+ * | |
+ * | Queue-0 |
+ * | |
+ * -------------- ---
+ * | | ^
+ * | Queue-1 | Queue region
+ * | | v
+ * -------------- ---
+ * | ... |
+ * | Queue-x |
+ * | ... |
+ * --------------
+ * | Misc-reg-1 |
+ * --------------
+ *
+ * As described above, a single queue register is continuous and occupies the
+ * length of queue-region. The global offset for a single queue register is
+ * calculated by:
+ * offset = queue-base + (queue-id * queue-region) + reg-offset-in-region.
+ *
+ * The first part of queue region is basically the same for HIP08 and later chip
+ * register layouts, therefore, HISI_QUEUE_* registers are defined for it.
+ */
+#define HISI_DMA_QUEUE_SQ_BASE_L_REG 0x0
+#define HISI_DMA_QUEUE_SQ_BASE_H_REG 0x4
+#define HISI_DMA_QUEUE_SQ_DEPTH_REG 0x8
+#define HISI_DMA_QUEUE_SQ_TAIL_REG 0xC
+#define HISI_DMA_QUEUE_CQ_BASE_L_REG 0x10
+#define HISI_DMA_QUEUE_CQ_BASE_H_REG 0x14
+#define HISI_DMA_QUEUE_CQ_DEPTH_REG 0x18
+#define HISI_DMA_QUEUE_CQ_HEAD_REG 0x1C
+#define HISI_DMA_QUEUE_CTRL0_REG 0x20
+#define HISI_DMA_QUEUE_CTRL0_EN_B 0
+#define HISI_DMA_QUEUE_CTRL0_PAUSE_B 4
+#define HISI_DMA_QUEUE_CTRL1_REG 0x24
+#define HISI_DMA_QUEUE_CTRL1_RESET_B 0
+#define HISI_DMA_QUEUE_FSM_REG 0x30
+#define HISI_DMA_QUEUE_FSM_STS_M GENMASK(3, 0)
+#define HISI_DMA_QUEUE_INT_STATUS_REG 0x40
+#define HISI_DMA_QUEUE_ERR_INT_NUM0_REG 0x84
+#define HISI_DMA_QUEUE_ERR_INT_NUM1_REG 0x88
+#define HISI_DMA_QUEUE_ERR_INT_NUM2_REG 0x8C
+#define HISI_DMA_QUEUE_REGION_SIZE 0x100
+
+/**
+ * HiSilicon IP08 DMA register and field define:
+ */
+#define HISI_DMA_HIP08_QUEUE_BASE 0x0
+#define HISI_DMA_HIP08_QUEUE_CTRL0_ERR_ABORT_B 2
+#define HISI_DMA_HIP08_QUEUE_INT_MASK_REG 0x44
+#define HISI_DMA_HIP08_QUEUE_INT_MASK_M GENMASK(14, 0)
+#define HISI_DMA_HIP08_QUEUE_ERR_INT_NUM3_REG 0x90
+#define HISI_DMA_HIP08_QUEUE_ERR_INT_NUM4_REG 0x94
+#define HISI_DMA_HIP08_QUEUE_ERR_INT_NUM5_REG 0x98
+#define HISI_DMA_HIP08_QUEUE_ERR_INT_NUM6_REG 0x48
+#define HISI_DMA_HIP08_MODE_REG 0x217C
+#define HISI_DMA_HIP08_MODE_SEL_B 0
+#define HISI_DMA_HIP08_DUMP_START_REG 0x2000
+#define HISI_DMA_HIP08_DUMP_END_REG 0x2280
+
+/**
+ * In fact, there are multiple states, but it need to pay attention to
+ * the following two states for the driver:
+ */
+enum {
+ HISI_DMA_STATE_IDLE = 0,
+ HISI_DMA_STATE_RUN,
+};
+
+struct hisi_dma_dev {
+ struct rte_dma_dev_data *data;
+ uint8_t revision; /**< PCI revision. */
+ uint8_t reg_layout; /**< hardware register layout. */
+ void *io_base;
+ uint8_t queue_id; /**< hardware DMA queue index. */
+};
+
#endif /* HISI_DMADEV_H */
--
2.33.0
next prev parent reply other threads:[~2021-10-30 10:41 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-10-30 10:36 [dpdk-dev] [PATCH 0/6] dma: add hisilicon DMA driver Chengwen Feng
2021-10-30 10:36 ` [dpdk-dev] [PATCH 1/6] dma/hisilicon: add device probe and remove functions Chengwen Feng
2021-10-30 10:36 ` Chengwen Feng [this message]
2021-10-30 10:36 ` [dpdk-dev] [PATCH 3/6] dma/hisilicon: add control path functions Chengwen Feng
2021-10-30 10:36 ` [dpdk-dev] [PATCH 4/6] dma/hisilicon: add data " Chengwen Feng
2021-10-30 10:36 ` [dpdk-dev] [PATCH 5/6] dma/hisilicon: support multi-process Chengwen Feng
2021-10-30 10:36 ` [dpdk-dev] [PATCH 6/6] devbind: add Kunpeng DMA to dmadev category Chengwen Feng
2021-11-02 12:37 ` [dpdk-dev] [PATCH v2 0/6] dma: add hisilicon DMA driver Chengwen Feng
2021-11-02 12:37 ` [dpdk-dev] [PATCH v2 1/6] dma/hisilicon: add device probe and remove functions Chengwen Feng
2021-11-07 17:28 ` Thomas Monjalon
2021-11-02 12:37 ` [dpdk-dev] [PATCH v2 2/6] dma/hisilicon: add dmadev instances create and destroy Chengwen Feng
2021-11-02 12:37 ` [dpdk-dev] [PATCH v2 3/6] dma/hisilicon: add control path functions Chengwen Feng
2021-11-02 12:37 ` [dpdk-dev] [PATCH v2 4/6] dma/hisilicon: add data " Chengwen Feng
2021-11-02 12:37 ` [dpdk-dev] [PATCH v2 5/6] dma/hisilicon: support multi-process Chengwen Feng
2021-11-02 12:37 ` [dpdk-dev] [PATCH v2 6/6] devbind: add Kunpeng DMA to dmadev category Chengwen Feng
2021-11-07 18:59 ` [dpdk-dev] [PATCH v2 0/6] dma: add hisilicon DMA driver Thomas Monjalon
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20211030103619.29924-3-fengchengwen@huawei.com \
--to=fengchengwen@huawei.com \
--cc=dev@dpdk.org \
--cc=thomas@monjalon.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).