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