xref: /wlan-dirver/qca-wifi-host-cmn/hif/src/ce/ce_service_srng.c (revision e2e92aa7d6099e5885f2c306e2f43aac9991c50f)
1 /*
2  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 #include "hif_io32.h"
20 #include "reg_struct.h"
21 #include "ce_api.h"
22 #include "ce_main.h"
23 #include "ce_internal.h"
24 #include "ce_reg.h"
25 #include "qdf_lock.h"
26 #include "regtable.h"
27 #include "hif_main.h"
28 #include "hif_debug.h"
29 #include "hal_api.h"
30 #include "pld_common.h"
31 #include "qdf_module.h"
32 #include "hif.h"
33 
34 /*
35  * Support for Copy Engine hardware, which is mainly used for
36  * communication between Host and Target over a PCIe interconnect.
37  */
38 
39 /*
40  * A single CopyEngine (CE) comprises two "rings":
41  *   a source ring
42  *   a destination ring
43  *
44  * Each ring consists of a number of descriptors which specify
45  * an address, length, and meta-data.
46  *
47  * Typically, one side of the PCIe interconnect (Host or Target)
48  * controls one ring and the other side controls the other ring.
49  * The source side chooses when to initiate a transfer and it
50  * chooses what to send (buffer address, length). The destination
51  * side keeps a supply of "anonymous receive buffers" available and
52  * it handles incoming data as it arrives (when the destination
53  * receives an interrupt).
54  *
55  * The sender may send a simple buffer (address/length) or it may
56  * send a small list of buffers.  When a small list is sent, hardware
57  * "gathers" these and they end up in a single destination buffer
58  * with a single interrupt.
59  *
60  * There are several "contexts" managed by this layer -- more, it
61  * may seem -- than should be needed. These are provided mainly for
62  * maximum flexibility and especially to facilitate a simpler HIF
63  * implementation. There are per-CopyEngine recv, send, and watermark
64  * contexts. These are supplied by the caller when a recv, send,
65  * or watermark handler is established and they are echoed back to
66  * the caller when the respective callbacks are invoked. There is
67  * also a per-transfer context supplied by the caller when a buffer
68  * (or sendlist) is sent and when a buffer is enqueued for recv.
69  * These per-transfer contexts are echoed back to the caller when
70  * the buffer is sent/received.
71  * Target TX harsh result toeplitz_hash_result
72  */
73 
74 #define CE_ADDR_COPY(desc, dma_addr) do {\
75 		(desc)->buffer_addr_lo = (uint32_t)((dma_addr) &\
76 							  0xFFFFFFFF);\
77 		(desc)->buffer_addr_hi =\
78 			(uint32_t)(((dma_addr) >> 32) & 0xFF);\
79 	} while (0)
80 
81 void hif_display_ctrl_traffic_pipes_state(struct hif_opaque_softc *hif_ctx)
82 {
83 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
84 	struct CE_state *CE_state;
85 	uint32_t hp = 0, tp = 0;
86 
87 	CE_state = scn->ce_id_to_state[2];
88 	hal_get_sw_hptp(scn->hal_soc,
89 			CE_state->status_ring->srng_ctx,
90 			&tp, &hp);
91 	hif_info_high("CE-2 Dest status ring current snapshot HP:%u TP:%u",
92 		      hp, tp);
93 
94 	hp = 0;
95 	tp = 0;
96 	CE_state = scn->ce_id_to_state[3];
97 	hal_get_sw_hptp(scn->hal_soc, CE_state->src_ring->srng_ctx, &tp, &hp);
98 	hif_info_high("CE-3 Source ring current snapshot HP:%u TP:%u", hp, tp);
99 }
100 
101 #if defined(HIF_CONFIG_SLUB_DEBUG_ON) || defined(HIF_CE_DEBUG_DATA_BUF)
102 void hif_record_ce_srng_desc_event(struct hif_softc *scn, int ce_id,
103 				   enum hif_ce_event_type type,
104 				   union ce_srng_desc *descriptor,
105 				   void *memory, int index,
106 				   int len, void *hal_ring)
107 {
108 	int record_index;
109 	struct hif_ce_desc_event *event;
110 	struct ce_desc_hist *ce_hist = &scn->hif_ce_desc_hist;
111 	struct hif_ce_desc_event *hist_ev = NULL;
112 
113 	if (ce_id < CE_COUNT_MAX)
114 		hist_ev = (struct hif_ce_desc_event *)ce_hist->hist_ev[ce_id];
115 	else
116 		return;
117 
118 	if (ce_id >= CE_COUNT_MAX)
119 		return;
120 
121 	if (!ce_hist->enable[ce_id])
122 		return;
123 
124 	if (!hist_ev)
125 		return;
126 
127 	record_index = get_next_record_index(
128 			&ce_hist->history_index[ce_id], HIF_CE_HISTORY_MAX);
129 
130 	event = &hist_ev[record_index];
131 
132 	hif_clear_ce_desc_debug_data(event);
133 
134 	event->type = type;
135 	event->time = qdf_get_log_timestamp();
136 	event->cpu_id = qdf_get_cpu();
137 
138 	if (descriptor)
139 		qdf_mem_copy(&event->descriptor, descriptor,
140 			     hal_get_entrysize_from_srng(hal_ring));
141 
142 	if (hal_ring)
143 		hal_get_sw_hptp(scn->hal_soc, hal_ring, &event->current_tp,
144 				&event->current_hp);
145 
146 	event->memory = memory;
147 	event->index = index;
148 
149 	if (event->type == HIF_CE_SRC_RING_BUFFER_POST)
150 		hif_ce_desc_record_rx_paddr(scn, event, memory);
151 
152 	if (ce_hist->data_enable[ce_id])
153 		hif_ce_desc_data_record(event, len);
154 
155 	hif_record_latest_evt(ce_hist, type, ce_id, event->time,
156 			      event->current_hp, event->current_tp);
157 }
158 #endif /* HIF_CONFIG_SLUB_DEBUG_ON || HIF_CE_DEBUG_DATA_BUF */
159 
160 static QDF_STATUS
161 ce_send_nolock_srng(struct CE_handle *copyeng,
162 			   void *per_transfer_context,
163 			   qdf_dma_addr_t buffer,
164 			   uint32_t nbytes,
165 			   uint32_t transfer_id,
166 			   uint32_t flags,
167 			   uint32_t user_flags)
168 {
169 	QDF_STATUS status;
170 	struct CE_state *CE_state = (struct CE_state *)copyeng;
171 	struct CE_ring_state *src_ring = CE_state->src_ring;
172 	unsigned int nentries_mask = src_ring->nentries_mask;
173 	unsigned int write_index = src_ring->write_index;
174 	uint64_t dma_addr = buffer;
175 	struct hif_softc *scn = CE_state->scn;
176 
177 	if (Q_TARGET_ACCESS_BEGIN(scn) < 0)
178 		return QDF_STATUS_E_FAILURE;
179 	if (unlikely(hal_srng_src_num_avail(scn->hal_soc, src_ring->srng_ctx,
180 					false) <= 0)) {
181 		OL_ATH_CE_PKT_ERROR_COUNT_INCR(scn, CE_RING_DELTA_FAIL);
182 		Q_TARGET_ACCESS_END(scn);
183 		return QDF_STATUS_E_FAILURE;
184 	}
185 	{
186 		enum hif_ce_event_type event_type = HIF_CE_SRC_RING_BUFFER_POST;
187 		struct ce_srng_src_desc *src_desc;
188 
189 		if (hal_srng_access_start(scn->hal_soc, src_ring->srng_ctx)) {
190 			Q_TARGET_ACCESS_END(scn);
191 			return QDF_STATUS_E_FAILURE;
192 		}
193 
194 		src_desc = hal_srng_src_get_next_reaped(scn->hal_soc,
195 				src_ring->srng_ctx);
196 		if (!src_desc) {
197 			Q_TARGET_ACCESS_END(scn);
198 			return QDF_STATUS_E_INVAL;
199 		}
200 
201 		/* Update low 32 bits source descriptor address */
202 		src_desc->buffer_addr_lo =
203 			(uint32_t)(dma_addr & 0xFFFFFFFF);
204 		src_desc->buffer_addr_hi =
205 			(uint32_t)((dma_addr >> 32) & 0xFF);
206 
207 		src_desc->meta_data = transfer_id;
208 
209 		/*
210 		 * Set the swap bit if:
211 		 * typical sends on this CE are swapped (host is big-endian)
212 		 * and this send doesn't disable the swapping
213 		 * (data is not bytestream)
214 		 */
215 		src_desc->byte_swap =
216 			(((CE_state->attr_flags & CE_ATTR_BYTE_SWAP_DATA)
217 			  != 0) & ((flags & CE_SEND_FLAG_SWAP_DISABLE) == 0));
218 		src_desc->gather = ((flags & CE_SEND_FLAG_GATHER) != 0);
219 		src_desc->nbytes = nbytes;
220 
221 		src_ring->per_transfer_context[write_index] =
222 			per_transfer_context;
223 		write_index = CE_RING_IDX_INCR(nentries_mask, write_index);
224 
225 		hal_srng_access_end(scn->hal_soc, src_ring->srng_ctx);
226 
227 		/* src_ring->write index hasn't been updated event though
228 		 * the register has already been written to.
229 		 */
230 		hif_record_ce_srng_desc_event(scn, CE_state->id, event_type,
231 					      (union ce_srng_desc *)src_desc,
232 					      per_transfer_context,
233 					      src_ring->write_index, nbytes,
234 					      src_ring->srng_ctx);
235 
236 		src_ring->write_index = write_index;
237 		status = QDF_STATUS_SUCCESS;
238 	}
239 	Q_TARGET_ACCESS_END(scn);
240 	return status;
241 }
242 
243 static QDF_STATUS
244 ce_sendlist_send_srng(struct CE_handle *copyeng,
245 		 void *per_transfer_context,
246 		 struct ce_sendlist *sendlist, unsigned int transfer_id)
247 {
248 	QDF_STATUS status = QDF_STATUS_E_NOMEM;
249 	struct ce_sendlist_s *sl = (struct ce_sendlist_s *)sendlist;
250 	struct CE_state *CE_state = (struct CE_state *)copyeng;
251 	struct CE_ring_state *src_ring = CE_state->src_ring;
252 	unsigned int num_items = sl->num_items;
253 	unsigned int sw_index;
254 	unsigned int write_index;
255 	struct hif_softc *scn = CE_state->scn;
256 
257 	QDF_ASSERT((num_items > 0) && (num_items < src_ring->nentries));
258 
259 	qdf_spin_lock_bh(&CE_state->ce_index_lock);
260 	sw_index = src_ring->sw_index;
261 	write_index = src_ring->write_index;
262 
263 	if (hal_srng_src_num_avail(scn->hal_soc, src_ring->srng_ctx, false) >=
264 	    num_items) {
265 		struct ce_sendlist_item *item;
266 		int i;
267 
268 		/* handle all but the last item uniformly */
269 		for (i = 0; i < num_items - 1; i++) {
270 			item = &sl->item[i];
271 			/* TBDXXX: Support extensible sendlist_types? */
272 			QDF_ASSERT(item->send_type == CE_SIMPLE_BUFFER_TYPE);
273 			status = ce_send_nolock_srng(copyeng,
274 					CE_SENDLIST_ITEM_CTXT,
275 				(qdf_dma_addr_t) item->data,
276 				item->u.nbytes, transfer_id,
277 				item->flags | CE_SEND_FLAG_GATHER,
278 				item->user_flags);
279 			QDF_ASSERT(status == QDF_STATUS_SUCCESS);
280 		}
281 		/* provide valid context pointer for final item */
282 		item = &sl->item[i];
283 		/* TBDXXX: Support extensible sendlist_types? */
284 		QDF_ASSERT(item->send_type == CE_SIMPLE_BUFFER_TYPE);
285 		status = ce_send_nolock_srng(copyeng, per_transfer_context,
286 					(qdf_dma_addr_t) item->data,
287 					item->u.nbytes,
288 					transfer_id, item->flags,
289 					item->user_flags);
290 		QDF_ASSERT(status == QDF_STATUS_SUCCESS);
291 		QDF_NBUF_UPDATE_TX_PKT_COUNT((qdf_nbuf_t)per_transfer_context,
292 					QDF_NBUF_TX_PKT_CE);
293 		DPTRACE(qdf_dp_trace((qdf_nbuf_t)per_transfer_context,
294 			QDF_DP_TRACE_CE_PACKET_PTR_RECORD,
295 			QDF_TRACE_DEFAULT_PDEV_ID,
296 			(uint8_t *)(((qdf_nbuf_t)per_transfer_context)->data),
297 			sizeof(((qdf_nbuf_t)per_transfer_context)->data), QDF_TX));
298 	} else {
299 		/*
300 		 * Probably not worth the additional complexity to support
301 		 * partial sends with continuation or notification.  We expect
302 		 * to use large rings and small sendlists. If we can't handle
303 		 * the entire request at once, punt it back to the caller.
304 		 */
305 	}
306 	qdf_spin_unlock_bh(&CE_state->ce_index_lock);
307 
308 	return status;
309 }
310 
311 #define SLOTS_PER_DATAPATH_TX 2
312 
313 #ifndef AH_NEED_TX_DATA_SWAP
314 #define AH_NEED_TX_DATA_SWAP 0
315 #endif
316 /**
317  * ce_recv_buf_enqueue_srng() - enqueue a recv buffer into a copy engine
318  * @copyeng: copy engine handle
319  * @per_recv_context: virtual address of the nbuf
320  * @buffer: physical address of the nbuf
321  *
322  * Return: QDF_STATUS_SUCCESS if the buffer is enqueued
323  */
324 static QDF_STATUS
325 ce_recv_buf_enqueue_srng(struct CE_handle *copyeng,
326 		    void *per_recv_context, qdf_dma_addr_t buffer)
327 {
328 	QDF_STATUS status;
329 	struct CE_state *CE_state = (struct CE_state *)copyeng;
330 	struct CE_ring_state *dest_ring = CE_state->dest_ring;
331 	unsigned int nentries_mask = dest_ring->nentries_mask;
332 	unsigned int write_index;
333 	unsigned int sw_index;
334 	uint64_t dma_addr = buffer;
335 	struct hif_softc *scn = CE_state->scn;
336 	struct ce_srng_dest_desc *dest_desc = NULL;
337 
338 	qdf_spin_lock_bh(&CE_state->ce_index_lock);
339 	write_index = dest_ring->write_index;
340 	sw_index = dest_ring->sw_index;
341 
342 	if (Q_TARGET_ACCESS_BEGIN(scn) < 0) {
343 		qdf_spin_unlock_bh(&CE_state->ce_index_lock);
344 		return QDF_STATUS_E_IO;
345 	}
346 
347 	/* HP/TP update if any should happen only once per interrupt,
348 	 * therefore checking for CE receive_count.
349 	 */
350 	hal_srng_check_and_update_hptp(scn->hal_soc, dest_ring->srng_ctx,
351 				       !CE_state->receive_count);
352 
353 	if (hal_srng_access_start(scn->hal_soc, dest_ring->srng_ctx)) {
354 		qdf_spin_unlock_bh(&CE_state->ce_index_lock);
355 		return QDF_STATUS_E_FAILURE;
356 	}
357 
358 	if ((hal_srng_src_num_avail(scn->hal_soc,
359 					dest_ring->srng_ctx, false) > 0)) {
360 		dest_desc = hal_srng_src_get_next(scn->hal_soc,
361 						  dest_ring->srng_ctx);
362 
363 		if (!dest_desc) {
364 			status = QDF_STATUS_E_FAILURE;
365 		} else {
366 
367 			CE_ADDR_COPY(dest_desc, dma_addr);
368 
369 			dest_ring->per_transfer_context[write_index] =
370 				per_recv_context;
371 
372 			/* Update Destination Ring Write Index */
373 			write_index = CE_RING_IDX_INCR(nentries_mask,
374 								write_index);
375 			status = QDF_STATUS_SUCCESS;
376 		}
377 	} else {
378 		dest_desc = NULL;
379 		status = QDF_STATUS_E_FAILURE;
380 	}
381 
382 	dest_ring->write_index = write_index;
383 	hal_srng_access_end(scn->hal_soc, dest_ring->srng_ctx);
384 	hif_record_ce_srng_desc_event(scn, CE_state->id,
385 				      HIF_CE_DEST_RING_BUFFER_POST,
386 				      (union ce_srng_desc *)dest_desc,
387 				      per_recv_context,
388 				      dest_ring->write_index, 0,
389 				      dest_ring->srng_ctx);
390 
391 	Q_TARGET_ACCESS_END(scn);
392 	qdf_spin_unlock_bh(&CE_state->ce_index_lock);
393 	return status;
394 }
395 
396 /*
397  * Guts of ce_recv_entries_done.
398  * The caller takes responsibility for any necessary locking.
399  */
400 static unsigned int
401 ce_recv_entries_done_nolock_srng(struct hif_softc *scn,
402 			    struct CE_state *CE_state)
403 {
404 	struct CE_ring_state *status_ring = CE_state->status_ring;
405 
406 	return hal_srng_dst_num_valid(scn->hal_soc,
407 				status_ring->srng_ctx, false);
408 }
409 
410 /*
411  * Guts of ce_send_entries_done.
412  * The caller takes responsibility for any necessary locking.
413  */
414 static unsigned int
415 ce_send_entries_done_nolock_srng(struct hif_softc *scn,
416 					struct CE_state *CE_state)
417 {
418 
419 	struct CE_ring_state *src_ring = CE_state->src_ring;
420 	int count = 0;
421 
422 	if (hal_srng_access_start(scn->hal_soc, src_ring->srng_ctx))
423 		return 0;
424 
425 	count = hal_srng_src_done_val(scn->hal_soc, src_ring->srng_ctx);
426 
427 	hal_srng_access_end_reap(scn->hal_soc, src_ring->srng_ctx);
428 
429 	return count;
430 }
431 
432 /*
433  * Guts of ce_completed_recv_next.
434  * The caller takes responsibility for any necessary locking.
435  */
436 static QDF_STATUS
437 ce_completed_recv_next_nolock_srng(struct CE_state *CE_state,
438 			      void **per_CE_contextp,
439 			      void **per_transfer_contextp,
440 			      qdf_dma_addr_t *bufferp,
441 			      unsigned int *nbytesp,
442 			      unsigned int *transfer_idp,
443 			      unsigned int *flagsp)
444 {
445 	QDF_STATUS status;
446 	struct CE_ring_state *dest_ring = CE_state->dest_ring;
447 	struct CE_ring_state *status_ring = CE_state->status_ring;
448 	unsigned int nentries_mask = dest_ring->nentries_mask;
449 	unsigned int sw_index = dest_ring->sw_index;
450 	struct hif_softc *scn = CE_state->scn;
451 	struct ce_srng_dest_status_desc *dest_status = NULL;
452 	int nbytes;
453 	struct ce_srng_dest_status_desc dest_status_info;
454 
455 	/* HP/TP update if any should happen only once per interrupt,
456 	 * therefore checking for CE receive_count.
457 	 */
458 	hal_srng_check_and_update_hptp(scn->hal_soc, status_ring->srng_ctx,
459 				       !CE_state->receive_count);
460 
461 	if (hal_srng_access_start(scn->hal_soc, status_ring->srng_ctx))
462 		return QDF_STATUS_E_FAILURE;
463 
464 	dest_status = hal_srng_dst_peek(scn->hal_soc, status_ring->srng_ctx);
465 	if (!dest_status) {
466 		hal_srng_access_end_reap(scn->hal_soc, status_ring->srng_ctx);
467 		return QDF_STATUS_E_FAILURE;
468 	}
469 
470 	/*
471 	 * By copying the dest_desc_info element to local memory, we could
472 	 * avoid extra memory read from non-cachable memory.
473 	 */
474 	dest_status_info = *dest_status;
475 	nbytes = dest_status_info.nbytes;
476 	if (nbytes == 0) {
477 		uint32_t hp, tp;
478 
479 		/*
480 		 * This closes a relatively unusual race where the Host
481 		 * sees the updated DRRI before the update to the
482 		 * corresponding descriptor has completed. We treat this
483 		 * as a descriptor that is not yet done.
484 		 */
485 		hal_get_sw_hptp(scn->hal_soc, status_ring->srng_ctx,
486 				&tp, &hp);
487 		hif_info_rl("No data to reap, hp %d tp %d", hp, tp);
488 		status = QDF_STATUS_E_FAILURE;
489 		hal_srng_access_end_reap(scn->hal_soc, status_ring->srng_ctx);
490 		goto done;
491 	}
492 
493 	/*
494 	 * Move the tail pointer since nbytes is non-zero and
495 	 * this entry is processed.
496 	 */
497 	hal_srng_dst_get_next(scn->hal_soc, status_ring->srng_ctx);
498 
499 	dest_status->nbytes = 0;
500 
501 	*nbytesp = nbytes;
502 	*transfer_idp = dest_status_info.meta_data;
503 	*flagsp = (dest_status_info.byte_swap) ? CE_RECV_FLAG_SWAPPED : 0;
504 
505 	if (per_CE_contextp)
506 		*per_CE_contextp = CE_state->recv_context;
507 
508 	/* NOTE: sw_index is more like a read_index in this context. It has a
509 	 * one-to-one mapping with status ring.
510 	 * Get the per trasnfer context from dest_ring.
511 	 */
512 	if (per_transfer_contextp)
513 		*per_transfer_contextp =
514 			dest_ring->per_transfer_context[sw_index];
515 
516 	dest_ring->per_transfer_context[sw_index] = 0;  /* sanity */
517 
518 	/* Update sw_index */
519 	sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index);
520 	dest_ring->sw_index = sw_index;
521 	status = QDF_STATUS_SUCCESS;
522 
523 	hal_srng_access_end(scn->hal_soc, status_ring->srng_ctx);
524 	hif_record_ce_srng_desc_event(scn, CE_state->id,
525 				      HIF_CE_DEST_RING_BUFFER_REAP,
526 				      NULL,
527 				      dest_ring->
528 				      per_transfer_context[sw_index],
529 				      dest_ring->sw_index, nbytes,
530 				      dest_ring->srng_ctx);
531 
532 done:
533 	hif_record_ce_srng_desc_event(scn, CE_state->id,
534 				      HIF_CE_DEST_STATUS_RING_REAP,
535 				      (union ce_srng_desc *)dest_status,
536 				      NULL,
537 				      -1, 0,
538 				      status_ring->srng_ctx);
539 
540 	return status;
541 }
542 
543 static QDF_STATUS
544 ce_revoke_recv_next_srng(struct CE_handle *copyeng,
545 		    void **per_CE_contextp,
546 		    void **per_transfer_contextp, qdf_dma_addr_t *bufferp)
547 {
548 	struct CE_state *CE_state = (struct CE_state *)copyeng;
549 	struct CE_ring_state *dest_ring = CE_state->dest_ring;
550 	unsigned int sw_index;
551 
552 	if (!dest_ring)
553 		return QDF_STATUS_E_FAILURE;
554 
555 	sw_index = dest_ring->sw_index;
556 
557 	if (per_CE_contextp)
558 		*per_CE_contextp = CE_state->recv_context;
559 
560 	/* NOTE: sw_index is more like a read_index in this context. It has a
561 	 * one-to-one mapping with status ring.
562 	 * Get the per trasnfer context from dest_ring.
563 	 */
564 	if (per_transfer_contextp)
565 		*per_transfer_contextp =
566 			dest_ring->per_transfer_context[sw_index];
567 
568 	if (!dest_ring->per_transfer_context[sw_index])
569 		return QDF_STATUS_E_FAILURE;
570 
571 	/* provide end condition */
572 	dest_ring->per_transfer_context[sw_index] = NULL;
573 
574 	/* Update sw_index */
575 	sw_index = CE_RING_IDX_INCR(dest_ring->nentries_mask, sw_index);
576 	dest_ring->sw_index = sw_index;
577 	return QDF_STATUS_SUCCESS;
578 }
579 
580 /*
581  * Guts of ce_completed_send_next.
582  * The caller takes responsibility for any necessary locking.
583  */
584 static QDF_STATUS
585 ce_completed_send_next_nolock_srng(struct CE_state *CE_state,
586 			      void **per_CE_contextp,
587 			      void **per_transfer_contextp,
588 			      qdf_dma_addr_t *bufferp,
589 			      unsigned int *nbytesp,
590 			      unsigned int *transfer_idp,
591 			      unsigned int *sw_idx,
592 			      unsigned int *hw_idx,
593 			      uint32_t *toeplitz_hash_result)
594 {
595 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
596 	struct CE_ring_state *src_ring = CE_state->src_ring;
597 	unsigned int nentries_mask = src_ring->nentries_mask;
598 	unsigned int sw_index = src_ring->sw_index;
599 	unsigned int swi = src_ring->sw_index;
600 	struct hif_softc *scn = CE_state->scn;
601 	struct ce_srng_src_desc *src_desc;
602 
603 	if (hal_srng_access_start(scn->hal_soc, src_ring->srng_ctx)) {
604 		status = QDF_STATUS_E_FAILURE;
605 		return status;
606 	}
607 
608 	src_desc = hal_srng_src_reap_next(scn->hal_soc, src_ring->srng_ctx);
609 	if (src_desc) {
610 		hif_record_ce_srng_desc_event(scn, CE_state->id,
611 					      HIF_TX_DESC_COMPLETION,
612 					      (union ce_srng_desc *)src_desc,
613 					      src_ring->
614 					      per_transfer_context[swi],
615 					      swi, src_desc->nbytes,
616 					      src_ring->srng_ctx);
617 
618 		/* Return data from completed source descriptor */
619 		*bufferp = (qdf_dma_addr_t)
620 			(((uint64_t)(src_desc)->buffer_addr_lo +
621 			  ((uint64_t)((src_desc)->buffer_addr_hi &
622 				  0xFF) << 32)));
623 		*nbytesp = src_desc->nbytes;
624 		*transfer_idp = src_desc->meta_data;
625 		*toeplitz_hash_result = 0; /*src_desc->toeplitz_hash_result;*/
626 
627 		if (per_CE_contextp)
628 			*per_CE_contextp = CE_state->send_context;
629 
630 		/* sw_index is used more like read index */
631 		if (per_transfer_contextp)
632 			*per_transfer_contextp =
633 				src_ring->per_transfer_context[sw_index];
634 
635 		src_ring->per_transfer_context[sw_index] = 0;   /* sanity */
636 
637 		/* Update sw_index */
638 		sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index);
639 		src_ring->sw_index = sw_index;
640 		status = QDF_STATUS_SUCCESS;
641 	}
642 	hal_srng_access_end_reap(scn->hal_soc, src_ring->srng_ctx);
643 
644 	return status;
645 }
646 
647 /* NB: Modelled after ce_completed_send_next */
648 static QDF_STATUS
649 ce_cancel_send_next_srng(struct CE_handle *copyeng,
650 		void **per_CE_contextp,
651 		void **per_transfer_contextp,
652 		qdf_dma_addr_t *bufferp,
653 		unsigned int *nbytesp,
654 		unsigned int *transfer_idp,
655 		uint32_t *toeplitz_hash_result)
656 {
657 	struct CE_state *CE_state;
658 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
659 	struct CE_ring_state *src_ring;
660 	unsigned int nentries_mask;
661 	unsigned int sw_index;
662 	struct hif_softc *scn;
663 	struct ce_srng_src_desc *src_desc;
664 
665 	CE_state = (struct CE_state *)copyeng;
666 	src_ring = CE_state->src_ring;
667 	if (!src_ring)
668 		return QDF_STATUS_E_FAILURE;
669 
670 	nentries_mask = src_ring->nentries_mask;
671 	sw_index = src_ring->sw_index;
672 	scn = CE_state->scn;
673 
674 	if (hal_srng_access_start(scn->hal_soc, src_ring->srng_ctx)) {
675 		status = QDF_STATUS_E_FAILURE;
676 		return status;
677 	}
678 
679 	src_desc = hal_srng_src_pending_reap_next(scn->hal_soc,
680 			src_ring->srng_ctx);
681 	if (src_desc) {
682 		/* Return data from completed source descriptor */
683 		*bufferp = (qdf_dma_addr_t)
684 			(((uint64_t)(src_desc)->buffer_addr_lo +
685 			  ((uint64_t)((src_desc)->buffer_addr_hi &
686 				  0xFF) << 32)));
687 		*nbytesp = src_desc->nbytes;
688 		*transfer_idp = src_desc->meta_data;
689 		*toeplitz_hash_result = 0; /*src_desc->toeplitz_hash_result;*/
690 
691 		if (per_CE_contextp)
692 			*per_CE_contextp = CE_state->send_context;
693 
694 		/* sw_index is used more like read index */
695 		if (per_transfer_contextp)
696 			*per_transfer_contextp =
697 				src_ring->per_transfer_context[sw_index];
698 
699 		src_ring->per_transfer_context[sw_index] = 0;   /* sanity */
700 
701 		/* Update sw_index */
702 		sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index);
703 		src_ring->sw_index = sw_index;
704 		status = QDF_STATUS_SUCCESS;
705 	}
706 	hal_srng_access_end_reap(scn->hal_soc, src_ring->srng_ctx);
707 
708 	return status;
709 }
710 
711 /*
712  * Adjust interrupts for the copy complete handler.
713  * If it's needed for either send or recv, then unmask
714  * this interrupt; otherwise, mask it.
715  *
716  * Called with target_lock held.
717  */
718 static void
719 ce_per_engine_handler_adjust_srng(struct CE_state *CE_state,
720 			     int disable_copy_compl_intr)
721 {
722 }
723 
724 static bool ce_check_int_watermark_srng(struct CE_state *CE_state,
725 					unsigned int *flags)
726 {
727 	/*TODO*/
728 	return false;
729 }
730 
731 static uint32_t ce_get_desc_size_srng(uint8_t ring_type)
732 {
733 	switch (ring_type) {
734 	case CE_RING_SRC:
735 		return sizeof(struct ce_srng_src_desc);
736 	case CE_RING_DEST:
737 		return sizeof(struct ce_srng_dest_desc);
738 	case CE_RING_STATUS:
739 		return sizeof(struct ce_srng_dest_status_desc);
740 	default:
741 		return 0;
742 	}
743 	return 0;
744 }
745 
746 static void ce_srng_msi_ring_params_setup(struct hif_softc *scn, uint32_t ce_id,
747 			      struct hal_srng_params *ring_params)
748 {
749 	uint32_t addr_low;
750 	uint32_t addr_high;
751 	uint32_t msi_data_start;
752 	uint32_t msi_data_count;
753 	uint32_t msi_irq_start;
754 	int ret;
755 	int irq_id;
756 
757 	ret = pld_get_user_msi_assignment(scn->qdf_dev->dev, "CE",
758 					  &msi_data_count, &msi_data_start,
759 					  &msi_irq_start);
760 
761 	/* msi config not found */
762 	if (ret)
763 		return;
764 
765 	irq_id = scn->int_assignment->msi_idx[ce_id];
766 	pld_get_msi_address(scn->qdf_dev->dev, &addr_low, &addr_high);
767 
768 	ring_params->msi_addr = addr_low;
769 	ring_params->msi_addr |= (qdf_dma_addr_t)(((uint64_t)addr_high) << 32);
770 	ring_params->msi_data =  irq_id + msi_data_start;
771 	ring_params->flags |= HAL_SRNG_MSI_INTR;
772 
773 	hif_debug("ce_id %d irq_id %d, msi_addr %pK, msi_data %d", ce_id,
774 		  irq_id, (void *)ring_params->msi_addr, ring_params->msi_data);
775 }
776 
777 static void ce_srng_src_ring_setup(struct hif_softc *scn, uint32_t ce_id,
778 				   struct CE_ring_state *src_ring,
779 				   struct CE_attr *attr)
780 {
781 	struct hal_srng_params ring_params = {0};
782 
783 	hif_debug("%s: ce_id %d", __func__, ce_id);
784 
785 	ring_params.ring_base_paddr = src_ring->base_addr_CE_space;
786 	ring_params.ring_base_vaddr = src_ring->base_addr_owner_space;
787 	ring_params.num_entries = src_ring->nentries;
788 	/*
789 	 * The minimum increment for the timer is 8us
790 	 * A default value of 0 disables the timer
791 	 * A valid default value caused continuous interrupts to
792 	 * fire with MSI enabled. Need to revisit usage of the timer
793 	 */
794 
795 	if (!(CE_ATTR_DISABLE_INTR & attr->flags)) {
796 		ce_srng_msi_ring_params_setup(scn, ce_id, &ring_params);
797 
798 		ring_params.intr_timer_thres_us = 0;
799 		ring_params.intr_batch_cntr_thres_entries = 1;
800 		ring_params.prefetch_timer = HAL_SRNG_PREFETCH_TIMER;
801 	}
802 
803 	src_ring->srng_ctx = hal_srng_setup(scn->hal_soc, CE_SRC, ce_id, 0,
804 					    &ring_params, 0);
805 }
806 
807 #ifdef WLAN_WAR_CE_DISABLE_SRNG_TIMER_IRQ
808 static void
809 ce_srng_initialize_dest_ring_thresh(struct CE_ring_state *dest_ring,
810 				    struct hal_srng_params *ring_params)
811 {
812 	ring_params->low_threshold = dest_ring->nentries >> 3;
813 	ring_params->intr_timer_thres_us = 0;
814 	ring_params->intr_batch_cntr_thres_entries = 1;
815 	ring_params->flags |= HAL_SRNG_LOW_THRES_INTR_ENABLE;
816 }
817 #else
818 static void
819 ce_srng_initialize_dest_ring_thresh(struct CE_ring_state *dest_ring,
820 				    struct hal_srng_params *ring_params)
821 {
822 	ring_params->low_threshold = dest_ring->nentries >> 3;
823 	ring_params->intr_timer_thres_us = 100000;
824 	ring_params->intr_batch_cntr_thres_entries = 0;
825 	ring_params->flags |= HAL_SRNG_LOW_THRES_INTR_ENABLE;
826 }
827 #endif
828 
829 #ifdef WLAN_DISABLE_STATUS_RING_TIMER_WAR
830 static inline bool ce_is_status_ring_timer_thresh_war_needed(void)
831 {
832 	return false;
833 }
834 #else
835 static inline bool ce_is_status_ring_timer_thresh_war_needed(void)
836 {
837 	return true;
838 }
839 #endif
840 
841 /**
842  * ce_srng_initialize_dest_timer_interrupt_war() - war initialization
843  * @dest_ring: ring being initialized
844  * @ring_params: pointer to initialized parameters
845  *
846  * For Napier & Hawkeye v1, the status ring timer interrupts do not work
847  * As a workaround host configures the destination rings to be a proxy for
848  * work needing to be done.
849  *
850  * The interrupts are setup such that if the destination ring is less than fully
851  * posted, there is likely undone work for the status ring that the host should
852  * process.
853  *
854  * There is a timing bug in srng based copy engines such that a fully posted
855  * srng based copy engine has 2 empty entries instead of just one.  The copy
856  * engine data structures work with 1 empty entry, but the software frequently
857  * fails to post the last entry due to the race condition.
858  */
859 static void ce_srng_initialize_dest_timer_interrupt_war(
860 					struct CE_ring_state *dest_ring,
861 					struct hal_srng_params *ring_params)
862 {
863 	int num_buffers_when_fully_posted = dest_ring->nentries - 2;
864 
865 	ring_params->low_threshold = num_buffers_when_fully_posted - 1;
866 	ring_params->intr_timer_thres_us = 1024;
867 	ring_params->intr_batch_cntr_thres_entries = 0;
868 	ring_params->flags |= HAL_SRNG_LOW_THRES_INTR_ENABLE;
869 }
870 
871 static void ce_srng_dest_ring_setup(struct hif_softc *scn,
872 				    uint32_t ce_id,
873 				    struct CE_ring_state *dest_ring,
874 				    struct CE_attr *attr)
875 {
876 	struct hal_srng_params ring_params = {0};
877 
878 	hif_debug("ce_id: %d", ce_id);
879 
880 	ring_params.ring_base_paddr = dest_ring->base_addr_CE_space;
881 	ring_params.ring_base_vaddr = dest_ring->base_addr_owner_space;
882 	ring_params.num_entries = dest_ring->nentries;
883 	ring_params.max_buffer_length = attr->src_sz_max;
884 
885 	if (!(CE_ATTR_DISABLE_INTR & attr->flags)) {
886 		ce_srng_msi_ring_params_setup(scn, ce_id, &ring_params);
887 		if (ce_is_status_ring_timer_thresh_war_needed()) {
888 			ce_srng_initialize_dest_timer_interrupt_war(
889 					dest_ring, &ring_params);
890 		} else {
891 			/* normal behavior for future chips */
892 			ce_srng_initialize_dest_ring_thresh(dest_ring,
893 							    &ring_params);
894 		}
895 		ring_params.prefetch_timer = HAL_SRNG_PREFETCH_TIMER;
896 	}
897 
898 	/*Dest ring is also source ring*/
899 	dest_ring->srng_ctx = hal_srng_setup(scn->hal_soc, CE_DST, ce_id, 0,
900 					     &ring_params, 0);
901 }
902 
903 #ifdef WLAN_CE_INTERRUPT_THRESHOLD_CONFIG
904 /**
905  * ce_status_ring_config_int_threshold() - configure ce status ring interrupt
906  *                                         thresholds
907  * @scn: hif handle
908  * @ring_params: ce srng params
909  *
910  * Return: None
911  */
912 static inline
913 void ce_status_ring_config_int_threshold(struct hif_softc *scn,
914 					 struct hal_srng_params *ring_params)
915 {
916 	ring_params->intr_timer_thres_us =
917 			scn->ini_cfg.ce_status_ring_timer_threshold;
918 	ring_params->intr_batch_cntr_thres_entries =
919 			scn->ini_cfg.ce_status_ring_batch_count_threshold;
920 }
921 #else
922 static inline
923 void ce_status_ring_config_int_threshold(struct hif_softc *scn,
924 					 struct hal_srng_params *ring_params)
925 {
926 	ring_params->intr_timer_thres_us = 0x1000;
927 	ring_params->intr_batch_cntr_thres_entries = 0x1;
928 }
929 #endif /* WLAN_CE_INTERRUPT_THRESHOLD_CONFIG */
930 
931 static void ce_srng_status_ring_setup(struct hif_softc *scn, uint32_t ce_id,
932 				struct CE_ring_state *status_ring,
933 				struct CE_attr *attr)
934 {
935 	struct hal_srng_params ring_params = {0};
936 
937 	hif_debug("ce_id: %d", ce_id);
938 
939 	ring_params.ring_base_paddr = status_ring->base_addr_CE_space;
940 	ring_params.ring_base_vaddr = status_ring->base_addr_owner_space;
941 	ring_params.num_entries = status_ring->nentries;
942 
943 	if (!(CE_ATTR_DISABLE_INTR & attr->flags)) {
944 		ce_srng_msi_ring_params_setup(scn, ce_id, &ring_params);
945 		ce_status_ring_config_int_threshold(scn, &ring_params);
946 	}
947 
948 	status_ring->srng_ctx = hal_srng_setup(scn->hal_soc, CE_DST_STATUS,
949 					       ce_id, 0, &ring_params, 0);
950 }
951 
952 static int ce_ring_setup_srng(struct hif_softc *scn, uint8_t ring_type,
953 		uint32_t ce_id, struct CE_ring_state *ring,
954 		struct CE_attr *attr)
955 {
956 	switch (ring_type) {
957 	case CE_RING_SRC:
958 		ce_srng_src_ring_setup(scn, ce_id, ring, attr);
959 		break;
960 	case CE_RING_DEST:
961 		ce_srng_dest_ring_setup(scn, ce_id, ring, attr);
962 		break;
963 	case CE_RING_STATUS:
964 		ce_srng_status_ring_setup(scn, ce_id, ring, attr);
965 		break;
966 	default:
967 		qdf_assert(0);
968 		break;
969 	}
970 
971 	return 0;
972 }
973 
974 static void ce_ring_cleanup_srng(struct hif_softc *scn,
975 				 struct CE_state *CE_state,
976 				 uint8_t ring_type)
977 {
978 	hal_ring_handle_t hal_srng = NULL;
979 
980 	switch (ring_type) {
981 	case CE_RING_SRC:
982 		hal_srng = (hal_ring_handle_t)CE_state->src_ring->srng_ctx;
983 	break;
984 	case CE_RING_DEST:
985 		hal_srng = (hal_ring_handle_t)CE_state->dest_ring->srng_ctx;
986 	break;
987 	case CE_RING_STATUS:
988 		hal_srng = (hal_ring_handle_t)CE_state->status_ring->srng_ctx;
989 	break;
990 	}
991 
992 	if (hal_srng)
993 		hal_srng_cleanup(scn->hal_soc, hal_srng, 0);
994 }
995 
996 static void ce_construct_shadow_config_srng(struct hif_softc *scn)
997 {
998 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
999 	int ce_id;
1000 
1001 	for (ce_id = 0; ce_id < scn->ce_count; ce_id++) {
1002 		if (hif_state->host_ce_config[ce_id].src_nentries)
1003 			hal_set_one_shadow_config(scn->hal_soc,
1004 						  CE_SRC, ce_id);
1005 
1006 		if (hif_state->host_ce_config[ce_id].dest_nentries) {
1007 			hal_set_one_shadow_config(scn->hal_soc,
1008 						  CE_DST, ce_id);
1009 
1010 			hal_set_one_shadow_config(scn->hal_soc,
1011 						  CE_DST_STATUS, ce_id);
1012 		}
1013 	}
1014 }
1015 
1016 static void ce_prepare_shadow_register_v2_cfg_srng(struct hif_softc *scn,
1017 		struct pld_shadow_reg_v2_cfg **shadow_config,
1018 		int *num_shadow_registers_configured)
1019 {
1020 	if (!scn->hal_soc) {
1021 		hif_err("hal not initialized: not initializing shadow config");
1022 		return;
1023 	}
1024 
1025 	hal_get_shadow_config(scn->hal_soc, shadow_config,
1026 			      num_shadow_registers_configured);
1027 
1028 	if (*num_shadow_registers_configured != 0) {
1029 		hif_err("hal shadow register configuration already constructed");
1030 
1031 		/* return with original configuration*/
1032 		return;
1033 	}
1034 	hal_construct_srng_shadow_regs(scn->hal_soc);
1035 	ce_construct_shadow_config_srng(scn);
1036 	hal_set_shadow_regs(scn->hal_soc);
1037 	hal_construct_shadow_regs(scn->hal_soc);
1038 	/* get updated configuration */
1039 	hal_get_shadow_config(scn->hal_soc, shadow_config,
1040 			      num_shadow_registers_configured);
1041 }
1042 
1043 #ifdef CONFIG_SHADOW_V3
1044 static void ce_prepare_shadow_register_v3_cfg_srng(struct hif_softc *scn,
1045 		struct pld_shadow_reg_v3_cfg **shadow_config,
1046 		int *num_shadow_registers_configured)
1047 {
1048 	if (!scn->hal_soc) {
1049 		hif_err("hal not initialized: not initializing shadow config");
1050 		return;
1051 	}
1052 
1053 	hal_get_shadow_v3_config(scn->hal_soc, shadow_config,
1054 				 num_shadow_registers_configured);
1055 
1056 	if (*num_shadow_registers_configured != 0) {
1057 		hif_err("hal shadow register configuration already constructed");
1058 
1059 		/* return with original configuration*/
1060 		return;
1061 	}
1062 	hal_construct_srng_shadow_regs(scn->hal_soc);
1063 	ce_construct_shadow_config_srng(scn);
1064 	hal_set_shadow_regs(scn->hal_soc);
1065 	hal_construct_shadow_regs(scn->hal_soc);
1066 	/* get updated configuration */
1067 	hal_get_shadow_v3_config(scn->hal_soc, shadow_config,
1068 				 num_shadow_registers_configured);
1069 }
1070 #endif
1071 
1072 #ifdef HIF_CE_LOG_INFO
1073 /**
1074  * ce_get_index_info_srng(): Get CE index info
1075  * @scn: HIF Context
1076  * @ce_state: CE opaque handle
1077  * @info: CE info
1078  *
1079  * Return: 0 for success and non zero for failure
1080  */
1081 static
1082 int ce_get_index_info_srng(struct hif_softc *scn, void *ce_state,
1083 			   struct ce_index *info)
1084 {
1085 	struct CE_state *CE_state = (struct CE_state *)ce_state;
1086 	uint32_t tp, hp;
1087 
1088 	info->id = CE_state->id;
1089 	if (CE_state->src_ring) {
1090 		hal_get_sw_hptp(scn->hal_soc, CE_state->src_ring->srng_ctx,
1091 				&tp, &hp);
1092 		info->u.srng_info.tp = tp;
1093 		info->u.srng_info.hp = hp;
1094 	} else if (CE_state->dest_ring && CE_state->status_ring) {
1095 		hal_get_sw_hptp(scn->hal_soc, CE_state->status_ring->srng_ctx,
1096 				&tp, &hp);
1097 		info->u.srng_info.status_tp = tp;
1098 		info->u.srng_info.status_hp = hp;
1099 		hal_get_sw_hptp(scn->hal_soc, CE_state->dest_ring->srng_ctx,
1100 				&tp, &hp);
1101 		info->u.srng_info.tp = tp;
1102 		info->u.srng_info.hp = hp;
1103 	}
1104 
1105 	return 0;
1106 }
1107 #endif
1108 
1109 #ifdef FEATURE_DIRECT_LINK
1110 /**
1111  * ce_set_srng_msi_irq_config_by_ceid(): Set srng MSI irq configuration for CE
1112  *  given by id
1113  * @scn: HIF Context
1114  * @ce_id:
1115  * @addr:
1116  * @data:
1117  *
1118  * Return: 0 for success and non zero for failure
1119  */
1120 static QDF_STATUS
1121 ce_set_srng_msi_irq_config_by_ceid(struct hif_softc *scn, uint8_t ce_id,
1122 				   uint64_t addr, uint32_t data)
1123 {
1124 	struct CE_state *ce_state;
1125 	hal_ring_handle_t ring_hdl;
1126 	struct hal_srng_params ring_params = {0};
1127 
1128 	ce_state = scn->ce_id_to_state[ce_id];
1129 	if (!ce_state)
1130 		return QDF_STATUS_E_NOSUPPORT;
1131 
1132 	ring_params.msi_addr = addr;
1133 	ring_params.msi_data = data;
1134 
1135 	if (ce_state->src_ring) {
1136 		ring_hdl = ce_state->src_ring->srng_ctx;
1137 
1138 		ring_params.intr_timer_thres_us = 0;
1139 		ring_params.intr_batch_cntr_thres_entries = 1;
1140 		ring_params.prefetch_timer = HAL_SRNG_PREFETCH_TIMER;
1141 	} else if (ce_state->dest_ring) {
1142 		ring_hdl = ce_state->status_ring->srng_ctx;
1143 
1144 		ce_status_ring_config_int_threshold(scn, &ring_params);
1145 
1146 		hal_srng_set_msi_irq_config(scn->hal_soc, ring_hdl,
1147 					    &ring_params);
1148 
1149 		if (ce_is_status_ring_timer_thresh_war_needed()) {
1150 			ce_srng_initialize_dest_timer_interrupt_war(
1151 					ce_state->dest_ring, &ring_params);
1152 		} else {
1153 			ce_srng_initialize_dest_ring_thresh(ce_state->dest_ring,
1154 							    &ring_params);
1155 		}
1156 		ring_params.prefetch_timer = HAL_SRNG_PREFETCH_TIMER;
1157 		ring_hdl = ce_state->dest_ring->srng_ctx;
1158 	} else {
1159 		return QDF_STATUS_E_FAILURE;
1160 	}
1161 
1162 	hal_srng_set_msi_irq_config(scn->hal_soc, ring_hdl, &ring_params);
1163 
1164 	return QDF_STATUS_SUCCESS;
1165 }
1166 
1167 static
1168 uint16_t ce_get_direct_link_dest_srng_buffers(struct hif_softc *scn,
1169 					      uint64_t **dma_addr,
1170 					      uint32_t *buf_size)
1171 {
1172 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
1173 	struct CE_state *ce_state;
1174 	struct service_to_pipe *tgt_svc_cfg;
1175 	uint64_t *dma_addr_arr = NULL;
1176 	uint32_t i;
1177 	uint32_t j = 0;
1178 
1179 	tgt_svc_cfg = hif_state->tgt_svc_map;
1180 
1181 	for (i = 0; i < hif_state->sz_tgt_svc_map; i++) {
1182 		if (tgt_svc_cfg[i].service_id != LPASS_DATA_MSG_SVC ||
1183 		    tgt_svc_cfg[i].pipedir != PIPEDIR_IN)
1184 			continue;
1185 
1186 		ce_state = scn->ce_id_to_state[tgt_svc_cfg[i].pipenum];
1187 		if (!ce_state || !ce_state->dest_ring) {
1188 			hif_err("Direct Link CE pipe %d not initialized",
1189 				tgt_svc_cfg[i].pipenum);
1190 			return QDF_STATUS_E_FAILURE;
1191 		}
1192 
1193 		QDF_ASSERT(scn->dl_recv_pages.dma_pages);
1194 
1195 		dma_addr_arr = qdf_mem_malloc(sizeof(*dma_addr_arr) *
1196 					      scn->dl_recv_pages.num_pages);
1197 		if (!dma_addr_arr)
1198 			return 0;
1199 
1200 		for (j = 0; j < scn->dl_recv_pages.num_pages; j++)
1201 			dma_addr_arr[j] =
1202 				scn->dl_recv_pages.dma_pages[j].page_p_addr;
1203 
1204 		*buf_size = ce_state->src_sz_max;
1205 
1206 		break;
1207 	}
1208 
1209 	*dma_addr = dma_addr_arr;
1210 
1211 	return j;
1212 }
1213 
1214 /**
1215  * ce_save_srng_info() - Get and save srng information
1216  * @hif_ctx: hif context
1217  * @srng_info: Direct Link CE srng information
1218  * @srng_ctx: Direct Link CE srng context
1219  *
1220  * Return: QDF status
1221  */
1222 static void
1223 ce_save_srng_info(struct hif_softc *hif_ctx, struct hif_ce_ring_info *srng_info,
1224 		  void *srng_ctx)
1225 {
1226 	struct hal_srng_params params;
1227 
1228 	hal_get_srng_params(hif_ctx->hal_soc, srng_ctx, &params);
1229 
1230 	srng_info->ring_id = params.ring_id;
1231 	srng_info->ring_dir = params.ring_dir;
1232 	srng_info->num_entries = params.num_entries;
1233 	srng_info->entry_size = params.entry_size;
1234 	srng_info->ring_base_paddr = params.ring_base_paddr;
1235 	srng_info->hp_paddr =
1236 		      hal_srng_get_hp_addr(hif_ctx->hal_soc, srng_ctx);
1237 	srng_info->tp_paddr =
1238 		      hal_srng_get_tp_addr(hif_ctx->hal_soc, srng_ctx);
1239 }
1240 
1241 static
1242 QDF_STATUS ce_get_direct_link_srng_info(struct hif_softc *scn,
1243 					struct hif_direct_link_ce_info *info,
1244 					uint8_t max_ce_info_len)
1245 {
1246 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
1247 	struct CE_state *ce_state;
1248 	struct service_to_pipe *tgt_svc_cfg;
1249 	uint8_t ce_info_idx = 0;
1250 	uint32_t i;
1251 
1252 	tgt_svc_cfg = hif_state->tgt_svc_map;
1253 
1254 	for (i = 0; i < hif_state->sz_tgt_svc_map; i++) {
1255 		if (tgt_svc_cfg[i].service_id != LPASS_DATA_MSG_SVC)
1256 			continue;
1257 
1258 		ce_state = scn->ce_id_to_state[tgt_svc_cfg[i].pipenum];
1259 		if (!ce_state) {
1260 			hif_err("Direct Link CE pipe %d not initialized",
1261 				tgt_svc_cfg[i].pipenum);
1262 			return QDF_STATUS_E_FAILURE;
1263 		}
1264 
1265 		if (ce_info_idx > max_ce_info_len)
1266 			return QDF_STATUS_E_FAILURE;
1267 
1268 		info[ce_info_idx].ce_id = ce_state->id;
1269 		info[ce_info_idx].pipe_dir = tgt_svc_cfg[i].pipedir;
1270 
1271 		if (ce_state->src_ring)
1272 			ce_save_srng_info(scn, &info[ce_info_idx].ring_info,
1273 					  ce_state->src_ring->srng_ctx);
1274 		else
1275 			ce_save_srng_info(scn, &info[ce_info_idx].ring_info,
1276 					  ce_state->dest_ring->srng_ctx);
1277 
1278 		ce_info_idx++;
1279 
1280 		if (!ce_state->status_ring)
1281 			continue;
1282 
1283 		if (ce_info_idx > max_ce_info_len)
1284 			return QDF_STATUS_E_FAILURE;
1285 
1286 		info[ce_info_idx].ce_id = ce_state->id;
1287 		info[ce_info_idx].pipe_dir = tgt_svc_cfg[i].pipedir;
1288 
1289 		ce_save_srng_info(scn, &info[ce_info_idx].ring_info,
1290 				  ce_state->status_ring->srng_ctx);
1291 		ce_info_idx++;
1292 	}
1293 
1294 	return QDF_STATUS_SUCCESS;
1295 }
1296 #endif
1297 
1298 static struct ce_ops ce_service_srng = {
1299 	.ce_get_desc_size = ce_get_desc_size_srng,
1300 	.ce_ring_setup = ce_ring_setup_srng,
1301 	.ce_srng_cleanup = ce_ring_cleanup_srng,
1302 	.ce_sendlist_send = ce_sendlist_send_srng,
1303 	.ce_completed_recv_next_nolock = ce_completed_recv_next_nolock_srng,
1304 	.ce_revoke_recv_next = ce_revoke_recv_next_srng,
1305 	.ce_cancel_send_next = ce_cancel_send_next_srng,
1306 	.ce_recv_buf_enqueue = ce_recv_buf_enqueue_srng,
1307 	.ce_per_engine_handler_adjust = ce_per_engine_handler_adjust_srng,
1308 	.ce_send_nolock = ce_send_nolock_srng,
1309 	.watermark_int = ce_check_int_watermark_srng,
1310 	.ce_completed_send_next_nolock = ce_completed_send_next_nolock_srng,
1311 	.ce_recv_entries_done_nolock = ce_recv_entries_done_nolock_srng,
1312 	.ce_send_entries_done_nolock = ce_send_entries_done_nolock_srng,
1313 	.ce_prepare_shadow_register_v2_cfg =
1314 		ce_prepare_shadow_register_v2_cfg_srng,
1315 #ifdef CONFIG_SHADOW_V3
1316 	.ce_prepare_shadow_register_v3_cfg =
1317 		ce_prepare_shadow_register_v3_cfg_srng,
1318 #endif
1319 #ifdef HIF_CE_LOG_INFO
1320 	.ce_get_index_info =
1321 		ce_get_index_info_srng,
1322 #endif
1323 #ifdef FEATURE_DIRECT_LINK
1324 	.ce_set_irq_config_by_ceid = ce_set_srng_msi_irq_config_by_ceid,
1325 	.ce_get_direct_link_dest_buffers = ce_get_direct_link_dest_srng_buffers,
1326 	.ce_get_direct_link_ring_info = ce_get_direct_link_srng_info,
1327 #endif
1328 };
1329 
1330 struct ce_ops *ce_services_srng(void)
1331 {
1332 	return &ce_service_srng;
1333 }
1334 qdf_export_symbol(ce_services_srng);
1335 
1336 void ce_service_srng_init(void)
1337 {
1338 	ce_service_register_module(CE_SVC_SRNG, &ce_services_srng);
1339 }
1340