1 /*
2  * Copyright (c) 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 any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include "dp_types.h"
19 #include "qdf_mem.h"
20 #include "qdf_nbuf.h"
21 #include "cfg_dp.h"
22 #include "wlan_cfg.h"
23 #include "dp_types.h"
24 #include "hal_rx_flow.h"
25 #include "dp_htt.h"
26 #include "dp_internal.h"
27 #include "hif.h"
28 #include "wlan_dp_rx_thread.h"
29 #include <wlan_dp_main.h>
30 #include <wlan_dp_fisa_rx.h>
31 #include <cdp_txrx_ctrl.h>
32 #include "qdf_ssr_driver_dump.h"
33 
34 /* Timeout in milliseconds to wait for CMEM FST HTT response */
35 #define DP_RX_FST_CMEM_RESP_TIMEOUT 2000
36 
37 #define INVALID_NAPI 0Xff
38 
39 #ifdef WLAN_SUPPORT_RX_FISA
40 void dp_fisa_rx_fst_update_work(void *arg);
41 
dp_rx_dump_fisa_table(struct wlan_dp_psoc_context * dp_ctx)42 static void dp_rx_dump_fisa_table(struct wlan_dp_psoc_context *dp_ctx)
43 {
44 	hal_soc_handle_t hal_soc_hdl = dp_ctx->hal_soc;
45 	struct wlan_dp_psoc_cfg *dp_cfg = &dp_ctx->dp_cfg;
46 	struct dp_rx_fst *fst = dp_ctx->rx_fst;
47 	struct dp_fisa_rx_sw_ft *sw_ft_entry;
48 	int i;
49 
50 	/* Check if it is enabled in the INI */
51 	if (!wlan_dp_cfg_is_rx_fisa_enabled(dp_cfg)) {
52 		dp_err("RX FISA feature is disabled");
53 		return;
54 	}
55 
56 	if (!fst->fst_in_cmem)
57 		return hal_rx_dump_fse_table(fst->hal_rx_fst);
58 
59 	sw_ft_entry = (struct dp_fisa_rx_sw_ft *)fst->base;
60 
61 	if (hif_force_wake_request(((struct hal_soc *)hal_soc_hdl)->hif_handle)) {
62 		dp_err("Wake up request failed");
63 		qdf_check_state_before_panic(__func__, __LINE__);
64 		return;
65 	}
66 
67 	for (i = 0; i < fst->max_entries; i++)
68 		hal_rx_dump_cmem_fse(hal_soc_hdl,
69 				     sw_ft_entry[i].cmem_offset, i);
70 
71 	if (hif_force_wake_release(((struct hal_soc *)hal_soc_hdl)->hif_handle)) {
72 		dp_err("Wake up release failed");
73 		qdf_check_state_before_panic(__func__, __LINE__);
74 		return;
75 	}
76 }
77 
dp_print_fisa_stats(struct wlan_dp_psoc_context * dp_ctx)78 static void dp_print_fisa_stats(struct wlan_dp_psoc_context *dp_ctx)
79 {
80 	struct wlan_dp_psoc_cfg *dp_cfg = &dp_ctx->dp_cfg;
81 	struct dp_rx_fst *fst = dp_ctx->rx_fst;
82 
83 	/* Check if it is enabled in the INI */
84 	if (!wlan_dp_cfg_is_rx_fisa_enabled(dp_cfg))
85 		return;
86 
87 	dp_info("invalid flow index: %u", fst->stats.invalid_flow_index);
88 	dp_info("workqueue update deferred: %u", fst->stats.update_deferred);
89 	dp_info("reo_mismatch: cce_match: %u",
90 		fst->stats.reo_mismatch.allow_cce_match);
91 	dp_info("reo_mismatch: allow_fse_metdata_mismatch: %u",
92 		fst->stats.reo_mismatch.allow_fse_metdata_mismatch);
93 	dp_info("reo_mismatch: allow_non_aggr: %u",
94 		fst->stats.reo_mismatch.allow_non_aggr);
95 }
96 
97 /* Length of string to store tuple information for printing */
98 #define DP_TUPLE_STR_LEN 512
99 
100 /**
101  * print_flow_tuple() - Debug function to dump flow tuple
102  * @flow_tuple: flow tuple containing tuple info
103  * @str: destination buffer
104  * @size: size of @str
105  *
106  * Return: NONE
107  */
108 static
print_flow_tuple(struct cdp_rx_flow_tuple_info * flow_tuple,char * str,uint32_t size)109 void print_flow_tuple(struct cdp_rx_flow_tuple_info *flow_tuple, char *str,
110 		      uint32_t size)
111 {
112 	qdf_scnprintf(str, size,
113 		      "dest 0x%x%x%x%x(0x%x) src 0x%x%x%x%x(0x%x) proto 0x%x",
114 		      flow_tuple->dest_ip_127_96,
115 		      flow_tuple->dest_ip_95_64,
116 		      flow_tuple->dest_ip_63_32,
117 		      flow_tuple->dest_ip_31_0,
118 		      flow_tuple->dest_port,
119 		      flow_tuple->src_ip_127_96,
120 		      flow_tuple->src_ip_95_64,
121 		      flow_tuple->src_ip_63_32,
122 		      flow_tuple->src_ip_31_0,
123 		      flow_tuple->src_port,
124 		      flow_tuple->l4_protocol);
125 }
126 
dp_rx_dump_fisa_stats(struct wlan_dp_psoc_context * dp_ctx)127 static QDF_STATUS dp_rx_dump_fisa_stats(struct wlan_dp_psoc_context *dp_ctx)
128 {
129 	char tuple_str[DP_TUPLE_STR_LEN] = {'\0'};
130 	struct dp_rx_fst *rx_fst = dp_ctx->rx_fst;
131 	struct dp_fisa_rx_sw_ft *sw_ft_entry =
132 		&((struct dp_fisa_rx_sw_ft *)rx_fst->base)[0];
133 	int ft_size = rx_fst->max_entries;
134 	int i;
135 
136 	dp_info("#flows added %d evicted %d hash collision %d",
137 		rx_fst->add_flow_count,
138 		rx_fst->del_flow_count,
139 		rx_fst->hash_collision_cnt);
140 
141 	for (i = 0; i < ft_size; i++, sw_ft_entry++) {
142 		if (!sw_ft_entry->is_populated)
143 			continue;
144 
145 		print_flow_tuple(&sw_ft_entry->rx_flow_tuple_info,
146 				 tuple_str,
147 				 sizeof(tuple_str));
148 
149 		dp_info("Flow[%d][%s][%s] ring %d msdu-aggr %d flushes %d bytes-agg %llu avg-bytes-aggr %llu same_mld_vdev_mismatch %llu",
150 			sw_ft_entry->flow_id,
151 			sw_ft_entry->is_flow_udp ? "udp" : "tcp",
152 			tuple_str,
153 			sw_ft_entry->napi_id,
154 			sw_ft_entry->aggr_count,
155 			sw_ft_entry->flush_count,
156 			sw_ft_entry->bytes_aggregated,
157 			qdf_do_div(sw_ft_entry->bytes_aggregated,
158 				   sw_ft_entry->flush_count),
159 			sw_ft_entry->same_mld_vdev_mismatch);
160 	}
161 	return QDF_STATUS_SUCCESS;
162 }
163 
dp_set_fst_in_cmem(bool fst_in_cmem)164 void dp_set_fst_in_cmem(bool fst_in_cmem)
165 {
166 	struct wlan_dp_psoc_context *dp_ctx = dp_get_context();
167 
168 	dp_ctx->fst_in_cmem = fst_in_cmem;
169 }
170 
dp_print_fisa_rx_stats(enum cdp_fisa_stats_id stats_id)171 void dp_print_fisa_rx_stats(enum cdp_fisa_stats_id stats_id)
172 {
173 	struct wlan_dp_psoc_context *dp_ctx = dp_get_context();
174 
175 	switch (stats_id) {
176 	case CDP_FISA_STATS_ID_ERR_STATS:
177 		dp_print_fisa_stats(dp_ctx);
178 		break;
179 	case CDP_FISA_STATS_ID_DUMP_HW_FST:
180 		dp_rx_dump_fisa_table(dp_ctx);
181 		break;
182 	case CDP_FISA_STATS_ID_DUMP_SW_FST:
183 		dp_rx_dump_fisa_stats(dp_ctx);
184 		break;
185 	default:
186 		break;
187 	}
188 }
189 
190 /**
191  * dp_rx_flow_send_htt_operation_cmd() - Invalidate FSE cache on FT change
192  * @dp_ctx: DP component handle
193  * @fse_op: Cache operation code
194  * @rx_flow_tuple: flow tuple whose entry has to be invalidated
195  *
196  * Return: Success if we successfully send FW HTT command
197  */
198 static QDF_STATUS
dp_rx_flow_send_htt_operation_cmd(struct wlan_dp_psoc_context * dp_ctx,enum dp_htt_flow_fst_operation fse_op,struct cdp_rx_flow_tuple_info * rx_flow_tuple)199 dp_rx_flow_send_htt_operation_cmd(struct wlan_dp_psoc_context *dp_ctx,
200 				  enum dp_htt_flow_fst_operation fse_op,
201 				  struct cdp_rx_flow_tuple_info *rx_flow_tuple)
202 {
203 	struct dp_htt_rx_flow_fst_operation fse_op_cmd;
204 	struct cdp_rx_flow_info rx_flow_info;
205 	union cdp_fisa_config cfg;
206 
207 	rx_flow_info.is_addr_ipv4 = true;
208 	rx_flow_info.op_code = CDP_FLOW_FST_ENTRY_ADD;
209 	qdf_mem_copy(&rx_flow_info.flow_tuple_info, rx_flow_tuple,
210 		     sizeof(struct cdp_rx_flow_tuple_info));
211 	rx_flow_info.fse_metadata = 0xDADA;
212 	fse_op_cmd.pdev_id = OL_TXRX_PDEV_ID;
213 	fse_op_cmd.op_code = fse_op;
214 	fse_op_cmd.rx_flow = &rx_flow_info;
215 
216 	cfg.fse_op_cmd = &fse_op_cmd;
217 
218 	return cdp_txrx_fisa_config(dp_ctx->cdp_soc, OL_TXRX_PDEV_ID,
219 				    CDP_FISA_HTT_RX_FSE_OP_CFG, &cfg);
220 }
221 
222 /**
223  * dp_fisa_fse_cache_flush_timer() - FSE cache flush timeout handler
224  * @arg: SoC handle
225  *
226  * Return: None
227  */
dp_fisa_fse_cache_flush_timer(void * arg)228 static void dp_fisa_fse_cache_flush_timer(void *arg)
229 {
230 	struct wlan_dp_psoc_context *dp_ctx =
231 					(struct wlan_dp_psoc_context *)arg;
232 	struct dp_rx_fst *fisa_hdl = dp_ctx->rx_fst;
233 	struct cdp_rx_flow_tuple_info rx_flow_tuple_info = { 0 };
234 	static uint32_t fse_cache_flush_rec_idx;
235 	struct fse_cache_flush_history *fse_cache_flush_rec;
236 	QDF_STATUS status;
237 
238 	if (!fisa_hdl)
239 		return;
240 
241 	if (qdf_atomic_read(&fisa_hdl->pm_suspended)) {
242 		qdf_atomic_set(&fisa_hdl->fse_cache_flush_posted, 0);
243 		return;
244 	}
245 
246 	fse_cache_flush_rec = &fisa_hdl->cache_fl_rec[fse_cache_flush_rec_idx %
247 							MAX_FSE_CACHE_FL_HST];
248 	fse_cache_flush_rec->timestamp = qdf_get_log_timestamp();
249 	fse_cache_flush_rec->flows_added =
250 			qdf_atomic_read(&fisa_hdl->fse_cache_flush_posted);
251 	fse_cache_flush_rec_idx++;
252 	dp_info("FSE cache flush for %d flows",
253 		fse_cache_flush_rec->flows_added);
254 
255 	status =
256 	 dp_rx_flow_send_htt_operation_cmd(dp_ctx,
257 					   DP_HTT_FST_CACHE_INVALIDATE_FULL,
258 					   &rx_flow_tuple_info);
259 	if (QDF_IS_STATUS_ERROR(status)) {
260 		dp_err("Failed to send the cache invalidation");
261 		/*
262 		 * Not big impact cache entry gets updated later
263 		 */
264 	}
265 
266 	qdf_atomic_set(&fisa_hdl->fse_cache_flush_posted, 0);
267 }
268 
269 /**
270  * dp_rx_fst_cmem_deinit() - De-initialize CMEM parameters
271  * @fst: Pointer to DP FST
272  *
273  * Return: None
274  */
dp_rx_fst_cmem_deinit(struct dp_rx_fst * fst)275 static void dp_rx_fst_cmem_deinit(struct dp_rx_fst *fst)
276 {
277 	struct dp_fisa_rx_fst_update_elem *elem;
278 	qdf_list_node_t *node;
279 	int i;
280 
281 	qdf_cancel_work(&fst->fst_update_work);
282 	qdf_flush_work(&fst->fst_update_work);
283 	qdf_flush_workqueue(0, fst->fst_update_wq);
284 	qdf_destroy_workqueue(0, fst->fst_update_wq);
285 
286 	qdf_spin_lock_bh(&fst->dp_rx_fst_lock);
287 	while (qdf_list_peek_front(&fst->fst_update_list, &node) ==
288 	       QDF_STATUS_SUCCESS) {
289 		elem = (struct dp_fisa_rx_fst_update_elem *)node;
290 		qdf_list_remove_front(&fst->fst_update_list, &node);
291 		qdf_mem_free(elem);
292 	}
293 	qdf_spin_unlock_bh(&fst->dp_rx_fst_lock);
294 
295 	qdf_list_destroy(&fst->fst_update_list);
296 	qdf_event_destroy(&fst->cmem_resp_event);
297 
298 	for (i = 0; i < MAX_REO_DEST_RINGS; i++)
299 		qdf_spinlock_destroy(&fst->dp_rx_sw_ft_lock[i]);
300 }
301 
302 /**
303  * dp_rx_fst_cmem_init() - Initialize CMEM parameters
304  * @fst: Pointer to DP FST
305  *
306  * Return: Success/Failure
307  */
dp_rx_fst_cmem_init(struct dp_rx_fst * fst)308 static QDF_STATUS dp_rx_fst_cmem_init(struct dp_rx_fst *fst)
309 {
310 	int i;
311 
312 	fst->fst_update_wq =
313 		qdf_alloc_high_prior_ordered_workqueue("dp_rx_fst_update_wq");
314 	if (!fst->fst_update_wq) {
315 		dp_err("failed to allocate fst update wq");
316 		return QDF_STATUS_E_FAILURE;
317 	}
318 
319 	qdf_create_work(0, &fst->fst_update_work,
320 			dp_fisa_rx_fst_update_work, fst);
321 	qdf_list_create(&fst->fst_update_list, 128);
322 	qdf_event_create(&fst->cmem_resp_event);
323 
324 	for (i = 0; i < MAX_REO_DEST_RINGS; i++)
325 		qdf_spinlock_create(&fst->dp_rx_sw_ft_lock[i]);
326 
327 	return QDF_STATUS_SUCCESS;
328 }
329 
330 #ifdef WLAN_SUPPORT_RX_FISA_HIST
331 static
dp_rx_sw_ft_hist_init(struct dp_fisa_rx_sw_ft * sw_ft,uint32_t max_entries,uint32_t rx_pkt_tlv_size)332 QDF_STATUS dp_rx_sw_ft_hist_init(struct dp_fisa_rx_sw_ft *sw_ft,
333 				 uint32_t max_entries,
334 				 uint32_t rx_pkt_tlv_size)
335 {
336 	int i;
337 	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
338 
339 	for (i = 0; i < max_entries; i++) {
340 		sw_ft[i].pkt_hist.tlv_hist =
341 			(uint8_t *)qdf_mem_malloc(rx_pkt_tlv_size *
342 						  FISA_FLOW_MAX_AGGR_COUNT);
343 		if (!sw_ft[i].pkt_hist.tlv_hist) {
344 			dp_err("unable to allocate tlv history");
345 			qdf_status = QDF_STATUS_E_NOMEM;
346 			break;
347 		}
348 	}
349 	return qdf_status;
350 }
351 
dp_rx_sw_ft_hist_deinit(struct dp_fisa_rx_sw_ft * sw_ft,uint32_t max_entries)352 static void dp_rx_sw_ft_hist_deinit(struct dp_fisa_rx_sw_ft *sw_ft,
353 				    uint32_t max_entries)
354 {
355 	int i;
356 
357 	for (i = 0; i < max_entries; i++) {
358 		if (sw_ft[i].pkt_hist.tlv_hist)
359 			qdf_mem_free(sw_ft[i].pkt_hist.tlv_hist);
360 	}
361 }
362 
363 #else
364 
365 static
dp_rx_sw_ft_hist_init(struct dp_fisa_rx_sw_ft * sw_ft,uint32_t max_entries,uint32_t rx_pkt_tlv_size)366 QDF_STATUS dp_rx_sw_ft_hist_init(struct dp_fisa_rx_sw_ft *sw_ft,
367 				 uint32_t max_entries,
368 				 uint32_t rx_pkt_tlv_size)
369 {
370 	return QDF_STATUS_SUCCESS;
371 }
372 
dp_rx_sw_ft_hist_deinit(struct dp_fisa_rx_sw_ft * sw_ft,uint32_t max_entries)373 static void dp_rx_sw_ft_hist_deinit(struct dp_fisa_rx_sw_ft *sw_ft,
374 				    uint32_t max_entries)
375 {
376 }
377 #endif
378 
dp_rx_fst_attach(struct wlan_dp_psoc_context * dp_ctx)379 QDF_STATUS dp_rx_fst_attach(struct wlan_dp_psoc_context *dp_ctx)
380 {
381 	struct dp_soc *soc = (struct dp_soc *)dp_ctx->cdp_soc;
382 	struct wlan_dp_psoc_cfg *dp_cfg = &dp_ctx->dp_cfg;
383 	struct dp_rx_fst *fst;
384 	struct dp_fisa_rx_sw_ft *ft_entry;
385 	cdp_config_param_type soc_param;
386 	int i = 0;
387 	QDF_STATUS status;
388 
389 	/* Check if it is enabled in the INI */
390 	if (!wlan_dp_cfg_is_rx_fisa_enabled(dp_cfg)) {
391 		dp_err("RX FISA feature is disabled");
392 		return QDF_STATUS_E_NOSUPPORT;
393 	}
394 
395 #ifdef NOT_YET /* Not required for now */
396 	/* Check if FW supports */
397 	if (!wlan_psoc_nif_fw_ext_cap_get((void *)pdev->ctrl_pdev,
398 					  WLAN_SOC_CEXT_RX_FSE_SUPPORT)) {
399 		QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_ERROR,
400 			  "rx fse disabled in FW\n");
401 		wlan_cfg_set_rx_flow_tag_enabled(cfg, false);
402 		return QDF_STATUS_E_NOSUPPORT;
403 	}
404 #endif
405 	if (dp_ctx->rx_fst) {
406 		QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_ERROR,
407 			  "RX FST already allocated\n");
408 		return QDF_STATUS_SUCCESS;
409 	}
410 
411 	fst = qdf_mem_malloc(sizeof(struct dp_rx_fst));
412 	if (!fst)
413 		return QDF_STATUS_E_NOMEM;
414 
415 	fst->rx_pkt_tlv_size = 0;
416 	status = cdp_txrx_get_psoc_param(dp_ctx->cdp_soc, CDP_RX_PKT_TLV_SIZE,
417 					 &soc_param);
418 	if (QDF_IS_STATUS_ERROR(status)) {
419 		dp_err("Unable to fetch RX pkt tlv size");
420 		return status;
421 	}
422 
423 	fst->rx_pkt_tlv_size = soc_param.rx_pkt_tlv_size;
424 
425 	/* This will clear entire FISA params */
426 	soc_param.fisa_params.rx_toeplitz_hash_key = NULL;
427 	status = cdp_txrx_get_psoc_param(dp_ctx->cdp_soc, CDP_CFG_FISA_PARAMS,
428 					 &soc_param);
429 	if (QDF_IS_STATUS_ERROR(status)) {
430 		dp_err("Unable to fetch fisa params");
431 		return status;
432 	}
433 
434 	fst->max_skid_length = soc_param.fisa_params.rx_flow_max_search;
435 	fst->max_entries = soc_param.fisa_params.fisa_fst_size;
436 	fst->rx_toeplitz_hash_key = soc_param.fisa_params.rx_toeplitz_hash_key;
437 
438 	fst->hash_mask = fst->max_entries - 1;
439 	fst->num_entries = 0;
440 	dp_info("FST setup params FT size %d, hash_mask 0x%x, skid_length %d",
441 		fst->max_entries, fst->hash_mask, fst->max_skid_length);
442 
443 	/* Allocate the software flowtable */
444 	fst->base = (uint8_t *)dp_context_alloc_mem(soc, DP_FISA_RX_FT_TYPE,
445 				DP_RX_GET_SW_FT_ENTRY_SIZE * fst->max_entries);
446 
447 	if (!fst->base)
448 		goto free_rx_fst;
449 
450 	ft_entry = (struct dp_fisa_rx_sw_ft *)fst->base;
451 
452 	for (i = 0; i < fst->max_entries; i++)
453 		ft_entry[i].napi_id = INVALID_NAPI;
454 
455 	status = dp_rx_sw_ft_hist_init(ft_entry, fst->max_entries,
456 				       fst->rx_pkt_tlv_size);
457 	if (QDF_IS_STATUS_ERROR(status))
458 		goto free_hist;
459 
460 	fst->hal_rx_fst = hal_rx_fst_attach(dp_ctx->hal_soc,
461 					    dp_ctx->qdf_dev,
462 					    &fst->hal_rx_fst_base_paddr,
463 					    fst->max_entries,
464 					    fst->max_skid_length,
465 					    fst->rx_toeplitz_hash_key,
466 					    dp_ctx->fst_cmem_base);
467 
468 	if (qdf_unlikely(!fst->hal_rx_fst)) {
469 		QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_ERROR,
470 			  "Rx Hal fst allocation failed, #entries:%d\n",
471 			  fst->max_entries);
472 		goto free_hist;
473 	}
474 
475 	qdf_spinlock_create(&fst->dp_rx_fst_lock);
476 
477 	status = qdf_timer_init(dp_ctx->qdf_dev, &fst->fse_cache_flush_timer,
478 				dp_fisa_fse_cache_flush_timer, (void *)dp_ctx,
479 				QDF_TIMER_TYPE_WAKE_APPS);
480 	if (QDF_IS_STATUS_ERROR(status)) {
481 		QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_ERROR,
482 			  "Failed to init cache_flush_timer\n");
483 		goto timer_init_fail;
484 	}
485 
486 	qdf_atomic_init(&fst->fse_cache_flush_posted);
487 
488 	fst->fse_cache_flush_allow = true;
489 	fst->rx_hash_enabled = wlan_cfg_is_rx_hash_enabled(soc->wlan_cfg_ctx);
490 	fst->soc_hdl = soc;
491 	fst->dp_ctx = dp_ctx;
492 	dp_ctx->rx_fst = fst;
493 	dp_ctx->fisa_enable = true;
494 	dp_ctx->fisa_lru_del_enable =
495 				wlan_dp_cfg_is_rx_fisa_lru_del_enabled(dp_cfg);
496 
497 	qdf_atomic_init(&dp_ctx->skip_fisa_param.skip_fisa);
498 	qdf_atomic_init(&fst->pm_suspended);
499 
500 	QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_ERROR,
501 		  "Rx FST attach successful, #entries:%d\n",
502 		  fst->max_entries);
503 
504 	qdf_ssr_driver_dump_register_region("dp_fisa", fst, sizeof(*fst));
505 	qdf_ssr_driver_dump_register_region("dp_fisa_sw_fse_table", fst->base,
506 					    DP_RX_GET_SW_FT_ENTRY_SIZE *
507 						   fst->max_entries);
508 
509 	return QDF_STATUS_SUCCESS;
510 
511 timer_init_fail:
512 	qdf_spinlock_destroy(&fst->dp_rx_fst_lock);
513 	hal_rx_fst_detach(dp_ctx->hal_soc, fst->hal_rx_fst, dp_ctx->qdf_dev,
514 			  dp_ctx->fst_cmem_base);
515 free_hist:
516 	dp_rx_sw_ft_hist_deinit((struct dp_fisa_rx_sw_ft *)fst->base,
517 				fst->max_entries);
518 	dp_context_free_mem(soc, DP_FISA_RX_FT_TYPE, fst->base);
519 free_rx_fst:
520 	qdf_mem_free(fst);
521 	return QDF_STATUS_E_NOMEM;
522 }
523 
524 /**
525  * dp_rx_fst_check_cmem_support() - Check if FW can allocate FSE in CMEM,
526  * allocate FSE in DDR if FW doesn't support CMEM allocation
527  * @dp_ctx: DP component context
528  *
529  * Return: None
530  */
dp_rx_fst_check_cmem_support(struct wlan_dp_psoc_context * dp_ctx)531 static void dp_rx_fst_check_cmem_support(struct wlan_dp_psoc_context *dp_ctx)
532 {
533 	struct dp_rx_fst *fst = dp_ctx->rx_fst;
534 	QDF_STATUS status;
535 
536 	/**
537 	 * FW doesn't support CMEM FSE, keep it in DDR
538 	 * dp_ctx->fst_cmem_base is non-NULL then CMEM support is
539 	 * already present
540 	 */
541 	if (!dp_ctx->fst_in_cmem && dp_ctx->fst_cmem_base == 0)
542 		return;
543 
544 	status = dp_rx_fst_cmem_init(fst);
545 	if (status != QDF_STATUS_SUCCESS)
546 		return;
547 
548 	hal_rx_fst_detach(dp_ctx->hal_soc, fst->hal_rx_fst, dp_ctx->qdf_dev,
549 			  dp_ctx->fst_cmem_base);
550 	fst->hal_rx_fst = NULL;
551 	fst->hal_rx_fst_base_paddr = 0;
552 	fst->flow_deletion_supported = true;
553 	fst->fst_in_cmem = true;
554 }
555 
556 /**
557  * dp_rx_flow_send_fst_fw_setup() - Program FST parameters in FW/HW post-attach
558  * @dp_ctx: DP component context
559  *
560  * Return: Success when fst parameters are programmed in FW, error otherwise
561  */
562 static QDF_STATUS
dp_rx_flow_send_fst_fw_setup(struct wlan_dp_psoc_context * dp_ctx)563 dp_rx_flow_send_fst_fw_setup(struct wlan_dp_psoc_context *dp_ctx)
564 {
565 	struct dp_htt_rx_flow_fst_setup fisa_hw_fst_setup_cmd = {0};
566 	struct dp_rx_fst *fst = dp_ctx->rx_fst;
567 	union cdp_fisa_config cfg;
568 	QDF_STATUS status;
569 
570 	/* check if FW has support to place FST in CMEM */
571 	dp_rx_fst_check_cmem_support(dp_ctx);
572 
573 	/* mac_id = 0 is used to configure both macs with same FT */
574 	fisa_hw_fst_setup_cmd.pdev_id = 0;
575 	fisa_hw_fst_setup_cmd.max_entries = fst->max_entries;
576 	fisa_hw_fst_setup_cmd.max_search = fst->max_skid_length;
577 	if (dp_ctx->fst_cmem_base) {
578 		fisa_hw_fst_setup_cmd.base_addr_lo =
579 			dp_ctx->fst_cmem_base & 0xffffffff;
580 		/* Higher order bits are mostly 0, Always use 0x10 */
581 		fisa_hw_fst_setup_cmd.base_addr_hi =
582 			(dp_ctx->fst_cmem_base >> 32) | 0x10;
583 		dp_info("cmem base address 0x%llx", dp_ctx->fst_cmem_base);
584 	} else {
585 		fisa_hw_fst_setup_cmd.base_addr_lo =
586 			fst->hal_rx_fst_base_paddr & 0xffffffff;
587 		fisa_hw_fst_setup_cmd.base_addr_hi =
588 			(fst->hal_rx_fst_base_paddr >> 32);
589 	}
590 
591 	fisa_hw_fst_setup_cmd.ip_da_sa_prefix =	HTT_RX_IPV4_COMPATIBLE_IPV6;
592 	fisa_hw_fst_setup_cmd.hash_key_len = HAL_FST_HASH_KEY_SIZE_BYTES;
593 	fisa_hw_fst_setup_cmd.hash_key = fst->rx_toeplitz_hash_key;
594 
595 	cfg.fse_setup_info = &fisa_hw_fst_setup_cmd;
596 
597 	status = cdp_txrx_fisa_config(dp_ctx->cdp_soc, OL_TXRX_PDEV_ID,
598 				      CDP_FISA_HTT_RX_FSE_SETUP_CFG, &cfg);
599 	if (!fst->fst_in_cmem || dp_ctx->fst_cmem_base) {
600 		/**
601 		 * Return from here if fst_cmem is not enabled or cmem address
602 		 * is known at init time
603 		 */
604 		return status;
605 	}
606 
607 	status = qdf_wait_single_event(&fst->cmem_resp_event,
608 				       DP_RX_FST_CMEM_RESP_TIMEOUT);
609 
610 	dp_err("FST params after CMEM update FT size %d, hash_mask 0x%x",
611 	       fst->max_entries, fst->hash_mask);
612 
613 	return status;
614 }
615 
dp_rx_fst_detach(struct wlan_dp_psoc_context * dp_ctx)616 void dp_rx_fst_detach(struct wlan_dp_psoc_context *dp_ctx)
617 {
618 	struct dp_soc *soc = (struct dp_soc *)dp_ctx->cdp_soc;
619 	struct dp_rx_fst *dp_fst;
620 
621 	dp_fst = dp_ctx->rx_fst;
622 	if (qdf_likely(dp_fst)) {
623 		qdf_ssr_driver_dump_unregister_region("dp_fisa_sw_fse_table");
624 		qdf_ssr_driver_dump_unregister_region("dp_fisa");
625 		qdf_timer_sync_cancel(&dp_fst->fse_cache_flush_timer);
626 		if (dp_fst->fst_in_cmem)
627 			dp_rx_fst_cmem_deinit(dp_fst);
628 		else
629 			hal_rx_fst_detach(soc->hal_soc, dp_fst->hal_rx_fst,
630 					  soc->osdev, dp_ctx->fst_cmem_base);
631 
632 		dp_rx_sw_ft_hist_deinit((struct dp_fisa_rx_sw_ft *)dp_fst->base,
633 					dp_fst->max_entries);
634 		dp_context_free_mem(soc, DP_FISA_RX_FT_TYPE, dp_fst->base);
635 		qdf_spinlock_destroy(&dp_fst->dp_rx_fst_lock);
636 		qdf_mem_free(dp_fst);
637 	}
638 
639 	dp_ctx->rx_fst = NULL;
640 	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
641 		  "Rx FST detached\n");
642 }
643 
644 /*
645  * dp_rx_fst_update_cmem_params() - Update CMEM FST params
646  * @soc:		DP SoC context
647  * @num_entries:	Number of flow search entries
648  * @cmem_ba_lo:		CMEM base address low
649  * @cmem_ba_hi:		CMEM base address high
650  *
651  * Return: None
652  */
dp_rx_fst_update_cmem_params(struct dp_soc * soc,uint16_t num_entries,uint32_t cmem_ba_lo,uint32_t cmem_ba_hi)653 void dp_rx_fst_update_cmem_params(struct dp_soc *soc, uint16_t num_entries,
654 				  uint32_t cmem_ba_lo, uint32_t cmem_ba_hi)
655 {
656 	struct wlan_dp_psoc_context *dp_ctx = dp_get_context();
657 	struct dp_rx_fst *fst = dp_ctx->rx_fst;
658 
659 	fst->max_entries = num_entries;
660 	fst->hash_mask = fst->max_entries - 1;
661 	fst->cmem_ba = cmem_ba_lo;
662 
663 	/* Address is not NULL then address is already known during init */
664 	if (dp_ctx->fst_cmem_base == 0)
665 		qdf_event_set(&fst->cmem_resp_event);
666 }
667 
dp_rx_fst_update_pm_suspend_status(struct wlan_dp_psoc_context * dp_ctx,bool suspended)668 void dp_rx_fst_update_pm_suspend_status(struct wlan_dp_psoc_context *dp_ctx,
669 					bool suspended)
670 {
671 	struct dp_rx_fst *fst = dp_ctx->rx_fst;
672 
673 	if (!fst)
674 		return;
675 
676 	if (suspended)
677 		qdf_atomic_set(&fst->pm_suspended, 1);
678 	else
679 		qdf_atomic_set(&fst->pm_suspended, 0);
680 }
681 
dp_rx_fst_requeue_wq(struct wlan_dp_psoc_context * dp_ctx)682 void dp_rx_fst_requeue_wq(struct wlan_dp_psoc_context *dp_ctx)
683 {
684 	struct dp_rx_fst *fst = dp_ctx->rx_fst;
685 
686 	if (!fst || !fst->fst_wq_defer)
687 		return;
688 
689 	fst->fst_wq_defer = false;
690 	qdf_queue_work(fst->soc_hdl->osdev,
691 		       fst->fst_update_wq,
692 		       &fst->fst_update_work);
693 
694 	dp_info("requeued defer fst update task");
695 }
696 
dp_rx_fst_target_config(struct wlan_dp_psoc_context * dp_ctx)697 QDF_STATUS dp_rx_fst_target_config(struct wlan_dp_psoc_context *dp_ctx)
698 {
699 	struct dp_soc *soc = cdp_soc_t_to_dp_soc(dp_ctx->cdp_soc);
700 	QDF_STATUS status;
701 	struct dp_rx_fst *fst = dp_ctx->rx_fst;
702 
703 	/* Check if it is enabled in the INI */
704 	if (!dp_ctx->fisa_enable) {
705 		dp_err("RX FISA feature is disabled");
706 		return QDF_STATUS_E_NOSUPPORT;
707 	}
708 
709 	status = dp_rx_flow_send_fst_fw_setup(dp_ctx);
710 	if (QDF_IS_STATUS_ERROR(status)) {
711 		dp_err("dp_rx_flow_send_fst_fw_setup failed %d",
712 		       status);
713 		return status;
714 	}
715 
716 	if (dp_ctx->fst_cmem_base) {
717 		dp_ctx->fst_in_cmem = true;
718 		dp_rx_fst_update_cmem_params(soc, fst->max_entries,
719 					     dp_ctx->fst_cmem_base & 0xffffffff,
720 					     dp_ctx->fst_cmem_base >> 32);
721 	}
722 	return status;
723 }
724 
725 static uint8_t
dp_rx_fisa_get_max_aggr_supported(struct wlan_dp_psoc_context * dp_ctx)726 dp_rx_fisa_get_max_aggr_supported(struct wlan_dp_psoc_context *dp_ctx)
727 {
728 	if (!dp_ctx->fisa_dynamic_aggr_size_support)
729 		return DP_RX_FISA_MAX_AGGR_COUNT_DEFAULT;
730 
731 	switch (hal_get_target_type(dp_ctx->hal_soc)) {
732 	case TARGET_TYPE_WCN6450:
733 		return DP_RX_FISA_MAX_AGGR_COUNT_1;
734 	default:
735 		return DP_RX_FISA_MAX_AGGR_COUNT_DEFAULT;
736 	}
737 }
738 
739 #define FISA_MAX_TIMEOUT 0xffffffff
740 #define FISA_DISABLE_TIMEOUT 0
dp_rx_fisa_config(struct wlan_dp_psoc_context * dp_ctx)741 QDF_STATUS dp_rx_fisa_config(struct wlan_dp_psoc_context *dp_ctx)
742 {
743 	struct dp_htt_rx_fisa_cfg fisa_config;
744 	union cdp_fisa_config cfg;
745 
746 	fisa_config.pdev_id = 0;
747 	fisa_config.fisa_timeout = FISA_MAX_TIMEOUT;
748 	fisa_config.max_aggr_supported =
749 		dp_rx_fisa_get_max_aggr_supported(dp_ctx);
750 
751 	cfg.fisa_config = &fisa_config;
752 
753 	return cdp_txrx_fisa_config(dp_ctx->cdp_soc, OL_TXRX_PDEV_ID,
754 				    CDP_FISA_HTT_RX_FISA_CFG, &cfg);
755 }
756 
dp_fisa_cfg_init(struct wlan_dp_psoc_cfg * config,struct wlan_objmgr_psoc * psoc)757 void dp_fisa_cfg_init(struct wlan_dp_psoc_cfg *config,
758 		      struct wlan_objmgr_psoc *psoc)
759 {
760 	config->fisa_enable = cfg_get(psoc, CFG_DP_RX_FISA_ENABLE);
761 	config->is_rx_fisa_enabled = cfg_get(psoc, CFG_DP_RX_FISA_ENABLE);
762 	config->is_rx_fisa_lru_del_enabled =
763 				cfg_get(psoc, CFG_DP_RX_FISA_LRU_DEL_ENABLE);
764 }
765 #else /* WLAN_SUPPORT_RX_FISA */
766 
767 #endif /* !WLAN_SUPPORT_RX_FISA */
768 
769