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 110705107fSDave Jiang static struct idxd_desc *__get_desc(struct idxd_wq *wq, int idx, int cpu) 12d1dfe5b8SDave Jiang { 13d1dfe5b8SDave Jiang struct idxd_desc *desc; 148e50d392SDave Jiang struct idxd_device *idxd = wq->idxd; 15d1dfe5b8SDave Jiang 16d1dfe5b8SDave Jiang desc = wq->descs[idx]; 17d1dfe5b8SDave Jiang memset(desc->hw, 0, sizeof(struct dsa_hw_desc)); 18*435b512dSDave Jiang memset(desc->completion, 0, idxd->data->compl_size); 190705107fSDave Jiang desc->cpu = cpu; 208e50d392SDave Jiang 218e50d392SDave Jiang if (device_pasid_enabled(idxd)) 228e50d392SDave Jiang desc->hw->pasid = idxd->pasid; 238e50d392SDave Jiang 248e50d392SDave Jiang /* 258e50d392SDave Jiang * Descriptor completion vectors are 1-8 for MSIX. We will round 268e50d392SDave Jiang * robin through the 8 vectors. 278e50d392SDave Jiang */ 288e50d392SDave Jiang wq->vec_ptr = (wq->vec_ptr % idxd->num_wq_irqs) + 1; 298e50d392SDave Jiang desc->hw->int_handle = wq->vec_ptr; 30d1dfe5b8SDave Jiang return desc; 31d1dfe5b8SDave Jiang } 32d1dfe5b8SDave Jiang 330705107fSDave Jiang struct idxd_desc *idxd_alloc_desc(struct idxd_wq *wq, enum idxd_op_type optype) 340705107fSDave Jiang { 350705107fSDave Jiang int cpu, idx; 360705107fSDave Jiang struct idxd_device *idxd = wq->idxd; 370705107fSDave Jiang DEFINE_SBQ_WAIT(wait); 380705107fSDave Jiang struct sbq_wait_state *ws; 390705107fSDave Jiang struct sbitmap_queue *sbq; 400705107fSDave Jiang 410705107fSDave Jiang if (idxd->state != IDXD_DEV_ENABLED) 420705107fSDave Jiang return ERR_PTR(-EIO); 430705107fSDave Jiang 440705107fSDave Jiang sbq = &wq->sbq; 450705107fSDave Jiang idx = sbitmap_queue_get(sbq, &cpu); 460705107fSDave Jiang if (idx < 0) { 470705107fSDave Jiang if (optype == IDXD_OP_NONBLOCK) 480705107fSDave Jiang return ERR_PTR(-EAGAIN); 490705107fSDave Jiang } else { 500705107fSDave Jiang return __get_desc(wq, idx, cpu); 510705107fSDave Jiang } 520705107fSDave Jiang 530705107fSDave Jiang ws = &sbq->ws[0]; 540705107fSDave Jiang for (;;) { 550705107fSDave Jiang sbitmap_prepare_to_wait(sbq, ws, &wait, TASK_INTERRUPTIBLE); 560705107fSDave Jiang if (signal_pending_state(TASK_INTERRUPTIBLE, current)) 570705107fSDave Jiang break; 580705107fSDave Jiang idx = sbitmap_queue_get(sbq, &cpu); 590705107fSDave Jiang if (idx > 0) 600705107fSDave Jiang break; 610705107fSDave Jiang schedule(); 620705107fSDave Jiang } 630705107fSDave Jiang 640705107fSDave Jiang sbitmap_finish_wait(sbq, ws, &wait); 650705107fSDave Jiang if (idx < 0) 660705107fSDave Jiang return ERR_PTR(-EAGAIN); 670705107fSDave Jiang 680705107fSDave Jiang return __get_desc(wq, idx, cpu); 690705107fSDave Jiang } 700705107fSDave Jiang 71d1dfe5b8SDave Jiang void idxd_free_desc(struct idxd_wq *wq, struct idxd_desc *desc) 72d1dfe5b8SDave Jiang { 730705107fSDave Jiang int cpu = desc->cpu; 74d1dfe5b8SDave Jiang 750705107fSDave Jiang desc->cpu = -1; 760705107fSDave Jiang sbitmap_queue_clear(&wq->sbq, desc->id, cpu); 77d1dfe5b8SDave Jiang } 78d1dfe5b8SDave Jiang 79d1dfe5b8SDave Jiang int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc) 80d1dfe5b8SDave Jiang { 81d1dfe5b8SDave Jiang struct idxd_device *idxd = wq->idxd; 82d1dfe5b8SDave Jiang int vec = desc->hw->int_handle; 8342d279f9SDave Jiang void __iomem *portal; 848e50d392SDave Jiang int rc; 85d1dfe5b8SDave Jiang 86d1dfe5b8SDave Jiang if (idxd->state != IDXD_DEV_ENABLED) 87d1dfe5b8SDave Jiang return -EIO; 88d1dfe5b8SDave Jiang 896daa9043SLinus Torvalds portal = wq->portal; 908e50d392SDave Jiang 91d1dfe5b8SDave Jiang /* 928e50d392SDave Jiang * The wmb() flushes writes to coherent DMA data before 938e50d392SDave Jiang * possibly triggering a DMA read. The wmb() is necessary 948e50d392SDave Jiang * even on UP because the recipient is a device. 95d1dfe5b8SDave Jiang */ 96d1dfe5b8SDave Jiang wmb(); 978e50d392SDave Jiang if (wq_dedicated(wq)) { 9842d279f9SDave Jiang iosubmit_cmds512(portal, desc->hw, 1); 998e50d392SDave Jiang } else { 1008e50d392SDave Jiang /* 1018e50d392SDave Jiang * It's not likely that we would receive queue full rejection 1028e50d392SDave Jiang * since the descriptor allocation gates at wq size. If we 1038e50d392SDave Jiang * receive a -EAGAIN, that means something went wrong such as the 1048e50d392SDave Jiang * device is not accepting descriptor at all. 1058e50d392SDave Jiang */ 1068e50d392SDave Jiang rc = enqcmds(portal, desc->hw); 1078e50d392SDave Jiang if (rc < 0) 1088e50d392SDave Jiang return rc; 1098e50d392SDave Jiang } 110d1dfe5b8SDave Jiang 111d1dfe5b8SDave Jiang /* 112d1dfe5b8SDave Jiang * Pending the descriptor to the lockless list for the irq_entry 113d1dfe5b8SDave Jiang * that we designated the descriptor to. 114d1dfe5b8SDave Jiang */ 1158f47d1a5SDave Jiang if (desc->hw->flags & IDXD_OP_FLAG_RCI) 1168f47d1a5SDave Jiang llist_add(&desc->llnode, 1178f47d1a5SDave Jiang &idxd->irq_entries[vec].pending_llist); 118d1dfe5b8SDave Jiang 119d1dfe5b8SDave Jiang return 0; 120d1dfe5b8SDave Jiang } 121