162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* Copyright(c) 2019-2022 HiSilicon Limited. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/bitfield.h> 562306a36Sopenharmony_ci#include <linux/dmaengine.h> 662306a36Sopenharmony_ci#include <linux/init.h> 762306a36Sopenharmony_ci#include <linux/iopoll.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/pci.h> 1062306a36Sopenharmony_ci#include <linux/spinlock.h> 1162306a36Sopenharmony_ci#include "virt-dma.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/* HiSilicon DMA register common field define */ 1462306a36Sopenharmony_ci#define HISI_DMA_Q_SQ_BASE_L 0x0 1562306a36Sopenharmony_ci#define HISI_DMA_Q_SQ_BASE_H 0x4 1662306a36Sopenharmony_ci#define HISI_DMA_Q_SQ_DEPTH 0x8 1762306a36Sopenharmony_ci#define HISI_DMA_Q_SQ_TAIL_PTR 0xc 1862306a36Sopenharmony_ci#define HISI_DMA_Q_CQ_BASE_L 0x10 1962306a36Sopenharmony_ci#define HISI_DMA_Q_CQ_BASE_H 0x14 2062306a36Sopenharmony_ci#define HISI_DMA_Q_CQ_DEPTH 0x18 2162306a36Sopenharmony_ci#define HISI_DMA_Q_CQ_HEAD_PTR 0x1c 2262306a36Sopenharmony_ci#define HISI_DMA_Q_CTRL0 0x20 2362306a36Sopenharmony_ci#define HISI_DMA_Q_CTRL0_QUEUE_EN BIT(0) 2462306a36Sopenharmony_ci#define HISI_DMA_Q_CTRL0_QUEUE_PAUSE BIT(4) 2562306a36Sopenharmony_ci#define HISI_DMA_Q_CTRL1 0x24 2662306a36Sopenharmony_ci#define HISI_DMA_Q_CTRL1_QUEUE_RESET BIT(0) 2762306a36Sopenharmony_ci#define HISI_DMA_Q_FSM_STS 0x30 2862306a36Sopenharmony_ci#define HISI_DMA_Q_FSM_STS_MASK GENMASK(3, 0) 2962306a36Sopenharmony_ci#define HISI_DMA_Q_ERR_INT_NUM0 0x84 3062306a36Sopenharmony_ci#define HISI_DMA_Q_ERR_INT_NUM1 0x88 3162306a36Sopenharmony_ci#define HISI_DMA_Q_ERR_INT_NUM2 0x8c 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* HiSilicon IP08 DMA register and field define */ 3462306a36Sopenharmony_ci#define HISI_DMA_HIP08_MODE 0x217C 3562306a36Sopenharmony_ci#define HISI_DMA_HIP08_Q_BASE 0x0 3662306a36Sopenharmony_ci#define HISI_DMA_HIP08_Q_CTRL0_ERR_ABORT_EN BIT(2) 3762306a36Sopenharmony_ci#define HISI_DMA_HIP08_Q_INT_STS 0x40 3862306a36Sopenharmony_ci#define HISI_DMA_HIP08_Q_INT_MSK 0x44 3962306a36Sopenharmony_ci#define HISI_DMA_HIP08_Q_INT_STS_MASK GENMASK(14, 0) 4062306a36Sopenharmony_ci#define HISI_DMA_HIP08_Q_ERR_INT_NUM3 0x90 4162306a36Sopenharmony_ci#define HISI_DMA_HIP08_Q_ERR_INT_NUM4 0x94 4262306a36Sopenharmony_ci#define HISI_DMA_HIP08_Q_ERR_INT_NUM5 0x98 4362306a36Sopenharmony_ci#define HISI_DMA_HIP08_Q_ERR_INT_NUM6 0x48 4462306a36Sopenharmony_ci#define HISI_DMA_HIP08_Q_CTRL0_SQCQ_DRCT BIT(24) 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* HiSilicon IP09 DMA register and field define */ 4762306a36Sopenharmony_ci#define HISI_DMA_HIP09_DMA_FLR_DISABLE 0xA00 4862306a36Sopenharmony_ci#define HISI_DMA_HIP09_DMA_FLR_DISABLE_B BIT(0) 4962306a36Sopenharmony_ci#define HISI_DMA_HIP09_Q_BASE 0x2000 5062306a36Sopenharmony_ci#define HISI_DMA_HIP09_Q_CTRL0_ERR_ABORT_EN GENMASK(31, 28) 5162306a36Sopenharmony_ci#define HISI_DMA_HIP09_Q_CTRL0_SQ_DRCT BIT(26) 5262306a36Sopenharmony_ci#define HISI_DMA_HIP09_Q_CTRL0_CQ_DRCT BIT(27) 5362306a36Sopenharmony_ci#define HISI_DMA_HIP09_Q_CTRL1_VA_ENABLE BIT(2) 5462306a36Sopenharmony_ci#define HISI_DMA_HIP09_Q_INT_STS 0x40 5562306a36Sopenharmony_ci#define HISI_DMA_HIP09_Q_INT_MSK 0x44 5662306a36Sopenharmony_ci#define HISI_DMA_HIP09_Q_INT_STS_MASK 0x1 5762306a36Sopenharmony_ci#define HISI_DMA_HIP09_Q_ERR_INT_STS 0x48 5862306a36Sopenharmony_ci#define HISI_DMA_HIP09_Q_ERR_INT_MSK 0x4C 5962306a36Sopenharmony_ci#define HISI_DMA_HIP09_Q_ERR_INT_STS_MASK GENMASK(18, 1) 6062306a36Sopenharmony_ci#define HISI_DMA_HIP09_PORT_CFG_REG(port_id) (0x800 + \ 6162306a36Sopenharmony_ci (port_id) * 0x20) 6262306a36Sopenharmony_ci#define HISI_DMA_HIP09_PORT_CFG_LINK_DOWN_MASK_B BIT(16) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#define HISI_DMA_HIP09_MAX_PORT_NUM 16 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define HISI_DMA_HIP08_MSI_NUM 32 6762306a36Sopenharmony_ci#define HISI_DMA_HIP08_CHAN_NUM 30 6862306a36Sopenharmony_ci#define HISI_DMA_HIP09_MSI_NUM 4 6962306a36Sopenharmony_ci#define HISI_DMA_HIP09_CHAN_NUM 4 7062306a36Sopenharmony_ci#define HISI_DMA_REVISION_HIP08B 0x21 7162306a36Sopenharmony_ci#define HISI_DMA_REVISION_HIP09A 0x30 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#define HISI_DMA_Q_OFFSET 0x100 7462306a36Sopenharmony_ci#define HISI_DMA_Q_DEPTH_VAL 1024 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#define PCI_BAR_2 2 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#define HISI_DMA_POLL_Q_STS_DELAY_US 10 7962306a36Sopenharmony_ci#define HISI_DMA_POLL_Q_STS_TIME_OUT_US 1000 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci#define HISI_DMA_MAX_DIR_NAME_LEN 128 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* 8462306a36Sopenharmony_ci * The HIP08B(HiSilicon IP08) and HIP09A(HiSilicon IP09) are DMA iEPs, they 8562306a36Sopenharmony_ci * have the same pci device id but different pci revision. 8662306a36Sopenharmony_ci * Unfortunately, they have different register layouts, so two layout 8762306a36Sopenharmony_ci * enumerations are defined. 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_cienum hisi_dma_reg_layout { 9062306a36Sopenharmony_ci HISI_DMA_REG_LAYOUT_INVALID = 0, 9162306a36Sopenharmony_ci HISI_DMA_REG_LAYOUT_HIP08, 9262306a36Sopenharmony_ci HISI_DMA_REG_LAYOUT_HIP09 9362306a36Sopenharmony_ci}; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cienum hisi_dma_mode { 9662306a36Sopenharmony_ci EP = 0, 9762306a36Sopenharmony_ci RC, 9862306a36Sopenharmony_ci}; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cienum hisi_dma_chan_status { 10162306a36Sopenharmony_ci DISABLE = -1, 10262306a36Sopenharmony_ci IDLE = 0, 10362306a36Sopenharmony_ci RUN, 10462306a36Sopenharmony_ci CPL, 10562306a36Sopenharmony_ci PAUSE, 10662306a36Sopenharmony_ci HALT, 10762306a36Sopenharmony_ci ABORT, 10862306a36Sopenharmony_ci WAIT, 10962306a36Sopenharmony_ci BUFFCLR, 11062306a36Sopenharmony_ci}; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistruct hisi_dma_sqe { 11362306a36Sopenharmony_ci __le32 dw0; 11462306a36Sopenharmony_ci#define OPCODE_MASK GENMASK(3, 0) 11562306a36Sopenharmony_ci#define OPCODE_SMALL_PACKAGE 0x1 11662306a36Sopenharmony_ci#define OPCODE_M2M 0x4 11762306a36Sopenharmony_ci#define LOCAL_IRQ_EN BIT(8) 11862306a36Sopenharmony_ci#define ATTR_SRC_MASK GENMASK(14, 12) 11962306a36Sopenharmony_ci __le32 dw1; 12062306a36Sopenharmony_ci __le32 dw2; 12162306a36Sopenharmony_ci#define ATTR_DST_MASK GENMASK(26, 24) 12262306a36Sopenharmony_ci __le32 length; 12362306a36Sopenharmony_ci __le64 src_addr; 12462306a36Sopenharmony_ci __le64 dst_addr; 12562306a36Sopenharmony_ci}; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistruct hisi_dma_cqe { 12862306a36Sopenharmony_ci __le32 rsv0; 12962306a36Sopenharmony_ci __le32 rsv1; 13062306a36Sopenharmony_ci __le16 sq_head; 13162306a36Sopenharmony_ci __le16 rsv2; 13262306a36Sopenharmony_ci __le16 rsv3; 13362306a36Sopenharmony_ci __le16 w0; 13462306a36Sopenharmony_ci#define STATUS_MASK GENMASK(15, 1) 13562306a36Sopenharmony_ci#define STATUS_SUCC 0x0 13662306a36Sopenharmony_ci#define VALID_BIT BIT(0) 13762306a36Sopenharmony_ci}; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistruct hisi_dma_desc { 14062306a36Sopenharmony_ci struct virt_dma_desc vd; 14162306a36Sopenharmony_ci struct hisi_dma_sqe sqe; 14262306a36Sopenharmony_ci}; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistruct hisi_dma_chan { 14562306a36Sopenharmony_ci struct virt_dma_chan vc; 14662306a36Sopenharmony_ci struct hisi_dma_dev *hdma_dev; 14762306a36Sopenharmony_ci struct hisi_dma_sqe *sq; 14862306a36Sopenharmony_ci struct hisi_dma_cqe *cq; 14962306a36Sopenharmony_ci dma_addr_t sq_dma; 15062306a36Sopenharmony_ci dma_addr_t cq_dma; 15162306a36Sopenharmony_ci u32 sq_tail; 15262306a36Sopenharmony_ci u32 cq_head; 15362306a36Sopenharmony_ci u32 qp_num; 15462306a36Sopenharmony_ci enum hisi_dma_chan_status status; 15562306a36Sopenharmony_ci struct hisi_dma_desc *desc; 15662306a36Sopenharmony_ci}; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistruct hisi_dma_dev { 15962306a36Sopenharmony_ci struct pci_dev *pdev; 16062306a36Sopenharmony_ci void __iomem *base; 16162306a36Sopenharmony_ci struct dma_device dma_dev; 16262306a36Sopenharmony_ci u32 chan_num; 16362306a36Sopenharmony_ci u32 chan_depth; 16462306a36Sopenharmony_ci enum hisi_dma_reg_layout reg_layout; 16562306a36Sopenharmony_ci void __iomem *queue_base; /* queue region start of register */ 16662306a36Sopenharmony_ci struct hisi_dma_chan chan[]; 16762306a36Sopenharmony_ci}; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic const struct debugfs_reg32 hisi_dma_comm_chan_regs[] = { 17262306a36Sopenharmony_ci {"DMA_QUEUE_SQ_DEPTH ", 0x0008ull}, 17362306a36Sopenharmony_ci {"DMA_QUEUE_SQ_TAIL_PTR ", 0x000Cull}, 17462306a36Sopenharmony_ci {"DMA_QUEUE_CQ_DEPTH ", 0x0018ull}, 17562306a36Sopenharmony_ci {"DMA_QUEUE_CQ_HEAD_PTR ", 0x001Cull}, 17662306a36Sopenharmony_ci {"DMA_QUEUE_CTRL0 ", 0x0020ull}, 17762306a36Sopenharmony_ci {"DMA_QUEUE_CTRL1 ", 0x0024ull}, 17862306a36Sopenharmony_ci {"DMA_QUEUE_FSM_STS ", 0x0030ull}, 17962306a36Sopenharmony_ci {"DMA_QUEUE_SQ_STS ", 0x0034ull}, 18062306a36Sopenharmony_ci {"DMA_QUEUE_CQ_TAIL_PTR ", 0x003Cull}, 18162306a36Sopenharmony_ci {"DMA_QUEUE_INT_STS ", 0x0040ull}, 18262306a36Sopenharmony_ci {"DMA_QUEUE_INT_MSK ", 0x0044ull}, 18362306a36Sopenharmony_ci {"DMA_QUEUE_INT_RO ", 0x006Cull}, 18462306a36Sopenharmony_ci}; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic const struct debugfs_reg32 hisi_dma_hip08_chan_regs[] = { 18762306a36Sopenharmony_ci {"DMA_QUEUE_BYTE_CNT ", 0x0038ull}, 18862306a36Sopenharmony_ci {"DMA_ERR_INT_NUM6 ", 0x0048ull}, 18962306a36Sopenharmony_ci {"DMA_QUEUE_DESP0 ", 0x0050ull}, 19062306a36Sopenharmony_ci {"DMA_QUEUE_DESP1 ", 0x0054ull}, 19162306a36Sopenharmony_ci {"DMA_QUEUE_DESP2 ", 0x0058ull}, 19262306a36Sopenharmony_ci {"DMA_QUEUE_DESP3 ", 0x005Cull}, 19362306a36Sopenharmony_ci {"DMA_QUEUE_DESP4 ", 0x0074ull}, 19462306a36Sopenharmony_ci {"DMA_QUEUE_DESP5 ", 0x0078ull}, 19562306a36Sopenharmony_ci {"DMA_QUEUE_DESP6 ", 0x007Cull}, 19662306a36Sopenharmony_ci {"DMA_QUEUE_DESP7 ", 0x0080ull}, 19762306a36Sopenharmony_ci {"DMA_ERR_INT_NUM0 ", 0x0084ull}, 19862306a36Sopenharmony_ci {"DMA_ERR_INT_NUM1 ", 0x0088ull}, 19962306a36Sopenharmony_ci {"DMA_ERR_INT_NUM2 ", 0x008Cull}, 20062306a36Sopenharmony_ci {"DMA_ERR_INT_NUM3 ", 0x0090ull}, 20162306a36Sopenharmony_ci {"DMA_ERR_INT_NUM4 ", 0x0094ull}, 20262306a36Sopenharmony_ci {"DMA_ERR_INT_NUM5 ", 0x0098ull}, 20362306a36Sopenharmony_ci {"DMA_QUEUE_SQ_STS2 ", 0x00A4ull}, 20462306a36Sopenharmony_ci}; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic const struct debugfs_reg32 hisi_dma_hip09_chan_regs[] = { 20762306a36Sopenharmony_ci {"DMA_QUEUE_ERR_INT_STS ", 0x0048ull}, 20862306a36Sopenharmony_ci {"DMA_QUEUE_ERR_INT_MSK ", 0x004Cull}, 20962306a36Sopenharmony_ci {"DFX_SQ_READ_ERR_PTR ", 0x0068ull}, 21062306a36Sopenharmony_ci {"DFX_DMA_ERR_INT_NUM0 ", 0x0084ull}, 21162306a36Sopenharmony_ci {"DFX_DMA_ERR_INT_NUM1 ", 0x0088ull}, 21262306a36Sopenharmony_ci {"DFX_DMA_ERR_INT_NUM2 ", 0x008Cull}, 21362306a36Sopenharmony_ci {"DFX_DMA_QUEUE_SQ_STS2 ", 0x00A4ull}, 21462306a36Sopenharmony_ci}; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic const struct debugfs_reg32 hisi_dma_hip08_comm_regs[] = { 21762306a36Sopenharmony_ci {"DMA_ECC_ERR_ADDR ", 0x2004ull}, 21862306a36Sopenharmony_ci {"DMA_ECC_ECC_CNT ", 0x2014ull}, 21962306a36Sopenharmony_ci {"COMMON_AND_CH_ERR_STS ", 0x2030ull}, 22062306a36Sopenharmony_ci {"LOCAL_CPL_ID_STS_0 ", 0x20E0ull}, 22162306a36Sopenharmony_ci {"LOCAL_CPL_ID_STS_1 ", 0x20E4ull}, 22262306a36Sopenharmony_ci {"LOCAL_CPL_ID_STS_2 ", 0x20E8ull}, 22362306a36Sopenharmony_ci {"LOCAL_CPL_ID_STS_3 ", 0x20ECull}, 22462306a36Sopenharmony_ci {"LOCAL_TLP_NUM ", 0x2158ull}, 22562306a36Sopenharmony_ci {"SQCQ_TLP_NUM ", 0x2164ull}, 22662306a36Sopenharmony_ci {"CPL_NUM ", 0x2168ull}, 22762306a36Sopenharmony_ci {"INF_BACK_PRESS_STS ", 0x2170ull}, 22862306a36Sopenharmony_ci {"DMA_CH_RAS_LEVEL ", 0x2184ull}, 22962306a36Sopenharmony_ci {"DMA_CM_RAS_LEVEL ", 0x2188ull}, 23062306a36Sopenharmony_ci {"DMA_CH_ERR_STS ", 0x2190ull}, 23162306a36Sopenharmony_ci {"DMA_CH_DONE_STS ", 0x2194ull}, 23262306a36Sopenharmony_ci {"DMA_SQ_TAG_STS_0 ", 0x21A0ull}, 23362306a36Sopenharmony_ci {"DMA_SQ_TAG_STS_1 ", 0x21A4ull}, 23462306a36Sopenharmony_ci {"DMA_SQ_TAG_STS_2 ", 0x21A8ull}, 23562306a36Sopenharmony_ci {"DMA_SQ_TAG_STS_3 ", 0x21ACull}, 23662306a36Sopenharmony_ci {"LOCAL_P_ID_STS_0 ", 0x21B0ull}, 23762306a36Sopenharmony_ci {"LOCAL_P_ID_STS_1 ", 0x21B4ull}, 23862306a36Sopenharmony_ci {"LOCAL_P_ID_STS_2 ", 0x21B8ull}, 23962306a36Sopenharmony_ci {"LOCAL_P_ID_STS_3 ", 0x21BCull}, 24062306a36Sopenharmony_ci {"DMA_PREBUFF_INFO_0 ", 0x2200ull}, 24162306a36Sopenharmony_ci {"DMA_CM_TABLE_INFO_0 ", 0x2220ull}, 24262306a36Sopenharmony_ci {"DMA_CM_CE_RO ", 0x2244ull}, 24362306a36Sopenharmony_ci {"DMA_CM_NFE_RO ", 0x2248ull}, 24462306a36Sopenharmony_ci {"DMA_CM_FE_RO ", 0x224Cull}, 24562306a36Sopenharmony_ci}; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic const struct debugfs_reg32 hisi_dma_hip09_comm_regs[] = { 24862306a36Sopenharmony_ci {"COMMON_AND_CH_ERR_STS ", 0x0030ull}, 24962306a36Sopenharmony_ci {"DMA_PORT_IDLE_STS ", 0x0150ull}, 25062306a36Sopenharmony_ci {"DMA_CH_RAS_LEVEL ", 0x0184ull}, 25162306a36Sopenharmony_ci {"DMA_CM_RAS_LEVEL ", 0x0188ull}, 25262306a36Sopenharmony_ci {"DMA_CM_CE_RO ", 0x0244ull}, 25362306a36Sopenharmony_ci {"DMA_CM_NFE_RO ", 0x0248ull}, 25462306a36Sopenharmony_ci {"DMA_CM_FE_RO ", 0x024Cull}, 25562306a36Sopenharmony_ci {"DFX_INF_BACK_PRESS_STS0 ", 0x1A40ull}, 25662306a36Sopenharmony_ci {"DFX_INF_BACK_PRESS_STS1 ", 0x1A44ull}, 25762306a36Sopenharmony_ci {"DFX_INF_BACK_PRESS_STS2 ", 0x1A48ull}, 25862306a36Sopenharmony_ci {"DFX_DMA_WRR_DISABLE ", 0x1A4Cull}, 25962306a36Sopenharmony_ci {"DFX_PA_REQ_TLP_NUM ", 0x1C00ull}, 26062306a36Sopenharmony_ci {"DFX_PA_BACK_TLP_NUM ", 0x1C04ull}, 26162306a36Sopenharmony_ci {"DFX_PA_RETRY_TLP_NUM ", 0x1C08ull}, 26262306a36Sopenharmony_ci {"DFX_LOCAL_NP_TLP_NUM ", 0x1C0Cull}, 26362306a36Sopenharmony_ci {"DFX_LOCAL_CPL_HEAD_TLP_NUM ", 0x1C10ull}, 26462306a36Sopenharmony_ci {"DFX_LOCAL_CPL_DATA_TLP_NUM ", 0x1C14ull}, 26562306a36Sopenharmony_ci {"DFX_LOCAL_CPL_EXT_DATA_TLP_NUM ", 0x1C18ull}, 26662306a36Sopenharmony_ci {"DFX_LOCAL_P_HEAD_TLP_NUM ", 0x1C1Cull}, 26762306a36Sopenharmony_ci {"DFX_LOCAL_P_ACK_TLP_NUM ", 0x1C20ull}, 26862306a36Sopenharmony_ci {"DFX_BUF_ALOC_PORT_REQ_NUM ", 0x1C24ull}, 26962306a36Sopenharmony_ci {"DFX_BUF_ALOC_PORT_RESULT_NUM ", 0x1C28ull}, 27062306a36Sopenharmony_ci {"DFX_BUF_FAIL_SIZE_NUM ", 0x1C2Cull}, 27162306a36Sopenharmony_ci {"DFX_BUF_ALOC_SIZE_NUM ", 0x1C30ull}, 27262306a36Sopenharmony_ci {"DFX_BUF_NP_RELEASE_SIZE_NUM ", 0x1C34ull}, 27362306a36Sopenharmony_ci {"DFX_BUF_P_RELEASE_SIZE_NUM ", 0x1C38ull}, 27462306a36Sopenharmony_ci {"DFX_BUF_PORT_RELEASE_SIZE_NUM ", 0x1C3Cull}, 27562306a36Sopenharmony_ci {"DFX_DMA_PREBUF_MEM0_ECC_ERR_ADDR ", 0x1CA8ull}, 27662306a36Sopenharmony_ci {"DFX_DMA_PREBUF_MEM0_ECC_CNT ", 0x1CACull}, 27762306a36Sopenharmony_ci {"DFX_DMA_LOC_NP_OSTB_ECC_ERR_ADDR ", 0x1CB0ull}, 27862306a36Sopenharmony_ci {"DFX_DMA_LOC_NP_OSTB_ECC_CNT ", 0x1CB4ull}, 27962306a36Sopenharmony_ci {"DFX_DMA_PREBUF_MEM1_ECC_ERR_ADDR ", 0x1CC0ull}, 28062306a36Sopenharmony_ci {"DFX_DMA_PREBUF_MEM1_ECC_CNT ", 0x1CC4ull}, 28162306a36Sopenharmony_ci {"DMA_CH_DONE_STS ", 0x02E0ull}, 28262306a36Sopenharmony_ci {"DMA_CH_ERR_STS ", 0x0320ull}, 28362306a36Sopenharmony_ci}; 28462306a36Sopenharmony_ci#endif /* CONFIG_DEBUG_FS*/ 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic enum hisi_dma_reg_layout hisi_dma_get_reg_layout(struct pci_dev *pdev) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci if (pdev->revision == HISI_DMA_REVISION_HIP08B) 28962306a36Sopenharmony_ci return HISI_DMA_REG_LAYOUT_HIP08; 29062306a36Sopenharmony_ci else if (pdev->revision >= HISI_DMA_REVISION_HIP09A) 29162306a36Sopenharmony_ci return HISI_DMA_REG_LAYOUT_HIP09; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci return HISI_DMA_REG_LAYOUT_INVALID; 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic u32 hisi_dma_get_chan_num(struct pci_dev *pdev) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci if (pdev->revision == HISI_DMA_REVISION_HIP08B) 29962306a36Sopenharmony_ci return HISI_DMA_HIP08_CHAN_NUM; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci return HISI_DMA_HIP09_CHAN_NUM; 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic u32 hisi_dma_get_msi_num(struct pci_dev *pdev) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci if (pdev->revision == HISI_DMA_REVISION_HIP08B) 30762306a36Sopenharmony_ci return HISI_DMA_HIP08_MSI_NUM; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci return HISI_DMA_HIP09_MSI_NUM; 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic u32 hisi_dma_get_queue_base(struct pci_dev *pdev) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci if (pdev->revision == HISI_DMA_REVISION_HIP08B) 31562306a36Sopenharmony_ci return HISI_DMA_HIP08_Q_BASE; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci return HISI_DMA_HIP09_Q_BASE; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic inline struct hisi_dma_chan *to_hisi_dma_chan(struct dma_chan *c) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci return container_of(c, struct hisi_dma_chan, vc.chan); 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic inline struct hisi_dma_desc *to_hisi_dma_desc(struct virt_dma_desc *vd) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci return container_of(vd, struct hisi_dma_desc, vd); 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic inline void hisi_dma_chan_write(void __iomem *base, u32 reg, u32 index, 33162306a36Sopenharmony_ci u32 val) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci writel_relaxed(val, base + reg + index * HISI_DMA_Q_OFFSET); 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic inline void hisi_dma_update_bit(void __iomem *addr, u32 pos, bool val) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci u32 tmp; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci tmp = readl_relaxed(addr); 34162306a36Sopenharmony_ci tmp = val ? tmp | pos : tmp & ~pos; 34262306a36Sopenharmony_ci writel_relaxed(tmp, addr); 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic void hisi_dma_pause_dma(struct hisi_dma_dev *hdma_dev, u32 index, 34662306a36Sopenharmony_ci bool pause) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci void __iomem *addr; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci addr = hdma_dev->queue_base + HISI_DMA_Q_CTRL0 + 35162306a36Sopenharmony_ci index * HISI_DMA_Q_OFFSET; 35262306a36Sopenharmony_ci hisi_dma_update_bit(addr, HISI_DMA_Q_CTRL0_QUEUE_PAUSE, pause); 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic void hisi_dma_enable_dma(struct hisi_dma_dev *hdma_dev, u32 index, 35662306a36Sopenharmony_ci bool enable) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci void __iomem *addr; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci addr = hdma_dev->queue_base + HISI_DMA_Q_CTRL0 + 36162306a36Sopenharmony_ci index * HISI_DMA_Q_OFFSET; 36262306a36Sopenharmony_ci hisi_dma_update_bit(addr, HISI_DMA_Q_CTRL0_QUEUE_EN, enable); 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic void hisi_dma_mask_irq(struct hisi_dma_dev *hdma_dev, u32 qp_index) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci void __iomem *q_base = hdma_dev->queue_base; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (hdma_dev->reg_layout == HISI_DMA_REG_LAYOUT_HIP08) 37062306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_HIP08_Q_INT_MSK, 37162306a36Sopenharmony_ci qp_index, HISI_DMA_HIP08_Q_INT_STS_MASK); 37262306a36Sopenharmony_ci else { 37362306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_HIP09_Q_INT_MSK, 37462306a36Sopenharmony_ci qp_index, HISI_DMA_HIP09_Q_INT_STS_MASK); 37562306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_HIP09_Q_ERR_INT_MSK, 37662306a36Sopenharmony_ci qp_index, 37762306a36Sopenharmony_ci HISI_DMA_HIP09_Q_ERR_INT_STS_MASK); 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic void hisi_dma_unmask_irq(struct hisi_dma_dev *hdma_dev, u32 qp_index) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci void __iomem *q_base = hdma_dev->queue_base; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (hdma_dev->reg_layout == HISI_DMA_REG_LAYOUT_HIP08) { 38662306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_HIP08_Q_INT_STS, 38762306a36Sopenharmony_ci qp_index, HISI_DMA_HIP08_Q_INT_STS_MASK); 38862306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_HIP08_Q_INT_MSK, 38962306a36Sopenharmony_ci qp_index, 0); 39062306a36Sopenharmony_ci } else { 39162306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_HIP09_Q_INT_STS, 39262306a36Sopenharmony_ci qp_index, HISI_DMA_HIP09_Q_INT_STS_MASK); 39362306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_HIP09_Q_ERR_INT_STS, 39462306a36Sopenharmony_ci qp_index, 39562306a36Sopenharmony_ci HISI_DMA_HIP09_Q_ERR_INT_STS_MASK); 39662306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_HIP09_Q_INT_MSK, 39762306a36Sopenharmony_ci qp_index, 0); 39862306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_HIP09_Q_ERR_INT_MSK, 39962306a36Sopenharmony_ci qp_index, 0); 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic void hisi_dma_do_reset(struct hisi_dma_dev *hdma_dev, u32 index) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci void __iomem *addr; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci addr = hdma_dev->queue_base + 40862306a36Sopenharmony_ci HISI_DMA_Q_CTRL1 + index * HISI_DMA_Q_OFFSET; 40962306a36Sopenharmony_ci hisi_dma_update_bit(addr, HISI_DMA_Q_CTRL1_QUEUE_RESET, 1); 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic void hisi_dma_reset_qp_point(struct hisi_dma_dev *hdma_dev, u32 index) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci void __iomem *q_base = hdma_dev->queue_base; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_Q_SQ_TAIL_PTR, index, 0); 41762306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_Q_CQ_HEAD_PTR, index, 0); 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic void hisi_dma_reset_or_disable_hw_chan(struct hisi_dma_chan *chan, 42162306a36Sopenharmony_ci bool disable) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci struct hisi_dma_dev *hdma_dev = chan->hdma_dev; 42462306a36Sopenharmony_ci u32 index = chan->qp_num, tmp; 42562306a36Sopenharmony_ci void __iomem *addr; 42662306a36Sopenharmony_ci int ret; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci hisi_dma_pause_dma(hdma_dev, index, true); 42962306a36Sopenharmony_ci hisi_dma_enable_dma(hdma_dev, index, false); 43062306a36Sopenharmony_ci hisi_dma_mask_irq(hdma_dev, index); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci addr = hdma_dev->queue_base + 43362306a36Sopenharmony_ci HISI_DMA_Q_FSM_STS + index * HISI_DMA_Q_OFFSET; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci ret = readl_relaxed_poll_timeout(addr, tmp, 43662306a36Sopenharmony_ci FIELD_GET(HISI_DMA_Q_FSM_STS_MASK, tmp) != RUN, 43762306a36Sopenharmony_ci HISI_DMA_POLL_Q_STS_DELAY_US, HISI_DMA_POLL_Q_STS_TIME_OUT_US); 43862306a36Sopenharmony_ci if (ret) { 43962306a36Sopenharmony_ci dev_err(&hdma_dev->pdev->dev, "disable channel timeout!\n"); 44062306a36Sopenharmony_ci WARN_ON(1); 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci hisi_dma_do_reset(hdma_dev, index); 44462306a36Sopenharmony_ci hisi_dma_reset_qp_point(hdma_dev, index); 44562306a36Sopenharmony_ci hisi_dma_pause_dma(hdma_dev, index, false); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (!disable) { 44862306a36Sopenharmony_ci hisi_dma_enable_dma(hdma_dev, index, true); 44962306a36Sopenharmony_ci hisi_dma_unmask_irq(hdma_dev, index); 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci ret = readl_relaxed_poll_timeout(addr, tmp, 45362306a36Sopenharmony_ci FIELD_GET(HISI_DMA_Q_FSM_STS_MASK, tmp) == IDLE, 45462306a36Sopenharmony_ci HISI_DMA_POLL_Q_STS_DELAY_US, HISI_DMA_POLL_Q_STS_TIME_OUT_US); 45562306a36Sopenharmony_ci if (ret) { 45662306a36Sopenharmony_ci dev_err(&hdma_dev->pdev->dev, "reset channel timeout!\n"); 45762306a36Sopenharmony_ci WARN_ON(1); 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic void hisi_dma_free_chan_resources(struct dma_chan *c) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci struct hisi_dma_chan *chan = to_hisi_dma_chan(c); 46462306a36Sopenharmony_ci struct hisi_dma_dev *hdma_dev = chan->hdma_dev; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci hisi_dma_reset_or_disable_hw_chan(chan, false); 46762306a36Sopenharmony_ci vchan_free_chan_resources(&chan->vc); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci memset(chan->sq, 0, sizeof(struct hisi_dma_sqe) * hdma_dev->chan_depth); 47062306a36Sopenharmony_ci memset(chan->cq, 0, sizeof(struct hisi_dma_cqe) * hdma_dev->chan_depth); 47162306a36Sopenharmony_ci chan->sq_tail = 0; 47262306a36Sopenharmony_ci chan->cq_head = 0; 47362306a36Sopenharmony_ci chan->status = DISABLE; 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cistatic void hisi_dma_desc_free(struct virt_dma_desc *vd) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci kfree(to_hisi_dma_desc(vd)); 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cistatic struct dma_async_tx_descriptor * 48262306a36Sopenharmony_cihisi_dma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dst, dma_addr_t src, 48362306a36Sopenharmony_ci size_t len, unsigned long flags) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci struct hisi_dma_chan *chan = to_hisi_dma_chan(c); 48662306a36Sopenharmony_ci struct hisi_dma_desc *desc; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci desc = kzalloc(sizeof(*desc), GFP_NOWAIT); 48962306a36Sopenharmony_ci if (!desc) 49062306a36Sopenharmony_ci return NULL; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci desc->sqe.length = cpu_to_le32(len); 49362306a36Sopenharmony_ci desc->sqe.src_addr = cpu_to_le64(src); 49462306a36Sopenharmony_ci desc->sqe.dst_addr = cpu_to_le64(dst); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci return vchan_tx_prep(&chan->vc, &desc->vd, flags); 49762306a36Sopenharmony_ci} 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_cistatic enum dma_status 50062306a36Sopenharmony_cihisi_dma_tx_status(struct dma_chan *c, dma_cookie_t cookie, 50162306a36Sopenharmony_ci struct dma_tx_state *txstate) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci return dma_cookie_status(c, cookie, txstate); 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_cistatic void hisi_dma_start_transfer(struct hisi_dma_chan *chan) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci struct hisi_dma_sqe *sqe = chan->sq + chan->sq_tail; 50962306a36Sopenharmony_ci struct hisi_dma_dev *hdma_dev = chan->hdma_dev; 51062306a36Sopenharmony_ci struct hisi_dma_desc *desc; 51162306a36Sopenharmony_ci struct virt_dma_desc *vd; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci vd = vchan_next_desc(&chan->vc); 51462306a36Sopenharmony_ci if (!vd) { 51562306a36Sopenharmony_ci chan->desc = NULL; 51662306a36Sopenharmony_ci return; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci list_del(&vd->node); 51962306a36Sopenharmony_ci desc = to_hisi_dma_desc(vd); 52062306a36Sopenharmony_ci chan->desc = desc; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci memcpy(sqe, &desc->sqe, sizeof(struct hisi_dma_sqe)); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci /* update other field in sqe */ 52562306a36Sopenharmony_ci sqe->dw0 = cpu_to_le32(FIELD_PREP(OPCODE_MASK, OPCODE_M2M)); 52662306a36Sopenharmony_ci sqe->dw0 |= cpu_to_le32(LOCAL_IRQ_EN); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci /* make sure data has been updated in sqe */ 52962306a36Sopenharmony_ci wmb(); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci /* update sq tail, point to new sqe position */ 53262306a36Sopenharmony_ci chan->sq_tail = (chan->sq_tail + 1) % hdma_dev->chan_depth; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci /* update sq_tail to trigger a new task */ 53562306a36Sopenharmony_ci hisi_dma_chan_write(hdma_dev->queue_base, HISI_DMA_Q_SQ_TAIL_PTR, 53662306a36Sopenharmony_ci chan->qp_num, chan->sq_tail); 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic void hisi_dma_issue_pending(struct dma_chan *c) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci struct hisi_dma_chan *chan = to_hisi_dma_chan(c); 54262306a36Sopenharmony_ci unsigned long flags; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci spin_lock_irqsave(&chan->vc.lock, flags); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (vchan_issue_pending(&chan->vc) && !chan->desc) 54762306a36Sopenharmony_ci hisi_dma_start_transfer(chan); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci spin_unlock_irqrestore(&chan->vc.lock, flags); 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_cistatic int hisi_dma_terminate_all(struct dma_chan *c) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci struct hisi_dma_chan *chan = to_hisi_dma_chan(c); 55562306a36Sopenharmony_ci unsigned long flags; 55662306a36Sopenharmony_ci LIST_HEAD(head); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci spin_lock_irqsave(&chan->vc.lock, flags); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci hisi_dma_pause_dma(chan->hdma_dev, chan->qp_num, true); 56162306a36Sopenharmony_ci if (chan->desc) { 56262306a36Sopenharmony_ci vchan_terminate_vdesc(&chan->desc->vd); 56362306a36Sopenharmony_ci chan->desc = NULL; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci vchan_get_all_descriptors(&chan->vc, &head); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci spin_unlock_irqrestore(&chan->vc.lock, flags); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci vchan_dma_desc_free_list(&chan->vc, &head); 57162306a36Sopenharmony_ci hisi_dma_pause_dma(chan->hdma_dev, chan->qp_num, false); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci return 0; 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_cistatic void hisi_dma_synchronize(struct dma_chan *c) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci struct hisi_dma_chan *chan = to_hisi_dma_chan(c); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci vchan_synchronize(&chan->vc); 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_cistatic int hisi_dma_alloc_qps_mem(struct hisi_dma_dev *hdma_dev) 58462306a36Sopenharmony_ci{ 58562306a36Sopenharmony_ci size_t sq_size = sizeof(struct hisi_dma_sqe) * hdma_dev->chan_depth; 58662306a36Sopenharmony_ci size_t cq_size = sizeof(struct hisi_dma_cqe) * hdma_dev->chan_depth; 58762306a36Sopenharmony_ci struct device *dev = &hdma_dev->pdev->dev; 58862306a36Sopenharmony_ci struct hisi_dma_chan *chan; 58962306a36Sopenharmony_ci int i; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci for (i = 0; i < hdma_dev->chan_num; i++) { 59262306a36Sopenharmony_ci chan = &hdma_dev->chan[i]; 59362306a36Sopenharmony_ci chan->sq = dmam_alloc_coherent(dev, sq_size, &chan->sq_dma, 59462306a36Sopenharmony_ci GFP_KERNEL); 59562306a36Sopenharmony_ci if (!chan->sq) 59662306a36Sopenharmony_ci return -ENOMEM; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci chan->cq = dmam_alloc_coherent(dev, cq_size, &chan->cq_dma, 59962306a36Sopenharmony_ci GFP_KERNEL); 60062306a36Sopenharmony_ci if (!chan->cq) 60162306a36Sopenharmony_ci return -ENOMEM; 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci return 0; 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic void hisi_dma_init_hw_qp(struct hisi_dma_dev *hdma_dev, u32 index) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci struct hisi_dma_chan *chan = &hdma_dev->chan[index]; 61062306a36Sopenharmony_ci void __iomem *q_base = hdma_dev->queue_base; 61162306a36Sopenharmony_ci u32 hw_depth = hdma_dev->chan_depth - 1; 61262306a36Sopenharmony_ci void __iomem *addr; 61362306a36Sopenharmony_ci u32 tmp; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci /* set sq, cq base */ 61662306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_Q_SQ_BASE_L, index, 61762306a36Sopenharmony_ci lower_32_bits(chan->sq_dma)); 61862306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_Q_SQ_BASE_H, index, 61962306a36Sopenharmony_ci upper_32_bits(chan->sq_dma)); 62062306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_Q_CQ_BASE_L, index, 62162306a36Sopenharmony_ci lower_32_bits(chan->cq_dma)); 62262306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_Q_CQ_BASE_H, index, 62362306a36Sopenharmony_ci upper_32_bits(chan->cq_dma)); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci /* set sq, cq depth */ 62662306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_Q_SQ_DEPTH, index, hw_depth); 62762306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_Q_CQ_DEPTH, index, hw_depth); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci /* init sq tail and cq head */ 63062306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_Q_SQ_TAIL_PTR, index, 0); 63162306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_Q_CQ_HEAD_PTR, index, 0); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci /* init error interrupt stats */ 63462306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_Q_ERR_INT_NUM0, index, 0); 63562306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_Q_ERR_INT_NUM1, index, 0); 63662306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_Q_ERR_INT_NUM2, index, 0); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci if (hdma_dev->reg_layout == HISI_DMA_REG_LAYOUT_HIP08) { 63962306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_HIP08_Q_ERR_INT_NUM3, 64062306a36Sopenharmony_ci index, 0); 64162306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_HIP08_Q_ERR_INT_NUM4, 64262306a36Sopenharmony_ci index, 0); 64362306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_HIP08_Q_ERR_INT_NUM5, 64462306a36Sopenharmony_ci index, 0); 64562306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_HIP08_Q_ERR_INT_NUM6, 64662306a36Sopenharmony_ci index, 0); 64762306a36Sopenharmony_ci /* 64862306a36Sopenharmony_ci * init SQ/CQ direction selecting register. 64962306a36Sopenharmony_ci * "0" is to local side and "1" is to remote side. 65062306a36Sopenharmony_ci */ 65162306a36Sopenharmony_ci addr = q_base + HISI_DMA_Q_CTRL0 + index * HISI_DMA_Q_OFFSET; 65262306a36Sopenharmony_ci hisi_dma_update_bit(addr, HISI_DMA_HIP08_Q_CTRL0_SQCQ_DRCT, 0); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci /* 65562306a36Sopenharmony_ci * 0 - Continue to next descriptor if error occurs. 65662306a36Sopenharmony_ci * 1 - Abort the DMA queue if error occurs. 65762306a36Sopenharmony_ci */ 65862306a36Sopenharmony_ci hisi_dma_update_bit(addr, 65962306a36Sopenharmony_ci HISI_DMA_HIP08_Q_CTRL0_ERR_ABORT_EN, 0); 66062306a36Sopenharmony_ci } else { 66162306a36Sopenharmony_ci addr = q_base + HISI_DMA_Q_CTRL0 + index * HISI_DMA_Q_OFFSET; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci /* 66462306a36Sopenharmony_ci * init SQ/CQ direction selecting register. 66562306a36Sopenharmony_ci * "0" is to local side and "1" is to remote side. 66662306a36Sopenharmony_ci */ 66762306a36Sopenharmony_ci hisi_dma_update_bit(addr, HISI_DMA_HIP09_Q_CTRL0_SQ_DRCT, 0); 66862306a36Sopenharmony_ci hisi_dma_update_bit(addr, HISI_DMA_HIP09_Q_CTRL0_CQ_DRCT, 0); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci /* 67162306a36Sopenharmony_ci * 0 - Continue to next descriptor if error occurs. 67262306a36Sopenharmony_ci * 1 - Abort the DMA queue if error occurs. 67362306a36Sopenharmony_ci */ 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci tmp = readl_relaxed(addr); 67662306a36Sopenharmony_ci tmp &= ~HISI_DMA_HIP09_Q_CTRL0_ERR_ABORT_EN; 67762306a36Sopenharmony_ci writel_relaxed(tmp, addr); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci /* 68062306a36Sopenharmony_ci * 0 - dma should process FLR whith CPU. 68162306a36Sopenharmony_ci * 1 - dma not process FLR, only cpu process FLR. 68262306a36Sopenharmony_ci */ 68362306a36Sopenharmony_ci addr = q_base + HISI_DMA_HIP09_DMA_FLR_DISABLE + 68462306a36Sopenharmony_ci index * HISI_DMA_Q_OFFSET; 68562306a36Sopenharmony_ci hisi_dma_update_bit(addr, HISI_DMA_HIP09_DMA_FLR_DISABLE_B, 0); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci addr = q_base + HISI_DMA_Q_CTRL1 + index * HISI_DMA_Q_OFFSET; 68862306a36Sopenharmony_ci hisi_dma_update_bit(addr, HISI_DMA_HIP09_Q_CTRL1_VA_ENABLE, 1); 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci} 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_cistatic void hisi_dma_enable_qp(struct hisi_dma_dev *hdma_dev, u32 qp_index) 69362306a36Sopenharmony_ci{ 69462306a36Sopenharmony_ci hisi_dma_init_hw_qp(hdma_dev, qp_index); 69562306a36Sopenharmony_ci hisi_dma_unmask_irq(hdma_dev, qp_index); 69662306a36Sopenharmony_ci hisi_dma_enable_dma(hdma_dev, qp_index, true); 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic void hisi_dma_disable_qp(struct hisi_dma_dev *hdma_dev, u32 qp_index) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci hisi_dma_reset_or_disable_hw_chan(&hdma_dev->chan[qp_index], true); 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic void hisi_dma_enable_qps(struct hisi_dma_dev *hdma_dev) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci int i; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci for (i = 0; i < hdma_dev->chan_num; i++) { 70962306a36Sopenharmony_ci hdma_dev->chan[i].qp_num = i; 71062306a36Sopenharmony_ci hdma_dev->chan[i].hdma_dev = hdma_dev; 71162306a36Sopenharmony_ci hdma_dev->chan[i].vc.desc_free = hisi_dma_desc_free; 71262306a36Sopenharmony_ci vchan_init(&hdma_dev->chan[i].vc, &hdma_dev->dma_dev); 71362306a36Sopenharmony_ci hisi_dma_enable_qp(hdma_dev, i); 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci} 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_cistatic void hisi_dma_disable_qps(struct hisi_dma_dev *hdma_dev) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci int i; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci for (i = 0; i < hdma_dev->chan_num; i++) { 72262306a36Sopenharmony_ci hisi_dma_disable_qp(hdma_dev, i); 72362306a36Sopenharmony_ci tasklet_kill(&hdma_dev->chan[i].vc.task); 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci} 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_cistatic irqreturn_t hisi_dma_irq(int irq, void *data) 72862306a36Sopenharmony_ci{ 72962306a36Sopenharmony_ci struct hisi_dma_chan *chan = data; 73062306a36Sopenharmony_ci struct hisi_dma_dev *hdma_dev = chan->hdma_dev; 73162306a36Sopenharmony_ci struct hisi_dma_desc *desc; 73262306a36Sopenharmony_ci struct hisi_dma_cqe *cqe; 73362306a36Sopenharmony_ci void __iomem *q_base; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci spin_lock(&chan->vc.lock); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci desc = chan->desc; 73862306a36Sopenharmony_ci cqe = chan->cq + chan->cq_head; 73962306a36Sopenharmony_ci q_base = hdma_dev->queue_base; 74062306a36Sopenharmony_ci if (desc) { 74162306a36Sopenharmony_ci chan->cq_head = (chan->cq_head + 1) % hdma_dev->chan_depth; 74262306a36Sopenharmony_ci hisi_dma_chan_write(q_base, HISI_DMA_Q_CQ_HEAD_PTR, 74362306a36Sopenharmony_ci chan->qp_num, chan->cq_head); 74462306a36Sopenharmony_ci if (FIELD_GET(STATUS_MASK, cqe->w0) == STATUS_SUCC) { 74562306a36Sopenharmony_ci vchan_cookie_complete(&desc->vd); 74662306a36Sopenharmony_ci hisi_dma_start_transfer(chan); 74762306a36Sopenharmony_ci } else { 74862306a36Sopenharmony_ci dev_err(&hdma_dev->pdev->dev, "task error!\n"); 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci spin_unlock(&chan->vc.lock); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci return IRQ_HANDLED; 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_cistatic int hisi_dma_request_qps_irq(struct hisi_dma_dev *hdma_dev) 75862306a36Sopenharmony_ci{ 75962306a36Sopenharmony_ci struct pci_dev *pdev = hdma_dev->pdev; 76062306a36Sopenharmony_ci int i, ret; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci for (i = 0; i < hdma_dev->chan_num; i++) { 76362306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, pci_irq_vector(pdev, i), 76462306a36Sopenharmony_ci hisi_dma_irq, IRQF_SHARED, "hisi_dma", 76562306a36Sopenharmony_ci &hdma_dev->chan[i]); 76662306a36Sopenharmony_ci if (ret) 76762306a36Sopenharmony_ci return ret; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci return 0; 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci/* This function enables all hw channels in a device */ 77462306a36Sopenharmony_cistatic int hisi_dma_enable_hw_channels(struct hisi_dma_dev *hdma_dev) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci int ret; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci ret = hisi_dma_alloc_qps_mem(hdma_dev); 77962306a36Sopenharmony_ci if (ret) { 78062306a36Sopenharmony_ci dev_err(&hdma_dev->pdev->dev, "fail to allocate qp memory!\n"); 78162306a36Sopenharmony_ci return ret; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci ret = hisi_dma_request_qps_irq(hdma_dev); 78562306a36Sopenharmony_ci if (ret) { 78662306a36Sopenharmony_ci dev_err(&hdma_dev->pdev->dev, "fail to request qp irq!\n"); 78762306a36Sopenharmony_ci return ret; 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci hisi_dma_enable_qps(hdma_dev); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci return 0; 79362306a36Sopenharmony_ci} 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_cistatic void hisi_dma_disable_hw_channels(void *data) 79662306a36Sopenharmony_ci{ 79762306a36Sopenharmony_ci hisi_dma_disable_qps(data); 79862306a36Sopenharmony_ci} 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_cistatic void hisi_dma_set_mode(struct hisi_dma_dev *hdma_dev, 80162306a36Sopenharmony_ci enum hisi_dma_mode mode) 80262306a36Sopenharmony_ci{ 80362306a36Sopenharmony_ci if (hdma_dev->reg_layout == HISI_DMA_REG_LAYOUT_HIP08) 80462306a36Sopenharmony_ci writel_relaxed(mode == RC ? 1 : 0, 80562306a36Sopenharmony_ci hdma_dev->base + HISI_DMA_HIP08_MODE); 80662306a36Sopenharmony_ci} 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_cistatic void hisi_dma_init_hw(struct hisi_dma_dev *hdma_dev) 80962306a36Sopenharmony_ci{ 81062306a36Sopenharmony_ci void __iomem *addr; 81162306a36Sopenharmony_ci int i; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci if (hdma_dev->reg_layout == HISI_DMA_REG_LAYOUT_HIP09) { 81462306a36Sopenharmony_ci for (i = 0; i < HISI_DMA_HIP09_MAX_PORT_NUM; i++) { 81562306a36Sopenharmony_ci addr = hdma_dev->base + HISI_DMA_HIP09_PORT_CFG_REG(i); 81662306a36Sopenharmony_ci hisi_dma_update_bit(addr, 81762306a36Sopenharmony_ci HISI_DMA_HIP09_PORT_CFG_LINK_DOWN_MASK_B, 1); 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_cistatic void hisi_dma_init_dma_dev(struct hisi_dma_dev *hdma_dev) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci struct dma_device *dma_dev; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci dma_dev = &hdma_dev->dma_dev; 82762306a36Sopenharmony_ci dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask); 82862306a36Sopenharmony_ci dma_dev->device_free_chan_resources = hisi_dma_free_chan_resources; 82962306a36Sopenharmony_ci dma_dev->device_prep_dma_memcpy = hisi_dma_prep_dma_memcpy; 83062306a36Sopenharmony_ci dma_dev->device_tx_status = hisi_dma_tx_status; 83162306a36Sopenharmony_ci dma_dev->device_issue_pending = hisi_dma_issue_pending; 83262306a36Sopenharmony_ci dma_dev->device_terminate_all = hisi_dma_terminate_all; 83362306a36Sopenharmony_ci dma_dev->device_synchronize = hisi_dma_synchronize; 83462306a36Sopenharmony_ci dma_dev->directions = BIT(DMA_MEM_TO_MEM); 83562306a36Sopenharmony_ci dma_dev->dev = &hdma_dev->pdev->dev; 83662306a36Sopenharmony_ci INIT_LIST_HEAD(&dma_dev->channels); 83762306a36Sopenharmony_ci} 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci/* --- debugfs implementation --- */ 84062306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 84162306a36Sopenharmony_ci#include <linux/debugfs.h> 84262306a36Sopenharmony_cistatic struct debugfs_reg32 *hisi_dma_get_ch_regs(struct hisi_dma_dev *hdma_dev, 84362306a36Sopenharmony_ci u32 *regs_sz) 84462306a36Sopenharmony_ci{ 84562306a36Sopenharmony_ci struct device *dev = &hdma_dev->pdev->dev; 84662306a36Sopenharmony_ci struct debugfs_reg32 *regs; 84762306a36Sopenharmony_ci u32 regs_sz_comm; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci regs_sz_comm = ARRAY_SIZE(hisi_dma_comm_chan_regs); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci if (hdma_dev->reg_layout == HISI_DMA_REG_LAYOUT_HIP08) 85262306a36Sopenharmony_ci *regs_sz = regs_sz_comm + ARRAY_SIZE(hisi_dma_hip08_chan_regs); 85362306a36Sopenharmony_ci else 85462306a36Sopenharmony_ci *regs_sz = regs_sz_comm + ARRAY_SIZE(hisi_dma_hip09_chan_regs); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci regs = devm_kcalloc(dev, *regs_sz, sizeof(struct debugfs_reg32), 85762306a36Sopenharmony_ci GFP_KERNEL); 85862306a36Sopenharmony_ci if (!regs) 85962306a36Sopenharmony_ci return NULL; 86062306a36Sopenharmony_ci memcpy(regs, hisi_dma_comm_chan_regs, sizeof(hisi_dma_comm_chan_regs)); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci if (hdma_dev->reg_layout == HISI_DMA_REG_LAYOUT_HIP08) 86362306a36Sopenharmony_ci memcpy(regs + regs_sz_comm, hisi_dma_hip08_chan_regs, 86462306a36Sopenharmony_ci sizeof(hisi_dma_hip08_chan_regs)); 86562306a36Sopenharmony_ci else 86662306a36Sopenharmony_ci memcpy(regs + regs_sz_comm, hisi_dma_hip09_chan_regs, 86762306a36Sopenharmony_ci sizeof(hisi_dma_hip09_chan_regs)); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci return regs; 87062306a36Sopenharmony_ci} 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_cistatic int hisi_dma_create_chan_dir(struct hisi_dma_dev *hdma_dev) 87362306a36Sopenharmony_ci{ 87462306a36Sopenharmony_ci char dir_name[HISI_DMA_MAX_DIR_NAME_LEN]; 87562306a36Sopenharmony_ci struct debugfs_regset32 *regsets; 87662306a36Sopenharmony_ci struct debugfs_reg32 *regs; 87762306a36Sopenharmony_ci struct dentry *chan_dir; 87862306a36Sopenharmony_ci struct device *dev; 87962306a36Sopenharmony_ci u32 regs_sz; 88062306a36Sopenharmony_ci int ret; 88162306a36Sopenharmony_ci int i; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci dev = &hdma_dev->pdev->dev; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci regsets = devm_kcalloc(dev, hdma_dev->chan_num, 88662306a36Sopenharmony_ci sizeof(*regsets), GFP_KERNEL); 88762306a36Sopenharmony_ci if (!regsets) 88862306a36Sopenharmony_ci return -ENOMEM; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci regs = hisi_dma_get_ch_regs(hdma_dev, ®s_sz); 89162306a36Sopenharmony_ci if (!regs) 89262306a36Sopenharmony_ci return -ENOMEM; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci for (i = 0; i < hdma_dev->chan_num; i++) { 89562306a36Sopenharmony_ci regsets[i].regs = regs; 89662306a36Sopenharmony_ci regsets[i].nregs = regs_sz; 89762306a36Sopenharmony_ci regsets[i].base = hdma_dev->queue_base + i * HISI_DMA_Q_OFFSET; 89862306a36Sopenharmony_ci regsets[i].dev = dev; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci memset(dir_name, 0, HISI_DMA_MAX_DIR_NAME_LEN); 90162306a36Sopenharmony_ci ret = sprintf(dir_name, "channel%d", i); 90262306a36Sopenharmony_ci if (ret < 0) 90362306a36Sopenharmony_ci return ret; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci chan_dir = debugfs_create_dir(dir_name, 90662306a36Sopenharmony_ci hdma_dev->dma_dev.dbg_dev_root); 90762306a36Sopenharmony_ci debugfs_create_regset32("regs", 0444, chan_dir, ®sets[i]); 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci return 0; 91162306a36Sopenharmony_ci} 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_cistatic void hisi_dma_create_debugfs(struct hisi_dma_dev *hdma_dev) 91462306a36Sopenharmony_ci{ 91562306a36Sopenharmony_ci struct debugfs_regset32 *regset; 91662306a36Sopenharmony_ci struct device *dev; 91762306a36Sopenharmony_ci int ret; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci dev = &hdma_dev->pdev->dev; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci if (hdma_dev->dma_dev.dbg_dev_root == NULL) 92262306a36Sopenharmony_ci return; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci regset = devm_kzalloc(dev, sizeof(*regset), GFP_KERNEL); 92562306a36Sopenharmony_ci if (!regset) 92662306a36Sopenharmony_ci return; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci if (hdma_dev->reg_layout == HISI_DMA_REG_LAYOUT_HIP08) { 92962306a36Sopenharmony_ci regset->regs = hisi_dma_hip08_comm_regs; 93062306a36Sopenharmony_ci regset->nregs = ARRAY_SIZE(hisi_dma_hip08_comm_regs); 93162306a36Sopenharmony_ci } else { 93262306a36Sopenharmony_ci regset->regs = hisi_dma_hip09_comm_regs; 93362306a36Sopenharmony_ci regset->nregs = ARRAY_SIZE(hisi_dma_hip09_comm_regs); 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci regset->base = hdma_dev->base; 93662306a36Sopenharmony_ci regset->dev = dev; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci debugfs_create_regset32("regs", 0444, 93962306a36Sopenharmony_ci hdma_dev->dma_dev.dbg_dev_root, regset); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci ret = hisi_dma_create_chan_dir(hdma_dev); 94262306a36Sopenharmony_ci if (ret < 0) 94362306a36Sopenharmony_ci dev_info(&hdma_dev->pdev->dev, "fail to create debugfs for channels!\n"); 94462306a36Sopenharmony_ci} 94562306a36Sopenharmony_ci#else 94662306a36Sopenharmony_cistatic void hisi_dma_create_debugfs(struct hisi_dma_dev *hdma_dev) { } 94762306a36Sopenharmony_ci#endif /* CONFIG_DEBUG_FS*/ 94862306a36Sopenharmony_ci/* --- debugfs implementation --- */ 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_cistatic int hisi_dma_probe(struct pci_dev *pdev, const struct pci_device_id *id) 95162306a36Sopenharmony_ci{ 95262306a36Sopenharmony_ci enum hisi_dma_reg_layout reg_layout; 95362306a36Sopenharmony_ci struct device *dev = &pdev->dev; 95462306a36Sopenharmony_ci struct hisi_dma_dev *hdma_dev; 95562306a36Sopenharmony_ci struct dma_device *dma_dev; 95662306a36Sopenharmony_ci u32 chan_num; 95762306a36Sopenharmony_ci u32 msi_num; 95862306a36Sopenharmony_ci int ret; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci reg_layout = hisi_dma_get_reg_layout(pdev); 96162306a36Sopenharmony_ci if (reg_layout == HISI_DMA_REG_LAYOUT_INVALID) { 96262306a36Sopenharmony_ci dev_err(dev, "unsupported device!\n"); 96362306a36Sopenharmony_ci return -EINVAL; 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci ret = pcim_enable_device(pdev); 96762306a36Sopenharmony_ci if (ret) { 96862306a36Sopenharmony_ci dev_err(dev, "failed to enable device mem!\n"); 96962306a36Sopenharmony_ci return ret; 97062306a36Sopenharmony_ci } 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci ret = pcim_iomap_regions(pdev, 1 << PCI_BAR_2, pci_name(pdev)); 97362306a36Sopenharmony_ci if (ret) { 97462306a36Sopenharmony_ci dev_err(dev, "failed to remap I/O region!\n"); 97562306a36Sopenharmony_ci return ret; 97662306a36Sopenharmony_ci } 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 97962306a36Sopenharmony_ci if (ret) 98062306a36Sopenharmony_ci return ret; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci chan_num = hisi_dma_get_chan_num(pdev); 98362306a36Sopenharmony_ci hdma_dev = devm_kzalloc(dev, struct_size(hdma_dev, chan, chan_num), 98462306a36Sopenharmony_ci GFP_KERNEL); 98562306a36Sopenharmony_ci if (!hdma_dev) 98662306a36Sopenharmony_ci return -EINVAL; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci hdma_dev->base = pcim_iomap_table(pdev)[PCI_BAR_2]; 98962306a36Sopenharmony_ci hdma_dev->pdev = pdev; 99062306a36Sopenharmony_ci hdma_dev->chan_depth = HISI_DMA_Q_DEPTH_VAL; 99162306a36Sopenharmony_ci hdma_dev->chan_num = chan_num; 99262306a36Sopenharmony_ci hdma_dev->reg_layout = reg_layout; 99362306a36Sopenharmony_ci hdma_dev->queue_base = hdma_dev->base + hisi_dma_get_queue_base(pdev); 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci pci_set_drvdata(pdev, hdma_dev); 99662306a36Sopenharmony_ci pci_set_master(pdev); 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci msi_num = hisi_dma_get_msi_num(pdev); 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci /* This will be freed by 'pcim_release()'. See 'pcim_enable_device()' */ 100162306a36Sopenharmony_ci ret = pci_alloc_irq_vectors(pdev, msi_num, msi_num, PCI_IRQ_MSI); 100262306a36Sopenharmony_ci if (ret < 0) { 100362306a36Sopenharmony_ci dev_err(dev, "Failed to allocate MSI vectors!\n"); 100462306a36Sopenharmony_ci return ret; 100562306a36Sopenharmony_ci } 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci hisi_dma_init_dma_dev(hdma_dev); 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci hisi_dma_set_mode(hdma_dev, RC); 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci hisi_dma_init_hw(hdma_dev); 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci ret = hisi_dma_enable_hw_channels(hdma_dev); 101462306a36Sopenharmony_ci if (ret < 0) { 101562306a36Sopenharmony_ci dev_err(dev, "failed to enable hw channel!\n"); 101662306a36Sopenharmony_ci return ret; 101762306a36Sopenharmony_ci } 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci ret = devm_add_action_or_reset(dev, hisi_dma_disable_hw_channels, 102062306a36Sopenharmony_ci hdma_dev); 102162306a36Sopenharmony_ci if (ret) 102262306a36Sopenharmony_ci return ret; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci dma_dev = &hdma_dev->dma_dev; 102562306a36Sopenharmony_ci ret = dmaenginem_async_device_register(dma_dev); 102662306a36Sopenharmony_ci if (ret < 0) { 102762306a36Sopenharmony_ci dev_err(dev, "failed to register device!\n"); 102862306a36Sopenharmony_ci return ret; 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci hisi_dma_create_debugfs(hdma_dev); 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci return 0; 103462306a36Sopenharmony_ci} 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_cistatic const struct pci_device_id hisi_dma_pci_tbl[] = { 103762306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, 0xa122) }, 103862306a36Sopenharmony_ci { 0, } 103962306a36Sopenharmony_ci}; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_cistatic struct pci_driver hisi_dma_pci_driver = { 104262306a36Sopenharmony_ci .name = "hisi_dma", 104362306a36Sopenharmony_ci .id_table = hisi_dma_pci_tbl, 104462306a36Sopenharmony_ci .probe = hisi_dma_probe, 104562306a36Sopenharmony_ci}; 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_cimodule_pci_driver(hisi_dma_pci_driver); 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ciMODULE_AUTHOR("Zhou Wang <wangzhou1@hisilicon.com>"); 105062306a36Sopenharmony_ciMODULE_AUTHOR("Zhenfa Qiu <qiuzhenfa@hisilicon.com>"); 105162306a36Sopenharmony_ciMODULE_DESCRIPTION("HiSilicon Kunpeng DMA controller driver"); 105262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 105362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, hisi_dma_pci_tbl); 1054