linux/drivers/dma/amd/qdma/qdma.h
Nishad Saraf 73d5fc92a1 dmaengine: amd: qdma: Add AMD QDMA driver
Adds driver to enable PCIe board which uses AMD QDMA (the Queue-based
Direct Memory Access) subsystem. For example, Xilinx Alveo V70 AI
Accelerator devices.
    https://www.xilinx.com/applications/data-center/v70.html

The QDMA subsystem is used in conjunction with the PCI Express IP block
to provide high performance data transfer between host memory and the
card's DMA subsystem.

            +-------+       +-------+       +-----------+
   PCIe     |       |       |       |       |           |
   Tx/Rx    |       |       |       |  AXI  |           |
 <=======>  | PCIE  | <===> | QDMA  | <====>| User Logic|
            |       |       |       |       |           |
            +-------+       +-------+       +-----------+

The primary mechanism to transfer data using the QDMA is for the QDMA
engine to operate on instructions (descriptors) provided by the host
operating system. Using the descriptors, the QDMA can move data in both
the Host to Card (H2C) direction, or the Card to Host (C2H) direction.
The QDMA provides a per-queue basis option whether DMA traffic goes
to an AXI4 memory map (MM) interface or to an AXI4-Stream interface.

The hardware detail is provided by
    https://docs.xilinx.com/r/en-US/pg302-qdma

Implements dmaengine APIs to support MM DMA transfers.
- probe the available DMA channels
- use dma_slave_map for channel lookup
- use virtual channel to manage dmaengine tx descriptors
- implement device_prep_slave_sg callback to handle host scatter gather
  list

Signed-off-by: Nishad Saraf <nishads@amd.com>
Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
Link: https://lore.kernel.org/r/20240819211948.688786-2-lizhi.hou@amd.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
2024-08-28 23:34:13 +05:30

266 lines
5.8 KiB
C

/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* DMA header for AMD Queue-based DMA Subsystem
*
* Copyright (C) 2023-2024, Advanced Micro Devices, Inc.
*/
#ifndef __QDMA_H
#define __QDMA_H
#include <linux/bitfield.h>
#include <linux/dmaengine.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include "../../virt-dma.h"
#define DISABLE 0
#define ENABLE 1
#define QDMA_MIN_IRQ 3
#define QDMA_INTR_NAME_MAX_LEN 30
#define QDMA_INTR_PREFIX "amd-qdma"
#define QDMA_IDENTIFIER 0x1FD3
#define QDMA_DEFAULT_RING_SIZE (BIT(10) + 1)
#define QDMA_DEFAULT_RING_ID 0
#define QDMA_POLL_INTRVL_US 10 /* 10us */
#define QDMA_POLL_TIMEOUT_US (500 * 1000) /* 500ms */
#define QDMA_DMAP_REG_STRIDE 16
#define QDMA_CTXT_REGMAP_LEN 8 /* 8 regs */
#define QDMA_MM_DESC_SIZE 32 /* Bytes */
#define QDMA_MM_DESC_LEN_BITS 28
#define QDMA_MM_DESC_MAX_LEN (BIT(QDMA_MM_DESC_LEN_BITS) - 1)
#define QDMA_MIN_DMA_ALLOC_SIZE 4096
#define QDMA_INTR_RING_SIZE BIT(13)
#define QDMA_INTR_RING_IDX_MASK GENMASK(9, 0)
#define QDMA_INTR_RING_BASE(_addr) ((_addr) >> 12)
#define QDMA_IDENTIFIER_REGOFF 0x0
#define QDMA_IDENTIFIER_MASK GENMASK(31, 16)
#define QDMA_QUEUE_ARM_BIT BIT(16)
#define qdma_err(qdev, fmt, args...) \
dev_err(&(qdev)->pdev->dev, fmt, ##args)
#define qdma_dbg(qdev, fmt, args...) \
dev_dbg(&(qdev)->pdev->dev, fmt, ##args)
#define qdma_info(qdev, fmt, args...) \
dev_info(&(qdev)->pdev->dev, fmt, ##args)
enum qdma_reg_fields {
QDMA_REGF_IRQ_ENABLE,
QDMA_REGF_WBK_ENABLE,
QDMA_REGF_WBI_CHECK,
QDMA_REGF_IRQ_ARM,
QDMA_REGF_IRQ_VEC,
QDMA_REGF_IRQ_AGG,
QDMA_REGF_WBI_INTVL_ENABLE,
QDMA_REGF_MRKR_DISABLE,
QDMA_REGF_QUEUE_ENABLE,
QDMA_REGF_QUEUE_MODE,
QDMA_REGF_DESC_BASE,
QDMA_REGF_DESC_SIZE,
QDMA_REGF_RING_ID,
QDMA_REGF_CMD_INDX,
QDMA_REGF_CMD_CMD,
QDMA_REGF_CMD_TYPE,
QDMA_REGF_CMD_BUSY,
QDMA_REGF_QUEUE_COUNT,
QDMA_REGF_QUEUE_MAX,
QDMA_REGF_QUEUE_BASE,
QDMA_REGF_FUNCTION_ID,
QDMA_REGF_INTR_AGG_BASE,
QDMA_REGF_INTR_VECTOR,
QDMA_REGF_INTR_SIZE,
QDMA_REGF_INTR_VALID,
QDMA_REGF_INTR_COLOR,
QDMA_REGF_INTR_FUNCTION_ID,
QDMA_REGF_ERR_INT_FUNC,
QDMA_REGF_ERR_INT_VEC,
QDMA_REGF_ERR_INT_ARM,
QDMA_REGF_MAX
};
enum qdma_regs {
QDMA_REGO_CTXT_DATA,
QDMA_REGO_CTXT_CMD,
QDMA_REGO_CTXT_MASK,
QDMA_REGO_MM_H2C_CTRL,
QDMA_REGO_MM_C2H_CTRL,
QDMA_REGO_QUEUE_COUNT,
QDMA_REGO_RING_SIZE,
QDMA_REGO_H2C_PIDX,
QDMA_REGO_C2H_PIDX,
QDMA_REGO_INTR_CIDX,
QDMA_REGO_FUNC_ID,
QDMA_REGO_ERR_INT,
QDMA_REGO_ERR_STAT,
QDMA_REGO_MAX
};
struct qdma_reg_field {
u16 lsb; /* Least significant bit of field */
u16 msb; /* Most significant bit of field */
};
struct qdma_reg {
u32 off;
u32 count;
};
#define QDMA_REGF(_msb, _lsb) { \
.lsb = (_lsb), \
.msb = (_msb), \
}
#define QDMA_REGO(_off, _count) { \
.off = (_off), \
.count = (_count), \
}
enum qdma_desc_size {
QDMA_DESC_SIZE_8B,
QDMA_DESC_SIZE_16B,
QDMA_DESC_SIZE_32B,
QDMA_DESC_SIZE_64B,
};
enum qdma_queue_op_mode {
QDMA_QUEUE_OP_STREAM,
QDMA_QUEUE_OP_MM,
};
enum qdma_ctxt_type {
QDMA_CTXT_DESC_SW_C2H,
QDMA_CTXT_DESC_SW_H2C,
QDMA_CTXT_DESC_HW_C2H,
QDMA_CTXT_DESC_HW_H2C,
QDMA_CTXT_DESC_CR_C2H,
QDMA_CTXT_DESC_CR_H2C,
QDMA_CTXT_WRB,
QDMA_CTXT_PFTCH,
QDMA_CTXT_INTR_COAL,
QDMA_CTXT_RSVD,
QDMA_CTXT_HOST_PROFILE,
QDMA_CTXT_TIMER,
QDMA_CTXT_FMAP,
QDMA_CTXT_FNC_STS,
};
enum qdma_ctxt_cmd {
QDMA_CTXT_CLEAR,
QDMA_CTXT_WRITE,
QDMA_CTXT_READ,
QDMA_CTXT_INVALIDATE,
QDMA_CTXT_MAX
};
struct qdma_ctxt_sw_desc {
u64 desc_base;
u16 vec;
};
struct qdma_ctxt_intr {
u64 agg_base;
u16 vec;
u32 size;
bool valid;
bool color;
};
struct qdma_ctxt_fmap {
u16 qbase;
u16 qmax;
};
struct qdma_device;
struct qdma_mm_desc {
__le64 src_addr;
__le32 len;
__le32 reserved1;
__le64 dst_addr;
__le64 reserved2;
} __packed;
struct qdma_mm_vdesc {
struct virt_dma_desc vdesc;
struct qdma_queue *queue;
struct scatterlist *sgl;
u64 sg_off;
u32 sg_len;
u64 dev_addr;
u32 pidx;
u32 pending_descs;
struct dma_slave_config cfg;
};
#define QDMA_VDESC_QUEUED(vdesc) (!(vdesc)->sg_len)
struct qdma_queue {
struct qdma_device *qdev;
struct virt_dma_chan vchan;
enum dma_transfer_direction dir;
struct dma_slave_config cfg;
struct qdma_mm_desc *desc_base;
struct qdma_mm_vdesc *submitted_vdesc;
struct qdma_mm_vdesc *issued_vdesc;
dma_addr_t dma_desc_base;
u32 pidx_reg;
u32 cidx_reg;
u32 ring_size;
u32 idx_mask;
u16 qid;
u32 pidx;
u32 cidx;
};
struct qdma_intr_ring {
struct qdma_device *qdev;
__le64 *base;
dma_addr_t dev_base;
char msix_name[QDMA_INTR_NAME_MAX_LEN];
u32 msix_vector;
u16 msix_id;
u32 ring_size;
u16 ridx;
u16 cidx;
u8 color;
};
#define QDMA_INTR_MASK_PIDX GENMASK_ULL(15, 0)
#define QDMA_INTR_MASK_CIDX GENMASK_ULL(31, 16)
#define QDMA_INTR_MASK_DESC_COLOR GENMASK_ULL(32, 32)
#define QDMA_INTR_MASK_STATE GENMASK_ULL(34, 33)
#define QDMA_INTR_MASK_ERROR GENMASK_ULL(36, 35)
#define QDMA_INTR_MASK_TYPE GENMASK_ULL(38, 38)
#define QDMA_INTR_MASK_QID GENMASK_ULL(62, 39)
#define QDMA_INTR_MASK_COLOR GENMASK_ULL(63, 63)
struct qdma_device {
struct platform_device *pdev;
struct dma_device dma_dev;
struct regmap *regmap;
struct mutex ctxt_lock; /* protect ctxt registers */
const struct qdma_reg_field *rfields;
const struct qdma_reg *roffs;
struct qdma_queue *h2c_queues;
struct qdma_queue *c2h_queues;
struct qdma_intr_ring *qintr_rings;
u32 qintr_ring_num;
u32 qintr_ring_idx;
u32 chan_num;
u32 queue_irq_start;
u32 queue_irq_num;
u32 err_irq_idx;
u32 fid;
};
extern const struct qdma_reg qdma_regos_default[QDMA_REGO_MAX];
extern const struct qdma_reg_field qdma_regfs_default[QDMA_REGF_MAX];
#endif /* __QDMA_H */