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 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 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 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 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 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 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 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 */ 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 */ 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 */ 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 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 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 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 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 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 */ 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 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 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 */ 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 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 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 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 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 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 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