1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2019 Intel Corporation. All rights rsvd. */
3 #include <linux/init.h>
4 #include <linux/kernel.h>
5 #include <linux/module.h>
7 #include <uapi/linux/idxd.h>
11 static struct idxd_desc
*__get_desc(struct idxd_wq
*wq
, int idx
, int cpu
)
13 struct idxd_desc
*desc
;
14 struct idxd_device
*idxd
= wq
->idxd
;
16 desc
= wq
->descs
[idx
];
17 memset(desc
->hw
, 0, sizeof(struct dsa_hw_desc
));
18 memset(desc
->completion
, 0, idxd
->data
->compl_size
);
21 if (device_pasid_enabled(idxd
))
22 desc
->hw
->pasid
= idxd
->pasid
;
27 struct idxd_desc
*idxd_alloc_desc(struct idxd_wq
*wq
, enum idxd_op_type optype
)
30 struct idxd_device
*idxd
= wq
->idxd
;
31 DEFINE_SBQ_WAIT(wait
);
32 struct sbq_wait_state
*ws
;
33 struct sbitmap_queue
*sbq
;
35 if (idxd
->state
!= IDXD_DEV_ENABLED
)
39 idx
= sbitmap_queue_get(sbq
, &cpu
);
41 if (optype
== IDXD_OP_NONBLOCK
)
42 return ERR_PTR(-EAGAIN
);
44 return __get_desc(wq
, idx
, cpu
);
49 sbitmap_prepare_to_wait(sbq
, ws
, &wait
, TASK_INTERRUPTIBLE
);
50 if (signal_pending_state(TASK_INTERRUPTIBLE
, current
))
52 idx
= sbitmap_queue_get(sbq
, &cpu
);
58 sbitmap_finish_wait(sbq
, ws
, &wait
);
60 return ERR_PTR(-EAGAIN
);
62 return __get_desc(wq
, idx
, cpu
);
64 EXPORT_SYMBOL_NS_GPL(idxd_alloc_desc
, IDXD
);
66 void idxd_free_desc(struct idxd_wq
*wq
, struct idxd_desc
*desc
)
71 sbitmap_queue_clear(&wq
->sbq
, desc
->id
, cpu
);
73 EXPORT_SYMBOL_NS_GPL(idxd_free_desc
, IDXD
);
75 static struct idxd_desc
*list_abort_desc(struct idxd_wq
*wq
, struct idxd_irq_entry
*ie
,
76 struct idxd_desc
*desc
)
78 struct idxd_desc
*d
, *n
;
80 lockdep_assert_held(&ie
->list_lock
);
81 list_for_each_entry_safe(d
, n
, &ie
->work_list
, list
) {
89 * At this point, the desc needs to be aborted is held by the completion
90 * handler where it has taken it off the pending list but has not added to the
91 * work list. It will be cleaned up by the interrupt handler when it sees the
92 * IDXD_COMP_DESC_ABORT for completion status.
97 static void llist_abort_desc(struct idxd_wq
*wq
, struct idxd_irq_entry
*ie
,
98 struct idxd_desc
*desc
)
100 struct idxd_desc
*d
, *t
, *found
= NULL
;
101 struct llist_node
*head
;
104 desc
->completion
->status
= IDXD_COMP_DESC_ABORT
;
106 * Grab the list lock so it will block the irq thread handler. This allows the
107 * abort code to locate the descriptor need to be aborted.
109 spin_lock(&ie
->list_lock
);
110 head
= llist_del_all(&ie
->pending_llist
);
112 llist_for_each_entry_safe(d
, t
, head
, llnode
) {
118 if (d
->completion
->status
)
119 list_add_tail(&d
->list
, &flist
);
121 list_add_tail(&d
->list
, &ie
->work_list
);
126 found
= list_abort_desc(wq
, ie
, desc
);
127 spin_unlock(&ie
->list_lock
);
130 idxd_dma_complete_txd(found
, IDXD_COMPLETE_ABORT
, false,
134 * completing the descriptor will return desc to allocator and
135 * the desc can be acquired by a different process and the
136 * desc->list can be modified. Delete desc from list so the
137 * list traversing does not get corrupted by the other process.
139 list_for_each_entry_safe(d
, t
, &flist
, list
) {
140 list_del_init(&d
->list
);
141 idxd_dma_complete_txd(found
, IDXD_COMPLETE_ABORT
, true,
147 * ENQCMDS typically fail when the WQ is inactive or busy. On host submission, the driver
148 * has better control of number of descriptors being submitted to a shared wq by limiting
149 * the number of driver allocated descriptors to the wq size. However, when the swq is
150 * exported to a guest kernel, it may be shared with multiple guest kernels. This means
151 * the likelihood of getting busy returned on the swq when submitting goes significantly up.
152 * Having a tunable retry mechanism allows the driver to keep trying for a bit before giving
153 * up. The sysfs knob can be tuned by the system administrator.
155 int idxd_enqcmds(struct idxd_wq
*wq
, void __iomem
*portal
, const void *desc
)
157 unsigned int retries
= wq
->enqcmds_retries
;
161 rc
= enqcmds(portal
, desc
);
170 int idxd_submit_desc(struct idxd_wq
*wq
, struct idxd_desc
*desc
)
172 struct idxd_device
*idxd
= wq
->idxd
;
173 struct idxd_irq_entry
*ie
= NULL
;
174 u32 desc_flags
= desc
->hw
->flags
;
175 void __iomem
*portal
;
178 if (idxd
->state
!= IDXD_DEV_ENABLED
)
181 if (!percpu_ref_tryget_live(&wq
->wq_active
)) {
182 wait_for_completion(&wq
->wq_resurrect
);
183 if (!percpu_ref_tryget_live(&wq
->wq_active
))
187 portal
= idxd_wq_portal_addr(wq
);
190 * Pending the descriptor to the lockless list for the irq_entry
191 * that we designated the descriptor to.
193 if (desc_flags
& IDXD_OP_FLAG_RCI
) {
195 desc
->hw
->int_handle
= ie
->int_handle
;
196 llist_add(&desc
->llnode
, &ie
->pending_llist
);
200 * The wmb() flushes writes to coherent DMA data before
201 * possibly triggering a DMA read. The wmb() is necessary
202 * even on UP because the recipient is a device.
206 if (wq_dedicated(wq
)) {
207 iosubmit_cmds512(portal
, desc
->hw
, 1);
209 rc
= idxd_enqcmds(wq
, portal
, desc
->hw
);
211 percpu_ref_put(&wq
->wq_active
);
212 /* abort operation frees the descriptor */
214 llist_abort_desc(wq
, ie
, desc
);
219 percpu_ref_put(&wq
->wq_active
);
222 EXPORT_SYMBOL_NS_GPL(idxd_submit_desc
, IDXD
);