1e9f08b65SZhou Wang // SPDX-License-Identifier: GPL-2.0-only 2e9f08b65SZhou Wang /* Copyright(c) 2019 HiSilicon Limited. */ 3e9f08b65SZhou Wang #include <linux/bitfield.h> 4e9f08b65SZhou Wang #include <linux/dmaengine.h> 5e9f08b65SZhou Wang #include <linux/init.h> 6e9f08b65SZhou Wang #include <linux/iopoll.h> 7e9f08b65SZhou Wang #include <linux/module.h> 8e9f08b65SZhou Wang #include <linux/pci.h> 9e9f08b65SZhou Wang #include <linux/spinlock.h> 10e9f08b65SZhou Wang #include "virt-dma.h" 11e9f08b65SZhou Wang 12e9f08b65SZhou Wang #define HISI_DMA_SQ_BASE_L 0x0 13e9f08b65SZhou Wang #define HISI_DMA_SQ_BASE_H 0x4 14e9f08b65SZhou Wang #define HISI_DMA_SQ_DEPTH 0x8 15e9f08b65SZhou Wang #define HISI_DMA_SQ_TAIL_PTR 0xc 16e9f08b65SZhou Wang #define HISI_DMA_CQ_BASE_L 0x10 17e9f08b65SZhou Wang #define HISI_DMA_CQ_BASE_H 0x14 18e9f08b65SZhou Wang #define HISI_DMA_CQ_DEPTH 0x18 19e9f08b65SZhou Wang #define HISI_DMA_CQ_HEAD_PTR 0x1c 20e9f08b65SZhou Wang #define HISI_DMA_CTRL0 0x20 21e9f08b65SZhou Wang #define HISI_DMA_CTRL0_QUEUE_EN_S 0 22e9f08b65SZhou Wang #define HISI_DMA_CTRL0_QUEUE_PAUSE_S 4 23e9f08b65SZhou Wang #define HISI_DMA_CTRL1 0x24 24e9f08b65SZhou Wang #define HISI_DMA_CTRL1_QUEUE_RESET_S 0 25e9f08b65SZhou Wang #define HISI_DMA_Q_FSM_STS 0x30 26e9f08b65SZhou Wang #define HISI_DMA_FSM_STS_MASK GENMASK(3, 0) 27e9f08b65SZhou Wang #define HISI_DMA_INT_STS 0x40 28e9f08b65SZhou Wang #define HISI_DMA_INT_STS_MASK GENMASK(12, 0) 29e9f08b65SZhou Wang #define HISI_DMA_INT_MSK 0x44 30e9f08b65SZhou Wang #define HISI_DMA_MODE 0x217c 31e9f08b65SZhou Wang #define HISI_DMA_OFFSET 0x100 32e9f08b65SZhou Wang 33e9f08b65SZhou Wang #define HISI_DMA_MSI_NUM 30 34e9f08b65SZhou Wang #define HISI_DMA_CHAN_NUM 30 35e9f08b65SZhou Wang #define HISI_DMA_Q_DEPTH_VAL 1024 36e9f08b65SZhou Wang 37e9f08b65SZhou Wang #define PCI_BAR_2 2 38e9f08b65SZhou Wang 39e9f08b65SZhou Wang enum hisi_dma_mode { 40e9f08b65SZhou Wang EP = 0, 41e9f08b65SZhou Wang RC, 42e9f08b65SZhou Wang }; 43e9f08b65SZhou Wang 44e9f08b65SZhou Wang enum hisi_dma_chan_status { 45e9f08b65SZhou Wang DISABLE = -1, 46e9f08b65SZhou Wang IDLE = 0, 47e9f08b65SZhou Wang RUN, 48e9f08b65SZhou Wang CPL, 49e9f08b65SZhou Wang PAUSE, 50e9f08b65SZhou Wang HALT, 51e9f08b65SZhou Wang ABORT, 52e9f08b65SZhou Wang WAIT, 53e9f08b65SZhou Wang BUFFCLR, 54e9f08b65SZhou Wang }; 55e9f08b65SZhou Wang 56e9f08b65SZhou Wang struct hisi_dma_sqe { 57e9f08b65SZhou Wang __le32 dw0; 58e9f08b65SZhou Wang #define OPCODE_MASK GENMASK(3, 0) 59e9f08b65SZhou Wang #define OPCODE_SMALL_PACKAGE 0x1 60e9f08b65SZhou Wang #define OPCODE_M2M 0x4 61e9f08b65SZhou Wang #define LOCAL_IRQ_EN BIT(8) 62e9f08b65SZhou Wang #define ATTR_SRC_MASK GENMASK(14, 12) 63e9f08b65SZhou Wang __le32 dw1; 64e9f08b65SZhou Wang __le32 dw2; 65e9f08b65SZhou Wang #define ATTR_DST_MASK GENMASK(26, 24) 66e9f08b65SZhou Wang __le32 length; 67e9f08b65SZhou Wang __le64 src_addr; 68e9f08b65SZhou Wang __le64 dst_addr; 69e9f08b65SZhou Wang }; 70e9f08b65SZhou Wang 71e9f08b65SZhou Wang struct hisi_dma_cqe { 72e9f08b65SZhou Wang __le32 rsv0; 73e9f08b65SZhou Wang __le32 rsv1; 74e9f08b65SZhou Wang __le16 sq_head; 75e9f08b65SZhou Wang __le16 rsv2; 76e9f08b65SZhou Wang __le16 rsv3; 77e9f08b65SZhou Wang __le16 w0; 78e9f08b65SZhou Wang #define STATUS_MASK GENMASK(15, 1) 79e9f08b65SZhou Wang #define STATUS_SUCC 0x0 80e9f08b65SZhou Wang #define VALID_BIT BIT(0) 81e9f08b65SZhou Wang }; 82e9f08b65SZhou Wang 83e9f08b65SZhou Wang struct hisi_dma_desc { 84e9f08b65SZhou Wang struct virt_dma_desc vd; 85e9f08b65SZhou Wang struct hisi_dma_sqe sqe; 86e9f08b65SZhou Wang }; 87e9f08b65SZhou Wang 88e9f08b65SZhou Wang struct hisi_dma_chan { 89e9f08b65SZhou Wang struct virt_dma_chan vc; 90e9f08b65SZhou Wang struct hisi_dma_dev *hdma_dev; 91e9f08b65SZhou Wang struct hisi_dma_sqe *sq; 92e9f08b65SZhou Wang struct hisi_dma_cqe *cq; 93e9f08b65SZhou Wang dma_addr_t sq_dma; 94e9f08b65SZhou Wang dma_addr_t cq_dma; 95e9f08b65SZhou Wang u32 sq_tail; 96e9f08b65SZhou Wang u32 cq_head; 97e9f08b65SZhou Wang u32 qp_num; 98e9f08b65SZhou Wang enum hisi_dma_chan_status status; 99e9f08b65SZhou Wang struct hisi_dma_desc *desc; 100e9f08b65SZhou Wang }; 101e9f08b65SZhou Wang 102e9f08b65SZhou Wang struct hisi_dma_dev { 103e9f08b65SZhou Wang struct pci_dev *pdev; 104e9f08b65SZhou Wang void __iomem *base; 105e9f08b65SZhou Wang struct dma_device dma_dev; 106e9f08b65SZhou Wang u32 chan_num; 107e9f08b65SZhou Wang u32 chan_depth; 108e9f08b65SZhou Wang struct hisi_dma_chan chan[]; 109e9f08b65SZhou Wang }; 110e9f08b65SZhou Wang 111e9f08b65SZhou Wang static inline struct hisi_dma_chan *to_hisi_dma_chan(struct dma_chan *c) 112e9f08b65SZhou Wang { 113e9f08b65SZhou Wang return container_of(c, struct hisi_dma_chan, vc.chan); 114e9f08b65SZhou Wang } 115e9f08b65SZhou Wang 116e9f08b65SZhou Wang static inline struct hisi_dma_desc *to_hisi_dma_desc(struct virt_dma_desc *vd) 117e9f08b65SZhou Wang { 118e9f08b65SZhou Wang return container_of(vd, struct hisi_dma_desc, vd); 119e9f08b65SZhou Wang } 120e9f08b65SZhou Wang 121e9f08b65SZhou Wang static inline void hisi_dma_chan_write(void __iomem *base, u32 reg, u32 index, 122e9f08b65SZhou Wang u32 val) 123e9f08b65SZhou Wang { 124e9f08b65SZhou Wang writel_relaxed(val, base + reg + index * HISI_DMA_OFFSET); 125e9f08b65SZhou Wang } 126e9f08b65SZhou Wang 127e9f08b65SZhou Wang static inline void hisi_dma_update_bit(void __iomem *addr, u32 pos, bool val) 128e9f08b65SZhou Wang { 129e9f08b65SZhou Wang u32 tmp; 130e9f08b65SZhou Wang 131e9f08b65SZhou Wang tmp = readl_relaxed(addr); 132e9f08b65SZhou Wang tmp = val ? tmp | BIT(pos) : tmp & ~BIT(pos); 133e9f08b65SZhou Wang writel_relaxed(tmp, addr); 134e9f08b65SZhou Wang } 135e9f08b65SZhou Wang 136e9f08b65SZhou Wang static void hisi_dma_free_irq_vectors(void *data) 137e9f08b65SZhou Wang { 138e9f08b65SZhou Wang pci_free_irq_vectors(data); 139e9f08b65SZhou Wang } 140e9f08b65SZhou Wang 141e9f08b65SZhou Wang static void hisi_dma_pause_dma(struct hisi_dma_dev *hdma_dev, u32 index, 142e9f08b65SZhou Wang bool pause) 143e9f08b65SZhou Wang { 144e9f08b65SZhou Wang void __iomem *addr = hdma_dev->base + HISI_DMA_CTRL0 + index * 145e9f08b65SZhou Wang HISI_DMA_OFFSET; 146e9f08b65SZhou Wang 147e9f08b65SZhou Wang hisi_dma_update_bit(addr, HISI_DMA_CTRL0_QUEUE_PAUSE_S, pause); 148e9f08b65SZhou Wang } 149e9f08b65SZhou Wang 150e9f08b65SZhou Wang static void hisi_dma_enable_dma(struct hisi_dma_dev *hdma_dev, u32 index, 151e9f08b65SZhou Wang bool enable) 152e9f08b65SZhou Wang { 153e9f08b65SZhou Wang void __iomem *addr = hdma_dev->base + HISI_DMA_CTRL0 + index * 154e9f08b65SZhou Wang HISI_DMA_OFFSET; 155e9f08b65SZhou Wang 156e9f08b65SZhou Wang hisi_dma_update_bit(addr, HISI_DMA_CTRL0_QUEUE_EN_S, enable); 157e9f08b65SZhou Wang } 158e9f08b65SZhou Wang 159e9f08b65SZhou Wang static void hisi_dma_mask_irq(struct hisi_dma_dev *hdma_dev, u32 qp_index) 160e9f08b65SZhou Wang { 161e9f08b65SZhou Wang hisi_dma_chan_write(hdma_dev->base, HISI_DMA_INT_MSK, qp_index, 162e9f08b65SZhou Wang HISI_DMA_INT_STS_MASK); 163e9f08b65SZhou Wang } 164e9f08b65SZhou Wang 165e9f08b65SZhou Wang static void hisi_dma_unmask_irq(struct hisi_dma_dev *hdma_dev, u32 qp_index) 166e9f08b65SZhou Wang { 167e9f08b65SZhou Wang void __iomem *base = hdma_dev->base; 168e9f08b65SZhou Wang 169e9f08b65SZhou Wang hisi_dma_chan_write(base, HISI_DMA_INT_STS, qp_index, 170e9f08b65SZhou Wang HISI_DMA_INT_STS_MASK); 171e9f08b65SZhou Wang hisi_dma_chan_write(base, HISI_DMA_INT_MSK, qp_index, 0); 172e9f08b65SZhou Wang } 173e9f08b65SZhou Wang 174e9f08b65SZhou Wang static void hisi_dma_do_reset(struct hisi_dma_dev *hdma_dev, u32 index) 175e9f08b65SZhou Wang { 176e9f08b65SZhou Wang void __iomem *addr = hdma_dev->base + HISI_DMA_CTRL1 + index * 177e9f08b65SZhou Wang HISI_DMA_OFFSET; 178e9f08b65SZhou Wang 179e9f08b65SZhou Wang hisi_dma_update_bit(addr, HISI_DMA_CTRL1_QUEUE_RESET_S, 1); 180e9f08b65SZhou Wang } 181e9f08b65SZhou Wang 182e9f08b65SZhou Wang static void hisi_dma_reset_qp_point(struct hisi_dma_dev *hdma_dev, u32 index) 183e9f08b65SZhou Wang { 184e9f08b65SZhou Wang hisi_dma_chan_write(hdma_dev->base, HISI_DMA_SQ_TAIL_PTR, index, 0); 185e9f08b65SZhou Wang hisi_dma_chan_write(hdma_dev->base, HISI_DMA_CQ_HEAD_PTR, index, 0); 186e9f08b65SZhou Wang } 187e9f08b65SZhou Wang 188e9f08b65SZhou Wang static void hisi_dma_reset_hw_chan(struct hisi_dma_chan *chan) 189e9f08b65SZhou Wang { 190e9f08b65SZhou Wang struct hisi_dma_dev *hdma_dev = chan->hdma_dev; 191e9f08b65SZhou Wang u32 index = chan->qp_num, tmp; 192e9f08b65SZhou Wang int ret; 193e9f08b65SZhou Wang 194e9f08b65SZhou Wang hisi_dma_pause_dma(hdma_dev, index, true); 195e9f08b65SZhou Wang hisi_dma_enable_dma(hdma_dev, index, false); 196e9f08b65SZhou Wang hisi_dma_mask_irq(hdma_dev, index); 197e9f08b65SZhou Wang 198e9f08b65SZhou Wang ret = readl_relaxed_poll_timeout(hdma_dev->base + 199e9f08b65SZhou Wang HISI_DMA_Q_FSM_STS + index * HISI_DMA_OFFSET, tmp, 200e9f08b65SZhou Wang FIELD_GET(HISI_DMA_FSM_STS_MASK, tmp) != RUN, 10, 1000); 201e9f08b65SZhou Wang if (ret) { 202e9f08b65SZhou Wang dev_err(&hdma_dev->pdev->dev, "disable channel timeout!\n"); 203e9f08b65SZhou Wang WARN_ON(1); 204e9f08b65SZhou Wang } 205e9f08b65SZhou Wang 206e9f08b65SZhou Wang hisi_dma_do_reset(hdma_dev, index); 207e9f08b65SZhou Wang hisi_dma_reset_qp_point(hdma_dev, index); 208e9f08b65SZhou Wang hisi_dma_pause_dma(hdma_dev, index, false); 209e9f08b65SZhou Wang hisi_dma_enable_dma(hdma_dev, index, true); 210e9f08b65SZhou Wang hisi_dma_unmask_irq(hdma_dev, index); 211e9f08b65SZhou Wang 212e9f08b65SZhou Wang ret = readl_relaxed_poll_timeout(hdma_dev->base + 213e9f08b65SZhou Wang HISI_DMA_Q_FSM_STS + index * HISI_DMA_OFFSET, tmp, 214e9f08b65SZhou Wang FIELD_GET(HISI_DMA_FSM_STS_MASK, tmp) == IDLE, 10, 1000); 215e9f08b65SZhou Wang if (ret) { 216e9f08b65SZhou Wang dev_err(&hdma_dev->pdev->dev, "reset channel timeout!\n"); 217e9f08b65SZhou Wang WARN_ON(1); 218e9f08b65SZhou Wang } 219e9f08b65SZhou Wang } 220e9f08b65SZhou Wang 221e9f08b65SZhou Wang static void hisi_dma_free_chan_resources(struct dma_chan *c) 222e9f08b65SZhou Wang { 223e9f08b65SZhou Wang struct hisi_dma_chan *chan = to_hisi_dma_chan(c); 224e9f08b65SZhou Wang struct hisi_dma_dev *hdma_dev = chan->hdma_dev; 225e9f08b65SZhou Wang 226e9f08b65SZhou Wang hisi_dma_reset_hw_chan(chan); 227e9f08b65SZhou Wang vchan_free_chan_resources(&chan->vc); 228e9f08b65SZhou Wang 229e9f08b65SZhou Wang memset(chan->sq, 0, sizeof(struct hisi_dma_sqe) * hdma_dev->chan_depth); 230e9f08b65SZhou Wang memset(chan->cq, 0, sizeof(struct hisi_dma_cqe) * hdma_dev->chan_depth); 231e9f08b65SZhou Wang chan->sq_tail = 0; 232e9f08b65SZhou Wang chan->cq_head = 0; 233e9f08b65SZhou Wang chan->status = DISABLE; 234e9f08b65SZhou Wang } 235e9f08b65SZhou Wang 236e9f08b65SZhou Wang static void hisi_dma_desc_free(struct virt_dma_desc *vd) 237e9f08b65SZhou Wang { 238e9f08b65SZhou Wang kfree(to_hisi_dma_desc(vd)); 239e9f08b65SZhou Wang } 240e9f08b65SZhou Wang 241e9f08b65SZhou Wang static struct dma_async_tx_descriptor * 242e9f08b65SZhou Wang hisi_dma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dst, dma_addr_t src, 243e9f08b65SZhou Wang size_t len, unsigned long flags) 244e9f08b65SZhou Wang { 245e9f08b65SZhou Wang struct hisi_dma_chan *chan = to_hisi_dma_chan(c); 246e9f08b65SZhou Wang struct hisi_dma_desc *desc; 247e9f08b65SZhou Wang 248e9f08b65SZhou Wang desc = kzalloc(sizeof(*desc), GFP_NOWAIT); 249e9f08b65SZhou Wang if (!desc) 250e9f08b65SZhou Wang return NULL; 251e9f08b65SZhou Wang 252e9f08b65SZhou Wang desc->sqe.length = cpu_to_le32(len); 253e9f08b65SZhou Wang desc->sqe.src_addr = cpu_to_le64(src); 254e9f08b65SZhou Wang desc->sqe.dst_addr = cpu_to_le64(dst); 255e9f08b65SZhou Wang 256e9f08b65SZhou Wang return vchan_tx_prep(&chan->vc, &desc->vd, flags); 257e9f08b65SZhou Wang } 258e9f08b65SZhou Wang 259e9f08b65SZhou Wang static enum dma_status 260e9f08b65SZhou Wang hisi_dma_tx_status(struct dma_chan *c, dma_cookie_t cookie, 261e9f08b65SZhou Wang struct dma_tx_state *txstate) 262e9f08b65SZhou Wang { 263e9f08b65SZhou Wang return dma_cookie_status(c, cookie, txstate); 264e9f08b65SZhou Wang } 265e9f08b65SZhou Wang 266e9f08b65SZhou Wang static void hisi_dma_start_transfer(struct hisi_dma_chan *chan) 267e9f08b65SZhou Wang { 268e9f08b65SZhou Wang struct hisi_dma_sqe *sqe = chan->sq + chan->sq_tail; 269e9f08b65SZhou Wang struct hisi_dma_dev *hdma_dev = chan->hdma_dev; 270e9f08b65SZhou Wang struct hisi_dma_desc *desc; 271e9f08b65SZhou Wang struct virt_dma_desc *vd; 272e9f08b65SZhou Wang 273e9f08b65SZhou Wang vd = vchan_next_desc(&chan->vc); 274e9f08b65SZhou Wang if (!vd) { 275e9f08b65SZhou Wang dev_err(&hdma_dev->pdev->dev, "no issued task!\n"); 276e9f08b65SZhou Wang chan->desc = NULL; 277e9f08b65SZhou Wang return; 278e9f08b65SZhou Wang } 279e9f08b65SZhou Wang list_del(&vd->node); 280e9f08b65SZhou Wang desc = to_hisi_dma_desc(vd); 281e9f08b65SZhou Wang chan->desc = desc; 282e9f08b65SZhou Wang 283e9f08b65SZhou Wang memcpy(sqe, &desc->sqe, sizeof(struct hisi_dma_sqe)); 284e9f08b65SZhou Wang 285e9f08b65SZhou Wang /* update other field in sqe */ 286e9f08b65SZhou Wang sqe->dw0 = cpu_to_le32(FIELD_PREP(OPCODE_MASK, OPCODE_M2M)); 287e9f08b65SZhou Wang sqe->dw0 |= cpu_to_le32(LOCAL_IRQ_EN); 288e9f08b65SZhou Wang 289e9f08b65SZhou Wang /* make sure data has been updated in sqe */ 290e9f08b65SZhou Wang wmb(); 291e9f08b65SZhou Wang 292e9f08b65SZhou Wang /* update sq tail, point to new sqe position */ 293e9f08b65SZhou Wang chan->sq_tail = (chan->sq_tail + 1) % hdma_dev->chan_depth; 294e9f08b65SZhou Wang 295e9f08b65SZhou Wang /* update sq_tail to trigger a new task */ 296e9f08b65SZhou Wang hisi_dma_chan_write(hdma_dev->base, HISI_DMA_SQ_TAIL_PTR, chan->qp_num, 297e9f08b65SZhou Wang chan->sq_tail); 298e9f08b65SZhou Wang } 299e9f08b65SZhou Wang 300e9f08b65SZhou Wang static void hisi_dma_issue_pending(struct dma_chan *c) 301e9f08b65SZhou Wang { 302e9f08b65SZhou Wang struct hisi_dma_chan *chan = to_hisi_dma_chan(c); 303e9f08b65SZhou Wang unsigned long flags; 304e9f08b65SZhou Wang 305e9f08b65SZhou Wang spin_lock_irqsave(&chan->vc.lock, flags); 306e9f08b65SZhou Wang 307e9f08b65SZhou Wang if (vchan_issue_pending(&chan->vc)) 308e9f08b65SZhou Wang hisi_dma_start_transfer(chan); 309e9f08b65SZhou Wang 310e9f08b65SZhou Wang spin_unlock_irqrestore(&chan->vc.lock, flags); 311e9f08b65SZhou Wang } 312e9f08b65SZhou Wang 313e9f08b65SZhou Wang static int hisi_dma_terminate_all(struct dma_chan *c) 314e9f08b65SZhou Wang { 315e9f08b65SZhou Wang struct hisi_dma_chan *chan = to_hisi_dma_chan(c); 316e9f08b65SZhou Wang unsigned long flags; 317e9f08b65SZhou Wang LIST_HEAD(head); 318e9f08b65SZhou Wang 319e9f08b65SZhou Wang spin_lock_irqsave(&chan->vc.lock, flags); 320e9f08b65SZhou Wang 321e9f08b65SZhou Wang hisi_dma_pause_dma(chan->hdma_dev, chan->qp_num, true); 322e9f08b65SZhou Wang if (chan->desc) { 323e9f08b65SZhou Wang vchan_terminate_vdesc(&chan->desc->vd); 324e9f08b65SZhou Wang chan->desc = NULL; 325e9f08b65SZhou Wang } 326e9f08b65SZhou Wang 327e9f08b65SZhou Wang vchan_get_all_descriptors(&chan->vc, &head); 328e9f08b65SZhou Wang 329e9f08b65SZhou Wang spin_unlock_irqrestore(&chan->vc.lock, flags); 330e9f08b65SZhou Wang 331e9f08b65SZhou Wang vchan_dma_desc_free_list(&chan->vc, &head); 332e9f08b65SZhou Wang hisi_dma_pause_dma(chan->hdma_dev, chan->qp_num, false); 333e9f08b65SZhou Wang 334e9f08b65SZhou Wang return 0; 335e9f08b65SZhou Wang } 336e9f08b65SZhou Wang 337e9f08b65SZhou Wang static void hisi_dma_synchronize(struct dma_chan *c) 338e9f08b65SZhou Wang { 339e9f08b65SZhou Wang struct hisi_dma_chan *chan = to_hisi_dma_chan(c); 340e9f08b65SZhou Wang 341e9f08b65SZhou Wang vchan_synchronize(&chan->vc); 342e9f08b65SZhou Wang } 343e9f08b65SZhou Wang 344e9f08b65SZhou Wang static int hisi_dma_alloc_qps_mem(struct hisi_dma_dev *hdma_dev) 345e9f08b65SZhou Wang { 346e9f08b65SZhou Wang size_t sq_size = sizeof(struct hisi_dma_sqe) * hdma_dev->chan_depth; 347e9f08b65SZhou Wang size_t cq_size = sizeof(struct hisi_dma_cqe) * hdma_dev->chan_depth; 348e9f08b65SZhou Wang struct device *dev = &hdma_dev->pdev->dev; 349e9f08b65SZhou Wang struct hisi_dma_chan *chan; 350e9f08b65SZhou Wang int i; 351e9f08b65SZhou Wang 352e9f08b65SZhou Wang for (i = 0; i < hdma_dev->chan_num; i++) { 353e9f08b65SZhou Wang chan = &hdma_dev->chan[i]; 354e9f08b65SZhou Wang chan->sq = dmam_alloc_coherent(dev, sq_size, &chan->sq_dma, 355e9f08b65SZhou Wang GFP_KERNEL); 356e9f08b65SZhou Wang if (!chan->sq) 357e9f08b65SZhou Wang return -ENOMEM; 358e9f08b65SZhou Wang 359e9f08b65SZhou Wang chan->cq = dmam_alloc_coherent(dev, cq_size, &chan->cq_dma, 360e9f08b65SZhou Wang GFP_KERNEL); 361e9f08b65SZhou Wang if (!chan->cq) 362e9f08b65SZhou Wang return -ENOMEM; 363e9f08b65SZhou Wang } 364e9f08b65SZhou Wang 365e9f08b65SZhou Wang return 0; 366e9f08b65SZhou Wang } 367e9f08b65SZhou Wang 368e9f08b65SZhou Wang static void hisi_dma_init_hw_qp(struct hisi_dma_dev *hdma_dev, u32 index) 369e9f08b65SZhou Wang { 370e9f08b65SZhou Wang struct hisi_dma_chan *chan = &hdma_dev->chan[index]; 371e9f08b65SZhou Wang u32 hw_depth = hdma_dev->chan_depth - 1; 372e9f08b65SZhou Wang void __iomem *base = hdma_dev->base; 373e9f08b65SZhou Wang 374e9f08b65SZhou Wang /* set sq, cq base */ 375e9f08b65SZhou Wang hisi_dma_chan_write(base, HISI_DMA_SQ_BASE_L, index, 376e9f08b65SZhou Wang lower_32_bits(chan->sq_dma)); 377e9f08b65SZhou Wang hisi_dma_chan_write(base, HISI_DMA_SQ_BASE_H, index, 378e9f08b65SZhou Wang upper_32_bits(chan->sq_dma)); 379e9f08b65SZhou Wang hisi_dma_chan_write(base, HISI_DMA_CQ_BASE_L, index, 380e9f08b65SZhou Wang lower_32_bits(chan->cq_dma)); 381e9f08b65SZhou Wang hisi_dma_chan_write(base, HISI_DMA_CQ_BASE_H, index, 382e9f08b65SZhou Wang upper_32_bits(chan->cq_dma)); 383e9f08b65SZhou Wang 384e9f08b65SZhou Wang /* set sq, cq depth */ 385e9f08b65SZhou Wang hisi_dma_chan_write(base, HISI_DMA_SQ_DEPTH, index, hw_depth); 386e9f08b65SZhou Wang hisi_dma_chan_write(base, HISI_DMA_CQ_DEPTH, index, hw_depth); 387e9f08b65SZhou Wang 388e9f08b65SZhou Wang /* init sq tail and cq head */ 389e9f08b65SZhou Wang hisi_dma_chan_write(base, HISI_DMA_SQ_TAIL_PTR, index, 0); 390e9f08b65SZhou Wang hisi_dma_chan_write(base, HISI_DMA_CQ_HEAD_PTR, index, 0); 391e9f08b65SZhou Wang } 392e9f08b65SZhou Wang 393e9f08b65SZhou Wang static void hisi_dma_enable_qp(struct hisi_dma_dev *hdma_dev, u32 qp_index) 394e9f08b65SZhou Wang { 395e9f08b65SZhou Wang hisi_dma_init_hw_qp(hdma_dev, qp_index); 396e9f08b65SZhou Wang hisi_dma_unmask_irq(hdma_dev, qp_index); 397e9f08b65SZhou Wang hisi_dma_enable_dma(hdma_dev, qp_index, true); 398e9f08b65SZhou Wang } 399e9f08b65SZhou Wang 400e9f08b65SZhou Wang static void hisi_dma_disable_qp(struct hisi_dma_dev *hdma_dev, u32 qp_index) 401e9f08b65SZhou Wang { 402e9f08b65SZhou Wang hisi_dma_reset_hw_chan(&hdma_dev->chan[qp_index]); 403e9f08b65SZhou Wang } 404e9f08b65SZhou Wang 405e9f08b65SZhou Wang static void hisi_dma_enable_qps(struct hisi_dma_dev *hdma_dev) 406e9f08b65SZhou Wang { 407e9f08b65SZhou Wang int i; 408e9f08b65SZhou Wang 409e9f08b65SZhou Wang for (i = 0; i < hdma_dev->chan_num; i++) { 410e9f08b65SZhou Wang hdma_dev->chan[i].qp_num = i; 411e9f08b65SZhou Wang hdma_dev->chan[i].hdma_dev = hdma_dev; 412e9f08b65SZhou Wang hdma_dev->chan[i].vc.desc_free = hisi_dma_desc_free; 413e9f08b65SZhou Wang vchan_init(&hdma_dev->chan[i].vc, &hdma_dev->dma_dev); 414e9f08b65SZhou Wang hisi_dma_enable_qp(hdma_dev, i); 415e9f08b65SZhou Wang } 416e9f08b65SZhou Wang } 417e9f08b65SZhou Wang 418e9f08b65SZhou Wang static void hisi_dma_disable_qps(struct hisi_dma_dev *hdma_dev) 419e9f08b65SZhou Wang { 420e9f08b65SZhou Wang int i; 421e9f08b65SZhou Wang 422e9f08b65SZhou Wang for (i = 0; i < hdma_dev->chan_num; i++) { 423e9f08b65SZhou Wang hisi_dma_disable_qp(hdma_dev, i); 424e9f08b65SZhou Wang tasklet_kill(&hdma_dev->chan[i].vc.task); 425e9f08b65SZhou Wang } 426e9f08b65SZhou Wang } 427e9f08b65SZhou Wang 428e9f08b65SZhou Wang static irqreturn_t hisi_dma_irq(int irq, void *data) 429e9f08b65SZhou Wang { 430e9f08b65SZhou Wang struct hisi_dma_chan *chan = data; 431e9f08b65SZhou Wang struct hisi_dma_dev *hdma_dev = chan->hdma_dev; 432e9f08b65SZhou Wang struct hisi_dma_desc *desc; 433e9f08b65SZhou Wang struct hisi_dma_cqe *cqe; 434e9f08b65SZhou Wang 435*d9c8d4b2SBarry Song spin_lock(&chan->vc.lock); 436e9f08b65SZhou Wang 437e9f08b65SZhou Wang desc = chan->desc; 438e9f08b65SZhou Wang cqe = chan->cq + chan->cq_head; 439e9f08b65SZhou Wang if (desc) { 440e9f08b65SZhou Wang if (FIELD_GET(STATUS_MASK, cqe->w0) == STATUS_SUCC) { 441e9f08b65SZhou Wang chan->cq_head = (chan->cq_head + 1) % 442e9f08b65SZhou Wang hdma_dev->chan_depth; 443e9f08b65SZhou Wang hisi_dma_chan_write(hdma_dev->base, 444e9f08b65SZhou Wang HISI_DMA_CQ_HEAD_PTR, chan->qp_num, 445e9f08b65SZhou Wang chan->cq_head); 446e9f08b65SZhou Wang vchan_cookie_complete(&desc->vd); 447e9f08b65SZhou Wang } else { 448e9f08b65SZhou Wang dev_err(&hdma_dev->pdev->dev, "task error!\n"); 449e9f08b65SZhou Wang } 450e9f08b65SZhou Wang 451e9f08b65SZhou Wang chan->desc = NULL; 452e9f08b65SZhou Wang } 453e9f08b65SZhou Wang 454*d9c8d4b2SBarry Song spin_unlock(&chan->vc.lock); 455e9f08b65SZhou Wang 456e9f08b65SZhou Wang return IRQ_HANDLED; 457e9f08b65SZhou Wang } 458e9f08b65SZhou Wang 459e9f08b65SZhou Wang static int hisi_dma_request_qps_irq(struct hisi_dma_dev *hdma_dev) 460e9f08b65SZhou Wang { 461e9f08b65SZhou Wang struct pci_dev *pdev = hdma_dev->pdev; 462e9f08b65SZhou Wang int i, ret; 463e9f08b65SZhou Wang 464e9f08b65SZhou Wang for (i = 0; i < hdma_dev->chan_num; i++) { 465e9f08b65SZhou Wang ret = devm_request_irq(&pdev->dev, pci_irq_vector(pdev, i), 466e9f08b65SZhou Wang hisi_dma_irq, IRQF_SHARED, "hisi_dma", 467e9f08b65SZhou Wang &hdma_dev->chan[i]); 468e9f08b65SZhou Wang if (ret) 469e9f08b65SZhou Wang return ret; 470e9f08b65SZhou Wang } 471e9f08b65SZhou Wang 472e9f08b65SZhou Wang return 0; 473e9f08b65SZhou Wang } 474e9f08b65SZhou Wang 475e9f08b65SZhou Wang /* This function enables all hw channels in a device */ 476e9f08b65SZhou Wang static int hisi_dma_enable_hw_channels(struct hisi_dma_dev *hdma_dev) 477e9f08b65SZhou Wang { 478e9f08b65SZhou Wang int ret; 479e9f08b65SZhou Wang 480e9f08b65SZhou Wang ret = hisi_dma_alloc_qps_mem(hdma_dev); 481e9f08b65SZhou Wang if (ret) { 482e9f08b65SZhou Wang dev_err(&hdma_dev->pdev->dev, "fail to allocate qp memory!\n"); 483e9f08b65SZhou Wang return ret; 484e9f08b65SZhou Wang } 485e9f08b65SZhou Wang 486e9f08b65SZhou Wang ret = hisi_dma_request_qps_irq(hdma_dev); 487e9f08b65SZhou Wang if (ret) { 488e9f08b65SZhou Wang dev_err(&hdma_dev->pdev->dev, "fail to request qp irq!\n"); 489e9f08b65SZhou Wang return ret; 490e9f08b65SZhou Wang } 491e9f08b65SZhou Wang 492e9f08b65SZhou Wang hisi_dma_enable_qps(hdma_dev); 493e9f08b65SZhou Wang 494e9f08b65SZhou Wang return 0; 495e9f08b65SZhou Wang } 496e9f08b65SZhou Wang 497e9f08b65SZhou Wang static void hisi_dma_disable_hw_channels(void *data) 498e9f08b65SZhou Wang { 499e9f08b65SZhou Wang hisi_dma_disable_qps(data); 500e9f08b65SZhou Wang } 501e9f08b65SZhou Wang 502e9f08b65SZhou Wang static void hisi_dma_set_mode(struct hisi_dma_dev *hdma_dev, 503e9f08b65SZhou Wang enum hisi_dma_mode mode) 504e9f08b65SZhou Wang { 505e9f08b65SZhou Wang writel_relaxed(mode == RC ? 1 : 0, hdma_dev->base + HISI_DMA_MODE); 506e9f08b65SZhou Wang } 507e9f08b65SZhou Wang 508e9f08b65SZhou Wang static int hisi_dma_probe(struct pci_dev *pdev, const struct pci_device_id *id) 509e9f08b65SZhou Wang { 510e9f08b65SZhou Wang struct device *dev = &pdev->dev; 511e9f08b65SZhou Wang struct hisi_dma_dev *hdma_dev; 512e9f08b65SZhou Wang struct dma_device *dma_dev; 513e9f08b65SZhou Wang int ret; 514e9f08b65SZhou Wang 515e9f08b65SZhou Wang ret = pcim_enable_device(pdev); 516e9f08b65SZhou Wang if (ret) { 517e9f08b65SZhou Wang dev_err(dev, "failed to enable device mem!\n"); 518e9f08b65SZhou Wang return ret; 519e9f08b65SZhou Wang } 520e9f08b65SZhou Wang 521e9f08b65SZhou Wang ret = pcim_iomap_regions(pdev, 1 << PCI_BAR_2, pci_name(pdev)); 522e9f08b65SZhou Wang if (ret) { 523e9f08b65SZhou Wang dev_err(dev, "failed to remap I/O region!\n"); 524e9f08b65SZhou Wang return ret; 525e9f08b65SZhou Wang } 526e9f08b65SZhou Wang 527e9f08b65SZhou Wang ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); 528e9f08b65SZhou Wang if (ret) 529e9f08b65SZhou Wang return ret; 530e9f08b65SZhou Wang 531e9f08b65SZhou Wang ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); 532e9f08b65SZhou Wang if (ret) 533e9f08b65SZhou Wang return ret; 534e9f08b65SZhou Wang 535999a32efSGustavo A. R. Silva hdma_dev = devm_kzalloc(dev, struct_size(hdma_dev, chan, HISI_DMA_CHAN_NUM), GFP_KERNEL); 536e9f08b65SZhou Wang if (!hdma_dev) 537e9f08b65SZhou Wang return -EINVAL; 538e9f08b65SZhou Wang 539e9f08b65SZhou Wang hdma_dev->base = pcim_iomap_table(pdev)[PCI_BAR_2]; 540e9f08b65SZhou Wang hdma_dev->pdev = pdev; 541e9f08b65SZhou Wang hdma_dev->chan_num = HISI_DMA_CHAN_NUM; 542e9f08b65SZhou Wang hdma_dev->chan_depth = HISI_DMA_Q_DEPTH_VAL; 543e9f08b65SZhou Wang 544e9f08b65SZhou Wang pci_set_drvdata(pdev, hdma_dev); 545e9f08b65SZhou Wang pci_set_master(pdev); 546e9f08b65SZhou Wang 547e9f08b65SZhou Wang ret = pci_alloc_irq_vectors(pdev, HISI_DMA_MSI_NUM, HISI_DMA_MSI_NUM, 548e9f08b65SZhou Wang PCI_IRQ_MSI); 549e9f08b65SZhou Wang if (ret < 0) { 550e9f08b65SZhou Wang dev_err(dev, "Failed to allocate MSI vectors!\n"); 551e9f08b65SZhou Wang return ret; 552e9f08b65SZhou Wang } 553e9f08b65SZhou Wang 554e9f08b65SZhou Wang ret = devm_add_action_or_reset(dev, hisi_dma_free_irq_vectors, pdev); 555e9f08b65SZhou Wang if (ret) 556e9f08b65SZhou Wang return ret; 557e9f08b65SZhou Wang 558e9f08b65SZhou Wang dma_dev = &hdma_dev->dma_dev; 559e9f08b65SZhou Wang dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask); 560e9f08b65SZhou Wang dma_dev->device_free_chan_resources = hisi_dma_free_chan_resources; 561e9f08b65SZhou Wang dma_dev->device_prep_dma_memcpy = hisi_dma_prep_dma_memcpy; 562e9f08b65SZhou Wang dma_dev->device_tx_status = hisi_dma_tx_status; 563e9f08b65SZhou Wang dma_dev->device_issue_pending = hisi_dma_issue_pending; 564e9f08b65SZhou Wang dma_dev->device_terminate_all = hisi_dma_terminate_all; 565e9f08b65SZhou Wang dma_dev->device_synchronize = hisi_dma_synchronize; 566e9f08b65SZhou Wang dma_dev->directions = BIT(DMA_MEM_TO_MEM); 567e9f08b65SZhou Wang dma_dev->dev = dev; 568e9f08b65SZhou Wang INIT_LIST_HEAD(&dma_dev->channels); 569e9f08b65SZhou Wang 570e9f08b65SZhou Wang hisi_dma_set_mode(hdma_dev, RC); 571e9f08b65SZhou Wang 572e9f08b65SZhou Wang ret = hisi_dma_enable_hw_channels(hdma_dev); 573e9f08b65SZhou Wang if (ret < 0) { 574e9f08b65SZhou Wang dev_err(dev, "failed to enable hw channel!\n"); 575e9f08b65SZhou Wang return ret; 576e9f08b65SZhou Wang } 577e9f08b65SZhou Wang 578e9f08b65SZhou Wang ret = devm_add_action_or_reset(dev, hisi_dma_disable_hw_channels, 579e9f08b65SZhou Wang hdma_dev); 580e9f08b65SZhou Wang if (ret) 581e9f08b65SZhou Wang return ret; 582e9f08b65SZhou Wang 583e9f08b65SZhou Wang ret = dmaenginem_async_device_register(dma_dev); 584e9f08b65SZhou Wang if (ret < 0) 585e9f08b65SZhou Wang dev_err(dev, "failed to register device!\n"); 586e9f08b65SZhou Wang 587e9f08b65SZhou Wang return ret; 588e9f08b65SZhou Wang } 589e9f08b65SZhou Wang 590e9f08b65SZhou Wang static const struct pci_device_id hisi_dma_pci_tbl[] = { 591e9f08b65SZhou Wang { PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, 0xa122) }, 592e9f08b65SZhou Wang { 0, } 593e9f08b65SZhou Wang }; 594e9f08b65SZhou Wang 595e9f08b65SZhou Wang static struct pci_driver hisi_dma_pci_driver = { 596e9f08b65SZhou Wang .name = "hisi_dma", 597e9f08b65SZhou Wang .id_table = hisi_dma_pci_tbl, 598e9f08b65SZhou Wang .probe = hisi_dma_probe, 599e9f08b65SZhou Wang }; 600e9f08b65SZhou Wang 601e9f08b65SZhou Wang module_pci_driver(hisi_dma_pci_driver); 602e9f08b65SZhou Wang 603e9f08b65SZhou Wang MODULE_AUTHOR("Zhou Wang <wangzhou1@hisilicon.com>"); 604e9f08b65SZhou Wang MODULE_AUTHOR("Zhenfa Qiu <qiuzhenfa@hisilicon.com>"); 605e9f08b65SZhou Wang MODULE_DESCRIPTION("HiSilicon Kunpeng DMA controller driver"); 606e9f08b65SZhou Wang MODULE_LICENSE("GPL v2"); 607e9f08b65SZhou Wang MODULE_DEVICE_TABLE(pci, hisi_dma_pci_tbl); 608