xref: /OK3568_Linux_fs/kernel/drivers/dma/plx_dma.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Microsemi Switchtec(tm) PCIe Management Driver
4*4882a593Smuzhiyun  * Copyright (c) 2019, Logan Gunthorpe <logang@deltatee.com>
5*4882a593Smuzhiyun  * Copyright (c) 2019, GigaIO Networks, Inc
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include "dmaengine.h"
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/circ_buf.h>
11*4882a593Smuzhiyun #include <linux/dmaengine.h>
12*4882a593Smuzhiyun #include <linux/kref.h>
13*4882a593Smuzhiyun #include <linux/list.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/pci.h>
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun MODULE_DESCRIPTION("PLX ExpressLane PEX PCI Switch DMA Engine");
18*4882a593Smuzhiyun MODULE_VERSION("0.1");
19*4882a593Smuzhiyun MODULE_LICENSE("GPL");
20*4882a593Smuzhiyun MODULE_AUTHOR("Logan Gunthorpe");
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define PLX_REG_DESC_RING_ADDR			0x214
23*4882a593Smuzhiyun #define PLX_REG_DESC_RING_ADDR_HI		0x218
24*4882a593Smuzhiyun #define PLX_REG_DESC_RING_NEXT_ADDR		0x21C
25*4882a593Smuzhiyun #define PLX_REG_DESC_RING_COUNT			0x220
26*4882a593Smuzhiyun #define PLX_REG_DESC_RING_LAST_ADDR		0x224
27*4882a593Smuzhiyun #define PLX_REG_DESC_RING_LAST_SIZE		0x228
28*4882a593Smuzhiyun #define PLX_REG_PREF_LIMIT			0x234
29*4882a593Smuzhiyun #define PLX_REG_CTRL				0x238
30*4882a593Smuzhiyun #define PLX_REG_CTRL2				0x23A
31*4882a593Smuzhiyun #define PLX_REG_INTR_CTRL			0x23C
32*4882a593Smuzhiyun #define PLX_REG_INTR_STATUS			0x23E
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #define PLX_REG_PREF_LIMIT_PREF_FOUR		8
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun #define PLX_REG_CTRL_GRACEFUL_PAUSE		BIT(0)
37*4882a593Smuzhiyun #define PLX_REG_CTRL_ABORT			BIT(1)
38*4882a593Smuzhiyun #define PLX_REG_CTRL_WRITE_BACK_EN		BIT(2)
39*4882a593Smuzhiyun #define PLX_REG_CTRL_START			BIT(3)
40*4882a593Smuzhiyun #define PLX_REG_CTRL_RING_STOP_MODE		BIT(4)
41*4882a593Smuzhiyun #define PLX_REG_CTRL_DESC_MODE_BLOCK		(0 << 5)
42*4882a593Smuzhiyun #define PLX_REG_CTRL_DESC_MODE_ON_CHIP		(1 << 5)
43*4882a593Smuzhiyun #define PLX_REG_CTRL_DESC_MODE_OFF_CHIP		(2 << 5)
44*4882a593Smuzhiyun #define PLX_REG_CTRL_DESC_INVALID		BIT(8)
45*4882a593Smuzhiyun #define PLX_REG_CTRL_GRACEFUL_PAUSE_DONE	BIT(9)
46*4882a593Smuzhiyun #define PLX_REG_CTRL_ABORT_DONE			BIT(10)
47*4882a593Smuzhiyun #define PLX_REG_CTRL_IMM_PAUSE_DONE		BIT(12)
48*4882a593Smuzhiyun #define PLX_REG_CTRL_IN_PROGRESS		BIT(30)
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun #define PLX_REG_CTRL_RESET_VAL	(PLX_REG_CTRL_DESC_INVALID | \
51*4882a593Smuzhiyun 				 PLX_REG_CTRL_GRACEFUL_PAUSE_DONE | \
52*4882a593Smuzhiyun 				 PLX_REG_CTRL_ABORT_DONE | \
53*4882a593Smuzhiyun 				 PLX_REG_CTRL_IMM_PAUSE_DONE)
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun #define PLX_REG_CTRL_START_VAL	(PLX_REG_CTRL_WRITE_BACK_EN | \
56*4882a593Smuzhiyun 				 PLX_REG_CTRL_DESC_MODE_OFF_CHIP | \
57*4882a593Smuzhiyun 				 PLX_REG_CTRL_START | \
58*4882a593Smuzhiyun 				 PLX_REG_CTRL_RESET_VAL)
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun #define PLX_REG_CTRL2_MAX_TXFR_SIZE_64B		0
61*4882a593Smuzhiyun #define PLX_REG_CTRL2_MAX_TXFR_SIZE_128B	1
62*4882a593Smuzhiyun #define PLX_REG_CTRL2_MAX_TXFR_SIZE_256B	2
63*4882a593Smuzhiyun #define PLX_REG_CTRL2_MAX_TXFR_SIZE_512B	3
64*4882a593Smuzhiyun #define PLX_REG_CTRL2_MAX_TXFR_SIZE_1KB		4
65*4882a593Smuzhiyun #define PLX_REG_CTRL2_MAX_TXFR_SIZE_2KB		5
66*4882a593Smuzhiyun #define PLX_REG_CTRL2_MAX_TXFR_SIZE_4B		7
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun #define PLX_REG_INTR_CRTL_ERROR_EN		BIT(0)
69*4882a593Smuzhiyun #define PLX_REG_INTR_CRTL_INV_DESC_EN		BIT(1)
70*4882a593Smuzhiyun #define PLX_REG_INTR_CRTL_ABORT_DONE_EN		BIT(3)
71*4882a593Smuzhiyun #define PLX_REG_INTR_CRTL_PAUSE_DONE_EN		BIT(4)
72*4882a593Smuzhiyun #define PLX_REG_INTR_CRTL_IMM_PAUSE_DONE_EN	BIT(5)
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun #define PLX_REG_INTR_STATUS_ERROR		BIT(0)
75*4882a593Smuzhiyun #define PLX_REG_INTR_STATUS_INV_DESC		BIT(1)
76*4882a593Smuzhiyun #define PLX_REG_INTR_STATUS_DESC_DONE		BIT(2)
77*4882a593Smuzhiyun #define PLX_REG_INTR_CRTL_ABORT_DONE		BIT(3)
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun struct plx_dma_hw_std_desc {
80*4882a593Smuzhiyun 	__le32 flags_and_size;
81*4882a593Smuzhiyun 	__le16 dst_addr_hi;
82*4882a593Smuzhiyun 	__le16 src_addr_hi;
83*4882a593Smuzhiyun 	__le32 dst_addr_lo;
84*4882a593Smuzhiyun 	__le32 src_addr_lo;
85*4882a593Smuzhiyun };
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun #define PLX_DESC_SIZE_MASK		0x7ffffff
88*4882a593Smuzhiyun #define PLX_DESC_FLAG_VALID		BIT(31)
89*4882a593Smuzhiyun #define PLX_DESC_FLAG_INT_WHEN_DONE	BIT(30)
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun #define PLX_DESC_WB_SUCCESS		BIT(30)
92*4882a593Smuzhiyun #define PLX_DESC_WB_RD_FAIL		BIT(29)
93*4882a593Smuzhiyun #define PLX_DESC_WB_WR_FAIL		BIT(28)
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun #define PLX_DMA_RING_COUNT		2048
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun struct plx_dma_desc {
98*4882a593Smuzhiyun 	struct dma_async_tx_descriptor txd;
99*4882a593Smuzhiyun 	struct plx_dma_hw_std_desc *hw;
100*4882a593Smuzhiyun 	u32 orig_size;
101*4882a593Smuzhiyun };
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun struct plx_dma_dev {
104*4882a593Smuzhiyun 	struct dma_device dma_dev;
105*4882a593Smuzhiyun 	struct dma_chan dma_chan;
106*4882a593Smuzhiyun 	struct pci_dev __rcu *pdev;
107*4882a593Smuzhiyun 	void __iomem *bar;
108*4882a593Smuzhiyun 	struct tasklet_struct desc_task;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	spinlock_t ring_lock;
111*4882a593Smuzhiyun 	bool ring_active;
112*4882a593Smuzhiyun 	int head;
113*4882a593Smuzhiyun 	int tail;
114*4882a593Smuzhiyun 	struct plx_dma_hw_std_desc *hw_ring;
115*4882a593Smuzhiyun 	dma_addr_t hw_ring_dma;
116*4882a593Smuzhiyun 	struct plx_dma_desc **desc_ring;
117*4882a593Smuzhiyun };
118*4882a593Smuzhiyun 
chan_to_plx_dma_dev(struct dma_chan * c)119*4882a593Smuzhiyun static struct plx_dma_dev *chan_to_plx_dma_dev(struct dma_chan *c)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun 	return container_of(c, struct plx_dma_dev, dma_chan);
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun 
to_plx_desc(struct dma_async_tx_descriptor * txd)124*4882a593Smuzhiyun static struct plx_dma_desc *to_plx_desc(struct dma_async_tx_descriptor *txd)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun 	return container_of(txd, struct plx_dma_desc, txd);
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun 
plx_dma_get_desc(struct plx_dma_dev * plxdev,int i)129*4882a593Smuzhiyun static struct plx_dma_desc *plx_dma_get_desc(struct plx_dma_dev *plxdev, int i)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun 	return plxdev->desc_ring[i & (PLX_DMA_RING_COUNT - 1)];
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun 
plx_dma_process_desc(struct plx_dma_dev * plxdev)134*4882a593Smuzhiyun static void plx_dma_process_desc(struct plx_dma_dev *plxdev)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun 	struct dmaengine_result res;
137*4882a593Smuzhiyun 	struct plx_dma_desc *desc;
138*4882a593Smuzhiyun 	u32 flags;
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	spin_lock_bh(&plxdev->ring_lock);
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	while (plxdev->tail != plxdev->head) {
143*4882a593Smuzhiyun 		desc = plx_dma_get_desc(plxdev, plxdev->tail);
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 		flags = le32_to_cpu(READ_ONCE(desc->hw->flags_and_size));
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 		if (flags & PLX_DESC_FLAG_VALID)
148*4882a593Smuzhiyun 			break;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 		res.residue = desc->orig_size - (flags & PLX_DESC_SIZE_MASK);
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 		if (flags & PLX_DESC_WB_SUCCESS)
153*4882a593Smuzhiyun 			res.result = DMA_TRANS_NOERROR;
154*4882a593Smuzhiyun 		else if (flags & PLX_DESC_WB_WR_FAIL)
155*4882a593Smuzhiyun 			res.result = DMA_TRANS_WRITE_FAILED;
156*4882a593Smuzhiyun 		else
157*4882a593Smuzhiyun 			res.result = DMA_TRANS_READ_FAILED;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 		dma_cookie_complete(&desc->txd);
160*4882a593Smuzhiyun 		dma_descriptor_unmap(&desc->txd);
161*4882a593Smuzhiyun 		dmaengine_desc_get_callback_invoke(&desc->txd, &res);
162*4882a593Smuzhiyun 		desc->txd.callback = NULL;
163*4882a593Smuzhiyun 		desc->txd.callback_result = NULL;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 		plxdev->tail++;
166*4882a593Smuzhiyun 	}
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	spin_unlock_bh(&plxdev->ring_lock);
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun 
plx_dma_abort_desc(struct plx_dma_dev * plxdev)171*4882a593Smuzhiyun static void plx_dma_abort_desc(struct plx_dma_dev *plxdev)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun 	struct dmaengine_result res;
174*4882a593Smuzhiyun 	struct plx_dma_desc *desc;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	plx_dma_process_desc(plxdev);
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	spin_lock_bh(&plxdev->ring_lock);
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	while (plxdev->tail != plxdev->head) {
181*4882a593Smuzhiyun 		desc = plx_dma_get_desc(plxdev, plxdev->tail);
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 		res.residue = desc->orig_size;
184*4882a593Smuzhiyun 		res.result = DMA_TRANS_ABORTED;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 		dma_cookie_complete(&desc->txd);
187*4882a593Smuzhiyun 		dma_descriptor_unmap(&desc->txd);
188*4882a593Smuzhiyun 		dmaengine_desc_get_callback_invoke(&desc->txd, &res);
189*4882a593Smuzhiyun 		desc->txd.callback = NULL;
190*4882a593Smuzhiyun 		desc->txd.callback_result = NULL;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 		plxdev->tail++;
193*4882a593Smuzhiyun 	}
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	spin_unlock_bh(&plxdev->ring_lock);
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun 
__plx_dma_stop(struct plx_dma_dev * plxdev)198*4882a593Smuzhiyun static void __plx_dma_stop(struct plx_dma_dev *plxdev)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun 	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
201*4882a593Smuzhiyun 	u32 val;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	val = readl(plxdev->bar + PLX_REG_CTRL);
204*4882a593Smuzhiyun 	if (!(val & ~PLX_REG_CTRL_GRACEFUL_PAUSE))
205*4882a593Smuzhiyun 		return;
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	writel(PLX_REG_CTRL_RESET_VAL | PLX_REG_CTRL_GRACEFUL_PAUSE,
208*4882a593Smuzhiyun 	       plxdev->bar + PLX_REG_CTRL);
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	while (!time_after(jiffies, timeout)) {
211*4882a593Smuzhiyun 		val = readl(plxdev->bar + PLX_REG_CTRL);
212*4882a593Smuzhiyun 		if (val & PLX_REG_CTRL_GRACEFUL_PAUSE_DONE)
213*4882a593Smuzhiyun 			break;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 		cpu_relax();
216*4882a593Smuzhiyun 	}
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	if (!(val & PLX_REG_CTRL_GRACEFUL_PAUSE_DONE))
219*4882a593Smuzhiyun 		dev_err(plxdev->dma_dev.dev,
220*4882a593Smuzhiyun 			"Timeout waiting for graceful pause!\n");
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	writel(PLX_REG_CTRL_RESET_VAL | PLX_REG_CTRL_GRACEFUL_PAUSE,
223*4882a593Smuzhiyun 	       plxdev->bar + PLX_REG_CTRL);
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	writel(0, plxdev->bar + PLX_REG_DESC_RING_COUNT);
226*4882a593Smuzhiyun 	writel(0, plxdev->bar + PLX_REG_DESC_RING_ADDR);
227*4882a593Smuzhiyun 	writel(0, plxdev->bar + PLX_REG_DESC_RING_ADDR_HI);
228*4882a593Smuzhiyun 	writel(0, plxdev->bar + PLX_REG_DESC_RING_NEXT_ADDR);
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun 
plx_dma_stop(struct plx_dma_dev * plxdev)231*4882a593Smuzhiyun static void plx_dma_stop(struct plx_dma_dev *plxdev)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun 	rcu_read_lock();
234*4882a593Smuzhiyun 	if (!rcu_dereference(plxdev->pdev)) {
235*4882a593Smuzhiyun 		rcu_read_unlock();
236*4882a593Smuzhiyun 		return;
237*4882a593Smuzhiyun 	}
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	__plx_dma_stop(plxdev);
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	rcu_read_unlock();
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun 
plx_dma_desc_task(struct tasklet_struct * t)244*4882a593Smuzhiyun static void plx_dma_desc_task(struct tasklet_struct *t)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun 	struct plx_dma_dev *plxdev = from_tasklet(plxdev, t, desc_task);
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	plx_dma_process_desc(plxdev);
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun 
plx_dma_prep_memcpy(struct dma_chan * c,dma_addr_t dma_dst,dma_addr_t dma_src,size_t len,unsigned long flags)251*4882a593Smuzhiyun static struct dma_async_tx_descriptor *plx_dma_prep_memcpy(struct dma_chan *c,
252*4882a593Smuzhiyun 		dma_addr_t dma_dst, dma_addr_t dma_src, size_t len,
253*4882a593Smuzhiyun 		unsigned long flags)
254*4882a593Smuzhiyun 	__acquires(plxdev->ring_lock)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun 	struct plx_dma_dev *plxdev = chan_to_plx_dma_dev(c);
257*4882a593Smuzhiyun 	struct plx_dma_desc *plxdesc;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	spin_lock_bh(&plxdev->ring_lock);
260*4882a593Smuzhiyun 	if (!plxdev->ring_active)
261*4882a593Smuzhiyun 		goto err_unlock;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	if (!CIRC_SPACE(plxdev->head, plxdev->tail, PLX_DMA_RING_COUNT))
264*4882a593Smuzhiyun 		goto err_unlock;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	if (len > PLX_DESC_SIZE_MASK)
267*4882a593Smuzhiyun 		goto err_unlock;
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	plxdesc = plx_dma_get_desc(plxdev, plxdev->head);
270*4882a593Smuzhiyun 	plxdev->head++;
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	plxdesc->hw->dst_addr_lo = cpu_to_le32(lower_32_bits(dma_dst));
273*4882a593Smuzhiyun 	plxdesc->hw->dst_addr_hi = cpu_to_le16(upper_32_bits(dma_dst));
274*4882a593Smuzhiyun 	plxdesc->hw->src_addr_lo = cpu_to_le32(lower_32_bits(dma_src));
275*4882a593Smuzhiyun 	plxdesc->hw->src_addr_hi = cpu_to_le16(upper_32_bits(dma_src));
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	plxdesc->orig_size = len;
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	if (flags & DMA_PREP_INTERRUPT)
280*4882a593Smuzhiyun 		len |= PLX_DESC_FLAG_INT_WHEN_DONE;
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	plxdesc->hw->flags_and_size = cpu_to_le32(len);
283*4882a593Smuzhiyun 	plxdesc->txd.flags = flags;
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	/* return with the lock held, it will be released in tx_submit */
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	return &plxdesc->txd;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun err_unlock:
290*4882a593Smuzhiyun 	/*
291*4882a593Smuzhiyun 	 * Keep sparse happy by restoring an even lock count on
292*4882a593Smuzhiyun 	 * this lock.
293*4882a593Smuzhiyun 	 */
294*4882a593Smuzhiyun 	__acquire(plxdev->ring_lock);
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	spin_unlock_bh(&plxdev->ring_lock);
297*4882a593Smuzhiyun 	return NULL;
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun 
plx_dma_tx_submit(struct dma_async_tx_descriptor * desc)300*4882a593Smuzhiyun static dma_cookie_t plx_dma_tx_submit(struct dma_async_tx_descriptor *desc)
301*4882a593Smuzhiyun 	__releases(plxdev->ring_lock)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun 	struct plx_dma_dev *plxdev = chan_to_plx_dma_dev(desc->chan);
304*4882a593Smuzhiyun 	struct plx_dma_desc *plxdesc = to_plx_desc(desc);
305*4882a593Smuzhiyun 	dma_cookie_t cookie;
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	cookie = dma_cookie_assign(desc);
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	/*
310*4882a593Smuzhiyun 	 * Ensure the descriptor updates are visible to the dma device
311*4882a593Smuzhiyun 	 * before setting the valid bit.
312*4882a593Smuzhiyun 	 */
313*4882a593Smuzhiyun 	wmb();
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	plxdesc->hw->flags_and_size |= cpu_to_le32(PLX_DESC_FLAG_VALID);
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	spin_unlock_bh(&plxdev->ring_lock);
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	return cookie;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun 
plx_dma_tx_status(struct dma_chan * chan,dma_cookie_t cookie,struct dma_tx_state * txstate)322*4882a593Smuzhiyun static enum dma_status plx_dma_tx_status(struct dma_chan *chan,
323*4882a593Smuzhiyun 		dma_cookie_t cookie, struct dma_tx_state *txstate)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun 	struct plx_dma_dev *plxdev = chan_to_plx_dma_dev(chan);
326*4882a593Smuzhiyun 	enum dma_status ret;
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	ret = dma_cookie_status(chan, cookie, txstate);
329*4882a593Smuzhiyun 	if (ret == DMA_COMPLETE)
330*4882a593Smuzhiyun 		return ret;
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	plx_dma_process_desc(plxdev);
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	return dma_cookie_status(chan, cookie, txstate);
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun 
plx_dma_issue_pending(struct dma_chan * chan)337*4882a593Smuzhiyun static void plx_dma_issue_pending(struct dma_chan *chan)
338*4882a593Smuzhiyun {
339*4882a593Smuzhiyun 	struct plx_dma_dev *plxdev = chan_to_plx_dma_dev(chan);
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	rcu_read_lock();
342*4882a593Smuzhiyun 	if (!rcu_dereference(plxdev->pdev)) {
343*4882a593Smuzhiyun 		rcu_read_unlock();
344*4882a593Smuzhiyun 		return;
345*4882a593Smuzhiyun 	}
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	/*
348*4882a593Smuzhiyun 	 * Ensure the valid bits are visible before starting the
349*4882a593Smuzhiyun 	 * DMA engine.
350*4882a593Smuzhiyun 	 */
351*4882a593Smuzhiyun 	wmb();
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	writew(PLX_REG_CTRL_START_VAL, plxdev->bar + PLX_REG_CTRL);
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	rcu_read_unlock();
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun 
plx_dma_isr(int irq,void * devid)358*4882a593Smuzhiyun static irqreturn_t plx_dma_isr(int irq, void *devid)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun 	struct plx_dma_dev *plxdev = devid;
361*4882a593Smuzhiyun 	u32 status;
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	status = readw(plxdev->bar + PLX_REG_INTR_STATUS);
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	if (!status)
366*4882a593Smuzhiyun 		return IRQ_NONE;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	if (status & PLX_REG_INTR_STATUS_DESC_DONE && plxdev->ring_active)
369*4882a593Smuzhiyun 		tasklet_schedule(&plxdev->desc_task);
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	writew(status, plxdev->bar + PLX_REG_INTR_STATUS);
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	return IRQ_HANDLED;
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun 
plx_dma_alloc_desc(struct plx_dma_dev * plxdev)376*4882a593Smuzhiyun static int plx_dma_alloc_desc(struct plx_dma_dev *plxdev)
377*4882a593Smuzhiyun {
378*4882a593Smuzhiyun 	struct plx_dma_desc *desc;
379*4882a593Smuzhiyun 	int i;
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	plxdev->desc_ring = kcalloc(PLX_DMA_RING_COUNT,
382*4882a593Smuzhiyun 				    sizeof(*plxdev->desc_ring), GFP_KERNEL);
383*4882a593Smuzhiyun 	if (!plxdev->desc_ring)
384*4882a593Smuzhiyun 		return -ENOMEM;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	for (i = 0; i < PLX_DMA_RING_COUNT; i++) {
387*4882a593Smuzhiyun 		desc = kzalloc(sizeof(*desc), GFP_KERNEL);
388*4882a593Smuzhiyun 		if (!desc)
389*4882a593Smuzhiyun 			goto free_and_exit;
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 		dma_async_tx_descriptor_init(&desc->txd, &plxdev->dma_chan);
392*4882a593Smuzhiyun 		desc->txd.tx_submit = plx_dma_tx_submit;
393*4882a593Smuzhiyun 		desc->hw = &plxdev->hw_ring[i];
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 		plxdev->desc_ring[i] = desc;
396*4882a593Smuzhiyun 	}
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	return 0;
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun free_and_exit:
401*4882a593Smuzhiyun 	for (i = 0; i < PLX_DMA_RING_COUNT; i++)
402*4882a593Smuzhiyun 		kfree(plxdev->desc_ring[i]);
403*4882a593Smuzhiyun 	kfree(plxdev->desc_ring);
404*4882a593Smuzhiyun 	return -ENOMEM;
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun 
plx_dma_alloc_chan_resources(struct dma_chan * chan)407*4882a593Smuzhiyun static int plx_dma_alloc_chan_resources(struct dma_chan *chan)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun 	struct plx_dma_dev *plxdev = chan_to_plx_dma_dev(chan);
410*4882a593Smuzhiyun 	size_t ring_sz = PLX_DMA_RING_COUNT * sizeof(*plxdev->hw_ring);
411*4882a593Smuzhiyun 	int rc;
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	plxdev->head = plxdev->tail = 0;
414*4882a593Smuzhiyun 	plxdev->hw_ring = dma_alloc_coherent(plxdev->dma_dev.dev, ring_sz,
415*4882a593Smuzhiyun 					     &plxdev->hw_ring_dma, GFP_KERNEL);
416*4882a593Smuzhiyun 	if (!plxdev->hw_ring)
417*4882a593Smuzhiyun 		return -ENOMEM;
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	rc = plx_dma_alloc_desc(plxdev);
420*4882a593Smuzhiyun 	if (rc)
421*4882a593Smuzhiyun 		goto out_free_hw_ring;
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	rcu_read_lock();
424*4882a593Smuzhiyun 	if (!rcu_dereference(plxdev->pdev)) {
425*4882a593Smuzhiyun 		rcu_read_unlock();
426*4882a593Smuzhiyun 		rc = -ENODEV;
427*4882a593Smuzhiyun 		goto out_free_hw_ring;
428*4882a593Smuzhiyun 	}
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	writel(PLX_REG_CTRL_RESET_VAL, plxdev->bar + PLX_REG_CTRL);
431*4882a593Smuzhiyun 	writel(lower_32_bits(plxdev->hw_ring_dma),
432*4882a593Smuzhiyun 	       plxdev->bar + PLX_REG_DESC_RING_ADDR);
433*4882a593Smuzhiyun 	writel(upper_32_bits(plxdev->hw_ring_dma),
434*4882a593Smuzhiyun 	       plxdev->bar + PLX_REG_DESC_RING_ADDR_HI);
435*4882a593Smuzhiyun 	writel(lower_32_bits(plxdev->hw_ring_dma),
436*4882a593Smuzhiyun 	       plxdev->bar + PLX_REG_DESC_RING_NEXT_ADDR);
437*4882a593Smuzhiyun 	writel(PLX_DMA_RING_COUNT, plxdev->bar + PLX_REG_DESC_RING_COUNT);
438*4882a593Smuzhiyun 	writel(PLX_REG_PREF_LIMIT_PREF_FOUR, plxdev->bar + PLX_REG_PREF_LIMIT);
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	plxdev->ring_active = true;
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	rcu_read_unlock();
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	return PLX_DMA_RING_COUNT;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun out_free_hw_ring:
447*4882a593Smuzhiyun 	dma_free_coherent(plxdev->dma_dev.dev, ring_sz, plxdev->hw_ring,
448*4882a593Smuzhiyun 			  plxdev->hw_ring_dma);
449*4882a593Smuzhiyun 	return rc;
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun 
plx_dma_free_chan_resources(struct dma_chan * chan)452*4882a593Smuzhiyun static void plx_dma_free_chan_resources(struct dma_chan *chan)
453*4882a593Smuzhiyun {
454*4882a593Smuzhiyun 	struct plx_dma_dev *plxdev = chan_to_plx_dma_dev(chan);
455*4882a593Smuzhiyun 	size_t ring_sz = PLX_DMA_RING_COUNT * sizeof(*plxdev->hw_ring);
456*4882a593Smuzhiyun 	struct pci_dev *pdev;
457*4882a593Smuzhiyun 	int irq = -1;
458*4882a593Smuzhiyun 	int i;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	spin_lock_bh(&plxdev->ring_lock);
461*4882a593Smuzhiyun 	plxdev->ring_active = false;
462*4882a593Smuzhiyun 	spin_unlock_bh(&plxdev->ring_lock);
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 	plx_dma_stop(plxdev);
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	rcu_read_lock();
467*4882a593Smuzhiyun 	pdev = rcu_dereference(plxdev->pdev);
468*4882a593Smuzhiyun 	if (pdev)
469*4882a593Smuzhiyun 		irq = pci_irq_vector(pdev, 0);
470*4882a593Smuzhiyun 	rcu_read_unlock();
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	if (irq > 0)
473*4882a593Smuzhiyun 		synchronize_irq(irq);
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 	tasklet_kill(&plxdev->desc_task);
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	plx_dma_abort_desc(plxdev);
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	for (i = 0; i < PLX_DMA_RING_COUNT; i++)
480*4882a593Smuzhiyun 		kfree(plxdev->desc_ring[i]);
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	kfree(plxdev->desc_ring);
483*4882a593Smuzhiyun 	dma_free_coherent(plxdev->dma_dev.dev, ring_sz, plxdev->hw_ring,
484*4882a593Smuzhiyun 			  plxdev->hw_ring_dma);
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun 
plx_dma_release(struct dma_device * dma_dev)488*4882a593Smuzhiyun static void plx_dma_release(struct dma_device *dma_dev)
489*4882a593Smuzhiyun {
490*4882a593Smuzhiyun 	struct plx_dma_dev *plxdev =
491*4882a593Smuzhiyun 		container_of(dma_dev, struct plx_dma_dev, dma_dev);
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	put_device(dma_dev->dev);
494*4882a593Smuzhiyun 	kfree(plxdev);
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun 
plx_dma_create(struct pci_dev * pdev)497*4882a593Smuzhiyun static int plx_dma_create(struct pci_dev *pdev)
498*4882a593Smuzhiyun {
499*4882a593Smuzhiyun 	struct plx_dma_dev *plxdev;
500*4882a593Smuzhiyun 	struct dma_device *dma;
501*4882a593Smuzhiyun 	struct dma_chan *chan;
502*4882a593Smuzhiyun 	int rc;
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	plxdev = kzalloc(sizeof(*plxdev), GFP_KERNEL);
505*4882a593Smuzhiyun 	if (!plxdev)
506*4882a593Smuzhiyun 		return -ENOMEM;
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun 	rc = request_irq(pci_irq_vector(pdev, 0), plx_dma_isr, 0,
509*4882a593Smuzhiyun 			 KBUILD_MODNAME, plxdev);
510*4882a593Smuzhiyun 	if (rc)
511*4882a593Smuzhiyun 		goto free_plx;
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 	spin_lock_init(&plxdev->ring_lock);
514*4882a593Smuzhiyun 	tasklet_setup(&plxdev->desc_task, plx_dma_desc_task);
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	RCU_INIT_POINTER(plxdev->pdev, pdev);
517*4882a593Smuzhiyun 	plxdev->bar = pcim_iomap_table(pdev)[0];
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	dma = &plxdev->dma_dev;
520*4882a593Smuzhiyun 	dma->chancnt = 1;
521*4882a593Smuzhiyun 	INIT_LIST_HEAD(&dma->channels);
522*4882a593Smuzhiyun 	dma_cap_set(DMA_MEMCPY, dma->cap_mask);
523*4882a593Smuzhiyun 	dma->copy_align = DMAENGINE_ALIGN_1_BYTE;
524*4882a593Smuzhiyun 	dma->dev = get_device(&pdev->dev);
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	dma->device_alloc_chan_resources = plx_dma_alloc_chan_resources;
527*4882a593Smuzhiyun 	dma->device_free_chan_resources = plx_dma_free_chan_resources;
528*4882a593Smuzhiyun 	dma->device_prep_dma_memcpy = plx_dma_prep_memcpy;
529*4882a593Smuzhiyun 	dma->device_issue_pending = plx_dma_issue_pending;
530*4882a593Smuzhiyun 	dma->device_tx_status = plx_dma_tx_status;
531*4882a593Smuzhiyun 	dma->device_release = plx_dma_release;
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	chan = &plxdev->dma_chan;
534*4882a593Smuzhiyun 	chan->device = dma;
535*4882a593Smuzhiyun 	dma_cookie_init(chan);
536*4882a593Smuzhiyun 	list_add_tail(&chan->device_node, &dma->channels);
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	rc = dma_async_device_register(dma);
539*4882a593Smuzhiyun 	if (rc) {
540*4882a593Smuzhiyun 		pci_err(pdev, "Failed to register dma device: %d\n", rc);
541*4882a593Smuzhiyun 		goto put_device;
542*4882a593Smuzhiyun 	}
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	pci_set_drvdata(pdev, plxdev);
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun 	return 0;
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun put_device:
549*4882a593Smuzhiyun 	put_device(&pdev->dev);
550*4882a593Smuzhiyun 	free_irq(pci_irq_vector(pdev, 0),  plxdev);
551*4882a593Smuzhiyun free_plx:
552*4882a593Smuzhiyun 	kfree(plxdev);
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	return rc;
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun 
plx_dma_probe(struct pci_dev * pdev,const struct pci_device_id * id)557*4882a593Smuzhiyun static int plx_dma_probe(struct pci_dev *pdev,
558*4882a593Smuzhiyun 			 const struct pci_device_id *id)
559*4882a593Smuzhiyun {
560*4882a593Smuzhiyun 	int rc;
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 	rc = pcim_enable_device(pdev);
563*4882a593Smuzhiyun 	if (rc)
564*4882a593Smuzhiyun 		return rc;
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(48));
567*4882a593Smuzhiyun 	if (rc)
568*4882a593Smuzhiyun 		rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
569*4882a593Smuzhiyun 	if (rc)
570*4882a593Smuzhiyun 		return rc;
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(48));
573*4882a593Smuzhiyun 	if (rc)
574*4882a593Smuzhiyun 		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
575*4882a593Smuzhiyun 	if (rc)
576*4882a593Smuzhiyun 		return rc;
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun 	rc = pcim_iomap_regions(pdev, 1, KBUILD_MODNAME);
579*4882a593Smuzhiyun 	if (rc)
580*4882a593Smuzhiyun 		return rc;
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 	rc = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
583*4882a593Smuzhiyun 	if (rc <= 0)
584*4882a593Smuzhiyun 		return rc;
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	pci_set_master(pdev);
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 	rc = plx_dma_create(pdev);
589*4882a593Smuzhiyun 	if (rc)
590*4882a593Smuzhiyun 		goto err_free_irq_vectors;
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 	pci_info(pdev, "PLX DMA Channel Registered\n");
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	return 0;
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun err_free_irq_vectors:
597*4882a593Smuzhiyun 	pci_free_irq_vectors(pdev);
598*4882a593Smuzhiyun 	return rc;
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun 
plx_dma_remove(struct pci_dev * pdev)601*4882a593Smuzhiyun static void plx_dma_remove(struct pci_dev *pdev)
602*4882a593Smuzhiyun {
603*4882a593Smuzhiyun 	struct plx_dma_dev *plxdev = pci_get_drvdata(pdev);
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun 	free_irq(pci_irq_vector(pdev, 0),  plxdev);
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	rcu_assign_pointer(plxdev->pdev, NULL);
608*4882a593Smuzhiyun 	synchronize_rcu();
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	spin_lock_bh(&plxdev->ring_lock);
611*4882a593Smuzhiyun 	plxdev->ring_active = false;
612*4882a593Smuzhiyun 	spin_unlock_bh(&plxdev->ring_lock);
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	__plx_dma_stop(plxdev);
615*4882a593Smuzhiyun 	plx_dma_abort_desc(plxdev);
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun 	plxdev->bar = NULL;
618*4882a593Smuzhiyun 	dma_async_device_unregister(&plxdev->dma_dev);
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun 	pci_free_irq_vectors(pdev);
621*4882a593Smuzhiyun }
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun static const struct pci_device_id plx_dma_pci_tbl[] = {
624*4882a593Smuzhiyun 	{
625*4882a593Smuzhiyun 		.vendor		= PCI_VENDOR_ID_PLX,
626*4882a593Smuzhiyun 		.device		= 0x87D0,
627*4882a593Smuzhiyun 		.subvendor	= PCI_ANY_ID,
628*4882a593Smuzhiyun 		.subdevice	= PCI_ANY_ID,
629*4882a593Smuzhiyun 		.class		= PCI_CLASS_SYSTEM_OTHER << 8,
630*4882a593Smuzhiyun 		.class_mask	= 0xFFFFFFFF,
631*4882a593Smuzhiyun 	},
632*4882a593Smuzhiyun 	{0}
633*4882a593Smuzhiyun };
634*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pci, plx_dma_pci_tbl);
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun static struct pci_driver plx_dma_pci_driver = {
637*4882a593Smuzhiyun 	.name           = KBUILD_MODNAME,
638*4882a593Smuzhiyun 	.id_table       = plx_dma_pci_tbl,
639*4882a593Smuzhiyun 	.probe          = plx_dma_probe,
640*4882a593Smuzhiyun 	.remove		= plx_dma_remove,
641*4882a593Smuzhiyun };
642*4882a593Smuzhiyun module_pci_driver(plx_dma_pci_driver);
643