xref: /OK3568_Linux_fs/kernel/drivers/dma/idxd/dma.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* Copyright(c) 2019 Intel Corporation. All rights rsvd. */
3*4882a593Smuzhiyun #include <linux/init.h>
4*4882a593Smuzhiyun #include <linux/kernel.h>
5*4882a593Smuzhiyun #include <linux/module.h>
6*4882a593Smuzhiyun #include <linux/pci.h>
7*4882a593Smuzhiyun #include <linux/device.h>
8*4882a593Smuzhiyun #include <linux/io-64-nonatomic-lo-hi.h>
9*4882a593Smuzhiyun #include <linux/dmaengine.h>
10*4882a593Smuzhiyun #include <uapi/linux/idxd.h>
11*4882a593Smuzhiyun #include "../dmaengine.h"
12*4882a593Smuzhiyun #include "registers.h"
13*4882a593Smuzhiyun #include "idxd.h"
14*4882a593Smuzhiyun 
to_idxd_wq(struct dma_chan * c)15*4882a593Smuzhiyun static inline struct idxd_wq *to_idxd_wq(struct dma_chan *c)
16*4882a593Smuzhiyun {
17*4882a593Smuzhiyun 	struct idxd_dma_chan *idxd_chan;
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun 	idxd_chan = container_of(c, struct idxd_dma_chan, chan);
20*4882a593Smuzhiyun 	return idxd_chan->wq;
21*4882a593Smuzhiyun }
22*4882a593Smuzhiyun 
idxd_dma_complete_txd(struct idxd_desc * desc,enum idxd_complete_type comp_type)23*4882a593Smuzhiyun void idxd_dma_complete_txd(struct idxd_desc *desc,
24*4882a593Smuzhiyun 			   enum idxd_complete_type comp_type)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun 	struct dma_async_tx_descriptor *tx;
27*4882a593Smuzhiyun 	struct dmaengine_result res;
28*4882a593Smuzhiyun 	int complete = 1;
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun 	if (desc->completion->status == DSA_COMP_SUCCESS)
31*4882a593Smuzhiyun 		res.result = DMA_TRANS_NOERROR;
32*4882a593Smuzhiyun 	else if (desc->completion->status)
33*4882a593Smuzhiyun 		res.result = DMA_TRANS_WRITE_FAILED;
34*4882a593Smuzhiyun 	else if (comp_type == IDXD_COMPLETE_ABORT)
35*4882a593Smuzhiyun 		res.result = DMA_TRANS_ABORTED;
36*4882a593Smuzhiyun 	else
37*4882a593Smuzhiyun 		complete = 0;
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	tx = &desc->txd;
40*4882a593Smuzhiyun 	if (complete && tx->cookie) {
41*4882a593Smuzhiyun 		dma_cookie_complete(tx);
42*4882a593Smuzhiyun 		dma_descriptor_unmap(tx);
43*4882a593Smuzhiyun 		dmaengine_desc_get_callback_invoke(tx, &res);
44*4882a593Smuzhiyun 		tx->callback = NULL;
45*4882a593Smuzhiyun 		tx->callback_result = NULL;
46*4882a593Smuzhiyun 	}
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun 
op_flag_setup(unsigned long flags,u32 * desc_flags)49*4882a593Smuzhiyun static void op_flag_setup(unsigned long flags, u32 *desc_flags)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun 	*desc_flags = IDXD_OP_FLAG_CRAV | IDXD_OP_FLAG_RCR;
52*4882a593Smuzhiyun 	if (flags & DMA_PREP_INTERRUPT)
53*4882a593Smuzhiyun 		*desc_flags |= IDXD_OP_FLAG_RCI;
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun 
set_completion_address(struct idxd_desc * desc,u64 * compl_addr)56*4882a593Smuzhiyun static inline void set_completion_address(struct idxd_desc *desc,
57*4882a593Smuzhiyun 					  u64 *compl_addr)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun 		*compl_addr = desc->compl_dma;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun 
idxd_prep_desc_common(struct idxd_wq * wq,struct dsa_hw_desc * hw,char opcode,u64 addr_f1,u64 addr_f2,u64 len,u64 compl,u32 flags)62*4882a593Smuzhiyun static inline void idxd_prep_desc_common(struct idxd_wq *wq,
63*4882a593Smuzhiyun 					 struct dsa_hw_desc *hw, char opcode,
64*4882a593Smuzhiyun 					 u64 addr_f1, u64 addr_f2, u64 len,
65*4882a593Smuzhiyun 					 u64 compl, u32 flags)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun 	struct idxd_device *idxd = wq->idxd;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	hw->flags = flags;
70*4882a593Smuzhiyun 	hw->opcode = opcode;
71*4882a593Smuzhiyun 	hw->src_addr = addr_f1;
72*4882a593Smuzhiyun 	hw->dst_addr = addr_f2;
73*4882a593Smuzhiyun 	hw->xfer_size = len;
74*4882a593Smuzhiyun 	hw->priv = !!(wq->type == IDXD_WQT_KERNEL);
75*4882a593Smuzhiyun 	hw->completion_addr = compl;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	/*
78*4882a593Smuzhiyun 	 * Descriptor completion vectors are 1-8 for MSIX. We will round
79*4882a593Smuzhiyun 	 * robin through the 8 vectors.
80*4882a593Smuzhiyun 	 */
81*4882a593Smuzhiyun 	wq->vec_ptr = (wq->vec_ptr % idxd->num_wq_irqs) + 1;
82*4882a593Smuzhiyun 	hw->int_handle =  wq->vec_ptr;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun static struct dma_async_tx_descriptor *
idxd_dma_prep_interrupt(struct dma_chan * c,unsigned long flags)86*4882a593Smuzhiyun idxd_dma_prep_interrupt(struct dma_chan *c, unsigned long flags)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	struct idxd_wq *wq = to_idxd_wq(c);
89*4882a593Smuzhiyun 	u32 desc_flags;
90*4882a593Smuzhiyun 	struct idxd_desc *desc;
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	if (wq->state != IDXD_WQ_ENABLED)
93*4882a593Smuzhiyun 		return NULL;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	op_flag_setup(flags, &desc_flags);
96*4882a593Smuzhiyun 	desc = idxd_alloc_desc(wq, IDXD_OP_BLOCK);
97*4882a593Smuzhiyun 	if (IS_ERR(desc))
98*4882a593Smuzhiyun 		return NULL;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	idxd_prep_desc_common(wq, desc->hw, DSA_OPCODE_NOOP,
101*4882a593Smuzhiyun 			      0, 0, 0, desc->compl_dma, desc_flags);
102*4882a593Smuzhiyun 	desc->txd.flags = flags;
103*4882a593Smuzhiyun 	return &desc->txd;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun static struct dma_async_tx_descriptor *
idxd_dma_submit_memcpy(struct dma_chan * c,dma_addr_t dma_dest,dma_addr_t dma_src,size_t len,unsigned long flags)107*4882a593Smuzhiyun idxd_dma_submit_memcpy(struct dma_chan *c, dma_addr_t dma_dest,
108*4882a593Smuzhiyun 		       dma_addr_t dma_src, size_t len, unsigned long flags)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun 	struct idxd_wq *wq = to_idxd_wq(c);
111*4882a593Smuzhiyun 	u32 desc_flags;
112*4882a593Smuzhiyun 	struct idxd_device *idxd = wq->idxd;
113*4882a593Smuzhiyun 	struct idxd_desc *desc;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	if (wq->state != IDXD_WQ_ENABLED)
116*4882a593Smuzhiyun 		return NULL;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	if (len > idxd->max_xfer_bytes)
119*4882a593Smuzhiyun 		return NULL;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	op_flag_setup(flags, &desc_flags);
122*4882a593Smuzhiyun 	desc = idxd_alloc_desc(wq, IDXD_OP_BLOCK);
123*4882a593Smuzhiyun 	if (IS_ERR(desc))
124*4882a593Smuzhiyun 		return NULL;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	idxd_prep_desc_common(wq, desc->hw, DSA_OPCODE_MEMMOVE,
127*4882a593Smuzhiyun 			      dma_src, dma_dest, len, desc->compl_dma,
128*4882a593Smuzhiyun 			      desc_flags);
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	desc->txd.flags = flags;
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	return &desc->txd;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
idxd_dma_alloc_chan_resources(struct dma_chan * chan)135*4882a593Smuzhiyun static int idxd_dma_alloc_chan_resources(struct dma_chan *chan)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun 	struct idxd_wq *wq = to_idxd_wq(chan);
138*4882a593Smuzhiyun 	struct device *dev = &wq->idxd->pdev->dev;
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	idxd_wq_get(wq);
141*4882a593Smuzhiyun 	dev_dbg(dev, "%s: client_count: %d\n", __func__,
142*4882a593Smuzhiyun 		idxd_wq_refcount(wq));
143*4882a593Smuzhiyun 	return 0;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun 
idxd_dma_free_chan_resources(struct dma_chan * chan)146*4882a593Smuzhiyun static void idxd_dma_free_chan_resources(struct dma_chan *chan)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun 	struct idxd_wq *wq = to_idxd_wq(chan);
149*4882a593Smuzhiyun 	struct device *dev = &wq->idxd->pdev->dev;
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	idxd_wq_put(wq);
152*4882a593Smuzhiyun 	dev_dbg(dev, "%s: client_count: %d\n", __func__,
153*4882a593Smuzhiyun 		idxd_wq_refcount(wq));
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun 
idxd_dma_tx_status(struct dma_chan * dma_chan,dma_cookie_t cookie,struct dma_tx_state * txstate)156*4882a593Smuzhiyun static enum dma_status idxd_dma_tx_status(struct dma_chan *dma_chan,
157*4882a593Smuzhiyun 					  dma_cookie_t cookie,
158*4882a593Smuzhiyun 					  struct dma_tx_state *txstate)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun 	return DMA_OUT_OF_ORDER;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun /*
164*4882a593Smuzhiyun  * issue_pending() does not need to do anything since tx_submit() does the job
165*4882a593Smuzhiyun  * already.
166*4882a593Smuzhiyun  */
idxd_dma_issue_pending(struct dma_chan * dma_chan)167*4882a593Smuzhiyun static void idxd_dma_issue_pending(struct dma_chan *dma_chan)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun 
idxd_dma_tx_submit(struct dma_async_tx_descriptor * tx)171*4882a593Smuzhiyun static dma_cookie_t idxd_dma_tx_submit(struct dma_async_tx_descriptor *tx)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun 	struct dma_chan *c = tx->chan;
174*4882a593Smuzhiyun 	struct idxd_wq *wq = to_idxd_wq(c);
175*4882a593Smuzhiyun 	dma_cookie_t cookie;
176*4882a593Smuzhiyun 	int rc;
177*4882a593Smuzhiyun 	struct idxd_desc *desc = container_of(tx, struct idxd_desc, txd);
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	cookie = dma_cookie_assign(tx);
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	rc = idxd_submit_desc(wq, desc);
182*4882a593Smuzhiyun 	if (rc < 0) {
183*4882a593Smuzhiyun 		idxd_free_desc(wq, desc);
184*4882a593Smuzhiyun 		return rc;
185*4882a593Smuzhiyun 	}
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	return cookie;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun 
idxd_dma_release(struct dma_device * device)190*4882a593Smuzhiyun static void idxd_dma_release(struct dma_device *device)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun 	struct idxd_dma_dev *idxd_dma = container_of(device, struct idxd_dma_dev, dma);
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	kfree(idxd_dma);
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun 
idxd_register_dma_device(struct idxd_device * idxd)197*4882a593Smuzhiyun int idxd_register_dma_device(struct idxd_device *idxd)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun 	struct idxd_dma_dev *idxd_dma;
200*4882a593Smuzhiyun 	struct dma_device *dma;
201*4882a593Smuzhiyun 	struct device *dev = &idxd->pdev->dev;
202*4882a593Smuzhiyun 	int rc;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	idxd_dma = kzalloc_node(sizeof(*idxd_dma), GFP_KERNEL, dev_to_node(dev));
205*4882a593Smuzhiyun 	if (!idxd_dma)
206*4882a593Smuzhiyun 		return -ENOMEM;
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	dma = &idxd_dma->dma;
209*4882a593Smuzhiyun 	INIT_LIST_HEAD(&dma->channels);
210*4882a593Smuzhiyun 	dma->dev = dev;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	dma_cap_set(DMA_INTERRUPT, dma->cap_mask);
213*4882a593Smuzhiyun 	dma_cap_set(DMA_PRIVATE, dma->cap_mask);
214*4882a593Smuzhiyun 	dma_cap_set(DMA_COMPLETION_NO_ORDER, dma->cap_mask);
215*4882a593Smuzhiyun 	dma->device_release = idxd_dma_release;
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	dma->device_prep_dma_interrupt = idxd_dma_prep_interrupt;
218*4882a593Smuzhiyun 	if (idxd->hw.opcap.bits[0] & IDXD_OPCAP_MEMMOVE) {
219*4882a593Smuzhiyun 		dma_cap_set(DMA_MEMCPY, dma->cap_mask);
220*4882a593Smuzhiyun 		dma->device_prep_dma_memcpy = idxd_dma_submit_memcpy;
221*4882a593Smuzhiyun 	}
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	dma->device_tx_status = idxd_dma_tx_status;
224*4882a593Smuzhiyun 	dma->device_issue_pending = idxd_dma_issue_pending;
225*4882a593Smuzhiyun 	dma->device_alloc_chan_resources = idxd_dma_alloc_chan_resources;
226*4882a593Smuzhiyun 	dma->device_free_chan_resources = idxd_dma_free_chan_resources;
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	rc = dma_async_device_register(dma);
229*4882a593Smuzhiyun 	if (rc < 0) {
230*4882a593Smuzhiyun 		kfree(idxd_dma);
231*4882a593Smuzhiyun 		return rc;
232*4882a593Smuzhiyun 	}
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	idxd_dma->idxd = idxd;
235*4882a593Smuzhiyun 	/*
236*4882a593Smuzhiyun 	 * This pointer is protected by the refs taken by the dma_chan. It will remain valid
237*4882a593Smuzhiyun 	 * as long as there are outstanding channels.
238*4882a593Smuzhiyun 	 */
239*4882a593Smuzhiyun 	idxd->idxd_dma = idxd_dma;
240*4882a593Smuzhiyun 	return 0;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun 
idxd_unregister_dma_device(struct idxd_device * idxd)243*4882a593Smuzhiyun void idxd_unregister_dma_device(struct idxd_device *idxd)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun 	dma_async_device_unregister(&idxd->idxd_dma->dma);
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun 
idxd_register_dma_channel(struct idxd_wq * wq)248*4882a593Smuzhiyun int idxd_register_dma_channel(struct idxd_wq *wq)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun 	struct idxd_device *idxd = wq->idxd;
251*4882a593Smuzhiyun 	struct dma_device *dma = &idxd->idxd_dma->dma;
252*4882a593Smuzhiyun 	struct device *dev = &idxd->pdev->dev;
253*4882a593Smuzhiyun 	struct idxd_dma_chan *idxd_chan;
254*4882a593Smuzhiyun 	struct dma_chan *chan;
255*4882a593Smuzhiyun 	int rc, i;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	idxd_chan = kzalloc_node(sizeof(*idxd_chan), GFP_KERNEL, dev_to_node(dev));
258*4882a593Smuzhiyun 	if (!idxd_chan)
259*4882a593Smuzhiyun 		return -ENOMEM;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	chan = &idxd_chan->chan;
262*4882a593Smuzhiyun 	chan->device = dma;
263*4882a593Smuzhiyun 	list_add_tail(&chan->device_node, &dma->channels);
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	for (i = 0; i < wq->num_descs; i++) {
266*4882a593Smuzhiyun 		struct idxd_desc *desc = wq->descs[i];
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 		dma_async_tx_descriptor_init(&desc->txd, chan);
269*4882a593Smuzhiyun 		desc->txd.tx_submit = idxd_dma_tx_submit;
270*4882a593Smuzhiyun 	}
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	rc = dma_async_device_channel_register(dma, chan);
273*4882a593Smuzhiyun 	if (rc < 0) {
274*4882a593Smuzhiyun 		kfree(idxd_chan);
275*4882a593Smuzhiyun 		return rc;
276*4882a593Smuzhiyun 	}
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	wq->idxd_chan = idxd_chan;
279*4882a593Smuzhiyun 	idxd_chan->wq = wq;
280*4882a593Smuzhiyun 	get_device(&wq->conf_dev);
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	return 0;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun 
idxd_unregister_dma_channel(struct idxd_wq * wq)285*4882a593Smuzhiyun void idxd_unregister_dma_channel(struct idxd_wq *wq)
286*4882a593Smuzhiyun {
287*4882a593Smuzhiyun 	struct idxd_dma_chan *idxd_chan = wq->idxd_chan;
288*4882a593Smuzhiyun 	struct dma_chan *chan = &idxd_chan->chan;
289*4882a593Smuzhiyun 	struct idxd_dma_dev *idxd_dma = wq->idxd->idxd_dma;
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	dma_async_device_channel_unregister(&idxd_dma->dma, chan);
292*4882a593Smuzhiyun 	list_del(&chan->device_node);
293*4882a593Smuzhiyun 	kfree(wq->idxd_chan);
294*4882a593Smuzhiyun 	wq->idxd_chan = NULL;
295*4882a593Smuzhiyun 	put_device(&wq->conf_dev);
296*4882a593Smuzhiyun }
297