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)); 18435b512dSDave 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 /* 25eb15e715SDave Jiang * Descriptor completion vectors are 1...N for MSIX. We will round 26eb15e715SDave Jiang * robin through the N vectors. 278e50d392SDave Jiang */ 288e50d392SDave Jiang wq->vec_ptr = (wq->vec_ptr % idxd->num_wq_irqs) + 1; 29eb15e715SDave Jiang if (!idxd->int_handles) { 308e50d392SDave Jiang desc->hw->int_handle = wq->vec_ptr; 31eb15e715SDave Jiang } else { 32eb15e715SDave Jiang desc->vector = wq->vec_ptr; 33eb15e715SDave Jiang /* 34eb15e715SDave Jiang * int_handles are only for descriptor completion. However for device 35eb15e715SDave Jiang * MSIX enumeration, vec 0 is used for misc interrupts. Therefore even 36eb15e715SDave Jiang * though we are rotating through 1...N for descriptor interrupts, we 37eb15e715SDave Jiang * need to acqurie the int_handles from 0..N-1. 38eb15e715SDave Jiang */ 39eb15e715SDave Jiang desc->hw->int_handle = idxd->int_handles[desc->vector - 1]; 40eb15e715SDave Jiang } 41eb15e715SDave Jiang 42d1dfe5b8SDave Jiang return desc; 43d1dfe5b8SDave Jiang } 44d1dfe5b8SDave Jiang 450705107fSDave Jiang struct idxd_desc *idxd_alloc_desc(struct idxd_wq *wq, enum idxd_op_type optype) 460705107fSDave Jiang { 470705107fSDave Jiang int cpu, idx; 480705107fSDave Jiang struct idxd_device *idxd = wq->idxd; 490705107fSDave Jiang DEFINE_SBQ_WAIT(wait); 500705107fSDave Jiang struct sbq_wait_state *ws; 510705107fSDave Jiang struct sbitmap_queue *sbq; 520705107fSDave Jiang 530705107fSDave Jiang if (idxd->state != IDXD_DEV_ENABLED) 540705107fSDave Jiang return ERR_PTR(-EIO); 550705107fSDave Jiang 560705107fSDave Jiang sbq = &wq->sbq; 570705107fSDave Jiang idx = sbitmap_queue_get(sbq, &cpu); 580705107fSDave Jiang if (idx < 0) { 590705107fSDave Jiang if (optype == IDXD_OP_NONBLOCK) 600705107fSDave Jiang return ERR_PTR(-EAGAIN); 610705107fSDave Jiang } else { 620705107fSDave Jiang return __get_desc(wq, idx, cpu); 630705107fSDave Jiang } 640705107fSDave Jiang 650705107fSDave Jiang ws = &sbq->ws[0]; 660705107fSDave Jiang for (;;) { 670705107fSDave Jiang sbitmap_prepare_to_wait(sbq, ws, &wait, TASK_INTERRUPTIBLE); 680705107fSDave Jiang if (signal_pending_state(TASK_INTERRUPTIBLE, current)) 690705107fSDave Jiang break; 700705107fSDave Jiang idx = sbitmap_queue_get(sbq, &cpu); 710705107fSDave Jiang if (idx > 0) 720705107fSDave Jiang break; 730705107fSDave Jiang schedule(); 740705107fSDave Jiang } 750705107fSDave Jiang 760705107fSDave Jiang sbitmap_finish_wait(sbq, ws, &wait); 770705107fSDave Jiang if (idx < 0) 780705107fSDave Jiang return ERR_PTR(-EAGAIN); 790705107fSDave Jiang 800705107fSDave Jiang return __get_desc(wq, idx, cpu); 810705107fSDave Jiang } 820705107fSDave Jiang 83d1dfe5b8SDave Jiang void idxd_free_desc(struct idxd_wq *wq, struct idxd_desc *desc) 84d1dfe5b8SDave Jiang { 850705107fSDave Jiang int cpu = desc->cpu; 86d1dfe5b8SDave Jiang 870705107fSDave Jiang desc->cpu = -1; 880705107fSDave Jiang sbitmap_queue_clear(&wq->sbq, desc->id, cpu); 89d1dfe5b8SDave Jiang } 90d1dfe5b8SDave Jiang 91d1dfe5b8SDave Jiang int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc) 92d1dfe5b8SDave Jiang { 93d1dfe5b8SDave Jiang struct idxd_device *idxd = wq->idxd; 9442d279f9SDave Jiang void __iomem *portal; 958e50d392SDave Jiang int rc; 96d1dfe5b8SDave Jiang 97d1dfe5b8SDave Jiang if (idxd->state != IDXD_DEV_ENABLED) 98d1dfe5b8SDave Jiang return -EIO; 99d1dfe5b8SDave Jiang 10093a40a6dSDave Jiang if (!percpu_ref_tryget_live(&wq->wq_active)) 10193a40a6dSDave Jiang return -ENXIO; 10293a40a6dSDave Jiang 1036daa9043SLinus Torvalds portal = wq->portal; 1048e50d392SDave Jiang 105d1dfe5b8SDave Jiang /* 1068e50d392SDave Jiang * The wmb() flushes writes to coherent DMA data before 1078e50d392SDave Jiang * possibly triggering a DMA read. The wmb() is necessary 1088e50d392SDave Jiang * even on UP because the recipient is a device. 109d1dfe5b8SDave Jiang */ 110d1dfe5b8SDave Jiang wmb(); 1118e50d392SDave Jiang if (wq_dedicated(wq)) { 11242d279f9SDave Jiang iosubmit_cmds512(portal, desc->hw, 1); 1138e50d392SDave Jiang } else { 1148e50d392SDave Jiang /* 1158e50d392SDave Jiang * It's not likely that we would receive queue full rejection 1168e50d392SDave Jiang * since the descriptor allocation gates at wq size. If we 1178e50d392SDave Jiang * receive a -EAGAIN, that means something went wrong such as the 1188e50d392SDave Jiang * device is not accepting descriptor at all. 1198e50d392SDave Jiang */ 1208e50d392SDave Jiang rc = enqcmds(portal, desc->hw); 121*ac24a2dcSDave Jiang if (rc < 0) { 122*ac24a2dcSDave Jiang percpu_ref_put(&wq->wq_active); 1238e50d392SDave Jiang return rc; 1248e50d392SDave Jiang } 125*ac24a2dcSDave Jiang } 126d1dfe5b8SDave Jiang 12793a40a6dSDave Jiang percpu_ref_put(&wq->wq_active); 12893a40a6dSDave Jiang 129d1dfe5b8SDave Jiang /* 130d1dfe5b8SDave Jiang * Pending the descriptor to the lockless list for the irq_entry 131d1dfe5b8SDave Jiang * that we designated the descriptor to. 132d1dfe5b8SDave Jiang */ 133eb15e715SDave Jiang if (desc->hw->flags & IDXD_OP_FLAG_RCI) { 134eb15e715SDave Jiang int vec; 135eb15e715SDave Jiang 136eb15e715SDave Jiang /* 137eb15e715SDave Jiang * If the driver is on host kernel, it would be the value 138eb15e715SDave Jiang * assigned to interrupt handle, which is index for MSIX 139eb15e715SDave Jiang * vector. If it's guest then can't use the int_handle since 140eb15e715SDave Jiang * that is the index to IMS for the entire device. The guest 141eb15e715SDave Jiang * device local index will be used. 142eb15e715SDave Jiang */ 143eb15e715SDave Jiang vec = !idxd->int_handles ? desc->hw->int_handle : desc->vector; 144eb15e715SDave Jiang llist_add(&desc->llnode, &idxd->irq_entries[vec].pending_llist); 145eb15e715SDave Jiang } 146d1dfe5b8SDave Jiang 147d1dfe5b8SDave Jiang return 0; 148d1dfe5b8SDave Jiang } 149