xref: /openbmc/linux/drivers/net/wireless/ath/ath12k/ce.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1d8899132SKalle Valo // SPDX-License-Identifier: BSD-3-Clause-Clear
2d8899132SKalle Valo /*
3d8899132SKalle Valo  * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
4d8899132SKalle Valo  * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
5d8899132SKalle Valo  */
6d8899132SKalle Valo 
7d8899132SKalle Valo #include "dp_rx.h"
8d8899132SKalle Valo #include "debug.h"
9d8899132SKalle Valo #include "hif.h"
10d8899132SKalle Valo 
11d8899132SKalle Valo const struct ce_attr ath12k_host_ce_config_qcn9274[] = {
12d8899132SKalle Valo 	/* CE0: host->target HTC control and raw streams */
13d8899132SKalle Valo 	{
14d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS,
15d8899132SKalle Valo 		.src_nentries = 16,
16d8899132SKalle Valo 		.src_sz_max = 2048,
17d8899132SKalle Valo 		.dest_nentries = 0,
18d8899132SKalle Valo 	},
19d8899132SKalle Valo 
20d8899132SKalle Valo 	/* CE1: target->host HTT + HTC control */
21d8899132SKalle Valo 	{
22d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS,
23d8899132SKalle Valo 		.src_nentries = 0,
24d8899132SKalle Valo 		.src_sz_max = 2048,
25d8899132SKalle Valo 		.dest_nentries = 512,
26d8899132SKalle Valo 		.recv_cb = ath12k_htc_rx_completion_handler,
27d8899132SKalle Valo 	},
28d8899132SKalle Valo 
29d8899132SKalle Valo 	/* CE2: target->host WMI */
30d8899132SKalle Valo 	{
31d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS,
32d8899132SKalle Valo 		.src_nentries = 0,
33d8899132SKalle Valo 		.src_sz_max = 2048,
34d8899132SKalle Valo 		.dest_nentries = 128,
35d8899132SKalle Valo 		.recv_cb = ath12k_htc_rx_completion_handler,
36d8899132SKalle Valo 	},
37d8899132SKalle Valo 
38d8899132SKalle Valo 	/* CE3: host->target WMI (mac0) */
39d8899132SKalle Valo 	{
40d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS,
41d8899132SKalle Valo 		.src_nentries = 32,
42d8899132SKalle Valo 		.src_sz_max = 2048,
43d8899132SKalle Valo 		.dest_nentries = 0,
44d8899132SKalle Valo 	},
45d8899132SKalle Valo 
46d8899132SKalle Valo 	/* CE4: host->target HTT */
47d8899132SKalle Valo 	{
48d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
49d8899132SKalle Valo 		.src_nentries = 2048,
50d8899132SKalle Valo 		.src_sz_max = 256,
51d8899132SKalle Valo 		.dest_nentries = 0,
52d8899132SKalle Valo 	},
53d8899132SKalle Valo 
54d8899132SKalle Valo 	/* CE5: target->host pktlog */
55d8899132SKalle Valo 	{
56d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS,
57d8899132SKalle Valo 		.src_nentries = 0,
58d8899132SKalle Valo 		.src_sz_max = 2048,
59d8899132SKalle Valo 		.dest_nentries = 512,
60d8899132SKalle Valo 		.recv_cb = ath12k_dp_htt_htc_t2h_msg_handler,
61d8899132SKalle Valo 	},
62d8899132SKalle Valo 
63d8899132SKalle Valo 	/* CE6: target autonomous hif_memcpy */
64d8899132SKalle Valo 	{
65d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
66d8899132SKalle Valo 		.src_nentries = 0,
67d8899132SKalle Valo 		.src_sz_max = 0,
68d8899132SKalle Valo 		.dest_nentries = 0,
69d8899132SKalle Valo 	},
70d8899132SKalle Valo 
71d8899132SKalle Valo 	/* CE7: host->target WMI (mac1) */
72d8899132SKalle Valo 	{
73d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS,
74d8899132SKalle Valo 		.src_nentries = 32,
75d8899132SKalle Valo 		.src_sz_max = 2048,
76d8899132SKalle Valo 		.dest_nentries = 0,
77d8899132SKalle Valo 	},
78d8899132SKalle Valo 
79d8899132SKalle Valo 	/* CE8: target autonomous hif_memcpy */
80d8899132SKalle Valo 	{
81d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
82d8899132SKalle Valo 		.src_nentries = 0,
83d8899132SKalle Valo 		.src_sz_max = 0,
84d8899132SKalle Valo 		.dest_nentries = 0,
85d8899132SKalle Valo 	},
86d8899132SKalle Valo 
87d8899132SKalle Valo 	/* CE9: MHI */
88d8899132SKalle Valo 	{
89d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
90d8899132SKalle Valo 		.src_nentries = 0,
91d8899132SKalle Valo 		.src_sz_max = 0,
92d8899132SKalle Valo 		.dest_nentries = 0,
93d8899132SKalle Valo 	},
94d8899132SKalle Valo 
95d8899132SKalle Valo 	/* CE10: MHI */
96d8899132SKalle Valo 	{
97d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
98d8899132SKalle Valo 		.src_nentries = 0,
99d8899132SKalle Valo 		.src_sz_max = 0,
100d8899132SKalle Valo 		.dest_nentries = 0,
101d8899132SKalle Valo 	},
102d8899132SKalle Valo 
103d8899132SKalle Valo 	/* CE11: MHI */
104d8899132SKalle Valo 	{
105d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
106d8899132SKalle Valo 		.src_nentries = 0,
107d8899132SKalle Valo 		.src_sz_max = 0,
108d8899132SKalle Valo 		.dest_nentries = 0,
109d8899132SKalle Valo 	},
110d8899132SKalle Valo 
111d8899132SKalle Valo 	/* CE12: CV Prefetch */
112d8899132SKalle Valo 	{
113d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
114d8899132SKalle Valo 		.src_nentries = 0,
115d8899132SKalle Valo 		.src_sz_max = 0,
116d8899132SKalle Valo 		.dest_nentries = 0,
117d8899132SKalle Valo 	},
118d8899132SKalle Valo 
119d8899132SKalle Valo 	/* CE13: CV Prefetch */
120d8899132SKalle Valo 	{
121d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
122d8899132SKalle Valo 		.src_nentries = 0,
123d8899132SKalle Valo 		.src_sz_max = 0,
124d8899132SKalle Valo 		.dest_nentries = 0,
125d8899132SKalle Valo 	},
126d8899132SKalle Valo 
127d8899132SKalle Valo 	/* CE14: target->host dbg log */
128d8899132SKalle Valo 	{
129d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS,
130d8899132SKalle Valo 		.src_nentries = 0,
131d8899132SKalle Valo 		.src_sz_max = 2048,
132d8899132SKalle Valo 		.dest_nentries = 512,
133d8899132SKalle Valo 		.recv_cb = ath12k_htc_rx_completion_handler,
134d8899132SKalle Valo 	},
135d8899132SKalle Valo 
136d8899132SKalle Valo 	/* CE15: reserved for future use */
137d8899132SKalle Valo 	{
138d8899132SKalle Valo 		.flags = (CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
139d8899132SKalle Valo 		.src_nentries = 0,
140d8899132SKalle Valo 		.src_sz_max = 0,
141d8899132SKalle Valo 		.dest_nentries = 0,
142d8899132SKalle Valo 	},
143d8899132SKalle Valo };
144d8899132SKalle Valo 
145d8899132SKalle Valo const struct ce_attr ath12k_host_ce_config_wcn7850[] = {
146d8899132SKalle Valo 	/* CE0: host->target HTC control and raw streams */
147d8899132SKalle Valo 	{
148d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS,
149d8899132SKalle Valo 		.src_nentries = 16,
150d8899132SKalle Valo 		.src_sz_max = 2048,
151d8899132SKalle Valo 		.dest_nentries = 0,
152d8899132SKalle Valo 	},
153d8899132SKalle Valo 
154d8899132SKalle Valo 	/* CE1: target->host HTT + HTC control */
155d8899132SKalle Valo 	{
156d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS,
157d8899132SKalle Valo 		.src_nentries = 0,
158d8899132SKalle Valo 		.src_sz_max = 2048,
159d8899132SKalle Valo 		.dest_nentries = 512,
160d8899132SKalle Valo 		.recv_cb = ath12k_htc_rx_completion_handler,
161d8899132SKalle Valo 	},
162d8899132SKalle Valo 
163d8899132SKalle Valo 	/* CE2: target->host WMI */
164d8899132SKalle Valo 	{
165d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS,
166d8899132SKalle Valo 		.src_nentries = 0,
167d8899132SKalle Valo 		.src_sz_max = 2048,
168d8899132SKalle Valo 		.dest_nentries = 64,
169d8899132SKalle Valo 		.recv_cb = ath12k_htc_rx_completion_handler,
170d8899132SKalle Valo 	},
171d8899132SKalle Valo 
172d8899132SKalle Valo 	/* CE3: host->target WMI (mac0) */
173d8899132SKalle Valo 	{
174d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS,
175d8899132SKalle Valo 		.src_nentries = 32,
176d8899132SKalle Valo 		.src_sz_max = 2048,
177d8899132SKalle Valo 		.dest_nentries = 0,
178d8899132SKalle Valo 	},
179d8899132SKalle Valo 
180d8899132SKalle Valo 	/* CE4: host->target HTT */
181d8899132SKalle Valo 	{
182d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
183d8899132SKalle Valo 		.src_nentries = 2048,
184d8899132SKalle Valo 		.src_sz_max = 256,
185d8899132SKalle Valo 		.dest_nentries = 0,
186d8899132SKalle Valo 	},
187d8899132SKalle Valo 
188d8899132SKalle Valo 	/* CE5: target->host pktlog */
189d8899132SKalle Valo 	{
190d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS,
191d8899132SKalle Valo 		.src_nentries = 0,
192d8899132SKalle Valo 		.src_sz_max = 0,
193d8899132SKalle Valo 		.dest_nentries = 0,
194d8899132SKalle Valo 	},
195d8899132SKalle Valo 
196d8899132SKalle Valo 	/* CE6: target autonomous hif_memcpy */
197d8899132SKalle Valo 	{
198d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
199d8899132SKalle Valo 		.src_nentries = 0,
200d8899132SKalle Valo 		.src_sz_max = 0,
201d8899132SKalle Valo 		.dest_nentries = 0,
202d8899132SKalle Valo 	},
203d8899132SKalle Valo 
204d8899132SKalle Valo 	/* CE7: host->target WMI (mac1) */
205d8899132SKalle Valo 	{
206d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
207d8899132SKalle Valo 		.src_nentries = 0,
208d8899132SKalle Valo 		.src_sz_max = 2048,
209d8899132SKalle Valo 		.dest_nentries = 0,
210d8899132SKalle Valo 	},
211d8899132SKalle Valo 
212d8899132SKalle Valo 	/* CE8: target autonomous hif_memcpy */
213d8899132SKalle Valo 	{
214d8899132SKalle Valo 		.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
215d8899132SKalle Valo 		.src_nentries = 0,
216d8899132SKalle Valo 		.src_sz_max = 0,
217d8899132SKalle Valo 		.dest_nentries = 0,
218d8899132SKalle Valo 	},
219d8899132SKalle Valo 
220d8899132SKalle Valo };
221d8899132SKalle Valo 
ath12k_ce_rx_buf_enqueue_pipe(struct ath12k_ce_pipe * pipe,struct sk_buff * skb,dma_addr_t paddr)222d8899132SKalle Valo static int ath12k_ce_rx_buf_enqueue_pipe(struct ath12k_ce_pipe *pipe,
223d8899132SKalle Valo 					 struct sk_buff *skb, dma_addr_t paddr)
224d8899132SKalle Valo {
225d8899132SKalle Valo 	struct ath12k_base *ab = pipe->ab;
226d8899132SKalle Valo 	struct ath12k_ce_ring *ring = pipe->dest_ring;
227d8899132SKalle Valo 	struct hal_srng *srng;
228d8899132SKalle Valo 	unsigned int write_index;
229d8899132SKalle Valo 	unsigned int nentries_mask = ring->nentries_mask;
230d8899132SKalle Valo 	struct hal_ce_srng_dest_desc *desc;
231d8899132SKalle Valo 	int ret;
232d8899132SKalle Valo 
233d8899132SKalle Valo 	lockdep_assert_held(&ab->ce.ce_lock);
234d8899132SKalle Valo 
235d8899132SKalle Valo 	write_index = ring->write_index;
236d8899132SKalle Valo 
237d8899132SKalle Valo 	srng = &ab->hal.srng_list[ring->hal_ring_id];
238d8899132SKalle Valo 
239d8899132SKalle Valo 	spin_lock_bh(&srng->lock);
240d8899132SKalle Valo 
241d8899132SKalle Valo 	ath12k_hal_srng_access_begin(ab, srng);
242d8899132SKalle Valo 
243d8899132SKalle Valo 	if (unlikely(ath12k_hal_srng_src_num_free(ab, srng, false) < 1)) {
244d8899132SKalle Valo 		ret = -ENOSPC;
245d8899132SKalle Valo 		goto exit;
246d8899132SKalle Valo 	}
247d8899132SKalle Valo 
248d8899132SKalle Valo 	desc = ath12k_hal_srng_src_get_next_entry(ab, srng);
249d8899132SKalle Valo 	if (!desc) {
250d8899132SKalle Valo 		ret = -ENOSPC;
251d8899132SKalle Valo 		goto exit;
252d8899132SKalle Valo 	}
253d8899132SKalle Valo 
254d8899132SKalle Valo 	ath12k_hal_ce_dst_set_desc(desc, paddr);
255d8899132SKalle Valo 
256d8899132SKalle Valo 	ring->skb[write_index] = skb;
257d8899132SKalle Valo 	write_index = CE_RING_IDX_INCR(nentries_mask, write_index);
258d8899132SKalle Valo 	ring->write_index = write_index;
259d8899132SKalle Valo 
260d8899132SKalle Valo 	pipe->rx_buf_needed--;
261d8899132SKalle Valo 
262d8899132SKalle Valo 	ret = 0;
263d8899132SKalle Valo exit:
264d8899132SKalle Valo 	ath12k_hal_srng_access_end(ab, srng);
265d8899132SKalle Valo 
266d8899132SKalle Valo 	spin_unlock_bh(&srng->lock);
267d8899132SKalle Valo 
268d8899132SKalle Valo 	return ret;
269d8899132SKalle Valo }
270d8899132SKalle Valo 
ath12k_ce_rx_post_pipe(struct ath12k_ce_pipe * pipe)271d8899132SKalle Valo static int ath12k_ce_rx_post_pipe(struct ath12k_ce_pipe *pipe)
272d8899132SKalle Valo {
273d8899132SKalle Valo 	struct ath12k_base *ab = pipe->ab;
274d8899132SKalle Valo 	struct sk_buff *skb;
275d8899132SKalle Valo 	dma_addr_t paddr;
276d8899132SKalle Valo 	int ret = 0;
277d8899132SKalle Valo 
278d8899132SKalle Valo 	if (!(pipe->dest_ring || pipe->status_ring))
279d8899132SKalle Valo 		return 0;
280d8899132SKalle Valo 
281d8899132SKalle Valo 	spin_lock_bh(&ab->ce.ce_lock);
282d8899132SKalle Valo 	while (pipe->rx_buf_needed) {
283d8899132SKalle Valo 		skb = dev_alloc_skb(pipe->buf_sz);
284d8899132SKalle Valo 		if (!skb) {
285d8899132SKalle Valo 			ret = -ENOMEM;
286d8899132SKalle Valo 			goto exit;
287d8899132SKalle Valo 		}
288d8899132SKalle Valo 
289d8899132SKalle Valo 		WARN_ON_ONCE(!IS_ALIGNED((unsigned long)skb->data, 4));
290d8899132SKalle Valo 
291d8899132SKalle Valo 		paddr = dma_map_single(ab->dev, skb->data,
292d8899132SKalle Valo 				       skb->len + skb_tailroom(skb),
293d8899132SKalle Valo 				       DMA_FROM_DEVICE);
294d8899132SKalle Valo 		if (unlikely(dma_mapping_error(ab->dev, paddr))) {
295d8899132SKalle Valo 			ath12k_warn(ab, "failed to dma map ce rx buf\n");
296d8899132SKalle Valo 			dev_kfree_skb_any(skb);
297d8899132SKalle Valo 			ret = -EIO;
298d8899132SKalle Valo 			goto exit;
299d8899132SKalle Valo 		}
300d8899132SKalle Valo 
301d8899132SKalle Valo 		ATH12K_SKB_RXCB(skb)->paddr = paddr;
302d8899132SKalle Valo 
303d8899132SKalle Valo 		ret = ath12k_ce_rx_buf_enqueue_pipe(pipe, skb, paddr);
304d8899132SKalle Valo 		if (ret) {
305d8899132SKalle Valo 			ath12k_warn(ab, "failed to enqueue rx buf: %d\n", ret);
306d8899132SKalle Valo 			dma_unmap_single(ab->dev, paddr,
307d8899132SKalle Valo 					 skb->len + skb_tailroom(skb),
308d8899132SKalle Valo 					 DMA_FROM_DEVICE);
309d8899132SKalle Valo 			dev_kfree_skb_any(skb);
310d8899132SKalle Valo 			goto exit;
311d8899132SKalle Valo 		}
312d8899132SKalle Valo 	}
313d8899132SKalle Valo 
314d8899132SKalle Valo exit:
315d8899132SKalle Valo 	spin_unlock_bh(&ab->ce.ce_lock);
316d8899132SKalle Valo 	return ret;
317d8899132SKalle Valo }
318d8899132SKalle Valo 
ath12k_ce_completed_recv_next(struct ath12k_ce_pipe * pipe,struct sk_buff ** skb,int * nbytes)319d8899132SKalle Valo static int ath12k_ce_completed_recv_next(struct ath12k_ce_pipe *pipe,
320d8899132SKalle Valo 					 struct sk_buff **skb, int *nbytes)
321d8899132SKalle Valo {
322d8899132SKalle Valo 	struct ath12k_base *ab = pipe->ab;
323d8899132SKalle Valo 	struct hal_ce_srng_dst_status_desc *desc;
324d8899132SKalle Valo 	struct hal_srng *srng;
325d8899132SKalle Valo 	unsigned int sw_index;
326d8899132SKalle Valo 	unsigned int nentries_mask;
327d8899132SKalle Valo 	int ret = 0;
328d8899132SKalle Valo 
329d8899132SKalle Valo 	spin_lock_bh(&ab->ce.ce_lock);
330d8899132SKalle Valo 
331d8899132SKalle Valo 	sw_index = pipe->dest_ring->sw_index;
332d8899132SKalle Valo 	nentries_mask = pipe->dest_ring->nentries_mask;
333d8899132SKalle Valo 
334d8899132SKalle Valo 	srng = &ab->hal.srng_list[pipe->status_ring->hal_ring_id];
335d8899132SKalle Valo 
336d8899132SKalle Valo 	spin_lock_bh(&srng->lock);
337d8899132SKalle Valo 
338d8899132SKalle Valo 	ath12k_hal_srng_access_begin(ab, srng);
339d8899132SKalle Valo 
340d8899132SKalle Valo 	desc = ath12k_hal_srng_dst_get_next_entry(ab, srng);
341d8899132SKalle Valo 	if (!desc) {
342d8899132SKalle Valo 		ret = -EIO;
343d8899132SKalle Valo 		goto err;
344d8899132SKalle Valo 	}
345d8899132SKalle Valo 
346d8899132SKalle Valo 	*nbytes = ath12k_hal_ce_dst_status_get_length(desc);
347d8899132SKalle Valo 	if (*nbytes == 0) {
348d8899132SKalle Valo 		ret = -EIO;
349d8899132SKalle Valo 		goto err;
350d8899132SKalle Valo 	}
351d8899132SKalle Valo 
352d8899132SKalle Valo 	*skb = pipe->dest_ring->skb[sw_index];
353d8899132SKalle Valo 	pipe->dest_ring->skb[sw_index] = NULL;
354d8899132SKalle Valo 
355d8899132SKalle Valo 	sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index);
356d8899132SKalle Valo 	pipe->dest_ring->sw_index = sw_index;
357d8899132SKalle Valo 
358d8899132SKalle Valo 	pipe->rx_buf_needed++;
359d8899132SKalle Valo err:
360d8899132SKalle Valo 	ath12k_hal_srng_access_end(ab, srng);
361d8899132SKalle Valo 
362d8899132SKalle Valo 	spin_unlock_bh(&srng->lock);
363d8899132SKalle Valo 
364d8899132SKalle Valo 	spin_unlock_bh(&ab->ce.ce_lock);
365d8899132SKalle Valo 
366d8899132SKalle Valo 	return ret;
367d8899132SKalle Valo }
368d8899132SKalle Valo 
ath12k_ce_recv_process_cb(struct ath12k_ce_pipe * pipe)369d8899132SKalle Valo static void ath12k_ce_recv_process_cb(struct ath12k_ce_pipe *pipe)
370d8899132SKalle Valo {
371d8899132SKalle Valo 	struct ath12k_base *ab = pipe->ab;
372d8899132SKalle Valo 	struct sk_buff *skb;
373d8899132SKalle Valo 	struct sk_buff_head list;
374d8899132SKalle Valo 	unsigned int nbytes, max_nbytes;
375d8899132SKalle Valo 	int ret;
376d8899132SKalle Valo 
377d8899132SKalle Valo 	__skb_queue_head_init(&list);
378d8899132SKalle Valo 	while (ath12k_ce_completed_recv_next(pipe, &skb, &nbytes) == 0) {
379d8899132SKalle Valo 		max_nbytes = skb->len + skb_tailroom(skb);
380d8899132SKalle Valo 		dma_unmap_single(ab->dev, ATH12K_SKB_RXCB(skb)->paddr,
381d8899132SKalle Valo 				 max_nbytes, DMA_FROM_DEVICE);
382d8899132SKalle Valo 
383d8899132SKalle Valo 		if (unlikely(max_nbytes < nbytes)) {
384d8899132SKalle Valo 			ath12k_warn(ab, "rxed more than expected (nbytes %d, max %d)",
385d8899132SKalle Valo 				    nbytes, max_nbytes);
386d8899132SKalle Valo 			dev_kfree_skb_any(skb);
387d8899132SKalle Valo 			continue;
388d8899132SKalle Valo 		}
389d8899132SKalle Valo 
390d8899132SKalle Valo 		skb_put(skb, nbytes);
391d8899132SKalle Valo 		__skb_queue_tail(&list, skb);
392d8899132SKalle Valo 	}
393d8899132SKalle Valo 
394d8899132SKalle Valo 	while ((skb = __skb_dequeue(&list))) {
395d8899132SKalle Valo 		ath12k_dbg(ab, ATH12K_DBG_AHB, "rx ce pipe %d len %d\n",
396d8899132SKalle Valo 			   pipe->pipe_num, skb->len);
397d8899132SKalle Valo 		pipe->recv_cb(ab, skb);
398d8899132SKalle Valo 	}
399d8899132SKalle Valo 
400d8899132SKalle Valo 	ret = ath12k_ce_rx_post_pipe(pipe);
401d8899132SKalle Valo 	if (ret && ret != -ENOSPC) {
402d8899132SKalle Valo 		ath12k_warn(ab, "failed to post rx buf to pipe: %d err: %d\n",
403d8899132SKalle Valo 			    pipe->pipe_num, ret);
404d8899132SKalle Valo 		mod_timer(&ab->rx_replenish_retry,
405d8899132SKalle Valo 			  jiffies + ATH12K_CE_RX_POST_RETRY_JIFFIES);
406d8899132SKalle Valo 	}
407d8899132SKalle Valo }
408d8899132SKalle Valo 
ath12k_ce_completed_send_next(struct ath12k_ce_pipe * pipe)409d8899132SKalle Valo static struct sk_buff *ath12k_ce_completed_send_next(struct ath12k_ce_pipe *pipe)
410d8899132SKalle Valo {
411d8899132SKalle Valo 	struct ath12k_base *ab = pipe->ab;
412d8899132SKalle Valo 	struct hal_ce_srng_src_desc *desc;
413d8899132SKalle Valo 	struct hal_srng *srng;
414d8899132SKalle Valo 	unsigned int sw_index;
415d8899132SKalle Valo 	unsigned int nentries_mask;
416d8899132SKalle Valo 	struct sk_buff *skb;
417d8899132SKalle Valo 
418d8899132SKalle Valo 	spin_lock_bh(&ab->ce.ce_lock);
419d8899132SKalle Valo 
420d8899132SKalle Valo 	sw_index = pipe->src_ring->sw_index;
421d8899132SKalle Valo 	nentries_mask = pipe->src_ring->nentries_mask;
422d8899132SKalle Valo 
423d8899132SKalle Valo 	srng = &ab->hal.srng_list[pipe->src_ring->hal_ring_id];
424d8899132SKalle Valo 
425d8899132SKalle Valo 	spin_lock_bh(&srng->lock);
426d8899132SKalle Valo 
427d8899132SKalle Valo 	ath12k_hal_srng_access_begin(ab, srng);
428d8899132SKalle Valo 
429d8899132SKalle Valo 	desc = ath12k_hal_srng_src_reap_next(ab, srng);
430d8899132SKalle Valo 	if (!desc) {
431d8899132SKalle Valo 		skb = ERR_PTR(-EIO);
432d8899132SKalle Valo 		goto err_unlock;
433d8899132SKalle Valo 	}
434d8899132SKalle Valo 
435d8899132SKalle Valo 	skb = pipe->src_ring->skb[sw_index];
436d8899132SKalle Valo 
437d8899132SKalle Valo 	pipe->src_ring->skb[sw_index] = NULL;
438d8899132SKalle Valo 
439d8899132SKalle Valo 	sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index);
440d8899132SKalle Valo 	pipe->src_ring->sw_index = sw_index;
441d8899132SKalle Valo 
442d8899132SKalle Valo err_unlock:
443d8899132SKalle Valo 	spin_unlock_bh(&srng->lock);
444d8899132SKalle Valo 
445d8899132SKalle Valo 	spin_unlock_bh(&ab->ce.ce_lock);
446d8899132SKalle Valo 
447d8899132SKalle Valo 	return skb;
448d8899132SKalle Valo }
449d8899132SKalle Valo 
ath12k_ce_send_done_cb(struct ath12k_ce_pipe * pipe)450d8899132SKalle Valo static void ath12k_ce_send_done_cb(struct ath12k_ce_pipe *pipe)
451d8899132SKalle Valo {
452d8899132SKalle Valo 	struct ath12k_base *ab = pipe->ab;
453d8899132SKalle Valo 	struct sk_buff *skb;
454d8899132SKalle Valo 
455d8899132SKalle Valo 	while (!IS_ERR(skb = ath12k_ce_completed_send_next(pipe))) {
456d8899132SKalle Valo 		if (!skb)
457d8899132SKalle Valo 			continue;
458d8899132SKalle Valo 
459d8899132SKalle Valo 		dma_unmap_single(ab->dev, ATH12K_SKB_CB(skb)->paddr, skb->len,
460d8899132SKalle Valo 				 DMA_TO_DEVICE);
461d8899132SKalle Valo 		dev_kfree_skb_any(skb);
462d8899132SKalle Valo 	}
463d8899132SKalle Valo }
464d8899132SKalle Valo 
ath12k_ce_srng_msi_ring_params_setup(struct ath12k_base * ab,u32 ce_id,struct hal_srng_params * ring_params)465d8899132SKalle Valo static void ath12k_ce_srng_msi_ring_params_setup(struct ath12k_base *ab, u32 ce_id,
466d8899132SKalle Valo 						 struct hal_srng_params *ring_params)
467d8899132SKalle Valo {
468d8899132SKalle Valo 	u32 msi_data_start;
469d8899132SKalle Valo 	u32 msi_data_count, msi_data_idx;
470d8899132SKalle Valo 	u32 msi_irq_start;
471d8899132SKalle Valo 	u32 addr_lo;
472d8899132SKalle Valo 	u32 addr_hi;
473d8899132SKalle Valo 	int ret;
474d8899132SKalle Valo 
475d8899132SKalle Valo 	ret = ath12k_hif_get_user_msi_vector(ab, "CE",
476d8899132SKalle Valo 					     &msi_data_count, &msi_data_start,
477d8899132SKalle Valo 					     &msi_irq_start);
478d8899132SKalle Valo 
479d8899132SKalle Valo 	if (ret)
480d8899132SKalle Valo 		return;
481d8899132SKalle Valo 
482d8899132SKalle Valo 	ath12k_hif_get_msi_address(ab, &addr_lo, &addr_hi);
483d8899132SKalle Valo 	ath12k_hif_get_ce_msi_idx(ab, ce_id, &msi_data_idx);
484d8899132SKalle Valo 
485d8899132SKalle Valo 	ring_params->msi_addr = addr_lo;
486d8899132SKalle Valo 	ring_params->msi_addr |= (dma_addr_t)(((uint64_t)addr_hi) << 32);
487d8899132SKalle Valo 	ring_params->msi_data = (msi_data_idx % msi_data_count) + msi_data_start;
488d8899132SKalle Valo 	ring_params->flags |= HAL_SRNG_FLAGS_MSI_INTR;
489d8899132SKalle Valo }
490d8899132SKalle Valo 
ath12k_ce_init_ring(struct ath12k_base * ab,struct ath12k_ce_ring * ce_ring,int ce_id,enum hal_ring_type type)491d8899132SKalle Valo static int ath12k_ce_init_ring(struct ath12k_base *ab,
492d8899132SKalle Valo 			       struct ath12k_ce_ring *ce_ring,
493d8899132SKalle Valo 			       int ce_id, enum hal_ring_type type)
494d8899132SKalle Valo {
495d8899132SKalle Valo 	struct hal_srng_params params = { 0 };
496d8899132SKalle Valo 	int ret;
497d8899132SKalle Valo 
498d8899132SKalle Valo 	params.ring_base_paddr = ce_ring->base_addr_ce_space;
499d8899132SKalle Valo 	params.ring_base_vaddr = ce_ring->base_addr_owner_space;
500d8899132SKalle Valo 	params.num_entries = ce_ring->nentries;
501d8899132SKalle Valo 
502d8899132SKalle Valo 	if (!(CE_ATTR_DIS_INTR & ab->hw_params->host_ce_config[ce_id].flags))
503d8899132SKalle Valo 		ath12k_ce_srng_msi_ring_params_setup(ab, ce_id, &params);
504d8899132SKalle Valo 
505d8899132SKalle Valo 	switch (type) {
506d8899132SKalle Valo 	case HAL_CE_SRC:
507d8899132SKalle Valo 		if (!(CE_ATTR_DIS_INTR & ab->hw_params->host_ce_config[ce_id].flags))
508d8899132SKalle Valo 			params.intr_batch_cntr_thres_entries = 1;
509d8899132SKalle Valo 		break;
510d8899132SKalle Valo 	case HAL_CE_DST:
511d8899132SKalle Valo 		params.max_buffer_len = ab->hw_params->host_ce_config[ce_id].src_sz_max;
512d8899132SKalle Valo 		if (!(ab->hw_params->host_ce_config[ce_id].flags & CE_ATTR_DIS_INTR)) {
513d8899132SKalle Valo 			params.intr_timer_thres_us = 1024;
514d8899132SKalle Valo 			params.flags |= HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN;
515d8899132SKalle Valo 			params.low_threshold = ce_ring->nentries - 3;
516d8899132SKalle Valo 		}
517d8899132SKalle Valo 		break;
518d8899132SKalle Valo 	case HAL_CE_DST_STATUS:
519d8899132SKalle Valo 		if (!(ab->hw_params->host_ce_config[ce_id].flags & CE_ATTR_DIS_INTR)) {
520d8899132SKalle Valo 			params.intr_batch_cntr_thres_entries = 1;
521d8899132SKalle Valo 			params.intr_timer_thres_us = 0x1000;
522d8899132SKalle Valo 		}
523d8899132SKalle Valo 		break;
524d8899132SKalle Valo 	default:
525d8899132SKalle Valo 		ath12k_warn(ab, "Invalid CE ring type %d\n", type);
526d8899132SKalle Valo 		return -EINVAL;
527d8899132SKalle Valo 	}
528d8899132SKalle Valo 
529d8899132SKalle Valo 	/* TODO: Init other params needed by HAL to init the ring */
530d8899132SKalle Valo 
531d8899132SKalle Valo 	ret = ath12k_hal_srng_setup(ab, type, ce_id, 0, &params);
532d8899132SKalle Valo 	if (ret < 0) {
533d8899132SKalle Valo 		ath12k_warn(ab, "failed to setup srng: %d ring_id %d\n",
534d8899132SKalle Valo 			    ret, ce_id);
535d8899132SKalle Valo 		return ret;
536d8899132SKalle Valo 	}
537d8899132SKalle Valo 
538d8899132SKalle Valo 	ce_ring->hal_ring_id = ret;
539d8899132SKalle Valo 
540d8899132SKalle Valo 	return 0;
541d8899132SKalle Valo }
542d8899132SKalle Valo 
543d8899132SKalle Valo static struct ath12k_ce_ring *
ath12k_ce_alloc_ring(struct ath12k_base * ab,int nentries,int desc_sz)544d8899132SKalle Valo ath12k_ce_alloc_ring(struct ath12k_base *ab, int nentries, int desc_sz)
545d8899132SKalle Valo {
546d8899132SKalle Valo 	struct ath12k_ce_ring *ce_ring;
547d8899132SKalle Valo 	dma_addr_t base_addr;
548d8899132SKalle Valo 
549d8899132SKalle Valo 	ce_ring = kzalloc(struct_size(ce_ring, skb, nentries), GFP_KERNEL);
550d8899132SKalle Valo 	if (!ce_ring)
551d8899132SKalle Valo 		return ERR_PTR(-ENOMEM);
552d8899132SKalle Valo 
553d8899132SKalle Valo 	ce_ring->nentries = nentries;
554d8899132SKalle Valo 	ce_ring->nentries_mask = nentries - 1;
555d8899132SKalle Valo 
556d8899132SKalle Valo 	/* Legacy platforms that do not support cache
557d8899132SKalle Valo 	 * coherent DMA are unsupported
558d8899132SKalle Valo 	 */
559d8899132SKalle Valo 	ce_ring->base_addr_owner_space_unaligned =
560d8899132SKalle Valo 		dma_alloc_coherent(ab->dev,
561d8899132SKalle Valo 				   nentries * desc_sz + CE_DESC_RING_ALIGN,
562d8899132SKalle Valo 				   &base_addr, GFP_KERNEL);
563d8899132SKalle Valo 	if (!ce_ring->base_addr_owner_space_unaligned) {
564d8899132SKalle Valo 		kfree(ce_ring);
565d8899132SKalle Valo 		return ERR_PTR(-ENOMEM);
566d8899132SKalle Valo 	}
567d8899132SKalle Valo 
568d8899132SKalle Valo 	ce_ring->base_addr_ce_space_unaligned = base_addr;
569d8899132SKalle Valo 
570d8899132SKalle Valo 	ce_ring->base_addr_owner_space =
571d8899132SKalle Valo 		PTR_ALIGN(ce_ring->base_addr_owner_space_unaligned,
572d8899132SKalle Valo 			  CE_DESC_RING_ALIGN);
573d8899132SKalle Valo 
574d8899132SKalle Valo 	ce_ring->base_addr_ce_space = ALIGN(ce_ring->base_addr_ce_space_unaligned,
575d8899132SKalle Valo 					    CE_DESC_RING_ALIGN);
576d8899132SKalle Valo 
577d8899132SKalle Valo 	return ce_ring;
578d8899132SKalle Valo }
579d8899132SKalle Valo 
ath12k_ce_alloc_pipe(struct ath12k_base * ab,int ce_id)580d8899132SKalle Valo static int ath12k_ce_alloc_pipe(struct ath12k_base *ab, int ce_id)
581d8899132SKalle Valo {
582d8899132SKalle Valo 	struct ath12k_ce_pipe *pipe = &ab->ce.ce_pipe[ce_id];
583d8899132SKalle Valo 	const struct ce_attr *attr = &ab->hw_params->host_ce_config[ce_id];
584d8899132SKalle Valo 	struct ath12k_ce_ring *ring;
585d8899132SKalle Valo 	int nentries;
586d8899132SKalle Valo 	int desc_sz;
587d8899132SKalle Valo 
588d8899132SKalle Valo 	pipe->attr_flags = attr->flags;
589d8899132SKalle Valo 
590d8899132SKalle Valo 	if (attr->src_nentries) {
591d8899132SKalle Valo 		pipe->send_cb = ath12k_ce_send_done_cb;
592d8899132SKalle Valo 		nentries = roundup_pow_of_two(attr->src_nentries);
593d8899132SKalle Valo 		desc_sz = ath12k_hal_ce_get_desc_size(HAL_CE_DESC_SRC);
594d8899132SKalle Valo 		ring = ath12k_ce_alloc_ring(ab, nentries, desc_sz);
595d8899132SKalle Valo 		if (IS_ERR(ring))
596d8899132SKalle Valo 			return PTR_ERR(ring);
597d8899132SKalle Valo 		pipe->src_ring = ring;
598d8899132SKalle Valo 	}
599d8899132SKalle Valo 
600d8899132SKalle Valo 	if (attr->dest_nentries) {
601d8899132SKalle Valo 		pipe->recv_cb = attr->recv_cb;
602d8899132SKalle Valo 		nentries = roundup_pow_of_two(attr->dest_nentries);
603d8899132SKalle Valo 		desc_sz = ath12k_hal_ce_get_desc_size(HAL_CE_DESC_DST);
604d8899132SKalle Valo 		ring = ath12k_ce_alloc_ring(ab, nentries, desc_sz);
605d8899132SKalle Valo 		if (IS_ERR(ring))
606d8899132SKalle Valo 			return PTR_ERR(ring);
607d8899132SKalle Valo 		pipe->dest_ring = ring;
608d8899132SKalle Valo 
609d8899132SKalle Valo 		desc_sz = ath12k_hal_ce_get_desc_size(HAL_CE_DESC_DST_STATUS);
610d8899132SKalle Valo 		ring = ath12k_ce_alloc_ring(ab, nentries, desc_sz);
611d8899132SKalle Valo 		if (IS_ERR(ring))
612d8899132SKalle Valo 			return PTR_ERR(ring);
613d8899132SKalle Valo 		pipe->status_ring = ring;
614d8899132SKalle Valo 	}
615d8899132SKalle Valo 
616d8899132SKalle Valo 	return 0;
617d8899132SKalle Valo }
618d8899132SKalle Valo 
ath12k_ce_per_engine_service(struct ath12k_base * ab,u16 ce_id)619d8899132SKalle Valo void ath12k_ce_per_engine_service(struct ath12k_base *ab, u16 ce_id)
620d8899132SKalle Valo {
621d8899132SKalle Valo 	struct ath12k_ce_pipe *pipe = &ab->ce.ce_pipe[ce_id];
622d8899132SKalle Valo 
623d8899132SKalle Valo 	if (pipe->send_cb)
624d8899132SKalle Valo 		pipe->send_cb(pipe);
625d8899132SKalle Valo 
626d8899132SKalle Valo 	if (pipe->recv_cb)
627d8899132SKalle Valo 		ath12k_ce_recv_process_cb(pipe);
628d8899132SKalle Valo }
629d8899132SKalle Valo 
ath12k_ce_poll_send_completed(struct ath12k_base * ab,u8 pipe_id)630d8899132SKalle Valo void ath12k_ce_poll_send_completed(struct ath12k_base *ab, u8 pipe_id)
631d8899132SKalle Valo {
632d8899132SKalle Valo 	struct ath12k_ce_pipe *pipe = &ab->ce.ce_pipe[pipe_id];
633d8899132SKalle Valo 
634d8899132SKalle Valo 	if ((pipe->attr_flags & CE_ATTR_DIS_INTR) && pipe->send_cb)
635d8899132SKalle Valo 		pipe->send_cb(pipe);
636d8899132SKalle Valo }
637d8899132SKalle Valo 
ath12k_ce_send(struct ath12k_base * ab,struct sk_buff * skb,u8 pipe_id,u16 transfer_id)638d8899132SKalle Valo int ath12k_ce_send(struct ath12k_base *ab, struct sk_buff *skb, u8 pipe_id,
639d8899132SKalle Valo 		   u16 transfer_id)
640d8899132SKalle Valo {
641d8899132SKalle Valo 	struct ath12k_ce_pipe *pipe = &ab->ce.ce_pipe[pipe_id];
642d8899132SKalle Valo 	struct hal_ce_srng_src_desc *desc;
643d8899132SKalle Valo 	struct hal_srng *srng;
644d8899132SKalle Valo 	unsigned int write_index, sw_index;
645d8899132SKalle Valo 	unsigned int nentries_mask;
646d8899132SKalle Valo 	int ret = 0;
647d8899132SKalle Valo 	u8 byte_swap_data = 0;
648d8899132SKalle Valo 	int num_used;
649d8899132SKalle Valo 
650d8899132SKalle Valo 	/* Check if some entries could be regained by handling tx completion if
651d8899132SKalle Valo 	 * the CE has interrupts disabled and the used entries is more than the
652d8899132SKalle Valo 	 * defined usage threshold.
653d8899132SKalle Valo 	 */
654d8899132SKalle Valo 	if (pipe->attr_flags & CE_ATTR_DIS_INTR) {
655d8899132SKalle Valo 		spin_lock_bh(&ab->ce.ce_lock);
656d8899132SKalle Valo 		write_index = pipe->src_ring->write_index;
657d8899132SKalle Valo 
658d8899132SKalle Valo 		sw_index = pipe->src_ring->sw_index;
659d8899132SKalle Valo 
660d8899132SKalle Valo 		if (write_index >= sw_index)
661d8899132SKalle Valo 			num_used = write_index - sw_index;
662d8899132SKalle Valo 		else
663d8899132SKalle Valo 			num_used = pipe->src_ring->nentries - sw_index +
664d8899132SKalle Valo 				   write_index;
665d8899132SKalle Valo 
666d8899132SKalle Valo 		spin_unlock_bh(&ab->ce.ce_lock);
667d8899132SKalle Valo 
668d8899132SKalle Valo 		if (num_used > ATH12K_CE_USAGE_THRESHOLD)
669d8899132SKalle Valo 			ath12k_ce_poll_send_completed(ab, pipe->pipe_num);
670d8899132SKalle Valo 	}
671d8899132SKalle Valo 
672d8899132SKalle Valo 	if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags))
673d8899132SKalle Valo 		return -ESHUTDOWN;
674d8899132SKalle Valo 
675d8899132SKalle Valo 	spin_lock_bh(&ab->ce.ce_lock);
676d8899132SKalle Valo 
677d8899132SKalle Valo 	write_index = pipe->src_ring->write_index;
678d8899132SKalle Valo 	nentries_mask = pipe->src_ring->nentries_mask;
679d8899132SKalle Valo 
680d8899132SKalle Valo 	srng = &ab->hal.srng_list[pipe->src_ring->hal_ring_id];
681d8899132SKalle Valo 
682d8899132SKalle Valo 	spin_lock_bh(&srng->lock);
683d8899132SKalle Valo 
684d8899132SKalle Valo 	ath12k_hal_srng_access_begin(ab, srng);
685d8899132SKalle Valo 
686d8899132SKalle Valo 	if (unlikely(ath12k_hal_srng_src_num_free(ab, srng, false) < 1)) {
687d8899132SKalle Valo 		ath12k_hal_srng_access_end(ab, srng);
688d8899132SKalle Valo 		ret = -ENOBUFS;
689d8899132SKalle Valo 		goto unlock;
690d8899132SKalle Valo 	}
691d8899132SKalle Valo 
692d8899132SKalle Valo 	desc = ath12k_hal_srng_src_get_next_reaped(ab, srng);
693d8899132SKalle Valo 	if (!desc) {
694d8899132SKalle Valo 		ath12k_hal_srng_access_end(ab, srng);
695d8899132SKalle Valo 		ret = -ENOBUFS;
696d8899132SKalle Valo 		goto unlock;
697d8899132SKalle Valo 	}
698d8899132SKalle Valo 
699d8899132SKalle Valo 	if (pipe->attr_flags & CE_ATTR_BYTE_SWAP_DATA)
700d8899132SKalle Valo 		byte_swap_data = 1;
701d8899132SKalle Valo 
702d8899132SKalle Valo 	ath12k_hal_ce_src_set_desc(desc, ATH12K_SKB_CB(skb)->paddr,
703d8899132SKalle Valo 				   skb->len, transfer_id, byte_swap_data);
704d8899132SKalle Valo 
705d8899132SKalle Valo 	pipe->src_ring->skb[write_index] = skb;
706d8899132SKalle Valo 	pipe->src_ring->write_index = CE_RING_IDX_INCR(nentries_mask,
707d8899132SKalle Valo 						       write_index);
708d8899132SKalle Valo 
709d8899132SKalle Valo 	ath12k_hal_srng_access_end(ab, srng);
710d8899132SKalle Valo 
711d8899132SKalle Valo unlock:
712d8899132SKalle Valo 	spin_unlock_bh(&srng->lock);
713d8899132SKalle Valo 
714d8899132SKalle Valo 	spin_unlock_bh(&ab->ce.ce_lock);
715d8899132SKalle Valo 
716d8899132SKalle Valo 	return ret;
717d8899132SKalle Valo }
718d8899132SKalle Valo 
ath12k_ce_rx_pipe_cleanup(struct ath12k_ce_pipe * pipe)719d8899132SKalle Valo static void ath12k_ce_rx_pipe_cleanup(struct ath12k_ce_pipe *pipe)
720d8899132SKalle Valo {
721d8899132SKalle Valo 	struct ath12k_base *ab = pipe->ab;
722d8899132SKalle Valo 	struct ath12k_ce_ring *ring = pipe->dest_ring;
723d8899132SKalle Valo 	struct sk_buff *skb;
724d8899132SKalle Valo 	int i;
725d8899132SKalle Valo 
726d8899132SKalle Valo 	if (!(ring && pipe->buf_sz))
727d8899132SKalle Valo 		return;
728d8899132SKalle Valo 
729d8899132SKalle Valo 	for (i = 0; i < ring->nentries; i++) {
730d8899132SKalle Valo 		skb = ring->skb[i];
731d8899132SKalle Valo 		if (!skb)
732d8899132SKalle Valo 			continue;
733d8899132SKalle Valo 
734d8899132SKalle Valo 		ring->skb[i] = NULL;
735d8899132SKalle Valo 		dma_unmap_single(ab->dev, ATH12K_SKB_RXCB(skb)->paddr,
736d8899132SKalle Valo 				 skb->len + skb_tailroom(skb), DMA_FROM_DEVICE);
737d8899132SKalle Valo 		dev_kfree_skb_any(skb);
738d8899132SKalle Valo 	}
739d8899132SKalle Valo }
740d8899132SKalle Valo 
ath12k_ce_cleanup_pipes(struct ath12k_base * ab)741d8899132SKalle Valo void ath12k_ce_cleanup_pipes(struct ath12k_base *ab)
742d8899132SKalle Valo {
743d8899132SKalle Valo 	struct ath12k_ce_pipe *pipe;
744d8899132SKalle Valo 	int pipe_num;
745d8899132SKalle Valo 
746d8899132SKalle Valo 	for (pipe_num = 0; pipe_num < ab->hw_params->ce_count; pipe_num++) {
747d8899132SKalle Valo 		pipe = &ab->ce.ce_pipe[pipe_num];
748d8899132SKalle Valo 		ath12k_ce_rx_pipe_cleanup(pipe);
749d8899132SKalle Valo 
750d8899132SKalle Valo 		/* Cleanup any src CE's which have interrupts disabled */
751d8899132SKalle Valo 		ath12k_ce_poll_send_completed(ab, pipe_num);
752d8899132SKalle Valo 
753d8899132SKalle Valo 		/* NOTE: Should we also clean up tx buffer in all pipes? */
754d8899132SKalle Valo 	}
755d8899132SKalle Valo }
756d8899132SKalle Valo 
ath12k_ce_rx_post_buf(struct ath12k_base * ab)757d8899132SKalle Valo void ath12k_ce_rx_post_buf(struct ath12k_base *ab)
758d8899132SKalle Valo {
759d8899132SKalle Valo 	struct ath12k_ce_pipe *pipe;
760d8899132SKalle Valo 	int i;
761d8899132SKalle Valo 	int ret;
762d8899132SKalle Valo 
763d8899132SKalle Valo 	for (i = 0; i < ab->hw_params->ce_count; i++) {
764d8899132SKalle Valo 		pipe = &ab->ce.ce_pipe[i];
765d8899132SKalle Valo 		ret = ath12k_ce_rx_post_pipe(pipe);
766d8899132SKalle Valo 		if (ret) {
767d8899132SKalle Valo 			if (ret == -ENOSPC)
768d8899132SKalle Valo 				continue;
769d8899132SKalle Valo 
770d8899132SKalle Valo 			ath12k_warn(ab, "failed to post rx buf to pipe: %d err: %d\n",
771d8899132SKalle Valo 				    i, ret);
772d8899132SKalle Valo 			mod_timer(&ab->rx_replenish_retry,
773d8899132SKalle Valo 				  jiffies + ATH12K_CE_RX_POST_RETRY_JIFFIES);
774d8899132SKalle Valo 
775d8899132SKalle Valo 			return;
776d8899132SKalle Valo 		}
777d8899132SKalle Valo 	}
778d8899132SKalle Valo }
779d8899132SKalle Valo 
ath12k_ce_rx_replenish_retry(struct timer_list * t)780d8899132SKalle Valo void ath12k_ce_rx_replenish_retry(struct timer_list *t)
781d8899132SKalle Valo {
782d8899132SKalle Valo 	struct ath12k_base *ab = from_timer(ab, t, rx_replenish_retry);
783d8899132SKalle Valo 
784d8899132SKalle Valo 	ath12k_ce_rx_post_buf(ab);
785d8899132SKalle Valo }
786d8899132SKalle Valo 
ath12k_ce_shadow_config(struct ath12k_base * ab)787d8899132SKalle Valo static void ath12k_ce_shadow_config(struct ath12k_base *ab)
788d8899132SKalle Valo {
789d8899132SKalle Valo 	int i;
790d8899132SKalle Valo 
791d8899132SKalle Valo 	for (i = 0; i < ab->hw_params->ce_count; i++) {
792d8899132SKalle Valo 		if (ab->hw_params->host_ce_config[i].src_nentries)
793d8899132SKalle Valo 			ath12k_hal_srng_update_shadow_config(ab, HAL_CE_SRC, i);
794d8899132SKalle Valo 
795d8899132SKalle Valo 		if (ab->hw_params->host_ce_config[i].dest_nentries) {
796d8899132SKalle Valo 			ath12k_hal_srng_update_shadow_config(ab, HAL_CE_DST, i);
797d8899132SKalle Valo 			ath12k_hal_srng_update_shadow_config(ab, HAL_CE_DST_STATUS, i);
798d8899132SKalle Valo 		}
799d8899132SKalle Valo 	}
800d8899132SKalle Valo }
801d8899132SKalle Valo 
ath12k_ce_get_shadow_config(struct ath12k_base * ab,u32 ** shadow_cfg,u32 * shadow_cfg_len)802d8899132SKalle Valo void ath12k_ce_get_shadow_config(struct ath12k_base *ab,
803d8899132SKalle Valo 				 u32 **shadow_cfg, u32 *shadow_cfg_len)
804d8899132SKalle Valo {
805d8899132SKalle Valo 	if (!ab->hw_params->supports_shadow_regs)
806d8899132SKalle Valo 		return;
807d8899132SKalle Valo 
808d8899132SKalle Valo 	ath12k_hal_srng_get_shadow_config(ab, shadow_cfg, shadow_cfg_len);
809d8899132SKalle Valo 
810d8899132SKalle Valo 	/* shadow is already configured */
811d8899132SKalle Valo 	if (*shadow_cfg_len)
812d8899132SKalle Valo 		return;
813d8899132SKalle Valo 
814d8899132SKalle Valo 	/* shadow isn't configured yet, configure now.
815d8899132SKalle Valo 	 * non-CE srngs are configured firstly, then
816d8899132SKalle Valo 	 * all CE srngs.
817d8899132SKalle Valo 	 */
818d8899132SKalle Valo 	ath12k_hal_srng_shadow_config(ab);
819d8899132SKalle Valo 	ath12k_ce_shadow_config(ab);
820d8899132SKalle Valo 
821d8899132SKalle Valo 	/* get the shadow configuration */
822d8899132SKalle Valo 	ath12k_hal_srng_get_shadow_config(ab, shadow_cfg, shadow_cfg_len);
823d8899132SKalle Valo }
824d8899132SKalle Valo 
ath12k_ce_init_pipes(struct ath12k_base * ab)825d8899132SKalle Valo int ath12k_ce_init_pipes(struct ath12k_base *ab)
826d8899132SKalle Valo {
827d8899132SKalle Valo 	struct ath12k_ce_pipe *pipe;
828d8899132SKalle Valo 	int i;
829d8899132SKalle Valo 	int ret;
830d8899132SKalle Valo 
831d8899132SKalle Valo 	ath12k_ce_get_shadow_config(ab, &ab->qmi.ce_cfg.shadow_reg_v3,
832d8899132SKalle Valo 				    &ab->qmi.ce_cfg.shadow_reg_v3_len);
833d8899132SKalle Valo 
834d8899132SKalle Valo 	for (i = 0; i < ab->hw_params->ce_count; i++) {
835d8899132SKalle Valo 		pipe = &ab->ce.ce_pipe[i];
836d8899132SKalle Valo 
837d8899132SKalle Valo 		if (pipe->src_ring) {
838d8899132SKalle Valo 			ret = ath12k_ce_init_ring(ab, pipe->src_ring, i,
839d8899132SKalle Valo 						  HAL_CE_SRC);
840d8899132SKalle Valo 			if (ret) {
841d8899132SKalle Valo 				ath12k_warn(ab, "failed to init src ring: %d\n",
842d8899132SKalle Valo 					    ret);
843d8899132SKalle Valo 				/* Should we clear any partial init */
844d8899132SKalle Valo 				return ret;
845d8899132SKalle Valo 			}
846d8899132SKalle Valo 
847d8899132SKalle Valo 			pipe->src_ring->write_index = 0;
848d8899132SKalle Valo 			pipe->src_ring->sw_index = 0;
849d8899132SKalle Valo 		}
850d8899132SKalle Valo 
851d8899132SKalle Valo 		if (pipe->dest_ring) {
852d8899132SKalle Valo 			ret = ath12k_ce_init_ring(ab, pipe->dest_ring, i,
853d8899132SKalle Valo 						  HAL_CE_DST);
854d8899132SKalle Valo 			if (ret) {
855d8899132SKalle Valo 				ath12k_warn(ab, "failed to init dest ring: %d\n",
856d8899132SKalle Valo 					    ret);
857d8899132SKalle Valo 				/* Should we clear any partial init */
858d8899132SKalle Valo 				return ret;
859d8899132SKalle Valo 			}
860d8899132SKalle Valo 
861d8899132SKalle Valo 			pipe->rx_buf_needed = pipe->dest_ring->nentries ?
862d8899132SKalle Valo 					      pipe->dest_ring->nentries - 2 : 0;
863d8899132SKalle Valo 
864d8899132SKalle Valo 			pipe->dest_ring->write_index = 0;
865d8899132SKalle Valo 			pipe->dest_ring->sw_index = 0;
866d8899132SKalle Valo 		}
867d8899132SKalle Valo 
868d8899132SKalle Valo 		if (pipe->status_ring) {
869d8899132SKalle Valo 			ret = ath12k_ce_init_ring(ab, pipe->status_ring, i,
870d8899132SKalle Valo 						  HAL_CE_DST_STATUS);
871d8899132SKalle Valo 			if (ret) {
872d8899132SKalle Valo 				ath12k_warn(ab, "failed to init dest status ing: %d\n",
873d8899132SKalle Valo 					    ret);
874d8899132SKalle Valo 				/* Should we clear any partial init */
875d8899132SKalle Valo 				return ret;
876d8899132SKalle Valo 			}
877d8899132SKalle Valo 
878d8899132SKalle Valo 			pipe->status_ring->write_index = 0;
879d8899132SKalle Valo 			pipe->status_ring->sw_index = 0;
880d8899132SKalle Valo 		}
881d8899132SKalle Valo 	}
882d8899132SKalle Valo 
883d8899132SKalle Valo 	return 0;
884d8899132SKalle Valo }
885d8899132SKalle Valo 
ath12k_ce_free_pipes(struct ath12k_base * ab)886d8899132SKalle Valo void ath12k_ce_free_pipes(struct ath12k_base *ab)
887d8899132SKalle Valo {
888d8899132SKalle Valo 	struct ath12k_ce_pipe *pipe;
889d8899132SKalle Valo 	int desc_sz;
890d8899132SKalle Valo 	int i;
891d8899132SKalle Valo 
892d8899132SKalle Valo 	for (i = 0; i < ab->hw_params->ce_count; i++) {
893d8899132SKalle Valo 		pipe = &ab->ce.ce_pipe[i];
894d8899132SKalle Valo 
895d8899132SKalle Valo 		if (pipe->src_ring) {
896d8899132SKalle Valo 			desc_sz = ath12k_hal_ce_get_desc_size(HAL_CE_DESC_SRC);
897d8899132SKalle Valo 			dma_free_coherent(ab->dev,
898d8899132SKalle Valo 					  pipe->src_ring->nentries * desc_sz +
899d8899132SKalle Valo 					  CE_DESC_RING_ALIGN,
900d8899132SKalle Valo 					  pipe->src_ring->base_addr_owner_space,
901d8899132SKalle Valo 					  pipe->src_ring->base_addr_ce_space);
902d8899132SKalle Valo 			kfree(pipe->src_ring);
903d8899132SKalle Valo 			pipe->src_ring = NULL;
904d8899132SKalle Valo 		}
905d8899132SKalle Valo 
906d8899132SKalle Valo 		if (pipe->dest_ring) {
907d8899132SKalle Valo 			desc_sz = ath12k_hal_ce_get_desc_size(HAL_CE_DESC_DST);
908d8899132SKalle Valo 			dma_free_coherent(ab->dev,
909d8899132SKalle Valo 					  pipe->dest_ring->nentries * desc_sz +
910d8899132SKalle Valo 					  CE_DESC_RING_ALIGN,
911d8899132SKalle Valo 					  pipe->dest_ring->base_addr_owner_space,
912d8899132SKalle Valo 					  pipe->dest_ring->base_addr_ce_space);
913d8899132SKalle Valo 			kfree(pipe->dest_ring);
914d8899132SKalle Valo 			pipe->dest_ring = NULL;
915d8899132SKalle Valo 		}
916d8899132SKalle Valo 
917d8899132SKalle Valo 		if (pipe->status_ring) {
918d8899132SKalle Valo 			desc_sz =
919d8899132SKalle Valo 			  ath12k_hal_ce_get_desc_size(HAL_CE_DESC_DST_STATUS);
920d8899132SKalle Valo 			dma_free_coherent(ab->dev,
921d8899132SKalle Valo 					  pipe->status_ring->nentries * desc_sz +
922d8899132SKalle Valo 					  CE_DESC_RING_ALIGN,
923d8899132SKalle Valo 					  pipe->status_ring->base_addr_owner_space,
924d8899132SKalle Valo 					  pipe->status_ring->base_addr_ce_space);
925d8899132SKalle Valo 			kfree(pipe->status_ring);
926d8899132SKalle Valo 			pipe->status_ring = NULL;
927d8899132SKalle Valo 		}
928d8899132SKalle Valo 	}
929d8899132SKalle Valo }
930d8899132SKalle Valo 
ath12k_ce_alloc_pipes(struct ath12k_base * ab)931d8899132SKalle Valo int ath12k_ce_alloc_pipes(struct ath12k_base *ab)
932d8899132SKalle Valo {
933d8899132SKalle Valo 	struct ath12k_ce_pipe *pipe;
934d8899132SKalle Valo 	int i;
935d8899132SKalle Valo 	int ret;
936d8899132SKalle Valo 	const struct ce_attr *attr;
937d8899132SKalle Valo 
938d8899132SKalle Valo 	spin_lock_init(&ab->ce.ce_lock);
939d8899132SKalle Valo 
940d8899132SKalle Valo 	for (i = 0; i < ab->hw_params->ce_count; i++) {
941d8899132SKalle Valo 		attr = &ab->hw_params->host_ce_config[i];
942d8899132SKalle Valo 		pipe = &ab->ce.ce_pipe[i];
943d8899132SKalle Valo 		pipe->pipe_num = i;
944d8899132SKalle Valo 		pipe->ab = ab;
945d8899132SKalle Valo 		pipe->buf_sz = attr->src_sz_max;
946d8899132SKalle Valo 
947d8899132SKalle Valo 		ret = ath12k_ce_alloc_pipe(ab, i);
948d8899132SKalle Valo 		if (ret) {
949*480c9df5SColin Ian King 			/* Free any partial successful allocation */
950d8899132SKalle Valo 			ath12k_ce_free_pipes(ab);
951d8899132SKalle Valo 			return ret;
952d8899132SKalle Valo 		}
953d8899132SKalle Valo 	}
954d8899132SKalle Valo 
955d8899132SKalle Valo 	return 0;
956d8899132SKalle Valo }
957d8899132SKalle Valo 
ath12k_ce_get_attr_flags(struct ath12k_base * ab,int ce_id)958d8899132SKalle Valo int ath12k_ce_get_attr_flags(struct ath12k_base *ab, int ce_id)
959d8899132SKalle Valo {
960d8899132SKalle Valo 	if (ce_id >= ab->hw_params->ce_count)
961d8899132SKalle Valo 		return -EINVAL;
962d8899132SKalle Valo 
963d8899132SKalle Valo 	return ab->hw_params->host_ce_config[ce_id].flags;
964d8899132SKalle Valo }
965