1 /*
2  * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2023 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 
20 #include "hif.h"
21 #include "hif_io32.h"
22 #include "ce_api.h"
23 #include "ce_main.h"
24 #include "ce_internal.h"
25 #include "ce_reg.h"
26 #include "qdf_lock.h"
27 #include "regtable.h"
28 #include "hif_main.h"
29 #include "hif_debug.h"
30 #include "hif_napi.h"
31 #include "qdf_module.h"
32 #include <qdf_tracepoint.h>
33 
34 #ifdef IPA_OFFLOAD
35 #ifdef QCA_WIFI_3_0
36 #define CE_IPA_RING_INIT(ce_desc)                       \
37 	do {                                            \
38 		ce_desc->gather = 0;                    \
39 		ce_desc->enable_11h = 0;                \
40 		ce_desc->meta_data_low = 0;             \
41 		ce_desc->packet_result_offset = 64;     \
42 		ce_desc->toeplitz_hash_enable = 0;      \
43 		ce_desc->addr_y_search_disable = 0;     \
44 		ce_desc->addr_x_search_disable = 0;     \
45 		ce_desc->misc_int_disable = 0;          \
46 		ce_desc->target_int_disable = 0;        \
47 		ce_desc->host_int_disable = 0;          \
48 		ce_desc->dest_byte_swap = 0;            \
49 		ce_desc->byte_swap = 0;                 \
50 		ce_desc->type = 2;                      \
51 		ce_desc->tx_classify = 1;               \
52 		ce_desc->buffer_addr_hi = 0;            \
53 		ce_desc->meta_data = 0;                 \
54 		ce_desc->nbytes = 128;                  \
55 	} while (0)
56 #else
57 #define CE_IPA_RING_INIT(ce_desc)                       \
58 	do {                                            \
59 		ce_desc->byte_swap = 0;                 \
60 		ce_desc->nbytes = 60;                   \
61 		ce_desc->gather = 0;                    \
62 	} while (0)
63 #endif /* QCA_WIFI_3_0 */
64 #endif /* IPA_OFFLOAD */
65 
66 static int war1_allow_sleep;
67 /* io32 write workaround */
68 static int hif_ce_war1;
69 
70 /**
71  * hif_ce_war_disable() - disable ce war gobally
72  */
hif_ce_war_disable(void)73 void hif_ce_war_disable(void)
74 {
75 	hif_ce_war1 = 0;
76 }
77 
78 /**
79  * hif_ce_war_enable() - enable ce war gobally
80  */
hif_ce_war_enable(void)81 void hif_ce_war_enable(void)
82 {
83 	hif_ce_war1 = 1;
84 }
85 
86 /*
87  * Note: For MCL, #if defined (HIF_CONFIG_SLUB_DEBUG_ON) needs to be checked
88  * for defined here
89  */
90 #if defined(HIF_CONFIG_SLUB_DEBUG_ON) || defined(HIF_CE_DEBUG_DATA_BUF)
91 
92 #define CE_DEBUG_PRINT_BUF_SIZE(x) (((x) * 3) - 1)
93 #define CE_DEBUG_DATA_PER_ROW 16
94 
95 static const char *ce_event_type_to_str(enum hif_ce_event_type type);
96 
get_next_record_index(qdf_atomic_t * table_index,int array_size)97 int get_next_record_index(qdf_atomic_t *table_index, int array_size)
98 {
99 	int record_index = qdf_atomic_inc_return(table_index);
100 
101 	if (record_index == array_size)
102 		qdf_atomic_sub(array_size, table_index);
103 
104 	while (record_index >= array_size)
105 		record_index -= array_size;
106 
107 	return record_index;
108 }
109 
110 qdf_export_symbol(get_next_record_index);
111 
112 #ifdef HIF_CE_DEBUG_DATA_BUF
hif_ce_desc_data_record(struct hif_ce_desc_event * event,int len)113 void hif_ce_desc_data_record(struct hif_ce_desc_event *event, int len)
114 {
115 	uint8_t *data = NULL;
116 
117 	if (!event->data) {
118 		hif_err_rl("No ce debug memory allocated");
119 		return;
120 	}
121 
122 	if (event->memory && len > 0)
123 		data = qdf_nbuf_data((qdf_nbuf_t)event->memory);
124 
125 	event->actual_data_len = 0;
126 	qdf_mem_zero(event->data, CE_DEBUG_MAX_DATA_BUF_SIZE);
127 
128 	if (data && len > 0) {
129 		qdf_mem_copy(event->data, data,
130 				((len < CE_DEBUG_MAX_DATA_BUF_SIZE) ?
131 				 len : CE_DEBUG_MAX_DATA_BUF_SIZE));
132 		event->actual_data_len = len;
133 	}
134 }
135 
136 qdf_export_symbol(hif_ce_desc_data_record);
137 
hif_clear_ce_desc_debug_data(struct hif_ce_desc_event * event)138 void hif_clear_ce_desc_debug_data(struct hif_ce_desc_event *event)
139 {
140 	qdf_mem_zero(event,
141 		     offsetof(struct hif_ce_desc_event, data));
142 }
143 
144 qdf_export_symbol(hif_clear_ce_desc_debug_data);
145 #else
hif_clear_ce_desc_debug_data(struct hif_ce_desc_event * event)146 void hif_clear_ce_desc_debug_data(struct hif_ce_desc_event *event)
147 {
148 	qdf_mem_zero(event, sizeof(struct hif_ce_desc_event));
149 }
150 
151 qdf_export_symbol(hif_clear_ce_desc_debug_data);
152 #endif /* HIF_CE_DEBUG_DATA_BUF */
153 
154 #if defined(HIF_RECORD_PADDR)
hif_ce_desc_record_rx_paddr(struct hif_softc * scn,struct hif_ce_desc_event * event,qdf_nbuf_t memory)155 void hif_ce_desc_record_rx_paddr(struct hif_softc *scn,
156 				 struct hif_ce_desc_event *event,
157 				 qdf_nbuf_t memory)
158 {
159 	if (memory) {
160 		event->dma_addr = QDF_NBUF_CB_PADDR(memory);
161 		event->dma_to_phy = qdf_mem_paddr_from_dmaaddr(
162 					scn->qdf_dev,
163 					event->dma_addr);
164 
165 		event->virt_to_phy =
166 			virt_to_phys(qdf_nbuf_data(memory));
167 	}
168 }
169 #endif /* HIF_RECORD_RX_PADDR */
170 
hif_display_latest_desc_hist(struct hif_opaque_softc * hif_ctx)171 void hif_display_latest_desc_hist(struct hif_opaque_softc *hif_ctx)
172 {
173 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
174 	struct ce_desc_hist *ce_hist;
175 	struct latest_evt_history *evt;
176 	int i, j;
177 
178 	if (!scn)
179 		return;
180 
181 	ce_hist = &scn->hif_ce_desc_hist;
182 
183 	for (i = 0; i < HIF_CE_MAX_LATEST_HIST; i++) {
184 		if (!ce_hist->enable[i + HIF_CE_MAX_LATEST_HIST])
185 			continue;
186 
187 		for (j = 0; j < HIF_CE_MAX_LATEST_EVTS; j++) {
188 			evt = &ce_hist->latest_evts[i][j];
189 			hif_info_high("CE_id:%d event_idx:%d cpu_id:%d irq_entry:0x%llx tasklet_entry:0x%llx tasklet_resched:0x%llx tasklet_exit:0x%llx ce_work:0x%llx hp:%x tp:%x",
190 				      (i + HIF_CE_MAX_LATEST_HIST), j, evt->cpu_id,
191 				      evt->irq_entry_ts, evt->bh_entry_ts,
192 				      evt->bh_resched_ts, evt->bh_exit_ts,
193 				      evt->bh_work_ts, evt->ring_hp, evt->ring_tp);
194 		}
195 	}
196 }
197 
hif_record_latest_evt(struct ce_desc_hist * ce_hist,uint8_t type,int ce_id,uint64_t time,uint32_t hp,uint32_t tp)198 void hif_record_latest_evt(struct ce_desc_hist *ce_hist,
199 			   uint8_t type,
200 			   int ce_id, uint64_t time,
201 			   uint32_t hp, uint32_t tp)
202 {
203 	struct latest_evt_history *latest_evts;
204 	int idx = 0;
205 
206 	if (ce_id != 2 && ce_id != 3)
207 		return;
208 
209 	latest_evts = &ce_hist->latest_evts[ce_id - HIF_CE_MAX_LATEST_HIST][idx];
210 
211 	switch (type) {
212 	case HIF_IRQ_EVENT:
213 		if (latest_evts[idx].irq_entry_ts >
214 		    latest_evts[idx + 1].irq_entry_ts)
215 			idx = 1;
216 		latest_evts[idx].irq_entry_ts = time;
217 		latest_evts[idx].cpu_id = qdf_get_cpu();
218 		break;
219 	case HIF_CE_TASKLET_ENTRY:
220 		if (latest_evts[idx].bh_entry_ts >
221 		    latest_evts[idx + 1].bh_entry_ts)
222 			idx = 1;
223 		latest_evts[idx].bh_entry_ts = time;
224 		break;
225 	case HIF_CE_TASKLET_RESCHEDULE:
226 		if (latest_evts[idx].bh_resched_ts >
227 		    latest_evts[idx + 1].bh_resched_ts)
228 			idx = 1;
229 		latest_evts[idx].bh_resched_ts = time;
230 		break;
231 	case HIF_CE_TASKLET_EXIT:
232 		if (latest_evts[idx].bh_exit_ts >
233 		    latest_evts[idx + 1].bh_exit_ts)
234 			idx = 1;
235 		latest_evts[idx].bh_exit_ts = time;
236 		break;
237 	case HIF_TX_DESC_COMPLETION:
238 	case HIF_CE_DEST_STATUS_RING_REAP:
239 		if (latest_evts[idx].bh_work_ts >
240 		    latest_evts[idx + 1].bh_work_ts)
241 			idx = 1;
242 		latest_evts[idx].bh_work_ts = time;
243 		latest_evts[idx].ring_hp = hp;
244 		latest_evts[idx].ring_tp = tp;
245 		break;
246 	default:
247 		break;
248 	}
249 }
250 
251 /**
252  * hif_record_ce_desc_event() - record ce descriptor events
253  * @scn: hif_softc
254  * @ce_id: which ce is the event occurring on
255  * @type: what happened
256  * @descriptor: pointer to the descriptor posted/completed
257  * @memory: virtual address of buffer related to the descriptor
258  * @index: index that the descriptor was/will be at.
259  * @len:
260  */
hif_record_ce_desc_event(struct hif_softc * scn,int ce_id,enum hif_ce_event_type type,union ce_desc * descriptor,void * memory,int index,int len)261 void hif_record_ce_desc_event(struct hif_softc *scn, int ce_id,
262 				enum hif_ce_event_type type,
263 				union ce_desc *descriptor,
264 				void *memory, int index,
265 				int len)
266 {
267 	int record_index;
268 	struct hif_ce_desc_event *event;
269 
270 	struct ce_desc_hist *ce_hist = &scn->hif_ce_desc_hist;
271 	struct hif_ce_desc_event *hist_ev = NULL;
272 
273 	if (ce_id < CE_COUNT_MAX)
274 		hist_ev = (struct hif_ce_desc_event *)ce_hist->hist_ev[ce_id];
275 	else
276 		return;
277 
278 	if (ce_id >= CE_COUNT_MAX)
279 		return;
280 
281 	if (!ce_hist->enable[ce_id])
282 		return;
283 
284 	if (!hist_ev)
285 		return;
286 
287 	record_index = get_next_record_index(
288 			&ce_hist->history_index[ce_id], HIF_CE_HISTORY_MAX);
289 
290 	event = &hist_ev[record_index];
291 
292 	hif_clear_ce_desc_debug_data(event);
293 
294 	event->type = type;
295 	event->time = qdf_get_log_timestamp();
296 	event->cpu_id = qdf_get_cpu();
297 
298 	if (descriptor)
299 		qdf_mem_copy(&event->descriptor, descriptor,
300 			     sizeof(union ce_desc));
301 
302 	event->memory = memory;
303 	event->index = index;
304 
305 	if (event->type == HIF_RX_DESC_POST ||
306 	    event->type == HIF_RX_DESC_COMPLETION)
307 		hif_ce_desc_record_rx_paddr(scn, event, memory);
308 
309 	if (ce_hist->data_enable[ce_id])
310 		hif_ce_desc_data_record(event, len);
311 
312 	hif_record_latest_evt(ce_hist, type, ce_id, event->time, 0, 0);
313 }
314 qdf_export_symbol(hif_record_ce_desc_event);
315 
316 /**
317  * ce_init_ce_desc_event_log() - initialize the ce event log
318  * @scn: HIF context
319  * @ce_id: copy engine id for which we are initializing the log
320  * @size: size of array to dedicate
321  *
322  * Currently the passed size is ignored in favor of a precompiled value.
323  */
ce_init_ce_desc_event_log(struct hif_softc * scn,int ce_id,int size)324 void ce_init_ce_desc_event_log(struct hif_softc *scn, int ce_id, int size)
325 {
326 	struct ce_desc_hist *ce_hist = &scn->hif_ce_desc_hist;
327 	qdf_atomic_init(&ce_hist->history_index[ce_id]);
328 	qdf_mutex_create(&ce_hist->ce_dbg_datamem_lock[ce_id]);
329 }
330 
331 /**
332  * ce_deinit_ce_desc_event_log() - deinitialize the ce event log
333  * @scn: HIF context
334  * @ce_id: copy engine id for which we are deinitializing the log
335  *
336  */
ce_deinit_ce_desc_event_log(struct hif_softc * scn,int ce_id)337 inline void ce_deinit_ce_desc_event_log(struct hif_softc *scn, int ce_id)
338 {
339 	struct ce_desc_hist *ce_hist = &scn->hif_ce_desc_hist;
340 
341 	qdf_mutex_destroy(&ce_hist->ce_dbg_datamem_lock[ce_id]);
342 }
343 
344 #else /* (HIF_CONFIG_SLUB_DEBUG_ON) || defined(HIF_CE_DEBUG_DATA_BUF) */
hif_record_ce_desc_event(struct hif_softc * scn,int ce_id,enum hif_ce_event_type type,union ce_desc * descriptor,void * memory,int index,int len)345 void hif_record_ce_desc_event(struct hif_softc *scn,
346 		int ce_id, enum hif_ce_event_type type,
347 		union ce_desc *descriptor, void *memory,
348 		int index, int len)
349 {
350 }
351 qdf_export_symbol(hif_record_ce_desc_event);
352 
ce_init_ce_desc_event_log(struct hif_softc * scn,int ce_id,int size)353 inline void ce_init_ce_desc_event_log(struct hif_softc *scn, int ce_id,
354 					int size)
355 {
356 }
357 
ce_deinit_ce_desc_event_log(struct hif_softc * scn,int ce_id)358 void ce_deinit_ce_desc_event_log(struct hif_softc *scn, int ce_id)
359 {
360 }
361 #endif /*defined(HIF_CONFIG_SLUB_DEBUG_ON) || defined(HIF_CE_DEBUG_DATA_BUF) */
362 
363 #ifdef NAPI_YIELD_BUDGET_BASED
hif_ce_service_should_yield(struct hif_softc * scn,struct CE_state * ce_state)364 bool hif_ce_service_should_yield(struct hif_softc *scn,
365 				 struct CE_state *ce_state)
366 {
367 	bool yield =  hif_max_num_receives_reached(scn, ce_state->receive_count);
368 
369 	/* Setting receive_count to MAX_NUM_OF_RECEIVES when this count goes
370 	 * beyond MAX_NUM_OF_RECEIVES for NAPI backet calculation issue. This
371 	 * can happen in fast path handling as processing is happening in
372 	 * batches.
373 	 */
374 	if (yield)
375 		ce_state->receive_count = MAX_NUM_OF_RECEIVES;
376 
377 	return yield;
378 }
379 #else
380 /**
381  * hif_ce_service_should_yield() - return true if the service is hogging the cpu
382  * @scn: hif context
383  * @ce_state: context of the copy engine being serviced
384  *
385  * Return: true if the service should yield
386  */
hif_ce_service_should_yield(struct hif_softc * scn,struct CE_state * ce_state)387 bool hif_ce_service_should_yield(struct hif_softc *scn,
388 				 struct CE_state *ce_state)
389 {
390 	bool yield, time_limit_reached, rxpkt_thresh_reached = 0;
391 
392 	time_limit_reached = qdf_time_sched_clock() >
393 					ce_state->ce_service_yield_time ? 1 : 0;
394 
395 	if (!time_limit_reached)
396 		rxpkt_thresh_reached = hif_max_num_receives_reached
397 					(scn, ce_state->receive_count);
398 
399 	/* Setting receive_count to MAX_NUM_OF_RECEIVES when this count goes
400 	 * beyond MAX_NUM_OF_RECEIVES for NAPI backet calculation issue. This
401 	 * can happen in fast path handling as processing is happening in
402 	 * batches.
403 	 */
404 	if (rxpkt_thresh_reached)
405 		ce_state->receive_count = MAX_NUM_OF_RECEIVES;
406 
407 	yield =  time_limit_reached || rxpkt_thresh_reached;
408 
409 	if (yield &&
410 	    ce_state->htt_rx_data &&
411 	    hif_napi_enabled(GET_HIF_OPAQUE_HDL(scn), ce_state->id)) {
412 		hif_napi_update_yield_stats(ce_state,
413 					    time_limit_reached,
414 					    rxpkt_thresh_reached);
415 	}
416 
417 	return yield;
418 }
419 qdf_export_symbol(hif_ce_service_should_yield);
420 #endif
421 
ce_flush_tx_ring_write_idx(struct CE_handle * ce_tx_hdl,bool force_flush)422 void ce_flush_tx_ring_write_idx(struct CE_handle *ce_tx_hdl, bool force_flush)
423 {
424 	struct CE_state *ce_state = (struct CE_state *)ce_tx_hdl;
425 	struct CE_ring_state *src_ring = ce_state->src_ring;
426 	struct hif_softc *scn = ce_state->scn;
427 
428 	if (force_flush)
429 		ce_ring_set_event(src_ring, CE_RING_FLUSH_EVENT);
430 
431 	if (ce_ring_get_clear_event(src_ring, CE_RING_FLUSH_EVENT)) {
432 		qdf_spin_lock_bh(&ce_state->ce_index_lock);
433 		CE_SRC_RING_WRITE_IDX_SET(scn, ce_state->ctrl_addr,
434 					  src_ring->write_index);
435 		qdf_spin_unlock_bh(&ce_state->ce_index_lock);
436 
437 		src_ring->last_flush_ts = qdf_get_log_timestamp();
438 		hif_debug("flushed");
439 	}
440 }
441 
442 /* Make sure this wrapper is called under ce_index_lock */
ce_tx_ring_write_idx_update_wrapper(struct CE_handle * ce_tx_hdl,int coalesce)443 void ce_tx_ring_write_idx_update_wrapper(struct CE_handle *ce_tx_hdl,
444 					 int coalesce)
445 {
446 	struct CE_state *ce_state = (struct CE_state *)ce_tx_hdl;
447 	struct CE_ring_state *src_ring = ce_state->src_ring;
448 	struct hif_softc *scn = ce_state->scn;
449 
450 	if (!coalesce)
451 		CE_SRC_RING_WRITE_IDX_SET(scn, ce_state->ctrl_addr,
452 					  src_ring->write_index);
453 }
454 
455 /*
456  * Guts of ce_send, used by both ce_send and ce_sendlist_send.
457  * The caller takes responsibility for any needed locking.
458  */
459 
war_ce_src_ring_write_idx_set(struct hif_softc * scn,u32 ctrl_addr,unsigned int write_index)460 void war_ce_src_ring_write_idx_set(struct hif_softc *scn,
461 				   u32 ctrl_addr, unsigned int write_index)
462 {
463 	if (hif_ce_war1) {
464 		void __iomem *indicator_addr;
465 
466 		indicator_addr = scn->mem + ctrl_addr + DST_WATERMARK_ADDRESS;
467 
468 		if (!war1_allow_sleep
469 		    && ctrl_addr == CE_BASE_ADDRESS(CDC_WAR_DATA_CE)) {
470 			hif_write32_mb(scn, indicator_addr,
471 				       (CDC_WAR_MAGIC_STR | write_index));
472 		} else {
473 			unsigned long irq_flags;
474 
475 			local_irq_save(irq_flags);
476 			hif_write32_mb(scn, indicator_addr, 1);
477 
478 			/*
479 			 * PCIE write waits for ACK in IPQ8K, there is no
480 			 * need to read back value.
481 			 */
482 			(void)hif_read32_mb(scn, indicator_addr);
483 			/* conservative */
484 			(void)hif_read32_mb(scn, indicator_addr);
485 
486 			CE_SRC_RING_WRITE_IDX_SET(scn,
487 						  ctrl_addr, write_index);
488 
489 			hif_write32_mb(scn, indicator_addr, 0);
490 			local_irq_restore(irq_flags);
491 		}
492 	} else {
493 		CE_SRC_RING_WRITE_IDX_SET(scn, ctrl_addr, write_index);
494 	}
495 }
496 
497 qdf_export_symbol(war_ce_src_ring_write_idx_set);
498 
499 QDF_STATUS
ce_send(struct CE_handle * copyeng,void * per_transfer_context,qdf_dma_addr_t buffer,uint32_t nbytes,uint32_t transfer_id,uint32_t flags,uint32_t user_flag)500 ce_send(struct CE_handle *copyeng,
501 		void *per_transfer_context,
502 		qdf_dma_addr_t buffer,
503 		uint32_t nbytes,
504 		uint32_t transfer_id,
505 		uint32_t flags,
506 		uint32_t user_flag)
507 {
508 	struct CE_state *CE_state = (struct CE_state *)copyeng;
509 	QDF_STATUS status;
510 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(CE_state->scn);
511 
512 	qdf_spin_lock_bh(&CE_state->ce_index_lock);
513 	status = hif_state->ce_services->ce_send_nolock(copyeng,
514 			per_transfer_context, buffer, nbytes,
515 			transfer_id, flags, user_flag);
516 	qdf_spin_unlock_bh(&CE_state->ce_index_lock);
517 
518 	return status;
519 }
520 qdf_export_symbol(ce_send);
521 
ce_sendlist_sizeof(void)522 unsigned int ce_sendlist_sizeof(void)
523 {
524 	return sizeof(struct ce_sendlist);
525 }
526 
ce_sendlist_init(struct ce_sendlist * sendlist)527 void ce_sendlist_init(struct ce_sendlist *sendlist)
528 {
529 	struct ce_sendlist_s *sl = (struct ce_sendlist_s *)sendlist;
530 
531 	sl->num_items = 0;
532 }
533 
534 QDF_STATUS
ce_sendlist_buf_add(struct ce_sendlist * sendlist,qdf_dma_addr_t buffer,uint32_t nbytes,uint32_t flags,uint32_t user_flags)535 ce_sendlist_buf_add(struct ce_sendlist *sendlist,
536 					qdf_dma_addr_t buffer,
537 					uint32_t nbytes,
538 					uint32_t flags,
539 					uint32_t user_flags)
540 {
541 	struct ce_sendlist_s *sl = (struct ce_sendlist_s *)sendlist;
542 	unsigned int num_items = sl->num_items;
543 	struct ce_sendlist_item *item;
544 
545 	if (num_items >= CE_SENDLIST_ITEMS_MAX) {
546 		QDF_ASSERT(num_items < CE_SENDLIST_ITEMS_MAX);
547 		return QDF_STATUS_E_RESOURCES;
548 	}
549 
550 	item = &sl->item[num_items];
551 	item->send_type = CE_SIMPLE_BUFFER_TYPE;
552 	item->data = buffer;
553 	item->u.nbytes = nbytes;
554 	item->flags = flags;
555 	item->user_flags = user_flags;
556 	sl->num_items = num_items + 1;
557 	return QDF_STATUS_SUCCESS;
558 }
559 
560 QDF_STATUS
ce_sendlist_send(struct CE_handle * copyeng,void * per_transfer_context,struct ce_sendlist * sendlist,unsigned int transfer_id)561 ce_sendlist_send(struct CE_handle *copyeng,
562 		 void *per_transfer_context,
563 		 struct ce_sendlist *sendlist, unsigned int transfer_id)
564 {
565 	struct CE_state *CE_state = (struct CE_state *)copyeng;
566 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(CE_state->scn);
567 
568 	return hif_state->ce_services->ce_sendlist_send(copyeng,
569 			per_transfer_context, sendlist, transfer_id);
570 }
571 
572 #ifndef AH_NEED_TX_DATA_SWAP
573 #define AH_NEED_TX_DATA_SWAP 0
574 #endif
575 
576 /**
577  * ce_batch_send() - sends bunch of msdus at once
578  * @ce_tx_hdl : pointer to CE handle
579  * @msdu : list of msdus to be sent
580  * @transfer_id : transfer id
581  * @len : Downloaded length
582  * @sendhead : sendhead
583  *
584  * Assumption : Called with an array of MSDU's
585  * Function:
586  * For each msdu in the array
587  * 1. Send each msdu
588  * 2. Increment write index accordinlgy.
589  *
590  * Return: list of msds not sent
591  */
ce_batch_send(struct CE_handle * ce_tx_hdl,qdf_nbuf_t msdu,uint32_t transfer_id,u_int32_t len,uint32_t sendhead)592 qdf_nbuf_t ce_batch_send(struct CE_handle *ce_tx_hdl,  qdf_nbuf_t msdu,
593 		uint32_t transfer_id, u_int32_t len, uint32_t sendhead)
594 {
595 	struct CE_state *ce_state = (struct CE_state *)ce_tx_hdl;
596 	struct hif_softc *scn = ce_state->scn;
597 	struct CE_ring_state *src_ring = ce_state->src_ring;
598 	u_int32_t ctrl_addr = ce_state->ctrl_addr;
599 	/*  A_target_id_t targid = TARGID(scn);*/
600 
601 	uint32_t nentries_mask = src_ring->nentries_mask;
602 	uint32_t sw_index, write_index;
603 
604 	struct CE_src_desc *src_desc_base =
605 		(struct CE_src_desc *)src_ring->base_addr_owner_space;
606 	uint32_t *src_desc;
607 
608 	struct CE_src_desc lsrc_desc = {0};
609 	int deltacount = 0;
610 	qdf_nbuf_t freelist = NULL, hfreelist = NULL, tempnext;
611 
612 	DATA_CE_UPDATE_SWINDEX(src_ring->sw_index, scn, ctrl_addr);
613 	sw_index = src_ring->sw_index;
614 	write_index = src_ring->write_index;
615 
616 	deltacount = CE_RING_DELTA(nentries_mask, write_index, sw_index-1);
617 
618 	while (msdu) {
619 		tempnext = qdf_nbuf_next(msdu);
620 
621 		if (deltacount < 2) {
622 			if (sendhead)
623 				return msdu;
624 			hif_err("Out of descriptors");
625 			src_ring->write_index = write_index;
626 			war_ce_src_ring_write_idx_set(scn, ctrl_addr,
627 					write_index);
628 
629 			sw_index = src_ring->sw_index;
630 			write_index = src_ring->write_index;
631 
632 			deltacount = CE_RING_DELTA(nentries_mask, write_index,
633 					sw_index-1);
634 			if (!freelist) {
635 				freelist = msdu;
636 				hfreelist = msdu;
637 			} else {
638 				qdf_nbuf_set_next(freelist, msdu);
639 				freelist = msdu;
640 			}
641 			qdf_nbuf_set_next(msdu, NULL);
642 			msdu = tempnext;
643 			continue;
644 		}
645 
646 		src_desc = (uint32_t *)CE_SRC_RING_TO_DESC(src_desc_base,
647 				write_index);
648 
649 		src_desc[0]   = qdf_nbuf_get_frag_paddr(msdu, 0);
650 
651 		lsrc_desc.meta_data = transfer_id;
652 		if (len  > msdu->len)
653 			len =  msdu->len;
654 		lsrc_desc.nbytes = len;
655 		/*  Data packet is a byte stream, so disable byte swap */
656 		lsrc_desc.byte_swap = AH_NEED_TX_DATA_SWAP;
657 		lsrc_desc.gather    = 0; /*For the last one, gather is not set*/
658 
659 		src_desc[1] = ((uint32_t *)&lsrc_desc)[1];
660 
661 
662 		src_ring->per_transfer_context[write_index] = msdu;
663 		write_index = CE_RING_IDX_INCR(nentries_mask, write_index);
664 
665 		if (sendhead)
666 			break;
667 		qdf_nbuf_set_next(msdu, NULL);
668 		msdu = tempnext;
669 
670 	}
671 
672 
673 	src_ring->write_index = write_index;
674 	war_ce_src_ring_write_idx_set(scn, ctrl_addr, write_index);
675 
676 	return hfreelist;
677 }
678 
679 /**
680  * ce_update_tx_ring() - Advance sw index.
681  * @ce_tx_hdl : pointer to CE handle
682  * @num_htt_cmpls : htt completions received.
683  *
684  * Function:
685  * Increment the value of sw index of src ring
686  * according to number of htt completions
687  * received.
688  *
689  * Return: void
690  */
691 #ifdef DATA_CE_SW_INDEX_NO_INLINE_UPDATE
ce_update_tx_ring(struct CE_handle * ce_tx_hdl,uint32_t num_htt_cmpls)692 void ce_update_tx_ring(struct CE_handle *ce_tx_hdl, uint32_t num_htt_cmpls)
693 {
694 	struct CE_state *ce_state = (struct CE_state *)ce_tx_hdl;
695 	struct CE_ring_state *src_ring = ce_state->src_ring;
696 	uint32_t nentries_mask = src_ring->nentries_mask;
697 	/*
698 	 * Advance the s/w index:
699 	 * This effectively simulates completing the CE ring descriptors
700 	 */
701 	src_ring->sw_index =
702 		CE_RING_IDX_ADD(nentries_mask, src_ring->sw_index,
703 				num_htt_cmpls);
704 }
705 #else
ce_update_tx_ring(struct CE_handle * ce_tx_hdl,uint32_t num_htt_cmpls)706 void ce_update_tx_ring(struct CE_handle *ce_tx_hdl, uint32_t num_htt_cmpls)
707 {}
708 #endif
709 
710 /**
711  * ce_send_single() - sends
712  * @ce_tx_hdl : pointer to CE handle
713  * @msdu : msdu to be sent
714  * @transfer_id : transfer id
715  * @len : Downloaded length
716  *
717  * Function:
718  * 1. Send one msdu
719  * 2. Increment write index of src ring accordinlgy.
720  *
721  * Return: QDF_STATUS: CE sent status
722  */
ce_send_single(struct CE_handle * ce_tx_hdl,qdf_nbuf_t msdu,uint32_t transfer_id,u_int32_t len)723 QDF_STATUS ce_send_single(struct CE_handle *ce_tx_hdl, qdf_nbuf_t msdu,
724 			  uint32_t transfer_id, u_int32_t len)
725 {
726 	struct CE_state *ce_state = (struct CE_state *)ce_tx_hdl;
727 	struct hif_softc *scn = ce_state->scn;
728 	struct CE_ring_state *src_ring = ce_state->src_ring;
729 	uint32_t ctrl_addr = ce_state->ctrl_addr;
730 	/*A_target_id_t targid = TARGID(scn);*/
731 
732 	uint32_t nentries_mask = src_ring->nentries_mask;
733 	uint32_t sw_index, write_index;
734 
735 	struct CE_src_desc *src_desc_base =
736 		(struct CE_src_desc *)src_ring->base_addr_owner_space;
737 	uint32_t *src_desc;
738 
739 	struct CE_src_desc lsrc_desc = {0};
740 	enum hif_ce_event_type event_type;
741 
742 	DATA_CE_UPDATE_SWINDEX(src_ring->sw_index, scn, ctrl_addr);
743 	sw_index = src_ring->sw_index;
744 	write_index = src_ring->write_index;
745 
746 	if (qdf_unlikely(CE_RING_DELTA(nentries_mask, write_index,
747 					sw_index-1) < 1)) {
748 		hif_err("ce send fail %d %d %d", nentries_mask,
749 		       write_index, sw_index);
750 		return QDF_STATUS_E_RESOURCES;
751 	}
752 
753 	src_desc = (uint32_t *)CE_SRC_RING_TO_DESC(src_desc_base, write_index);
754 
755 	src_desc[0] = qdf_nbuf_get_frag_paddr(msdu, 0);
756 
757 	lsrc_desc.meta_data = transfer_id;
758 	lsrc_desc.nbytes = len;
759 	/*  Data packet is a byte stream, so disable byte swap */
760 	lsrc_desc.byte_swap = AH_NEED_TX_DATA_SWAP;
761 	lsrc_desc.gather    = 0; /* For the last one, gather is not set */
762 
763 	src_desc[1] = ((uint32_t *)&lsrc_desc)[1];
764 
765 
766 	src_ring->per_transfer_context[write_index] = msdu;
767 
768 	if (((struct CE_src_desc *)src_desc)->gather)
769 		event_type = HIF_TX_GATHER_DESC_POST;
770 	else if (qdf_unlikely(ce_state->state != CE_RUNNING))
771 		event_type = HIF_TX_DESC_SOFTWARE_POST;
772 	else
773 		event_type = HIF_TX_DESC_POST;
774 
775 	hif_record_ce_desc_event(scn, ce_state->id, event_type,
776 				(union ce_desc *)src_desc, msdu,
777 				write_index, len);
778 
779 	write_index = CE_RING_IDX_INCR(nentries_mask, write_index);
780 
781 	src_ring->write_index = write_index;
782 
783 	war_ce_src_ring_write_idx_set(scn, ctrl_addr, write_index);
784 
785 	return QDF_STATUS_SUCCESS;
786 }
787 
788 /**
789  * ce_recv_buf_enqueue() - enqueue a recv buffer into a copy engine
790  * @copyeng: copy engine handle
791  * @per_recv_context: virtual address of the nbuf
792  * @buffer: physical address of the nbuf
793  *
794  * Return: QDF_STATUS_SUCCESS if the buffer is enqueued
795  */
796 QDF_STATUS
ce_recv_buf_enqueue(struct CE_handle * copyeng,void * per_recv_context,qdf_dma_addr_t buffer)797 ce_recv_buf_enqueue(struct CE_handle *copyeng,
798 		    void *per_recv_context, qdf_dma_addr_t buffer)
799 {
800 	struct CE_state *CE_state = (struct CE_state *)copyeng;
801 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(CE_state->scn);
802 
803 	return hif_state->ce_services->ce_recv_buf_enqueue(copyeng,
804 			per_recv_context, buffer);
805 }
806 qdf_export_symbol(ce_recv_buf_enqueue);
807 
808 void
ce_send_watermarks_set(struct CE_handle * copyeng,unsigned int low_alert_nentries,unsigned int high_alert_nentries)809 ce_send_watermarks_set(struct CE_handle *copyeng,
810 		       unsigned int low_alert_nentries,
811 		       unsigned int high_alert_nentries)
812 {
813 	struct CE_state *CE_state = (struct CE_state *)copyeng;
814 	uint32_t ctrl_addr = CE_state->ctrl_addr;
815 	struct hif_softc *scn = CE_state->scn;
816 
817 	CE_SRC_RING_LOWMARK_SET(scn, ctrl_addr, low_alert_nentries);
818 	CE_SRC_RING_HIGHMARK_SET(scn, ctrl_addr, high_alert_nentries);
819 }
820 
821 void
ce_recv_watermarks_set(struct CE_handle * copyeng,unsigned int low_alert_nentries,unsigned int high_alert_nentries)822 ce_recv_watermarks_set(struct CE_handle *copyeng,
823 		       unsigned int low_alert_nentries,
824 		       unsigned int high_alert_nentries)
825 {
826 	struct CE_state *CE_state = (struct CE_state *)copyeng;
827 	uint32_t ctrl_addr = CE_state->ctrl_addr;
828 	struct hif_softc *scn = CE_state->scn;
829 
830 	CE_DEST_RING_LOWMARK_SET(scn, ctrl_addr,
831 				low_alert_nentries);
832 	CE_DEST_RING_HIGHMARK_SET(scn, ctrl_addr,
833 				high_alert_nentries);
834 }
835 
ce_send_entries_avail(struct CE_handle * copyeng)836 unsigned int ce_send_entries_avail(struct CE_handle *copyeng)
837 {
838 	struct CE_state *CE_state = (struct CE_state *)copyeng;
839 	struct CE_ring_state *src_ring = CE_state->src_ring;
840 	unsigned int nentries_mask = src_ring->nentries_mask;
841 	unsigned int sw_index;
842 	unsigned int write_index;
843 
844 	qdf_spin_lock(&CE_state->ce_index_lock);
845 	sw_index = src_ring->sw_index;
846 	write_index = src_ring->write_index;
847 	qdf_spin_unlock(&CE_state->ce_index_lock);
848 
849 	return CE_RING_DELTA(nentries_mask, write_index, sw_index - 1);
850 }
851 
ce_recv_entries_avail(struct CE_handle * copyeng)852 unsigned int ce_recv_entries_avail(struct CE_handle *copyeng)
853 {
854 	struct CE_state *CE_state = (struct CE_state *)copyeng;
855 	struct CE_ring_state *dest_ring = CE_state->dest_ring;
856 	unsigned int nentries_mask = dest_ring->nentries_mask;
857 	unsigned int sw_index;
858 	unsigned int write_index;
859 
860 	qdf_spin_lock(&CE_state->ce_index_lock);
861 	sw_index = dest_ring->sw_index;
862 	write_index = dest_ring->write_index;
863 	qdf_spin_unlock(&CE_state->ce_index_lock);
864 
865 	return CE_RING_DELTA(nentries_mask, write_index, sw_index - 1);
866 }
867 
868 /*
869  * Guts of ce_completed_recv_next.
870  * The caller takes responsibility for any necessary locking.
871  */
872 QDF_STATUS
ce_completed_recv_next(struct CE_handle * copyeng,void ** per_CE_contextp,void ** per_transfer_contextp,qdf_dma_addr_t * bufferp,unsigned int * nbytesp,unsigned int * transfer_idp,unsigned int * flagsp)873 ce_completed_recv_next(struct CE_handle *copyeng,
874 		       void **per_CE_contextp,
875 		       void **per_transfer_contextp,
876 		       qdf_dma_addr_t *bufferp,
877 		       unsigned int *nbytesp,
878 		       unsigned int *transfer_idp, unsigned int *flagsp)
879 {
880 	struct CE_state *CE_state = (struct CE_state *)copyeng;
881 	QDF_STATUS status;
882 	struct hif_softc *scn = CE_state->scn;
883 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
884 	struct ce_ops *ce_services;
885 
886 	ce_services = hif_state->ce_services;
887 	qdf_spin_lock_bh(&CE_state->ce_index_lock);
888 	status =
889 		ce_services->ce_completed_recv_next_nolock(CE_state,
890 				per_CE_contextp, per_transfer_contextp, bufferp,
891 					      nbytesp, transfer_idp, flagsp);
892 	qdf_spin_unlock_bh(&CE_state->ce_index_lock);
893 
894 	return status;
895 }
896 
897 QDF_STATUS
ce_revoke_recv_next(struct CE_handle * copyeng,void ** per_CE_contextp,void ** per_transfer_contextp,qdf_dma_addr_t * bufferp)898 ce_revoke_recv_next(struct CE_handle *copyeng,
899 		    void **per_CE_contextp,
900 		    void **per_transfer_contextp, qdf_dma_addr_t *bufferp)
901 {
902 	struct CE_state *CE_state = (struct CE_state *)copyeng;
903 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(CE_state->scn);
904 
905 	return hif_state->ce_services->ce_revoke_recv_next(copyeng,
906 			per_CE_contextp, per_transfer_contextp, bufferp);
907 }
908 
909 QDF_STATUS
ce_cancel_send_next(struct CE_handle * copyeng,void ** per_CE_contextp,void ** per_transfer_contextp,qdf_dma_addr_t * bufferp,unsigned int * nbytesp,unsigned int * transfer_idp,uint32_t * toeplitz_hash_result)910 ce_cancel_send_next(struct CE_handle *copyeng,
911 		void **per_CE_contextp,
912 		void **per_transfer_contextp,
913 		qdf_dma_addr_t *bufferp,
914 		unsigned int *nbytesp,
915 		unsigned int *transfer_idp,
916 		uint32_t *toeplitz_hash_result)
917 {
918 	struct CE_state *CE_state = (struct CE_state *)copyeng;
919 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(CE_state->scn);
920 
921 	return hif_state->ce_services->ce_cancel_send_next
922 		(copyeng, per_CE_contextp, per_transfer_contextp,
923 		 bufferp, nbytesp, transfer_idp, toeplitz_hash_result);
924 }
925 qdf_export_symbol(ce_cancel_send_next);
926 
927 QDF_STATUS
ce_completed_send_next(struct CE_handle * copyeng,void ** per_CE_contextp,void ** per_transfer_contextp,qdf_dma_addr_t * bufferp,unsigned int * nbytesp,unsigned int * transfer_idp,unsigned int * sw_idx,unsigned int * hw_idx,unsigned int * toeplitz_hash_result)928 ce_completed_send_next(struct CE_handle *copyeng,
929 		       void **per_CE_contextp,
930 		       void **per_transfer_contextp,
931 		       qdf_dma_addr_t *bufferp,
932 		       unsigned int *nbytesp,
933 		       unsigned int *transfer_idp,
934 		       unsigned int *sw_idx,
935 		       unsigned int *hw_idx,
936 		       unsigned int *toeplitz_hash_result)
937 {
938 	struct CE_state *CE_state = (struct CE_state *)copyeng;
939 	struct hif_softc *scn = CE_state->scn;
940 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
941 	struct ce_ops *ce_services;
942 	QDF_STATUS status;
943 
944 	ce_services = hif_state->ce_services;
945 	qdf_spin_lock_bh(&CE_state->ce_index_lock);
946 	status =
947 		ce_services->ce_completed_send_next_nolock(CE_state,
948 					per_CE_contextp, per_transfer_contextp,
949 					bufferp, nbytesp, transfer_idp, sw_idx,
950 					      hw_idx, toeplitz_hash_result);
951 	qdf_spin_unlock_bh(&CE_state->ce_index_lock);
952 
953 	return status;
954 }
955 
956 #ifdef ATH_11AC_TXCOMPACT
957 /* CE engine descriptor reap
958  * Similar to ce_per_engine_service , Only difference is ce_per_engine_service
959  * does receive and reaping of completed descriptor ,
960  * This function only handles reaping of Tx complete descriptor.
961  * The Function is called from threshold reap  poll routine
962  * hif_send_complete_check so should not contain receive functionality
963  * within it .
964  */
965 
ce_per_engine_servicereap(struct hif_softc * scn,unsigned int ce_id)966 void ce_per_engine_servicereap(struct hif_softc *scn, unsigned int ce_id)
967 {
968 	void *CE_context;
969 	void *transfer_context;
970 	qdf_dma_addr_t buf;
971 	unsigned int nbytes;
972 	unsigned int id;
973 	unsigned int sw_idx, hw_idx;
974 	uint32_t toeplitz_hash_result;
975 	struct CE_state *CE_state = scn->ce_id_to_state[ce_id];
976 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
977 
978 	if (Q_TARGET_ACCESS_BEGIN(scn) < 0)
979 		return;
980 
981 	hif_record_ce_desc_event(scn, ce_id, HIF_CE_REAP_ENTRY,
982 			NULL, NULL, 0, 0);
983 
984 	/* Since this function is called from both user context and
985 	 * tasklet context the spinlock has to lock the bottom halves.
986 	 * This fix assumes that ATH_11AC_TXCOMPACT flag is always
987 	 * enabled in TX polling mode. If this is not the case, more
988 	 * bottom halve spin lock changes are needed. Due to data path
989 	 * performance concern, after internal discussion we've decided
990 	 * to make minimum change, i.e., only address the issue occurred
991 	 * in this function. The possible negative effect of this minimum
992 	 * change is that, in the future, if some other function will also
993 	 * be opened to let the user context to use, those cases need to be
994 	 * addressed by change spin_lock to spin_lock_bh also.
995 	 */
996 
997 	qdf_spin_lock_bh(&CE_state->ce_index_lock);
998 
999 	if (CE_state->send_cb) {
1000 		{
1001 			struct ce_ops *ce_services = hif_state->ce_services;
1002 			/* Pop completed send buffers and call the
1003 			 * registered send callback for each
1004 			 */
1005 			while (ce_services->ce_completed_send_next_nolock
1006 				 (CE_state, &CE_context,
1007 				  &transfer_context, &buf,
1008 				  &nbytes, &id, &sw_idx, &hw_idx,
1009 				  &toeplitz_hash_result) ==
1010 				  QDF_STATUS_SUCCESS) {
1011 				if (ce_id != CE_HTT_H2T_MSG) {
1012 					qdf_spin_unlock_bh(
1013 						&CE_state->ce_index_lock);
1014 					CE_state->send_cb(
1015 						(struct CE_handle *)
1016 						CE_state, CE_context,
1017 						transfer_context, buf,
1018 						nbytes, id, sw_idx, hw_idx,
1019 						toeplitz_hash_result);
1020 					qdf_spin_lock_bh(
1021 						&CE_state->ce_index_lock);
1022 				} else {
1023 					struct HIF_CE_pipe_info *pipe_info =
1024 						(struct HIF_CE_pipe_info *)
1025 						CE_context;
1026 
1027 					qdf_spin_lock_bh(&pipe_info->
1028 						 completion_freeq_lock);
1029 					pipe_info->num_sends_allowed++;
1030 					qdf_spin_unlock_bh(&pipe_info->
1031 						   completion_freeq_lock);
1032 				}
1033 			}
1034 		}
1035 	}
1036 
1037 	qdf_spin_unlock_bh(&CE_state->ce_index_lock);
1038 
1039 	hif_record_ce_desc_event(scn, ce_id, HIF_CE_REAP_EXIT,
1040 			NULL, NULL, 0, 0);
1041 	Q_TARGET_ACCESS_END(scn);
1042 }
1043 
1044 #endif /*ATH_11AC_TXCOMPACT */
1045 
1046 #ifdef ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST
check_ce_id_and_epping_enabled(int CE_id,uint32_t mode)1047 static inline bool check_ce_id_and_epping_enabled(int CE_id, uint32_t mode)
1048 {
1049 	// QDF_IS_EPPING_ENABLED is pre lithium feature
1050 	// CE4 completion is enabled only lithium and later
1051 	// so no need to check for EPPING
1052 	return true;
1053 }
1054 
1055 #else /* ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST */
1056 
check_ce_id_and_epping_enabled(int CE_id,uint32_t mode)1057 static inline bool check_ce_id_and_epping_enabled(int CE_id, uint32_t mode)
1058 {
1059 	if (CE_id != CE_HTT_H2T_MSG || QDF_IS_EPPING_ENABLED(mode))
1060 		return true;
1061 	else
1062 		return false;
1063 }
1064 
1065 #endif /* ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST */
1066 
1067 /*
1068  * ce_engine_service_reg:
1069  *
1070  * Called from ce_per_engine_service and goes through the regular interrupt
1071  * handling that does not involve the WLAN fast path feature.
1072  *
1073  * Returns void
1074  */
ce_engine_service_reg(struct hif_softc * scn,int CE_id)1075 void ce_engine_service_reg(struct hif_softc *scn, int CE_id)
1076 {
1077 	struct CE_state *CE_state = scn->ce_id_to_state[CE_id];
1078 	uint32_t ctrl_addr = CE_state->ctrl_addr;
1079 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
1080 	void *CE_context;
1081 	void *transfer_context;
1082 	qdf_dma_addr_t buf;
1083 	unsigned int nbytes;
1084 	unsigned int id;
1085 	unsigned int flags;
1086 	unsigned int more_comp_cnt = 0;
1087 	unsigned int more_snd_comp_cnt = 0;
1088 	unsigned int sw_idx, hw_idx;
1089 	uint32_t toeplitz_hash_result;
1090 	uint32_t mode = hif_get_conparam(scn);
1091 
1092 more_completions:
1093 	if (CE_state->recv_cb) {
1094 
1095 		/* Pop completed recv buffers and call
1096 		 * the registered recv callback for each
1097 		 */
1098 		while (hif_state->ce_services->ce_completed_recv_next_nolock
1099 				(CE_state, &CE_context, &transfer_context,
1100 				&buf, &nbytes, &id, &flags) ==
1101 				QDF_STATUS_SUCCESS) {
1102 			qdf_spin_unlock(&CE_state->ce_index_lock);
1103 			CE_state->recv_cb((struct CE_handle *)CE_state,
1104 					  CE_context, transfer_context, buf,
1105 					  nbytes, id, flags);
1106 
1107 			qdf_spin_lock(&CE_state->ce_index_lock);
1108 			/*
1109 			 * EV #112693 -
1110 			 * [Peregrine][ES1][WB342][Win8x86][Performance]
1111 			 * BSoD_0x133 occurred in VHT80 UDP_DL
1112 			 * Break out DPC by force if number of loops in
1113 			 * hif_pci_ce_recv_data reaches MAX_NUM_OF_RECEIVES
1114 			 * to avoid spending too long time in
1115 			 * DPC for each interrupt handling. Schedule another
1116 			 * DPC to avoid data loss if we had taken
1117 			 * force-break action before apply to Windows OS
1118 			 * only currently, Linux/MAC os can expand to their
1119 			 * platform if necessary
1120 			 */
1121 
1122 			/* Break the receive processes by
1123 			 * force if force_break set up
1124 			 */
1125 			if (qdf_unlikely(CE_state->force_break)) {
1126 				qdf_atomic_set(&CE_state->rx_pending, 1);
1127 				return;
1128 			}
1129 		}
1130 	}
1131 
1132 	/*
1133 	 * Attention: We may experience potential infinite loop for below
1134 	 * While Loop during Sending Stress test.
1135 	 * Resolve the same way as Receive Case (Refer to EV #112693)
1136 	 */
1137 
1138 	if (CE_state->send_cb) {
1139 		/* Pop completed send buffers and call
1140 		 * the registered send callback for each
1141 		 */
1142 
1143 #ifdef ATH_11AC_TXCOMPACT
1144 		while (hif_state->ce_services->ce_completed_send_next_nolock
1145 			 (CE_state, &CE_context,
1146 			 &transfer_context, &buf, &nbytes,
1147 			 &id, &sw_idx, &hw_idx,
1148 			 &toeplitz_hash_result) == QDF_STATUS_SUCCESS) {
1149 
1150 			if (check_ce_id_and_epping_enabled(CE_id, mode)) {
1151 				qdf_spin_unlock(&CE_state->ce_index_lock);
1152 				CE_state->send_cb((struct CE_handle *)CE_state,
1153 						  CE_context, transfer_context,
1154 						  buf, nbytes, id, sw_idx,
1155 						  hw_idx, toeplitz_hash_result);
1156 				qdf_spin_lock(&CE_state->ce_index_lock);
1157 			} else {
1158 				struct HIF_CE_pipe_info *pipe_info =
1159 					(struct HIF_CE_pipe_info *)CE_context;
1160 
1161 				qdf_spin_lock_bh(&pipe_info->
1162 					      completion_freeq_lock);
1163 				pipe_info->num_sends_allowed++;
1164 				qdf_spin_unlock_bh(&pipe_info->
1165 						completion_freeq_lock);
1166 			}
1167 		}
1168 #else                           /*ATH_11AC_TXCOMPACT */
1169 		while (hif_state->ce_services->ce_completed_send_next_nolock
1170 			 (CE_state, &CE_context,
1171 			  &transfer_context, &buf, &nbytes,
1172 			  &id, &sw_idx, &hw_idx,
1173 			  &toeplitz_hash_result) == QDF_STATUS_SUCCESS) {
1174 			qdf_spin_unlock(&CE_state->ce_index_lock);
1175 			CE_state->send_cb((struct CE_handle *)CE_state,
1176 				  CE_context, transfer_context, buf,
1177 				  nbytes, id, sw_idx, hw_idx,
1178 				  toeplitz_hash_result);
1179 			qdf_spin_lock(&CE_state->ce_index_lock);
1180 		}
1181 #endif /*ATH_11AC_TXCOMPACT */
1182 	}
1183 
1184 more_watermarks:
1185 	if (CE_state->misc_cbs) {
1186 		if (CE_state->watermark_cb &&
1187 				hif_state->ce_services->watermark_int(CE_state,
1188 					&flags)) {
1189 			qdf_spin_unlock(&CE_state->ce_index_lock);
1190 			/* Convert HW IS bits to software flags */
1191 			CE_state->watermark_cb((struct CE_handle *)CE_state,
1192 					CE_state->wm_context, flags);
1193 			qdf_spin_lock(&CE_state->ce_index_lock);
1194 		}
1195 	}
1196 
1197 	/*
1198 	 * Clear the misc interrupts (watermark) that were handled above,
1199 	 * and that will be checked again below.
1200 	 * Clear and check for copy-complete interrupts again, just in case
1201 	 * more copy completions happened while the misc interrupts were being
1202 	 * handled.
1203 	 */
1204 	if (!ce_srng_based(scn) && !CE_state->msi_supported) {
1205 		if (TARGET_REGISTER_ACCESS_ALLOWED(scn)) {
1206 			CE_ENGINE_INT_STATUS_CLEAR(scn, ctrl_addr,
1207 					   CE_WATERMARK_MASK |
1208 					   HOST_IS_COPY_COMPLETE_MASK);
1209 		} else {
1210 			qdf_atomic_set(&CE_state->rx_pending, 0);
1211 			hif_err_rl("%s: target access is not allowed",
1212 				   __func__);
1213 			return;
1214 		}
1215 	}
1216 
1217 	/*
1218 	 * Now that per-engine interrupts are cleared, verify that
1219 	 * no recv interrupts arrive while processing send interrupts,
1220 	 * and no recv or send interrupts happened while processing
1221 	 * misc interrupts.Go back and check again.Keep checking until
1222 	 * we find no more events to process.
1223 	 */
1224 	if (CE_state->recv_cb &&
1225 		hif_state->ce_services->ce_recv_entries_done_nolock(scn,
1226 				CE_state)) {
1227 		if (QDF_IS_EPPING_ENABLED(mode) ||
1228 		    more_comp_cnt++ < CE_TXRX_COMP_CHECK_THRESHOLD) {
1229 			goto more_completions;
1230 		} else {
1231 			if (!ce_srng_based(scn) &&
1232 			    !CE_state->batch_intr_supported) {
1233 				hif_err_rl(
1234 					"Potential infinite loop detected during Rx processing id:%u nentries_mask:0x%x sw read_idx:0x%x hw read_idx:0x%x",
1235 					CE_state->id,
1236 					CE_state->dest_ring->nentries_mask,
1237 					CE_state->dest_ring->sw_index,
1238 					CE_DEST_RING_READ_IDX_GET(scn,
1239 							  CE_state->ctrl_addr));
1240 			}
1241 		}
1242 	}
1243 
1244 	if (CE_state->send_cb &&
1245 		hif_state->ce_services->ce_send_entries_done_nolock(scn,
1246 				CE_state)) {
1247 		if (QDF_IS_EPPING_ENABLED(mode) ||
1248 		    more_snd_comp_cnt++ < CE_TXRX_COMP_CHECK_THRESHOLD) {
1249 			goto more_completions;
1250 		} else {
1251 			if (!ce_srng_based(scn) &&
1252 			    !CE_state->batch_intr_supported) {
1253 				hif_err_rl(
1254 					"Potential infinite loop detected during send completion id:%u mask:0x%x sw read_idx:0x%x hw_index:0x%x write_index: 0x%x hw read_idx:0x%x",
1255 					CE_state->id,
1256 					CE_state->src_ring->nentries_mask,
1257 					CE_state->src_ring->sw_index,
1258 					CE_state->src_ring->hw_index,
1259 					CE_state->src_ring->write_index,
1260 					CE_SRC_RING_READ_IDX_GET(scn,
1261 							 CE_state->ctrl_addr));
1262 			}
1263 		}
1264 	}
1265 
1266 	if (CE_state->misc_cbs && CE_state->watermark_cb) {
1267 		if (hif_state->ce_services->watermark_int(CE_state, &flags))
1268 			goto more_watermarks;
1269 	}
1270 
1271 	qdf_atomic_set(&CE_state->rx_pending, 0);
1272 }
1273 
1274 #ifdef WLAN_TRACEPOINTS
1275 /**
1276  * ce_trace_tasklet_sched_latency() - Trace ce tasklet scheduling
1277  *  latency
1278  * @ce_state: CE context
1279  *
1280  * Return: None
1281  */
1282 static inline
ce_trace_tasklet_sched_latency(struct CE_state * ce_state)1283 void ce_trace_tasklet_sched_latency(struct CE_state *ce_state)
1284 {
1285 	qdf_trace_dp_ce_tasklet_sched_latency(ce_state->id,
1286 					      ce_state->ce_service_start_time -
1287 					      ce_state->ce_tasklet_sched_time);
1288 }
1289 #else
1290 static inline
ce_trace_tasklet_sched_latency(struct CE_state * ce_state)1291 void ce_trace_tasklet_sched_latency(struct CE_state *ce_state)
1292 {
1293 }
1294 #endif
1295 
1296 /*
1297  * Guts of interrupt handler for per-engine interrupts on a particular CE.
1298  *
1299  * Invokes registered callbacks for recv_complete,
1300  * send_complete, and watermarks.
1301  *
1302  * Returns: number of messages processed
1303  */
ce_per_engine_service(struct hif_softc * scn,unsigned int CE_id)1304 int ce_per_engine_service(struct hif_softc *scn, unsigned int CE_id)
1305 {
1306 	struct CE_state *CE_state = scn->ce_id_to_state[CE_id];
1307 
1308 	if (hif_is_nss_wifi_enabled(scn) && (CE_state->htt_rx_data))
1309 		return CE_state->receive_count;
1310 
1311 	if (Q_TARGET_ACCESS_BEGIN(scn) < 0) {
1312 		hif_err("[premature rc=0]");
1313 		return 0; /* no work done */
1314 	}
1315 
1316 	/* Clear force_break flag and re-initialize receive_count to 0 */
1317 	CE_state->receive_count = 0;
1318 	CE_state->force_break = 0;
1319 	CE_state->ce_service_start_time = qdf_time_sched_clock();
1320 	CE_state->ce_service_yield_time =
1321 		CE_state->ce_service_start_time +
1322 		hif_get_ce_service_max_yield_time(
1323 			(struct hif_opaque_softc *)scn);
1324 
1325 	ce_trace_tasklet_sched_latency(CE_state);
1326 
1327 	qdf_spin_lock(&CE_state->ce_index_lock);
1328 
1329 	CE_state->service(scn, CE_id);
1330 
1331 	qdf_spin_unlock(&CE_state->ce_index_lock);
1332 
1333 	if (Q_TARGET_ACCESS_END(scn) < 0)
1334 		hif_err("<--[premature rc=%d]", CE_state->receive_count);
1335 	return CE_state->receive_count;
1336 }
1337 qdf_export_symbol(ce_per_engine_service);
1338 
1339 /*
1340  * Handler for per-engine interrupts on ALL active CEs.
1341  * This is used in cases where the system is sharing a
1342  * single interrupt for all CEs
1343  */
1344 
ce_per_engine_service_any(int irq,struct hif_softc * scn)1345 void ce_per_engine_service_any(int irq, struct hif_softc *scn)
1346 {
1347 	int CE_id;
1348 	uint32_t intr_summary;
1349 
1350 	if (Q_TARGET_ACCESS_BEGIN(scn) < 0)
1351 		return;
1352 
1353 	if (!qdf_atomic_read(&scn->tasklet_from_intr)) {
1354 		for (CE_id = 0; CE_id < scn->ce_count; CE_id++) {
1355 			struct CE_state *CE_state = scn->ce_id_to_state[CE_id];
1356 
1357 			if (qdf_atomic_read(&CE_state->rx_pending)) {
1358 				qdf_atomic_set(&CE_state->rx_pending, 0);
1359 				ce_per_engine_service(scn, CE_id);
1360 			}
1361 		}
1362 
1363 		Q_TARGET_ACCESS_END(scn);
1364 		return;
1365 	}
1366 
1367 	intr_summary = CE_INTERRUPT_SUMMARY(scn);
1368 
1369 	for (CE_id = 0; intr_summary && (CE_id < scn->ce_count); CE_id++) {
1370 		if (intr_summary & (1 << CE_id))
1371 			intr_summary &= ~(1 << CE_id);
1372 		else
1373 			continue;       /* no intr pending on this CE */
1374 
1375 		ce_per_engine_service(scn, CE_id);
1376 	}
1377 
1378 	Q_TARGET_ACCESS_END(scn);
1379 }
1380 
1381 /*Iterate the CE_state list and disable the compl interrupt
1382  * if it has been registered already.
1383  */
ce_disable_any_copy_compl_intr_nolock(struct hif_softc * scn)1384 void ce_disable_any_copy_compl_intr_nolock(struct hif_softc *scn)
1385 {
1386 	int CE_id;
1387 
1388 	if (Q_TARGET_ACCESS_BEGIN(scn) < 0)
1389 		return;
1390 
1391 	for (CE_id = 0; CE_id < scn->ce_count; CE_id++) {
1392 		struct CE_state *CE_state = scn->ce_id_to_state[CE_id];
1393 		uint32_t ctrl_addr = CE_state->ctrl_addr;
1394 
1395 		/* if the interrupt is currently enabled, disable it */
1396 		if (!CE_state->disable_copy_compl_intr
1397 		    && (CE_state->send_cb || CE_state->recv_cb))
1398 			CE_COPY_COMPLETE_INTR_DISABLE(scn, ctrl_addr);
1399 
1400 		if (CE_state->watermark_cb)
1401 			CE_WATERMARK_INTR_DISABLE(scn, ctrl_addr);
1402 	}
1403 	Q_TARGET_ACCESS_END(scn);
1404 }
1405 
ce_enable_any_copy_compl_intr_nolock(struct hif_softc * scn)1406 void ce_enable_any_copy_compl_intr_nolock(struct hif_softc *scn)
1407 {
1408 	int CE_id;
1409 
1410 	if (Q_TARGET_ACCESS_BEGIN(scn) < 0)
1411 		return;
1412 
1413 	for (CE_id = 0; CE_id < scn->ce_count; CE_id++) {
1414 		struct CE_state *CE_state = scn->ce_id_to_state[CE_id];
1415 		uint32_t ctrl_addr = CE_state->ctrl_addr;
1416 
1417 		/*
1418 		 * If the CE is supposed to have copy complete interrupts
1419 		 * enabled (i.e. there a callback registered, and the
1420 		 * "disable" flag is not set), then re-enable the interrupt.
1421 		 */
1422 		if (!CE_state->disable_copy_compl_intr
1423 		    && (CE_state->send_cb || CE_state->recv_cb))
1424 			CE_COPY_COMPLETE_INTR_ENABLE(scn, ctrl_addr);
1425 
1426 		if (CE_state->watermark_cb)
1427 			CE_WATERMARK_INTR_ENABLE(scn, ctrl_addr);
1428 	}
1429 	Q_TARGET_ACCESS_END(scn);
1430 }
1431 
1432 /**
1433  * ce_send_cb_register(): register completion handler
1434  * @copyeng: CE_state representing the ce we are adding the behavior to
1435  * @fn_ptr: callback that the ce should use when processing tx completions
1436  * @ce_send_context: context to pass back in the callback
1437  * @disable_interrupts: if the interrupts should be enabled or not.
1438  *
1439  * Caller should guarantee that no transactions are in progress before
1440  * switching the callback function.
1441  *
1442  * Registers the send context before the fn pointer so that if the cb is valid
1443  * the context should be valid.
1444  *
1445  * Beware that currently this function will enable completion interrupts.
1446  */
1447 void
ce_send_cb_register(struct CE_handle * copyeng,ce_send_cb fn_ptr,void * ce_send_context,int disable_interrupts)1448 ce_send_cb_register(struct CE_handle *copyeng,
1449 		    ce_send_cb fn_ptr,
1450 		    void *ce_send_context, int disable_interrupts)
1451 {
1452 	struct CE_state *CE_state = (struct CE_state *)copyeng;
1453 	struct hif_softc *scn;
1454 	struct HIF_CE_state *hif_state;
1455 
1456 	if (!CE_state) {
1457 		hif_err("Error CE state = NULL");
1458 		return;
1459 	}
1460 	scn = CE_state->scn;
1461 	hif_state = HIF_GET_CE_STATE(scn);
1462 	if (!hif_state) {
1463 		hif_err("Error HIF state = NULL");
1464 		return;
1465 	}
1466 	CE_state->send_context = ce_send_context;
1467 	CE_state->send_cb = fn_ptr;
1468 	hif_state->ce_services->ce_per_engine_handler_adjust(CE_state,
1469 							disable_interrupts);
1470 }
1471 qdf_export_symbol(ce_send_cb_register);
1472 
1473 /**
1474  * ce_recv_cb_register(): register completion handler
1475  * @copyeng: CE_state representing the ce we are adding the behavior to
1476  * @fn_ptr: callback that the ce should use when processing rx completions
1477  * @CE_recv_context: context to pass back in the callback
1478  * @disable_interrupts: if the interrupts should be enabled or not.
1479  *
1480  * Registers the send context before the fn pointer so that if the cb is valid
1481  * the context should be valid.
1482  *
1483  * Caller should guarantee that no transactions are in progress before
1484  * switching the callback function.
1485  */
1486 void
ce_recv_cb_register(struct CE_handle * copyeng,CE_recv_cb fn_ptr,void * CE_recv_context,int disable_interrupts)1487 ce_recv_cb_register(struct CE_handle *copyeng,
1488 		    CE_recv_cb fn_ptr,
1489 		    void *CE_recv_context, int disable_interrupts)
1490 {
1491 	struct CE_state *CE_state = (struct CE_state *)copyeng;
1492 	struct hif_softc *scn;
1493 	struct HIF_CE_state *hif_state;
1494 
1495 	if (!CE_state) {
1496 		hif_err("ERROR CE state = NULL");
1497 		return;
1498 	}
1499 	scn = CE_state->scn;
1500 	hif_state = HIF_GET_CE_STATE(scn);
1501 	if (!hif_state) {
1502 		hif_err("Error HIF state = NULL");
1503 		return;
1504 	}
1505 	CE_state->recv_context = CE_recv_context;
1506 	CE_state->recv_cb = fn_ptr;
1507 	hif_state->ce_services->ce_per_engine_handler_adjust(CE_state,
1508 							disable_interrupts);
1509 }
1510 qdf_export_symbol(ce_recv_cb_register);
1511 
1512 /**
1513  * ce_watermark_cb_register(): register completion handler
1514  * @copyeng: CE_state representing the ce we are adding the behavior to
1515  * @fn_ptr: callback that the ce should use when processing watermark events
1516  * @CE_wm_context: context to pass back in the callback
1517  *
1518  * Caller should guarantee that no watermark events are being processed before
1519  * switching the callback function.
1520  */
1521 void
ce_watermark_cb_register(struct CE_handle * copyeng,CE_watermark_cb fn_ptr,void * CE_wm_context)1522 ce_watermark_cb_register(struct CE_handle *copyeng,
1523 			 CE_watermark_cb fn_ptr, void *CE_wm_context)
1524 {
1525 	struct CE_state *CE_state = (struct CE_state *)copyeng;
1526 	struct hif_softc *scn = CE_state->scn;
1527 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
1528 
1529 	CE_state->watermark_cb = fn_ptr;
1530 	CE_state->wm_context = CE_wm_context;
1531 	hif_state->ce_services->ce_per_engine_handler_adjust(CE_state,
1532 							0);
1533 	if (fn_ptr)
1534 		CE_state->misc_cbs = 1;
1535 }
1536 
1537 #ifdef CUSTOM_CB_SCHEDULER_SUPPORT
1538 void
ce_register_custom_cb(struct CE_handle * copyeng,void (* custom_cb)(void *),void * custom_cb_context)1539 ce_register_custom_cb(struct CE_handle *copyeng, void (*custom_cb)(void *),
1540 		      void *custom_cb_context)
1541 {
1542 	struct CE_state *CE_state = (struct CE_state *)copyeng;
1543 
1544 	CE_state->custom_cb = custom_cb;
1545 	CE_state->custom_cb_context = custom_cb_context;
1546 	qdf_atomic_init(&CE_state->custom_cb_pending);
1547 }
1548 
1549 void
ce_unregister_custom_cb(struct CE_handle * copyeng)1550 ce_unregister_custom_cb(struct CE_handle *copyeng)
1551 {
1552 	struct CE_state *CE_state = (struct CE_state *)copyeng;
1553 
1554 	qdf_assert_always(!qdf_atomic_read(&CE_state->custom_cb_pending));
1555 	CE_state->custom_cb = NULL;
1556 	CE_state->custom_cb_context = NULL;
1557 }
1558 
1559 void
ce_enable_custom_cb(struct CE_handle * copyeng)1560 ce_enable_custom_cb(struct CE_handle *copyeng)
1561 {
1562 	struct CE_state *CE_state = (struct CE_state *)copyeng;
1563 	int32_t custom_cb_pending;
1564 
1565 	qdf_assert_always(CE_state->custom_cb);
1566 	qdf_assert_always(CE_state->custom_cb_context);
1567 
1568 	custom_cb_pending = qdf_atomic_inc_return(&CE_state->custom_cb_pending);
1569 	qdf_assert_always(custom_cb_pending >= 1);
1570 }
1571 
1572 void
ce_disable_custom_cb(struct CE_handle * copyeng)1573 ce_disable_custom_cb(struct CE_handle *copyeng)
1574 {
1575 	struct CE_state *CE_state = (struct CE_state *)copyeng;
1576 
1577 	qdf_assert_always(CE_state->custom_cb);
1578 	qdf_assert_always(CE_state->custom_cb_context);
1579 
1580 	qdf_atomic_dec_if_positive(&CE_state->custom_cb_pending);
1581 }
1582 #endif /* CUSTOM_CB_SCHEDULER_SUPPORT */
1583 
ce_get_rx_pending(struct hif_softc * scn)1584 bool ce_get_rx_pending(struct hif_softc *scn)
1585 {
1586 	int CE_id;
1587 
1588 	for (CE_id = 0; CE_id < scn->ce_count; CE_id++) {
1589 		struct CE_state *CE_state = scn->ce_id_to_state[CE_id];
1590 
1591 		if (qdf_atomic_read(&CE_state->rx_pending))
1592 			return true;
1593 	}
1594 
1595 	return false;
1596 }
1597 
1598 /**
1599  * ce_check_rx_pending() - ce_check_rx_pending
1600  * @CE_state: context of the copy engine to check
1601  *
1602  * Return: true if there per_engine_service
1603  *	didn't process all the rx descriptors.
1604  */
ce_check_rx_pending(struct CE_state * CE_state)1605 bool ce_check_rx_pending(struct CE_state *CE_state)
1606 {
1607 	if (qdf_atomic_read(&CE_state->rx_pending))
1608 		return true;
1609 	else
1610 		return false;
1611 }
1612 qdf_export_symbol(ce_check_rx_pending);
1613 
1614 #ifdef IPA_OFFLOAD
1615 #ifdef QCN7605_SUPPORT
ce_ipa_get_wr_index_addr(struct CE_state * CE_state)1616 static qdf_dma_addr_t ce_ipa_get_wr_index_addr(struct CE_state *CE_state)
1617 {
1618 	u_int32_t ctrl_addr = CE_state->ctrl_addr;
1619 	struct hif_softc *scn = CE_state->scn;
1620 	qdf_dma_addr_t wr_index_addr;
1621 
1622 	wr_index_addr = shadow_sr_wr_ind_addr(scn, ctrl_addr);
1623 	return wr_index_addr;
1624 }
1625 #else
ce_ipa_get_wr_index_addr(struct CE_state * CE_state)1626 static qdf_dma_addr_t ce_ipa_get_wr_index_addr(struct CE_state *CE_state)
1627 {
1628 	struct hif_softc *scn = CE_state->scn;
1629 	qdf_dma_addr_t wr_index_addr;
1630 
1631 	wr_index_addr = CE_BASE_ADDRESS(CE_state->id) +
1632 			SR_WR_INDEX_ADDRESS;
1633 	return wr_index_addr;
1634 }
1635 #endif
1636 
1637 /**
1638  * ce_ipa_get_resource() - get uc resource on copyengine
1639  * @ce: copyengine context
1640  * @ce_sr: copyengine source ring resource info
1641  * @ce_sr_ring_size: copyengine source ring size
1642  * @ce_reg_paddr: copyengine register physical address
1643  *
1644  * Copy engine should release resource to micro controller
1645  * Micro controller needs
1646  *  - Copy engine source descriptor base address
1647  *  - Copy engine source descriptor size
1648  *  - PCI BAR address to access copy engine register
1649  *
1650  * Return: None
1651  */
ce_ipa_get_resource(struct CE_handle * ce,qdf_shared_mem_t ** ce_sr,uint32_t * ce_sr_ring_size,qdf_dma_addr_t * ce_reg_paddr)1652 void ce_ipa_get_resource(struct CE_handle *ce,
1653 			 qdf_shared_mem_t **ce_sr,
1654 			 uint32_t *ce_sr_ring_size,
1655 			 qdf_dma_addr_t *ce_reg_paddr)
1656 {
1657 	struct CE_state *CE_state = (struct CE_state *)ce;
1658 	uint32_t ring_loop;
1659 	struct CE_src_desc *ce_desc;
1660 	qdf_dma_addr_t phy_mem_base;
1661 	struct hif_softc *scn = CE_state->scn;
1662 
1663 	if (CE_UNUSED == CE_state->state) {
1664 		*qdf_mem_get_dma_addr_ptr(scn->qdf_dev,
1665 			&CE_state->scn->ipa_ce_ring->mem_info) = 0;
1666 		*ce_sr_ring_size = 0;
1667 		return;
1668 	}
1669 
1670 	/* Update default value for descriptor */
1671 	for (ring_loop = 0; ring_loop < CE_state->src_ring->nentries;
1672 	     ring_loop++) {
1673 		ce_desc = (struct CE_src_desc *)
1674 			  ((char *)CE_state->src_ring->base_addr_owner_space +
1675 			   ring_loop * (sizeof(struct CE_src_desc)));
1676 		CE_IPA_RING_INIT(ce_desc);
1677 	}
1678 
1679 	/* Get BAR address */
1680 	hif_read_phy_mem_base(CE_state->scn, &phy_mem_base);
1681 
1682 	*ce_sr = CE_state->scn->ipa_ce_ring;
1683 	*ce_sr_ring_size = (uint32_t)(CE_state->src_ring->nentries *
1684 		sizeof(struct CE_src_desc));
1685 	*ce_reg_paddr = phy_mem_base + ce_ipa_get_wr_index_addr(CE_state);
1686 
1687 }
1688 
1689 #endif /* IPA_OFFLOAD */
1690 
1691 #ifdef HIF_CE_DEBUG_DATA_BUF
1692 /**
1693  * hif_dump_desc_data_buf() - record ce descriptor events
1694  * @buf: buffer to copy to
1695  * @pos: Current position till which the buf is filled
1696  * @data: Data to be copied
1697  * @data_len: Length of the data to be copied
1698  */
hif_dump_desc_data_buf(uint8_t * buf,ssize_t pos,uint8_t * data,uint32_t data_len)1699 static uint32_t hif_dump_desc_data_buf(uint8_t *buf, ssize_t pos,
1700 					uint8_t *data, uint32_t data_len)
1701 {
1702 	pos += snprintf(buf + pos, PAGE_SIZE - pos, "Data:(Max%dBytes)\n",
1703 			CE_DEBUG_MAX_DATA_BUF_SIZE);
1704 
1705 	if ((data_len > 0) && data) {
1706 		if (data_len < 16) {
1707 			hex_dump_to_buffer(data,
1708 						CE_DEBUG_DATA_PER_ROW,
1709 						16, 1, buf + pos,
1710 						(ssize_t)PAGE_SIZE - pos,
1711 						false);
1712 			pos += CE_DEBUG_PRINT_BUF_SIZE(data_len);
1713 			pos += snprintf(buf + pos, PAGE_SIZE - pos, "\n");
1714 		} else {
1715 			uint32_t rows = (data_len / 16) + 1;
1716 			uint32_t row = 0;
1717 
1718 			for (row = 0; row < rows; row++) {
1719 				hex_dump_to_buffer(data + (row * 16),
1720 							CE_DEBUG_DATA_PER_ROW,
1721 							16, 1, buf + pos,
1722 							(ssize_t)PAGE_SIZE
1723 							- pos, false);
1724 				pos +=
1725 				CE_DEBUG_PRINT_BUF_SIZE(CE_DEBUG_DATA_PER_ROW);
1726 				pos += snprintf(buf + pos, PAGE_SIZE - pos,
1727 						"\n");
1728 			}
1729 		}
1730 	}
1731 
1732 	return pos;
1733 }
1734 #endif
1735 
1736 /*
1737  * Note: For MCL, #if defined (HIF_CONFIG_SLUB_DEBUG_ON) needs to be checked
1738  * for defined here
1739  */
1740 #if defined(HIF_CONFIG_SLUB_DEBUG_ON) || defined(HIF_CE_DEBUG_DATA_BUF)
ce_event_type_to_str(enum hif_ce_event_type type)1741 static const char *ce_event_type_to_str(enum hif_ce_event_type type)
1742 {
1743 	switch (type) {
1744 	case HIF_RX_DESC_POST:
1745 		return "HIF_RX_DESC_POST";
1746 	case HIF_RX_DESC_COMPLETION:
1747 		return "HIF_RX_DESC_COMPLETION";
1748 	case HIF_TX_GATHER_DESC_POST:
1749 		return "HIF_TX_GATHER_DESC_POST";
1750 	case HIF_TX_DESC_POST:
1751 		return "HIF_TX_DESC_POST";
1752 	case HIF_TX_DESC_SOFTWARE_POST:
1753 		return "HIF_TX_DESC_SOFTWARE_POST";
1754 	case HIF_TX_DESC_COMPLETION:
1755 		return "HIF_TX_DESC_COMPLETION";
1756 	case FAST_RX_WRITE_INDEX_UPDATE:
1757 		return "FAST_RX_WRITE_INDEX_UPDATE";
1758 	case FAST_RX_SOFTWARE_INDEX_UPDATE:
1759 		return "FAST_RX_SOFTWARE_INDEX_UPDATE";
1760 	case FAST_TX_WRITE_INDEX_UPDATE:
1761 		return "FAST_TX_WRITE_INDEX_UPDATE";
1762 	case FAST_TX_WRITE_INDEX_SOFTWARE_UPDATE:
1763 		return "FAST_TX_WRITE_INDEX_SOFTWARE_UPDATE";
1764 	case FAST_TX_SOFTWARE_INDEX_UPDATE:
1765 		return "FAST_TX_SOFTWARE_INDEX_UPDATE";
1766 	case RESUME_WRITE_INDEX_UPDATE:
1767 		return "RESUME_WRITE_INDEX_UPDATE";
1768 	case HIF_IRQ_EVENT:
1769 		return "HIF_IRQ_EVENT";
1770 	case HIF_CE_TASKLET_ENTRY:
1771 		return "HIF_CE_TASKLET_ENTRY";
1772 	case HIF_CE_TASKLET_RESCHEDULE:
1773 		return "HIF_CE_TASKLET_RESCHEDULE";
1774 	case HIF_CE_TASKLET_EXIT:
1775 		return "HIF_CE_TASKLET_EXIT";
1776 	case HIF_CE_REAP_ENTRY:
1777 		return "HIF_CE_REAP_ENTRY";
1778 	case HIF_CE_REAP_EXIT:
1779 		return "HIF_CE_REAP_EXIT";
1780 	case NAPI_SCHEDULE:
1781 		return "NAPI_SCHEDULE";
1782 	case NAPI_POLL_ENTER:
1783 		return "NAPI_POLL_ENTER";
1784 	case NAPI_COMPLETE:
1785 		return "NAPI_COMPLETE";
1786 	case NAPI_POLL_EXIT:
1787 		return "NAPI_POLL_EXIT";
1788 	case HIF_RX_NBUF_ALLOC_FAILURE:
1789 		return "HIF_RX_NBUF_ALLOC_FAILURE";
1790 	case HIF_RX_NBUF_MAP_FAILURE:
1791 		return "HIF_RX_NBUF_MAP_FAILURE";
1792 	case HIF_RX_NBUF_ENQUEUE_FAILURE:
1793 		return "HIF_RX_NBUF_ENQUEUE_FAILURE";
1794 	default:
1795 		return "invalid";
1796 	}
1797 }
1798 
1799 /**
1800  * hif_dump_desc_event() - record ce descriptor events
1801  * @scn: HIF context
1802  * @buf: Buffer to which to be copied
1803  */
hif_dump_desc_event(struct hif_softc * scn,char * buf)1804 ssize_t hif_dump_desc_event(struct hif_softc *scn, char *buf)
1805 {
1806 	struct hif_ce_desc_event *event;
1807 	uint64_t secs, usecs;
1808 	ssize_t len = 0;
1809 	struct ce_desc_hist *ce_hist = NULL;
1810 	struct hif_ce_desc_event *hist_ev = NULL;
1811 
1812 	if (!scn)
1813 		return -EINVAL;
1814 
1815 	ce_hist = &scn->hif_ce_desc_hist;
1816 
1817 	if (ce_hist->hist_id >= CE_COUNT_MAX ||
1818 	    ce_hist->hist_index >= HIF_CE_HISTORY_MAX) {
1819 		qdf_print("Invalid values");
1820 		return -EINVAL;
1821 	}
1822 
1823 	hist_ev =
1824 		(struct hif_ce_desc_event *)ce_hist->hist_ev[ce_hist->hist_id];
1825 
1826 	if (!hist_ev) {
1827 		qdf_print("Low Memory");
1828 		return -EINVAL;
1829 	}
1830 
1831 	event = &hist_ev[ce_hist->hist_index];
1832 
1833 	qdf_log_timestamp_to_secs(event->time, &secs, &usecs);
1834 
1835 	len += snprintf(buf, PAGE_SIZE - len,
1836 			"\nTime:%lld.%06lld, CE:%d, EventType: %s, EventIndex: %d\nDataAddr=%pK",
1837 			secs, usecs, ce_hist->hist_id,
1838 			ce_event_type_to_str(event->type),
1839 			event->index, event->memory);
1840 #ifdef HIF_CE_DEBUG_DATA_BUF
1841 	len += snprintf(buf + len, PAGE_SIZE - len, ", Data len=%zu",
1842 			event->actual_data_len);
1843 #endif
1844 
1845 	len += snprintf(buf + len, PAGE_SIZE - len, "\nCE descriptor: ");
1846 
1847 	hex_dump_to_buffer(&event->descriptor, sizeof(union ce_desc),
1848 				16, 1, buf + len,
1849 				(ssize_t)PAGE_SIZE - len, false);
1850 	len += CE_DEBUG_PRINT_BUF_SIZE(sizeof(union ce_desc));
1851 	len += snprintf(buf + len, PAGE_SIZE - len, "\n");
1852 
1853 #ifdef HIF_CE_DEBUG_DATA_BUF
1854 	if (ce_hist->data_enable[ce_hist->hist_id])
1855 		len = hif_dump_desc_data_buf(buf, len, event->data,
1856 						(event->actual_data_len <
1857 						 CE_DEBUG_MAX_DATA_BUF_SIZE) ?
1858 						event->actual_data_len :
1859 						CE_DEBUG_MAX_DATA_BUF_SIZE);
1860 #endif /*HIF_CE_DEBUG_DATA_BUF*/
1861 
1862 	len += snprintf(buf + len, PAGE_SIZE - len, "END\n");
1863 
1864 	return len;
1865 }
1866 
1867 /*
1868  * hif_store_desc_trace_buf_index() -
1869  * API to get the CE id and CE debug storage buffer index
1870  *
1871  * @dev: network device
1872  * @attr: sysfs attribute
1873  * @buf: data got from the user
1874  *
1875  * Return total length
1876  */
hif_input_desc_trace_buf_index(struct hif_softc * scn,const char * buf,size_t size)1877 ssize_t hif_input_desc_trace_buf_index(struct hif_softc *scn,
1878 					const char *buf, size_t size)
1879 {
1880 	struct ce_desc_hist *ce_hist = NULL;
1881 
1882 	if (!scn)
1883 		return -EINVAL;
1884 
1885 	ce_hist = &scn->hif_ce_desc_hist;
1886 
1887 	if (!size) {
1888 		qdf_nofl_err("%s: Invalid input buffer.", __func__);
1889 		return -EINVAL;
1890 	}
1891 
1892 	if (sscanf(buf, "%u %u", (unsigned int *)&ce_hist->hist_id,
1893 		   (unsigned int *)&ce_hist->hist_index) != 2) {
1894 		qdf_nofl_err("%s: Invalid input value.", __func__);
1895 		return -EINVAL;
1896 	}
1897 	if ((ce_hist->hist_id >= CE_COUNT_MAX) ||
1898 	   (ce_hist->hist_index >= HIF_CE_HISTORY_MAX)) {
1899 		qdf_print("Invalid values");
1900 		return -EINVAL;
1901 	}
1902 
1903 	return size;
1904 }
1905 
1906 #endif /*defined(HIF_CONFIG_SLUB_DEBUG_ON) || defined(HIF_CE_DEBUG_DATA_BUF) */
1907 
1908 #ifdef HIF_CE_DEBUG_DATA_BUF
1909 /*
1910  * hif_ce_en_desc_hist() -
1911  * API to enable recording the CE desc history
1912  *
1913  * @dev: network device
1914  * @attr: sysfs attribute
1915  * @buf: buffer to copy the data.
1916  *
1917  * Starts recording the ce desc history
1918  *
1919  * Return total length copied
1920  */
hif_ce_en_desc_hist(struct hif_softc * scn,const char * buf,size_t size)1921 ssize_t hif_ce_en_desc_hist(struct hif_softc *scn, const char *buf, size_t size)
1922 {
1923 	struct ce_desc_hist *ce_hist = NULL;
1924 	uint32_t cfg = 0;
1925 	uint32_t ce_id = 0;
1926 
1927 	if (!scn)
1928 		return -EINVAL;
1929 
1930 	ce_hist = &scn->hif_ce_desc_hist;
1931 
1932 	if (!size) {
1933 		qdf_nofl_err("%s: Invalid input buffer.", __func__);
1934 		return -EINVAL;
1935 	}
1936 
1937 	if (sscanf(buf, "%u %u", (unsigned int *)&ce_id,
1938 		   (unsigned int *)&cfg) != 2) {
1939 		qdf_nofl_err("%s: Invalid input: Enter CE Id<sp><1/0>.",
1940 			     __func__);
1941 		return -EINVAL;
1942 	}
1943 	if (ce_id >= CE_COUNT_MAX) {
1944 		qdf_print("Invalid value CE Id");
1945 		return -EINVAL;
1946 	}
1947 
1948 	if ((cfg > 1 || cfg < 0)) {
1949 		qdf_print("Invalid values: enter 0 or 1");
1950 		return -EINVAL;
1951 	}
1952 
1953 	if (!ce_hist->hist_ev[ce_id])
1954 		return -EINVAL;
1955 
1956 	qdf_mutex_acquire(&ce_hist->ce_dbg_datamem_lock[ce_id]);
1957 	if (cfg == 1) {
1958 		if (ce_hist->data_enable[ce_id] == 1) {
1959 			qdf_debug("Already Enabled");
1960 		} else {
1961 			if (alloc_mem_ce_debug_hist_data(scn, ce_id)
1962 							== QDF_STATUS_E_NOMEM){
1963 				ce_hist->data_enable[ce_id] = 0;
1964 				qdf_err("%s:Memory Alloc failed", __func__);
1965 			} else
1966 				ce_hist->data_enable[ce_id] = 1;
1967 		}
1968 	} else if (cfg == 0) {
1969 		if (ce_hist->data_enable[ce_id] == 0) {
1970 			qdf_debug("Already Disabled");
1971 		} else {
1972 			ce_hist->data_enable[ce_id] = 0;
1973 				free_mem_ce_debug_hist_data(scn, ce_id);
1974 		}
1975 	}
1976 	qdf_mutex_release(&ce_hist->ce_dbg_datamem_lock[ce_id]);
1977 
1978 	return size;
1979 }
1980 
1981 /*
1982  * hif_disp_ce_enable_desc_data_hist() -
1983  * API to display value of data_enable
1984  *
1985  * @dev: network device
1986  * @attr: sysfs attribute
1987  * @buf: buffer to copy the data.
1988  *
1989  * Return total length copied
1990  */
hif_disp_ce_enable_desc_data_hist(struct hif_softc * scn,char * buf)1991 ssize_t hif_disp_ce_enable_desc_data_hist(struct hif_softc *scn, char *buf)
1992 {
1993 	ssize_t len = 0;
1994 	uint32_t ce_id = 0;
1995 	struct ce_desc_hist *ce_hist = NULL;
1996 
1997 	if (!scn)
1998 		return -EINVAL;
1999 
2000 	ce_hist = &scn->hif_ce_desc_hist;
2001 
2002 	for (ce_id = 0; ce_id < CE_COUNT_MAX; ce_id++) {
2003 		len += snprintf(buf + len, PAGE_SIZE - len, " CE%d: %d\n",
2004 				ce_id, ce_hist->data_enable[ce_id]);
2005 	}
2006 
2007 	return len;
2008 }
2009 #endif /* HIF_CE_DEBUG_DATA_BUF */
2010 
2011 #ifdef OL_ATH_SMART_LOGGING
2012 #define GUARD_SPACE 10
2013 #define LOG_ID_SZ 4
2014 /*
2015  * hif_log_src_ce_dump() - Copy all the CE SRC ring to buf
2016  * @src_ring: SRC ring state
2017  * @buf_cur: Current pointer in ring buffer
2018  * @buf_init:Start of the ring buffer
2019  * @buf_sz: Size of the ring buffer
2020  * @skb_sz: Max size of the SKB buffer to be copied
2021  *
2022  * Dumps all the CE SRC ring descriptors and buffers pointed by them in to
2023  * the given buf, skb_sz is the max buffer size to be copied
2024  *
2025  * Return: Current pointer in ring buffer
2026  */
hif_log_src_ce_dump(struct CE_ring_state * src_ring,uint8_t * buf_cur,uint8_t * buf_init,uint32_t buf_sz,uint32_t skb_sz)2027 static uint8_t *hif_log_src_ce_dump(struct CE_ring_state *src_ring,
2028 				    uint8_t *buf_cur, uint8_t *buf_init,
2029 				    uint32_t buf_sz, uint32_t skb_sz)
2030 {
2031 	struct CE_src_desc *src_ring_base;
2032 	uint32_t len, entry;
2033 	struct CE_src_desc  *src_desc;
2034 	qdf_nbuf_t nbuf;
2035 	uint32_t available_buf;
2036 
2037 	src_ring_base = (struct CE_src_desc *)src_ring->base_addr_owner_space;
2038 	len = sizeof(struct CE_ring_state);
2039 	available_buf = buf_sz - (buf_cur - buf_init);
2040 	if (available_buf < (len + GUARD_SPACE)) {
2041 		buf_cur = buf_init;
2042 	}
2043 
2044 	qdf_mem_copy(buf_cur, src_ring, sizeof(struct CE_ring_state));
2045 	buf_cur += sizeof(struct CE_ring_state);
2046 
2047 	for (entry = 0; entry < src_ring->nentries; entry++) {
2048 		src_desc = CE_SRC_RING_TO_DESC(src_ring_base, entry);
2049 		nbuf = src_ring->per_transfer_context[entry];
2050 		if (nbuf) {
2051 			uint32_t skb_len  = qdf_nbuf_len(nbuf);
2052 			uint32_t skb_cp_len = qdf_min(skb_len, skb_sz);
2053 
2054 			len = sizeof(struct CE_src_desc) + skb_cp_len
2055 				+ LOG_ID_SZ + sizeof(skb_cp_len);
2056 			available_buf = buf_sz - (buf_cur - buf_init);
2057 			if (available_buf < (len + GUARD_SPACE)) {
2058 				buf_cur = buf_init;
2059 			}
2060 			qdf_mem_copy(buf_cur, src_desc,
2061 				     sizeof(struct CE_src_desc));
2062 			buf_cur += sizeof(struct CE_src_desc);
2063 
2064 			available_buf = buf_sz - (buf_cur - buf_init);
2065 			buf_cur += snprintf(buf_cur, available_buf, "SKB%d",
2066 						skb_cp_len);
2067 
2068 			if (skb_cp_len) {
2069 				qdf_mem_copy(buf_cur, qdf_nbuf_data(nbuf),
2070 					     skb_cp_len);
2071 				buf_cur += skb_cp_len;
2072 			}
2073 		} else {
2074 			len = sizeof(struct CE_src_desc) + LOG_ID_SZ;
2075 			available_buf = buf_sz - (buf_cur - buf_init);
2076 			if (available_buf < (len + GUARD_SPACE)) {
2077 				buf_cur = buf_init;
2078 			}
2079 			qdf_mem_copy(buf_cur, src_desc,
2080 				     sizeof(struct CE_src_desc));
2081 			buf_cur += sizeof(struct CE_src_desc);
2082 			available_buf = buf_sz - (buf_cur - buf_init);
2083 			buf_cur += snprintf(buf_cur, available_buf, "NUL");
2084 		}
2085 	}
2086 
2087 	return buf_cur;
2088 }
2089 
2090 /*
2091  * hif_log_dest_ce_dump() - Copy all the CE DEST ring to buf
2092  * @dest_ring: SRC ring state
2093  * @buf_cur: Current pointer in ring buffer
2094  * @buf_init:Start of the ring buffer
2095  * @buf_sz: Size of the ring buffer
2096  * @skb_sz: Max size of the SKB buffer to be copied
2097  *
2098  * Dumps all the CE SRC ring descriptors and buffers pointed by them in to
2099  * the given buf, skb_sz is the max buffer size to be copied
2100  *
2101  * Return: Current pointer in ring buffer
2102  */
hif_log_dest_ce_dump(struct CE_ring_state * dest_ring,uint8_t * buf_cur,uint8_t * buf_init,uint32_t buf_sz,uint32_t skb_sz)2103 static uint8_t *hif_log_dest_ce_dump(struct CE_ring_state *dest_ring,
2104 				     uint8_t *buf_cur, uint8_t *buf_init,
2105 				     uint32_t buf_sz, uint32_t skb_sz)
2106 {
2107 	struct CE_dest_desc *dest_ring_base;
2108 	uint32_t len, entry;
2109 	struct CE_dest_desc  *dest_desc;
2110 	qdf_nbuf_t nbuf;
2111 	uint32_t available_buf;
2112 
2113 	dest_ring_base =
2114 		(struct CE_dest_desc *)dest_ring->base_addr_owner_space;
2115 
2116 	len = sizeof(struct CE_ring_state);
2117 	available_buf = buf_sz - (buf_cur - buf_init);
2118 	if (available_buf < (len + GUARD_SPACE)) {
2119 		buf_cur = buf_init;
2120 	}
2121 
2122 	qdf_mem_copy(buf_cur, dest_ring, sizeof(struct CE_ring_state));
2123 	buf_cur += sizeof(struct CE_ring_state);
2124 
2125 	for (entry = 0; entry < dest_ring->nentries; entry++) {
2126 		dest_desc = CE_DEST_RING_TO_DESC(dest_ring_base, entry);
2127 
2128 		nbuf = dest_ring->per_transfer_context[entry];
2129 		if (nbuf) {
2130 			uint32_t skb_len  = qdf_nbuf_len(nbuf);
2131 			uint32_t skb_cp_len = qdf_min(skb_len, skb_sz);
2132 
2133 			len = sizeof(struct CE_dest_desc) + skb_cp_len
2134 				+ LOG_ID_SZ + sizeof(skb_cp_len);
2135 
2136 			available_buf = buf_sz - (buf_cur - buf_init);
2137 			if (available_buf < (len + GUARD_SPACE)) {
2138 				buf_cur = buf_init;
2139 			}
2140 
2141 			qdf_mem_copy(buf_cur, dest_desc,
2142 				     sizeof(struct CE_dest_desc));
2143 			buf_cur += sizeof(struct CE_dest_desc);
2144 			available_buf = buf_sz - (buf_cur - buf_init);
2145 			buf_cur += snprintf(buf_cur, available_buf, "SKB%d",
2146 						skb_cp_len);
2147 			if (skb_cp_len) {
2148 				qdf_mem_copy(buf_cur, qdf_nbuf_data(nbuf),
2149 					     skb_cp_len);
2150 				buf_cur += skb_cp_len;
2151 			}
2152 		} else {
2153 			len = sizeof(struct CE_dest_desc) + LOG_ID_SZ;
2154 			available_buf = buf_sz - (buf_cur - buf_init);
2155 			if (available_buf < (len + GUARD_SPACE)) {
2156 				buf_cur = buf_init;
2157 			}
2158 			qdf_mem_copy(buf_cur, dest_desc,
2159 				     sizeof(struct CE_dest_desc));
2160 			buf_cur += sizeof(struct CE_dest_desc);
2161 			available_buf = buf_sz - (buf_cur - buf_init);
2162 			buf_cur += snprintf(buf_cur, available_buf, "NUL");
2163 		}
2164 	}
2165 	return buf_cur;
2166 }
2167 
2168 /**
2169  * hif_log_dump_ce() - Copy all the CE DEST ring to buf
2170  * @scn:
2171  * @buf_cur:
2172  * @buf_init:
2173  * @buf_sz:
2174  * @ce:
2175  * @skb_sz:
2176  *
2177  * Calls the respective function to dump all the CE SRC/DEST ring descriptors
2178  * and buffers pointed by them in to the given buf
2179  */
hif_log_dump_ce(struct hif_softc * scn,uint8_t * buf_cur,uint8_t * buf_init,uint32_t buf_sz,uint32_t ce,uint32_t skb_sz)2180 uint8_t *hif_log_dump_ce(struct hif_softc *scn, uint8_t *buf_cur,
2181 			 uint8_t *buf_init, uint32_t buf_sz,
2182 			 uint32_t ce, uint32_t skb_sz)
2183 {
2184 	struct CE_state *ce_state;
2185 	struct CE_ring_state *src_ring;
2186 	struct CE_ring_state *dest_ring;
2187 
2188 	ce_state = scn->ce_id_to_state[ce];
2189 	src_ring = ce_state->src_ring;
2190 	dest_ring = ce_state->dest_ring;
2191 
2192 	if (src_ring) {
2193 		buf_cur = hif_log_src_ce_dump(src_ring, buf_cur,
2194 					      buf_init, buf_sz, skb_sz);
2195 	} else if (dest_ring) {
2196 		buf_cur = hif_log_dest_ce_dump(dest_ring, buf_cur,
2197 					       buf_init, buf_sz, skb_sz);
2198 	}
2199 
2200 	return buf_cur;
2201 }
2202 
2203 qdf_export_symbol(hif_log_dump_ce);
2204 #endif /* OL_ATH_SMART_LOGGING */
2205 
2206