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