1d1dfe5b8SDave Jiang // SPDX-License-Identifier: GPL-2.0 2d1dfe5b8SDave Jiang /* Copyright(c) 2019 Intel Corporation. All rights rsvd. */ 3d1dfe5b8SDave Jiang #include <linux/init.h> 4d1dfe5b8SDave Jiang #include <linux/kernel.h> 5d1dfe5b8SDave Jiang #include <linux/module.h> 6d1dfe5b8SDave Jiang #include <linux/pci.h> 7d1dfe5b8SDave Jiang #include <uapi/linux/idxd.h> 8d1dfe5b8SDave Jiang #include "idxd.h" 9d1dfe5b8SDave Jiang #include "registers.h" 10d1dfe5b8SDave Jiang 11d1dfe5b8SDave Jiang struct idxd_desc *idxd_alloc_desc(struct idxd_wq *wq, enum idxd_op_type optype) 12d1dfe5b8SDave Jiang { 13d1dfe5b8SDave Jiang struct idxd_desc *desc; 14d1dfe5b8SDave Jiang int idx; 15d1dfe5b8SDave Jiang struct idxd_device *idxd = wq->idxd; 16d1dfe5b8SDave Jiang 17d1dfe5b8SDave Jiang if (idxd->state != IDXD_DEV_ENABLED) 18d1dfe5b8SDave Jiang return ERR_PTR(-EIO); 19d1dfe5b8SDave Jiang 20d1dfe5b8SDave Jiang if (optype == IDXD_OP_BLOCK) 21d1dfe5b8SDave Jiang percpu_down_read(&wq->submit_lock); 22d1dfe5b8SDave Jiang else if (!percpu_down_read_trylock(&wq->submit_lock)) 23d1dfe5b8SDave Jiang return ERR_PTR(-EBUSY); 24d1dfe5b8SDave Jiang 25d1dfe5b8SDave Jiang if (!atomic_add_unless(&wq->dq_count, 1, wq->size)) { 26d1dfe5b8SDave Jiang int rc; 27d1dfe5b8SDave Jiang 28d1dfe5b8SDave Jiang if (optype == IDXD_OP_NONBLOCK) { 29d1dfe5b8SDave Jiang percpu_up_read(&wq->submit_lock); 30d1dfe5b8SDave Jiang return ERR_PTR(-EAGAIN); 31d1dfe5b8SDave Jiang } 32d1dfe5b8SDave Jiang 33d1dfe5b8SDave Jiang percpu_up_read(&wq->submit_lock); 34d1dfe5b8SDave Jiang percpu_down_write(&wq->submit_lock); 35d1dfe5b8SDave Jiang rc = wait_event_interruptible(wq->submit_waitq, 36d1dfe5b8SDave Jiang atomic_add_unless(&wq->dq_count, 37d1dfe5b8SDave Jiang 1, wq->size) || 38d1dfe5b8SDave Jiang idxd->state != IDXD_DEV_ENABLED); 39d1dfe5b8SDave Jiang percpu_up_write(&wq->submit_lock); 40d1dfe5b8SDave Jiang if (rc < 0) 41d1dfe5b8SDave Jiang return ERR_PTR(-EINTR); 42d1dfe5b8SDave Jiang if (idxd->state != IDXD_DEV_ENABLED) 43d1dfe5b8SDave Jiang return ERR_PTR(-EIO); 44d1dfe5b8SDave Jiang } else { 45d1dfe5b8SDave Jiang percpu_up_read(&wq->submit_lock); 46d1dfe5b8SDave Jiang } 47d1dfe5b8SDave Jiang 48d1dfe5b8SDave Jiang idx = sbitmap_get(&wq->sbmap, 0, false); 49d1dfe5b8SDave Jiang if (idx < 0) { 50d1dfe5b8SDave Jiang atomic_dec(&wq->dq_count); 51d1dfe5b8SDave Jiang return ERR_PTR(-EAGAIN); 52d1dfe5b8SDave Jiang } 53d1dfe5b8SDave Jiang 54d1dfe5b8SDave Jiang desc = wq->descs[idx]; 55d1dfe5b8SDave Jiang memset(desc->hw, 0, sizeof(struct dsa_hw_desc)); 56d1dfe5b8SDave Jiang memset(desc->completion, 0, sizeof(struct dsa_completion_record)); 57d1dfe5b8SDave Jiang return desc; 58d1dfe5b8SDave Jiang } 59d1dfe5b8SDave Jiang 60d1dfe5b8SDave Jiang void idxd_free_desc(struct idxd_wq *wq, struct idxd_desc *desc) 61d1dfe5b8SDave Jiang { 62d1dfe5b8SDave Jiang atomic_dec(&wq->dq_count); 63d1dfe5b8SDave Jiang 64d1dfe5b8SDave Jiang sbitmap_clear_bit(&wq->sbmap, desc->id); 65d1dfe5b8SDave Jiang wake_up(&wq->submit_waitq); 66d1dfe5b8SDave Jiang } 67d1dfe5b8SDave Jiang 68d1dfe5b8SDave Jiang int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc) 69d1dfe5b8SDave Jiang { 70d1dfe5b8SDave Jiang struct idxd_device *idxd = wq->idxd; 71d1dfe5b8SDave Jiang int vec = desc->hw->int_handle; 72*42d279f9SDave Jiang void __iomem *portal; 73d1dfe5b8SDave Jiang 74d1dfe5b8SDave Jiang if (idxd->state != IDXD_DEV_ENABLED) 75d1dfe5b8SDave Jiang return -EIO; 76d1dfe5b8SDave Jiang 77*42d279f9SDave Jiang portal = wq->dportal + idxd_get_wq_portal_offset(IDXD_PORTAL_UNLIMITED); 78d1dfe5b8SDave Jiang /* 79d1dfe5b8SDave Jiang * The wmb() flushes writes to coherent DMA data before possibly 80d1dfe5b8SDave Jiang * triggering a DMA read. The wmb() is necessary even on UP because 81d1dfe5b8SDave Jiang * the recipient is a device. 82d1dfe5b8SDave Jiang */ 83d1dfe5b8SDave Jiang wmb(); 84*42d279f9SDave Jiang iosubmit_cmds512(portal, desc->hw, 1); 85d1dfe5b8SDave Jiang 86d1dfe5b8SDave Jiang /* 87d1dfe5b8SDave Jiang * Pending the descriptor to the lockless list for the irq_entry 88d1dfe5b8SDave Jiang * that we designated the descriptor to. 89d1dfe5b8SDave Jiang */ 908f47d1a5SDave Jiang if (desc->hw->flags & IDXD_OP_FLAG_RCI) 918f47d1a5SDave Jiang llist_add(&desc->llnode, 928f47d1a5SDave Jiang &idxd->irq_entries[vec].pending_llist); 93d1dfe5b8SDave Jiang 94d1dfe5b8SDave Jiang return 0; 95d1dfe5b8SDave Jiang } 96