diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2016-06-24 03:39:32 -0600 |
|---|---|---|
| committer | Linux Build Service Account <lnxbuild@localhost> | 2016-06-24 03:39:33 -0600 |
| commit | 05e466a76f1864fe082aeb4751dc73ba79674440 (patch) | |
| tree | 7021691c0331ea9d001b0a3c5e10d339baa446b2 | |
| parent | da91b7eca039f863e4f133233ce32cb631597257 (diff) | |
| parent | 5a3b9b629935f3ab91080be0cea395ad9ca6c163 (diff) | |
Promotion of wlan-cld3.driver.lnx.1.1-00019.
CRs Change ID Subject
--------------------------------------------------------------------------------------------------------------
1022025 If37780ea64698ab616131a550cd877368c56faa6 qcacld-3.0: Fix issues in channel bonding APIs
1026747 I3190414ff32d8a75b07c2c311e257f4d388ef26d qcacld-3.0: Disable FEATURE_MEMDUMP in Kbuild
1013236 Ib85dffff39d0db69a695e8167b6a221b51ef7d45 qcacld-3.0: Enhance logging related to scan
1007004 I91363e90698cabda72028135eb7fe9adeb1fbc86 qcacld-3.0: Set wlan phy mode in OEM channel info respon
865207 I8023e8a4f9758d6003a3f666cc45c1e98265c01a qcacld-3.0: CL 1506155 – update fw common interface file
1027691 Ia8182b1deed1a6a1d2643f91660880fb52450e3d qcacld-3.0: Add context checking in epping_disable
975526 Ie66a83b6efe216df192b033c9d137a93fdce688f qcacld-3.0: Add htt apis for High Latency systems (Part
994562 Iaf4e15b4ebb7107d8bbf7a54e42f9ea9358dcdaf qcacld-3.0: Obtain channel params from CDS
975526 If1655d4d832f88e565ab946ef9e9719f256ab7b1 qcacld-3.0: Add txrx apis for High Latency systems (Part
865207 I2e6e837fade375ef86c0c4247490b44ec502be1b qcacld-3.0: CL 1507516 – update fw common interface file
865207 I0db10a599f4bbbdf23e5968fa5dab59b722efa30 qcacld-3.0: CL 1513397 – update fw common interface file
865207 I4acd731ec8850766d4d47715ff78b813281d0b6a qcacld-3.0: CL 1511668 – update fw common interface file
865207 I63ee1aeb2eba793e3a06c2632f43ea044ba33422 qcacld-3.0: CL 1509574 – update fw common interface file
975526 Ib380e10a0b343b6a8f9c2c0bf6d6dd602d2601c5 qcacld-3.0: Add wma apis for High Latency systems (Part
865207 Ie7c14aadf124a0aaaad1470e678e99f2fb5d436b qcacld-3.0: CL 1524393 – update fw common interface file
1023663 989842 I1d0813f70280618c0502db6e67233054726c3c17 qcacld-3.0: USB bus support (Corestack)
865207 I68367a8d688cdc9f85efe01a7c48856c8bab7220 qcacld-3.0: CL 1521398 – update fw common interface file
921847 I5aad1875262dd73878cc8393d09de1b23953d3a2 qcacld-3.0: Change struct of EVENT_WLAN_SECURITY diag ev
975526 Ic63e07abdabae9795bba6f76daa954235c894245 qcacld-3.0: Add hdd tx-rx apis for High Latency systems
688141 I84c2045bca3ae8775e6afbc1abeb6eec73488be7 Release 5.1.0.12
1023663 989842 Idb9fe1232d451e4f88a001fbd6591ba13b0c859a qcacld-3.0: Add USB bus support (CDS, Utils, SAP)
865207 I427fef8d8f2503c52d511fdae58fe410420e67a0 qcacld-3.0: CL 1522096 – update fw common interface file
1024437 I868300cba9326b0146d3afadc9fef6337877d58d qcacld-3.0: Fix out of bound memory copy in WMA
1014267 If0f8fb71413e0aeb5d355c5bbb1f0626a18b8d6f Revert "qcacld-3.0: 11ac 160MHZ support workaround"
865207 Ib7f2e5ed41c8ea889192814aed10e94e7ecf11e3 qcacld-3.0: CL 1517922 – update fw common interface file
865207 I0f591f9a620587ef77be09e3714c7156d4189172 qcacld-3.0: CL 1519524 – update fw common interface file
937687 I32c2bc3755b42693947a38808e510683b9477b44 qcacld-3.0: Convert wlan_hdd_stats.c to unified logging
865207 I86ed461a5d3d6d7f48e5ce2eb9370771a619d667 qcacld-3.0: CL 1509448 – update fw common interface file
865207 I90dc3218517e1a6b38fd7ded07c5ea17bc832b9b qcacld-3.0: CL 1515963 – update fw common interface file
1029203 Id725f2726e1caafe48c6b76d59a24f71ffa01af6 qcacld-3.0: Fix regression in the sched_scan interval va
1031927 I7e21a9199b42cdbc60c3207ecf9d705e0a151da8 qcacld-3.0: Remove redundant spam logs from BMI
865207 I3af426b0120e46e56bc0e2ff2831a471016d30e1 qcacld-3.0: Add place holder enums for new feature
1020982 I4e5ddcbd7e7b2b0141904410adb66f228dab0046 qcacld-3.0: Fix the regression in join failure processin
994443 Iea3de57c1b7d087442e4b8984b4184d24bb8c930 qcacld-3.0: Add support for adaptive dwell scan time
Change-Id: I5ba776d0d1cadae1fc4f2b39a53a164ff79d2798
CRs-Fixed: 975526, 989842, 1023663, 1026747, 1007004, 1027691, 1031927, 1020982, 688141, 1024437, 921847, 865207, 994562, 994443, 1022025, 937687, 1014267, 1029203, 1013236
104 files changed, 11459 insertions, 1274 deletions
@@ -138,7 +138,7 @@ ifeq ($(KERNEL_BUILD), 0) CONFIG_WLAN_SYNC_TSF := y #Flag to enable memdump feature - CONFIG_WLAN_FEATURE_MEMDUMP := y + CONFIG_WLAN_FEATURE_MEMDUMP := n #Flag to enable Fast Path feature CONFIG_WLAN_FASTPATH := y diff --git a/core/bmi/src/bmi_1.c b/core/bmi/src/bmi_1.c index e2c4a28df76b..9033d9dc1686 100644 --- a/core/bmi/src/bmi_1.c +++ b/core/bmi/src/bmi_1.c @@ -63,9 +63,6 @@ bmi_read_memory(uint32_t address, qdf_mem_set(bmi_rsp_buff, 0, BMI_DATASZ_MAX + sizeof(cid) + sizeof(address) + sizeof(length)); - BMI_DBG("BMI Read: device: 0x%p, address: 0x%x, length: %d", - scn, address, length); - cid = BMI_READ_MEMORY; align = 0; remaining = length; @@ -102,7 +99,6 @@ bmi_read_memory(uint32_t address, address += rxlen; } - BMI_DBG("BMI Read Memory: Exit"); return QDF_STATUS_SUCCESS; } @@ -135,9 +131,6 @@ QDF_STATUS bmi_write_memory(uint32_t address, uint8_t *buffer, uint32_t length, bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header)); qdf_mem_set(bmi_cmd_buff, 0, BMI_DATASZ_MAX + header); - BMI_DBG("BMI Write Memory:device: 0x%p, address: 0x%x, length: %d", - scn, address, length); - cid = BMI_WRITE_MEMORY; remaining = length; @@ -176,8 +169,6 @@ QDF_STATUS bmi_write_memory(uint32_t address, uint8_t *buffer, uint32_t length, address += txlen; } - BMI_DBG("BMI Write Memory: Exit"); - return QDF_STATUS_SUCCESS; } diff --git a/core/bmi/src/ol_fw.c b/core/bmi/src/ol_fw.c index 778b9dc681b4..ee7f9401fa5f 100644 --- a/core/bmi/src/ol_fw.c +++ b/core/bmi/src/ol_fw.c @@ -1565,6 +1565,39 @@ void ol_dump_target_memory(struct hif_opaque_softc *scn, void *memory_block) } } +#ifdef CONFIG_HL_SUPPORT + +/** + * ol_dump_ce_register() - cannot read the section + * @scn: ol_softc handler + * @memory_block: non-NULL reserved memory location + * + * Return: -EACCES for LL and not apllicable for HL + */ +static inline int +ol_dump_ce_register(struct hif_opaque_softc *scn, void *memory_block) +{ + return 0; +} +#else + +static int +ol_dump_ce_register(struct hif_opaque_softc *scn, void *memory_block) +{ + int ret; + + BMI_ERR("Could not read dump section!"); + + if (hif_dump_registers(scn)) + BMI_ERR("Failed to dump bus registers"); + + ol_dump_target_memory(scn, memory_block); + ret = -EACCES; + + return ret; +} +#endif + /** * ol_target_coredump() - API to collect target ramdump * @inst - private context @@ -1639,11 +1672,7 @@ static int ol_target_coredump(void *inst, void *memory_block, buffer_loc += result; section_count++; } else { - BMI_ERR("Could not read dump section!"); - if (hif_dump_registers(scn)) - BMI_ERR("Failed to dump bus registers"); - ol_dump_target_memory(scn, memory_block); - ret = -EACCES; + ret = ol_dump_ce_register(scn, memory_block); break; /* Could not read the section */ } } else { diff --git a/core/cds/inc/cds_regdomain.h b/core/cds/inc/cds_regdomain.h index 9fc4d744d63d..e2e5299c0b6f 100644 --- a/core/cds/inc/cds_regdomain.h +++ b/core/cds/inc/cds_regdomain.h @@ -583,9 +583,6 @@ int32_t cds_fill_some_regulatory_info(struct regulatory *reg); int32_t cds_get_country_from_alpha2(uint8_t *alpha2); void cds_fill_and_send_ctl_to_fw(struct regulatory *reg); void cds_set_wma_dfs_region(uint8_t dfs_region); - -void cds_set_ch_params(uint8_t ch, uint32_t phy_mode, - struct ch_params_s *ch_params); uint16_t cds_reg_dmn_get_opclass_from_channel(uint8_t *country, uint8_t channel, uint8_t offset); diff --git a/core/cds/src/cds_concurrency.c b/core/cds/src/cds_concurrency.c index e22010f273f5..ec9360ce10fb 100644 --- a/core/cds/src/cds_concurrency.c +++ b/core/cds/src/cds_concurrency.c @@ -6378,11 +6378,10 @@ QDF_STATUS cds_check_and_restart_sap(eCsrRoamResult roam_result, } hdd_ap_ctx->sapConfig.ch_params.ch_width = hdd_ap_ctx->sapConfig.ch_width_orig; - sme_set_ch_params(WLAN_HDD_GET_HAL_CTX(sap_adapter), - hdd_ap_ctx->sapConfig.SapHw_mode, - hdd_ap_ctx->operatingChannel, - hdd_ap_ctx->sapConfig.sec_ch, - &hdd_ap_ctx->sapConfig.ch_params); + + cds_set_channel_params(hdd_ap_ctx->operatingChannel, + hdd_ap_ctx->sapConfig.sec_ch, + &hdd_ap_ctx->sapConfig.ch_params); /* * Create a workqueue and let the workqueue handle the restart * of sap task. if we directly call sap restart function without @@ -6947,9 +6946,7 @@ static void cds_check_sta_ap_concurrent_ch_intf(void *data) hdd_ap_ctx->sapConfig.channel = intf_ch; hdd_ap_ctx->sapConfig.ch_params.ch_width = hdd_ap_ctx->sapConfig.ch_width_orig; - sme_set_ch_params(hal_handle, - hdd_ap_ctx->sapConfig.SapHw_mode, - hdd_ap_ctx->sapConfig.channel, + cds_set_channel_params(hdd_ap_ctx->sapConfig.channel, hdd_ap_ctx->sapConfig.sec_ch, &hdd_ap_ctx->sapConfig.ch_params); diff --git a/core/cds/src/cds_reg_service.c b/core/cds/src/cds_reg_service.c index 67886938a56c..9d9185738390 100644 --- a/core/cds/src/cds_reg_service.c +++ b/core/cds/src/cds_reg_service.c @@ -346,7 +346,7 @@ enum channel_state cds_get_2g_bonded_channel_state(uint16_t oper_ch, return CHANNEL_STATE_INVALID; if (CH_WIDTH_40MHZ == ch_width) { - if ((sec_ch + 4 != oper_ch) || + if ((sec_ch + 4 != oper_ch) && (oper_ch + 4 != sec_ch)) return CHANNEL_STATE_INVALID; chan_state2 = cds_get_channel_state(sec_ch); @@ -372,8 +372,8 @@ enum channel_state cds_get_2g_bonded_channel_state(uint16_t oper_ch, bw_enabled = !(reg_channels[chan_enum].flags & IEEE80211_CHAN_NO_20MHZ); else if (CH_WIDTH_40MHZ == ch_width) - bw_enabled = !(reg_channels[chan_enum].flags & - IEEE80211_CHAN_NO_HT40); + bw_enabled = !((reg_channels[chan_enum].flags & + IEEE80211_CHAN_NO_HT40) == IEEE80211_CHAN_NO_HT40); if (bw_enabled) return chan_state; @@ -417,8 +417,8 @@ enum channel_state cds_get_5g_bonded_channel_state( bw_enabled = !(reg_channels[chan_enum].flags & IEEE80211_CHAN_NO_20MHZ); else if (CH_WIDTH_40MHZ == ch_width) - bw_enabled = !(reg_channels[chan_enum].flags & - IEEE80211_CHAN_NO_HT40); + bw_enabled = !((reg_channels[chan_enum].flags & + IEEE80211_CHAN_NO_HT40) == IEEE80211_CHAN_NO_HT40); else if (CH_WIDTH_80MHZ == ch_width) bw_enabled = !(reg_channels[chan_enum].flags & IEEE80211_CHAN_NO_80MHZ); @@ -449,6 +449,7 @@ static void cds_set_5g_channel_params(uint16_t oper_ch, enum channel_state chan_state = CHANNEL_STATE_ENABLE; enum channel_state chan_state2 = CHANNEL_STATE_ENABLE; const struct bonded_chan *bonded_chan_ptr; + const struct bonded_chan *bonded_chan_ptr2; if (CH_WIDTH_MAX <= ch_params->ch_width) ch_params->ch_width = CH_WIDTH_80P80MHZ; @@ -470,21 +471,27 @@ static void cds_set_5g_channel_params(uint16_t oper_ch, chan_state = chan_state2; if ((CHANNEL_STATE_ENABLE == chan_state) || (CHANNEL_STATE_DFS == chan_state)) { - if (CH_WIDTH_20MHZ >= ch_params->ch_width) + if (CH_WIDTH_20MHZ >= ch_params->ch_width) { ch_params->sec_ch_offset = PHY_SINGLE_CHANNEL_CENTERED; - else if (CH_WIDTH_40MHZ == ch_params->ch_width) { - if (oper_ch == bonded_chan_ptr->start_ch) + ch_params->center_freq_seg0 = oper_ch; + } else if (CH_WIDTH_40MHZ <= ch_params->ch_width) { + cds_search_5g_bonded_chan_array(oper_ch, + bonded_chan_40mhz_array, + QDF_ARRAY_SIZE(bonded_chan_40mhz_array), + &bonded_chan_ptr2); + if (oper_ch == bonded_chan_ptr2->start_ch) ch_params->sec_ch_offset = PHY_DOUBLE_CHANNEL_LOW_PRIMARY; else ch_params->sec_ch_offset = PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + ch_params->center_freq_seg0 = + (bonded_chan_ptr2->start_ch + + bonded_chan_ptr2->end_ch)/2; + } - ch_params->center_freq_seg0 = - (bonded_chan_ptr->start_ch + - bonded_chan_ptr->end_ch)/2; break; } @@ -528,6 +535,8 @@ static void cds_set_2g_channel_params(uint16_t oper_ch, else ch_params->sec_ch_offset = PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + ch_params->center_freq_seg0 = + (oper_ch + sec_ch_2g)/2; } else ch_params->sec_ch_offset = PHY_SINGLE_CHANNEL_CENTERED; @@ -704,26 +713,3 @@ uint16_t cds_bw_value(enum phy_ch_width bw) } } -/** - * cds_set_ch_params() - set channel parameters - * @ch: channel - * @phy_mode: physical mode - * @ch_param: channel parameters will be returned - * - * Return: None - */ -void cds_set_ch_params(uint8_t ch, uint32_t phy_mode, - struct ch_params_s *ch_params) -{ - tHalHandle *hal_ctx = cds_get_context(QDF_MODULE_ID_PE); - if (!hal_ctx) { - QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, - ("Invalid hal_ctx pointer")); - return; - } - /* - * TODO: remove SME call and move the SME set channel - * param functionality to CDS. - */ - sme_set_ch_params(hal_ctx, phy_mode, ch, 0, ch_params); -} diff --git a/core/cds/src/cds_sched.c b/core/cds/src/cds_sched.c index a09163453d87..6dcd4b471995 100644 --- a/core/cds/src/cds_sched.c +++ b/core/cds/src/cds_sched.c @@ -462,7 +462,6 @@ static int cds_mc_thread(void *Arg) QDF_ASSERT(0); break; } - /* Need some optimization */ pMacContext = cds_get_context(QDF_MODULE_ID_PE); @@ -504,7 +503,6 @@ static int cds_mc_thread(void *Arg) QDF_ASSERT(0); break; } - /* Need some optimization */ pMacContext = cds_get_context(QDF_MODULE_ID_SME); diff --git a/core/dp/htt/htt.c b/core/dp/htt/htt.c index 68ca137aa1ea..0bb7b6122b5c 100644 --- a/core/dp/htt/htt.c +++ b/core/dp/htt/htt.c @@ -49,7 +49,7 @@ #define HTT_HTC_PKT_POOL_INIT_SIZE 100 /* enough for a large A-MPDU */ -A_STATUS(*htt_h2t_rx_ring_cfg_msg)(struct htt_pdev_t *pdev); +QDF_STATUS(*htt_h2t_rx_ring_cfg_msg)(struct htt_pdev_t *pdev); #ifdef IPA_OFFLOAD A_STATUS htt_ipa_config(htt_pdev_handle pdev, A_STATUS status) @@ -145,6 +145,125 @@ void htt_htc_misc_pkt_pool_free(struct htt_pdev_t *pdev) #define NO_HTT_NEEDED false #endif +#if defined(QCA_TX_HTT2_SUPPORT) && defined(CONFIG_HL_SUPPORT) + +/** + * htt_htc_tx_htt2_service_start() - Start TX HTT2 service + * + * @pdev: pointer to htt device. + * @connect_req: pointer to service connection request information + * @connect_resp: pointer to service connection response information + * + * + * Return: None + */ +static void +htt_htc_tx_htt2_service_start(struct htt_pdev_t *pdev, + HTC_SERVICE_CONNECT_REQ *connect_req, + HTC_SERVICE_CONNECT_RESP *connect_resp) +{ + A_STATUS status; + + qdf_mem_set(connect_req, 0, sizeof(HTC_SERVICE_CONNECT_REQ)); + qdf_mem_set(connect_resp, 0, sizeof(HTC_SERVICE_CONNECT_RESP)); + + /* The same as HTT service but no RX. */ + connect_req->EpCallbacks.pContext = pdev; + connect_req->EpCallbacks.EpTxComplete = htt_h2t_send_complete; + connect_req->EpCallbacks.EpSendFull = htt_h2t_full; + connect_req->MaxSendQueueDepth = HTT_MAX_SEND_QUEUE_DEPTH; + /* Should NOT support credit flow control. */ + connect_req->ConnectionFlags |= + HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL; + /* Enable HTC schedule mechanism for TX HTT2 service. */ + connect_req->ConnectionFlags |= HTC_CONNECT_FLAGS_ENABLE_HTC_SCHEDULE; + + connect_req->ServiceID = HTT_DATA2_MSG_SVC; + + status = htc_connect_service(pdev->htc_pdev, connect_req, connect_resp); + + if (status != A_OK) { + pdev->htc_tx_htt2_endpoint = ENDPOINT_UNUSED; + pdev->htc_tx_htt2_max_size = 0; + } else { + pdev->htc_tx_htt2_endpoint = connect_resp->Endpoint; + pdev->htc_tx_htt2_max_size = HTC_TX_HTT2_MAX_SIZE; + } + + qdf_print("TX HTT %s, ep %d size %d\n", + (status == A_OK ? "ON" : "OFF"), + pdev->htc_tx_htt2_endpoint, + pdev->htc_tx_htt2_max_size); +} +#else + +static inline void +htt_htc_tx_htt2_service_start(struct htt_pdev_t *pdev, + HTC_SERVICE_CONNECT_REQ *connect_req, + HTC_SERVICE_CONNECT_RESP *connect_resp) +{ + return; +} +#endif + +/** + * htt_htc_credit_flow_disable() - disable flow control for + * HTT data message service + * + * @pdev: pointer to htt device. + * @connect_req: pointer to service connection request information + * + * HTC Credit mechanism is disabled based on + * default_tx_comp_req as throughput will be lower + * if we disable htc credit mechanism with default_tx_comp_req + * set since txrx download packet will be limited by ota + * completion. + * + * Return: None + */ +static +void htt_htc_credit_flow_disable(struct htt_pdev_t *pdev, + HTC_SERVICE_CONNECT_REQ *connect_req) +{ + if (pdev->osdev->bus_type == QDF_BUS_TYPE_SDIO) { + /* + * TODO:Conditional disabling will be removed once firmware + * with reduced tx completion is pushed into release builds. + */ + if (!pdev->cfg.default_tx_comp_req) + connect_req->ConnectionFlags |= + HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL; + } else { + connect_req->ConnectionFlags |= + HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL; + } +} + +#if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) + +/** + * htt_dump_bundle_stats() - dump wlan stats + * @pdev: handle to the HTT instance + * + * Return: None + */ +void htt_dump_bundle_stats(htt_pdev_handle pdev) +{ + htc_dump_bundle_stats(pdev->htc_pdev); +} + +/** + * htt_clear_bundle_stats() - clear wlan stats + * @pdev: handle to the HTT instance + * + * Return: None + */ +void htt_clear_bundle_stats(htt_pdev_handle pdev) +{ + htc_clear_bundle_stats(pdev->htc_pdev); +} +#endif + /** * htt_pdev_alloc() - allocate HTT pdev * @txrx_pdev: txrx pdev @@ -179,6 +298,9 @@ htt_pdev_alloc(ol_txrx_pdev_handle txrx_pdev, #ifdef ATH_11AC_TXCOMPACT pdev->htt_htc_pkt_misclist = NULL; #endif + + /* for efficiency, store a local copy of the is_high_latency flag */ + pdev->cfg.is_high_latency = ol_cfg_is_high_latency(pdev->ctrl_pdev); pdev->cfg.default_tx_comp_req = !ol_cfg_tx_free_at_download(pdev->ctrl_pdev); @@ -192,6 +314,13 @@ htt_pdev_alloc(ol_txrx_pdev_handle txrx_pdev, qdf_print("ce_classify_enabled %d\n", pdev->cfg.ce_classify_enabled); + if (pdev->cfg.is_high_latency) { + qdf_atomic_init(&pdev->htt_tx_credit.target_delta); + qdf_atomic_init(&pdev->htt_tx_credit.bus_delta); + qdf_atomic_add(HTT_MAX_BUS_CREDIT, + &pdev->htt_tx_credit.bus_delta); + } + pdev->targetdef = htc_get_targetdef(htc_pdev); #if defined(HELIUMPLUS_PADDR64) /* TODO: OKA: Remove hard-coding */ @@ -241,7 +370,6 @@ int htt_attach(struct htt_pdev_t *pdev, int desc_pool_size) { int i; - enum wlan_frm_fmt frm_type; int ret = 0; ret = htt_tx_attach(pdev, desc_pool_size); @@ -264,65 +392,112 @@ htt_attach(struct htt_pdev_t *pdev, int desc_pool_size) htt_htc_pkt_free(pdev, &pkt->u.pkt); } - /* - * LL - download just the initial portion of the frame. - * Download enough to cover the encapsulation headers checked - * by the target's tx classification descriptor engine. - */ - - /* account for the 802.3 or 802.11 header */ - frm_type = ol_cfg_frame_type(pdev->ctrl_pdev); - if (frm_type == wlan_frm_fmt_native_wifi) { - pdev->download_len = HTT_TX_HDR_SIZE_NATIVE_WIFI; - } else if (frm_type == wlan_frm_fmt_802_3) { - pdev->download_len = HTT_TX_HDR_SIZE_ETHERNET; + if (pdev->cfg.is_high_latency) { + /* + * HL - download the whole frame. + * Specify a download length greater than the max MSDU size, + * so the downloads will be limited by the actual frame sizes. + */ + pdev->download_len = 5000; + + if (ol_cfg_tx_free_at_download(pdev->ctrl_pdev)) + pdev->tx_send_complete_part2 = + ol_tx_download_done_hl_free; + else + pdev->tx_send_complete_part2 = + ol_tx_download_done_hl_retain; + + /* + * CHECK THIS LATER: does the HL HTT version of + * htt_rx_mpdu_desc_list_next + * (which is not currently implemented) present the + * adf_nbuf_data(rx_ind_msg) + * as the abstract rx descriptor? + * If not, the rx_fw_desc_offset initialization + * here will have to be adjusted accordingly. + * NOTE: for HL, because fw rx desc is in ind msg, + * not in rx desc, so the + * offset should be negtive value + */ + pdev->rx_fw_desc_offset = + HTT_ENDIAN_BYTE_IDX_SWAP( + HTT_RX_IND_FW_RX_DESC_BYTE_OFFSET + - HTT_RX_IND_HL_BYTES); + + htt_h2t_rx_ring_cfg_msg = htt_h2t_rx_ring_cfg_msg_hl; + + /* initialize the txrx credit count */ + ol_tx_target_credit_update( + pdev->txrx_pdev, ol_cfg_target_tx_credit( + pdev->ctrl_pdev)); } else { - qdf_print("Unexpected frame type spec: %d\n", frm_type); - HTT_ASSERT0(0); - } - /* - * Account for the optional L2 / ethernet header fields: - * 802.1Q, LLC/SNAP - */ - pdev->download_len += - HTT_TX_HDR_SIZE_802_1Q + HTT_TX_HDR_SIZE_LLC_SNAP; - - /* - * Account for the portion of the L3 (IP) payload that the - * target needs for its tx classification. - */ - pdev->download_len += ol_cfg_tx_download_size(pdev->ctrl_pdev); - - /* - * Account for the HTT tx descriptor, including the - * HTC header + alignment padding. - */ - pdev->download_len += sizeof(struct htt_host_tx_desc_t); - - /* - * The TXCOMPACT htt_tx_sched function uses pdev->download_len - * to apply for all requeued tx frames. Thus, - * pdev->download_len has to be the largest download length of - * any tx frame that will be downloaded. - * This maximum download length is for management tx frames, - * which have an 802.11 header. - */ + enum wlan_frm_fmt frm_type; + + /* + * LL - download just the initial portion of the frame. + * Download enough to cover the encapsulation headers checked + * by the target's tx classification descriptor engine. + * + * For LL, the FW rx desc directly referenced at its location + * inside the rx indication message. + */ + + /* account for the 802.3 or 802.11 header */ + frm_type = ol_cfg_frame_type(pdev->ctrl_pdev); + + if (frm_type == wlan_frm_fmt_native_wifi) { + pdev->download_len = HTT_TX_HDR_SIZE_NATIVE_WIFI; + } else if (frm_type == wlan_frm_fmt_802_3) { + pdev->download_len = HTT_TX_HDR_SIZE_ETHERNET; + } else { + qdf_print("Unexpected frame type spec: %d\n", frm_type); + HTT_ASSERT0(0); + } + + /* + * Account for the optional L2 / ethernet header fields: + * 802.1Q, LLC/SNAP + */ + pdev->download_len += + HTT_TX_HDR_SIZE_802_1Q + HTT_TX_HDR_SIZE_LLC_SNAP; + + /* + * Account for the portion of the L3 (IP) payload that the + * target needs for its tx classification. + */ + pdev->download_len += ol_cfg_tx_download_size(pdev->ctrl_pdev); + + /* + * Account for the HTT tx descriptor, including the + * HTC header + alignment padding. + */ + pdev->download_len += sizeof(struct htt_host_tx_desc_t); + + /* + * The TXCOMPACT htt_tx_sched function uses pdev->download_len + * to apply for all requeued tx frames. Thus, + * pdev->download_len has to be the largest download length of + * any tx frame that will be downloaded. + * This maximum download length is for management tx frames, + * which have an 802.11 header. + */ #ifdef ATH_11AC_TXCOMPACT - pdev->download_len = sizeof(struct htt_host_tx_desc_t) - + HTT_TX_HDR_SIZE_OUTER_HDR_MAX /* worst case */ - + HTT_TX_HDR_SIZE_802_1Q - + HTT_TX_HDR_SIZE_LLC_SNAP - + ol_cfg_tx_download_size(pdev->ctrl_pdev); + pdev->download_len = sizeof(struct htt_host_tx_desc_t) + + HTT_TX_HDR_SIZE_OUTER_HDR_MAX /* worst case */ + + HTT_TX_HDR_SIZE_802_1Q + + HTT_TX_HDR_SIZE_LLC_SNAP + + ol_cfg_tx_download_size(pdev->ctrl_pdev); #endif - pdev->tx_send_complete_part2 = ol_tx_download_done_ll; + pdev->tx_send_complete_part2 = ol_tx_download_done_ll; - /* - * For LL, the FW rx desc is alongside the HW rx desc fields in - * the htt_host_rx_desc_base struct/. - */ - pdev->rx_fw_desc_offset = RX_STD_DESC_FW_MSDU_OFFSET; + /* + * For LL, the FW rx desc is alongside the HW rx desc fields in + * the htt_host_rx_desc_base struct/. + */ + pdev->rx_fw_desc_offset = RX_STD_DESC_FW_MSDU_OFFSET; - htt_h2t_rx_ring_cfg_msg = htt_h2t_rx_ring_cfg_msg_ll; + htt_h2t_rx_ring_cfg_msg = htt_h2t_rx_ring_cfg_msg_ll; + } return 0; @@ -459,9 +634,7 @@ int htt_htc_attach(struct htt_pdev_t *pdev, uint16_t service_id) connect.MaxSendQueueDepth = HTT_MAX_SEND_QUEUE_DEPTH; /* disable flow control for HTT data message service */ -#ifndef HIF_SDIO - connect.ConnectionFlags |= HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL; -#endif + htt_htc_credit_flow_disable(pdev, &connect); /* connect to control service */ connect.service_id = service_id; @@ -473,6 +646,9 @@ int htt_htc_attach(struct htt_pdev_t *pdev, uint16_t service_id) htt_update_endpoint(pdev, service_id, response.Endpoint); + /* Start TX HTT2 service if the target support it. */ + htt_htc_tx_htt2_service_start(pdev, &connect, &response); + return 0; /* success */ } diff --git a/core/dp/htt/htt_h2t.c b/core/dp/htt/htt_h2t.c index c7aeb9f70006..f52c06403fdc 100644 --- a/core/dp/htt/htt_h2t.c +++ b/core/dp/htt/htt_h2t.c @@ -86,6 +86,18 @@ void htt_h2t_send_complete(void *context, HTC_PACKET *htc_pkt) send_complete_part2(htt_pkt->pdev_ctxt, htc_pkt->Status, netbuf, htt_pkt->msdu_id); } + + if (pdev->cfg.is_high_latency && !pdev->cfg.default_tx_comp_req) { + int32_t credit_delta; + + qdf_atomic_add(1, &pdev->htt_tx_credit.bus_delta); + credit_delta = htt_tx_credit_update(pdev); + + if (credit_delta) + ol_tx_credit_completion_handler(pdev->txrx_pdev, + credit_delta); + } + /* free the htt_htc_pkt / HTC_PACKET object */ htt_htc_pkt_free(pdev, htt_pkt); } @@ -194,11 +206,21 @@ A_STATUS htt_h2t_ver_req_msg(struct htt_pdev_t *pdev) struct htt_htc_pkt *pkt; qdf_nbuf_t msg; uint32_t *msg_word; + uint32_t msg_size; + uint32_t max_tx_group; pkt = htt_htc_pkt_alloc(pdev); if (!pkt) return A_ERROR; /* failure */ + max_tx_group = ol_tx_get_max_tx_groups_supported(pdev->txrx_pdev); + + if (max_tx_group) + msg_size = HTT_VER_REQ_BYTES + + sizeof(struct htt_option_tlv_mac_tx_queue_groups_t); + else + msg_size = HTT_VER_REQ_BYTES; + /* show that this is not a tx frame download * (not required, but helpful) */ @@ -206,7 +228,7 @@ A_STATUS htt_h2t_ver_req_msg(struct htt_pdev_t *pdev) pkt->pdev_ctxt = NULL; /* not used during send-done callback */ /* reserve room for the HTC header */ - msg = qdf_nbuf_alloc(pdev->osdev, HTT_MSG_BUF_SIZE(HTT_VER_REQ_BYTES), + msg = qdf_nbuf_alloc(pdev->osdev, HTT_MSG_BUF_SIZE(msg_size), HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, true); if (!msg) { @@ -220,7 +242,7 @@ A_STATUS htt_h2t_ver_req_msg(struct htt_pdev_t *pdev) * separately during the below call to qdf_nbuf_push_head. * The contribution from the HTC header is added separately inside HTC. */ - qdf_nbuf_put_tail(msg, HTT_VER_REQ_BYTES); + qdf_nbuf_put_tail(msg, msg_size); /* fill in the message contents */ msg_word = (uint32_t *) qdf_nbuf_data(msg); @@ -231,6 +253,18 @@ A_STATUS htt_h2t_ver_req_msg(struct htt_pdev_t *pdev) *msg_word = 0; HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_VERSION_REQ); + if (max_tx_group) { + *(msg_word + 1) = 0; + + /* Fill Group Info */ + HTT_OPTION_TLV_TAG_SET(*(msg_word+1), + HTT_OPTION_TLV_TAG_MAX_TX_QUEUE_GROUPS); + HTT_OPTION_TLV_LENGTH_SET(*(msg_word+1), + (sizeof(struct htt_option_tlv_mac_tx_queue_groups_t)/ + sizeof(uint32_t))); + HTT_OPTION_TLV_VALUE0_SET(*(msg_word+1), max_tx_group); + } + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, htt_h2t_send_complete_free_netbuf, qdf_nbuf_data(msg), qdf_nbuf_len(msg), @@ -246,10 +280,14 @@ A_STATUS htt_h2t_ver_req_msg(struct htt_pdev_t *pdev) htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); #endif + if ((pdev->cfg.is_high_latency) && + (!pdev->cfg.default_tx_comp_req)) + ol_tx_target_credit_update(pdev->txrx_pdev, -1); + return A_OK; } -A_STATUS htt_h2t_rx_ring_cfg_msg_ll(struct htt_pdev_t *pdev) +QDF_STATUS htt_h2t_rx_ring_cfg_msg_ll(struct htt_pdev_t *pdev) { struct htt_htc_pkt *pkt; qdf_nbuf_t msg; @@ -445,6 +483,148 @@ A_STATUS htt_h2t_rx_ring_cfg_msg_ll(struct htt_pdev_t *pdev) return A_OK; } +QDF_STATUS +htt_h2t_rx_ring_cfg_msg_hl(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + u_int32_t *msg_word; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return A_ERROR; /* failure */ + + /* show that this is not a tx frame download + * (not required, but helpful) */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + msg = qdf_nbuf_alloc( + pdev->osdev, + HTT_MSG_BUF_SIZE(HTT_RX_RING_CFG_BYTES(1)), + /* reserve room for the HTC header */ + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, true); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return A_ERROR; /* failure */ + } + /* + * Set the length of the message. + * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added + * separately during the below call to adf_nbuf_push_head. + * The contribution from the HTC header is added separately inside HTC. + */ + qdf_nbuf_put_tail(msg, HTT_RX_RING_CFG_BYTES(1)); + + /* fill in the message contents */ + msg_word = (u_int32_t *)qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_RX_RING_CFG); + HTT_RX_RING_CFG_NUM_RINGS_SET(*msg_word, 1); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_SET( + *msg_word, pdev->rx_ring.alloc_idx.paddr); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_BASE_PADDR_SET(*msg_word, pdev->rx_ring.base_paddr); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_LEN_SET(*msg_word, pdev->rx_ring.size); + HTT_RX_RING_CFG_BUF_SZ_SET(*msg_word, HTT_RX_BUF_SIZE); + + /* FIX THIS: if the FW creates a complete translated rx descriptor, + * then the MAC DMA of the HW rx descriptor should be disabled. */ + msg_word++; + *msg_word = 0; + + HTT_RX_RING_CFG_ENABLED_802_11_HDR_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_PPDU_START_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_PPDU_END_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_MPDU_START_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_MPDU_END_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_MSDU_START_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_MSDU_END_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_RX_ATTN_SET(*msg_word, 0); + /* always present? */ + HTT_RX_RING_CFG_ENABLED_FRAG_INFO_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_UCAST_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_MCAST_SET(*msg_word, 1); + /* Must change to dynamic enable at run time + * rather than at compile time + */ + HTT_RX_RING_CFG_ENABLED_CTRL_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_MGMT_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_NULL_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_PHY_SET(*msg_word, 0); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_802_11_HDR_SET(*msg_word, + 0); + HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD_SET(*msg_word, + 0); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_PPDU_START_SET(*msg_word, + 0); + HTT_RX_RING_CFG_OFFSET_PPDU_END_SET(*msg_word, + 0); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_MPDU_START_SET(*msg_word, + 0); + HTT_RX_RING_CFG_OFFSET_MPDU_END_SET(*msg_word, + 0); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_MSDU_START_SET(*msg_word, + 0); + HTT_RX_RING_CFG_OFFSET_MSDU_END_SET(*msg_word, + 0); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_RX_ATTN_SET(*msg_word, + 0); + HTT_RX_RING_CFG_OFFSET_FRAG_INFO_SET(*msg_word, + 0); + + SET_HTC_PACKET_INFO_TX( + &pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + +#ifdef ATH_11AC_TXCOMPACT + if (htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt) == A_OK) + htt_htc_misc_pkt_list_add(pdev, pkt); +#else + htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); +#endif + + if ((pdev->cfg.is_high_latency) && + (!pdev->cfg.default_tx_comp_req)) + ol_tx_target_credit_update(pdev->txrx_pdev, -1); + + return QDF_STATUS_SUCCESS; +} + int htt_h2t_dbg_stats_get(struct htt_pdev_t *pdev, uint32_t stats_type_upload_mask, @@ -533,6 +713,10 @@ htt_h2t_dbg_stats_get(struct htt_pdev_t *pdev, htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); #endif + if ((pdev->cfg.is_high_latency) && + (!pdev->cfg.default_tx_comp_req)) + ol_tx_target_credit_update(pdev->txrx_pdev, -1); + return 0; } @@ -589,6 +773,10 @@ A_STATUS htt_h2t_sync_msg(struct htt_pdev_t *pdev, uint8_t sync_cnt) htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); #endif + if ((pdev->cfg.is_high_latency) && + (!pdev->cfg.default_tx_comp_req)) + ol_tx_target_credit_update(pdev->txrx_pdev, -1); + return A_OK; } @@ -656,6 +844,10 @@ htt_h2t_aggr_cfg_msg(struct htt_pdev_t *pdev, htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); #endif + if ((pdev->cfg.is_high_latency) && + (!pdev->cfg.default_tx_comp_req)) + ol_tx_target_credit_update(pdev->txrx_pdev, -1); + return 0; } diff --git a/core/dp/htt/htt_internal.h b/core/dp/htt/htt_internal.h index da26fb641201..98b129c4efb6 100644 --- a/core/dp/htt/htt_internal.h +++ b/core/dp/htt/htt_internal.h @@ -420,7 +420,17 @@ static inline void htt_print_rx_desc(struct htt_host_rx_desc_base *rx_desc) #endif +#ifdef CONFIG_HL_SUPPORT + +static inline void htt_tx_resume_handler(void *context) +{ + return; +} +#else + void htt_tx_resume_handler(void *); +#endif + #ifdef ATH_11AC_TXCOMPACT #define HTT_TX_SCHED htt_tx_sched #else @@ -433,7 +443,16 @@ void htt_tx_detach(struct htt_pdev_t *pdev); int htt_rx_attach(struct htt_pdev_t *pdev); +#if defined(CONFIG_HL_SUPPORT) + +static inline void htt_rx_detach(struct htt_pdev_t *pdev) +{ + return; +} +#else + void htt_rx_detach(struct htt_pdev_t *pdev); +#endif int htt_htc_attach(struct htt_pdev_t *pdev, uint16_t service_id); @@ -458,8 +477,11 @@ A_STATUS htt_h2t_frag_desc_bank_cfg_msg(struct htt_pdev_t *pdev); #endif /* defined(HELIUMPLUS_PADDR64) */ -extern A_STATUS htt_h2t_rx_ring_cfg_msg_ll(struct htt_pdev_t *pdev); -extern A_STATUS (*htt_h2t_rx_ring_cfg_msg)(struct htt_pdev_t *pdev); +extern QDF_STATUS htt_h2t_rx_ring_cfg_msg_ll(struct htt_pdev_t *pdev); + +extern QDF_STATUS htt_h2t_rx_ring_cfg_msg_hl(struct htt_pdev_t *pdev); + +extern QDF_STATUS (*htt_h2t_rx_ring_cfg_msg)(struct htt_pdev_t *pdev); HTC_SEND_FULL_ACTION htt_h2t_full(void *context, HTC_PACKET *pkt); @@ -538,6 +560,44 @@ static inline int htt_rx_ipa_uc_detach(struct htt_pdev_t *pdev) } #endif /* IPA_OFFLOAD */ +/* Maximum Outstanding Bus Download */ +#define HTT_MAX_BUS_CREDIT 33 + +#ifdef CONFIG_HL_SUPPORT + +/** + * htt_tx_credit_update() - check for diff in bus delta and target delta + * @pdev: pointer to htt device. + * + * Return: min of bus delta and target delta + */ +int +htt_tx_credit_update(struct htt_pdev_t *pdev); +#else + +static inline int +htt_tx_credit_update(struct htt_pdev_t *pdev) +{ + return 0; +} +#endif + + +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +#define HTT_TX_GROUP_INDEX_OFFSET \ +(sizeof(struct htt_txq_group) / sizeof(u_int32_t)) + +void htt_tx_group_credit_process(struct htt_pdev_t *pdev, u_int32_t *msg_word); +#else + +static inline +void htt_tx_group_credit_process(struct htt_pdev_t *pdev, u_int32_t *msg_word) +{ + return; +} +#endif + #ifdef DEBUG_RX_RING_BUFFER /** * htt_rx_dbg_rxbuf_init() - init debug rx buff list diff --git a/core/dp/htt/htt_rx.c b/core/dp/htt/htt_rx.c index cebdc2e7fec3..0a1d82983175 100644 --- a/core/dp/htt/htt_rx.c +++ b/core/dp/htt/htt_rx.c @@ -55,7 +55,7 @@ #include <cds_ieee80211_defines.h> /* ieee80211_rx_status */ #include <cds_utils.h> #include <cds_concurrency.h> - +#include "ol_txrx_types.h" #ifdef DEBUG_DMA_DONE #include <asm/barrier.h> #include <wma_api.h> @@ -159,6 +159,169 @@ void htt_rx_hash_deinit(struct htt_pdev_t *pdev) pdev->rx_ring.hash_table = NULL; } +/* + * This function is used both below within this file (which the compiler + * will hopefully inline), and out-line from other files via the + * htt_rx_msdu_first_msdu_flag function pointer. + */ + +static inline bool +htt_rx_msdu_first_msdu_flag_hl(htt_pdev_handle pdev, void *msdu_desc) +{ + return ((u_int8_t *)msdu_desc - sizeof(struct hl_htt_rx_ind_base)) + [HTT_ENDIAN_BYTE_IDX_SWAP(HTT_RX_IND_HL_FLAG_OFFSET)] & + HTT_RX_IND_HL_FLAG_FIRST_MSDU ? true : false; +} + +u_int16_t +htt_rx_msdu_rx_desc_size_hl( + htt_pdev_handle pdev, + void *msdu_desc + ) +{ + return ((u_int8_t *)(msdu_desc) - HTT_RX_IND_HL_BYTES) + [HTT_ENDIAN_BYTE_IDX_SWAP(HTT_RX_IND_HL_RX_DESC_LEN_OFFSET)]; +} + +/** + * htt_rx_mpdu_desc_retry_hl() - Returns the retry bit from the Rx descriptor + * for the High Latency driver + * @pdev: Handle (pointer) to HTT pdev. + * @mpdu_desc: Void pointer to the Rx descriptor for MPDU + * before the beginning of the payload. + * + * This function returns the retry bit of the 802.11 header for the + * provided rx MPDU descriptor. For the high latency driver, this function + * pretends as if the retry bit is never set so that the mcast duplicate + * detection never fails. + * + * Return: boolean -- false always for HL + */ +static inline bool +htt_rx_mpdu_desc_retry_hl(htt_pdev_handle pdev, void *mpdu_desc) +{ + return false; +} + +#ifdef CONFIG_HL_SUPPORT +u_int16_t +htt_rx_mpdu_desc_seq_num_hl(htt_pdev_handle pdev, void *mpdu_desc) +{ + if (pdev->rx_desc_size_hl) { + return pdev->cur_seq_num_hl = + (u_int16_t)(HTT_WORD_GET(*(u_int32_t *)mpdu_desc, + HTT_HL_RX_DESC_MPDU_SEQ_NUM)); + } else { + return (u_int16_t)(pdev->cur_seq_num_hl); + } +} +#endif + +void +htt_rx_mpdu_desc_pn_hl( + htt_pdev_handle pdev, + void *mpdu_desc, + union htt_rx_pn_t *pn, + int pn_len_bits) +{ + if (htt_rx_msdu_first_msdu_flag_hl(pdev, mpdu_desc) == true) { + /* Fix Me: only for little endian */ + struct hl_htt_rx_desc_base *rx_desc = + (struct hl_htt_rx_desc_base *)mpdu_desc; + u_int32_t *word_ptr = (u_int32_t *)pn->pn128; + + /* TODO: for Host of big endian */ + switch (pn_len_bits) { + case 128: + /* bits 128:64 */ + *(word_ptr + 3) = rx_desc->pn_127_96; + /* bits 63:0 */ + *(word_ptr + 2) = rx_desc->pn_95_64; + case 48: + /* bits 48:0 + * copy 64 bits + */ + *(word_ptr + 1) = rx_desc->u0.pn_63_32; + case 24: + /* bits 23:0 + * copy 32 bits + */ + *(word_ptr + 0) = rx_desc->pn_31_0; + break; + default: + qdf_print( + "Error: invalid length spec (%d bits) for PN\n", + pn_len_bits); + qdf_assert(0); + break; + }; + } else { + /* not first msdu, no pn info */ + qdf_print( + "Error: get pn from a not-first msdu.\n"); + qdf_assert(0); + } +} + +/** + * htt_rx_mpdu_desc_tid_hl() - Returns the TID value from the Rx descriptor + * for High Latency driver + * @pdev: Handle (pointer) to HTT pdev. + * @mpdu_desc: Void pointer to the Rx descriptor for the MPDU + * before the beginning of the payload. + * + * This function returns the TID set in the 802.11 QoS Control for the MPDU + * in the packet header, by looking at the mpdu_start of the Rx descriptor. + * Rx descriptor gets a copy of the TID from the MAC. + * For the HL driver, this is currently uimplemented and always returns + * an invalid tid. It is the responsibility of the caller to make + * sure that return value is checked for valid range. + * + * Return: Invalid TID value (0xff) for HL driver. + */ +static inline uint8_t +htt_rx_mpdu_desc_tid_hl(htt_pdev_handle pdev, void *mpdu_desc) +{ + return 0xff; /* Invalid TID */ +} + +static inline bool +htt_rx_msdu_desc_completes_mpdu_hl(htt_pdev_handle pdev, void *msdu_desc) +{ + return ( + ((u_int8_t *)(msdu_desc) - sizeof(struct hl_htt_rx_ind_base)) + [HTT_ENDIAN_BYTE_IDX_SWAP(HTT_RX_IND_HL_FLAG_OFFSET)] + & HTT_RX_IND_HL_FLAG_LAST_MSDU) + ? true : false; +} + +static inline int +htt_rx_msdu_has_wlan_mcast_flag_hl(htt_pdev_handle pdev, void *msdu_desc) +{ + /* currently, only first msdu has hl rx_desc */ + return htt_rx_msdu_first_msdu_flag_hl(pdev, msdu_desc) == true; +} + +static inline bool +htt_rx_msdu_is_wlan_mcast_hl(htt_pdev_handle pdev, void *msdu_desc) +{ + struct hl_htt_rx_desc_base *rx_desc = + (struct hl_htt_rx_desc_base *)msdu_desc; + + return + HTT_WORD_GET(*(u_int32_t *)rx_desc, HTT_HL_RX_DESC_MCAST_BCAST); +} + +static inline int +htt_rx_msdu_is_frag_hl(htt_pdev_handle pdev, void *msdu_desc) +{ + struct hl_htt_rx_desc_base *rx_desc = + (struct hl_htt_rx_desc_base *)msdu_desc; + + return + HTT_WORD_GET(*(u_int32_t *)rx_desc, HTT_HL_RX_DESC_MCAST_BCAST); +} + static bool htt_rx_msdu_first_msdu_flag_ll(htt_pdev_handle pdev, void *msdu_desc) { @@ -170,6 +333,8 @@ htt_rx_msdu_first_msdu_flag_ll(htt_pdev_handle pdev, void *msdu_desc) RX_MSDU_END_4_FIRST_MSDU_LSB); } +#ifndef CONFIG_HL_SUPPORT + static int htt_rx_ring_size(struct htt_pdev_t *pdev) { int size; @@ -231,6 +396,7 @@ static void htt_rx_ring_refill_retry(void *arg) htt_pdev_handle pdev = (htt_pdev_handle) arg; htt_rx_msdu_buff_replenish(pdev); } +#endif void htt_rx_ring_fill_n(struct htt_pdev_t *pdev, int num) { @@ -351,6 +517,8 @@ unsigned int htt_rx_in_order_ring_elems(struct htt_pdev_t *pdev) pdev->rx_ring.size_mask; } +#ifndef CONFIG_HL_SUPPORT + void htt_rx_detach(struct htt_pdev_t *pdev) { qdf_timer_stop(&pdev->rx_ring.refill_retry_timer); @@ -404,6 +572,7 @@ void htt_rx_detach(struct htt_pdev_t *pdev) qdf_get_dma_mem_context((&pdev->rx_ring.buf), memctx)); } +#endif /*--- rx descriptor field access functions ----------------------------------*/ /* @@ -719,8 +888,74 @@ htt_set_checksum_result_ll(htt_pdev_handle pdev, qdf_nbuf_t msdu, #undef MAX_IP_VER #undef MAX_PROTO_VAL } + +#if defined(CONFIG_HL_SUPPORT) + +static void +htt_set_checksum_result_hl(qdf_nbuf_t msdu, + struct htt_host_rx_desc_base *rx_desc) +{ + u_int8_t flag = ((u_int8_t *)rx_desc - + sizeof(struct hl_htt_rx_ind_base))[ + HTT_ENDIAN_BYTE_IDX_SWAP( + HTT_RX_IND_HL_FLAG_OFFSET)]; + + int is_ipv6 = flag & HTT_RX_IND_HL_FLAG_IPV6 ? 1 : 0; + int is_tcp = flag & HTT_RX_IND_HL_FLAG_TCP ? 1 : 0; + int is_udp = flag & HTT_RX_IND_HL_FLAG_UDP ? 1 : 0; + + qdf_nbuf_rx_cksum_t cksum = { + QDF_NBUF_RX_CKSUM_NONE, + QDF_NBUF_RX_CKSUM_NONE, + 0 + }; + + switch ((is_udp << 2) | (is_tcp << 1) | (is_ipv6 << 0)) { + case 0x4: + cksum.l4_type = QDF_NBUF_RX_CKSUM_UDP; + break; + case 0x2: + cksum.l4_type = QDF_NBUF_RX_CKSUM_TCP; + break; + case 0x5: + cksum.l4_type = QDF_NBUF_RX_CKSUM_UDPIPV6; + break; + case 0x3: + cksum.l4_type = QDF_NBUF_RX_CKSUM_TCPIPV6; + break; + default: + cksum.l4_type = QDF_NBUF_RX_CKSUM_NONE; + break; + } + if (cksum.l4_type != (qdf_nbuf_l4_rx_cksum_type_t) + QDF_NBUF_RX_CKSUM_NONE) { + cksum.l4_result = flag & HTT_RX_IND_HL_FLAG_C4_FAILED ? + QDF_NBUF_RX_CKSUM_NONE : + QDF_NBUF_RX_CKSUM_TCP_UDP_UNNECESSARY; + } + qdf_nbuf_set_rx_cksum(msdu, &cksum); +} +#endif + #else -#define htt_set_checksum_result_ll(pdev, msdu, rx_desc) /* no-op */ + +static inline +void htt_set_checksum_result_ll(htt_pdev_handle pdev, qdf_nbuf_t msdu, + struct htt_host_rx_desc_base *rx_desc) +{ + return; +} + +#if defined(CONFIG_HL_SUPPORT) + +static inline +void htt_set_checksum_result_hl(qdf_nbuf_t msdu, + struct htt_host_rx_desc_base *rx_desc) +{ + return; +} +#endif + #endif #ifdef DEBUG_DMA_DONE @@ -1074,6 +1309,70 @@ htt_rx_amsdu_pop_ll(htt_pdev_handle pdev, return msdu_chaining; } +#if defined(CONFIG_HL_SUPPORT) + +static int +htt_rx_amsdu_pop_hl( + htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + qdf_nbuf_t *head_msdu, + qdf_nbuf_t *tail_msdu) +{ + pdev->rx_desc_size_hl = + (qdf_nbuf_data(rx_ind_msg)) + [HTT_ENDIAN_BYTE_IDX_SWAP( + HTT_RX_IND_HL_RX_DESC_LEN_OFFSET)]; + + /* point to the rx desc */ + qdf_nbuf_pull_head(rx_ind_msg, + sizeof(struct hl_htt_rx_ind_base)); + *head_msdu = *tail_msdu = rx_ind_msg; + + htt_set_checksum_result_hl(rx_ind_msg, + (struct htt_host_rx_desc_base *) + (qdf_nbuf_data(rx_ind_msg))); + + qdf_nbuf_set_next(*tail_msdu, NULL); + return 0; +} + +static int +htt_rx_frag_pop_hl( + htt_pdev_handle pdev, + qdf_nbuf_t frag_msg, + qdf_nbuf_t *head_msdu, + qdf_nbuf_t *tail_msdu) +{ + qdf_nbuf_pull_head(frag_msg, HTT_RX_FRAG_IND_BYTES); + pdev->rx_desc_size_hl = + (qdf_nbuf_data(frag_msg)) + [HTT_ENDIAN_BYTE_IDX_SWAP( + HTT_RX_IND_HL_RX_DESC_LEN_OFFSET)]; + + /* point to the rx desc */ + qdf_nbuf_pull_head(frag_msg, + sizeof(struct hl_htt_rx_ind_base)); + *head_msdu = *tail_msdu = frag_msg; + + qdf_nbuf_set_next(*tail_msdu, NULL); + return 0; +} + +static inline int +htt_rx_offload_msdu_pop_hl(htt_pdev_handle pdev, + qdf_nbuf_t offload_deliver_msg, + int *vdev_id, + int *peer_id, + int *tid, + u_int8_t *fw_desc, + qdf_nbuf_t *head_buf, + qdf_nbuf_t *tail_buf) +{ + return 0; +} + +#endif + int htt_rx_offload_msdu_pop_ll(htt_pdev_handle pdev, qdf_nbuf_t offload_deliver_msg, @@ -2260,6 +2559,152 @@ void *htt_rx_in_ord_mpdu_desc_list_next_ll(htt_pdev_handle pdev, return (void *)htt_rx_desc(netbuf); } +#if defined(CONFIG_HL_SUPPORT) + +/** + * htt_rx_mpdu_desc_list_next_hl() - provides an abstract way to obtain + * the next MPDU descriptor + * @pdev: the HTT instance the rx data was received on + * @rx_ind_msg: the netbuf containing the rx indication message + * + * for HL, the returned value is not mpdu_desc, + * it's translated hl_rx_desc just after the hl_ind_msg + * for HL AMSDU, we can't point to payload now, because + * hl rx desc is not fixed, we can't retrive the desc + * by minus rx_desc_size when release. keep point to hl rx desc + * now + * + * Return: next abstract rx descriptor from the series of MPDUs + * referenced by an rx ind msg + */ +static inline void * +htt_rx_mpdu_desc_list_next_hl(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg) +{ + void *mpdu_desc = (void *)qdf_nbuf_data(rx_ind_msg); + return mpdu_desc; +} + +/** + * htt_rx_msdu_desc_retrieve_hl() - Retrieve a previously-stored rx descriptor + * from a MSDU buffer + * @pdev: the HTT instance the rx data was received on + * @msdu - the buffer containing the MSDU payload + * + * currently for HL AMSDU, we don't point to payload. + * we shift to payload in ol_rx_deliver later + * + * Return: the corresponding abstract rx MSDU descriptor + */ +static inline void * +htt_rx_msdu_desc_retrieve_hl(htt_pdev_handle pdev, qdf_nbuf_t msdu) +{ + return qdf_nbuf_data(msdu); +} + +static +bool htt_rx_mpdu_is_encrypted_hl(htt_pdev_handle pdev, void *mpdu_desc) +{ + if (htt_rx_msdu_first_msdu_flag_hl(pdev, mpdu_desc) == true) { + /* Fix Me: only for little endian */ + struct hl_htt_rx_desc_base *rx_desc = + (struct hl_htt_rx_desc_base *)mpdu_desc; + + return HTT_WORD_GET(*(u_int32_t *)rx_desc, + HTT_HL_RX_DESC_MPDU_ENC); + } else { + /* not first msdu, no encrypt info for hl */ + qdf_print( + "Error: get encrypted from a not-first msdu.\n"); + qdf_assert(0); + return false; + } +} + +static inline bool +htt_rx_msdu_chan_info_present_hl(htt_pdev_handle pdev, void *mpdu_desc) +{ + if (htt_rx_msdu_first_msdu_flag_hl(pdev, mpdu_desc) == true && + HTT_WORD_GET(*(u_int32_t *)mpdu_desc, + HTT_HL_RX_DESC_CHAN_INFO_PRESENT)) + return true; + + return false; +} + +static bool +htt_rx_msdu_center_freq_hl(htt_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + void *mpdu_desc, + uint16_t *primary_chan_center_freq_mhz, + uint16_t *contig_chan1_center_freq_mhz, + uint16_t *contig_chan2_center_freq_mhz, + uint8_t *phy_mode) +{ + int pn_len, index; + uint32_t *chan_info; + + index = htt_rx_msdu_is_wlan_mcast(pdev, mpdu_desc) ? + txrx_sec_mcast : txrx_sec_ucast; + + pn_len = (peer ? + pdev->txrx_pdev->rx_pn[peer->security[index].sec_type]. + len : 0); + chan_info = (uint32_t *)((uint8_t *)mpdu_desc + + HTT_HL_RX_DESC_PN_OFFSET + pn_len); + + if (htt_rx_msdu_chan_info_present_hl(pdev, mpdu_desc)) { + if (primary_chan_center_freq_mhz) + *primary_chan_center_freq_mhz = + HTT_WORD_GET( + *chan_info, + HTT_CHAN_INFO_PRIMARY_CHAN_CENTER_FREQ); + if (contig_chan1_center_freq_mhz) + *contig_chan1_center_freq_mhz = + HTT_WORD_GET( + *chan_info, + HTT_CHAN_INFO_CONTIG_CHAN1_CENTER_FREQ); + chan_info++; + if (contig_chan2_center_freq_mhz) + *contig_chan2_center_freq_mhz = + HTT_WORD_GET( + *chan_info, + HTT_CHAN_INFO_CONTIG_CHAN2_CENTER_FREQ); + if (phy_mode) + *phy_mode = + HTT_WORD_GET(*chan_info, + HTT_CHAN_INFO_PHY_MODE); + return true; + } + + if (primary_chan_center_freq_mhz) + *primary_chan_center_freq_mhz = 0; + if (contig_chan1_center_freq_mhz) + *contig_chan1_center_freq_mhz = 0; + if (contig_chan2_center_freq_mhz) + *contig_chan2_center_freq_mhz = 0; + if (phy_mode) + *phy_mode = 0; + return false; +} + +static bool +htt_rx_msdu_desc_key_id_hl(htt_pdev_handle htt_pdev, + void *mpdu_desc, u_int8_t *key_id) +{ + if (htt_rx_msdu_first_msdu_flag_hl(htt_pdev, mpdu_desc) == true) { + /* Fix Me: only for little endian */ + struct hl_htt_rx_desc_base *rx_desc = + (struct hl_htt_rx_desc_base *)mpdu_desc; + + *key_id = rx_desc->key_id_oct; + return true; + } + + return false; +} + +#endif + void *htt_rx_msdu_desc_retrieve_ll(htt_pdev_handle pdev, qdf_nbuf_t msdu) { return htt_rx_desc(msdu); @@ -2329,16 +2774,36 @@ void htt_rx_msdu_desc_free(htt_pdev_handle htt_pdev, qdf_nbuf_t msdu) */ } +#if defined(CONFIG_HL_SUPPORT) + +/** + * htt_rx_fill_ring_count() - replenish rx msdu buffer + * @pdev: Handle (pointer) to HTT pdev. + * + * This funciton will replenish the rx buffer to the max number + * that can be kept in the ring + * + * Return: None + */ +static inline void htt_rx_fill_ring_count(htt_pdev_handle pdev) +{ + return; +} +#else + +static void htt_rx_fill_ring_count(htt_pdev_handle pdev) +{ + int num_to_fill; + num_to_fill = pdev->rx_ring.fill_level - pdev->rx_ring.fill_cnt; + htt_rx_ring_fill_n(pdev, num_to_fill /* okay if <= 0 */); +} +#endif + void htt_rx_msdu_buff_replenish(htt_pdev_handle pdev) { - if (qdf_atomic_dec_and_test(&pdev->rx_ring.refill_ref_cnt)) { - int num_to_fill; - num_to_fill = pdev->rx_ring.fill_level - - pdev->rx_ring.fill_cnt; + if (qdf_atomic_dec_and_test(&pdev->rx_ring.refill_ref_cnt)) + htt_rx_fill_ring_count(pdev); - htt_rx_ring_fill_n(pdev, - num_to_fill /* okay if <= 0 */); - } qdf_atomic_inc(&pdev->rx_ring.refill_ref_cnt); } @@ -2614,6 +3079,51 @@ void htt_rx_hash_dump_table(struct htt_pdev_t *pdev) /* move the function to the end of file * to omit ll/hl pre-declaration */ + +#if defined(CONFIG_HL_SUPPORT) + +int htt_rx_attach(struct htt_pdev_t *pdev) +{ + pdev->rx_ring.size = HTT_RX_RING_SIZE_MIN; + HTT_ASSERT2(IS_PWR2(pdev->rx_ring.size)); + pdev->rx_ring.size_mask = pdev->rx_ring.size - 1; + /* host can force ring base address if it wish to do so */ + pdev->rx_ring.base_paddr = 0; + htt_rx_amsdu_pop = htt_rx_amsdu_pop_hl; + htt_rx_frag_pop = htt_rx_frag_pop_hl; + htt_rx_offload_msdu_pop = htt_rx_offload_msdu_pop_hl; + htt_rx_mpdu_desc_list_next = htt_rx_mpdu_desc_list_next_hl; + htt_rx_mpdu_desc_retry = htt_rx_mpdu_desc_retry_hl; + htt_rx_mpdu_desc_seq_num = htt_rx_mpdu_desc_seq_num_hl; + htt_rx_mpdu_desc_pn = htt_rx_mpdu_desc_pn_hl; + htt_rx_mpdu_desc_tid = htt_rx_mpdu_desc_tid_hl; + htt_rx_msdu_desc_completes_mpdu = htt_rx_msdu_desc_completes_mpdu_hl; + htt_rx_msdu_first_msdu_flag = htt_rx_msdu_first_msdu_flag_hl; + htt_rx_msdu_has_wlan_mcast_flag = htt_rx_msdu_has_wlan_mcast_flag_hl; + htt_rx_msdu_is_wlan_mcast = htt_rx_msdu_is_wlan_mcast_hl; + htt_rx_msdu_is_frag = htt_rx_msdu_is_frag_hl; + htt_rx_msdu_desc_retrieve = htt_rx_msdu_desc_retrieve_hl; + htt_rx_mpdu_is_encrypted = htt_rx_mpdu_is_encrypted_hl; + htt_rx_msdu_desc_key_id = htt_rx_msdu_desc_key_id_hl; + htt_rx_msdu_chan_info_present = htt_rx_msdu_chan_info_present_hl; + htt_rx_msdu_center_freq = htt_rx_msdu_center_freq_hl; + + /* + * HL case, the rx descriptor can be different sizes for + * different sub-types of RX_IND messages, e.g. for the + * initial vs. interior vs. final MSDUs within a PPDU. + * The size of each RX_IND message's rx desc is read from + * a field within the RX_IND message itself. + * In the meantime, until the rx_desc_size_hl variable is + * set to its real value based on the RX_IND message, + * initialize it to a reasonable value (zero). + */ + pdev->rx_desc_size_hl = 0; + return 0; /* success */ +} + +#else + int htt_rx_attach(struct htt_pdev_t *pdev) { qdf_dma_addr_t paddr; @@ -2763,6 +3273,7 @@ fail2: fail1: return 1; /* failure */ } +#endif #ifdef IPA_OFFLOAD #ifdef QCA_WIFI_3_0 diff --git a/core/dp/htt/htt_t2h.c b/core/dp/htt/htt_t2h.c index 08eb3c28f991..70dc057a1da7 100644 --- a/core/dp/htt/htt_t2h.c +++ b/core/dp/htt/htt_t2h.c @@ -58,34 +58,24 @@ #define DEBUG_CREDIT 0 #endif -static uint8_t *htt_t2h_mac_addr_deswizzle(uint8_t *tgt_mac_addr, - uint8_t *buffer) +#if defined(CONFIG_HL_SUPPORT) + + + +/** + * htt_rx_frag_set_last_msdu() - set last msdu bit in rx descriptor + * for recieved frames + * @pdev: Handle (pointer) to HTT pdev. + * @msg: htt recieved msg + * + * Return: None + */ +static inline +void htt_rx_frag_set_last_msdu(struct htt_pdev_t *pdev, qdf_nbuf_t msg) { -#ifdef BIG_ENDIAN_HOST - /* - * The host endianness is opposite of the target endianness. - * To make uint32_t elements come out correctly, the target->host - * upload has swizzled the bytes in each uint32_t element of the - * message. - * For byte-array message fields like the MAC address, this - * upload swizzling puts the bytes in the wrong order, and needs - * to be undone. - */ - buffer[0] = tgt_mac_addr[3]; - buffer[1] = tgt_mac_addr[2]; - buffer[2] = tgt_mac_addr[1]; - buffer[3] = tgt_mac_addr[0]; - buffer[4] = tgt_mac_addr[7]; - buffer[5] = tgt_mac_addr[6]; - return buffer; -#else - /* - * The host endianness matches the target endianness - - * we can use the mac addr directly from the message buffer. - */ - return tgt_mac_addr; -#endif + return; } +#else static void htt_rx_frag_set_last_msdu(struct htt_pdev_t *pdev, qdf_nbuf_t msg) { @@ -131,6 +121,36 @@ static void htt_rx_frag_set_last_msdu(struct htt_pdev_t *pdev, qdf_nbuf_t msg) rx_desc->msdu_end.last_msdu = 1; qdf_nbuf_map(pdev->osdev, msdu, QDF_DMA_FROM_DEVICE); } +#endif + +static uint8_t *htt_t2h_mac_addr_deswizzle(uint8_t *tgt_mac_addr, + uint8_t *buffer) +{ +#ifdef BIG_ENDIAN_HOST + /* + * The host endianness is opposite of the target endianness. + * To make uint32_t elements come out correctly, the target->host + * upload has swizzled the bytes in each uint32_t element of the + * message. + * For byte-array message fields like the MAC address, this + * upload swizzling puts the bytes in the wrong order, and needs + * to be undone. + */ + buffer[0] = tgt_mac_addr[3]; + buffer[1] = tgt_mac_addr[2]; + buffer[2] = tgt_mac_addr[1]; + buffer[3] = tgt_mac_addr[0]; + buffer[4] = tgt_mac_addr[7]; + buffer[5] = tgt_mac_addr[6]; + return buffer; +#else + /* + * The host endianness matches the target endianness - + * we can use the mac addr directly from the message buffer. + */ + return tgt_mac_addr; +#endif +} /* Target to host Msg/event handler for low priority messages*/ void htt_t2h_lp_msg_handler(void *context, qdf_nbuf_t htt_t2h_msg, @@ -284,10 +304,26 @@ void htt_t2h_lp_msg_handler(void *context, qdf_nbuf_t htt_t2h_msg, case HTT_T2H_MSG_TYPE_MGMT_TX_COMPL_IND: { struct htt_mgmt_tx_compl_ind *compl_msg; + int32_t credit_delta = 1; compl_msg = (struct htt_mgmt_tx_compl_ind *)(msg_word + 1); + if (pdev->cfg.is_high_latency) { + if (!pdev->cfg.default_tx_comp_req) { + qdf_atomic_add(credit_delta, + &pdev->htt_tx_credit. + target_delta); + credit_delta = htt_tx_credit_update(pdev); + } + if (credit_delta) + ol_tx_target_credit_update( + pdev->txrx_pdev, credit_delta); + } + ol_tx_desc_update_group_credit( + pdev->txrx_pdev, compl_msg->desc_id, 1, + 0, compl_msg->status); + if (!ol_tx_get_is_mgmt_over_wmi_enabled()) { ol_tx_single_completion_handler(pdev->txrx_pdev, compl_msg->status, @@ -330,6 +366,15 @@ void htt_t2h_lp_msg_handler(void *context, qdf_nbuf_t htt_t2h_msg, HTT_TX_CREDIT_DELTA_ABS_GET(*msg_word); sign = HTT_TX_CREDIT_SIGN_BIT_GET(*msg_word) ? -1 : 1; htt_credit_delta = sign * htt_credit_delta_abs; + + if (pdev->cfg.is_high_latency && + !pdev->cfg.default_tx_comp_req) { + qdf_atomic_add(htt_credit_delta, + &pdev->htt_tx_credit.target_delta); + htt_credit_delta = htt_tx_credit_update(pdev); + } + + htt_tx_group_credit_process(pdev, msg_word); ol_tx_credit_completion_handler(pdev->txrx_pdev, htt_credit_delta); break; @@ -535,6 +580,10 @@ void htt_t2h_msg_handler(void *context, HTC_PACKET *pkt) ol_rx_indication_handler(pdev->txrx_pdev, htt_t2h_msg, peer_id, tid, num_mpdu_ranges); + + if (pdev->cfg.is_high_latency) + return; + break; } case HTT_T2H_MSG_TYPE_TX_COMPL_IND: @@ -563,6 +612,27 @@ void htt_t2h_msg_handler(void *context, HTC_PACKET *pkt) compl->payload[num_msdus]; } } + + if (pdev->cfg.is_high_latency) { + if (!pdev->cfg.default_tx_comp_req) { + int credit_delta; + + qdf_atomic_add(num_msdus, + &pdev->htt_tx_credit. + target_delta); + credit_delta = htt_tx_credit_update(pdev); + + if (credit_delta) { + ol_tx_target_credit_update( + pdev->txrx_pdev, + credit_delta); + } + } else { + ol_tx_target_credit_update(pdev->txrx_pdev, + num_msdus); + } + } + ol_tx_completion_handler(pdev->txrx_pdev, num_msdus, status, msg_word + 1); HTT_TX_SCHED(pdev); @@ -637,6 +707,12 @@ void htt_t2h_msg_handler(void *context, HTC_PACKET *pkt) break; } + if (qdf_unlikely(pdev->cfg.is_high_latency)) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND "); + qdf_print("not supported on high latency.\n"); + break; + } + peer_id = HTT_RX_IN_ORD_PADDR_IND_PEER_ID_GET(*msg_word); tid = HTT_RX_IN_ORD_PADDR_IND_EXT_TID_GET(*msg_word); offload_ind = HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_GET(*msg_word); diff --git a/core/dp/htt/htt_tx.c b/core/dp/htt/htt_tx.c index dd75737991b3..2131d7bda430 100644 --- a/core/dp/htt/htt_tx.c +++ b/core/dp/htt/htt_tx.c @@ -228,6 +228,7 @@ int htt_tx_frag_alloc(htt_pdev_handle pdev, return 0; } #else + /** * htt_tx_desc_get_size() - get tx descripotrs size * @pdev: htt device instance pointer @@ -238,22 +239,28 @@ int htt_tx_frag_alloc(htt_pdev_handle pdev, */ static inline void htt_tx_desc_get_size(struct htt_pdev_t *pdev) { - /* - * Start with the size of the base struct - * that actually gets downloaded. - * - * Add the fragmentation descriptor elements. - * Add the most that the OS may deliver, plus one more - * in case the txrx code adds a prefix fragment (for - * TSO or audio interworking SNAP header) - */ - pdev->tx_descs.size = + if (pdev->cfg.is_high_latency) { + pdev->tx_descs.size = sizeof(struct htt_host_tx_desc_t); + } else { + /* + * Start with the size of the base struct + * that actually gets downloaded. + * + * Add the fragmentation descriptor elements. + * Add the most that the OS may deliver, plus one more + * in case the txrx code adds a prefix fragment (for + * TSO or audio interworking SNAP header) + */ + pdev->tx_descs.size = sizeof(struct htt_host_tx_desc_t) + (ol_cfg_netbuf_frags_max(pdev->ctrl_pdev) + 1) * 8 - /* 2x uint32_t */ + /* 2x uint32_t */ + 4; /* uint32_t fragmentation list terminator */ + } } +#ifndef CONFIG_HL_SUPPORT + /** * htt_tx_frag_desc_field_update() - Update fragment descriptor field * @pdev: htt device instance pointer @@ -273,6 +280,7 @@ static void htt_tx_frag_desc_field_update(struct htt_pdev_t *pdev, *fptr = (uint32_t)htt_tx_get_paddr(pdev, (char *)desc_v_ptr) + HTT_TX_DESC_LEN; } +#endif /** * htt_tx_frag_desc_attach() - Attach fragment descriptor @@ -300,6 +308,8 @@ static inline int htt_tx_frag_desc_attach(struct htt_pdev_t *pdev, static void htt_tx_frag_desc_detach(struct htt_pdev_t *pdev) {} #endif /* HELIUMPLUS */ +#ifdef CONFIG_HL_SUPPORT + /** * htt_tx_attach() - Attach HTT device instance * @pdev: htt device instance pointer @@ -313,6 +323,180 @@ int htt_tx_attach(struct htt_pdev_t *pdev, int desc_pool_elems) { int i, i_int, pool_size; uint32_t **p; + uint32_t num_link = 0; + uint16_t num_page, num_desc_per_page; + void **cacheable_pages = NULL; + + htt_tx_desc_get_size(pdev); + + /* + * Make sure tx_descs.size is a multiple of 4-bytes. + * It should be, but round up just to be sure. + */ + pdev->tx_descs.size = (pdev->tx_descs.size + 3) & (~0x3); + + pdev->tx_descs.pool_elems = desc_pool_elems; + pdev->tx_descs.alloc_cnt = 0; + pool_size = pdev->tx_descs.pool_elems * pdev->tx_descs.size; + qdf_mem_multi_pages_alloc(pdev->osdev, &pdev->tx_descs.desc_pages, + pdev->tx_descs.size, + pdev->tx_descs.pool_elems, + qdf_get_dma_mem_context((&pdev->tx_descs), + memctx), true); + if ((0 == pdev->tx_descs.desc_pages.num_pages) || + (NULL == pdev->tx_descs.desc_pages.cacheable_pages)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "HTT desc alloc fail"); + goto out_fail; + } + num_page = pdev->tx_descs.desc_pages.num_pages; + num_desc_per_page = pdev->tx_descs.desc_pages.num_element_per_page; + + /* link tx descriptors into a freelist */ + cacheable_pages = pdev->tx_descs.desc_pages.cacheable_pages; + + pdev->tx_descs.freelist = (uint32_t *)cacheable_pages[0]; + p = (uint32_t **)pdev->tx_descs.freelist; + for (i = 0; i < num_page; i++) { + for (i_int = 0; i_int < num_desc_per_page; i_int++) { + if (i_int == (num_desc_per_page - 1)) { + /* + * Last element on this page, + * should point next page + */ + if (!cacheable_pages[i + 1]) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "over flow num link %d\n", + num_link); + goto free_htt_desc; + } + *p = (uint32_t *)cacheable_pages[i + 1]; + } else { + *p = (uint32_t *) + (((char *)p) + pdev->tx_descs.size); + } + num_link++; + p = (uint32_t **) *p; + /* Last link established exit */ + if (num_link == (pdev->tx_descs.pool_elems - 1)) + break; + } + } + *p = NULL; + + if (htt_tx_frag_desc_attach(pdev, desc_pool_elems)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "HTT Frag descriptor alloc fail"); + goto free_htt_desc; + } + + /* success */ + return 0; + +free_htt_desc: + qdf_mem_multi_pages_free(pdev->osdev, &pdev->tx_descs.desc_pages, + qdf_get_dma_mem_context((&pdev->tx_descs), + memctx), true); +out_fail: + return -ENOBUFS; +} + +void htt_tx_detach(struct htt_pdev_t *pdev) +{ + if (!pdev) { + qdf_print("htt tx detach invalid instance"); + return; + } + + htt_tx_frag_desc_detach(pdev); + qdf_mem_multi_pages_free(pdev->osdev, &pdev->tx_descs.desc_pages, + qdf_get_dma_mem_context((&pdev->tx_descs), + memctx), true); +} + +/** + * htt_tx_set_frag_desc_addr() - set up the fragmentation descriptor address + * @pdev: pointer to the HTT instance making the allocation + * @htt_tx_desc: Host tx decriptor that does not include HTC hdr + * @index: index to alloc htt tx desc + * + * + * Return: None + */ +static inline void +htt_tx_set_frag_desc_addr(struct htt_pdev_t *pdev, + struct htt_tx_msdu_desc_t *htt_tx_desc, + uint16_t index) +{ + return; +} + +/** + * htt_tx_desc_frags_table_set() - set up the descriptor and payload + * to correspondinf fragments + * @pdev: pointer to the HTT instance making the allocation + * @htt_tx_desc: Host tx decriptor that does not include HTC hdr + * @paddr: fragment physical address + * @frag_desc_paddr_lo: frag descriptor address + * @reset: reset + * + * Return: None + */ +void htt_tx_desc_frags_table_set(htt_pdev_handle pdev, + void *desc, + qdf_dma_addr_t paddr, + qdf_dma_addr_t frag_desc_paddr, + int reset) +{ + /* fragments table only applies to LL systems */ + return; +} + +/** + * htt_tx_credit_update() - get the number of credits by which the amount of + * target credits needs to be updated + * @pdev: htt context + * + * Return: number of credits + */ +int htt_tx_credit_update(struct htt_pdev_t *pdev) +{ + int credit_delta; + credit_delta = QDF_MIN(qdf_atomic_read( + &pdev->htt_tx_credit.target_delta), + qdf_atomic_read(&pdev->htt_tx_credit.bus_delta)); + if (credit_delta) { + qdf_atomic_add(-credit_delta, + &pdev->htt_tx_credit.target_delta); + qdf_atomic_add(-credit_delta, + &pdev->htt_tx_credit.bus_delta); + } + return credit_delta; +} + +/** + * htt_tx_get_paddr() - get physical address for htt desc + * + * Get HTT descriptor physical address from virtaul address + * Find page first and find offset + * Not required for HL systems + * + * Return: Physical address of descriptor + */ +static inline +qdf_dma_addr_t htt_tx_get_paddr(htt_pdev_handle pdev, + char *target_vaddr) +{ + return 0; +} + + +#else + +int htt_tx_attach(struct htt_pdev_t *pdev, int desc_pool_elems) +{ + int i, i_int, pool_size; + uint32_t **p; struct qdf_mem_dma_page_t *page_info; uint32_t num_link = 0; uint16_t num_page, num_desc_per_page; @@ -399,14 +583,55 @@ void htt_tx_detach(struct htt_pdev_t *pdev) qdf_get_dma_mem_context((&pdev->tx_descs), memctx), false); } -/** - * htt_tx_get_paddr() - get physical address for htt desc - * - * Get HTT descriptor physical address from virtaul address - * Find page first and find offset - * - * Return: Physical address of descriptor - */ +static void +htt_tx_set_frag_desc_addr(struct htt_pdev_t *pdev, + struct htt_tx_msdu_desc_t *htt_tx_desc, + uint16_t index) +{ + uint32_t *fragmentation_descr_field_ptr; + fragmentation_descr_field_ptr = (uint32_t *) + ((uint32_t *)htt_tx_desc) + + HTT_TX_DESC_FRAGS_DESC_PADDR_OFFSET_DWORD; + /* + * The fragmentation descriptor is allocated from consistent + * memory. Therefore, we can use the address directly rather + * than having to map it from a virtual/CPU address to a + * physical/bus address. + */ + htt_tx_frag_desc_field_update(pdev, fragmentation_descr_field_ptr, + index, htt_tx_desc); + + return; +} + +void htt_tx_desc_frags_table_set(htt_pdev_handle pdev, + void *htt_tx_desc, + qdf_dma_addr_t paddr, + qdf_dma_addr_t frag_desc_paddr, + int reset) +{ + uint32_t *fragmentation_descr_field_ptr; + + fragmentation_descr_field_ptr = (uint32_t *) + ((uint32_t *) htt_tx_desc) + + HTT_TX_DESC_FRAGS_DESC_PADDR_OFFSET_DWORD; + if (reset) { +#if defined(HELIUMPLUS_PADDR64) + *fragmentation_descr_field_ptr = frag_desc_paddr; +#else + *fragmentation_descr_field_ptr = + htt_tx_get_paddr(pdev, htt_tx_desc) + HTT_TX_DESC_LEN; +#endif + } else { + *fragmentation_descr_field_ptr = paddr; + } +} + +void htt_tx_pending_discard(htt_pdev_handle pdev) +{ + htc_flush_surprise_remove(pdev->htc_pdev); +} + static qdf_dma_addr_t htt_tx_get_paddr(htt_pdev_handle pdev, char *target_vaddr) { @@ -434,6 +659,8 @@ static qdf_dma_addr_t htt_tx_get_paddr(htt_pdev_handle pdev, return page_info->page_p_addr + offset; } +#endif + /*--- descriptor allocation functions ---------------------------------------*/ void *htt_tx_desc_alloc(htt_pdev_handle pdev, qdf_dma_addr_t *paddr, @@ -441,7 +668,6 @@ void *htt_tx_desc_alloc(htt_pdev_handle pdev, qdf_dma_addr_t *paddr, { struct htt_host_tx_desc_t *htt_host_tx_desc; /* includes HTC hdr */ struct htt_tx_msdu_desc_t *htt_tx_desc; /* doesn't include HTC hdr */ - uint32_t *fragmentation_descr_field_ptr; htt_host_tx_desc = (struct htt_host_tx_desc_t *)pdev->tx_descs.freelist; if (!htt_host_tx_desc) @@ -461,17 +687,7 @@ void *htt_tx_desc_alloc(htt_pdev_handle pdev, qdf_dma_addr_t *paddr, * would be helpful to have separate htt_tx_desc_alloc functions for * HL vs. LL, to remove the below conditional branch. */ - fragmentation_descr_field_ptr = (uint32_t *) - ((uint32_t *) htt_tx_desc) + - HTT_TX_DESC_FRAGS_DESC_PADDR_OFFSET_DWORD; - /* - * The fragmentation descriptor is allocated from consistent - * memory. Therefore, we can use the address directly rather - * than having to map it from a virtual/CPU address to a - * physical/bus address. - */ - htt_tx_frag_desc_field_update(pdev, fragmentation_descr_field_ptr, - index, htt_tx_desc); + htt_tx_set_frag_desc_addr(pdev, htt_tx_desc, index); /* * Include the headroom for the HTC frame header when specifying the @@ -502,40 +718,12 @@ void htt_tx_desc_free(htt_pdev_handle pdev, void *tx_desc) /*--- descriptor field access methods ---------------------------------------*/ -void htt_tx_desc_frags_table_set(htt_pdev_handle pdev, - void *htt_tx_desc, - qdf_dma_addr_t paddr, - qdf_dma_addr_t frag_desc_paddr, - int reset) -{ - uint32_t *fragmentation_descr_field_ptr; - - fragmentation_descr_field_ptr = (uint32_t *) - ((uint32_t *) htt_tx_desc) + - HTT_TX_DESC_FRAGS_DESC_PADDR_OFFSET_DWORD; - if (reset) { -#if defined(HELIUMPLUS_PADDR64) - *fragmentation_descr_field_ptr = frag_desc_paddr; -#else - *fragmentation_descr_field_ptr = - htt_tx_get_paddr(pdev, htt_tx_desc) + HTT_TX_DESC_LEN; -#endif - } else { - *fragmentation_descr_field_ptr = paddr; - } -} - /* PUT THESE AS inline IN ol_htt_tx_api.h */ void htt_tx_desc_flag_postponed(htt_pdev_handle pdev, void *desc) { } -void htt_tx_pending_discard(htt_pdev_handle pdev) -{ - htc_flush_surprise_remove(pdev->htc_pdev); -} - void htt_tx_desc_flag_batch_more(htt_pdev_handle pdev, void *desc) { } @@ -628,6 +816,7 @@ int htt_tx_send_std(htt_pdev_handle pdev, qdf_nbuf_t msdu, uint16_t msdu_id) } +#ifndef CONFIG_HL_SUPPORT #ifdef FEATURE_RUNTIME_PM /** * htt_tx_resume_handler() - resume callback for the htt endpoint @@ -645,6 +834,7 @@ void htt_tx_resume_handler(void *context) void htt_tx_resume_handler(void *context) { } #endif +#endif qdf_nbuf_t htt_tx_send_batch(htt_pdev_handle pdev, qdf_nbuf_t head_msdu, int num_msdus) @@ -1420,6 +1610,9 @@ htt_tx_desc_init(htt_pdev_handle pdev, HTT_TX_DESC_EXT_TID_SET(local_word0, msdu_info->info.ext_tid); HTT_TX_DESC_CKSUM_OFFLOAD_SET(local_word0, msdu_info->action.cksum_offload); + if (pdev->cfg.is_high_latency) + HTT_TX_DESC_TX_COMP_SET(local_word0, msdu_info->action. + tx_comp_req); HTT_TX_DESC_NO_ENCRYPT_SET(local_word0, msdu_info->action.do_encrypt ? 0 : 1); @@ -1510,3 +1703,53 @@ htt_tx_desc_init(htt_pdev_handle pdev, qdf_nbuf_data_attr_set(msdu, data_attr); } +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +/** + * htt_tx_group_credit_process() - process group data for + * credit update indication + * @pdev: pointer to htt device. + * @msg_word: htt msg + * + * Return: None + */ +void htt_tx_group_credit_process(struct htt_pdev_t *pdev, u_int32_t *msg_word) +{ + int group_credit_sign; + int32_t group_credit; + u_int32_t group_credit_abs, vdev_id_mask, ac_mask; + u_int8_t group_abs, group_id; + u_int8_t group_offset = 0, more_group_present = 0; + more_group_present = HTT_TX_CREDIT_TXQ_GRP_GET(*msg_word); + + while (more_group_present) { + /* Parse the Group Data */ + group_id = HTT_TXQ_GROUP_ID_GET(*(msg_word+1 + +group_offset)); + group_credit_abs = + HTT_TXQ_GROUP_CREDIT_COUNT_GET(*(msg_word+1 + +group_offset)); + group_credit_sign = + HTT_TXQ_GROUP_SIGN_GET(*(msg_word+1 + +group_offset)) ? -1 : 1; + group_credit = group_credit_sign * group_credit_abs; + group_abs = HTT_TXQ_GROUP_ABS_GET(*(msg_word+1 + +group_offset)); + + vdev_id_mask = + HTT_TXQ_GROUP_VDEV_ID_MASK_GET(*(msg_word+2 + +group_offset)); + ac_mask = HTT_TXQ_GROUP_AC_MASK_GET(*(msg_word+2 + +group_offset)); + + ol_txrx_update_tx_queue_groups(pdev->txrx_pdev, group_id, + group_credit, group_abs, + vdev_id_mask, ac_mask); + more_group_present = HTT_TXQ_GROUP_EXT_GET(*(msg_word+1 + +group_offset)); + group_offset += HTT_TX_GROUP_INDEX_OFFSET; + } + ol_tx_update_group_credit_stats(pdev->txrx_pdev); +} +#endif + diff --git a/core/dp/htt/htt_types.h b/core/dp/htt/htt_types.h index 6b21de364d71..6d2af7ad80af 100644 --- a/core/dp/htt/htt_types.h +++ b/core/dp/htt/htt_types.h @@ -170,6 +170,11 @@ struct ipa_uc_rx_ring_elem_t { uint32_t rx_packet_leng; }; +struct htt_tx_credit_t { + qdf_atomic_t bus_delta; + qdf_atomic_t target_delta; +}; + #if defined(HELIUMPLUS_PADDR64) /** * msdu_ext_frag_desc: @@ -242,6 +247,7 @@ struct htt_pdev_t { struct htt_htc_pkt_union *htt_htc_pkt_freelist; struct { + int is_high_latency; int is_full_reorder_offload; int default_tx_comp_req; int ce_classify_enabled; @@ -354,6 +360,9 @@ struct htt_pdev_t { struct htt_rx_hash_bucket **hash_table; uint32_t listnode_offset; } rx_ring; +#ifdef CONFIG_HL_SUPPORT + int rx_desc_size_hl; +#endif long rx_fw_desc_offset; int rx_mpdu_range_offset_words; int rx_ind_msdu_byte_idx; @@ -384,13 +393,18 @@ struct htt_pdev_t { struct { int htc_err_cnt; } stats; - +#ifdef CONFIG_HL_SUPPORT + int cur_seq_num_hl; +#endif struct htt_tx_mgmt_desc_ctxt tx_mgmt_desc_ctxt; struct targetdef_s *targetdef; struct ce_reg_def *target_ce_def; struct htt_ipa_uc_tx_resource_t ipa_uc_tx_rsc; struct htt_ipa_uc_rx_resource_t ipa_uc_rx_rsc; + + struct htt_tx_credit_t htt_tx_credit; + #ifdef DEBUG_RX_RING_BUFFER struct rx_buf_debug *rx_buff_list; int rx_buff_index; diff --git a/core/dp/ol/inc/ol_cfg.h b/core/dp/ol/inc/ol_cfg.h index 7caea62dee17..0fbab7f14c40 100644 --- a/core/dp/ol/inc/ol_cfg.h +++ b/core/dp/ol/inc/ol_cfg.h @@ -32,7 +32,11 @@ #include <cdp_txrx_cmn.h> /* ol_pdev_handle */ #include <cds_ieee80211_common.h> /* ieee80211_qosframe_htc_addr4 */ #include <enet.h> /* LLC_SNAP_HDR_LEN */ +#if defined(CONFIG_HL_SUPPORT) +#include "wlan_tgt_def_config_hl.h" +#else #include "wlan_tgt_def_config.h" +#endif #include "ol_txrx_ctrl_api.h" /* txrx_pdev_cfg_param_t */ /** @@ -256,6 +260,7 @@ int ol_cfg_netbuf_frags_max(ol_pdev_handle pdev); * 1 -> free the tx frame as soon as the download completes */ int ol_cfg_tx_free_at_download(ol_pdev_handle pdev); +void ol_cfg_set_tx_free_at_download(ol_pdev_handle pdev); /** * @brief Low water mark for target tx credit. diff --git a/core/dp/ol/inc/ol_htt_api.h b/core/dp/ol/inc/ol_htt_api.h index 371af50bfa20..e97ffb55826a 100644 --- a/core/dp/ol/inc/ol_htt_api.h +++ b/core/dp/ol/inc/ol_htt_api.h @@ -365,4 +365,23 @@ static inline void htt_ipa_uc_detach(struct htt_pdev_t *pdev) void htt_rx_mon_note_capture_channel(htt_pdev_handle pdev, int mon_ch); void ol_htt_mon_note_chan(ol_txrx_pdev_handle pdev, int mon_ch); + +#if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) + +void htt_dump_bundle_stats(struct htt_pdev_t *pdev); +void htt_clear_bundle_stats(struct htt_pdev_t *pdev); +#else + +static inline void htt_dump_bundle_stats(struct htt_pdev_t *pdev) +{ + return; +} + +static inline void htt_clear_bundle_stats(struct htt_pdev_t *pdev) +{ + return; +} +#endif + + #endif /* _OL_HTT_API__H_ */ diff --git a/core/dp/ol/inc/ol_htt_rx_api.h b/core/dp/ol/inc/ol_htt_rx_api.h index 942b4cb95f01..303819a8732d 100644 --- a/core/dp/ol/inc/ol_htt_rx_api.h +++ b/core/dp/ol/inc/ol_htt_rx_api.h @@ -824,11 +824,13 @@ void htt_rx_frag_ind_flush_seq_num_range(htt_pdev_handle pdev, qdf_nbuf_t rx_frag_ind_msg, int *seq_num_start, int *seq_num_end); + /** - * @brief Return the HL rx desc size - * @param pdev - the HTT instance the rx data was received on - * @param msdu_desc - the hl rx desc pointer + * htt_rx_msdu_rx_desc_size_hl() - Return the HL rx desc size + * @pdev: the HTT instance the rx data was received on. + * @msdu_desc: the hl rx desc pointer * + * Return: HL rx desc size */ uint16_t htt_rx_msdu_rx_desc_size_hl(htt_pdev_handle pdev, void *msdu_desc); diff --git a/core/dp/ol/inc/ol_htt_tx_api.h b/core/dp/ol/inc/ol_htt_tx_api.h index f5d0abc66fab..81ff598107f4 100644 --- a/core/dp/ol/inc/ol_htt_tx_api.h +++ b/core/dp/ol/inc/ol_htt_tx_api.h @@ -393,6 +393,9 @@ static inline int htt_tx_frag_alloc(htt_pdev_handle pdev, return 0; } #endif /* defined(HELIUMPLUS_PADDR64) */ + +#if defined(CONFIG_HL_SUPPORT) + /** * @brief Discard all tx frames in the process of being downloaded. * @details @@ -404,7 +407,14 @@ static inline int htt_tx_frag_alloc(htt_pdev_handle pdev, * @param[OUT] frag_paddr_lo - physical address of the fragment descriptor * (MSDU Link Extension Descriptor) */ +static inline void htt_tx_pending_discard(htt_pdev_handle pdev) +{ + return; +} +#else + void htt_tx_pending_discard(htt_pdev_handle pdev); +#endif /** * @brief Download a MSDU descriptor and (a portion of) the MSDU payload. diff --git a/core/dp/ol/inc/ol_txrx_ctrl_api.h b/core/dp/ol/inc/ol_txrx_ctrl_api.h index cb937ba6f75f..e0a3a1735b4c 100644 --- a/core/dp/ol/inc/ol_txrx_ctrl_api.h +++ b/core/dp/ol/inc/ol_txrx_ctrl_api.h @@ -68,6 +68,10 @@ #define WLAN_HDD_NETIF_OPER_HISTORY 4 #define WLAN_DUMP_TX_FLOW_POOL_INFO 5 #define WLAN_TXRX_DESC_STATS 6 +#define WLAN_SCHEDULER_STATS 21 +#define WLAN_TX_QUEUE_STATS 22 +#define WLAN_BUNDLE_STATS 23 +#define WLAN_CREDIT_STATS 24 /** * @brief Set up the data SW subsystem. @@ -156,6 +160,7 @@ struct ol_tx_wmm_param_t { struct ol_tx_ac_param_t ac[OL_TX_NUM_WMM_AC]; }; +#if defined(CONFIG_HL_SUPPORT) /** * @brief Set paramters of WMM scheduler per AC settings. . * @details @@ -164,23 +169,9 @@ struct ol_tx_wmm_param_t { * @param data_pdev - the physical device being paused * @param wmm_param - the wmm parameters */ -#define ol_txrx_set_wmm_param(data_pdev, wmm_param) /* no-op */ - -/** - * @brief notify tx data SW that a peer's transmissions are suspended. - * @details - * This function applies only to HL systems - in LL systems, tx flow control - * is handled entirely within the target FW. - * The HL host tx data SW is doing tx classification and tx download - * scheduling, and therefore also needs to actively participate in tx - * flow control. Specifically, the HL tx data SW needs to check whether a - * given peer is available to transmit to, or is paused. - * This function is used to tell the HL tx data SW when a peer is paused, - * so the host tx data SW can hold the tx frames for that SW. - * - * @param data_peer - which peer is being paused - */ -#define ol_txrx_peer_pause(data_peer) /* no-op */ +void +ol_txrx_set_wmm_param(ol_txrx_pdev_handle data_pdev, + struct ol_tx_wmm_param_t wmm_param); /** * @brief notify tx data SW that a peer-TID is ready to transmit to. @@ -204,7 +195,9 @@ struct ol_tx_wmm_param_t { * @param tid - which TID within the peer is being unpaused, or -1 as a * wildcard to unpause all TIDs within the peer */ -#define ol_txrx_peer_tid_unpause(data_peer, tid) /* no-op */ +void +ol_txrx_peer_tid_unpause(ol_txrx_peer_handle data_peer, int tid); + /** * @brief Tell a paused peer to release a specified number of tx frames. @@ -230,8 +223,9 @@ struct ol_tx_wmm_param_t { * @param max_frms - limit on the number of tx frames to release from the * specified TID's queues within the specified peer */ -#define ol_txrx_tx_release(peer, tid_mask, max_frms) /* no-op */ - +void ol_txrx_tx_release(ol_txrx_peer_handle peer, + u_int32_t tid_mask, + int max_frms); /** * @brief Suspend all tx data per thermal event/timer for the @@ -240,7 +234,9 @@ struct ol_tx_wmm_param_t { * This function applies only to HL systerms, and it makes pause and * unpause operations happen in pairs. */ -#define ol_txrx_throttle_pause(data_pdev) /* no-op */ +void +ol_txrx_throttle_pause(ol_txrx_pdev_handle data_pdev); + /** * @brief Resume all tx data per thermal event/timer for the @@ -249,7 +245,64 @@ struct ol_tx_wmm_param_t { * This function applies only to HL systerms, and it makes pause and * unpause operations happen in pairs. */ -#define ol_txrx_throttle_unpause(data_pdev) /* no-op */ +void +ol_txrx_throttle_unpause(ol_txrx_pdev_handle data_pdev); + +#else + +static inline +void ol_txrx_set_wmm_param(ol_txrx_pdev_handle data_pdev, + struct ol_tx_wmm_param_t wmm_param) +{ + return; +} + +static inline void +ol_txrx_peer_tid_unpause(ol_txrx_peer_handle data_peer, int tid) +{ + return; +} + +static inline void +ol_txrx_tx_release(ol_txrx_peer_handle peer, + u_int32_t tid_mask, + int max_frms) +{ + return; +} + +static inline void +ol_txrx_throttle_pause(ol_txrx_pdev_handle data_pdev) +{ + return; +} + +static inline void +ol_txrx_throttle_unpause(ol_txrx_pdev_handle data_pdev) +{ + return; +} + +#endif /* CONFIG_HL_SUPPORT */ + +/** + * @brief notify tx data SW that a peer's transmissions are suspended. + * @details + * This function applies only to HL systems - in LL systems, tx flow control + * is handled entirely within the target FW. + * The HL host tx data SW is doing tx classification and tx download + * scheduling, and therefore also needs to actively participate in tx + * flow control. Specifically, the HL tx data SW needs to check whether a + * given peer is available to transmit to, or is paused. + * This function is used to tell the HL tx data SW when a peer is paused, + * so the host tx data SW can hold the tx frames for that SW. + * + * @param data_peer - which peer is being paused + */ +static inline void ol_txrx_peer_pause(struct ol_txrx_peer_t *data_peer) +{ + return; +} /** * @brief Suspend all tx data for the specified physical device. @@ -263,7 +316,9 @@ struct ol_tx_wmm_param_t { * * @param data_pdev - the physical device being paused */ -#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || \ + defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(CONFIG_HL_SUPPORT) + void ol_txrx_pdev_pause(struct ol_txrx_pdev_t *data_pdev, uint32_t reason); #else static inline @@ -281,7 +336,9 @@ void ol_txrx_pdev_pause(struct ol_txrx_pdev_t *data_pdev, uint32_t reason) * * @param data_pdev - the physical device being unpaused */ -#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || \ + defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(CONFIG_HL_SUPPORT) + void ol_txrx_pdev_unpause(struct ol_txrx_pdev_t *pdev, uint32_t reason); #else static inline @@ -488,6 +545,58 @@ int16_t ol_txrx_peer_rssi(ol_txrx_peer_handle peer); */ #define QCA_TX_DELAY_HIST_REPORT_BINS 6 +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + +/** + * @brief Configure the bad peer tx limit setting. + * @details + * + * @param pdev - the physics device + */ +void +ol_txrx_bad_peer_txctl_set_setting( + struct ol_txrx_pdev_t *pdev, + int enable, + int period, + int txq_limit); + +/** + * @brief Configure the bad peer tx threshold limit + * @details + * + * @param pdev - the physics device + */ +void +ol_txrx_bad_peer_txctl_update_threshold( + struct ol_txrx_pdev_t *pdev, + int level, + int tput_thresh, + int tx_limit); + +#else + +static inline void +ol_txrx_bad_peer_txctl_set_setting( + struct ol_txrx_pdev_t *pdev, + int enable, + int period, + int txq_limit) +{ + return; +} + +static inline void +ol_txrx_bad_peer_txctl_update_threshold( + struct ol_txrx_pdev_t *pdev, + int level, + int tput_thresh, + int tx_limit) +{ + return; +} +#endif /* defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) */ + + void ol_txrx_set_ocb_peer(struct ol_txrx_pdev_t *pdev, struct ol_txrx_peer_t *peer); diff --git a/core/dp/ol/inc/ol_txrx_dbg.h b/core/dp/ol/inc/ol_txrx_dbg.h index 745e24f7baea..8e5470344b19 100644 --- a/core/dp/ol/inc/ol_txrx_dbg.h +++ b/core/dp/ol/inc/ol_txrx_dbg.h @@ -134,7 +134,26 @@ void ol_rx_pn_trace_display(ol_txrx_pdev_handle pdev, int just_once); /* uncomment this to enable the tx queue log feature */ /* #define ENABLE_TX_QUEUE_LOG 1 */ -#define ol_tx_queue_log_display(pdev) +#if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) + +void +ol_tx_queue_log_display(ol_txrx_pdev_handle pdev); +void ol_tx_queue_log_clear(ol_txrx_pdev_handle pdev); +#else + +static inline void +ol_tx_queue_log_display(ol_txrx_pdev_handle pdev) +{ + return; +} + +static inline +void ol_tx_queue_log_clear(ol_txrx_pdev_handle pdev) +{ + return; +} +#endif /* defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) */ + /*----------------------------------------*/ diff --git a/core/dp/ol/inc/ol_txrx_htt_api.h b/core/dp/ol/inc/ol_txrx_htt_api.h index 024fe0ce07dd..863a0acfcafb 100644 --- a/core/dp/ol/inc/ol_txrx_htt_api.h +++ b/core/dp/ol/inc/ol_txrx_htt_api.h @@ -153,6 +153,147 @@ ol_tx_completion_handler(ol_txrx_pdev_handle pdev, void ol_tx_credit_completion_handler(ol_txrx_pdev_handle pdev, int credits); +struct rate_report_t { + u_int16_t id; + u_int16_t phy:4; + u_int32_t rate; +}; + +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + +/** + * @brief Process a link status report for all peers. + * @details + * The ol_txrx_peer_link_status_handler function performs basic peer link + * status analysis + * + * According to the design, there are 3 kinds of peers which will be + * treated differently: + * 1) normal: not do any flow control for the peer + * 2) limited: will apply flow control for the peer, but frames are allowed + * to send + * 3) paused: will apply flow control for the peer, no frame is allowed + * to send + * + * @param pdev - the data physical device that sent the tx frames + * @param status - the number of peers need to be handled + * @param peer_link_report - the link status dedail message + */ +void +ol_txrx_peer_link_status_handler( + ol_txrx_pdev_handle pdev, + u_int16_t peer_num, + struct rate_report_t *peer_link_status); + + +#else +static inline void ol_txrx_peer_link_status_handler( + ol_txrx_pdev_handle pdev, + u_int16_t peer_num, + struct rate_report_t *peer_link_status) +{ + return; +} +#endif + + +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +/** + * ol_txrx_update_tx_queue_groups() - update vdev tx queue group if + * vdev id mask and ac mask is not matching + * @pdev: the data physical device + * @group_id: TXQ group id + * @credit: TXQ group credit count + * @absolute: TXQ group absolute + * @vdev_id_mask: TXQ vdev group id mask + * @ac_mask: TQX access category mask + * + * Return: None + */ +void +ol_txrx_update_tx_queue_groups( + ol_txrx_pdev_handle pdev, + u_int8_t group_id, + int32_t credit, + u_int8_t absolute, + u_int32_t vdev_id_mask, + u_int32_t ac_mask +); + +/** + * ol_tx_desc_update_group_credit() - update group credits for txq group + * @pdev: the data physical device + * @tx_desc_id: desc id of tx completion message + * @credit: number of credits to update + * @absolute: absolute value + * @status: tx completion message status + * + * Return: None + */ +void +ol_tx_desc_update_group_credit( + ol_txrx_pdev_handle pdev, + u_int16_t tx_desc_id, + int credit, u_int8_t absolute, enum htt_tx_status status); + +#ifdef DEBUG_HL_LOGGING + +/** + * ol_tx_update_group_credit_stats() - update group credits stats for txq groups + * @pdev: the data physical device + * + * Return: None + */ +void +ol_tx_update_group_credit_stats(ol_txrx_pdev_handle pdev); + +/** + * ol_tx_dump_group_credit_stats() - dump group credits stats for txq groups + * @pdev: the data physical device + * + * Return: None + */ +void +ol_tx_dump_group_credit_stats(ol_txrx_pdev_handle pdev); + +/** + * ol_tx_clear_group_credit_stats() - clear group credits stats for txq groups + * @pdev: the data physical device + * + * Return: None + */ +void +ol_tx_clear_group_credit_stats(ol_txrx_pdev_handle pdev); +#else + +static inline void ol_tx_update_group_credit_stats(ol_txrx_pdev_handle pdev) +{ + return; +} + +static inline void ol_tx_dump_group_credit_stats(ol_txrx_pdev_handle pdev) +{ + return; +} + +static inline void ol_tx_clear_group_credit_stats(ol_txrx_pdev_handle pdev) +{ + return; +} +#endif + +#else +static inline void +ol_tx_desc_update_group_credit( + ol_txrx_pdev_handle pdev, + u_int16_t tx_desc_id, + int credit, u_int8_t absolute, enum htt_tx_status status) +{ + return; +} +#endif + /** * @brief Init the total amount of target credit. * @details @@ -576,4 +717,22 @@ ol_rx_in_order_indication_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id, uint8_t tid, uint8_t is_offload); +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +/** + * ol_tx_get_max_tx_groups_supported() - get max TCQ groups supported + * @pdev: the data physical device that received the frames + * + * Return: number of max groups supported + */ +u_int32_t ol_tx_get_max_tx_groups_supported(struct ol_txrx_pdev_t *pdev); +#else + +static inline u_int32_t +ol_tx_get_max_tx_groups_supported(struct ol_txrx_pdev_t *pdev) +{ + return 0; +} +#endif + #endif /* _OL_TXRX_HTT_API__H_ */ diff --git a/core/dp/txrx/ol_cfg.c b/core/dp/txrx/ol_cfg.c index 60adb2aac92d..1b4a5911c0b5 100644 --- a/core/dp/txrx/ol_cfg.c +++ b/core/dp/txrx/ol_cfg.c @@ -57,6 +57,36 @@ void ol_tx_set_flow_control_parameters(struct txrx_pdev_cfg_t *cfg_ctx, } #endif +#ifdef CONFIG_HL_SUPPORT + +/** + * ol_pdev_cfg_param_update() - assign download size of tx frame for txrx + * pdev that will be used across datapath + * @cfg_ctx: ptr to config parameter for txrx pdev + * + * Return: None + */ +static inline +void ol_pdev_cfg_param_update(struct txrx_pdev_cfg_t *cfg_ctx) +{ + cfg_ctx->is_high_latency = 1; + /* 802.1Q and SNAP / LLC headers are accounted for elsewhere */ + cfg_ctx->tx_download_size = 1500; + cfg_ctx->tx_free_at_download = 0; +} +#else + +static inline +void ol_pdev_cfg_param_update(struct txrx_pdev_cfg_t *cfg_ctx) +{ + /* + * Need to change HTT_LL_TX_HDR_SIZE_IP accordingly. + * Include payload, up to the end of UDP header for IPv4 case + */ + cfg_ctx->tx_download_size = 16; +} +#endif + #if CFG_TGT_DEFAULT_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK static inline uint8_t ol_defrag_timeout_check(void) @@ -86,6 +116,7 @@ uint8_t ol_defrag_timeout_check(void) * * Return: the control device object */ + ol_pdev_handle ol_pdev_cfg_attach(qdf_device_t osdev, struct txrx_pdev_cfg_param_t cfg_param) { @@ -97,11 +128,8 @@ ol_pdev_handle ol_pdev_cfg_attach(qdf_device_t osdev, return NULL; } - /* - * Need to change HTT_LL_TX_HDR_SIZE_IP accordingly. - * Include payload, up to the end of UDP header for IPv4 case - */ - cfg_ctx->tx_download_size = 16; + ol_pdev_cfg_param_update(cfg_ctx); + /* temporarily diabled PN check for Riva/Pronto */ cfg_ctx->rx_pn_check = 1; cfg_ctx->defrag_timeout_check = ol_defrag_timeout_check(); @@ -248,6 +276,21 @@ int ol_cfg_tx_free_at_download(ol_pdev_handle pdev) return cfg->tx_free_at_download; } +void ol_cfg_set_tx_free_at_download(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + cfg->tx_free_at_download = 1; +} + + +#ifdef CONFIG_HL_SUPPORT +uint16_t ol_cfg_target_tx_credit(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->target_tx_credit; +} +#else + uint16_t ol_cfg_target_tx_credit(ol_pdev_handle pdev) { struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; @@ -259,6 +302,7 @@ uint16_t ol_cfg_target_tx_credit(ol_pdev_handle pdev) return rc; } +#endif int ol_cfg_tx_download_size(ol_pdev_handle pdev) { @@ -326,6 +370,7 @@ int ol_cfg_get_tx_flow_start_queue_offset(ol_pdev_handle pdev) struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; return cfg->tx_flow_start_queue_offset; } + #endif #ifdef IPA_OFFLOAD diff --git a/core/dp/txrx/ol_rx.c b/core/dp/txrx/ol_rx.c index e1f65ce2a345..52b894a49a53 100644 --- a/core/dp/txrx/ol_rx.c +++ b/core/dp/txrx/ol_rx.c @@ -1019,6 +1019,10 @@ ol_rx_deliver(struct ol_txrx_vdev_t *vdev, qdf_nbuf_t next = qdf_nbuf_next(msdu); rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, msdu); + /* for HL, point to payload right now*/ + if (pdev->cfg.is_high_latency) + qdf_nbuf_pull_head(msdu, + htt_rx_msdu_rx_desc_size_hl(htt_pdev, rx_desc)); #ifdef QCA_SUPPORT_SW_TXRX_ENCAP info.is_msdu_cmpl_mpdu = diff --git a/core/dp/txrx/ol_rx_defrag.c b/core/dp/txrx/ol_rx_defrag.c index 11b9f5a1467b..74aaec2fcd21 100644 --- a/core/dp/txrx/ol_rx_defrag.c +++ b/core/dp/txrx/ol_rx_defrag.c @@ -104,16 +104,178 @@ const struct ol_rx_defrag_cipher f_wep = { 0, }; -inline struct ieee80211_frame *ol_rx_frag_get_mac_hdr( +#if defined(CONFIG_HL_SUPPORT) + +/** + * ol_rx_frag_get_mac_hdr() - retrieve mac header + * @htt_pdev: pointer to htt pdev handle + * @frag: rx fragment + * + * Return: pointer to ieee mac header of frag + */ +static struct ieee80211_frame *ol_rx_frag_get_mac_hdr( + htt_pdev_handle htt_pdev, qdf_nbuf_t frag) +{ + void *rx_desc; + int rx_desc_len; + + rx_desc = htt_rx_msdu_desc_retrieve(htt_pdev, frag); + rx_desc_len = htt_rx_msdu_rx_desc_size_hl(htt_pdev, rx_desc); + return (struct ieee80211_frame *)(qdf_nbuf_data(frag) + rx_desc_len); +} + +/** + * ol_rx_frag_pull_hdr() - point to payload of rx frag + * @htt_pdev: pointer to htt pdev handle + * @frag: rx fragment + * @hdrsize: header size + * + * Return: None + */ +static void ol_rx_frag_pull_hdr(htt_pdev_handle htt_pdev, + qdf_nbuf_t frag, int hdrsize) +{ + void *rx_desc; + int rx_desc_len; + + rx_desc = htt_rx_msdu_desc_retrieve(htt_pdev, frag); + rx_desc_len = htt_rx_msdu_rx_desc_size_hl(htt_pdev, rx_desc); + qdf_nbuf_pull_head(frag, rx_desc_len + hdrsize); +} + +/** + * ol_rx_frag_clone() - clone the rx frag + * @frag: rx fragment to clone from + * + * Return: cloned buffer + */ +static inline qdf_nbuf_t +ol_rx_frag_clone(qdf_nbuf_t frag) +{ + return qdf_nbuf_clone(frag); +} + +/** + * ol_rx_frag_desc_adjust() - adjust rx frag descriptor position + * @pdev: pointer to txrx handle + * @msdu: msdu + * @rx_desc_old_position: rx descriptor old position + * @ind_old_position:index of old position + * @rx_desc_len: rx desciptor length + * + * Return: None + */ +static void +ol_rx_frag_desc_adjust(ol_txrx_pdev_handle pdev, + qdf_nbuf_t msdu, + void **rx_desc_old_position, + void **ind_old_position, int *rx_desc_len) +{ + *rx_desc_old_position = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, + msdu); + *ind_old_position = *rx_desc_old_position - HTT_RX_IND_HL_BYTES; + *rx_desc_len = htt_rx_msdu_rx_desc_size_hl(pdev->htt_pdev, + *rx_desc_old_position); +} + +/** + * ol_rx_frag_restructure() - point to payload for HL + * @pdev: physical device object + * @msdu: the buffer containing the MSDU payload + * @rx_desc_old_position: rx MSDU descriptor + * @ind_old_position: rx msdu indication + * @f_type: pointing to rx defrag cipher + * @rx_desc_len: length by which rx descriptor to move + * + * Return: None + */ +static void +ol_rx_frag_restructure( + ol_txrx_pdev_handle pdev, + qdf_nbuf_t msdu, + void *rx_desc_old_position, + void *ind_old_position, + const struct ol_rx_defrag_cipher *f_type, + int rx_desc_len) +{ + if ((ind_old_position == NULL) || (rx_desc_old_position == NULL)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "ind_old_position,rx_desc_old_position is NULL\n"); + ASSERT(0); + return; + } + /* move rx description*/ + qdf_mem_move(rx_desc_old_position + f_type->ic_header, + rx_desc_old_position, rx_desc_len); + /* move rx indication*/ + qdf_mem_move(ind_old_position + f_type->ic_header, ind_old_position, + HTT_RX_IND_HL_BYTES); +} + +/** + * ol_rx_get_desc_len() - point to payload for HL + * @htt_pdev: the HTT instance the rx data was received on + * @wbuf: buffer containing the MSDU payload + * @rx_desc_old_position: rx MSDU descriptor + * + * Return: Return the HL rx desc size + */ +static +int ol_rx_get_desc_len(htt_pdev_handle htt_pdev, + qdf_nbuf_t wbuf, + void **rx_desc_old_position) +{ + int rx_desc_len = 0; + *rx_desc_old_position = htt_rx_msdu_desc_retrieve(htt_pdev, wbuf); + rx_desc_len = htt_rx_msdu_rx_desc_size_hl(htt_pdev, + *rx_desc_old_position); + + return rx_desc_len; +} + +/** + * ol_rx_defrag_push_rx_desc() - point to payload for HL + * @nbuf: buffer containing the MSDU payload + * @rx_desc_old_position: rx MSDU descriptor + * @ind_old_position: rx msdu indication + * @rx_desc_len: HL rx desc size + * + * Return: Return the HL rx desc size + */ +static +void ol_rx_defrag_push_rx_desc(qdf_nbuf_t nbuf, + void *rx_desc_old_position, + void *ind_old_position, + int rx_desc_len) +{ + qdf_nbuf_push_head(nbuf, rx_desc_len); + qdf_mem_move( + qdf_nbuf_data(nbuf), rx_desc_old_position, rx_desc_len); + qdf_mem_move( + qdf_nbuf_data(nbuf) - HTT_RX_IND_HL_BYTES, ind_old_position, + HTT_RX_IND_HL_BYTES); +} +#else + +static inline struct ieee80211_frame *ol_rx_frag_get_mac_hdr( htt_pdev_handle htt_pdev, qdf_nbuf_t frag) { return (struct ieee80211_frame *) qdf_nbuf_data(frag); } -#define ol_rx_frag_pull_hdr(pdev, frag, hdrsize) \ + +static inline void ol_rx_frag_pull_hdr(htt_pdev_handle htt_pdev, + qdf_nbuf_t frag, int hdrsize) +{ qdf_nbuf_pull_head(frag, hdrsize); -#define OL_RX_FRAG_CLONE(frag) NULL /* no-op */ +} + +static inline qdf_nbuf_t +ol_rx_frag_clone(qdf_nbuf_t frag) +{ + return NULL; +} static inline void ol_rx_frag_desc_adjust(ol_txrx_pdev_handle pdev, @@ -126,6 +288,38 @@ ol_rx_frag_desc_adjust(ol_txrx_pdev_handle pdev, *rx_desc_len = 0; } +static inline void +ol_rx_frag_restructure( + ol_txrx_pdev_handle pdev, + qdf_nbuf_t msdu, + void *rx_desc_old_position, + void *ind_old_position, + const struct ol_rx_defrag_cipher *f_type, + int rx_desc_len) +{ + /* no op */ + return; +} + +static inline +int ol_rx_get_desc_len(htt_pdev_handle htt_pdev, + qdf_nbuf_t wbuf, + void **rx_desc_old_position) +{ + return 0; +} + +static inline +void ol_rx_defrag_push_rx_desc(qdf_nbuf_t nbuf, + void *rx_desc_old_position, + void *ind_old_position, + int rx_desc_len) +{ + return; +} +#endif /* CONFIG_HL_SUPPORT */ + + /* * Process incoming fragments */ @@ -302,7 +496,7 @@ ol_rx_fraglist_insert(htt_pdev_handle htt_pdev, qdf_nbuf_t frag_clone; qdf_assert(frag); - frag_clone = OL_RX_FRAG_CLONE(frag); + frag_clone = ol_rx_frag_clone(frag); frag = frag_clone ? frag_clone : frag; mac_hdr = (struct ieee80211_frame *) @@ -608,6 +802,13 @@ ol_rx_frag_tkip_decap(ol_txrx_pdev_handle pdev, return OL_RX_DEFRAG_ERR; qdf_mem_move(origHdr + f_tkip.ic_header, origHdr, hdrlen); + ol_rx_frag_restructure( + pdev, + msdu, + rx_desc_old_position, + ind_old_position, + &f_tkip, + rx_desc_len); qdf_nbuf_pull_head(msdu, f_tkip.ic_header); qdf_nbuf_trim_tail(msdu, f_tkip.ic_trailer); return OL_RX_DEFRAG_OK; @@ -630,6 +831,13 @@ ol_rx_frag_wep_decap(ol_txrx_pdev_handle pdev, qdf_nbuf_t msdu, uint16_t hdrlen) &ind_old_position, &rx_desc_len); origHdr = (uint8_t *) (qdf_nbuf_data(msdu) + rx_desc_len); qdf_mem_move(origHdr + f_wep.ic_header, origHdr, hdrlen); + ol_rx_frag_restructure( + pdev, + msdu, + rx_desc_old_position, + ind_old_position, + &f_wep, + rx_desc_len); qdf_nbuf_pull_head(msdu, f_wep.ic_header); qdf_nbuf_trim_tail(msdu, f_wep.ic_trailer); return OL_RX_DEFRAG_OK; @@ -694,6 +902,13 @@ ol_rx_frag_ccmp_decap(ol_txrx_pdev_handle pdev, return OL_RX_DEFRAG_ERR; qdf_mem_move(origHdr + f_ccmp.ic_header, origHdr, hdrlen); + ol_rx_frag_restructure( + pdev, + nbuf, + rx_desc_old_position, + ind_old_position, + &f_ccmp, + rx_desc_len); qdf_nbuf_pull_head(nbuf, f_ccmp.ic_header); return OL_RX_DEFRAG_OK; @@ -788,6 +1003,7 @@ ol_rx_defrag_mic(ol_txrx_pdev_handle pdev, void *rx_desc_old_position = NULL; void *ind_old_position = NULL; int rx_desc_len = 0; + htt_pdev_handle htt_pdev = pdev->htt_pdev; ol_rx_frag_desc_adjust(pdev, wbuf, @@ -831,7 +1047,8 @@ ol_rx_defrag_mic(ol_txrx_pdev_handle pdev, if (wbuf == NULL) return OL_RX_DEFRAG_ERR; - rx_desc_len = 0; + rx_desc_len = ol_rx_get_desc_len(htt_pdev, wbuf, + &rx_desc_old_position); if (space != 0) { const uint8_t *data_next; @@ -1008,6 +1225,9 @@ void ol_rx_defrag_nwifi_to_8023(ol_txrx_pdev_handle pdev, qdf_nbuf_t msdu) qdf_mem_copy(eth_hdr->ethertype, llchdr.ethertype, sizeof(llchdr.ethertype)); + + ol_rx_defrag_push_rx_desc(msdu, rx_desc_old_position, + ind_old_position, rx_desc_len); } /* @@ -1058,5 +1278,8 @@ ol_rx_defrag_qos_decap(ol_txrx_pdev_handle pdev, if (wh) wh->i_fc[0] &= ~IEEE80211_FC0_SUBTYPE_QOS; + ol_rx_defrag_push_rx_desc(nbuf, rx_desc_old_position, + ind_old_position, rx_desc_len); + } } diff --git a/core/dp/txrx/ol_rx_fwd.c b/core/dp/txrx/ol_rx_fwd.c index 7d33ae3cafce..589f9d2e8e1f 100644 --- a/core/dp/txrx/ol_rx_fwd.c +++ b/core/dp/txrx/ol_rx_fwd.c @@ -121,7 +121,18 @@ static inline void ol_rx_fwd_to_tx(struct ol_txrx_vdev_t *vdev, qdf_nbuf_t msdu) */ qdf_nbuf_set_next(msdu, NULL); /* add NULL terminator */ - msdu = OL_TX_LL(vdev, msdu); + /* for HL, point to payload before send to tx again.*/ + if (pdev->cfg.is_high_latency) { + void *rx_desc; + + rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, + msdu); + qdf_nbuf_pull_head(msdu, + htt_rx_msdu_rx_desc_size_hl(pdev->htt_pdev, + rx_desc)); + } + + msdu = OL_TX_SEND(vdev, msdu); if (msdu) { /* @@ -131,6 +142,7 @@ static inline void ol_rx_fwd_to_tx(struct ol_txrx_vdev_t *vdev, qdf_nbuf_t msdu) */ qdf_nbuf_tx_free(msdu, QDF_NBUF_PKT_ERROR); } + return; } void @@ -232,6 +244,7 @@ ol_rx_fwd_check(struct ol_txrx_vdev_t *vdev, ol_rx_deliver(vdev, peer, tid, deliver_list_head); } } + return; } /* diff --git a/core/dp/txrx/ol_tx.c b/core/dp/txrx/ol_tx.c index 789dae36d7bb..c2c79fb0b232 100644 --- a/core/dp/txrx/ol_tx.c +++ b/core/dp/txrx/ol_tx.c @@ -41,7 +41,10 @@ #include <ol_txrx.h> /* internal header files relevant only for HL systems */ +#include <ol_tx_classify.h> /* ol_tx_classify, ol_tx_classify_mgmt */ #include <ol_tx_queue.h> /* ol_tx_enqueue */ +#include <ol_tx_sched.h> /* ol_tx_sched */ + /* internal header files relevant only for specific systems (Pronto) */ #include <ol_txrx_encap.h> /* OL_TX_ENCAP, etc */ @@ -165,7 +168,7 @@ qdf_nbuf_t ol_tx_data(ol_txrx_vdev_handle vdev, qdf_nbuf_t skb) /* Terminate the (single-element) list of tx frames */ qdf_nbuf_set_next(skb, NULL); - ret = OL_TX_LL(vdev, skb); + ret = OL_TX_SEND(vdev, skb); if (ret) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_WARN, "%s: Failed to tx", __func__); @@ -202,7 +205,7 @@ qdf_nbuf_t ol_tx_send_ipa_data_frame(void *vdev, /* Terminate the (single-element) list of tx frames */ qdf_nbuf_set_next(skb, NULL); - ret = OL_TX_LL((struct ol_txrx_vdev_t *)vdev, skb); + ret = OL_TX_SEND((struct ol_txrx_vdev_t *)vdev, skb); if (ret) { TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, "%s: Failed to tx", __func__); @@ -1041,7 +1044,8 @@ static inline uint8_t ol_txrx_tx_raw_subtype(enum ol_tx_spec tx_spec) qdf_nbuf_t ol_tx_non_std_ll(ol_txrx_vdev_handle vdev, - enum ol_tx_spec tx_spec, qdf_nbuf_t msdu_list) + enum ol_tx_spec tx_spec, + qdf_nbuf_t msdu_list) { qdf_nbuf_t msdu = msdu_list; htt_pdev_handle htt_pdev = vdev->pdev->htt_pdev; @@ -1082,14 +1086,14 @@ ol_tx_non_std_ll(ol_txrx_vdev_handle vdev, uint8_t sub_type = ol_txrx_tx_raw_subtype(tx_spec); htt_tx_desc_type(htt_pdev, tx_desc->htt_tx_desc, - htt_pkt_type_native_wifi, - sub_type); + htt_pkt_type_native_wifi, + sub_type); } else if (ol_txrx_tx_is_raw(tx_spec)) { /* different types of raw frames */ uint8_t sub_type = ol_txrx_tx_raw_subtype(tx_spec); htt_tx_desc_type(htt_pdev, tx_desc->htt_tx_desc, - htt_pkt_type_raw, sub_type); + htt_pkt_type_raw, sub_type); } } /* @@ -1125,9 +1129,10 @@ ol_tx_non_std_ll(ol_txrx_vdev_handle vdev, /** * parse_ocb_tx_header() - Function to check for OCB - * TX control header on a packet and extract it if present - * * @msdu: Pointer to OS packet (qdf_nbuf_t) + * @tx_ctrl: TX control header on a packet and extract it if present + * + * Return: true if ocb parsing is successful */ #define OCB_HEADER_VERSION 1 bool parse_ocb_tx_header(qdf_nbuf_t msdu, @@ -1137,7 +1142,7 @@ bool parse_ocb_tx_header(qdf_nbuf_t msdu, struct ocb_tx_ctrl_hdr_t *tx_ctrl_hdr; /* Check if TX control header is present */ - eth_hdr_p = (struct ether_header *) qdf_nbuf_data(msdu); + eth_hdr_p = (struct ether_header *)qdf_nbuf_data(msdu); if (eth_hdr_p->ether_type != QDF_SWAP_U16(ETHERTYPE_OCB_TX)) /* TX control header is not present. Nothing to do.. */ return true; @@ -1146,12 +1151,12 @@ bool parse_ocb_tx_header(qdf_nbuf_t msdu, qdf_nbuf_pull_head(msdu, sizeof(struct ether_header)); /* Parse the TX control header */ - tx_ctrl_hdr = (struct ocb_tx_ctrl_hdr_t *) qdf_nbuf_data(msdu); + tx_ctrl_hdr = (struct ocb_tx_ctrl_hdr_t *)qdf_nbuf_data(msdu); if (tx_ctrl_hdr->version == OCB_HEADER_VERSION) { if (tx_ctrl) qdf_mem_copy(tx_ctrl, tx_ctrl_hdr, - sizeof(*tx_ctrl_hdr)); + sizeof(*tx_ctrl_hdr)); } else { /* The TX control header is invalid. */ return false; @@ -1162,6 +1167,440 @@ bool parse_ocb_tx_header(qdf_nbuf_t msdu, return true; } + +#if defined(CONFIG_HL_SUPPORT) && defined(CONFIG_TX_DESC_HI_PRIO_RESERVE) + +/** + * ol_tx_hl_desc_alloc() - Allocate and initialize a tx descriptor + * for a HL system. + * @pdev: the data physical device sending the data + * @vdev: the virtual device sending the data + * @msdu: the tx frame + * @msdu_info: the tx meta data + * + * Return: the tx decriptor + */ +static inline +struct ol_tx_desc_t *ol_tx_hl_desc_alloc(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t msdu, + struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ol_tx_desc_t *tx_desc = NULL; + + if (qdf_atomic_read(&pdev->tx_queue.rsrc_cnt) > + TXRX_HL_TX_DESC_HI_PRIO_RESERVED) { + tx_desc = ol_tx_desc_hl(pdev, vdev, msdu, msdu_info); + } else if (qdf_nbuf_is_ipv4_pkt(msdu) == true) { + if ((qdf_nbuf_is_ipv4_dhcp_pkt(msdu) == true) || + (qdf_nbuf_is_ipv4_eapol_pkt(msdu) == true)) { + tx_desc = ol_tx_desc_hl(pdev, vdev, msdu, msdu_info); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Provided tx descriptor from reserve pool for DHCP/EAPOL\n"); + } + } + return tx_desc; +} +#else + +static inline +struct ol_tx_desc_t *ol_tx_hl_desc_alloc(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t msdu, + struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ol_tx_desc_t *tx_desc = NULL; + tx_desc = ol_tx_desc_hl(pdev, vdev, msdu, msdu_info); + return tx_desc; +} +#endif + +#if defined(CONFIG_HL_SUPPORT) + +/** + * ol_txrx_mgmt_tx_desc_alloc() - Allocate and initialize a tx descriptor + * for management frame + * @pdev: the data physical device sending the data + * @vdev: the virtual device sending the data + * @tx_mgmt_frm: the tx managment frame + * @tx_msdu_info: the tx meta data + * + * Return: the tx decriptor + */ +static inline +struct ol_tx_desc_t * +ol_txrx_mgmt_tx_desc_alloc( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t tx_mgmt_frm, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + struct ol_tx_desc_t *tx_desc; + tx_msdu_info->htt.action.tx_comp_req = 1; + tx_desc = ol_tx_desc_hl(pdev, vdev, tx_mgmt_frm, tx_msdu_info); + return tx_desc; +} + +/** + * ol_txrx_mgmt_send_frame() - send a management frame + * @vdev: virtual device sending the frame + * @tx_desc: tx desc + * @tx_mgmt_frm: management frame to send + * @tx_msdu_info: the tx meta data + * @chanfreq: download change frequency + * + * Return: + * 0 -> the frame is accepted for transmission, -OR- + * 1 -> the frame was not accepted + */ +static inline +int ol_txrx_mgmt_send_frame( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t tx_mgmt_frm, + struct ol_txrx_msdu_info_t *tx_msdu_info, + uint16_t chanfreq) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + struct ol_tx_frms_queue_t *txq; + /* + * 1. Look up the peer and queue the frame in the peer's mgmt queue. + * 2. Invoke the download scheduler. + */ + txq = ol_tx_classify_mgmt(vdev, tx_desc, tx_mgmt_frm, tx_msdu_info); + if (!txq) { + /*TXRX_STATS_MSDU_LIST_INCR(vdev->pdev, tx.dropped.no_txq, + msdu);*/ + qdf_atomic_inc(&pdev->tx_queue.rsrc_cnt); + ol_tx_desc_frame_free_nonstd(vdev->pdev, tx_desc, + 1 /* error */); + if (tx_msdu_info->peer) { + /* remove the peer reference added above */ + ol_txrx_peer_unref_delete(tx_msdu_info->peer); + } + return 1; /* can't accept the tx mgmt frame */ + } + /* Initialize the HTT tx desc l2 header offset field. + * Even though tx encap does not apply to mgmt frames, + * htt_tx_desc_mpdu_header still needs to be called, + * to specifiy that there was no L2 header added by tx encap, + * so the frame's length does not need to be adjusted to account for + * an added L2 header. + */ + htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, 0); + htt_tx_desc_init( + pdev->htt_pdev, tx_desc->htt_tx_desc, + tx_desc->htt_tx_desc_paddr, + ol_tx_desc_id(pdev, tx_desc), + tx_mgmt_frm, + &tx_msdu_info->htt, &tx_msdu_info->tso_info, NULL, 0); + htt_tx_desc_display(tx_desc->htt_tx_desc); + htt_tx_desc_set_chanfreq(tx_desc->htt_tx_desc, chanfreq); + + ol_tx_enqueue(vdev->pdev, txq, tx_desc, tx_msdu_info); + if (tx_msdu_info->peer) { + /* remove the peer reference added above */ + ol_txrx_peer_unref_delete(tx_msdu_info->peer); + } + ol_tx_sched(vdev->pdev); + + return 0; +} + +#else + +static inline +struct ol_tx_desc_t * +ol_txrx_mgmt_tx_desc_alloc( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t tx_mgmt_frm, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + struct ol_tx_desc_t *tx_desc; + /* For LL tx_comp_req is not used so initialized to 0 */ + tx_msdu_info->htt.action.tx_comp_req = 0; + tx_desc = ol_tx_desc_ll(pdev, vdev, tx_mgmt_frm, tx_msdu_info); + /* FIX THIS - + * The FW currently has trouble using the host's fragments table + * for management frames. Until this is fixed, rather than + * specifying the fragment table to the FW, specify just the + * address of the initial fragment. + */ +#if defined(HELIUMPLUS_PADDR64) + /* dump_frag_desc("ol_txrx_mgmt_send(): after ol_tx_desc_ll", + tx_desc); */ +#endif /* defined(HELIUMPLUS_PADDR64) */ + if (tx_desc) { + /* + * Following the call to ol_tx_desc_ll, frag 0 is the + * HTT tx HW descriptor, and the frame payload is in + * frag 1. + */ + htt_tx_desc_frags_table_set( + pdev->htt_pdev, + tx_desc->htt_tx_desc, + qdf_nbuf_get_frag_paddr(tx_mgmt_frm, 1), + 0, 0); +#if defined(HELIUMPLUS_PADDR64) && defined(HELIUMPLUS_DEBUG) + dump_frag_desc( + "after htt_tx_desc_frags_table_set", + tx_desc); +#endif /* defined(HELIUMPLUS_PADDR64) */ + } + + return tx_desc; +} + +static inline +int ol_txrx_mgmt_send_frame( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t tx_mgmt_frm, + struct ol_txrx_msdu_info_t *tx_msdu_info, + uint16_t chanfreq) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + htt_tx_desc_set_chanfreq(tx_desc->htt_tx_desc, chanfreq); + QDF_NBUF_CB_TX_PACKET_TRACK(tx_desc->netbuf) = + QDF_NBUF_TX_PKT_MGMT_TRACK; + ol_tx_send_nonstd(pdev, tx_desc, tx_mgmt_frm, + htt_pkt_type_mgmt); + + return 0; +} +#endif + +/** + * ol_tx_hl_base() - send tx frames for a HL system. + * @vdev: the virtual device sending the data + * @tx_spec: indicate what non-standard transmission actions to apply + * @msdu_list: the tx frames to send + * @tx_comp_req: tx completion req + * + * Return: NULL if all MSDUs are accepted + */ +static inline qdf_nbuf_t +ol_tx_hl_base( + ol_txrx_vdev_handle vdev, + enum ol_tx_spec tx_spec, + qdf_nbuf_t msdu_list, + int tx_comp_req) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + qdf_nbuf_t msdu = msdu_list; + struct ol_txrx_msdu_info_t tx_msdu_info; + struct ocb_tx_ctrl_hdr_t tx_ctrl; + + htt_pdev_handle htt_pdev = pdev->htt_pdev; + tx_msdu_info.peer = NULL; + tx_msdu_info.tso_info.is_tso = 0; + + /* + * The msdu_list variable could be used instead of the msdu var, + * but just to clarify which operations are done on a single MSDU + * vs. a list of MSDUs, use a distinct variable for single MSDUs + * within the list. + */ + while (msdu) { + qdf_nbuf_t next; + struct ol_tx_frms_queue_t *txq; + struct ol_tx_desc_t *tx_desc = NULL; + + qdf_mem_zero(&tx_ctrl, sizeof(tx_ctrl)); + + /* + * The netbuf will get stored into a (peer-TID) tx queue list + * inside the ol_tx_classify_store function or else dropped, + * so store the next pointer immediately. + */ + next = qdf_nbuf_next(msdu); + + tx_desc = ol_tx_hl_desc_alloc(pdev, vdev, msdu, &tx_msdu_info); + + if (!tx_desc) { + /* + * If we're out of tx descs, there's no need to try + * to allocate tx descs for the remaining MSDUs. + */ + TXRX_STATS_MSDU_LIST_INCR(pdev, tx.dropped.host_reject, + msdu); + return msdu; /* the list of unaccepted MSDUs */ + } + + /* OL_TXRX_PROT_AN_LOG(pdev->prot_an_tx_sent, msdu);*/ + + if (tx_spec != OL_TX_SPEC_STD) { +#if defined(FEATURE_WLAN_TDLS) + if (tx_spec & OL_TX_SPEC_NO_FREE) { + tx_desc->pkt_type = OL_TX_FRM_NO_FREE; + } else if (tx_spec & OL_TX_SPEC_TSO) { +#else + if (tx_spec & OL_TX_SPEC_TSO) { +#endif + tx_desc->pkt_type = OL_TX_FRM_TSO; + } + if (ol_txrx_tx_is_raw(tx_spec)) { + /* CHECK THIS: does this need + * to happen after htt_tx_desc_init? + */ + /* different types of raw frames */ + u_int8_t sub_type = + ol_txrx_tx_raw_subtype( + tx_spec); + htt_tx_desc_type(htt_pdev, + tx_desc->htt_tx_desc, + htt_pkt_type_raw, + sub_type); + } + } + + tx_msdu_info.htt.info.ext_tid = qdf_nbuf_get_tid(msdu); + tx_msdu_info.htt.info.vdev_id = vdev->vdev_id; + tx_msdu_info.htt.info.frame_type = htt_frm_type_data; + tx_msdu_info.htt.info.l2_hdr_type = pdev->htt_pkt_type; + tx_msdu_info.htt.action.tx_comp_req = tx_comp_req; + + /* If the vdev is in OCB mode, + * parse the tx control header. + */ + if (vdev->opmode == wlan_op_mode_ocb) { + if (!parse_ocb_tx_header(msdu, &tx_ctrl)) { + /* There was an error parsing + * the header.Skip this packet. + */ + goto MSDU_LOOP_BOTTOM; + } + } + + txq = ol_tx_classify(vdev, tx_desc, msdu, + &tx_msdu_info); + + if ((!txq) || TX_FILTER_CHECK(&tx_msdu_info)) { + /* drop this frame, + * but try sending subsequent frames + */ + /*TXRX_STATS_MSDU_LIST_INCR(pdev, + tx.dropped.no_txq, + msdu);*/ + qdf_atomic_inc(&pdev->tx_queue.rsrc_cnt); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1); + if (tx_msdu_info.peer) { + /* remove the peer reference + * added above */ + ol_txrx_peer_unref_delete( + tx_msdu_info.peer); + } + goto MSDU_LOOP_BOTTOM; + } + + if (tx_msdu_info.peer) { + /*If the state is not associated then drop all + *the data packets received for that peer*/ + if (tx_msdu_info.peer->state == + OL_TXRX_PEER_STATE_DISC) { + qdf_atomic_inc( + &pdev->tx_queue.rsrc_cnt); + ol_tx_desc_frame_free_nonstd(pdev, + tx_desc, + 1); + ol_txrx_peer_unref_delete( + tx_msdu_info.peer); + msdu = next; + continue; + } else if (tx_msdu_info.peer->state != + OL_TXRX_PEER_STATE_AUTH) { + if (tx_msdu_info.htt.info.ethertype != + ETHERTYPE_PAE && + tx_msdu_info.htt.info.ethertype + != ETHERTYPE_WAI) { + qdf_atomic_inc( + &pdev->tx_queue. + rsrc_cnt); + ol_tx_desc_frame_free_nonstd( + pdev, + tx_desc, 1); + ol_txrx_peer_unref_delete( + tx_msdu_info.peer); + msdu = next; + continue; + } + } + } + /* + * Initialize the HTT tx desc l2 header offset field. + * htt_tx_desc_mpdu_header needs to be called to + * make sure, the l2 header size is initialized + * correctly to handle cases where TX ENCAP is disabled + * or Tx Encap fails to perform Encap + */ + htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, 0); + + /* + * Note: when the driver is built without support for + * SW tx encap,the following macro is a no-op. + * When the driver is built with support for SW tx + * encap, it performs encap, and if an error is + * encountered, jumps to the MSDU_LOOP_BOTTOM label. + */ + OL_TX_ENCAP_WRAPPER(pdev, vdev, tx_desc, msdu, + tx_msdu_info); + + /* initialize the HW tx descriptor */ + htt_tx_desc_init( + pdev->htt_pdev, tx_desc->htt_tx_desc, + tx_desc->htt_tx_desc_paddr, + ol_tx_desc_id(pdev, tx_desc), + msdu, + &tx_msdu_info.htt, + &tx_msdu_info.tso_info, + &tx_ctrl, + vdev->opmode == wlan_op_mode_ocb); + /* + * If debug display is enabled, show the meta-data + * being downloaded to the target via the + * HTT tx descriptor. + */ + htt_tx_desc_display(tx_desc->htt_tx_desc); + + ol_tx_enqueue(pdev, txq, tx_desc, &tx_msdu_info); + if (tx_msdu_info.peer) { + OL_TX_PEER_STATS_UPDATE(tx_msdu_info.peer, + msdu); + /* remove the peer reference added above */ + ol_txrx_peer_unref_delete(tx_msdu_info.peer); + } +MSDU_LOOP_BOTTOM: + msdu = next; + } + ol_tx_sched(pdev); + return NULL; /* all MSDUs were accepted */ +} + +qdf_nbuf_t +ol_tx_hl(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + int tx_comp_req = pdev->cfg.default_tx_comp_req; + return ol_tx_hl_base(vdev, OL_TX_SPEC_STD, msdu_list, tx_comp_req); +} + +qdf_nbuf_t +ol_tx_non_std_hl(ol_txrx_vdev_handle vdev, + enum ol_tx_spec tx_spec, + qdf_nbuf_t msdu_list) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + int tx_comp_req = pdev->cfg.default_tx_comp_req; + + if (!tx_comp_req) { + if ((tx_spec == OL_TX_SPEC_NO_FREE) && + (pdev->tx_data_callback.func)) + tx_comp_req = 1; + } + return ol_tx_hl_base(vdev, tx_spec, msdu_list, tx_comp_req); +} + /** * ol_tx_non_std - Allow the control-path SW to send data frames * @@ -1188,7 +1627,10 @@ qdf_nbuf_t ol_tx_non_std(ol_txrx_vdev_handle vdev, enum ol_tx_spec tx_spec, qdf_nbuf_t msdu_list) { - return ol_tx_non_std_ll(vdev, tx_spec, msdu_list); + if (vdev->pdev->cfg.is_high_latency) + return ol_tx_non_std_hl(vdev, tx_spec, msdu_list); + else + return ol_tx_non_std_ll(vdev, tx_spec, msdu_list); } void @@ -1297,7 +1739,7 @@ ol_txrx_mgmt_send_ext(ol_txrx_vdev_handle vdev, struct ol_txrx_pdev_t *pdev = vdev->pdev; struct ol_tx_desc_t *tx_desc; struct ol_txrx_msdu_info_t tx_msdu_info; - + int result = 0; tx_msdu_info.tso_info.is_tso = 0; tx_msdu_info.htt.action.use_6mbps = use_6mbps; @@ -1348,37 +1790,8 @@ ol_txrx_mgmt_send_ext(ol_txrx_vdev_handle vdev, tx_msdu_info.peer = NULL; - - /* For LL tx_comp_req is not used so initialized to 0 */ - tx_msdu_info.htt.action.tx_comp_req = 0; - tx_desc = ol_tx_desc_ll(pdev, vdev, tx_mgmt_frm, &tx_msdu_info); - /* FIX THIS - - * The FW currently has trouble using the host's fragments table - * for management frames. Until this is fixed, rather than - * specifying the fragment table to the FW, specify just the - * address of the initial fragment. - */ -#if defined(HELIUMPLUS_PADDR64) - /* dump_frag_desc("ol_txrx_mgmt_send(): after ol_tx_desc_ll", - tx_desc); */ -#endif /* defined(HELIUMPLUS_PADDR64) */ - if (tx_desc) { - /* - * Following the call to ol_tx_desc_ll, frag 0 is the - * HTT tx HW descriptor, and the frame payload is in - * frag 1. - */ - htt_tx_desc_frags_table_set( - pdev->htt_pdev, - tx_desc->htt_tx_desc, - qdf_nbuf_get_frag_paddr(tx_mgmt_frm, 1), - 0, 0); -#if defined(HELIUMPLUS_PADDR64) && defined(HELIUMPLUS_DEBUG) - dump_frag_desc( - "after htt_tx_desc_frags_table_set", - tx_desc); -#endif /* defined(HELIUMPLUS_PADDR64) */ - } + tx_desc = ol_txrx_mgmt_tx_desc_alloc(pdev, vdev, tx_mgmt_frm, + &tx_msdu_info); if (!tx_desc) return -EINVAL; /* can't accept the tx mgmt frame */ @@ -1386,11 +1799,8 @@ ol_txrx_mgmt_send_ext(ol_txrx_vdev_handle vdev, TXRX_ASSERT1(type < OL_TXRX_MGMT_NUM_TYPES); tx_desc->pkt_type = type + OL_TXRX_MGMT_TYPE_BASE; - htt_tx_desc_set_chanfreq(tx_desc->htt_tx_desc, chanfreq); - QDF_NBUF_CB_TX_PACKET_TRACK(tx_desc->netbuf) = - QDF_NBUF_TX_PKT_MGMT_TRACK; - ol_tx_send_nonstd(pdev, tx_desc, tx_mgmt_frm, - htt_pkt_type_mgmt); + result = ol_txrx_mgmt_send_frame(vdev, tx_desc, tx_mgmt_frm, + &tx_msdu_info, chanfreq); return 0; /* accepted the tx mgmt frame */ } diff --git a/core/dp/txrx/ol_tx.h b/core/dp/txrx/ol_tx.h index d90e44d697e5..561900a71dcd 100644 --- a/core/dp/txrx/ol_tx.h +++ b/core/dp/txrx/ol_tx.h @@ -47,6 +47,12 @@ qdf_nbuf_t ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list); qdf_nbuf_t ol_tx_ll_queue(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list); +#ifdef CONFIG_HL_SUPPORT +#define OL_TX_SEND ol_tx_hl +#else +#define OL_TX_SEND OL_TX_LL +#endif + #ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL #define OL_TX_LL ol_tx_ll_queue #else @@ -67,6 +73,29 @@ void ol_tx_pdev_ll_pause_queue_send_all(struct ol_txrx_pdev_t *pdev) return; } #endif + +/** + * ol_tx_non_std_hl() - send non std tx frame. + * @vdev: the virtual device sending the data + * @tx_spec: indicate what non-standard transmission actions to apply + * @msdu_list: the tx frames to send + * + * Return: NULL if all MSDUs are accepted + */ +qdf_nbuf_t +ol_tx_non_std_hl(ol_txrx_vdev_handle data_vdev, + enum ol_tx_spec tx_spec, qdf_nbuf_t msdu_list); + +/** + * ol_tx_hl() - transmit tx frames for a HL system. + * @vdev: the virtual device transmit the data + * @msdu_list: the tx frames to send + * + * Return: NULL if all MSDUs are accepted + */ +qdf_nbuf_t +ol_tx_hl(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list); + qdf_nbuf_t ol_tx_non_std_ll(ol_txrx_vdev_handle data_vdev, enum ol_tx_spec tx_spec, qdf_nbuf_t msdu_list); diff --git a/core/dp/txrx/ol_tx_classify.c b/core/dp/txrx/ol_tx_classify.c new file mode 100644 index 000000000000..879b21946b65 --- /dev/null +++ b/core/dp/txrx/ol_tx_classify.c @@ -0,0 +1,888 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include <qdf_nbuf.h> /* qdf_nbuf_t, etc. */ +#include <htt.h> /* HTT_TX_EXT_TID_MGMT */ +#include <ol_htt_tx_api.h> /* htt_tx_desc_tid */ +#include <ol_txrx_api.h> /* ol_txrx_vdev_handle */ +#include <ol_txrx_ctrl_api.h> /* ol_txrx_sync */ +#include <ol_txrx.h> +#include <ol_txrx_internal.h> /* TXRX_ASSERT1 */ +#include <ol_txrx_types.h> /* pdev stats */ +#include <ol_tx_desc.h> /* ol_tx_desc */ +#include <ol_tx_send.h> /* ol_tx_send */ +#include <ol_txrx_peer_find.h> +#include <ol_tx_classify.h> +#include <ol_tx_queue.h> +#include <ipv4.h> +#include <ipv6_defs.h> +#include <ip_prot.h> +#include <enet.h> /* ETHERTYPE_VLAN, etc. */ +#include <cds_ieee80211_common.h> /* ieee80211_frame */ + +/* + * In theory, this tx classify code could be used on the host or in the target. + * Thus, this code uses generic OS primitives, that can be aliased to either + * the host's OS primitives or the target's OS primitives. + * For now, the following #defines set up these host-specific or + * target-specific aliases. + */ + +#if defined(CONFIG_HL_SUPPORT) + +#define OL_TX_CLASSIFY_EXTENSION(vdev, tx_desc, netbuf, msdu_info, txq) +#define OL_TX_CLASSIFY_MGMT_EXTENSION(vdev, tx_desc, netbuf, msdu_info, txq) + +#ifdef QCA_TX_HTT2_SUPPORT +static void +ol_tx_classify_htt2_frm( + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t tx_nbuf, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + struct htt_msdu_info_t *htt = &tx_msdu_info->htt; + A_UINT8 candi_frm = 0; + + /* + * Offload the frame re-order to L3 protocol and ONLY support + * TCP protocol now. + */ + if ((htt->info.l2_hdr_type == htt_pkt_type_ethernet) && + (htt->info.frame_type == htt_frm_type_data) && + htt->info.is_unicast && + (htt->info.ethertype == ETHERTYPE_IPV4)) { + struct ipv4_hdr_t *ipHdr; + + ipHdr = (struct ipv4_hdr_t *)(qdf_nbuf_data(tx_nbuf) + + htt->info.l3_hdr_offset); + if (ipHdr->protocol == IP_PROTOCOL_TCP) + candi_frm = 1; + } + + qdf_nbuf_set_tx_parallel_dnload_frm(tx_nbuf, candi_frm); +} + +#define OL_TX_CLASSIFY_HTT2_EXTENSION(vdev, netbuf, msdu_info) \ + ol_tx_classify_htt2_frm(vdev, netbuf, msdu_info); +#else +#define OL_TX_CLASSIFY_HTT2_EXTENSION(vdev, netbuf, msdu_info) /* no-op */ +#endif /* QCA_TX_HTT2_SUPPORT */ +/* DHCP go with voice priority; WMM_AC_VO_TID1();*/ +#define TX_DHCP_TID 6 + +#if defined(QCA_BAD_PEER_TX_FLOW_CL) +static inline A_BOOL +ol_if_tx_bad_peer_txq_overflow( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + struct ol_tx_frms_queue_t *txq) +{ + if (peer && pdev && txq && (peer->tx_limit_flag) && + (txq->frms >= pdev->tx_peer_bal.peer_bal_txq_limit)) + return true; + else + return false; +} +#else +static inline A_BOOL ol_if_tx_bad_peer_txq_overflow( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + struct ol_tx_frms_queue_t *txq) +{ + return false; +} +#endif + +/* EAPOL go with voice priority: WMM_AC_TO_TID1(WMM_AC_VO);*/ +#define TX_EAPOL_TID 6 + +/* ARP go with voice priority: WMM_AC_TO_TID1(pdev->arp_ac_override)*/ +#define TX_ARP_TID 6 + +/* For non-IP case, use default TID */ +#define TX_DEFAULT_TID 0 + +/* + * Determine IP TOS priority + * IP Tos format : + * (Refer Pg 57 WMM-test-plan-v1.2) + * IP-TOS - 8bits + * : DSCP(6-bits) ECN(2-bits) + * : DSCP - P2 P1 P0 X X X + * where (P2 P1 P0) form 802.1D + */ +static inline A_UINT8 +ol_tx_tid_by_ipv4(A_UINT8 *pkt) +{ + A_UINT8 ipPri, tid; + struct ipv4_hdr_t *ipHdr = (struct ipv4_hdr_t *)pkt; + + ipPri = ipHdr->tos >> 5; + tid = ipPri & 0x7; + + return tid; +} + +static inline A_UINT8 +ol_tx_tid_by_ipv6(A_UINT8 *pkt) +{ + return (ipv6_traffic_class((struct ipv6_hdr_t *)pkt) >> 5) & 0x7; +} + +static inline void +ol_tx_set_ether_type( + A_UINT8 *datap, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + A_UINT16 typeorlength; + A_UINT8 *ptr; + A_UINT8 *l3_data_ptr; + + if (tx_msdu_info->htt.info.l2_hdr_type == htt_pkt_type_raw) { + /* adjust hdr_ptr to RA */ + struct ieee80211_frame *wh = (struct ieee80211_frame *)datap; + + if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == + IEEE80211_FC0_TYPE_DATA) { + struct llc_snap_hdr_t *llc; + /* dot11 encapsulated frame */ + struct ieee80211_qosframe *whqos = + (struct ieee80211_qosframe *)datap; + if (whqos->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) { + tx_msdu_info->htt.info.l3_hdr_offset = + sizeof(struct ieee80211_qosframe); + } else { + tx_msdu_info->htt.info.l3_hdr_offset = + sizeof(struct ieee80211_frame); + } + llc = (struct llc_snap_hdr_t *) + (datap + tx_msdu_info->htt.info.l3_hdr_offset); + tx_msdu_info->htt.info.ethertype = + (llc->ethertype[0] << 8) | llc->ethertype[1]; + /* + * l3_hdr_offset refers to the end of the 802.3 or + * 802.11 header, which may be a LLC/SNAP header rather + * than the IP header. + * Thus, don't increment l3_hdr_offset += sizeof(*llc); + * rather,leave it as is. + */ + } else { + /* + * This function should only be applied to data frames. + * For management frames, we already know to use + * HTT_TX_EXT_TID_MGMT. + */ + TXRX_ASSERT2(0); + } + } else if (tx_msdu_info->htt.info.l2_hdr_type == + htt_pkt_type_ethernet) { + ptr = (datap + ETHERNET_ADDR_LEN * 2); + typeorlength = (ptr[0] << 8) | ptr[1]; + /*ETHERNET_HDR_LEN;*/ + l3_data_ptr = datap + sizeof(struct ethernet_hdr_t); + + if (typeorlength == ETHERTYPE_VLAN) { + ptr = (datap + ETHERNET_ADDR_LEN * 2 + + ETHERTYPE_VLAN_LEN); + typeorlength = (ptr[0] << 8) | ptr[1]; + l3_data_ptr += ETHERTYPE_VLAN_LEN; + } + + if (!IS_ETHERTYPE(typeorlength)) { + /* 802.3 header*/ + struct llc_snap_hdr_t *llc_hdr = + (struct llc_snap_hdr_t *)l3_data_ptr; + typeorlength = (llc_hdr->ethertype[0] << 8) | + llc_hdr->ethertype[1]; + l3_data_ptr += sizeof(struct llc_snap_hdr_t); + } + + tx_msdu_info->htt.info.l3_hdr_offset = (A_UINT8)(l3_data_ptr - + datap); + tx_msdu_info->htt.info.ethertype = typeorlength; + } +} + +static inline A_UINT8 +ol_tx_tid_by_ether_type( + A_UINT8 *datap, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + A_UINT8 tid; + A_UINT8 *l3_data_ptr; + A_UINT16 typeorlength; + + l3_data_ptr = datap + tx_msdu_info->htt.info.l3_hdr_offset; + typeorlength = tx_msdu_info->htt.info.ethertype; + + /* IP packet, do packet inspection for TID */ + if (typeorlength == ETHERTYPE_IPV4) { + tid = ol_tx_tid_by_ipv4(l3_data_ptr); + } else if (typeorlength == ETHERTYPE_IPV6) { + tid = ol_tx_tid_by_ipv6(l3_data_ptr); + } else if (ETHERTYPE_IS_EAPOL_WAPI(typeorlength)) { + /* EAPOL go with voice priority*/ + tid = TX_EAPOL_TID; + } else if (typeorlength == ETHERTYPE_ARP) { + tid = TX_ARP_TID; + } else { + /* For non-IP case, use default TID */ + tid = TX_DEFAULT_TID; + } + return tid; +} + +static inline A_UINT8 +ol_tx_tid_by_raw_type( + A_UINT8 *datap, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + A_UINT8 tid = HTT_TX_EXT_TID_NON_QOS_MCAST_BCAST; + + /* adjust hdr_ptr to RA */ + struct ieee80211_frame *wh = (struct ieee80211_frame *)datap; + + /* FIXME: This code does not handle 4 address formats. The QOS field + * is not at usual location. + */ + if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == + IEEE80211_FC0_TYPE_DATA) { + /* dot11 encapsulated frame */ + struct ieee80211_qosframe *whqos = + (struct ieee80211_qosframe *)datap; + if (whqos->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) + tid = whqos->i_qos[0] & IEEE80211_QOS_TID; + else + tid = HTT_NON_QOS_TID; + } else { + /* + * This function should only be applied to data frames. + * For management frames, we already know to use + * HTT_TX_EXT_TID_MGMT. + */ + qdf_assert(0); + } + return tid; +} + +static A_UINT8 +ol_tx_tid( + struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t tx_nbuf, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + A_UINT8 *datap = qdf_nbuf_data(tx_nbuf); + A_UINT8 tid; + + if (pdev->frame_format == wlan_frm_fmt_raw) { + tx_msdu_info->htt.info.l2_hdr_type = htt_pkt_type_raw; + + ol_tx_set_ether_type(datap, tx_msdu_info); + tid = tx_msdu_info->htt.info.ext_tid == + QDF_NBUF_TX_EXT_TID_INVALID ? + ol_tx_tid_by_raw_type(datap, tx_msdu_info) : + tx_msdu_info->htt.info.ext_tid; + } else if (pdev->frame_format == wlan_frm_fmt_802_3) { + tx_msdu_info->htt.info.l2_hdr_type = htt_pkt_type_ethernet; + + ol_tx_set_ether_type(datap, tx_msdu_info); + tid = + tx_msdu_info->htt.info.ext_tid == + QDF_NBUF_TX_EXT_TID_INVALID ? + ol_tx_tid_by_ether_type(datap, tx_msdu_info) : + tx_msdu_info->htt.info.ext_tid; + } else if (pdev->frame_format == wlan_frm_fmt_native_wifi) { + struct llc_snap_hdr_t *llc; + + tx_msdu_info->htt.info.l2_hdr_type = htt_pkt_type_native_wifi; + tx_msdu_info->htt.info.l3_hdr_offset = + sizeof(struct ieee80211_frame); + llc = (struct llc_snap_hdr_t *) + (datap + tx_msdu_info->htt.info.l3_hdr_offset); + tx_msdu_info->htt.info.ethertype = + (llc->ethertype[0] << 8) | llc->ethertype[1]; + /* + * Native WiFi is a special case of "raw" 802.11 header format. + * However, we expect that for all cases that use native WiFi, + * the TID will be directly specified out of band. + */ + tid = tx_msdu_info->htt.info.ext_tid; + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_FATAL, + "Invalid standard frame type: %d\n", + pdev->frame_format); + qdf_assert(0); + tid = HTT_TX_EXT_TID_INVALID; + } + return tid; +} + +#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS) +static inline +struct ol_txrx_peer_t *ol_tx_tdls_peer_find(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + uint8_t *peer_id) +{ + struct ol_txrx_peer_t *peer = NULL; + + if (vdev->hlTdlsFlag) { + peer = ol_txrx_find_peer_by_addr(pdev, + vdev->hl_tdls_ap_mac_addr.raw, + peer_id); + if (peer && (peer->peer_ids[0] == HTT_INVALID_PEER_ID)) { + peer = NULL; + } else { + if (peer) + qdf_atomic_inc(&peer->ref_cnt); + } + } + if (!peer) + peer = ol_txrx_assoc_peer_find(vdev); + + return peer; +} + +#else +struct ol_txrx_peer_t *ol_tx_tdls_peer_find(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + uint8_t *peer_id) +{ + struct ol_txrx_peer_t *peer = NULL; + peer = ol_txrx_assoc_peer_find(vdev); + + return peer; +} + + +#endif + +struct ol_tx_frms_queue_t * +ol_tx_classify( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t tx_nbuf, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + struct ol_txrx_peer_t *peer = NULL; + struct ol_tx_frms_queue_t *txq = NULL; + A_UINT8 *dest_addr; + A_UINT8 tid; +#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS) + u_int8_t peer_id; +#endif + + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + dest_addr = ol_tx_dest_addr_find(pdev, tx_nbuf); + if ((IEEE80211_IS_MULTICAST(dest_addr)) || + (vdev->opmode == wlan_op_mode_ocb)) { + txq = &vdev->txqs[OL_TX_VDEV_MCAST_BCAST]; + tx_msdu_info->htt.info.ext_tid = + HTT_TX_EXT_TID_NON_QOS_MCAST_BCAST; + if (vdev->opmode == wlan_op_mode_sta) { + /* + * The STA sends a frame with a broadcast + * dest addr (DA) as a + * unicast frame to the AP's receive addr (RA). + * Find the peer object that represents the AP + * that the STA is associated with. + */ + peer = ol_txrx_assoc_peer_find(vdev); + if (!peer) { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "Error: STA %p (%02x:%02x:%02x:%02x:%02x:%02x) trying to send bcast DA tx data frame w/o association\n", + vdev, + vdev->mac_addr.raw[0], + vdev->mac_addr.raw[1], + vdev->mac_addr.raw[2], + vdev->mac_addr.raw[3], + vdev->mac_addr.raw[4], + vdev->mac_addr.raw[5]); + return NULL; /* error */ + } else if ((peer->security[ + OL_TXRX_PEER_SECURITY_MULTICAST].sec_type + != htt_sec_type_wapi) && + (qdf_nbuf_is_ipv4_pkt(tx_nbuf) == true)) { + if (true == qdf_nbuf_is_ipv4_dhcp_pkt( + tx_nbuf)) { + /* DHCP frame to go with + * voice priority + */ + txq = &peer->txqs[TX_DHCP_TID]; + tx_msdu_info->htt.info.ext_tid = + TX_DHCP_TID; + } + } + /* + * The following line assumes each peer object has a + * single ID. This is currently true, and is expected + * to remain true. + */ + tx_msdu_info->htt.info.peer_id = peer->peer_ids[0]; + } else if (vdev->opmode == wlan_op_mode_ocb) { + tx_msdu_info->htt.info.peer_id = HTT_INVALID_PEER_ID; + /* In OCB mode, don't worry about the peer. + *We don't need it. */ + peer = NULL; + } else { + tx_msdu_info->htt.info.peer_id = HTT_INVALID_PEER_ID; + /* + * Look up the vdev's BSS peer, so that the + * classify_extension function can check whether to + * encrypt multicast / broadcast frames. + */ + peer = ol_txrx_peer_find_hash_find(pdev, + vdev->mac_addr.raw, + 0, 1); + if (!peer) { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "Error: vdev %p (%02x:%02x:%02x:%02x:%02x:%02x) trying to send bcast/mcast, but no self-peer found\n", + vdev, + vdev->mac_addr.raw[0], + vdev->mac_addr.raw[1], + vdev->mac_addr.raw[2], + vdev->mac_addr.raw[3], + vdev->mac_addr.raw[4], + vdev->mac_addr.raw[5]); + return NULL; /* error */ + } + } + tx_msdu_info->htt.info.is_unicast = false; + } else { + /* tid would be overwritten for non QoS case*/ + tid = ol_tx_tid(pdev, tx_nbuf, tx_msdu_info); + if ((HTT_TX_EXT_TID_INVALID == tid) || + (tid >= OL_TX_NUM_TIDS)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "%s Error: could not classify packet into valid TID(%d).\n", + __func__, tid); + return NULL; + } +#ifdef ATH_SUPPORT_WAPI + /* Check to see if a frame is a WAI frame */ + if (tx_msdu_info->htt.info.ethertype == ETHERTYPE_WAI) { + /* WAI frames should not be encrypted */ + tx_msdu_info->htt.action.do_encrypt = 0; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "Tx Frame is a WAI frame\n"); + } +#endif /* ATH_SUPPORT_WAPI */ + + /* + * Find the peer and increment its reference count. + * If this vdev is an AP, use the dest addr (DA) to determine + * which peer STA this unicast data frame is for. + * If this vdev is a STA, the unicast data frame is for the + * AP the STA is associated with. + */ + if (vdev->opmode == wlan_op_mode_sta) { + /* + * TO DO: + * To support TDLS, first check if there is a TDLS + * peer STA, + * and if so, check if the DA matches the TDLS peer + * STA's MAC address. If there is no peer TDLS STA, + * or if the DA is not the TDLS STA's address, + * then the frame is either for the AP itself, or is + * supposed to be sent to the AP for forwarding. + */ +#if 0 + if (vdev->num_tdls_peers > 0) { + peer = NULL; + for (i = 0; i < vdev->num_tdls_peers; i++) { + int differs = adf_os_mem_cmp( + vdev->tdls_peers[i]-> + mac_addr.raw, + dest_addr, + OL_TXRX_MAC_ADDR_LEN); + if (!differs) { + peer = vdev->tdls_peers[i]; + break; + } + } + } else { + /* send to AP */ + peer = ol_txrx_assoc_peer_find(vdev); + } +#endif + + peer = ol_tx_tdls_peer_find(pdev, vdev, &peer_id); + } else { + peer = ol_txrx_peer_find_hash_find(pdev, dest_addr, + 0, 1); + } + tx_msdu_info->htt.info.is_unicast = true; + if (!peer) { + /* + * Unicast data xfer can only happen to an + * associated peer. It is illegitimate to send unicast + * data if there is no peer to send it to. + */ + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "Error: vdev %p (%02x:%02x:%02x:%02x:%02x:%02x) trying to send unicast tx data frame to an unknown peer\n", + vdev, + vdev->mac_addr.raw[0], vdev->mac_addr.raw[1], + vdev->mac_addr.raw[2], vdev->mac_addr.raw[3], + vdev->mac_addr.raw[4], vdev->mac_addr.raw[5]); + return NULL; /* error */ + } + TX_SCHED_DEBUG_PRINT("Peer found\n"); + if (!peer->qos_capable) { + tid = OL_TX_NON_QOS_TID; + } else if ((peer->security[ + OL_TXRX_PEER_SECURITY_UNICAST].sec_type + != htt_sec_type_wapi) && + (qdf_nbuf_is_ipv4_pkt(tx_nbuf) == true)) { + if (true == qdf_nbuf_is_ipv4_dhcp_pkt(tx_nbuf)) + /* DHCP frame to go with voice priority */ + tid = TX_DHCP_TID; + } + + /* Only allow encryption when in authenticated state */ + if (OL_TXRX_PEER_STATE_AUTH != peer->state) + tx_msdu_info->htt.action.do_encrypt = 0; + + txq = &peer->txqs[tid]; + tx_msdu_info->htt.info.ext_tid = tid; + /* + * The following line assumes each peer object has a single ID. + * This is currently true, and is expected to remain true. + */ + tx_msdu_info->htt.info.peer_id = peer->peer_ids[0]; + /* + * WORKAROUND - check that the peer ID is valid. + * If tx data is provided before ol_rx_peer_map_handler is + * called to record the peer ID specified by the target, + * then we could end up here with an invalid peer ID. + * TO DO: rather than dropping the tx frame, pause the txq it + * goes into, then fill in the peer ID for the entries in the + * txq when the peer_map event provides the peer ID, and then + * unpause the txq. + */ + if (tx_msdu_info->htt.info.peer_id == HTT_INVALID_PEER_ID) { + if (peer) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: remove the peer for invalid peer_id %p\n", + __func__, peer); + /* remove the peer reference added above */ + ol_txrx_peer_unref_delete(peer); + tx_msdu_info->peer = NULL; + } + return NULL; + } + } + tx_msdu_info->peer = peer; + if (ol_if_tx_bad_peer_txq_overflow(pdev, peer, txq)) + return NULL; + /* + * If relevant, do a deeper inspection to determine additional + * characteristics of the tx frame. + * If the frame is invalid, then the txq will be set to NULL to + * indicate an error. + */ + OL_TX_CLASSIFY_EXTENSION(vdev, tx_desc, tx_nbuf, tx_msdu_info, txq); + if (IEEE80211_IS_MULTICAST(dest_addr) && vdev->opmode != + wlan_op_mode_sta && tx_msdu_info->peer != + NULL) { + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "%s: remove the peer reference %p\n", + __func__, peer); + /* remove the peer reference added above */ + ol_txrx_peer_unref_delete(tx_msdu_info->peer); + /* Making peer NULL in case if multicast non STA mode */ + tx_msdu_info->peer = NULL; + } + + /* Whether this frame can download though HTT2 data pipe or not. */ + OL_TX_CLASSIFY_HTT2_EXTENSION(vdev, tx_nbuf, tx_msdu_info); + + /* Update Tx Queue info */ + tx_desc->txq = txq; + + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); + return txq; +} + +struct ol_tx_frms_queue_t * +ol_tx_classify_mgmt( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t tx_nbuf, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + struct ol_txrx_peer_t *peer = NULL; + struct ol_tx_frms_queue_t *txq = NULL; + A_UINT8 *dest_addr; + union ol_txrx_align_mac_addr_t local_mac_addr_aligned, *mac_addr; + + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + dest_addr = ol_tx_dest_addr_find(pdev, tx_nbuf); + if (IEEE80211_IS_MULTICAST(dest_addr)) { + /* + * AP: beacons are broadcast, + * public action frames (e.g. extended channel + * switch announce) may be broadcast + * STA: probe requests can be either broadcast or unicast + */ + txq = &vdev->txqs[OL_TX_VDEV_DEFAULT_MGMT]; + tx_msdu_info->htt.info.peer_id = HTT_INVALID_PEER_ID; + tx_msdu_info->peer = NULL; + tx_msdu_info->htt.info.is_unicast = 0; + } else { + /* + * Find the peer and increment its reference count. + * If this vdev is an AP, use the receiver addr (RA) to + * determine which peer STA this unicast mgmt frame is for. + * If this vdev is a STA, the unicast mgmt frame is for the + * AP the STA is associated with. + * Probe request / response and Assoc request / response are + * sent before the peer exists - in this case, use the + * vdev's default tx queue. + */ + if (vdev->opmode == wlan_op_mode_sta) { + /* + * TO DO: + * To support TDLS, first check if there is a TDLS + * peer STA, and if so, check if the DA matches + * the TDLS peer STA's MAC address. + */ + peer = ol_txrx_assoc_peer_find(vdev); + /* + * Some special case(preauth for example) needs to send + * unicast mgmt frame to unassociated AP. In such case, + * we need to check if dest addr match the associated + * peer addr. If not, we set peer as NULL to queue this + * frame to vdev queue. + */ + if (peer) { + qdf_mem_copy( + &local_mac_addr_aligned.raw[0], + dest_addr, OL_TXRX_MAC_ADDR_LEN); + mac_addr = &local_mac_addr_aligned; + if (ol_txrx_peer_find_mac_addr_cmp( + mac_addr, + &peer->mac_addr) != 0) { + qdf_atomic_dec(&peer->ref_cnt); + peer = NULL; + } + } + } else { + /* find the peer and increment its reference count */ + peer = ol_txrx_peer_find_hash_find(pdev, dest_addr, + 0, 1); + } + tx_msdu_info->peer = peer; + if (!peer) { + txq = &vdev->txqs[OL_TX_VDEV_DEFAULT_MGMT]; + tx_msdu_info->htt.info.peer_id = HTT_INVALID_PEER_ID; + } else { + txq = &peer->txqs[HTT_TX_EXT_TID_MGMT]; + tx_msdu_info->htt.info.ext_tid = HTT_TX_EXT_TID_MGMT; + /* + * The following line assumes each peer object has a + * single ID. This is currently true, and is expected + * to remain true. + */ + tx_msdu_info->htt.info.peer_id = peer->peer_ids[0]; + } + tx_msdu_info->htt.info.is_unicast = 1; + } + /* + * If relevant, do a deeper inspection to determine additional + * characteristics of the tx frame. + * If the frame is invalid, then the txq will be set to NULL to + * indicate an error. + */ + OL_TX_CLASSIFY_MGMT_EXTENSION(vdev, tx_desc, tx_nbuf, + tx_msdu_info, txq); + + /* Whether this frame can download though HTT2 data pipe or not. */ + OL_TX_CLASSIFY_HTT2_EXTENSION(vdev, tx_nbuf, tx_msdu_info); + + /* Update Tx Queue info */ + tx_desc->txq = txq; + + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); + return txq; +} + +A_STATUS +ol_tx_classify_extension( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t tx_msdu, + struct ol_txrx_msdu_info_t *msdu_info) +{ + A_UINT8 *datap = qdf_nbuf_data(tx_msdu); + struct ol_txrx_peer_t *peer; + int which_key; + + /* + * The following msdu_info fields were already filled in by the + * ol_tx entry function or the regular ol_tx_classify function: + * htt.info.vdev_id (ol_tx_hl or ol_tx_non_std_hl) + * htt.info.ext_tid (ol_tx_non_std_hl or ol_tx_classify) + * htt.info.frame_type (ol_tx_hl or ol_tx_non_std_hl) + * htt.info.l2_hdr_type (ol_tx_hl or ol_tx_non_std_hl) + * htt.info.is_unicast (ol_tx_classify) + * htt.info.peer_id (ol_tx_classify) + * peer (ol_tx_classify) + * if (is_unicast) { + * htt.info.ethertype (ol_tx_classify) + * htt.info.l3_hdr_offset (ol_tx_classify) + * } + * The following fields need to be filled in by this function: + * if (!is_unicast) { + * htt.info.ethertype + * htt.info.l3_hdr_offset + * } + * htt.action.band (NOT CURRENTLY USED) + * htt.action.do_encrypt + * htt.action.do_tx_complete + * The following fields are not needed for data frames, and can + * be left uninitialized: + * htt.info.frame_subtype + */ + + if (!msdu_info->htt.info.is_unicast) { + int l2_hdr_size; + A_UINT16 ethertype; + + if (msdu_info->htt.info.l2_hdr_type == htt_pkt_type_ethernet) { + struct ethernet_hdr_t *eh; + + eh = (struct ethernet_hdr_t *)datap; + l2_hdr_size = sizeof(*eh); + ethertype = (eh->ethertype[0] << 8) | eh->ethertype[1]; + + if (ethertype == ETHERTYPE_VLAN) { + struct ethernet_vlan_hdr_t *evh; + + evh = (struct ethernet_vlan_hdr_t *)datap; + l2_hdr_size = sizeof(*evh); + ethertype = (evh->ethertype[0] << 8) | + evh->ethertype[1]; + } + + if (!IS_ETHERTYPE(ethertype)) { + /* 802.3 header*/ + struct llc_snap_hdr_t *llc = + (struct llc_snap_hdr_t *)(datap + + l2_hdr_size); + ethertype = (llc->ethertype[0] << 8) | + llc->ethertype[1]; + l2_hdr_size += sizeof(*llc); + } + msdu_info->htt.info.l3_hdr_offset = l2_hdr_size; + msdu_info->htt.info.ethertype = ethertype; + } else { /* 802.11 */ + struct llc_snap_hdr_t *llc; + l2_hdr_size = ol_txrx_ieee80211_hdrsize(datap); + llc = (struct llc_snap_hdr_t *)(datap + l2_hdr_size); + ethertype = (llc->ethertype[0] << 8) | + llc->ethertype[1]; + /* + * Don't include the LLC/SNAP header in l2_hdr_size, + * because l3_hdr_offset is actually supposed to refer + * to the header after the 802.3 or 802.11 header, + * which could be a LLC/SNAP header rather + * than the L3 header. + */ + } + msdu_info->htt.info.l3_hdr_offset = l2_hdr_size; + msdu_info->htt.info.ethertype = ethertype; + which_key = txrx_sec_mcast; + } else { + which_key = txrx_sec_ucast; + } + peer = msdu_info->peer; + /* + * msdu_info->htt.action.do_encrypt is initially set in ol_tx_desc_hl. + * Add more check here. + */ + msdu_info->htt.action.do_encrypt = (!peer) ? 0 : + (peer->security[which_key].sec_type == htt_sec_type_none) ? 0 : + msdu_info->htt.action.do_encrypt; + /* + * For systems that have a frame by frame spec for whether to receive + * a tx completion notification, use the tx completion notification + * only for certain management frames, not for data frames. + * (In the future, this may be changed slightly, e.g. to request a + * tx completion notification for the final EAPOL message sent by a + * STA during the key delivery handshake.) + */ + msdu_info->htt.action.do_tx_complete = 0; + + return A_OK; +} + +A_STATUS +ol_tx_classify_mgmt_extension( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t tx_msdu, + struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ieee80211_frame *wh; + + /* + * The following msdu_info fields were already filled in by the + * ol_tx entry function or the regular ol_tx_classify_mgmt function: + * htt.info.vdev_id (ol_txrx_mgmt_send) + * htt.info.frame_type (ol_txrx_mgmt_send) + * htt.info.l2_hdr_type (ol_txrx_mgmt_send) + * htt.action.do_tx_complete (ol_txrx_mgmt_send) + * htt.info.peer_id (ol_tx_classify_mgmt) + * htt.info.ext_tid (ol_tx_classify_mgmt) + * htt.info.is_unicast (ol_tx_classify_mgmt) + * peer (ol_tx_classify_mgmt) + * The following fields need to be filled in by this function: + * htt.info.frame_subtype + * htt.info.l3_hdr_offset + * htt.action.band (NOT CURRENTLY USED) + * The following fields are not needed for mgmt frames, and can + * be left uninitialized: + * htt.info.ethertype + * htt.action.do_encrypt + * (This will be filled in by other SW, which knows whether + * the peer has robust-managment-frames enabled.) + */ + wh = (struct ieee80211_frame *)qdf_nbuf_data(tx_msdu); + msdu_info->htt.info.frame_subtype = + (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) >> + IEEE80211_FC0_SUBTYPE_SHIFT; + msdu_info->htt.info.l3_hdr_offset = sizeof(struct ieee80211_frame); + + return A_OK; +} + +#endif /* defined(CONFIG_HL_SUPPORT) */ diff --git a/core/dp/txrx/ol_tx_classify.h b/core/dp/txrx/ol_tx_classify.h new file mode 100644 index 000000000000..159897ae5c42 --- /dev/null +++ b/core/dp/txrx/ol_tx_classify.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2012, 2014, 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_tx_classify.h + * @brief API definitions for the tx classify module within the data SW. + */ +#ifndef _OL_TX_CLASSIFY__H_ +#define _OL_TX_CLASSIFY__H_ + +#include <qdf_nbuf.h> /* qdf_nbuf_t */ +#include <ol_txrx_types.h> /* ol_txrx_vdev_t, etc. */ + +static inline u_int8_t * +ol_tx_dest_addr_find( + struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t tx_nbuf) +{ + u_int8_t *hdr_ptr; + void *datap = qdf_nbuf_data(tx_nbuf); + + if (pdev->frame_format == wlan_frm_fmt_raw) { + /* adjust hdr_ptr to RA */ + struct ieee80211_frame *wh = + (struct ieee80211_frame *)datap; + hdr_ptr = wh->i_addr1; + } else if (pdev->frame_format == + wlan_frm_fmt_native_wifi) { + /* adjust hdr_ptr to RA */ + struct ieee80211_frame *wh = ( + struct ieee80211_frame *)datap; + hdr_ptr = wh->i_addr1; + } else if (pdev->frame_format == wlan_frm_fmt_802_3) { + hdr_ptr = datap; + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "Invalid standard frame type: %d\n", + pdev->frame_format); + qdf_assert(0); + hdr_ptr = NULL; + } + return hdr_ptr; +} + +#if defined(CONFIG_HL_SUPPORT) + +/** + * @brief Classify a tx frame to which tid queue. + * + * @param vdev - the virtual device sending the data + * (for specifying the transmitter address for multicast / broadcast data) + * @param tx_desc - descriptor object with meta-data about the tx frame + * @param netbuf - the tx frame + * @param tx_msdu_info - characteristics of the tx frame + */ +struct ol_tx_frms_queue_t * +ol_tx_classify( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t netbuf, + struct ol_txrx_msdu_info_t *tx_msdu_info); + +struct ol_tx_frms_queue_t * +ol_tx_classify_mgmt( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t netbuf, + struct ol_txrx_msdu_info_t *tx_msdu_info); + +#else + +#define ol_tx_classify(vdev, tx_desc, netbuf, tx_msdu_info) NULL +#define ol_tx_classify_mgmt(vdev, tx_desc, netbuf, tx_msdu_info) NULL + +#endif /* defined(CONFIG_HL_SUPPORT) */ + + +#endif /* _OL_TX_CLASSIFY__H_ */ diff --git a/core/dp/txrx/ol_tx_desc.c b/core/dp/txrx/ol_tx_desc.c index 5635abc61b8d..04d18c49da80 100644 --- a/core/dp/txrx/ol_tx_desc.c +++ b/core/dp/txrx/ol_tx_desc.c @@ -105,7 +105,56 @@ static inline void ol_tx_desc_reset_timestamp(struct ol_tx_desc_t *tx_desc) } #endif +#ifdef CONFIG_HL_SUPPORT + +/** + * ol_tx_desc_vdev_update() - vedv assign. + * @tx_desc: tx descriptor pointer + * @vdev: vdev handle + * + * Return: None + */ +static inline void +ol_tx_desc_vdev_update(struct ol_tx_desc_t *tx_desc, + struct ol_txrx_vdev_t *vdev) +{ + tx_desc->vdev = vdev; +} +#else + +static inline void +ol_tx_desc_vdev_update(struct ol_tx_desc_t *tx_desc, + struct ol_txrx_vdev_t *vdev) +{ + return; +} +#endif + +#ifdef CONFIG_PER_VDEV_TX_DESC_POOL + +/** + * ol_tx_desc_count_inc() - tx desc count increment for desc allocation. + * @vdev: vdev handle + * + * Return: None + */ +static inline void +ol_tx_desc_count_inc(struct ol_txrx_vdev_t *vdev) +{ + qdf_atomic_inc(&vdev->tx_desc_count); +} +#else + +static inline void +ol_tx_desc_count_inc(struct ol_txrx_vdev_t *vdev) +{ + return; +} + +#endif + #ifndef QCA_LL_TX_FLOW_CONTROL_V2 + /** * ol_tx_desc_alloc() - allocate descriptor from freelist * @pdev: pdev handle @@ -127,6 +176,13 @@ struct ol_tx_desc_t *ol_tx_desc_alloc(struct ol_txrx_pdev_t *pdev, ol_tx_desc_compute_delay(tx_desc); } qdf_spin_unlock_bh(&pdev->tx_mutex); + + if (!tx_desc) + return NULL; + + ol_tx_desc_vdev_update(tx_desc, vdev); + ol_tx_desc_count_inc(vdev); + return tx_desc; } @@ -220,6 +276,53 @@ ol_tx_desc_alloc_wrapper(struct ol_txrx_pdev_t *pdev, #endif #endif +/** + * ol_tx_desc_alloc_hl() - allocate tx descriptor + * @pdev: pdev handle + * @vdev: vdev handle + * @msdu_info: tx msdu info + * + * Return: tx descriptor pointer/ NULL in case of error + */ +static struct ol_tx_desc_t * +ol_tx_desc_alloc_hl(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ol_tx_desc_t *tx_desc; + + tx_desc = ol_tx_desc_alloc_wrapper(pdev, vdev, msdu_info); + if (!tx_desc) + return NULL; + + qdf_atomic_dec(&pdev->tx_queue.rsrc_cnt); + + return tx_desc; +} + +#if defined(CONFIG_PER_VDEV_TX_DESC_POOL) && defined(CONFIG_HL_SUPPORT) + +/** + * ol_tx_desc_vdev_rm() - decrement the tx desc count for vdev. + * @tx_desc: tx desc + * + * Return: None + */ +static inline void +ol_tx_desc_vdev_rm(struct ol_tx_desc_t *tx_desc) +{ + qdf_atomic_dec(&tx_desc->vdev->tx_desc_count); + tx_desc->vdev = NULL; +} +#else + +static inline void +ol_tx_desc_vdev_rm(struct ol_tx_desc_t *tx_desc) +{ + return; +} +#endif + #ifndef QCA_LL_TX_FLOW_CONTROL_V2 /** * ol_tx_desc_free() - put descriptor to freelist @@ -246,6 +349,8 @@ void ol_tx_desc_free(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc) ol_tx_desc_reset_timestamp(tx_desc); ol_tx_put_desc_global_pool(pdev, tx_desc); + ol_tx_desc_vdev_rm(tx_desc); + qdf_spin_unlock_bh(&pdev->tx_mutex); } @@ -313,7 +418,7 @@ void dump_pkt(qdf_nbuf_t nbuf, qdf_dma_addr_t nbuf_paddr, int len) { qdf_print("%s: Pkt: VA 0x%p PA 0x%llx len %d\n", __func__, - qdf_nbuf_data(nbuf), nbuf_paddr, len); + qdf_nbuf_data(nbuf), (long long unsigned int)nbuf_paddr, len); print_hex_dump(KERN_DEBUG, "Pkt: ", DUMP_PREFIX_ADDRESS, 16, 4, qdf_nbuf_data(nbuf), len, true); } @@ -491,6 +596,52 @@ struct ol_tx_desc_t *ol_tx_desc_ll(struct ol_txrx_pdev_t *pdev, return tx_desc; } +struct ol_tx_desc_t * +ol_tx_desc_hl( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t netbuf, + struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ol_tx_desc_t *tx_desc; + + /* FIX THIS: these inits should probably be done by tx classify */ + msdu_info->htt.info.vdev_id = vdev->vdev_id; + msdu_info->htt.info.frame_type = pdev->htt_pkt_type; + msdu_info->htt.action.cksum_offload = qdf_nbuf_get_tx_cksum(netbuf); + switch (qdf_nbuf_get_exemption_type(netbuf)) { + case QDF_NBUF_EXEMPT_NO_EXEMPTION: + case QDF_NBUF_EXEMPT_ON_KEY_MAPPING_KEY_UNAVAILABLE: + /* We want to encrypt this frame */ + msdu_info->htt.action.do_encrypt = 1; + break; + case QDF_NBUF_EXEMPT_ALWAYS: + /* We don't want to encrypt this frame */ + msdu_info->htt.action.do_encrypt = 0; + break; + default: + qdf_assert(0); + break; + } + + /* allocate the descriptor */ + tx_desc = ol_tx_desc_alloc_hl(pdev, vdev, msdu_info); + if (!tx_desc) + return NULL; + + /* initialize the SW tx descriptor */ + tx_desc->netbuf = netbuf; + /* fix this - get pkt_type from msdu_info */ + tx_desc->pkt_type = OL_TX_FRM_STD; + +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + tx_desc->orig_l2_hdr_bytes = 0; +#endif + /* the HW tx descriptor will be initialized later by the caller */ + + return tx_desc; +} + void ol_tx_desc_frame_list_free(struct ol_txrx_pdev_t *pdev, ol_tx_desc_list *tx_descs, int had_error) { diff --git a/core/dp/txrx/ol_tx_desc.h b/core/dp/txrx/ol_tx_desc.h index 2509fecdb484..4842a8a4aad6 100644 --- a/core/dp/txrx/ol_tx_desc.h +++ b/core/dp/txrx/ol_tx_desc.h @@ -72,6 +72,31 @@ struct ol_tx_desc_t *ol_tx_desc_ll(struct ol_txrx_pdev_t *pdev, qdf_nbuf_t netbuf, struct ol_txrx_msdu_info_t *msdu_info); + +/** + * @brief Allocate and initialize a tx descriptor for a HL system. + * @details + * Allocate a tx descriptor pair for a new tx frame - a SW tx descriptor + * for private use within the host data SW, and a HTT tx descriptor for + * downloading tx meta-data to the target FW/HW. + * Fill in the fields of this pair of tx descriptors based on the + * information in the netbuf. + * + * @param pdev - the data physical device sending the data + * (for accessing the tx desc pool) + * @param vdev - the virtual device sending the data + * (for specifying the transmitter address for multicast / broadcast data) + * @param netbuf - the tx frame + * @param msdu_info - tx meta-data + */ +struct ol_tx_desc_t * +ol_tx_desc_hl( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t netbuf, + struct ol_txrx_msdu_info_t *msdu_info); + + /** * @brief Use a tx descriptor ID to find the corresponding desriptor object. * diff --git a/core/dp/txrx/ol_tx_queue.c b/core/dp/txrx/ol_tx_queue.c index 5351a8efbe03..c57db12adbd3 100644 --- a/core/dp/txrx/ol_tx_queue.c +++ b/core/dp/txrx/ol_tx_queue.c @@ -37,10 +37,1609 @@ #include <ol_txrx_internal.h> /* TXRX_ASSERT1, etc. */ #include <ol_tx_desc.h> /* ol_tx_desc, ol_tx_desc_frame_list_free */ #include <ol_tx.h> /* ol_tx_vdev_ll_pause_queue_send */ +#include <ol_tx_sched.h> /* ol_tx_sched_notify, etc. */ #include <ol_tx_queue.h> +#include <ol_txrx.h> /* ol_tx_desc_pool_size_hl */ #include <ol_txrx_dbg.h> /* ENABLE_TX_QUEUE_LOG */ #include <qdf_types.h> /* bool */ #include "cdp_txrx_flow_ctrl_legacy.h" +#include <ol_txrx_peer_find.h> + +#if defined(CONFIG_HL_SUPPORT) + +#ifndef offsetof +#define offsetof(type, field) ((qdf_size_t)(&((type *)0)->field)) +#endif + +/*--- function prototypes for optional host ADDBA negotiation ---------------*/ + +#define OL_TX_QUEUE_ADDBA_CHECK(pdev, txq, tx_msdu_info) /* no-op */ + +#ifndef container_of +#define container_of(ptr, type, member) ((type *)( \ + (char *)(ptr) - (char *)(&((type *)0)->member))) +#endif +/*--- function definitions --------------------------------------------------*/ + +/** + * ol_tx_queue_vdev_flush() - try to flush pending frames in the tx queues + * no matter it's queued in the TX scheduler or not + * @pdev: the physical device object + * @vdev: the virtual device object + * + * Return: None + */ +static void +ol_tx_queue_vdev_flush(struct ol_txrx_pdev_t *pdev, struct ol_txrx_vdev_t *vdev) +{ +#define PEER_ARRAY_COUNT 10 + struct ol_tx_frms_queue_t *txq; + struct ol_txrx_peer_t *peer, *peers[PEER_ARRAY_COUNT]; + int i, j, peer_count; + + /* flush VDEV TX queues */ + for (i = 0; i < OL_TX_VDEV_NUM_QUEUES; i++) { + txq = &vdev->txqs[i]; + ol_tx_queue_free(pdev, txq, (i + OL_TX_NUM_TIDS)); + } + /* flush PEER TX queues */ + do { + peer_count = 0; + /* select candidate peers */ + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { + for (i = 0; i < OL_TX_NUM_TIDS; i++) { + txq = &peer->txqs[i]; + if (txq->frms) { + qdf_atomic_inc(&peer->ref_cnt); + peers[peer_count++] = peer; + break; + } + } + if (peer_count >= PEER_ARRAY_COUNT) + break; + } + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + /* flush TX queues of candidate peers */ + for (i = 0; i < peer_count; i++) { + for (j = 0; j < OL_TX_NUM_TIDS; j++) { + txq = &peers[i]->txqs[j]; + if (txq->frms) + ol_tx_queue_free(pdev, txq, j); + } + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: Delete Peer %p\n", __func__, peer); + ol_txrx_peer_unref_delete(peers[i]); + } + } while (peer_count >= PEER_ARRAY_COUNT); +} + +/** + * ol_tx_queue_flush() - try to flush pending frames in the tx queues + * no matter it's queued in the TX scheduler or not + * @pdev: the physical device object + * + * Return: None + */ +static inline void +ol_tx_queue_flush(struct ol_txrx_pdev_t *pdev) +{ + struct ol_txrx_vdev_t *vdev; + + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + ol_tx_queue_vdev_flush(pdev, vdev); + } +} + +void +ol_tx_queue_discard( + struct ol_txrx_pdev_t *pdev, + bool flush_all, + ol_tx_desc_list *tx_descs) +{ + u_int16_t num; + u_int16_t discarded, actual_discarded = 0; + + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + + if (flush_all == true) + /* flush all the pending tx queues in the scheduler */ + num = ol_tx_desc_pool_size_hl(pdev->ctrl_pdev) - + qdf_atomic_read(&pdev->tx_queue.rsrc_cnt); + else + num = pdev->tx_queue.rsrc_threshold_hi - + pdev->tx_queue.rsrc_threshold_lo; + + TX_SCHED_DEBUG_PRINT("+%s : %u\n,", __func__, + qdf_atomic_read(&pdev->tx_queue.rsrc_cnt)); + while (num > 0) { + discarded = ol_tx_sched_discard_select( + pdev, (u_int16_t)num, tx_descs, flush_all); + if (discarded == 0) + /* + * No more packets could be discarded. + * Probably tx queues are empty. + */ + break; + + num -= discarded; + actual_discarded += discarded; + } + qdf_atomic_add(actual_discarded, &pdev->tx_queue.rsrc_cnt); + TX_SCHED_DEBUG_PRINT("-%s\n", __func__); + + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + + if (flush_all == true && num > 0) + /* + * try to flush pending frames in the tx queues + * which are not queued in the TX scheduler. + */ + ol_tx_queue_flush(pdev); +} + +#ifdef CONFIG_PER_VDEV_TX_DESC_POOL + +/** + * is_ol_tx_discard_frames_success() - check whether currently queued tx frames + * can be discarded or not + * @pdev: the physical device object + * @tx_desc: tx desciptor ptr + * + * Return: Success if available tx descriptors are too few + */ +static bool +is_ol_tx_discard_frames_success(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ + ol_txrx_vdev_handle vdev; + vdev = tx_desc->vdev; + return qdf_atomic_read(&vdev->tx_desc_count) > + ((ol_tx_desc_pool_size_hl(pdev->ctrl_pdev) >> 1) + - TXRX_HL_TX_FLOW_CTRL_MGMT_RESERVED); +} +#else + +static inline bool +is_ol_tx_discard_frames_success(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ + return qdf_atomic_read(&pdev->tx_queue.rsrc_cnt) <= + pdev->tx_queue.rsrc_threshold_lo; +} +#endif + +void +ol_tx_enqueue( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + struct ol_tx_desc_t *tx_desc, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + int bytes; + struct ol_tx_sched_notify_ctx_t notify_ctx; + + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + + /* + * If too few tx descriptors are available, drop some currently-queued + * tx frames, to provide enough tx descriptors for new frames, which + * may be higher priority than the current frames. + */ + if (is_ol_tx_discard_frames_success(pdev, tx_desc)) { + ol_tx_desc_list tx_descs; + TAILQ_INIT(&tx_descs); + ol_tx_queue_discard(pdev, false, &tx_descs); + /*Discard Frames in Discard List*/ + ol_tx_desc_frame_list_free(pdev, &tx_descs, 1 /* error */); + } + + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + TAILQ_INSERT_TAIL(&txq->head, tx_desc, tx_desc_list_elem); + + bytes = qdf_nbuf_len(tx_desc->netbuf); + txq->frms++; + txq->bytes += bytes; + ol_tx_queue_log_enqueue(pdev, tx_msdu_info, 1, bytes); + + if (txq->flag != ol_tx_queue_paused) { + notify_ctx.event = OL_TX_ENQUEUE_FRAME; + notify_ctx.frames = 1; + notify_ctx.bytes = qdf_nbuf_len(tx_desc->netbuf); + notify_ctx.txq = txq; + notify_ctx.info.tx_msdu_info = tx_msdu_info; + ol_tx_sched_notify(pdev, ¬ify_ctx); + txq->flag = ol_tx_queue_active; + } + + if (!ETHERTYPE_IS_EAPOL_WAPI(tx_msdu_info->htt.info.ethertype)) + OL_TX_QUEUE_ADDBA_CHECK(pdev, txq, tx_msdu_info); + + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + +u_int16_t +ol_tx_dequeue( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + ol_tx_desc_list *head, + u_int16_t max_frames, + u_int32_t *credit, + int *bytes) +{ + u_int16_t num_frames; + int bytes_sum; + unsigned credit_sum; + + TXRX_ASSERT2(txq->flag != ol_tx_queue_paused); + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + + if (txq->frms < max_frames) + max_frames = txq->frms; + + bytes_sum = 0; + credit_sum = 0; + for (num_frames = 0; num_frames < max_frames; num_frames++) { + unsigned frame_credit; + struct ol_tx_desc_t *tx_desc; + tx_desc = TAILQ_FIRST(&txq->head); + + frame_credit = htt_tx_msdu_credit(tx_desc->netbuf); + if (credit_sum + frame_credit > *credit) + break; + + credit_sum += frame_credit; + bytes_sum += qdf_nbuf_len(tx_desc->netbuf); + TAILQ_REMOVE(&txq->head, tx_desc, tx_desc_list_elem); + TAILQ_INSERT_TAIL(head, tx_desc, tx_desc_list_elem); + } + txq->frms -= num_frames; + txq->bytes -= bytes_sum; + /* a paused queue remains paused, regardless of whether it has frames */ + if (txq->frms == 0 && txq->flag == ol_tx_queue_active) + txq->flag = ol_tx_queue_empty; + + ol_tx_queue_log_dequeue(pdev, txq, num_frames, bytes_sum); + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); + + *bytes = bytes_sum; + *credit = credit_sum; + return num_frames; +} + +void +ol_tx_queue_free( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid) +{ + int frms = 0, bytes = 0; + struct ol_tx_desc_t *tx_desc; + struct ol_tx_sched_notify_ctx_t notify_ctx; + ol_tx_desc_list tx_tmp_list; + + TAILQ_INIT(&tx_tmp_list); + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + + notify_ctx.event = OL_TX_DELETE_QUEUE; + notify_ctx.txq = txq; + notify_ctx.info.ext_tid = tid; + ol_tx_sched_notify(pdev, ¬ify_ctx); + + frms = txq->frms; + tx_desc = TAILQ_FIRST(&txq->head); + while (txq->frms) { + bytes += qdf_nbuf_len(tx_desc->netbuf); + txq->frms--; + tx_desc = TAILQ_NEXT(tx_desc, tx_desc_list_elem); + } + ol_tx_queue_log_free(pdev, txq, tid, frms, bytes); + txq->bytes -= bytes; + ol_tx_queue_log_free(pdev, txq, tid, frms, bytes); + txq->flag = ol_tx_queue_empty; + /* txq->head gets reset during the TAILQ_CONCAT call */ + TAILQ_CONCAT(&tx_tmp_list, &txq->head, tx_desc_list_elem); + + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + /* free tx frames without holding tx_queue_spinlock */ + qdf_atomic_add(frms, &pdev->tx_queue.rsrc_cnt); + while (frms) { + tx_desc = TAILQ_FIRST(&tx_tmp_list); + TAILQ_REMOVE(&tx_tmp_list, tx_desc, tx_desc_list_elem); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 0); + frms--; + } + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + + +/*--- queue pause / unpause functions ---------------------------------------*/ + +/** + * ol_txrx_peer_tid_pause_base() - suspend/pause txq for a given tid given peer + * @pdev: the physical device object + * @peer: peer device object + * @tid: tid for which queue needs to be paused + * + * Return: None + */ +static void +ol_txrx_peer_tid_pause_base( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + int tid) +{ + struct ol_tx_frms_queue_t *txq = &peer->txqs[tid]; + + if (txq->paused_count.total++ == 0) { + struct ol_tx_sched_notify_ctx_t notify_ctx; + + notify_ctx.event = OL_TX_PAUSE_QUEUE; + notify_ctx.txq = txq; + notify_ctx.info.ext_tid = tid; + ol_tx_sched_notify(pdev, ¬ify_ctx); + txq->flag = ol_tx_queue_paused; + } +} +#ifdef QCA_BAD_PEER_TX_FLOW_CL + +/** + * ol_txrx_peer_pause_but_no_mgmt_q_base() - suspend/pause all txqs except + * management queue for a given peer + * @pdev: the physical device object + * @peer: peer device object + * + * Return: None + */ +static void +ol_txrx_peer_pause_but_no_mgmt_q_base( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + int i; + for (i = 0; i < OL_TX_MGMT_TID; i++) + ol_txrx_peer_tid_pause_base(pdev, peer, i); +} +#endif + + +/** + * ol_txrx_peer_pause_base() - suspend/pause all txqs for a given peer + * @pdev: the physical device object + * @peer: peer device object + * + * Return: None + */ +static void +ol_txrx_peer_pause_base( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + int i; + for (i = 0; i < QDF_ARRAY_SIZE(peer->txqs); i++) + ol_txrx_peer_tid_pause_base(pdev, peer, i); +} + +/** + * ol_txrx_peer_tid_unpause_base() - unpause txq for a given tid given peer + * @pdev: the physical device object + * @peer: peer device object + * @tid: tid for which queue needs to be unpaused + * + * Return: None + */ +static void +ol_txrx_peer_tid_unpause_base( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + int tid) +{ + struct ol_tx_frms_queue_t *txq = &peer->txqs[tid]; + /* + * Don't actually unpause the tx queue until all pause requests + * have been removed. + */ + TXRX_ASSERT2(txq->paused_count.total > 0); + /* return, if not already paused */ + if (txq->paused_count.total == 0) + return; + + if (--txq->paused_count.total == 0) { + struct ol_tx_sched_notify_ctx_t notify_ctx; + + notify_ctx.event = OL_TX_UNPAUSE_QUEUE; + notify_ctx.txq = txq; + notify_ctx.info.ext_tid = tid; + ol_tx_sched_notify(pdev, ¬ify_ctx); + + if (txq->frms == 0) { + txq->flag = ol_tx_queue_empty; + } else { + txq->flag = ol_tx_queue_active; + /* + * Now that the are new tx frames available to download, + * invoke the scheduling function, to see if it wants to + * download the new frames. + * Since the queue lock is currently held, and since + * the scheduler function takes the lock, temporarily + * release the lock. + */ + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + ol_tx_sched(pdev); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + } + } +} +#ifdef QCA_BAD_PEER_TX_FLOW_CL +/** + * ol_txrx_peer_unpause_but_no_mgmt_q_base() - unpause all txqs except + * management queue for a given peer + * @pdev: the physical device object + * @peer: peer device object + * + * Return: None + */ +static void +ol_txrx_peer_unpause_but_no_mgmt_q_base( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + int i; + for (i = 0; i < OL_TX_MGMT_TID; i++) + ol_txrx_peer_tid_unpause_base(pdev, peer, i); +} +#endif + +void +ol_txrx_peer_tid_unpause(ol_txrx_peer_handle peer, int tid) +{ + struct ol_txrx_pdev_t *pdev = peer->vdev->pdev; + + /* TO DO: log the queue unpause */ + + /* acquire the mutex lock, since we'll be modifying the queues */ + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + + if (tid == -1) { + int i; + for (i = 0; i < QDF_ARRAY_SIZE(peer->txqs); i++) + ol_txrx_peer_tid_unpause_base(pdev, peer, i); + + } else { + ol_txrx_peer_tid_unpause_base(pdev, peer, tid); + } + + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + +void +ol_txrx_throttle_pause(ol_txrx_pdev_handle pdev) +{ +#if defined(QCA_SUPPORT_TX_THROTTLE) + qdf_spin_lock_bh(&pdev->tx_throttle.mutex); + + if (pdev->tx_throttle.is_paused == true) { + qdf_spin_unlock_bh(&pdev->tx_throttle.mutex); + return; + } + + pdev->tx_throttle.is_paused = true; + qdf_spin_unlock_bh(&pdev->tx_throttle.mutex); +#endif + ol_txrx_pdev_pause(pdev, 0); +} + +void +ol_txrx_throttle_unpause(ol_txrx_pdev_handle pdev) +{ +#if defined(QCA_SUPPORT_TX_THROTTLE) + qdf_spin_lock_bh(&pdev->tx_throttle.mutex); + + if (pdev->tx_throttle.is_paused == false) { + qdf_spin_unlock_bh(&pdev->tx_throttle.mutex); + return; + } + + pdev->tx_throttle.is_paused = false; + qdf_spin_unlock_bh(&pdev->tx_throttle.mutex); +#endif + ol_txrx_pdev_unpause(pdev, 0); +} + +void +ol_txrx_vdev_pause(ol_txrx_vdev_handle vdev, uint32_t reason) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + struct ol_txrx_peer_t *peer; + /* TO DO: log the queue pause */ + /* acquire the mutex lock, since we'll be modifying the queues */ + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + + + /* use peer_ref_mutex before accessing peer_list */ + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { + ol_txrx_peer_pause_base(pdev, peer); + } + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + + +void ol_txrx_vdev_unpause(ol_txrx_vdev_handle vdev, uint32_t reason) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + struct ol_txrx_peer_t *peer; + /* TO DO: log the queue unpause */ + /* acquire the mutex lock, since we'll be modifying the queues */ + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + + + + /* take peer_ref_mutex before accessing peer_list */ + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + + TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { + int i; + for (i = 0; i < QDF_ARRAY_SIZE(peer->txqs); i++) + ol_txrx_peer_tid_unpause_base(pdev, peer, i); + } + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + +void ol_txrx_vdev_flush(ol_txrx_vdev_handle vdev) +{ + ol_tx_queue_vdev_flush(vdev->pdev, vdev); +} + +#ifdef QCA_BAD_PEER_TX_FLOW_CL + +/** + * ol_txrx_peer_bal_add_limit_peer() - add one peer into limit list + * @pdev: Pointer to PDEV structure. + * @peer_id: Peer Identifier. + * @peer_limit Peer limit threshold + * + * Add one peer into the limit list of pdev + * Note that the peer limit info will be also updated + * If it is the first time, start the timer + * + * Return: None + */ +void +ol_txrx_peer_bal_add_limit_peer(struct ol_txrx_pdev_t *pdev, + u_int16_t peer_id, u_int16_t peer_limit) +{ + u_int16_t i, existed = 0; + struct ol_txrx_peer_t *peer = NULL; + + for (i = 0; i < pdev->tx_peer_bal.peer_num; i++) { + if (pdev->tx_peer_bal.limit_list[i].peer_id == peer_id) { + existed = 1; + break; + } + } + + if (!existed) { + u_int32_t peer_num = pdev->tx_peer_bal.peer_num; + /* Check if peer_num has reached the capabilit */ + if (peer_num >= MAX_NO_PEERS_IN_LIMIT) { + TX_SCHED_DEBUG_PRINT_ALWAYS( + "reach the maxinum peer num %d\n", + peer_num); + return; + } + pdev->tx_peer_bal.limit_list[peer_num].peer_id = peer_id; + pdev->tx_peer_bal.limit_list[peer_num].limit_flag = true; + pdev->tx_peer_bal.limit_list[peer_num].limit = peer_limit; + pdev->tx_peer_bal.peer_num++; + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer) { + peer->tx_limit_flag = true; + peer->tx_limit = peer_limit; + } + + TX_SCHED_DEBUG_PRINT_ALWAYS( + "Add one peer into limit queue, peer_id %d, cur peer num %d\n", + peer_id, + pdev->tx_peer_bal.peer_num); + } + + /* Only start the timer once */ + if (pdev->tx_peer_bal.peer_bal_timer_state == + ol_tx_peer_bal_timer_inactive) { + qdf_timer_start(&pdev->tx_peer_bal.peer_bal_timer, + pdev->tx_peer_bal.peer_bal_period_ms); + pdev->tx_peer_bal.peer_bal_timer_state = + ol_tx_peer_bal_timer_active; + } +} + +/** + * ol_txrx_peer_bal_remove_limit_peer() - remove one peer from limit list + * @pdev: Pointer to PDEV structure. + * @peer_id: Peer Identifier. + * + * Remove one peer from the limit list of pdev + * Note that Only stop the timer if no peer in limit state + * + * Return: NULL + */ +void +ol_txrx_peer_bal_remove_limit_peer(struct ol_txrx_pdev_t *pdev, + u_int16_t peer_id) +{ + u_int16_t i; + struct ol_txrx_peer_t *peer = NULL; + + for (i = 0; i < pdev->tx_peer_bal.peer_num; i++) { + if (pdev->tx_peer_bal.limit_list[i].peer_id == peer_id) { + pdev->tx_peer_bal.limit_list[i] = + pdev->tx_peer_bal.limit_list[ + pdev->tx_peer_bal.peer_num - 1]; + pdev->tx_peer_bal.peer_num--; + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer) + peer->tx_limit_flag = false; + + + TX_SCHED_DEBUG_PRINT( + "Remove one peer from limitq, peer_id %d, cur peer num %d\n", + peer_id, + pdev->tx_peer_bal.peer_num); + break; + } + } + + /* Only stop the timer if no peer in limit state */ + if (pdev->tx_peer_bal.peer_num == 0) { + qdf_timer_stop(&pdev->tx_peer_bal.peer_bal_timer); + pdev->tx_peer_bal.peer_bal_timer_state = + ol_tx_peer_bal_timer_inactive; + } +} + +void +ol_txrx_peer_pause_but_no_mgmt_q(ol_txrx_peer_handle peer) +{ + struct ol_txrx_pdev_t *pdev = peer->vdev->pdev; + + /* TO DO: log the queue pause */ + + /* acquire the mutex lock, since we'll be modifying the queues */ + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + + ol_txrx_peer_pause_but_no_mgmt_q_base(pdev, peer); + + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + +void +ol_txrx_peer_unpause_but_no_mgmt_q(ol_txrx_peer_handle peer) +{ + struct ol_txrx_pdev_t *pdev = peer->vdev->pdev; + + /* TO DO: log the queue pause */ + + /* acquire the mutex lock, since we'll be modifying the queues */ + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + + ol_txrx_peer_unpause_but_no_mgmt_q_base(pdev, peer); + + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + +u_int16_t +ol_tx_bad_peer_dequeue_check(struct ol_tx_frms_queue_t *txq, + u_int16_t max_frames, + u_int16_t *tx_limit_flag) +{ + if (txq && (txq->peer) && (txq->peer->tx_limit_flag) && + (txq->peer->tx_limit < max_frames)) { + TX_SCHED_DEBUG_PRINT( + "Peer ID %d goes to limit, threshold is %d\n", + txq->peer->peer_ids[0], txq->peer->tx_limit); + *tx_limit_flag = 1; + return txq->peer->tx_limit; + } else { + return max_frames; + } +} + +void +ol_tx_bad_peer_update_tx_limit(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + u_int16_t frames, + u_int16_t tx_limit_flag) +{ + qdf_spin_lock_bh(&pdev->tx_peer_bal.mutex); + if (txq && tx_limit_flag && (txq->peer) && + (txq->peer->tx_limit_flag)) { + if (txq->peer->tx_limit < frames) + txq->peer->tx_limit = 0; + else + txq->peer->tx_limit -= frames; + + TX_SCHED_DEBUG_PRINT_ALWAYS( + "Peer ID %d in limit, deque %d frms\n", + txq->peer->peer_ids[0], frames); + } else if (txq->peer) { + TX_SCHED_DEBUG_PRINT("Download peer_id %d, num_frames %d\n", + txq->peer->peer_ids[0], frames); + } + qdf_spin_unlock_bh(&pdev->tx_peer_bal.mutex); +} + +void +ol_txrx_bad_peer_txctl_set_setting(struct ol_txrx_pdev_t *pdev, + int enable, int period, int txq_limit) +{ + if (enable) + pdev->tx_peer_bal.enabled = ol_tx_peer_bal_enable; + else + pdev->tx_peer_bal.enabled = ol_tx_peer_bal_disable; + + /* Set the current settingl */ + pdev->tx_peer_bal.peer_bal_period_ms = period; + pdev->tx_peer_bal.peer_bal_txq_limit = txq_limit; +} + +void +ol_txrx_bad_peer_txctl_update_threshold(struct ol_txrx_pdev_t *pdev, + int level, int tput_thresh, + int tx_limit) +{ + /* Set the current settingl */ + pdev->tx_peer_bal.ctl_thresh[level].tput_thresh = + tput_thresh; + pdev->tx_peer_bal.ctl_thresh[level].tx_limit = + tx_limit; +} + +/** + * ol_tx_pdev_peer_bal_timer() - timer function + * @context: context of timer function + * + * Return: None + */ +void +ol_tx_pdev_peer_bal_timer(void *context) +{ + int i; + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)context; + + qdf_spin_lock_bh(&pdev->tx_peer_bal.mutex); + + for (i = 0; i < pdev->tx_peer_bal.peer_num; i++) { + if (pdev->tx_peer_bal.limit_list[i].limit_flag) { + u_int16_t peer_id = + pdev->tx_peer_bal.limit_list[i].peer_id; + u_int16_t tx_limit = + pdev->tx_peer_bal.limit_list[i].limit; + + struct ol_txrx_peer_t *peer = NULL; + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + TX_SCHED_DEBUG_PRINT( + "%s peer_id %d peer = 0x%x tx limit %d\n", + __func__, peer_id, + (int)peer, tx_limit); + + /* It is possible the peer limit is still not 0, + but it is the scenario should not be cared */ + if (peer) { + peer->tx_limit = tx_limit; + } else { + ol_txrx_peer_bal_remove_limit_peer(pdev, + peer_id); + TX_SCHED_DEBUG_PRINT_ALWAYS( + "No such a peer, peer id = %d\n", + peer_id); + } + } + } + + qdf_spin_unlock_bh(&pdev->tx_peer_bal.mutex); + + if (pdev->tx_peer_bal.peer_num) { + ol_tx_sched(pdev); + qdf_timer_start(&pdev->tx_peer_bal.peer_bal_timer, + pdev->tx_peer_bal.peer_bal_period_ms); + } +} + +void +ol_txrx_set_txq_peer( + struct ol_tx_frms_queue_t *txq, + struct ol_txrx_peer_t *peer) +{ + if (txq) + txq->peer = peer; +} + +void ol_tx_badpeer_flow_cl_init(struct ol_txrx_pdev_t *pdev) +{ + u_int32_t timer_period; + + qdf_spinlock_create(&pdev->tx_peer_bal.mutex); + pdev->tx_peer_bal.peer_num = 0; + pdev->tx_peer_bal.peer_bal_timer_state + = ol_tx_peer_bal_timer_inactive; + + timer_period = 2000; + pdev->tx_peer_bal.peer_bal_period_ms = timer_period; + + qdf_timer_init( + pdev->osdev, + &pdev->tx_peer_bal.peer_bal_timer, + ol_tx_pdev_peer_bal_timer, + pdev, QDF_TIMER_TYPE_SW); +} + +void ol_tx_badpeer_flow_cl_deinit(struct ol_txrx_pdev_t *pdev) +{ + qdf_timer_stop(&pdev->tx_peer_bal.peer_bal_timer); + pdev->tx_peer_bal.peer_bal_timer_state = + ol_tx_peer_bal_timer_inactive; + qdf_timer_free(&pdev->tx_peer_bal.peer_bal_timer); + qdf_spinlock_destroy(&pdev->tx_peer_bal.mutex); +} + +void +ol_txrx_peer_link_status_handler( + ol_txrx_pdev_handle pdev, + u_int16_t peer_num, + struct rate_report_t *peer_link_status) +{ + u_int16_t i = 0; + struct ol_txrx_peer_t *peer = NULL; + + if (NULL == pdev) { + TX_SCHED_DEBUG_PRINT_ALWAYS("Error: NULL pdev handler\n"); + return; + } + + if (NULL == peer_link_status) { + TX_SCHED_DEBUG_PRINT_ALWAYS( + "Error:NULL link report message. peer num %d\n", + peer_num); + return; + } + + /* Check if bad peer tx flow CL is enabled */ + if (pdev->tx_peer_bal.enabled != ol_tx_peer_bal_enable) { + TX_SCHED_DEBUG_PRINT_ALWAYS( + "Bad peer tx flow CL is not enabled, ignore it\n"); + return; + } + + /* Check peer_num is reasonable */ + if (peer_num > MAX_NO_PEERS_IN_LIMIT) { + TX_SCHED_DEBUG_PRINT_ALWAYS( + "%s: Bad peer_num %d\n", __func__, peer_num); + return; + } + + TX_SCHED_DEBUG_PRINT_ALWAYS("%s: peer_num %d\n", __func__, peer_num); + + for (i = 0; i < peer_num; i++) { + u_int16_t peer_limit, peer_id; + u_int16_t pause_flag, unpause_flag; + u_int32_t peer_phy, peer_tput; + + peer_id = peer_link_status->id; + peer_phy = peer_link_status->phy; + peer_tput = peer_link_status->rate; + + TX_SCHED_DEBUG_PRINT("%s: peer id %d tput %d phy %d\n", + __func__, peer_id, peer_tput, peer_phy); + + /* Sanity check for the PHY mode value */ + if (peer_phy > TXRX_IEEE11_AC) { + TX_SCHED_DEBUG_PRINT_ALWAYS( + "%s: PHY value is illegal: %d, and the peer_id %d\n", + __func__, peer_link_status->phy, peer_id); + continue; + } + pause_flag = false; + unpause_flag = false; + peer_limit = 0; + + /* From now on, PHY, PER info should be all fine */ + qdf_spin_lock_bh(&pdev->tx_peer_bal.mutex); + + /* Update link status analysis for each peer */ + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer) { + u_int32_t thresh, limit, phy; + phy = peer_link_status->phy; + thresh = pdev->tx_peer_bal.ctl_thresh[phy].tput_thresh; + limit = pdev->tx_peer_bal.ctl_thresh[phy].tx_limit; + + if (((peer->tx_pause_flag) || (peer->tx_limit_flag)) && + (peer_tput) && (peer_tput < thresh)) + peer_limit = limit; + + if (peer_limit) { + ol_txrx_peer_bal_add_limit_peer(pdev, peer_id, + peer_limit); + } else if (pdev->tx_peer_bal.peer_num) { + TX_SCHED_DEBUG_PRINT( + "%s: Check if peer_id %d exit limit\n", + __func__, peer_id); + ol_txrx_peer_bal_remove_limit_peer(pdev, + peer_id); + } + if ((peer_tput == 0) && + (peer->tx_pause_flag == false)) { + peer->tx_pause_flag = true; + pause_flag = true; + } else if (peer->tx_pause_flag) { + unpause_flag = true; + peer->tx_pause_flag = false; + } + } else { + TX_SCHED_DEBUG_PRINT( + "%s: Remove peer_id %d from limit list\n", + __func__, peer_id); + ol_txrx_peer_bal_remove_limit_peer(pdev, peer_id); + } + + peer_link_status++; + qdf_spin_unlock_bh(&pdev->tx_peer_bal.mutex); + if (pause_flag) + ol_txrx_peer_pause_but_no_mgmt_q(peer); + else if (unpause_flag) + ol_txrx_peer_unpause_but_no_mgmt_q(peer); + } +} +#endif /* QCA_BAD_PEER_TX_FLOW_CL */ + +/*--- ADDBA triggering functions --------------------------------------------*/ + + +/*=== debug functions =======================================================*/ + +/*--- queue event log -------------------------------------------------------*/ + +#if defined(DEBUG_HL_LOGGING) + +#define negative_sign -1 + +/** + * ol_tx_queue_log_entry_type_info() - log queues entry info + * @type: log entry type + * @size: size + * @align: alignment + * @var_size: variable size record + * + * Return: None + */ +static void +ol_tx_queue_log_entry_type_info( + u_int8_t *type, int *size, int *align, int var_size) +{ + switch (*type) { + case ol_tx_log_entry_type_enqueue: + case ol_tx_log_entry_type_dequeue: + case ol_tx_log_entry_type_queue_free: + *size = sizeof(struct ol_tx_log_queue_add_t); + *align = 2; + break; + + case ol_tx_log_entry_type_queue_state: + *size = offsetof(struct ol_tx_log_queue_state_var_sz_t, data); + *align = 4; + if (var_size) { + /* read the variable-sized record, + * to see how large it is + */ + int align_pad; + struct ol_tx_log_queue_state_var_sz_t *record; + + align_pad = + (*align - ((((u_int32_t) *type) + 1))) + & (*align - 1); + record = (struct ol_tx_log_queue_state_var_sz_t *) + (type + 1 + align_pad); + *size += record->num_cats_active * + (sizeof(u_int32_t) /* bytes */ + + sizeof(u_int16_t) /* frms */); + } + break; + + /*case ol_tx_log_entry_type_drop:*/ + default: + *size = 0; + *align = 0; + }; +} + +/** + * ol_tx_queue_log_oldest_update() - log oldest record + * @pdev: pointer to txrx handle + * @offset: offset value + * + * Return: None + */ +static void +ol_tx_queue_log_oldest_update(struct ol_txrx_pdev_t *pdev, int offset) +{ + int oldest_record_offset; + + /* + * If the offset of the oldest record is between the current and + * new values of the offset of the newest record, then the oldest + * record has to be dropped from the log to provide room for the + * newest record. + * Advance the offset of the oldest record until it points to a + * record that is beyond the new value of the offset of the newest + * record. + */ + if (!pdev->txq_log.wrapped) + /* + * The log has not even filled up yet - no need to remove + * the oldest record to make room for a new record. + */ + return; + + + if (offset > pdev->txq_log.offset) { + /* + * not wraparound - + * The oldest record offset may have already wrapped around, + * even if the newest record has not. In this case, then + * the oldest record offset is fine where it is. + */ + if (pdev->txq_log.oldest_record_offset == 0) + return; + + oldest_record_offset = pdev->txq_log.oldest_record_offset; + } else + /* wraparound */ + oldest_record_offset = 0; + + + while (oldest_record_offset < offset) { + int size, align, align_pad; + u_int8_t type; + + type = pdev->txq_log.data[oldest_record_offset]; + if (type == ol_tx_log_entry_type_wrap) { + oldest_record_offset = 0; + break; + } + ol_tx_queue_log_entry_type_info( + &pdev->txq_log.data[oldest_record_offset], + &size, &align, 1); + align_pad = + (align - ((oldest_record_offset + 1/*type*/))) + & (align - 1); + /* + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "TXQ LOG old alloc: offset %d, type %d, size %d (%d)\n", + oldest_record_offset, type, size, size + 1 + align_pad); + */ + oldest_record_offset += size + 1 + align_pad; + } + if (oldest_record_offset >= pdev->txq_log.size) + oldest_record_offset = 0; + + pdev->txq_log.oldest_record_offset = oldest_record_offset; +} + +/** + * ol_tx_queue_log_alloc() - log data allocation + * @pdev: physical device object + * @type: ol_tx_log_entry_type + * @extra_bytes: extra bytes + * + * + * Return: log element + */ +void* +ol_tx_queue_log_alloc( + struct ol_txrx_pdev_t *pdev, + u_int8_t type /* ol_tx_log_entry_type */, + int extra_bytes) +{ + int size, align, align_pad; + int offset; + + ol_tx_queue_log_entry_type_info(&type, &size, &align, 0); + size += extra_bytes; + + offset = pdev->txq_log.offset; + align_pad = (align - ((offset + 1/*type*/))) & (align - 1); + + if (pdev->txq_log.size - offset >= size + 1 + align_pad) + /* no need to wrap around */ + goto alloc_found; + + if (!pdev->txq_log.allow_wrap) + return NULL; /* log is full and can't wrap */ + + /* handle wrap-around */ + pdev->txq_log.wrapped = 1; + offset = 0; + align_pad = (align - ((offset + 1/*type*/))) & (align - 1); + /* sanity check that the log is large enough to hold this entry */ + if (pdev->txq_log.size <= size + 1 + align_pad) + return NULL; + + +alloc_found: + ol_tx_queue_log_oldest_update(pdev, offset + size + 1 + align_pad); + if (offset == 0) + pdev->txq_log.data[pdev->txq_log.offset] = + ol_tx_log_entry_type_wrap; + + /* + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "TXQ LOG new alloc: offset %d, type %d, size %d (%d)\n", + offset, type, size, size + 1 + align_pad); + */ + pdev->txq_log.data[offset] = type; + pdev->txq_log.offset = offset + size + 1 + align_pad; + if (pdev->txq_log.offset >= pdev->txq_log.size) { + pdev->txq_log.offset = 0; + pdev->txq_log.wrapped = 1; + } + return &pdev->txq_log.data[offset + 1 + align_pad]; +} + +/** + * ol_tx_queue_log_record_display() - show log record of tx queue + * @pdev: pointer to txrx handle + * @offset: offset value + * + * Return: size of record + */ +static int +ol_tx_queue_log_record_display(struct ol_txrx_pdev_t *pdev, int offset) +{ + int size, align, align_pad; + u_int8_t type; + struct ol_txrx_peer_t *peer; + + qdf_spin_lock_bh(&pdev->txq_log_spinlock); + type = pdev->txq_log.data[offset]; + ol_tx_queue_log_entry_type_info( + &pdev->txq_log.data[offset], &size, &align, 1); + align_pad = (align - ((offset + 1/*type*/))) & (align - 1); + + switch (type) { + case ol_tx_log_entry_type_enqueue: + { + struct ol_tx_log_queue_add_t record; + qdf_mem_copy(&record, + &pdev->txq_log.data[offset + 1 + align_pad], + sizeof(struct ol_tx_log_queue_add_t)); + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + + if (record.peer_id != 0xffff) { + peer = ol_txrx_peer_find_by_id(pdev, + record.peer_id); + if (peer != NULL) + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "Q: %6d %5d %3d %4d (%02x:%02x:%02x:%02x:%02x:%02x)", + record.num_frms, record.num_bytes, + record.tid, + record.peer_id, + peer->mac_addr.raw[0], + peer->mac_addr.raw[1], + peer->mac_addr.raw[2], + peer->mac_addr.raw[3], + peer->mac_addr.raw[4], + peer->mac_addr.raw[5]); + else + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "Q: %6d %5d %3d %4d", + record.num_frms, record.num_bytes, + record.tid, record.peer_id); + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO, + "Q: %6d %5d %3d from vdev", + record.num_frms, record.num_bytes, + record.tid); + } + break; + } + case ol_tx_log_entry_type_dequeue: + { + struct ol_tx_log_queue_add_t record; + qdf_mem_copy(&record, + &pdev->txq_log.data[offset + 1 + align_pad], + sizeof(struct ol_tx_log_queue_add_t)); + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + + if (record.peer_id != 0xffff) { + peer = ol_txrx_peer_find_by_id(pdev, record.peer_id); + if (peer != NULL) + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "DQ: %6d %5d %3d %4d (%02x:%02x:%02x:%02x:%02x:%02x)", + record.num_frms, record.num_bytes, + record.tid, + record.peer_id, + peer->mac_addr.raw[0], + peer->mac_addr.raw[1], + peer->mac_addr.raw[2], + peer->mac_addr.raw[3], + peer->mac_addr.raw[4], + peer->mac_addr.raw[5]); + else + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "DQ: %6d %5d %3d %4d", + record.num_frms, record.num_bytes, + record.tid, record.peer_id); + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO, + "DQ: %6d %5d %3d from vdev", + record.num_frms, record.num_bytes, + record.tid); + } + break; + } + case ol_tx_log_entry_type_queue_free: + { + struct ol_tx_log_queue_add_t record; + qdf_mem_copy(&record, + &pdev->txq_log.data[offset + 1 + align_pad], + sizeof(struct ol_tx_log_queue_add_t)); + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + + if (record.peer_id != 0xffff) { + peer = ol_txrx_peer_find_by_id(pdev, record.peer_id); + if (peer != NULL) + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "F: %6d %5d %3d %4d (%02x:%02x:%02x:%02x:%02x:%02x)", + record.num_frms, record.num_bytes, + record.tid, + record.peer_id, + peer->mac_addr.raw[0], + peer->mac_addr.raw[1], + peer->mac_addr.raw[2], + peer->mac_addr.raw[3], + peer->mac_addr.raw[4], + peer->mac_addr.raw[5]); + else + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "F: %6d %5d %3d %4d", + record.num_frms, record.num_bytes, + record.tid, record.peer_id); + } else { + /* shouldn't happen */ + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO, + "Unexpected vdev queue removal\n"); + } + break; + } + + case ol_tx_log_entry_type_queue_state: + { + int i, j; + u_int32_t active_bitmap; + struct ol_tx_log_queue_state_var_sz_t record; + u_int8_t *data; + + qdf_mem_copy(&record, + &pdev->txq_log.data[offset + 1 + align_pad], + sizeof(struct ol_tx_log_queue_state_var_sz_t)); + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "S: bitmap = %#x", + record.active_bitmap); + data = &record.data[0]; + j = 0; + i = 0; + active_bitmap = record.active_bitmap; + while (active_bitmap) { + if (active_bitmap & 0x1) { + u_int16_t frms; + u_int32_t bytes; + + frms = data[0] | (data[1] << 8); + bytes = (data[2] << 0) | (data[3] << 8) | + (data[4] << 16) | (data[5] << 24); + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "cat %2d: %6d %5d", + i, frms, bytes); + data += 6; + j++; + } + i++; + active_bitmap >>= 1; + } + break; + } + + /*case ol_tx_log_entry_type_drop:*/ + + case ol_tx_log_entry_type_wrap: + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + return negative_sign * offset; /* go back to the top */ + + default: + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "*** invalid tx log entry type (%d)\n", type); + return 0; /* error */ + }; + + return size + 1 + align_pad; +} + +/** + * ol_tx_queue_log_display() - show tx queue log + * @pdev: pointer to txrx handle + * + * Return: None + */ +void +ol_tx_queue_log_display(struct ol_txrx_pdev_t *pdev) +{ + int offset; + int unwrap; + + qdf_spin_lock_bh(&pdev->txq_log_spinlock); + offset = pdev->txq_log.oldest_record_offset; + unwrap = pdev->txq_log.wrapped; + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + /* + * In theory, this should use mutex to guard against the offset + * being changed while in use, but since this is just for debugging, + * don't bother. + */ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Tx queue log:"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + ": Frames Bytes TID PEER"); + + while (unwrap || offset != pdev->txq_log.offset) { + int delta = ol_tx_queue_log_record_display(pdev, offset); + if (delta == 0) + return; /* error */ + + if (delta < 0) + unwrap = 0; + + offset += delta; + } +} + +void +ol_tx_queue_log_enqueue( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_msdu_info_t *msdu_info, + int frms, int bytes) +{ + int tid; + u_int16_t peer_id = msdu_info->htt.info.peer_id; + struct ol_tx_log_queue_add_t *log_elem; + tid = msdu_info->htt.info.ext_tid; + + qdf_spin_lock_bh(&pdev->txq_log_spinlock); + log_elem = ol_tx_queue_log_alloc(pdev, ol_tx_log_entry_type_enqueue, 0); + if (!log_elem) { + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + return; + } + + log_elem->num_frms = frms; + log_elem->num_bytes = bytes; + log_elem->peer_id = peer_id; + log_elem->tid = tid; + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); +} + +void +ol_tx_queue_log_dequeue( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int frms, int bytes) +{ + int ext_tid; + u_int16_t peer_id; + struct ol_tx_log_queue_add_t *log_elem; + + ext_tid = txq->ext_tid; + qdf_spin_lock_bh(&pdev->txq_log_spinlock); + log_elem = ol_tx_queue_log_alloc(pdev, ol_tx_log_entry_type_dequeue, 0); + if (!log_elem) { + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + return; + } + + if (ext_tid < OL_TX_NUM_TIDS) { + struct ol_txrx_peer_t *peer; + struct ol_tx_frms_queue_t *txq_base; + + txq_base = txq - ext_tid; + peer = container_of(txq_base, struct ol_txrx_peer_t, txqs[0]); + peer_id = peer->peer_ids[0]; + } else { + peer_id = ~0; + } + + log_elem->num_frms = frms; + log_elem->num_bytes = bytes; + log_elem->peer_id = peer_id; + log_elem->tid = ext_tid; + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); +} + +void +ol_tx_queue_log_free( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, int frms, int bytes) +{ + u_int16_t peer_id; + struct ol_tx_log_queue_add_t *log_elem; + + qdf_spin_lock_bh(&pdev->txq_log_spinlock); + log_elem = ol_tx_queue_log_alloc(pdev, ol_tx_log_entry_type_queue_free, + 0); + if (!log_elem) { + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + return; + } + + if (tid < OL_TX_NUM_TIDS) { + struct ol_txrx_peer_t *peer; + struct ol_tx_frms_queue_t *txq_base; + + txq_base = txq - tid; + peer = container_of(txq_base, struct ol_txrx_peer_t, txqs[0]); + peer_id = peer->peer_ids[0]; + } else { + peer_id = ~0; + } + + log_elem->num_frms = frms; + log_elem->num_bytes = bytes; + log_elem->peer_id = peer_id; + log_elem->tid = tid; + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); +} + +void +ol_tx_queue_log_sched( + struct ol_txrx_pdev_t *pdev, + int credit, + int *num_cats, + u_int32_t **active_bitmap, + u_int8_t **data) +{ + int data_size; + struct ol_tx_log_queue_state_var_sz_t *log_elem; + + data_size = sizeof(u_int32_t) /* bytes */ + + sizeof(u_int16_t) /* frms */; + data_size *= *num_cats; + + qdf_spin_lock_bh(&pdev->txq_log_spinlock); + log_elem = ol_tx_queue_log_alloc( + pdev, ol_tx_log_entry_type_queue_state, data_size); + if (!log_elem) { + *num_cats = 0; + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + return; + } + log_elem->num_cats_active = *num_cats; + log_elem->active_bitmap = 0; + log_elem->credit = credit; + + *active_bitmap = &log_elem->active_bitmap; + *data = &log_elem->data[0]; + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); +} + +/** + * ol_tx_queue_log_clear() - clear tx queue log + * @pdev: pointer to txrx handle + * + * Return: None + */ +void +ol_tx_queue_log_clear(struct ol_txrx_pdev_t *pdev) +{ + qdf_spin_lock_bh(&pdev->txq_log_spinlock); + qdf_mem_zero(&pdev->txq_log, sizeof(pdev->txq_log)); + pdev->txq_log.size = OL_TXQ_LOG_SIZE; + pdev->txq_log.oldest_record_offset = 0; + pdev->txq_log.offset = 0; + pdev->txq_log.allow_wrap = 1; + pdev->txq_log.wrapped = 0; + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); +} +#endif /* defined(DEBUG_HL_LOGGING) */ + +/*--- queue state printouts -------------------------------------------------*/ + +#if TXRX_DEBUG_LEVEL > 5 + +/** + * ol_tx_queue_display() - show tx queue info + * @txq: pointer to txq frames + * @indent: indent + * + * Return: None + */ +void +ol_tx_queue_display(struct ol_tx_frms_queue_t *txq, int indent) +{ + char *state; + + state = (txq->flag == ol_tx_queue_active) ? "active" : "paused"; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*stxq %p (%s): %d frms, %d bytes\n", + indent, " ", txq, state, txq->frms, txq->bytes); +} + +void +ol_tx_queues_display(struct ol_txrx_pdev_t *pdev) +{ + struct ol_txrx_vdev_t *vdev; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "pdev %p tx queues:\n", pdev); + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + struct ol_txrx_peer_t *peer; + int i; + for (i = 0; i < QDF_ARRAY_SIZE(vdev->txqs); i++) { + if (vdev->txqs[i].frms == 0) + continue; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "vdev %d (%p), txq %d\n", vdev->vdev_id, + vdev, i); + ol_tx_queue_display(&vdev->txqs[i], 4); + } + TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { + for (i = 0; i < QDF_ARRAY_SIZE(peer->txqs); i++) { + if (peer->txqs[i].frms == 0) + continue; + + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO_LOW, + "peer %d (%p), txq %d\n", + peer->peer_ids[0], vdev, i); + ol_tx_queue_display(&peer->txqs[i], 6); + } + } + } +} +#endif + +#endif /* defined(CONFIG_HL_SUPPORT) */ #if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) @@ -141,12 +1740,14 @@ void ol_txrx_vdev_flush(ol_txrx_vdev_handle vdev) vdev->ll_pause.txq.depth = 0; qdf_spin_unlock_bh(&vdev->ll_pause.mutex); } -#else /* defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) */ +#endif /* defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) */ + +#if (!defined(QCA_LL_LEGACY_TX_FLOW_CONTROL)) && (!defined(CONFIG_HL_SUPPORT)) void ol_txrx_vdev_flush(ol_txrx_vdev_handle data_vdev) { return; } -#endif /* defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) */ +#endif #ifdef QCA_LL_TX_FLOW_CONTROL_V2 @@ -231,6 +1832,9 @@ void ol_txrx_vdev_unpause(ol_txrx_vdev_handle vdev, uint32_t reason) } #endif +#endif + +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(CONFIG_HL_SUPPORT) /** * ol_txrx_pdev_pause() - pause network queues for each vdev @@ -344,6 +1948,7 @@ void ol_tx_pdev_throttle_phase_timer(void *context) /* Traffic is stopped */ TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, "throttle phase --> OFF\n"); + ol_txrx_throttle_pause(pdev); ol_txrx_thermal_pause(pdev); cur_level = pdev->tx_throttle.current_throttle_level; cur_phase = pdev->tx_throttle.current_throttle_phase; @@ -359,6 +1964,7 @@ void ol_tx_pdev_throttle_phase_timer(void *context) /* Traffic can go */ TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, "throttle phase --> ON\n"); + ol_txrx_throttle_unpause(pdev); ol_txrx_thermal_unpause(pdev); cur_level = pdev->tx_throttle.current_throttle_level; cur_phase = pdev->tx_throttle.current_throttle_phase; @@ -381,6 +1987,55 @@ void ol_tx_pdev_throttle_tx_timer(void *context) } #endif +#ifdef CONFIG_HL_SUPPORT + +/** + * ol_tx_set_throttle_phase_time() - Set the thermal mitgation throttle phase + * and time + * @pdev: the peer device object + * @level: throttle phase level + * @ms: throttle time + * + * Return: None + */ +static void +ol_tx_set_throttle_phase_time(struct ol_txrx_pdev_t *pdev, int level, int *ms) +{ + qdf_timer_stop(&pdev->tx_throttle.phase_timer); + + /* Set the phase */ + if (level != THROTTLE_LEVEL_0) { + pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF; + *ms = pdev->tx_throttle.throttle_time_ms[level] + [THROTTLE_PHASE_OFF]; + + /* pause all */ + ol_txrx_throttle_pause(pdev); + } else { + pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_ON; + *ms = pdev->tx_throttle.throttle_time_ms[level] + [THROTTLE_PHASE_ON]; + + /* unpause all */ + ol_txrx_throttle_unpause(pdev); + } +} +#else + +static void +ol_tx_set_throttle_phase_time(struct ol_txrx_pdev_t *pdev, int level, int *ms) +{ + /* Reset the phase */ + pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF; + + /* Start with the new time */ + *ms = pdev->tx_throttle. + throttle_time_ms[level][THROTTLE_PHASE_OFF]; + + qdf_timer_stop(&pdev->tx_throttle.phase_timer); +} +#endif + void ol_tx_throttle_set_level(struct ol_txrx_pdev_t *pdev, int level) { int ms = 0; @@ -397,15 +2052,7 @@ void ol_tx_throttle_set_level(struct ol_txrx_pdev_t *pdev, int level) /* Set the current throttle level */ pdev->tx_throttle.current_throttle_level = (enum throttle_level) level; - /* Reset the phase */ - pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF; - ol_txrx_thermal_unpause(pdev); - - /* Start with the new time */ - ms = pdev->tx_throttle. - throttle_time_ms[level][THROTTLE_PHASE_OFF]; - - qdf_timer_stop(&pdev->tx_throttle.phase_timer); + ol_tx_set_throttle_phase_time(pdev, level, &ms); if (level != THROTTLE_LEVEL_0) qdf_timer_start(&pdev->tx_throttle.phase_timer, ms); @@ -435,6 +2082,7 @@ void ol_tx_throttle_init_period(struct ol_txrx_pdev_t *pdev, int period, pdev->tx_throttle. throttle_time_ms[i][THROTTLE_PHASE_ON]); } + } void ol_tx_throttle_init(struct ol_txrx_pdev_t *pdev) @@ -470,4 +2118,176 @@ void ol_tx_throttle_init(struct ol_txrx_pdev_t *pdev) pdev->tx_throttle.tx_threshold = THROTTLE_TX_THRESHOLD; } #endif /* QCA_SUPPORT_TX_THROTTLE */ + +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +/** + * ol_tx_vdev_has_tx_queue_group() - check for vdev having txq groups + * @group: pointer to tx queue grpup + * @vdev_id: vdev id + * + * Return: true if vedv has txq groups + */ +static bool +ol_tx_vdev_has_tx_queue_group( + struct ol_tx_queue_group_t *group, + u_int8_t vdev_id) +{ + u_int16_t vdev_bitmap; + vdev_bitmap = OL_TXQ_GROUP_VDEV_ID_MASK_GET(group->membership); + if (OL_TXQ_GROUP_VDEV_ID_BIT_MASK_GET(vdev_bitmap, vdev_id)) + return true; + + return false; +} + +/** + * ol_tx_ac_has_tx_queue_group() - check for ac having txq groups + * @group: pointer to tx queue grpup + * @ac: acess category + * + * Return: true if vedv has txq groups + */ +static bool +ol_tx_ac_has_tx_queue_group( + struct ol_tx_queue_group_t *group, + u_int8_t ac) +{ + u_int16_t ac_bitmap; + ac_bitmap = OL_TXQ_GROUP_AC_MASK_GET(group->membership); + if (OL_TXQ_GROUP_AC_BIT_MASK_GET(ac_bitmap, ac)) + return true; + + return false; +} + +u_int32_t ol_tx_txq_group_credit_limit( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + u_int32_t credit) +{ + u_int8_t i; + int updated_credit = credit; + /* + * If this tx queue belongs to a group, check whether the group's + * credit limit is more stringent than the global credit limit. + */ + for (i = 0; i < OL_TX_MAX_GROUPS_PER_QUEUE; i++) { + if (txq->group_ptrs[i]) { + int group_credit; + group_credit = qdf_atomic_read( + &txq->group_ptrs[i]->credit); + updated_credit = QDF_MIN(updated_credit, group_credit); + } + } + + credit = (updated_credit < 0) ? 0 : updated_credit; + + return credit; +} + +void ol_tx_txq_group_credit_update( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int32_t credit, + u_int8_t absolute) +{ + u_int8_t i; + /* + * If this tx queue belongs to a group then + * update group credit + */ + for (i = 0; i < OL_TX_MAX_GROUPS_PER_QUEUE; i++) { + if (txq->group_ptrs[i]) + ol_txrx_update_group_credit(txq->group_ptrs[i], + credit, absolute); + } + ol_tx_update_group_credit_stats(pdev); +} + +void +ol_tx_set_vdev_group_ptr( + ol_txrx_pdev_handle pdev, + u_int8_t vdev_id, + struct ol_tx_queue_group_t *grp_ptr) +{ + struct ol_txrx_vdev_t *vdev = NULL; + struct ol_txrx_peer_t *peer = NULL; + + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + if (vdev->vdev_id == vdev_id) { + u_int8_t i, j; + /* update vdev queues group pointers */ + for (i = 0; i < OL_TX_VDEV_NUM_QUEUES; i++) { + for (j = 0; j < OL_TX_MAX_GROUPS_PER_QUEUE; j++) + vdev->txqs[i].group_ptrs[j] = grp_ptr; + } + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + /* Update peer queue group pointers */ + TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { + for (i = 0; i < OL_TX_NUM_TIDS; i++) { + for (j = 0; + j < OL_TX_MAX_GROUPS_PER_QUEUE; + j++) + peer->txqs[i].group_ptrs[j] = + grp_ptr; + } + } + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + break; + } + } +} + +void ol_tx_txq_set_group_ptr( + struct ol_tx_frms_queue_t *txq, + struct ol_tx_queue_group_t *grp_ptr) +{ + u_int8_t i; + for (i = 0; i < OL_TX_MAX_GROUPS_PER_QUEUE; i++) + txq->group_ptrs[i] = grp_ptr; +} + +void ol_tx_set_peer_group_ptr( + ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + u_int8_t vdev_id, + u_int8_t tid) +{ + u_int8_t i, j = 0; + struct ol_tx_queue_group_t *group = NULL; + + for (i = 0; i < OL_TX_MAX_GROUPS_PER_QUEUE; i++) + peer->txqs[tid].group_ptrs[i] = NULL; + + for (i = 0; i < OL_TX_MAX_TXQ_GROUPS; i++) { + group = &pdev->txq_grps[i]; + if (ol_tx_vdev_has_tx_queue_group(group, vdev_id)) { + if (tid < OL_TX_NUM_QOS_TIDS) { + if (ol_tx_ac_has_tx_queue_group( + group, + TXRX_TID_TO_WMM_AC(tid))) { + peer->txqs[tid].group_ptrs[j] = group; + j++; + } + } else { + peer->txqs[tid].group_ptrs[j] = group; + j++; + } + } + if (j >= OL_TX_MAX_GROUPS_PER_QUEUE) + break; + } +} + +u_int32_t ol_tx_get_max_tx_groups_supported(struct ol_txrx_pdev_t *pdev) +{ +#ifdef HIF_SDIO + return OL_TX_MAX_TXQ_GROUPS; +#else + return 0; +#endif +} +#endif + /*--- End of LL tx throttle queue code ---------------------------------------*/ diff --git a/core/dp/txrx/ol_tx_queue.h b/core/dp/txrx/ol_tx_queue.h index c78bbc20fd3d..56ff9e7d6f68 100644 --- a/core/dp/txrx/ol_tx_queue.h +++ b/core/dp/txrx/ol_tx_queue.h @@ -37,46 +37,405 @@ #include <qdf_types.h> /* bool */ /*--- function prototypes for optional queue log feature --------------------*/ -#if defined(ENABLE_TX_QUEUE_LOG) +#if defined(ENABLE_TX_QUEUE_LOG) || \ + (defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT)) +/** + * ol_tx_queue_log_enqueue() - enqueue tx queue logs + * @pdev: physical device object + * @msdu_info: tx msdu meta data + * @frms: number of frames for which logs need to be enqueued + * @bytes: number of bytes + * + * + * Return: None + */ void ol_tx_queue_log_enqueue(struct ol_txrx_pdev_t *pdev, struct ol_txrx_msdu_info_t *msdu_info, int frms, int bytes); + +/** + * ol_tx_queue_log_dequeue() - dequeue tx queue logs + * @pdev: physical device object + * @txq: tx queue + * @frms: number of frames for which logs need to be dequeued + * @bytes: number of bytes + * + * + * Return: None + */ void ol_tx_queue_log_dequeue(struct ol_txrx_pdev_t *pdev, struct ol_tx_frms_queue_t *txq, int frms, int bytes); + +/** + * ol_tx_queue_log_free() - free tx queue logs + * @pdev: physical device object + * @txq: tx queue + * @tid: tid value + * @frms: number of frames for which logs need to be freed + * @bytes: number of bytes + * + * + * Return: None + */ void ol_tx_queue_log_free(struct ol_txrx_pdev_t *pdev, struct ol_tx_frms_queue_t *txq, int tid, int frms, int bytes); -#define OL_TX_QUEUE_LOG_ENQUEUE ol_tx_queue_log_enqueue -#define OL_TX_QUEUE_LOG_DEQUEUE ol_tx_queue_log_dequeue -#define OL_TX_QUEUE_LOG_FREE ol_tx_queue_log_free #else -#define OL_TX_QUEUE_LOG_ENQUEUE(pdev, msdu_info, frms, bytes) /* no-op */ -#define OL_TX_QUEUE_LOG_DEQUEUE(pdev, txq, frms, bytes) /* no-op */ -#define OL_TX_QUEUE_LOG_FREE(pdev, txq, tid, frms, bytes) /* no-op */ +static inline void +ol_tx_queue_log_enqueue(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_msdu_info_t *msdu_info, + int frms, int bytes) +{ + return; +} + +static inline void +ol_tx_queue_log_dequeue(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, int frms, int bytes) +{ + return; +} + +static inline void +ol_tx_queue_log_free(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, int frms, int bytes) +{ + return; +} -#endif /* TXRX_DEBUG_LEVEL > 5 */ +#endif -#define ol_tx_enqueue(pdev, txq, tx_desc, tx_msdu_info) /* no-op */ -#define ol_tx_dequeue(pdev, ext_tid, txq, head, num_frames, credit, bytes) 0 -#define ol_tx_queue_free(pdev, txq, tid) /* no-op */ -#define ol_tx_queue_discard(pdev, flush, tx_descs) /* no-op */ +#if defined(CONFIG_HL_SUPPORT) +/** + * @brief Queue a tx frame to the tid queue. + * + * @param pdev - the data virtual device sending the data + * (for storing the tx desc in the virtual dev's tx_target_list, + * and for accessing the phy dev) + * @param txq - which queue the tx frame gets stored in + * @param tx_desc - tx meta-data, including prev and next ptrs + * @param tx_msdu_info - characteristics of the tx frame + */ +void +ol_tx_enqueue( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + struct ol_tx_desc_t *tx_desc, + struct ol_txrx_msdu_info_t *tx_msdu_info); + +/** + * @brief - remove the specified number of frames from the head of a tx queue + * @details + * This function removes frames from the head of a tx queue, + * and returns them as a NULL-terminated linked list. + * The function will remove frames until one of the following happens: + * 1. The tx queue is empty + * 2. The specified number of frames have been removed + * 3. Removal of more frames would exceed the specified credit limit + * + * @param pdev - the physical device object + * @param txq - which tx queue to remove frames from + * @param head - which contains return linked-list of tx frames (descriptors) + * @param num_frames - maximum number of frames to remove + * @param[in/out] credit - + * input: max credit the dequeued frames can consume + * output: how much credit the dequeued frames consume + * @param[out] bytes - the sum of the sizes of the dequeued frames + * @return number of frames dequeued +*/ +u_int16_t +ol_tx_dequeue( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + ol_tx_desc_list *head, + u_int16_t num_frames, + u_int32_t *credit, + int *bytes); + +/** + * @brief - free all of frames from the tx queue while deletion + * @details + * This function frees all of frames from the tx queue. + * This function is called during peer or vdev deletion. + * This function notifies the scheduler, so the scheduler can update + * its state to account for the absence of the queue. + * + * @param pdev - the physical device object, which stores the txqs + * @param txq - which tx queue to free frames from + * @param tid - the extended TID that the queue belongs to + */ +void +ol_tx_queue_free( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid); + +/** + * @brief - discard pending tx frames from the tx queue + * @details + * This function is called if there are too many queues in tx scheduler. + * This function is called if we wants to flush all pending tx + * queues in tx scheduler. + * + * @param pdev - the physical device object, which stores the txqs + * @param flush_all - flush all pending tx queues if set to true + * @param tx_descs - List Of tx_descs to be discarded will be returned by this function + */ + +void +ol_tx_queue_discard( + struct ol_txrx_pdev_t *pdev, + bool flush_all, + ol_tx_desc_list *tx_descs); + +#else + +static inline void +ol_tx_enqueue( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + struct ol_tx_desc_t *tx_desc, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + return; +} + +static inline u_int16_t +ol_tx_dequeue( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + ol_tx_desc_list *head, + u_int16_t num_frames, + u_int32_t *credit, + int *bytes) +{ + return 0; +} + +static inline void +ol_tx_queue_free( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid) +{ + return; +} + +static inline void +ol_tx_queue_discard( + struct ol_txrx_pdev_t *pdev, + bool flush_all, + ol_tx_desc_list *tx_descs) +{ + return; +} +#endif /* defined(CONFIG_HL_SUPPORT) */ + +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + +void +ol_txrx_peer_bal_add_limit_peer( + struct ol_txrx_pdev_t *pdev, + u_int16_t peer_id, + u_int16_t peer_limit); + +void +ol_txrx_peer_bal_remove_limit_peer( + struct ol_txrx_pdev_t *pdev, + u_int16_t peer_id); + +/** + * ol_txrx_peer_pause_but_no_mgmt_q() - suspend/pause all txqs except + * management queue for a given peer + * @peer: peer device object + * + * Return: None + */ +void +ol_txrx_peer_pause_but_no_mgmt_q(ol_txrx_peer_handle peer); + +/** + * ol_txrx_peer_unpause_but_no_mgmt_q() - unpause all txqs except management + * queue for a given peer + * @peer: peer device object + * + * Return: None + */ +void +ol_txrx_peer_unpause_but_no_mgmt_q(ol_txrx_peer_handle peer); + +/** + * ol_tx_bad_peer_dequeue_check() - retrieve the send limit + * of the tx queue category + * @txq: tx queue of the head of the category list + * @max_frames: send limit of the txq category + * @tx_limit_flag: set true is tx limit is reached + * + * Return: send limit + */ +u_int16_t +ol_tx_bad_peer_dequeue_check(struct ol_tx_frms_queue_t *txq, + u_int16_t max_frames, + u_int16_t *tx_limit_flag); + +/** + * ol_tx_bad_peer_update_tx_limit() - update the send limit of the + * tx queue category + * @pdev: the physical device object + * @txq: tx queue of the head of the category list + * @frames: frames that has been dequeued + * @tx_limit_flag: tx limit reached flag + * + * Return: None + */ +void +ol_tx_bad_peer_update_tx_limit(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + u_int16_t frames, + u_int16_t tx_limit_flag); + +/** + * ol_txrx_set_txq_peer() - set peer to the tx queue's peer + * @txq: tx queue for a given tid + * @peer: the peer device object + * + * Return: None + */ +void +ol_txrx_set_txq_peer( + struct ol_tx_frms_queue_t *txq, + struct ol_txrx_peer_t *peer); + +/** + * @brief - initialize the peer balance context + * @param pdev - the physical device object, which stores the txqs + */ +void ol_tx_badpeer_flow_cl_init(struct ol_txrx_pdev_t *pdev); + +/** + * @brief - deinitialize the peer balance context + * @param pdev - the physical device object, which stores the txqs + */ +void ol_tx_badpeer_flow_cl_deinit(struct ol_txrx_pdev_t *pdev); + +#else + +static inline void ol_txrx_peer_bal_add_limit_peer( + struct ol_txrx_pdev_t *pdev, + u_int16_t peer_id, + u_int16_t peer_limit) +{ + return; +} + +static inline void ol_txrx_peer_bal_remove_limit_peer( + struct ol_txrx_pdev_t *pdev, + u_int16_t peer_id) +{ + return; +} + +static inline void ol_txrx_peer_pause_but_no_mgmt_q(ol_txrx_peer_handle peer) +{ + return; +} + +static inline void ol_txrx_peer_unpause_but_no_mgmt_q(ol_txrx_peer_handle peer) +{ + return; +} + +static inline u_int16_t +ol_tx_bad_peer_dequeue_check(struct ol_tx_frms_queue_t *txq, + u_int16_t max_frames, + u_int16_t *tx_limit_flag) +{ + /* just return max_frames */ + return max_frames; +} + +static inline void +ol_tx_bad_peer_update_tx_limit(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + u_int16_t frames, + u_int16_t tx_limit_flag) +{ + return; +} + +static inline void +ol_txrx_set_txq_peer( + struct ol_tx_frms_queue_t *txq, + struct ol_txrx_peer_t *peer) +{ + return; +} + +static inline void ol_tx_badpeer_flow_cl_init(struct ol_txrx_pdev_t *pdev) +{ + return; +} + +static inline void ol_tx_badpeer_flow_cl_deinit(struct ol_txrx_pdev_t *pdev) +{ + return; +} + +#endif /* defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) */ + +#if defined(CONFIG_HL_SUPPORT) && defined(DEBUG_HL_LOGGING) + +/** + * ol_tx_queue_log_sched() - start logging of tx queues for HL + * @pdev: physical device object + * @credit: number of credits + * @num_active_tids: number of active tids for which logging needs to be done + * @active_bitmap:bitmap + * @data: buffer + * + * Return: None + */ void ol_tx_queue_log_sched(struct ol_txrx_pdev_t *pdev, int credit, int *num_active_tids, uint32_t **active_bitmap, uint8_t **data); +#else + +static inline void +ol_tx_queue_log_sched(struct ol_txrx_pdev_t *pdev, + int credit, + int *num_active_tids, + uint32_t **active_bitmap, uint8_t **data) +{ + return; +} +#endif /* defined(CONFIG_HL_SUPPORT) && defined(DEBUG_HL_LOGGING) */ + +#if defined(CONFIG_HL_SUPPORT) && TXRX_DEBUG_LEVEL > 5 +/** + * @brief - show current state of all tx queues + * @param pdev - the physical device object, which stores the txqs + */ +void +ol_tx_queues_display(struct ol_txrx_pdev_t *pdev); -#define OL_TX_QUEUE_LOG_SCHED( \ - pdev, credit, num_active_tids, active_bitmap, data) +#else -#define ol_tx_queues_display(pdev) /* no-op */ +static inline void +ol_tx_queues_display(struct ol_txrx_pdev_t *pdev) +{ + return; +} +#endif #define ol_tx_queue_decs_reinit(peer, peer_id) /* no-op */ @@ -89,4 +448,134 @@ void ol_tx_throttle_init(struct ol_txrx_pdev_t *pdev); #else #define ol_tx_throttle_init(pdev) /*no op */ #endif + +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +static inline bool +ol_tx_is_txq_last_serviced_queue(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq) +{ + return txq == pdev->tx_sched.last_used_txq; +} + +/** + * ol_tx_txq_group_credit_limit() - check for credit limit of a given tx queue + * @pdev: physical device object + * @txq: tx queue for which credit limit needs be to checked + * @credit: number of credits of the selected category + * + * Return: updated credits + */ +u_int32_t ol_tx_txq_group_credit_limit( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + u_int32_t credit); + +/** + * ol_tx_txq_group_credit_update() - update group credits of the + * selected catoegory + * @pdev: physical device object + * @txq: tx queue for which credit needs to be updated + * @credit: number of credits by which selected category needs to be updated + * @absolute: TXQ group absolute value + * + * Return: None + */ +void ol_tx_txq_group_credit_update( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int32_t credit, + u_int8_t absolute); + +/** + * ol_tx_set_vdev_group_ptr() - update vdev queues group pointer + * @pdev: physical device object + * @vdev_id: vdev id for which group pointer needs to update + * @grp_ptr: pointer to ol tx queue group which needs to be set for vdev queues + * + * Return: None + */ +void +ol_tx_set_vdev_group_ptr( + ol_txrx_pdev_handle pdev, + u_int8_t vdev_id, + struct ol_tx_queue_group_t *grp_ptr); + +/** + * ol_tx_txq_set_group_ptr() - update tx queue group pointer + * @txq: tx queue of which group pointer needs to update + * @grp_ptr: pointer to ol tx queue group which needs to be + * set for given tx queue + * + * + * Return: None + */ +void +ol_tx_txq_set_group_ptr( + struct ol_tx_frms_queue_t *txq, + struct ol_tx_queue_group_t *grp_ptr); + +/** + * ol_tx_set_peer_group_ptr() - update peer tx queues group pointer + * for a given tid + * @pdev: physical device object + * @peer: peer device object + * @vdev_id: vdev id + * @tid: tid for which group pointer needs to update + * + * + * Return: None + */ +void +ol_tx_set_peer_group_ptr( + ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + u_int8_t vdev_id, + u_int8_t tid); +#else + +static inline bool +ol_tx_is_txq_last_serviced_queue(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq) +{ + return 0; +} + +static inline +u_int32_t ol_tx_txq_group_credit_limit( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + u_int32_t credit) +{ + return credit; +} + +static inline void ol_tx_txq_group_credit_update( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int32_t credit, + u_int8_t absolute) +{ + return; +} + +static inline void +ol_tx_txq_set_group_ptr( + struct ol_tx_frms_queue_t *txq, + struct ol_tx_queue_group_t *grp_ptr) +{ + return; +} + +static inline void +ol_tx_set_peer_group_ptr( + ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + u_int8_t vdev_id, + u_int8_t tid) +{ + return; +} +#endif + #endif /* _OL_TX_QUEUE__H_ */ diff --git a/core/dp/txrx/ol_tx_sched.c b/core/dp/txrx/ol_tx_sched.c new file mode 100644 index 000000000000..bafd83c661eb --- /dev/null +++ b/core/dp/txrx/ol_tx_sched.c @@ -0,0 +1,1482 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include <qdf_nbuf.h> /* qdf_nbuf_t, etc. */ +#include <htt.h> /* HTT_TX_EXT_TID_MGMT */ +#include <ol_htt_tx_api.h> /* htt_tx_desc_tid */ +#include <ol_txrx_api.h> /* ol_txrx_vdev_handle */ +#include <ol_txrx_ctrl_api.h> /* ol_txrx_sync */ +#include <ol_txrx_internal.h> /* TXRX_ASSERT1 */ +#include <ol_txrx_types.h> /* pdev stats, etc. */ +#include <ol_tx_desc.h> /* ol_tx_desc */ +#include <ol_tx_send.h> /* ol_tx_send */ +#include <ol_tx_sched.h> /* OL_TX_SCHED, etc. */ +#include <ol_tx_queue.h> +#include <ol_txrx.h> +#include <qdf_types.h> +#include <qdf_mem.h> /* qdf_os_mem_alloc_consistent et al */ + +#if defined(CONFIG_HL_SUPPORT) + +#if defined(DEBUG_HL_LOGGING) +static void +ol_tx_sched_log(struct ol_txrx_pdev_t *pdev); + +#else +static void +ol_tx_sched_log(struct ol_txrx_pdev_t *pdev) +{ + return; +} +#endif /* defined(DEBUG_HL_LOGGING) */ + +#if DEBUG_HTT_CREDIT +#define OL_TX_DISPATCH_LOG_CREDIT() \ + do { \ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, \ + "TX %d bytes\n", qdf_nbuf_len(msdu)); \ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, \ + " <HTT> Decrease credit %d - 1 = %d, len:%d.\n", \ + qdf_atomic_read(&pdev->target_tx_credit), \ + qdf_atomic_read(&pdev->target_tx_credit) - 1, \ + qdf_nbuf_len(msdu)); \ + } while (0) +#else +#define OL_TX_DISPATCH_LOG_CREDIT() +#endif + +/*--- generic definitions used by the scheduler framework for all algs ---*/ + +struct ol_tx_sched_ctx { + ol_tx_desc_list head; + int frms; +}; + +typedef TAILQ_HEAD(ol_tx_frms_queue_list_s, ol_tx_frms_queue_t) + ol_tx_frms_queue_list; + +#define OL_A_MAX(_x, _y) ((_x) > (_y) ? (_x) : (_y)) + +#define OL_A_MIN(_x, _y) ((_x) < (_y) ? (_x) : (_y)) + + /*--- scheduler algorithm selection ---*/ + + /*--- scheduler options ----------------------------------------------- + * 1. Round-robin scheduler: + * Select the TID that is at the head of the list of active TIDs. + * Select the head tx queue for this TID. + * Move the tx queue to the back of the list of tx queues for + * this TID. + * Move the TID to the back of the list of active TIDs. + * Send as many frames from the tx queue as credit allows. + * 2. Weighted-round-robin advanced scheduler: + * Keep an ordered list of which TID gets selected next. + * Use a weighted-round-robin scheme to determine when to promote + * a TID within this list. + * If a TID at the head of the list is inactive, leave it at the + * head, but check the next TIDs. + * If the credit available is less than the credit threshold for the + * next active TID, don't send anything, and leave the TID at the + * head of the list. + * After a TID is selected, move it to the back of the list. + * Select the head tx queue for this TID. + * Move the tx queue to the back of the list of tx queues for this + * TID. + * Send no more frames than the limit specified for the TID. + */ +#define OL_TX_SCHED_RR 1 +#define OL_TX_SCHED_WRR_ADV 2 + +#ifndef OL_TX_SCHED + /*#define OL_TX_SCHED OL_TX_SCHED_RR*/ +#define OL_TX_SCHED OL_TX_SCHED_WRR_ADV /* default */ +#endif + + +#if OL_TX_SCHED == OL_TX_SCHED_RR + +#define ol_tx_sched_rr_t ol_tx_sched_t + +#define OL_TX_SCHED_NUM_CATEGORIES (OL_TX_NUM_TIDS + OL_TX_VDEV_NUM_QUEUES) + +#define ol_tx_sched_init ol_tx_sched_init_rr +#define ol_tx_sched_select_init(pdev) /* no-op */ +#define ol_tx_sched_select_batch ol_tx_sched_select_batch_rr +#define ol_tx_sched_txq_enqueue ol_tx_sched_txq_enqueue_rr +#define ol_tx_sched_txq_deactivate ol_tx_sched_txq_deactivate_rr +#define ol_tx_sched_category_tx_queues ol_tx_sched_category_tx_queues_rr +#define ol_tx_sched_txq_discard ol_tx_sched_txq_discard_rr +#define ol_tx_sched_category_info ol_tx_sched_category_info_rr +#define ol_tx_sched_discard_select_category \ + ol_tx_sched_discard_select_category_rr + +#elif OL_TX_SCHED == OL_TX_SCHED_WRR_ADV + +#define ol_tx_sched_wrr_adv_t ol_tx_sched_t + +#define OL_TX_SCHED_NUM_CATEGORIES OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES + +#define ol_tx_sched_init ol_tx_sched_init_wrr_adv +#define ol_tx_sched_select_init(pdev) \ + do { \ + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); \ + ol_tx_sched_select_init_wrr_adv(pdev); \ + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); \ + } while (0) +#define ol_tx_sched_select_batch ol_tx_sched_select_batch_wrr_adv +#define ol_tx_sched_txq_enqueue ol_tx_sched_txq_enqueue_wrr_adv +#define ol_tx_sched_txq_deactivate ol_tx_sched_txq_deactivate_wrr_adv +#define ol_tx_sched_category_tx_queues ol_tx_sched_category_tx_queues_wrr_adv +#define ol_tx_sched_txq_discard ol_tx_sched_txq_discard_wrr_adv +#define ol_tx_sched_category_info ol_tx_sched_category_info_wrr_adv +#define ol_tx_sched_discard_select_category \ + ol_tx_sched_discard_select_category_wrr_adv + +#else + +#error Unknown OL TX SCHED specification + +#endif /* OL_TX_SCHED */ + + /*--- round-robin scheduler ----------------------------------------*/ +#if OL_TX_SCHED == OL_TX_SCHED_RR + + /*--- definitions ---*/ + + struct ol_tx_active_queues_in_tid_t { + /* list_elem is used to queue up into up level queues*/ + TAILQ_ENTRY(ol_tx_active_queues_in_tid_t) list_elem; + u_int32_t frms; + u_int32_t bytes; + ol_tx_frms_queue_list head; + bool active; + int tid; + }; + + struct ol_tx_sched_rr_t { + struct ol_tx_active_queues_in_tid_t + tx_active_queues_in_tid_array[OL_TX_NUM_TIDS + + OL_TX_VDEV_NUM_QUEUES]; + TAILQ_HEAD(ol_tx_active_tids_s, ol_tx_active_queues_in_tid_t) + tx_active_tids_list; + u_int8_t discard_weights[OL_TX_NUM_TIDS + + OL_TX_VDEV_NUM_QUEUES]; + }; + +#define TX_SCH_MAX_CREDIT_FOR_THIS_TID(tidq) 16 + +/*--- functions ---*/ + +/* + * The scheduler sync spinlock has been acquired outside this function, + * so there is no need to worry about mutex within this function. + */ +static int +ol_tx_sched_select_batch_rr( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_sched_ctx *sctx, + u_int32_t credit) +{ + struct ol_tx_sched_rr_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_active_queues_in_tid_t *txq_queue; + struct ol_tx_frms_queue_t *next_tq; + u_int16_t frames, used_credits, tx_limit, tx_limit_flag = 0; + int bytes; + + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + + if (TAILQ_EMPTY(&scheduler->tx_active_tids_list)) + return; + + txq_queue = TAILQ_FIRST(&scheduler->tx_active_tids_list); + + TAILQ_REMOVE(&scheduler->tx_active_tids_list, txq_queue, list_elem); + txq_queue->active = false; + + next_tq = TAILQ_FIRST(&txq_queue->head); + TAILQ_REMOVE(&txq_queue->head, next_tq, list_elem); + + credit = OL_A_MIN(credit, TX_SCH_MAX_CREDIT_FOR_THIS_TID(next_tq)); + frames = next_tq->frms; /* download as many frames as credit allows */ + tx_limit = ol_tx_bad_peer_dequeue_check(txq, + category->specs.send_limit, + &tx_limit_flag); + frames = ol_tx_dequeue( + pdev, txq, &sctx->head, tx_limit, &credit, &bytes); + ol_tx_bad_peer_update_tx_limit(pdev, txq, frames, tx_limit_flag); + + used_credits = credit; + txq_queue->frms -= frames; + txq_queue->bytes -= bytes; + + if (next_tq->frms > 0) { + TAILQ_INSERT_TAIL(&txq_queue->head, next_tq, list_elem); + TAILQ_INSERT_TAIL( + &scheduler->tx_active_tids_list, + txq_queue, list_elem); + txq_queue->active = true; + } else if (!TAILQ_EMPTY(&txq_queue->head)) { + /* + * This tx queue is empty, but there's another tx queue for the + * same TID that is not empty. + *Thus, the TID as a whole is active. + */ + TAILQ_INSERT_TAIL( + &scheduler->tx_active_tids_list, + txq_queue, list_elem); + txq_queue->active = true; + } + sctx->frms += frames; + + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); + return used_credits; +} + +static inline void +ol_tx_sched_txq_enqueue_rr( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, + int frms, + int bytes) +{ + struct ol_tx_sched_rr_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_active_queues_in_tid_t *txq_queue; + + txq_queue = &scheduler->tx_active_queues_in_tid_array[tid]; + if (txq->flag != ol_tx_queue_active) + TAILQ_INSERT_TAIL(&txq_queue->head, txq, list_elem); + + txq_queue->frms += frms; + txq_queue->bytes += bytes; + + if (!txq_queue->active) { + TAILQ_INSERT_TAIL( + &scheduler->tx_active_tids_list, + txq_queue, list_elem); + txq_queue->active = true; + } +} + +static inline void +ol_tx_sched_txq_deactivate_rr( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid) +{ + struct ol_tx_sched_rr_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_active_queues_in_tid_t *txq_queue; + + txq_queue = &scheduler->tx_active_queues_in_tid_array[tid]; + txq_queue->frms -= txq->frms; + txq_queue->bytes -= txq->bytes; + + TAILQ_REMOVE(&txq_queue->head, txq, list_elem); + /*if (txq_queue->frms == 0 && txq_queue->active) {*/ + if (TAILQ_EMPTY(&txq_queue->head) && txq_queue->active) { + TAILQ_REMOVE(&scheduler->tx_active_tids_list, txq_queue, + list_elem); + txq_queue->active = false; + } +} + +ol_tx_frms_queue_list * +ol_tx_sched_category_tx_queues_rr(struct ol_txrx_pdev_t *pdev, int tid) +{ + struct ol_tx_sched_rr_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_active_queues_in_tid_t *txq_queue; + + txq_queue = &scheduler->tx_active_queues_in_tid_array[tid]; + return &txq_queue->head; +} + +int +ol_tx_sched_discard_select_category_rr(struct ol_txrx_pdev_t *pdev) +{ + struct ol_tx_sched_rr_t *scheduler; + u_int8_t i, tid = 0; + int max_score = 0; + + scheduler = pdev->tx_sched.scheduler; + /* + * Choose which TID's tx frames to drop next based on two factors: + * 1. Which TID has the most tx frames present + * 2. The TID's priority (high-priority TIDs have a low discard_weight) + */ + for (i = 0; i < (OL_TX_NUM_TIDS + OL_TX_VDEV_NUM_QUEUES); i++) { + int score; + score = + scheduler->tx_active_queues_in_tid_array[i].frms * + scheduler->discard_weights[i]; + if (max_score == 0 || score > max_score) { + max_score = score; + tid = i; + } + } + return tid; +} + +void +ol_tx_sched_txq_discard_rr( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, int frames, int bytes) +{ + struct ol_tx_sched_rr_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_active_queues_in_tid_t *txq_queue; + + txq_queue = &scheduler->tx_active_queues_in_tid_array[tid]; + + if (0 == txq->frms) + TAILQ_REMOVE(&txq_queue->head, txq, list_elem); + + txq_queue->frms -= frames; + txq_queue->bytes -= bytes; + if (txq_queue->active == true && txq_queue->frms == 0) { + TAILQ_REMOVE(&scheduler->tx_active_tids_list, txq_queue, + list_elem); + txq_queue->active = false; + } +} + +void +ol_tx_sched_category_info_rr( + struct ol_txrx_pdev_t *pdev, + int cat, int *active, + int *frms, int *bytes) +{ + struct ol_tx_sched_rr_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_active_queues_in_tid_t *txq_queue; + + txq_queue = &scheduler->tx_active_queues_in_tid_array[cat]; + + *active = txq_queue->active; + *frms = txq_queue->frms; + *bytes = txq_queue->bytes; +} + +enum { + ol_tx_sched_discard_weight_voice = 1, + ol_tx_sched_discard_weight_video = 4, + ol_tx_sched_discard_weight_ucast_default = 8, + ol_tx_sched_discard_weight_mgmt_non_qos = 1, /* 0? */ + ol_tx_sched_discard_weight_mcast = 1, /* 0? also for probe & assoc */ +}; + +void * +ol_tx_sched_init_rr( + struct ol_txrx_pdev_t *pdev) +{ + struct ol_tx_sched_rr_t *scheduler; + int i; + + scheduler = qdf_mem_malloc(sizeof(struct ol_tx_sched_rr_t)); + if (scheduler == NULL) + return scheduler; + + for (i = 0; i < (OL_TX_NUM_TIDS + OL_TX_VDEV_NUM_QUEUES); i++) { + scheduler->tx_active_queues_in_tid_array[i].tid = i; + TAILQ_INIT(&scheduler->tx_active_queues_in_tid_array[i].head); + scheduler->tx_active_queues_in_tid_array[i].active = 0; + scheduler->tx_active_queues_in_tid_array[i].frms = 0; + scheduler->tx_active_queues_in_tid_array[i].bytes = 0; + } + for (i = 0; i < OL_TX_NUM_TIDS; i++) { + scheduler->tx_active_queues_in_tid_array[i].tid = i; + if (i < OL_TX_NON_QOS_TID) { + int ac = TXRX_TID_TO_WMM_AC(i); + switch (ac) { + case TXRX_WMM_AC_VO: + scheduler->discard_weights[i] = + ol_tx_sched_discard_weight_voice; + case TXRX_WMM_AC_VI: + scheduler->discard_weights[i] = + ol_tx_sched_discard_weight_video; + default: + scheduler->discard_weights[i] = + ol_tx_sched_discard_weight_ucast_default; + }; + } else { + scheduler->discard_weights[i] = + ol_tx_sched_discard_weight_mgmt_non_qos; + } + } + for (i = 0; i < OL_TX_VDEV_NUM_QUEUES; i++) { + int j = i + OL_TX_NUM_TIDS; + scheduler->tx_active_queues_in_tid_array[j].tid = + OL_TX_NUM_TIDS - 1; + scheduler->discard_weights[j] = + ol_tx_sched_discard_weight_mcast; + } + TAILQ_INIT(&scheduler->tx_active_tids_list); + + return scheduler; +} + +void +ol_txrx_set_wmm_param(ol_txrx_pdev_handle data_pdev, + struct ol_tx_wmm_param_t wmm_param) +{ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "Dummy function when OL_TX_SCHED_RR is enabled\n"); +} + +#endif /* OL_TX_SCHED == OL_TX_SCHED_RR */ + +/*--- advanced scheduler ----------------------------------------------------*/ +#if OL_TX_SCHED == OL_TX_SCHED_WRR_ADV + +/*--- definitions ---*/ + +struct ol_tx_sched_wrr_adv_category_info_t { + struct { + int wrr_skip_weight; + u_int32_t credit_threshold; + u_int16_t send_limit; + int credit_reserve; + int discard_weight; + } specs; + struct { + int wrr_count; + int frms; + int bytes; + ol_tx_frms_queue_list head; + bool active; + } state; +#ifdef DEBUG_HL_LOGGING + struct { + char *cat_name; + unsigned int queued; + unsigned int dispatched; + unsigned int discard; + } stat; +#endif +}; + +#define OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(cat, \ + wrr_skip_weight, \ + credit_threshold, \ + send_limit, \ + credit_reserve, \ + discard_weights) \ +enum { OL_TX_SCHED_WRR_ADV_ ## cat ## _WRR_SKIP_WEIGHT = \ + (wrr_skip_weight) }; \ +enum { OL_TX_SCHED_WRR_ADV_ ## cat ## _CREDIT_THRESHOLD = \ + (credit_threshold) }; \ +enum { OL_TX_SCHED_WRR_ADV_ ## cat ## _SEND_LIMIT = \ + (send_limit) }; \ +enum { OL_TX_SCHED_WRR_ADV_ ## cat ## _CREDIT_RESERVE = \ + (credit_reserve) }; \ +enum { OL_TX_SCHED_WRR_ADV_ ## cat ## _DISCARD_WEIGHT = \ + (discard_weights) } + +/* Rome: + * For high-volume traffic flows (VI, BE, BK), use a credit threshold + * roughly equal to a large A-MPDU (occupying half the target memory + * available for holding tx frames) to download AMPDU-sized batches + * of traffic. + * For high-priority, low-volume traffic flows (VO and mgmt), use no + * credit threshold, to minimize download latency. + */ +/* WRR send + * skip credit limit credit disc + * wts thresh (frms) reserv wts + */ +#ifdef HIF_SDIO +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(VO, 1, 17, 24, 0, 1); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(VI, 3, 17, 16, 1, 4); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(BE, 10, 17, 16, 1, 8); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(BK, 12, 6, 6, 1, 8); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(NON_QOS_DATA, 12, 6, 4, 1, 8); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(UCAST_MGMT, 1, 1, 4, 0, 1); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(MCAST_DATA, 10, 17, 4, 1, 4); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(MCAST_MGMT, 1, 1, 4, 0, 1); +#else +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(VO, 1, 16, 24, 0, 1); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(VI, 3, 16, 16, 1, 4); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(BE, 10, 12, 12, 1, 8); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(BK, 12, 6, 6, 1, 8); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(NON_QOS_DATA, 12, 6, 4, 1, 8); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(UCAST_MGMT, 1, 1, 4, 0, 1); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(MCAST_DATA, 10, 16, 4, 1, 4); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(MCAST_MGMT, 1, 1, 4, 0, 1); +#endif + +#ifdef DEBUG_HL_LOGGING + +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INIT(category, scheduler) \ + do { \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .stat.queued = 0; \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .stat.discard = 0; \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .stat.dispatched = 0; \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .stat.cat_name = #category; \ + } while (0) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_QUEUED(category, frms) \ + do { \ + category->stat.queued += frms; \ + } while (0) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_DISCARD(category, frms) \ + do { \ + category->stat.discard += frms; \ + } while (0) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_DISPATCHED(category, frms) \ + do { \ + category->stat.dispatched += frms; \ + } while (0) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_DUMP(scheduler) \ + ol_tx_sched_wrr_adv_cat_stat_dump(scheduler) +#define OL_TX_SCHED_WRR_ADV_CAT_CUR_STATE_DUMP(scheduler) \ + ol_tx_sched_wrr_adv_cat_cur_state_dump(scheduler) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_CLEAR(scheduler) \ + ol_tx_sched_wrr_adv_cat_stat_clear(scheduler) + +#else /* DEBUG_HL_LOGGING */ + +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INIT(category, scheduler) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_QUEUED(category, frms) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_DISCARD(category, frms) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_DISPATCHED(category, frms) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_DUMP(scheduler) +#define OL_TX_SCHED_WRR_ADV_CAT_CUR_STATE_DUMP(scheduler) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_CLEAR(scheduler) + +#endif /* DEBUG_HL_LOGGING */ + +#define OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(category, scheduler) \ + do { \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .specs.wrr_skip_weight = \ + OL_TX_SCHED_WRR_ADV_ ## category ## _WRR_SKIP_WEIGHT; \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .specs.credit_threshold = \ + OL_TX_SCHED_WRR_ADV_ ## category ## _CREDIT_THRESHOLD; \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .specs.send_limit = \ + OL_TX_SCHED_WRR_ADV_ ## category ## _SEND_LIMIT; \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .specs.credit_reserve = \ + OL_TX_SCHED_WRR_ADV_ ## category ## _CREDIT_RESERVE; \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .specs.discard_weight = \ + OL_TX_SCHED_WRR_ADV_ ## category ## _DISCARD_WEIGHT; \ + OL_TX_SCHED_WRR_ADV_CAT_STAT_INIT(category, scheduler); \ + } while (0) + +struct ol_tx_sched_wrr_adv_t { + int order[OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES]; + int index; + struct ol_tx_sched_wrr_adv_category_info_t + categories[OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES]; +}; + +#define OL_TX_AIFS_DEFAULT_VO 2 +#define OL_TX_AIFS_DEFAULT_VI 2 +#define OL_TX_AIFS_DEFAULT_BE 3 +#define OL_TX_AIFS_DEFAULT_BK 7 +#define OL_TX_CW_MIN_DEFAULT_VO 3 +#define OL_TX_CW_MIN_DEFAULT_VI 7 +#define OL_TX_CW_MIN_DEFAULT_BE 15 +#define OL_TX_CW_MIN_DEFAULT_BK 15 + +/*--- functions ---*/ + +#ifdef DEBUG_HL_LOGGING +static void ol_tx_sched_wrr_adv_cat_stat_dump( + struct ol_tx_sched_wrr_adv_t *scheduler) +{ + int i; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Scheduler Stats:"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "====category(CRR,CRT,WSW): Queued Discard Dequeued frms wrr==="); + for (i = 0; i < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES; ++i) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%12s(%2d, %2d, %2d): %6d %7d %8d %4d %3d", + scheduler->categories[i].stat.cat_name, + scheduler->categories[i].specs.credit_reserve, + scheduler->categories[i].specs.credit_threshold, + scheduler->categories[i].specs.wrr_skip_weight, + scheduler->categories[i].stat.queued, + scheduler->categories[i].stat.discard, + scheduler->categories[i].stat.dispatched, + scheduler->categories[i].state.frms, + scheduler->categories[i].state.wrr_count); + } +} + +static void ol_tx_sched_wrr_adv_cat_cur_state_dump( + struct ol_tx_sched_wrr_adv_t *scheduler) +{ + int i; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Scheduler State Snapshot:"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "====category(CRR,CRT,WSW): IS_Active Pend_Frames Pend_bytes wrr==="); + for (i = 0; i < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES; ++i) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%12s(%2d, %2d, %2d): %9d %11d %10d %3d", + scheduler->categories[i].stat.cat_name, + scheduler->categories[i].specs.credit_reserve, + scheduler->categories[i].specs.credit_threshold, + scheduler->categories[i].specs.wrr_skip_weight, + scheduler->categories[i].state.active, + scheduler->categories[i].state.frms, + scheduler->categories[i].state.bytes, + scheduler->categories[i].state.wrr_count); + } +} + +static void ol_tx_sched_wrr_adv_cat_stat_clear( + struct ol_tx_sched_wrr_adv_t *scheduler) +{ + int i; + for (i = 0; i < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES; ++i) { + scheduler->categories[i].stat.queued = 0; + scheduler->categories[i].stat.discard = 0; + scheduler->categories[i].stat.dispatched = 0; + } +} + +#endif + +static void +ol_tx_sched_select_init_wrr_adv(struct ol_txrx_pdev_t *pdev) +{ + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + /* start selection from the front of the ordered list */ + scheduler->index = 0; + pdev->tx_sched.last_used_txq = NULL; +} + +static void +ol_tx_sched_wrr_adv_rotate_order_list_tail( + struct ol_tx_sched_wrr_adv_t *scheduler, int idx) +{ + int value; + /* remember the value of the specified element */ + value = scheduler->order[idx]; + /* shift all further elements up one space */ + for (; idx < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES-1; idx++) + scheduler->order[idx] = scheduler->order[idx + 1]; + + /* put the specified element at the end */ + scheduler->order[idx] = value; +} + +static void +ol_tx_sched_wrr_adv_credit_sanity_check(struct ol_txrx_pdev_t *pdev, + u_int32_t credit) +{ + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + int i; + int okay = 1; + + for (i = 0; i < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES; i++) { + if (scheduler->categories[i].specs.credit_threshold > credit) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "*** Config error: credit (%d) not enough to support category %d threshold (%d)\n", + credit, i, + scheduler->categories[i].specs. + credit_threshold); + okay = 0; + } + } + qdf_assert(okay); +} + +/* + * The scheduler sync spinlock has been acquired outside this function, + * so there is no need to worry about mutex within this function. + */ +static int +ol_tx_sched_select_batch_wrr_adv( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_sched_ctx *sctx, + u_int32_t credit) +{ + static int first = 1; + int category_index = 0; + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_frms_queue_t *txq; + int index; + struct ol_tx_sched_wrr_adv_category_info_t *category = NULL; + int frames, bytes, used_credits = 0, tx_limit; + u_int16_t tx_limit_flag; + + /* + * Just for good measure, do a sanity check that the initial credit + * is enough to cover every category's credit threshold. + */ + if (first) { + first = 0; + ol_tx_sched_wrr_adv_credit_sanity_check(pdev, credit); + } + + /* choose the traffic category from the ordered list */ + index = scheduler->index; + while (index < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES) { + category_index = scheduler->order[index]; + category = &scheduler->categories[category_index]; + if (!category->state.active) { + /* move on to the next category */ + index++; + continue; + } + if (++category->state.wrr_count < + category->specs.wrr_skip_weight) { + /* skip this cateogry (move it to the back) */ + ol_tx_sched_wrr_adv_rotate_order_list_tail(scheduler, + index); + /* try again (iterate) on the new element + *that was moved up */ + continue; + } + /* found the first active category whose WRR turn is present */ + break; + } + if (index >= OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES) { + /* no categories are active */ + return 0; + } + + /* is there enough credit for the selected category? */ + if (credit < category->specs.credit_threshold) { + /* + * Can't send yet - wait until more credit becomes available. + * In the meantime, restore the WRR counter (since we didn't + * service this category after all). + */ + category->state.wrr_count = category->state.wrr_count - 1; + return 0; + } + /* enough credit is available - go ahead and send some frames */ + /* + * This category was serviced - reset the WRR counter, and move this + * category to the back of the order list. + */ + category->state.wrr_count = 0; + ol_tx_sched_wrr_adv_rotate_order_list_tail(scheduler, index); + /* + * With this category moved to the back, if there's still any credit + * left, set up the next invocation of this function to start from + * where this one left off, by looking at the category that just got + * shifted forward into the position the service category was + * occupying. + */ + scheduler->index = index; + + /* + * Take the tx queue from the head of the category list. + */ + txq = TAILQ_FIRST(&category->state.head); + + if (txq) { + TAILQ_REMOVE(&category->state.head, txq, list_elem); + credit = ol_tx_txq_group_credit_limit(pdev, txq, credit); + if (credit > category->specs.credit_reserve) { + credit -= category->specs.credit_reserve; + /* + * this tx queue will download some frames, + * so update last_used_txq + */ + pdev->tx_sched.last_used_txq = txq; + + tx_limit = ol_tx_bad_peer_dequeue_check(txq, + category->specs.send_limit, + &tx_limit_flag); + frames = ol_tx_dequeue( + pdev, txq, &sctx->head, + tx_limit, &credit, &bytes); + ol_tx_bad_peer_update_tx_limit(pdev, txq, + frames, + tx_limit_flag); + + OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_DISPATCHED(category, + frames); + used_credits = credit; + category->state.frms -= frames; + category->state.bytes -= bytes; + if (txq->frms > 0) { + TAILQ_INSERT_TAIL(&category->state.head, + txq, list_elem); + } else { + if (category->state.frms == 0) + category->state.active = 0; + } + sctx->frms += frames; + ol_tx_txq_group_credit_update(pdev, txq, -credit, 0); + } else { + if (ol_tx_is_txq_last_serviced_queue(pdev, txq)) { + /* + * The scheduler has looked at all the active + * tx queues but none were able to download any + * of their tx frames. + * Nothing is changed, so if none were able + * to download before, + * they wont be able to download now. + * Return that no credit has been used, which + * will cause the scheduler to stop. + */ + TAILQ_INSERT_HEAD(&category->state.head, txq, + list_elem); + return 0; + } else { + TAILQ_INSERT_TAIL(&category->state.head, txq, + list_elem); + if (!pdev->tx_sched.last_used_txq) + pdev->tx_sched.last_used_txq = txq; + } + } + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); + } else { + used_credits = 0; + /* TODO: find its reason */ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "ol_tx_sched_select_batch_wrr_adv: error, no TXQ can be popped."); + } + return used_credits; +} + +static inline void +ol_tx_sched_txq_enqueue_wrr_adv( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, + int frms, + int bytes) +{ + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_sched_wrr_adv_category_info_t *category; + + category = &scheduler->categories[pdev->tid_to_ac[tid]]; + category->state.frms += frms; + category->state.bytes += bytes; + OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_QUEUED(category, frms); + if (txq->flag != ol_tx_queue_active) { + TAILQ_INSERT_TAIL(&category->state.head, txq, list_elem); + category->state.active = 1; /* may have already been active */ + } +} + +static inline void +ol_tx_sched_txq_deactivate_wrr_adv( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid) +{ + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_sched_wrr_adv_category_info_t *category; + + category = &scheduler->categories[pdev->tid_to_ac[tid]]; + category->state.frms -= txq->frms; + category->state.bytes -= txq->bytes; + + TAILQ_REMOVE(&category->state.head, txq, list_elem); + + if (category->state.frms == 0 && category->state.active) + category->state.active = 0; +} + +ol_tx_frms_queue_list * +ol_tx_sched_category_tx_queues_wrr_adv(struct ol_txrx_pdev_t *pdev, int cat) +{ + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_sched_wrr_adv_category_info_t *category; + + category = &scheduler->categories[cat]; + return &category->state.head; +} + +int +ol_tx_sched_discard_select_category_wrr_adv(struct ol_txrx_pdev_t *pdev) +{ + struct ol_tx_sched_wrr_adv_t *scheduler; + u_int8_t i, cat = 0; + int max_score = 0; + + scheduler = pdev->tx_sched.scheduler; + /* + * Choose which category's tx frames to drop next based on two factors: + * 1. Which category has the most tx frames present + * 2. The category's priority (high-priority categories have a low + * discard_weight) + */ + for (i = 0; i < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES; i++) { + int score; + score = + scheduler->categories[i].state.frms * + scheduler->categories[i].specs.discard_weight; + if (max_score == 0 || score > max_score) { + max_score = score; + cat = i; + } + } + return cat; +} + +void +ol_tx_sched_txq_discard_wrr_adv( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int cat, int frames, int bytes) +{ + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_sched_wrr_adv_category_info_t *category; + + category = &scheduler->categories[cat]; + + if (0 == txq->frms) + TAILQ_REMOVE(&category->state.head, txq, list_elem); + + + category->state.frms -= frames; + category->state.bytes -= bytes; + OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_DISCARD(category, frames); + if (category->state.frms == 0) + category->state.active = 0; +} + +void +ol_tx_sched_category_info_wrr_adv( + struct ol_txrx_pdev_t *pdev, + int cat, int *active, + int *frms, int *bytes) +{ + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_sched_wrr_adv_category_info_t *category; + + category = &scheduler->categories[cat]; + *active = category->state.active; + *frms = category->state.frms; + *bytes = category->state.bytes; +} + +void * +ol_tx_sched_init_wrr_adv( + struct ol_txrx_pdev_t *pdev) +{ + struct ol_tx_sched_wrr_adv_t *scheduler; + int i; + + scheduler = qdf_mem_malloc( + sizeof(struct ol_tx_sched_wrr_adv_t)); + if (scheduler == NULL) + return scheduler; + + qdf_mem_zero(scheduler, sizeof(*scheduler)); + + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(VO, scheduler); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(VI, scheduler); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(BE, scheduler); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(BK, scheduler); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(NON_QOS_DATA, scheduler); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(UCAST_MGMT, scheduler); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(MCAST_DATA, scheduler); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(MCAST_MGMT, scheduler); + + for (i = 0; i < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES; i++) { + scheduler->categories[i].state.active = 0; + scheduler->categories[i].state.frms = 0; + /*scheduler->categories[i].state.bytes = 0;*/ + TAILQ_INIT(&scheduler->categories[i].state.head); + /* init categories to not be skipped before + *their initial selection */ + scheduler->categories[i].state.wrr_count = + scheduler->categories[i].specs.wrr_skip_weight - 1; + } + + /* + * Init the order array - the initial ordering doesn't matter, as the + * order array will get reshuffled as data arrives. + */ + for (i = 0; i < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES; i++) + scheduler->order[i] = i; + + return scheduler; +} + + +/* WMM parameters are suppposed to be passed when associate with AP. + * According to AIFS+CWMin, the function maps each queue to one of four default + * settings of the scheduler, ie. VO, VI, BE, or BK. + */ +void +ol_txrx_set_wmm_param(ol_txrx_pdev_handle data_pdev, + struct ol_tx_wmm_param_t wmm_param) +{ + struct ol_tx_sched_wrr_adv_t def_cfg; + struct ol_tx_sched_wrr_adv_t *scheduler = + data_pdev->tx_sched.scheduler; + u_int32_t i, ac_selected; + u_int32_t weight[OL_TX_NUM_WMM_AC], default_edca[OL_TX_NUM_WMM_AC]; + + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(VO, (&def_cfg)); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(VI, (&def_cfg)); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(BE, (&def_cfg)); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(BK, (&def_cfg)); + + /* default_eca = AIFS + CWMin */ + default_edca[OL_TX_SCHED_WRR_ADV_CAT_VO] = + OL_TX_AIFS_DEFAULT_VO + OL_TX_CW_MIN_DEFAULT_VO; + default_edca[OL_TX_SCHED_WRR_ADV_CAT_VI] = + OL_TX_AIFS_DEFAULT_VI + OL_TX_CW_MIN_DEFAULT_VI; + default_edca[OL_TX_SCHED_WRR_ADV_CAT_BE] = + OL_TX_AIFS_DEFAULT_BE + OL_TX_CW_MIN_DEFAULT_BE; + default_edca[OL_TX_SCHED_WRR_ADV_CAT_BK] = + OL_TX_AIFS_DEFAULT_BK + OL_TX_CW_MIN_DEFAULT_BK; + + weight[OL_TX_SCHED_WRR_ADV_CAT_VO] = + wmm_param.ac[OL_TX_WMM_AC_VO].aifs + + wmm_param.ac[OL_TX_WMM_AC_VO].cwmin; + weight[OL_TX_SCHED_WRR_ADV_CAT_VI] = + wmm_param.ac[OL_TX_WMM_AC_VI].aifs + + wmm_param.ac[OL_TX_WMM_AC_VI].cwmin; + weight[OL_TX_SCHED_WRR_ADV_CAT_BK] = + wmm_param.ac[OL_TX_WMM_AC_BK].aifs + + wmm_param.ac[OL_TX_WMM_AC_BK].cwmin; + weight[OL_TX_SCHED_WRR_ADV_CAT_BE] = + wmm_param.ac[OL_TX_WMM_AC_BE].aifs + + wmm_param.ac[OL_TX_WMM_AC_BE].cwmin; + + for (i = 0; i < OL_TX_NUM_WMM_AC; i++) { + if (default_edca[OL_TX_SCHED_WRR_ADV_CAT_VO] >= weight[i]) + ac_selected = OL_TX_SCHED_WRR_ADV_CAT_VO; + else if (default_edca[OL_TX_SCHED_WRR_ADV_CAT_VI] >= weight[i]) + ac_selected = OL_TX_SCHED_WRR_ADV_CAT_VI; + else if (default_edca[OL_TX_SCHED_WRR_ADV_CAT_BE] >= weight[i]) + ac_selected = OL_TX_SCHED_WRR_ADV_CAT_BE; + else + ac_selected = OL_TX_SCHED_WRR_ADV_CAT_BK; + + + scheduler->categories[i].specs.wrr_skip_weight = + def_cfg.categories[ac_selected].specs.wrr_skip_weight; + scheduler->categories[i].specs.credit_threshold = + def_cfg.categories[ac_selected].specs.credit_threshold; + scheduler->categories[i].specs.send_limit = + def_cfg.categories[ac_selected].specs.send_limit; + scheduler->categories[i].specs.credit_reserve = + def_cfg.categories[ac_selected].specs.credit_reserve; + scheduler->categories[i].specs.discard_weight = + def_cfg.categories[ac_selected].specs.discard_weight; + } +} + +#endif /* OL_TX_SCHED == OL_TX_SCHED_WRR_ADV */ + +/*--- congestion control discard --------------------------------------------*/ + +struct ol_tx_frms_queue_t * +ol_tx_sched_discard_select_txq( + struct ol_txrx_pdev_t *pdev, + ol_tx_frms_queue_list *tx_queues) +{ + struct ol_tx_frms_queue_t *txq; + struct ol_tx_frms_queue_t *selected_txq = NULL; + int max_frms = 0; + + /* return the tx queue with the most frames */ + TAILQ_FOREACH(txq, tx_queues, list_elem) { + if (txq->frms > max_frms) { + max_frms = txq->frms; + selected_txq = txq; + } + } + return selected_txq; +} + +u_int16_t +ol_tx_sched_discard_select( + struct ol_txrx_pdev_t *pdev, + u_int16_t frms, + ol_tx_desc_list *tx_descs, + bool force) +{ + int cat; + struct ol_tx_frms_queue_t *txq; + int bytes; + u_int32_t credit; + struct ol_tx_sched_notify_ctx_t notify_ctx; + + /* first decide what category of traffic (e.g. TID or AC) + *to discard next */ + cat = ol_tx_sched_discard_select_category(pdev); + + /* then decide which peer within this category to discard from next */ + txq = ol_tx_sched_discard_select_txq( + pdev, ol_tx_sched_category_tx_queues(pdev, cat)); + if (NULL == txq) + /* No More pending Tx Packets in Tx Queue. Exit Discard loop */ + return 0; + + + if (force == false) { + /* + * Now decide how many frames to discard from this peer-TID. + * Don't discard more frames than the caller has specified. + * Don't discard more than a fixed quantum of frames at a time. + * Don't discard more than 50% of the queue's frames at a time, + * but if there's only 1 frame left, go ahead and discard it. + */ +#define OL_TX_DISCARD_QUANTUM 10 + if (OL_TX_DISCARD_QUANTUM < frms) + frms = OL_TX_DISCARD_QUANTUM; + + + if (txq->frms > 1 && frms >= (txq->frms >> 1)) + frms = txq->frms >> 1; + } + + /* + * Discard from the head of the queue, because: + * 1. Front-dropping gives applications like TCP that include ARQ + * an early notification of congestion. + * 2. For time-sensitive applications like RTP, the newest frames are + * most relevant. + */ + credit = 10000; /* no credit limit */ + frms = ol_tx_dequeue(pdev, txq, tx_descs, frms, &credit, &bytes); + + notify_ctx.event = OL_TX_DISCARD_FRAMES; + notify_ctx.frames = frms; + notify_ctx.bytes = bytes; + notify_ctx.txq = txq; + notify_ctx.info.ext_tid = cat; + ol_tx_sched_notify(pdev, ¬ify_ctx); + + TX_SCHED_DEBUG_PRINT("%s Tx Drop : %d\n", __func__, frms); + return frms; +} + +/*--- scheduler framework ---------------------------------------------------*/ + +/* + * The scheduler mutex spinlock has been acquired outside this function, + * so there is need to take locks inside this function. + */ +void +ol_tx_sched_notify( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_sched_notify_ctx_t *ctx) +{ + struct ol_tx_frms_queue_t *txq = ctx->txq; + int tid; + + if (!pdev->tx_sched.scheduler) + return; + + switch (ctx->event) { + case OL_TX_ENQUEUE_FRAME: + tid = ctx->info.tx_msdu_info->htt.info.ext_tid; + ol_tx_sched_txq_enqueue(pdev, txq, tid, 1, ctx->bytes); + break; + case OL_TX_DELETE_QUEUE: + tid = ctx->info.ext_tid; + if (txq->flag == ol_tx_queue_active) + ol_tx_sched_txq_deactivate(pdev, txq, tid); + + break; + case OL_TX_PAUSE_QUEUE: + tid = ctx->info.ext_tid; + if (txq->flag == ol_tx_queue_active) + ol_tx_sched_txq_deactivate(pdev, txq, tid); + + break; + case OL_TX_UNPAUSE_QUEUE: + tid = ctx->info.ext_tid; + if (txq->frms != 0) + ol_tx_sched_txq_enqueue(pdev, txq, tid, + txq->frms, txq->bytes); + + break; + case OL_TX_DISCARD_FRAMES: + /* not necessarily TID, could be category */ + tid = ctx->info.ext_tid; + ol_tx_sched_txq_discard(pdev, txq, tid, + ctx->frames, ctx->bytes); + break; + default: + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Error: unknown sched notification (%d)\n", + ctx->event); + qdf_assert(0); + break; + } +} + +#define OL_TX_MSDU_ID_STORAGE_ERR(ptr) (NULL == ptr) + +void +ol_tx_sched_dispatch( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_sched_ctx *sctx) +{ + qdf_nbuf_t msdu, prev = NULL, head_msdu = NULL; + struct ol_tx_desc_t *tx_desc; + + u_int16_t *msdu_id_storage; + u_int16_t msdu_id; + int num_msdus = 0; + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + while (sctx->frms) { + tx_desc = TAILQ_FIRST(&sctx->head); + if (tx_desc == NULL) { + /* TODO: find its reason */ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: err, no enough tx_desc from stx->head.\n", + __func__); + break; + } + msdu = tx_desc->netbuf; + TAILQ_REMOVE(&sctx->head, tx_desc, tx_desc_list_elem); + if (NULL == head_msdu) + head_msdu = msdu; + + if (prev) + qdf_nbuf_set_next(prev, msdu); + + prev = msdu; + +#ifndef ATH_11AC_TXCOMPACT + /* + * When the tx frame is downloaded to the target, there are two + * outstanding references: + * 1. The host download SW (HTT, HTC, HIF) + * This reference is cleared by the ol_tx_send_done callback + * functions. + * 2. The target FW + * This reference is cleared by the ol_tx_completion_handler + * function. + * It is extremely probable that the download completion is + * processed before the tx completion message. However, under + * exceptional conditions the tx completion may be processed + *first. Thus, rather that assuming that reference (1) is + *done before reference (2), + * explicit reference tracking is needed. + * Double-increment the ref count to account for both references + * described above. + */ + qdf_atomic_init(&tx_desc->ref_cnt); + qdf_atomic_inc(&tx_desc->ref_cnt); + qdf_atomic_inc(&tx_desc->ref_cnt); +#endif + + /*Store the MSDU Id for each MSDU*/ + /* store MSDU ID */ + msdu_id = ol_tx_desc_id(pdev, tx_desc); + msdu_id_storage = ol_tx_msdu_id_storage(msdu); + if (OL_TX_MSDU_ID_STORAGE_ERR(msdu_id_storage)) { + /* + * Send the prior frames as a batch, + *then send this as a single, + * then resume handling the remaining frames. + */ + if (head_msdu) + ol_tx_send_batch(pdev, head_msdu, num_msdus); + + prev = NULL; + head_msdu = prev; + num_msdus = 0; + + if (htt_tx_send_std(pdev->htt_pdev, msdu, msdu_id)) { + ol_tx_target_credit_incr(pdev, msdu); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, + 1 /* error */); + } + } else { + *msdu_id_storage = msdu_id; + num_msdus++; + } + sctx->frms--; + } + + /*Send Batch Of Frames*/ + if (head_msdu) + ol_tx_send_batch(pdev, head_msdu, num_msdus); + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + + void +ol_tx_sched(struct ol_txrx_pdev_t *pdev) +{ + struct ol_tx_sched_ctx sctx; + u_int32_t credit; + + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + if (pdev->tx_sched.tx_sched_status != ol_tx_scheduler_idle) { + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + return; + } + pdev->tx_sched.tx_sched_status = ol_tx_scheduler_running; + + ol_tx_sched_log(pdev); + /*adf_os_print("BEFORE tx sched:\n");*/ + /*ol_tx_queues_display(pdev);*/ + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + + TAILQ_INIT(&sctx.head); + sctx.frms = 0; + + ol_tx_sched_select_init(pdev); + while (qdf_atomic_read(&pdev->target_tx_credit) > 0) { + int num_credits; + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + credit = qdf_atomic_read(&pdev->target_tx_credit); + num_credits = ol_tx_sched_select_batch(pdev, &sctx, credit); + if (num_credits > 0) { +#if DEBUG_HTT_CREDIT + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + " <HTT> Decrease credit %d - %d = %d.\n", + qdf_atomic_read(&pdev->target_tx_credit), + num_credits, + qdf_atomic_read(&pdev->target_tx_credit) - + num_credits); +#endif + qdf_atomic_add(-num_credits, &pdev->target_tx_credit); + } + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + + if (num_credits == 0) + break; + } + ol_tx_sched_dispatch(pdev, &sctx); + + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + /*adf_os_print("AFTER tx sched:\n");*/ + /*ol_tx_queues_display(pdev);*/ + + pdev->tx_sched.tx_sched_status = ol_tx_scheduler_idle; + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + +void * +ol_tx_sched_attach( + struct ol_txrx_pdev_t *pdev) +{ + pdev->tx_sched.tx_sched_status = ol_tx_scheduler_idle; + return ol_tx_sched_init(pdev); +} + +void +ol_tx_sched_detach( + struct ol_txrx_pdev_t *pdev) +{ + if (pdev->tx_sched.scheduler) { + qdf_mem_free(pdev->tx_sched.scheduler); + pdev->tx_sched.scheduler = NULL; + } +} + +/*--- debug functions -------------------------------------------------------*/ + +#if defined(DEBUG_HL_LOGGING) + +static void +ol_tx_sched_log(struct ol_txrx_pdev_t *pdev) +{ + u_int8_t *buf; + u_int32_t *active_bitmap; + int i, j, num_cats_active; + int active, frms, bytes; + int credit; + + /* don't bother recording state if credit is zero */ + credit = qdf_atomic_read(&pdev->target_tx_credit); + if (credit == 0) + return; + + + /* + * See how many TIDs are active, so queue state can be stored only + * for those TIDs. + * Do an initial iteration through all categories to see if any + * are active. Doing an extra iteration is inefficient, but + * efficiency is not a dominant concern when logging is enabled. + */ + num_cats_active = 0; + for (i = 0; i < OL_TX_SCHED_NUM_CATEGORIES; i++) { + ol_tx_sched_category_info(pdev, i, &active, &frms, &bytes); + if (active) + num_cats_active++; + } + /* don't bother recording state if there are no active queues */ + if (num_cats_active == 0) + return; + + + ol_tx_queue_log_sched(pdev, credit, &num_cats_active, + &active_bitmap, &buf); + + if (num_cats_active == 0) + return; + + *active_bitmap = 0; + for (i = 0, j = 0; + i < OL_TX_SCHED_NUM_CATEGORIES && j < num_cats_active; + i++) { + u_int8_t *p; + ol_tx_sched_category_info(pdev, i, &active, &frms, &bytes); + if (!active) + continue; + + p = &buf[j*6]; + p[0] = (frms >> 0) & 0xff; + p[1] = (frms >> 8) & 0xff; + + p[2] = (bytes >> 0) & 0xff; + p[3] = (bytes >> 8) & 0xff; + p[4] = (bytes >> 16) & 0xff; + p[5] = (bytes >> 24) & 0xff; + j++; + *active_bitmap |= 1 << i; + } +} + +#endif /* defined(DEBUG_HL_LOGGING) */ + +void ol_tx_sched_stats_display(struct ol_txrx_pdev_t *pdev) +{ + OL_TX_SCHED_WRR_ADV_CAT_STAT_DUMP(pdev->tx_sched.scheduler); +} + +void ol_tx_sched_cur_state_display(struct ol_txrx_pdev_t *pdev) +{ + OL_TX_SCHED_WRR_ADV_CAT_CUR_STATE_DUMP(pdev->tx_sched.scheduler); +} + +void ol_tx_sched_stats_clear(struct ol_txrx_pdev_t *pdev) +{ + OL_TX_SCHED_WRR_ADV_CAT_STAT_CLEAR(pdev->tx_sched.scheduler); +} + +#endif /* defined(CONFIG_HL_SUPPORT) */ diff --git a/core/dp/txrx/ol_tx_sched.h b/core/dp/txrx/ol_tx_sched.h new file mode 100644 index 000000000000..cc5d48bddade --- /dev/null +++ b/core/dp/txrx/ol_tx_sched.h @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_tx_sched.h + * @brief API definitions for the tx scheduler module within the data SW. + */ +#ifndef _OL_TX_SCHED__H_ +#define _OL_TX_SCHED__H_ + +#include <qdf_types.h> + +enum ol_tx_queue_action { + OL_TX_ENQUEUE_FRAME, + OL_TX_DELETE_QUEUE, + OL_TX_PAUSE_QUEUE, + OL_TX_UNPAUSE_QUEUE, + OL_TX_DISCARD_FRAMES, +}; + +struct ol_tx_sched_notify_ctx_t { + int event; + struct ol_tx_frms_queue_t *txq; + union { + int ext_tid; + struct ol_txrx_msdu_info_t *tx_msdu_info; + } info; + int frames; + int bytes; +}; + +#if defined(CONFIG_HL_SUPPORT) + +void +ol_tx_sched_notify( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_sched_notify_ctx_t *ctx); + +void +ol_tx_sched(struct ol_txrx_pdev_t *pdev); + +u_int16_t +ol_tx_sched_discard_select( + struct ol_txrx_pdev_t *pdev, + u_int16_t frms, + ol_tx_desc_list *tx_descs, + bool force); + +void * +ol_tx_sched_attach(struct ol_txrx_pdev_t *pdev); + +void +ol_tx_sched_detach(struct ol_txrx_pdev_t *pdev); + +void ol_tx_sched_stats_display(struct ol_txrx_pdev_t *pdev); + +void ol_tx_sched_cur_state_display(struct ol_txrx_pdev_t *pdev); + +void ol_tx_sched_stats_clear(struct ol_txrx_pdev_t *pdev); + +#else + +static inline void +ol_tx_sched_notify( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_sched_notify_ctx_t *ctx) +{ + return; +} + +static inline void +ol_tx_sched(struct ol_txrx_pdev_t *pdev) +{ + return; +} + +static inline u_int16_t +ol_tx_sched_discard_select( + struct ol_txrx_pdev_t *pdev, + u_int16_t frms, + ol_tx_desc_list *tx_descs, + bool force) +{ + return 0; +} + +static inline void * +ol_tx_sched_attach(struct ol_txrx_pdev_t *pdev) +{ + return NULL; +} + +static inline void +ol_tx_sched_detach(struct ol_txrx_pdev_t *pdev) +{ + return; +} + +static inline void ol_tx_sched_stats_display(struct ol_txrx_pdev_t *pdev) +{ + return; +} + +static inline void ol_tx_sched_cur_state_display(struct ol_txrx_pdev_t *pdev) +{ + return; +} + +static inline void ol_tx_sched_stats_clear(struct ol_txrx_pdev_t *pdev) +{ + return; +} + +#endif /* defined(CONFIG_HL_SUPPORT) */ + +#if defined(CONFIG_HL_SUPPORT) || defined(TX_CREDIT_RECLAIM_SUPPORT) +/* + * HL needs to keep track of the amount of credit available to download + * tx frames to the target - the download scheduler decides when to + * download frames, and which frames to download, based on the credit + * availability. + * LL systems that use TX_CREDIT_RECLAIM_SUPPORT also need to keep track + * of the target_tx_credit, to determine when to poll for tx completion + * messages. + */ + +static inline void +ol_tx_target_credit_adjust(int factor, + struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t msdu) +{ + qdf_atomic_add(factor * htt_tx_msdu_credit(msdu), + &pdev->target_tx_credit); +} + +static inline void ol_tx_target_credit_decr(struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t msdu) +{ + ol_tx_target_credit_adjust(-1, pdev, msdu); +} + +static inline void ol_tx_target_credit_incr(struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t msdu) +{ + ol_tx_target_credit_adjust(1, pdev, msdu); +} +#else +/* + * LL does not need to keep track of target credit. + * Since the host tx descriptor pool size matches the target's, + * we know the target has space for the new tx frame if the host's + * tx descriptor allocation succeeded. + */ +static inline void +ol_tx_target_credit_adjust(int factor, + struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t msdu) +{ + return; +} + +static inline void ol_tx_target_credit_decr(struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t msdu) +{ + return; +} + +static inline void ol_tx_target_credit_incr(struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t msdu) +{ + return; +} +#endif +#endif /* _OL_TX_SCHED__H_ */ diff --git a/core/dp/txrx/ol_tx_send.c b/core/dp/txrx/ol_tx_send.c index b381d1f4f196..9bfbc4788f3b 100644 --- a/core/dp/txrx/ol_tx_send.c +++ b/core/dp/txrx/ol_tx_send.c @@ -47,15 +47,20 @@ #include <ol_txrx_types.h> /* ol_txrx_vdev_t, etc */ #include <ol_tx_desc.h> /* ol_tx_desc_find, ol_tx_desc_frame_free */ #ifdef QCA_COMPUTE_TX_DELAY +#include <ol_tx_classify.h> /* ol_tx_dest_addr_find */ #endif #include <ol_txrx_internal.h> /* OL_TX_DESC_NO_REFS, etc. */ #include <ol_osif_txrx_api.h> #include <ol_tx.h> /* ol_tx_reinject */ #include <ol_cfg.h> /* ol_cfg_is_high_latency */ +#include <ol_tx_sched.h> #ifdef QCA_SUPPORT_SW_TXRX_ENCAP #include <ol_txrx_encap.h> /* OL_TX_RESTORE_HDR, etc */ #endif +#include <ol_tx_queue.h> +#include <ol_txrx.h> + #ifdef TX_CREDIT_RECLAIM_SUPPORT @@ -73,7 +78,8 @@ #endif /* TX_CREDIT_RECLAIM_SUPPORT */ -#if defined(TX_CREDIT_RECLAIM_SUPPORT) +#if defined(CONFIG_HL_SUPPORT) || defined(TX_CREDIT_RECLAIM_SUPPORT) + /* * HL needs to keep track of the amount of credit available to download * tx frames to the target - the download scheduler decides when to @@ -83,53 +89,87 @@ * of the target_tx_credit, to determine when to poll for tx completion * messages. */ -#define OL_TX_TARGET_CREDIT_ADJUST(factor, pdev, msdu) \ - qdf_atomic_add( \ - factor * htt_tx_msdu_credit(msdu), &pdev->target_tx_credit) -#define OL_TX_TARGET_CREDIT_DECR(pdev, msdu) \ - OL_TX_TARGET_CREDIT_ADJUST(-1, pdev, msdu) -#define OL_TX_TARGET_CREDIT_INCR(pdev, msdu) \ - OL_TX_TARGET_CREDIT_ADJUST(1, pdev, msdu) -#define OL_TX_TARGET_CREDIT_DECR_INT(pdev, delta) \ - qdf_atomic_add(-1 * delta, &pdev->target_tx_credit) -#define OL_TX_TARGET_CREDIT_INCR_INT(pdev, delta) \ - qdf_atomic_add(delta, &pdev->target_tx_credit) +static inline void +ol_tx_target_credit_decr_int(struct ol_txrx_pdev_t *pdev, int delta) +{ + qdf_atomic_add(-1 * delta, &pdev->target_tx_credit); +} + +static inline void +ol_tx_target_credit_incr_int(struct ol_txrx_pdev_t *pdev, int delta) +{ + qdf_atomic_add(delta, &pdev->target_tx_credit); +} #else -/* - * LL does not need to keep track of target credit. - * Since the host tx descriptor pool size matches the target's, - * we know the target has space for the new tx frame if the host's - * tx descriptor allocation succeeded. - */ -#define OL_TX_TARGET_CREDIT_ADJUST(factor, pdev, msdu) /* no-op */ -#define OL_TX_TARGET_CREDIT_DECR(pdev, msdu) /* no-op */ -#define OL_TX_TARGET_CREDIT_INCR(pdev, msdu) /* no-op */ -#define OL_TX_TARGET_CREDIT_DECR_INT(pdev, delta) /* no-op */ -#define OL_TX_TARGET_CREDIT_INCR_INT(pdev, delta) /* no-op */ + +static inline void +ol_tx_target_credit_decr_int(struct ol_txrx_pdev_t *pdev, int delta) +{ + return; +} + +static inline void +ol_tx_target_credit_incr_int(struct ol_txrx_pdev_t *pdev, int delta) +{ + return; +} #endif -#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL -#define OL_TX_FLOW_CT_UNPAUSE_OS_Q(pdev) \ - do { \ - struct ol_txrx_vdev_t *vdev; \ - TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { \ - if (qdf_atomic_read(&vdev->os_q_paused) && \ - (vdev->tx_fl_hwm != 0)) { \ - qdf_spin_lock(&pdev->tx_mutex); \ - if (pdev->tx_desc.num_free > \ - vdev->tx_fl_hwm) { \ - qdf_atomic_set(&vdev->os_q_paused, 0); \ - qdf_spin_unlock(&pdev->tx_mutex); \ - ol_txrx_flow_control_cb(vdev, true);\ - } \ - else { \ - qdf_spin_unlock(&pdev->tx_mutex); \ - } \ - } \ - } \ - } while (0) +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) + +/** + * ol_tx_flow_ct_unpause_os_q() - Unpause OS Q + * @pdev: physical device object + * + * + * Return: None + */ +static void ol_tx_flow_ct_unpause_os_q(ol_txrx_pdev_handle pdev) +{ + struct ol_txrx_vdev_t *vdev; + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + if (qdf_atomic_read(&vdev->os_q_paused) && + (vdev->tx_fl_hwm != 0)) { + qdf_spin_lock(&pdev->tx_mutex); + if (pdev->tx_desc.num_free > vdev->tx_fl_hwm) { + qdf_atomic_set(&vdev->os_q_paused, 0); + qdf_spin_unlock(&pdev->tx_mutex); + ol_txrx_flow_control_cb(vdev, true); + } else { + qdf_spin_unlock(&pdev->tx_mutex); + } + } + } +} +#elif defined(CONFIG_HL_SUPPORT) && defined(CONFIG_PER_VDEV_TX_DESC_POOL) + +static void ol_tx_flow_ct_unpause_os_q(ol_txrx_pdev_handle pdev) +{ + struct ol_txrx_vdev_t *vdev; + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + if (qdf_atomic_read(&vdev->os_q_paused) && + (vdev->tx_fl_hwm != 0)) { + qdf_spin_lock(&pdev->tx_mutex); + if (((ol_tx_desc_pool_size_hl( + vdev->pdev->ctrl_pdev) >> 1) + - TXRX_HL_TX_FLOW_CTRL_MGMT_RESERVED) + - qdf_atomic_read(&vdev->tx_desc_count) + > vdev->tx_fl_hwm) { + qdf_atomic_set(&vdev->os_q_paused, 0); + qdf_spin_unlock(&pdev->tx_mutex); + vdev->osif_flow_control_cb(vdev, true); + } else { + qdf_spin_unlock(&pdev->tx_mutex); + } + } + } +} #else -#define OL_TX_FLOW_CT_UNPAUSE_OS_Q(pdev) + +static inline void ol_tx_flow_ct_unpause_os_q(ol_txrx_pdev_handle pdev) +{ + return; +} #endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ static inline uint16_t @@ -145,7 +185,7 @@ ol_tx_send_base(struct ol_txrx_pdev_t *pdev, qdf_nbuf_len(msdu)); msdu_credit_consumed = htt_tx_msdu_credit(msdu); - OL_TX_TARGET_CREDIT_DECR_INT(pdev, msdu_credit_consumed); + ol_tx_target_credit_decr_int(pdev, msdu_credit_consumed); OL_TX_CREDIT_RECLAIM(pdev); /* @@ -190,7 +230,7 @@ ol_tx_send(struct ol_txrx_pdev_t *pdev, vdev_id)); failed = htt_tx_send_std(pdev->htt_pdev, msdu, id); if (qdf_unlikely(failed)) { - OL_TX_TARGET_CREDIT_INCR_INT(pdev, msdu_credit_consumed); + ol_tx_target_credit_incr_int(pdev, msdu_credit_consumed); ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1 /* had error */); } } @@ -212,7 +252,7 @@ ol_tx_send_batch(struct ol_txrx_pdev_t *pdev, msdu_id_storage = ol_tx_msdu_id_storage(rejected); tx_desc = ol_tx_desc_find(pdev, *msdu_id_storage); - OL_TX_TARGET_CREDIT_INCR(pdev, rejected); + ol_tx_target_credit_incr(pdev, rejected); ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1 /* had error */); rejected = next; @@ -235,7 +275,7 @@ ol_tx_send_nonstd(struct ol_txrx_pdev_t *pdev, if (failed) { TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Error: freeing tx frame after htt_tx failed"); - OL_TX_TARGET_CREDIT_INCR_INT(pdev, msdu_credit_consumed); + ol_tx_target_credit_incr_int(pdev, msdu_credit_consumed); ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1 /* had error */); } } @@ -266,7 +306,7 @@ ol_tx_download_done_base(struct ol_txrx_pdev_t *pdev, } if (status != A_OK) { - OL_TX_TARGET_CREDIT_INCR(pdev, msdu); + ol_tx_target_credit_incr(pdev, msdu); ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1 /* download err */); } else { @@ -340,9 +380,15 @@ static void ol_tx_delay_compute(struct ol_txrx_pdev_t *pdev, enum htt_tx_status status, uint16_t *desc_ids, int num_msdus); -#define OL_TX_DELAY_COMPUTE ol_tx_delay_compute + #else -#define OL_TX_DELAY_COMPUTE(pdev, status, desc_ids, num_msdus) /* no-op */ +static inline void +ol_tx_delay_compute(struct ol_txrx_pdev_t *pdev, + enum htt_tx_status status, + uint16_t *desc_ids, int num_msdus) +{ + return; +} #endif /* QCA_COMPUTE_TX_DELAY */ #ifndef OL_TX_RESTORE_HDR @@ -469,8 +515,11 @@ void ol_tx_credit_completion_handler(ol_txrx_pdev_handle pdev, int credits) { ol_tx_target_credit_update(pdev, credits); + if (pdev->cfg.is_high_latency) + ol_tx_sched(pdev); + /* UNPAUSE OS Q */ - OL_TX_FLOW_CT_UNPAUSE_OS_Q(pdev); + ol_tx_flow_ct_unpause_os_q(pdev); } /* WARNING: ol_tx_inspect_handler()'s bahavior is similar to that of @@ -495,7 +544,7 @@ ol_tx_completion_handler(ol_txrx_pdev_handle pdev, ol_tx_desc_list tx_descs; TAILQ_INIT(&tx_descs); - OL_TX_DELAY_COMPUTE(pdev, status, desc_ids, num_msdus); + ol_tx_delay_compute(pdev, status, desc_ids, num_msdus); for (i = 0; i < num_msdus; i++) { tx_desc_id = desc_ids[i]; @@ -507,6 +556,7 @@ ol_tx_completion_handler(ol_txrx_pdev_handle pdev, qdf_nbuf_data_addr(netbuf), sizeof(qdf_nbuf_data(netbuf)), tx_desc->id, status)); qdf_runtime_pm_put(); + ol_tx_desc_update_group_credit(pdev, tx_desc_id, 1, 0, status); /* Per SDU update of byte count */ byte_cnt += qdf_nbuf_len(netbuf); if (OL_TX_DESC_NO_REFS(tx_desc)) { @@ -540,14 +590,158 @@ ol_tx_completion_handler(ol_txrx_pdev_handle pdev, status != htt_tx_status_ok); } - OL_TX_TARGET_CREDIT_ADJUST(num_msdus, pdev, NULL); + if (pdev->cfg.is_high_latency) { + /* + * Credit was already explicitly updated by HTT, + * but update the number of available tx descriptors, + * then invoke the scheduler, since new credit is probably + * available now. + */ + qdf_atomic_add(num_msdus, &pdev->tx_queue.rsrc_cnt); + ol_tx_sched(pdev); + } else { + ol_tx_target_credit_adjust(num_msdus, pdev, NULL); + } /* UNPAUSE OS Q */ - OL_TX_FLOW_CT_UNPAUSE_OS_Q(pdev); + ol_tx_flow_ct_unpause_os_q(pdev); /* Do one shot statistics */ TXRX_STATS_UPDATE_TX_STATS(pdev, status, num_msdus, byte_cnt); } +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +void ol_tx_desc_update_group_credit(ol_txrx_pdev_handle pdev, + u_int16_t tx_desc_id, int credit, u_int8_t absolute, + enum htt_tx_status status) +{ + uint8_t i, is_member; + uint16_t vdev_id_mask; + struct ol_tx_desc_t *tx_desc; + + tx_desc = ol_tx_desc_find(pdev, tx_desc_id); + for (i = 0; i < OL_TX_MAX_TXQ_GROUPS; i++) { + vdev_id_mask = + OL_TXQ_GROUP_VDEV_ID_MASK_GET( + pdev->txq_grps[i].membership); + is_member = OL_TXQ_GROUP_VDEV_ID_BIT_MASK_GET(vdev_id_mask, + tx_desc->vdev->vdev_id); + if (is_member) { + ol_txrx_update_group_credit(&pdev->txq_grps[i], + credit, absolute); + break; + } + } + ol_tx_update_group_credit_stats(pdev); +} + +#ifdef DEBUG_HL_LOGGING + +void ol_tx_update_group_credit_stats(ol_txrx_pdev_handle pdev) +{ + uint16_t curr_index; + uint8_t i; + + qdf_spin_lock_bh(&pdev->grp_stat_spinlock); + pdev->grp_stats.last_valid_index++; + if (pdev->grp_stats.last_valid_index > (OL_TX_GROUP_STATS_LOG_SIZE + - 1)) { + pdev->grp_stats.last_valid_index -= OL_TX_GROUP_STATS_LOG_SIZE; + pdev->grp_stats.wrap_around = 1; + } + curr_index = pdev->grp_stats.last_valid_index; + + for (i = 0; i < OL_TX_MAX_TXQ_GROUPS; i++) { + pdev->grp_stats.stats[curr_index].grp[i].member_vdevs = + OL_TXQ_GROUP_VDEV_ID_MASK_GET( + pdev->txq_grps[i].membership); + pdev->grp_stats.stats[curr_index].grp[i].credit = + qdf_atomic_read(&pdev->txq_grps[i].credit); + } + + qdf_spin_unlock_bh(&pdev->grp_stat_spinlock); +} + +void ol_tx_dump_group_credit_stats(ol_txrx_pdev_handle pdev) +{ + uint16_t i, j, is_break = 0; + int16_t curr_index, old_index, wrap_around; + uint16_t curr_credit, old_credit, mem_vdevs; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Group credit stats:"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + " No: GrpID: Credit: Change: vdev_map"); + + qdf_spin_lock_bh(&pdev->grp_stat_spinlock); + curr_index = pdev->grp_stats.last_valid_index; + wrap_around = pdev->grp_stats.wrap_around; + qdf_spin_unlock_bh(&pdev->grp_stat_spinlock); + + if (curr_index < 0) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Not initialized"); + return; + } + + for (i = 0; i < OL_TX_GROUP_STATS_LOG_SIZE; i++) { + old_index = curr_index - 1; + if (old_index < 0) { + if (wrap_around == 0) + is_break = 1; + else + old_index = OL_TX_GROUP_STATS_LOG_SIZE - 1; + } + + for (j = 0; j < OL_TX_MAX_TXQ_GROUPS; j++) { + qdf_spin_lock_bh(&pdev->grp_stat_spinlock); + curr_credit = + pdev->grp_stats.stats[curr_index]. + grp[j].credit; + if (!is_break) + old_credit = + pdev->grp_stats.stats[old_index]. + grp[j].credit; + + mem_vdevs = + pdev->grp_stats.stats[curr_index].grp[j]. + member_vdevs; + qdf_spin_unlock_bh(&pdev->grp_stat_spinlock); + + if (!is_break) + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "%4d: %5d: %6d %6d %8x", + curr_index, j, + curr_credit, + (curr_credit - old_credit), + mem_vdevs); + else + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "%4d: %5d: %6d %6s %8x", + curr_index, j, + curr_credit, "NA", mem_vdevs); + } + + if (is_break) + break; + + curr_index = old_index; + } +} + +void ol_tx_clear_group_credit_stats(ol_txrx_pdev_handle pdev) +{ + qdf_spin_lock_bh(&pdev->grp_stat_spinlock); + qdf_mem_zero(&pdev->grp_stats, sizeof(pdev->grp_stats)); + pdev->grp_stats.last_valid_index = -1; + pdev->grp_stats.wrap_around = 0; + qdf_spin_unlock_bh(&pdev->grp_stat_spinlock); +} +#endif +#endif + /* * ol_tx_single_completion_handler performs the same tx completion * processing as ol_tx_completion_handler, but for a single frame. @@ -581,8 +775,18 @@ ol_tx_single_completion_handler(ol_txrx_pdev_handle pdev, qdf_atomic_read(&pdev->target_tx_credit), 1, qdf_atomic_read(&pdev->target_tx_credit) + 1); - - qdf_atomic_add(1, &pdev->target_tx_credit); + if (pdev->cfg.is_high_latency) { + /* + * Credit was already explicitly updated by HTT, + * but update the number of available tx descriptors, + * then invoke the scheduler, since new credit is probably + * available now. + */ + qdf_atomic_add(1, &pdev->tx_queue.rsrc_cnt); + ol_tx_sched(pdev); + } else { + qdf_atomic_add(1, &pdev->target_tx_credit); + } } /* WARNING: ol_tx_inspect_handler()'s bahavior is similar to that of @@ -649,7 +853,12 @@ ol_tx_inspect_handler(ol_txrx_pdev_handle pdev, qdf_atomic_read(&pdev->target_tx_credit) + num_msdus); - OL_TX_TARGET_CREDIT_ADJUST(num_msdus, pdev, NULL); + if (pdev->cfg.is_high_latency) { + /* credit was already explicitly updated by HTT */ + ol_tx_sched(pdev); + } else { + ol_tx_target_credit_adjust(num_msdus, pdev, NULL); + } } #ifdef QCA_COMPUTE_TX_DELAY @@ -777,31 +986,6 @@ ol_tx_delay_hist(ol_txrx_pdev_handle pdev, } #ifdef QCA_COMPUTE_TX_DELAY_PER_TID -static inline uint8_t *ol_tx_dest_addr_find(struct ol_txrx_pdev_t *pdev, - qdf_nbuf_t tx_nbuf) -{ - uint8_t *hdr_ptr; - void *datap = qdf_nbuf_data(tx_nbuf); - - if (pdev->frame_format == wlan_frm_fmt_raw) { - /* adjust hdr_ptr to RA */ - struct ieee80211_frame *wh = (struct ieee80211_frame *)datap; - hdr_ptr = wh->i_addr1; - } else if (pdev->frame_format == wlan_frm_fmt_native_wifi) { - /* adjust hdr_ptr to RA */ - struct ieee80211_frame *wh = (struct ieee80211_frame *)datap; - hdr_ptr = wh->i_addr1; - } else if (pdev->frame_format == wlan_frm_fmt_802_3) { - hdr_ptr = datap; - } else { - QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "Invalid standard frame type: %d", - pdev->frame_format); - qdf_assert(0); - hdr_ptr = NULL; - } - return hdr_ptr; -} static uint8_t ol_tx_delay_tid_from_l3_hdr(struct ol_txrx_pdev_t *pdev, diff --git a/core/dp/txrx/ol_tx_send.h b/core/dp/txrx/ol_tx_send.h index d7d6072fb7df..460fe718e76b 100644 --- a/core/dp/txrx/ol_tx_send.h +++ b/core/dp/txrx/ol_tx_send.h @@ -35,11 +35,20 @@ #include <qdf_nbuf.h> /* qdf_nbuf_t */ #include <cdp_txrx_cmn.h> /* ol_txrx_vdev_t, etc. */ +#if defined(CONFIG_HL_SUPPORT) + +static inline void ol_tx_discard_target_frms(ol_txrx_pdev_handle pdev) +{ + return; +} +#else + /** * @flush the ol tx when surprise remove. * */ void ol_tx_discard_target_frms(ol_txrx_pdev_handle pdev); +#endif /** * @brief Send a tx frame to the target. diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c index 0a4b6f7f75a0..09cffd3d559a 100644 --- a/core/dp/txrx/ol_txrx.c +++ b/core/dp/txrx/ol_txrx.c @@ -68,6 +68,7 @@ #include <ol_tx_send.h> /* ol_tx_discard_target_frms */ #include <ol_tx_desc.h> /* ol_tx_desc_frame_free */ #include <ol_tx_queue.h> +#include <ol_tx_sched.h> /* ol_tx_sched_attach, etc. */ #include <ol_txrx.h> #include <cdp_txrx_flow_ctrl_legacy.h> #include <cdp_txrx_ipa.h> @@ -80,6 +81,132 @@ #include <cds_concurrency.h> #include "epping_main.h" +#ifdef CONFIG_HL_SUPPORT + +/** + * ol_txrx_copy_mac_addr_raw() - copy raw mac addr + * @vdev: the data virtual device + * @bss_addr: bss address + * + * Return: None + */ +void +ol_txrx_copy_mac_addr_raw(ol_txrx_vdev_handle vdev, uint8_t *bss_addr) +{ + if (bss_addr && vdev->last_real_peer && + (qdf_mem_cmp((u8 *)bss_addr, + vdev->last_real_peer->mac_addr.raw, + IEEE80211_ADDR_LEN) == 0)) + qdf_mem_copy(vdev->hl_tdls_ap_mac_addr.raw, + vdev->last_real_peer->mac_addr.raw, + OL_TXRX_MAC_ADDR_LEN); +} + +/** + * ol_txrx_add_last_real_peer() - add last peer + * @pdev: the data physical device + * @vdev: virtual device + * @peer_id: peer id + * + * Return: None + */ +void +ol_txrx_add_last_real_peer(ol_txrx_pdev_handle pdev, + ol_txrx_vdev_handle vdev, + uint8_t *peer_id) +{ + ol_txrx_peer_handle peer; + if (vdev->last_real_peer == NULL) { + peer = NULL; + peer = ol_txrx_find_peer_by_addr(pdev, + vdev->hl_tdls_ap_mac_addr.raw, + peer_id); + if (peer && (peer->peer_ids[0] != + HTT_INVALID_PEER_ID)) + vdev->last_real_peer = peer; + } +} + +/** + * is_vdev_restore_last_peer() - check for vdev last peer + * @peer: peer object + * + * Return: true if last peer is not null + */ +bool +is_vdev_restore_last_peer(struct ol_txrx_peer_t *peer) +{ + struct ol_txrx_vdev_t *vdev; + vdev = peer->vdev; + return vdev->last_real_peer && (vdev->last_real_peer == peer); +} + +/** + * ol_txrx_update_last_real_peer() - check for vdev last peer + * @pdev: the data physical device + * @peer: peer device + * @peer_id: peer id + * @restore_last_peer: restore last peer flag + * + * Return: None + */ +void +ol_txrx_update_last_real_peer( + ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + uint8_t *peer_id, bool restore_last_peer) +{ + struct ol_txrx_vdev_t *vdev; + vdev = peer->vdev; + if (restore_last_peer && (vdev->last_real_peer == NULL)) { + peer = NULL; + peer = ol_txrx_find_peer_by_addr(pdev, + vdev->hl_tdls_ap_mac_addr.raw, peer_id); + if (peer && (peer->peer_ids[0] != HTT_INVALID_PEER_ID)) + vdev->last_real_peer = peer; + } +} +#endif + +u_int16_t +ol_tx_desc_pool_size_hl(ol_pdev_handle ctrl_pdev) +{ + u_int16_t desc_pool_size; + u_int16_t steady_state_tx_lifetime_ms; + u_int16_t safety_factor; + + /* + * Steady-state tx latency: + * roughly 1-2 ms flight time + * + roughly 1-2 ms prep time, + * + roughly 1-2 ms target->host notification time. + * = roughly 6 ms total + * Thus, steady state number of frames = + * steady state max throughput / frame size * tx latency, e.g. + * 1 Gbps / 1500 bytes * 6 ms = 500 + * + */ + steady_state_tx_lifetime_ms = 6; + + safety_factor = 8; + + desc_pool_size = + ol_cfg_max_thruput_mbps(ctrl_pdev) * + 1000 /* 1e6 bps/mbps / 1e3 ms per sec = 1000 */ / + (8 * OL_TX_AVG_FRM_BYTES) * + steady_state_tx_lifetime_ms * + safety_factor; + + /* minimum */ + if (desc_pool_size < OL_TX_DESC_POOL_SIZE_MIN_HL) + desc_pool_size = OL_TX_DESC_POOL_SIZE_MIN_HL; + + /* maximum */ + if (desc_pool_size > OL_TX_DESC_POOL_SIZE_MAX_HL) + desc_pool_size = OL_TX_DESC_POOL_SIZE_MAX_HL; + + return desc_pool_size; +} /*=== function definitions ===*/ @@ -137,7 +264,7 @@ QDF_STATUS ol_txrx_get_vdevid(struct ol_txrx_peer_t *peer, uint8_t *vdev_id) { if (!peer) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "peer argument is null!!"); + "peer argument is null!!"); return QDF_STATUS_E_FAILURE; } @@ -159,14 +286,14 @@ void *ol_txrx_get_vdev_by_sta_id(uint8_t sta_id) pdev = cds_get_context(QDF_MODULE_ID_TXRX); if (!pdev) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "PDEV not found for sta_id [%d]", sta_id); + "PDEV not found for sta_id [%d]", sta_id); return NULL; } peer = ol_txrx_peer_find_by_local_id(pdev, sta_id); if (!peer) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "PEER [%d] not found", sta_id); + "PEER [%d] not found", sta_id); return NULL; } @@ -290,6 +417,105 @@ static void ol_txrx_local_peer_id_cleanup(struct ol_txrx_pdev_t *pdev) #define ol_txrx_local_peer_id_cleanup(pdev) /* no-op */ #endif +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +/** + * ol_txrx_update_group_credit() - update group credit for tx queue + * @group: for which credit needs to be updated + * @credit: credits + * @absolute: TXQ group absolute + * + * Return: allocated pool size + */ +void ol_txrx_update_group_credit( + struct ol_tx_queue_group_t *group, + int32_t credit, + u_int8_t absolute) +{ + if (absolute) + qdf_atomic_set(&group->credit, credit); + else + qdf_atomic_add(credit, &group->credit); +} + +/** + * ol_txrx_update_tx_queue_groups() - update vdev tx queue group if + * vdev id mask and ac mask is not matching + * @pdev: the data physical device + * @group_id: TXQ group id + * @credit: TXQ group credit count + * @absolute: TXQ group absolute + * @vdev_id_mask: TXQ vdev group id mask + * @ac_mask: TQX access category mask + * + * Return: None + */ +void ol_txrx_update_tx_queue_groups( + ol_txrx_pdev_handle pdev, + u_int8_t group_id, + int32_t credit, + u_int8_t absolute, + u_int32_t vdev_id_mask, + u_int32_t ac_mask + ) +{ + struct ol_tx_queue_group_t *group; + u_int32_t group_vdev_bit_mask, vdev_bit_mask, group_vdev_id_mask; + u_int32_t membership; + struct ol_txrx_vdev_t *vdev; + group = &pdev->txq_grps[group_id]; + + membership = OL_TXQ_GROUP_MEMBERSHIP_GET(vdev_id_mask, ac_mask); + + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + /* + * if the membership (vdev id mask and ac mask) + * matches then no need to update tx qeue groups. + */ + if (group->membership == membership) + /* Update Credit Only */ + goto credit_update; + + + /* + * membership (vdev id mask and ac mask) is not matching + * TODO: ignoring ac mask for now + */ + group_vdev_id_mask = + OL_TXQ_GROUP_VDEV_ID_MASK_GET(group->membership); + + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + group_vdev_bit_mask = + OL_TXQ_GROUP_VDEV_ID_BIT_MASK_GET( + group_vdev_id_mask, vdev->vdev_id); + vdev_bit_mask = + OL_TXQ_GROUP_VDEV_ID_BIT_MASK_GET( + vdev_id_mask, vdev->vdev_id); + + if (group_vdev_bit_mask != vdev_bit_mask) { + /* + * Change in vdev tx queue group + */ + if (!vdev_bit_mask) { + /* Set Group Pointer (vdev and peer) to NULL */ + ol_tx_set_vdev_group_ptr( + pdev, vdev->vdev_id, NULL); + } else { + /* Set Group Pointer (vdev and peer) */ + ol_tx_set_vdev_group_ptr( + pdev, vdev->vdev_id, group); + } + } + } + /* Update membership */ + group->membership = membership; +credit_update: + /* Update Credit */ + ol_txrx_update_group_credit(group, credit, absolute); + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); +} +#endif + #ifdef WLAN_FEATURE_FASTPATH /** * setup_fastpath_ce_handles() Update pdev with ce_handle for fastpath use. @@ -404,6 +630,305 @@ uint32_t ol_tx_get_total_free_desc(struct ol_txrx_pdev_t *pdev) #endif +#if defined(CONFIG_HL_SUPPORT) && defined(CONFIG_PER_VDEV_TX_DESC_POOL) + +/** + * ol_txrx_rsrc_threshold_lo() - set threshold low - when to start tx desc + * margin replenishment + * @desc_pool_size: tx desc pool size + * + * Return: threshold low + */ +static inline uint16_t +ol_txrx_rsrc_threshold_lo(int desc_pool_size) +{ + int threshold_low; + /* + * 5% margin of unallocated desc is too much for per + * vdev mechanism. + * Define the value seperately. + */ + threshold_low = TXRX_HL_TX_FLOW_CTRL_MGMT_RESERVED; + + return threshold_low; +} + +/** + * ol_txrx_rsrc_threshold_hi() - set threshold high - where to stop + * during tx desc margin replenishment + * @desc_pool_size: tx desc pool size + * + * Return: threshold high + */ +static inline uint16_t +ol_txrx_rsrc_threshold_hi(int desc_pool_size) +{ + int threshold_high; + /* when freeing up descriptors, + * keep going until there's a 7.5% margin + */ + threshold_high = ((15 * desc_pool_size)/100)/2; + + return threshold_high; +} +#else + +static inline uint16_t +ol_txrx_rsrc_threshold_lo(int desc_pool_size) +{ + int threshold_low; + /* always maintain a 5% margin of unallocated descriptors */ + threshold_low = (5 * desc_pool_size)/100; + + return threshold_low; +} + +static inline uint16_t +ol_txrx_rsrc_threshold_hi(int desc_pool_size) +{ + int threshold_high; + /* when freeing up descriptors, keep going until + * there's a 15% margin + */ + threshold_high = (15 * desc_pool_size)/100; + + return threshold_high; +} +#endif + +#if defined(CONFIG_HL_SUPPORT) && defined(DEBUG_HL_LOGGING) + +/** + * ol_txrx_pdev_txq_log_init() - initialise pdev txq logs + * @pdev: the physical device object + * + * Return: None + */ +static void +ol_txrx_pdev_txq_log_init(struct ol_txrx_pdev_t *pdev) +{ + qdf_spinlock_create(&pdev->txq_log_spinlock); + pdev->txq_log.size = OL_TXQ_LOG_SIZE; + pdev->txq_log.oldest_record_offset = 0; + pdev->txq_log.offset = 0; + pdev->txq_log.allow_wrap = 1; + pdev->txq_log.wrapped = 0; +} + +/** + * ol_txrx_pdev_txq_log_destroy() - remove txq log spinlock for pdev + * @pdev: the physical device object + * + * Return: None + */ +static inline void +ol_txrx_pdev_txq_log_destroy(struct ol_txrx_pdev_t *pdev) +{ + qdf_spinlock_destroy(&pdev->txq_log_spinlock); +} + +#else + +static inline void +ol_txrx_pdev_txq_log_init(struct ol_txrx_pdev_t *pdev) +{ + return; +} + +static inline void +ol_txrx_pdev_txq_log_destroy(struct ol_txrx_pdev_t *pdev) +{ + return; +} + + +#endif + +#if defined(DEBUG_HL_LOGGING) + +/** + * ol_txrx_pdev_grp_stats_init() - initialise group stat spinlock for pdev + * @pdev: the physical device object + * + * Return: None + */ +static inline void +ol_txrx_pdev_grp_stats_init(struct ol_txrx_pdev_t *pdev) +{ + qdf_spinlock_create(&pdev->grp_stat_spinlock); + pdev->grp_stats.last_valid_index = -1; + pdev->grp_stats.wrap_around = 0; +} + +/** + * ol_txrx_pdev_grp_stat_destroy() - destroy group stat spinlock for pdev + * @pdev: the physical device object + * + * Return: None + */ +static inline void +ol_txrx_pdev_grp_stat_destroy(struct ol_txrx_pdev_t *pdev) +{ + qdf_spinlock_destroy(&pdev->grp_stat_spinlock); +} +#else + +static inline void +ol_txrx_pdev_grp_stats_init(struct ol_txrx_pdev_t *pdev) +{ + return; +} + +static inline void +ol_txrx_pdev_grp_stat_destroy(struct ol_txrx_pdev_t *pdev) +{ + return; +} +#endif + +#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS) + +/** + * ol_txrx_hl_tdls_flag_reset() - reset tdls flag for vdev + * @vdev: the virtual device object + * @flag: flag + * + * Return: None + */ +void +ol_txrx_hl_tdls_flag_reset(struct ol_txrx_vdev_t *vdev, bool flag) +{ + vdev->hlTdlsFlag = flag; +} +#endif + +#if defined(CONFIG_HL_SUPPORT) + +/** + * ol_txrx_vdev_txqs_init() - initialise vdev tx queues + * @vdev: the virtual device object + * + * Return: None + */ +static void +ol_txrx_vdev_txqs_init(struct ol_txrx_vdev_t *vdev) +{ + u_int8_t i; + for (i = 0; i < OL_TX_VDEV_NUM_QUEUES; i++) { + TAILQ_INIT(&vdev->txqs[i].head); + vdev->txqs[i].paused_count.total = 0; + vdev->txqs[i].frms = 0; + vdev->txqs[i].bytes = 0; + vdev->txqs[i].ext_tid = OL_TX_NUM_TIDS + i; + vdev->txqs[i].flag = ol_tx_queue_empty; + /* aggregation is not applicable for vdev tx queues */ + vdev->txqs[i].aggr_state = ol_tx_aggr_disabled; + ol_tx_txq_set_group_ptr(&vdev->txqs[i], NULL); + ol_txrx_set_txq_peer(&vdev->txqs[i], NULL); + } +} + +/** + * ol_txrx_vdev_tx_queue_free() - free vdev tx queues + * @vdev: the virtual device object + * + * Return: None + */ +static void +ol_txrx_vdev_tx_queue_free(struct ol_txrx_vdev_t *vdev) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + struct ol_tx_frms_queue_t *txq; + int i; + + for (i = 0; i < OL_TX_VDEV_NUM_QUEUES; i++) { + txq = &vdev->txqs[i]; + ol_tx_queue_free(pdev, txq, (i + OL_TX_NUM_TIDS)); + } +} + +/** + * ol_txrx_peer_txqs_init() - initialise peer tx queues + * @pdev: the physical device object + * @peer: peer object + * + * Return: None + */ +static void +ol_txrx_peer_txqs_init(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + uint8_t i; + struct ol_txrx_vdev_t *vdev = peer->vdev; + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + for (i = 0; i < OL_TX_NUM_TIDS; i++) { + TAILQ_INIT(&peer->txqs[i].head); + peer->txqs[i].paused_count.total = 0; + peer->txqs[i].frms = 0; + peer->txqs[i].bytes = 0; + peer->txqs[i].ext_tid = i; + peer->txqs[i].flag = ol_tx_queue_empty; + peer->txqs[i].aggr_state = ol_tx_aggr_untried; + ol_tx_set_peer_group_ptr(pdev, peer, vdev->vdev_id, i); + ol_txrx_set_txq_peer(&peer->txqs[i], peer); + } + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + + /* aggregation is not applicable for mgmt and non-QoS tx queues */ + for (i = OL_TX_NUM_QOS_TIDS; i < OL_TX_NUM_TIDS; i++) + peer->txqs[i].aggr_state = ol_tx_aggr_disabled; + + ol_txrx_peer_pause(peer); +} + +/** + * ol_txrx_peer_tx_queue_free() - free peer tx queues + * @pdev: the physical device object + * @peer: peer object + * + * Return: None + */ +static void +ol_txrx_peer_tx_queue_free(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + struct ol_tx_frms_queue_t *txq; + uint8_t i; + + for (i = 0; i < OL_TX_NUM_TIDS; i++) { + txq = &peer->txqs[i]; + ol_tx_queue_free(pdev, txq, i); + } +} +#else + +static inline void +ol_txrx_vdev_txqs_init(struct ol_txrx_vdev_t *vdev) +{ + return; +} + +static inline void +ol_txrx_vdev_tx_queue_free(struct ol_txrx_vdev_t *vdev) +{ + return; +} + +static inline void +ol_txrx_peer_txqs_init(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + return; +} + +static inline void +ol_txrx_peer_tx_queue_free(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + return; +} +#endif + /** * ol_txrx_pdev_attach() - allocate txrx pdev * @ctrl_pdev: cfg pdev @@ -425,6 +950,8 @@ ol_txrx_pdev_attach(ol_pdev_handle ctrl_pdev, goto fail0; qdf_mem_zero(pdev, sizeof(*pdev)); + /* init LL/HL cfg here */ + pdev->cfg.is_high_latency = ol_cfg_is_high_latency(ctrl_pdev); pdev->cfg.default_tx_comp_req = !ol_cfg_tx_free_at_download(ctrl_pdev); /* store provided params */ @@ -442,16 +969,33 @@ ol_txrx_pdev_attach(ol_pdev_handle ctrl_pdev, if (ol_txrx_peer_find_attach(pdev)) goto fail1; + /* initialize the counter of the target's tx buffer availability */ + qdf_atomic_init(&pdev->target_tx_credit); + qdf_atomic_init(&pdev->orig_target_tx_credit); + + if (ol_cfg_is_high_latency(ctrl_pdev)) { + qdf_spinlock_create(&pdev->tx_queue_spinlock); + pdev->tx_sched.scheduler = ol_tx_sched_attach(pdev); + if (pdev->tx_sched.scheduler == NULL) + goto fail2; + } + ol_txrx_pdev_txq_log_init(pdev); + ol_txrx_pdev_grp_stats_init(pdev); + pdev->htt_pdev = htt_pdev_alloc(pdev, ctrl_pdev, htc_pdev, osdev); if (!pdev->htt_pdev) - goto fail2; + goto fail3; return pdev; -fail2: +fail3: ol_txrx_peer_find_detach(pdev); +fail2: + if (ol_cfg_is_high_latency(ctrl_pdev)) + qdf_spinlock_destroy(&pdev->tx_queue_spinlock); + fail1: qdf_mem_free(pdev); @@ -538,18 +1082,31 @@ ol_txrx_pdev_post_attach(ol_txrx_pdev_handle pdev) * run out of tx descriptors. */ - /* initialize the counter of the target's tx buffer availability */ - qdf_atomic_init(&pdev->target_tx_credit); - qdf_atomic_init(&pdev->orig_target_tx_credit); /* * LL - initialize the target credit outselves. - * HL - wait for a HTT target credit initialization during htt_attach. + * HL - wait for a HTT target credit initialization + * during htt_attach. */ + if (pdev->cfg.is_high_latency) { + desc_pool_size = ol_tx_desc_pool_size_hl(pdev->ctrl_pdev); - qdf_atomic_add(ol_cfg_target_tx_credit(pdev->ctrl_pdev), - &pdev->target_tx_credit); + qdf_atomic_init(&pdev->tx_queue.rsrc_cnt); + qdf_atomic_add(desc_pool_size, &pdev->tx_queue.rsrc_cnt); - desc_pool_size = ol_tx_get_desc_global_pool_size(pdev); + pdev->tx_queue.rsrc_threshold_lo = + ol_txrx_rsrc_threshold_lo(desc_pool_size); + pdev->tx_queue.rsrc_threshold_hi = + ol_txrx_rsrc_threshold_hi(desc_pool_size); + + for (i = 0 ; i < OL_TX_MAX_TXQ_GROUPS; i++) + qdf_atomic_init(&pdev->txq_grps[i].credit); + + ol_tx_target_credit_init(pdev, desc_pool_size); + } else { + qdf_atomic_add(ol_cfg_target_tx_credit(pdev->ctrl_pdev), + &pdev->target_tx_credit); + desc_pool_size = ol_tx_get_desc_global_pool_size(pdev); + } ol_tx_desc_dup_detect_init(pdev, desc_pool_size); @@ -644,6 +1201,7 @@ ol_txrx_pdev_post_attach(ol_txrx_pdev_handle pdev) "%s:%d - %d FRAG VA 0x%p FRAG PA 0x%llx", __func__, __LINE__, i, c_element->tx_desc.htt_frag_desc, + (long long unsigned int) c_element->tx_desc.htt_frag_desc_paddr); #ifdef QCA_SUPPORT_TXDESC_SANITY_CHECKS c_element->tx_desc.pkt_type = 0xff; @@ -884,6 +1442,9 @@ ol_txrx_pdev_post_attach(ol_txrx_pdev_handle pdev) pdev->cfg.ll_pause_txq_limit = ol_tx_cfg_max_tx_queue_depth_ll(pdev->ctrl_pdev); + /* TX flow control for peer who is in very bad link status */ + ol_tx_badpeer_flow_cl_init(pdev); + #ifdef QCA_COMPUTE_TX_DELAY qdf_mem_zero(&pdev->tx_delay, sizeof(pdev->tx_delay)); qdf_spinlock_create(&pdev->tx_delay.mutex); @@ -1016,6 +1577,10 @@ void ol_txrx_pdev_detach(ol_txrx_pdev_handle pdev, int force) htt_pktlogmod_exit(pdev, osc); OL_RX_REORDER_TIMEOUT_CLEANUP(pdev); + + if (pdev->cfg.is_high_latency) + ol_tx_sched_detach(pdev); + #ifdef QCA_SUPPORT_TX_THROTTLE /* Thermal Mitigation */ qdf_timer_stop(&pdev->tx_throttle.phase_timer); @@ -1094,10 +1659,17 @@ void ol_txrx_pdev_detach(ol_txrx_pdev_handle pdev, int force) /* Thermal Mitigation */ qdf_spinlock_destroy(&pdev->tx_throttle.mutex); #endif + + /* TX flow control for peer who is in very bad link status */ + ol_tx_badpeer_flow_cl_deinit(pdev); + OL_TXRX_PEER_STATS_MUTEX_DESTROY(pdev); OL_RX_REORDER_TRACE_DETACH(pdev); OL_RX_PN_TRACE_DETACH(pdev); + + ol_txrx_pdev_txq_log_destroy(pdev); + ol_txrx_pdev_grp_stat_destroy(pdev); /* * WDI event detach */ @@ -1109,6 +1681,28 @@ void ol_txrx_pdev_detach(ol_txrx_pdev_handle pdev, int force) #endif } +#if defined(CONFIG_PER_VDEV_TX_DESC_POOL) + +/** + * ol_txrx_vdev_tx_desc_cnt_init() - initialise tx descriptor count for vdev + * @vdev: the virtual device object + * + * Return: None + */ +static inline void +ol_txrx_vdev_tx_desc_cnt_init(struct ol_txrx_vdev_t *vdev) +{ + qdf_atomic_init(&vdev->tx_desc_count); +} +#else + +static inline void +ol_txrx_vdev_tx_desc_cnt_init(struct ol_txrx_vdev_t *vdev) +{ + return; +} +#endif + /** * ol_txrx_vdev_attach - Allocate and initialize the data object * for a new virtual device. @@ -1148,17 +1742,23 @@ ol_txrx_vdev_attach(ol_txrx_pdev_handle pdev, vdev->fwd_tx_packets = 0; vdev->fwd_rx_packets = 0; + ol_txrx_vdev_tx_desc_cnt_init(vdev); + qdf_mem_copy(&vdev->mac_addr.raw[0], vdev_mac_addr, OL_TXRX_MAC_ADDR_LEN); TAILQ_INIT(&vdev->peer_list); vdev->last_real_peer = NULL; + ol_txrx_hl_tdls_flag_reset(vdev, false); + #ifdef QCA_IBSS_SUPPORT vdev->ibss_peer_num = 0; vdev->ibss_peer_heart_beat_timer = 0; #endif + ol_txrx_vdev_txqs_init(vdev); + qdf_spinlock_create(&vdev->ll_pause.mutex); vdev->ll_pause.paused_reason = 0; vdev->ll_pause.txq.head = vdev->ll_pause.txq.tail = NULL; @@ -1304,6 +1904,8 @@ ol_txrx_vdev_detach(ol_txrx_vdev_handle vdev, /* preconditions */ TXRX_ASSERT2(vdev); + ol_txrx_vdev_tx_queue_free(vdev); + qdf_spin_lock_bh(&vdev->ll_pause.mutex); qdf_timer_stop(&vdev->ll_pause.timer); qdf_timer_free(&vdev->ll_pause.timer); @@ -1337,8 +1939,7 @@ ol_txrx_vdev_detach(ol_txrx_vdev_handle vdev, if (!TAILQ_EMPTY(&vdev->peer_list)) { /* debug print - will be removed later */ TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, - "%s: not deleting vdev object %p (%02x:%02x:%02x:%02x:%02x:%02x)" - "until deletion finishes for all its peers\n", + "%s: not deleting vdev object %p (%02x:%02x:%02x:%02x:%02x:%02x) until deletion finishes for all its peers\n", __func__, vdev, vdev->mac_addr.raw[0], vdev->mac_addr.raw[1], vdev->mac_addr.raw[2], vdev->mac_addr.raw[3], @@ -1379,7 +1980,7 @@ ol_txrx_vdev_detach(ol_txrx_vdev_handle vdev, * Return: None */ void ol_txrx_flush_rx_frames(struct ol_txrx_peer_t *peer, - bool drop) + bool drop) { struct ol_rx_cached_buf *cache_buf; QDF_STATUS ret; @@ -1510,6 +2111,8 @@ ol_txrx_peer_attach(ol_txrx_vdev_handle vdev, uint8_t *peer_mac_addr) qdf_mem_copy(&peer->mac_addr.raw[0], peer_mac_addr, OL_TXRX_MAC_ADDR_LEN); + ol_txrx_peer_txqs_init(pdev, peer); + INIT_LIST_HEAD(&peer->cached_bufq); qdf_spin_lock_bh(&pdev->peer_ref_mutex); /* add this peer into the vdev's list */ @@ -1920,10 +2523,11 @@ QDF_STATUS ol_txrx_peer_state_update(struct ol_txrx_pdev_t *pdev, peer = ol_txrx_peer_find_hash_find(pdev, peer_mac, 0, 1); if (NULL == peer) { - TXRX_PRINT(TXRX_PRINT_LEVEL_INFO2, "%s: peer is null for peer_mac" - " 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", __FUNCTION__, - peer_mac[0], peer_mac[1], peer_mac[2], peer_mac[3], - peer_mac[4], peer_mac[5]); + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO2, + "%s: peer is null for peer_mac 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + __func__, + peer_mac[0], peer_mac[1], peer_mac[2], peer_mac[3], + peer_mac[4], peer_mac[5]); return QDF_STATUS_E_INVAL; } @@ -2213,6 +2817,8 @@ void ol_txrx_peer_unref_delete(ol_txrx_peer_handle peer) qdf_spin_unlock_bh(&pdev->peer_ref_mutex); } + ol_txrx_peer_tx_queue_free(pdev, peer); + /* * 'array' is allocated in addba handler and is supposed to be * freed in delba handler. There is the case (for example, in @@ -2375,11 +2981,14 @@ static void ol_txrx_dump_tx_desc(ol_txrx_pdev_handle pdev_handle) struct ol_txrx_pdev_t *pdev = (ol_txrx_pdev_handle) pdev_handle; uint32_t total; - total = ol_tx_get_desc_global_pool_size(pdev); + if (ol_cfg_is_high_latency(pdev->ctrl_pdev)) + total = qdf_atomic_read(&pdev->orig_target_tx_credit); + else + total = ol_tx_get_desc_global_pool_size(pdev); TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, - "total tx credit %d num_free %d", - total, pdev->tx_desc.num_free); + "total tx credit %d num_free %d", + total, pdev->tx_desc.num_free); return; } @@ -2410,7 +3019,7 @@ QDF_STATUS ol_txrx_wait_for_pending_tx(int timeout) qdf_sleep(OL_ATH_TX_DRAIN_WAIT_DELAY); if (timeout <= 0) { TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, - "%s: tx frames are pending", __func__); + "%s: tx frames are pending", __func__); ol_txrx_dump_tx_desc(txrx_pdev); return QDF_STATUS_E_TIMEOUT; } @@ -2495,7 +3104,10 @@ int ol_txrx_get_tx_pending(ol_txrx_pdev_handle pdev_handle) struct ol_txrx_pdev_t *pdev = (ol_txrx_pdev_handle) pdev_handle; uint32_t total; - total = ol_tx_get_desc_global_pool_size(pdev); + if (ol_cfg_is_high_latency(pdev->ctrl_pdev)) + total = qdf_atomic_read(&pdev->orig_target_tx_credit); + else + total = ol_tx_get_desc_global_pool_size(pdev); return total - ol_tx_get_total_free_desc(pdev); } @@ -2809,8 +3421,7 @@ int ol_txrx_debug(ol_txrx_vdev_handle vdev, int debug_specs) ol_txrx_pdev_display(vdev->pdev, 0); #else QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_FATAL, - "The pdev,vdev,peer display functions are disabled.\n" - "To enable them, recompile with TXRX_DEBUG_LEVEL > 5"); + "The pdev,vdev,peer display functions are disabled.\n To enable them, recompile with TXRX_DEBUG_LEVEL > 5"); #endif } if (debug_specs & TXRX_DBG_MASK_STATS) { @@ -2821,9 +3432,7 @@ int ol_txrx_debug(ol_txrx_vdev_handle vdev, int debug_specs) ol_txrx_prot_ans_display(vdev->pdev); #else QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_FATAL, - "txrx protocol analysis is disabled.\n" - "To enable it, recompile with " - "ENABLE_TXRX_PROT_ANALYZE defined"); + "txrx protocol analysis is disabled.\n To enable it, recompile with ENABLE_TXRX_PROT_ANALYZE defined"); #endif } if (debug_specs & TXRX_DBG_MASK_RX_REORDER_TRACE) { @@ -2831,9 +3440,7 @@ int ol_txrx_debug(ol_txrx_vdev_handle vdev, int debug_specs) ol_rx_reorder_trace_display(vdev->pdev, 0, 0); #else QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_FATAL, - "rx reorder seq num trace is disabled.\n" - "To enable it, recompile with " - "ENABLE_RX_REORDER_TRACE defined"); + "rx reorder seq num trace is disabled.\n To enable it, recompile with ENABLE_RX_REORDER_TRACE defined"); #endif } @@ -2860,7 +3467,7 @@ void ol_txrx_pdev_display(ol_txrx_pdev_handle pdev, int indent) QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, "%*svdev list:", indent + 4, " "); TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { - ol_txrx_vdev_display(vdev, indent + 8); + ol_txrx_vdev_display(vdev, indent + 8); } ol_txrx_peer_find_display(pdev, indent + 4); QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, @@ -2887,7 +3494,7 @@ void ol_txrx_vdev_display(ol_txrx_vdev_handle vdev, int indent) QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, "%*speer list:", indent + 4, " "); TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { - ol_txrx_peer_display(peer, indent + 8); + ol_txrx_peer_display(peer, indent + 8); } } @@ -2976,23 +3583,20 @@ ol_txrx_stats(uint8_t vdev_id, char *buffer, unsigned buf_len) ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_vdev_id(vdev_id); if (!vdev) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "%s: vdev is NULL", __func__); + "%s: vdev is NULL", __func__); snprintf(buffer, buf_len, "vdev not found"); return len; } len = scnprintf(buffer, buf_len, - "\nTXRX stats:\n" - "\nllQueue State : %s" - "\n pause %u unpause %u" - "\n overflow %u" - "\nllQueue timer state : %s\n", - ((vdev->ll_pause.is_q_paused == false) ? "UNPAUSED" : "PAUSED"), - vdev->ll_pause.q_pause_cnt, - vdev->ll_pause.q_unpause_cnt, - vdev->ll_pause.q_overflow_cnt, - ((vdev->ll_pause.is_q_timer_on == false) - ? "NOT-RUNNING" : "RUNNING")); + "\nTXRX stats:\n\nllQueue State : %s\n pause %u unpause %u\n overflow %u\n llQueue timer state : %s\n", + ((vdev->ll_pause.is_q_paused == false) ? + "UNPAUSED" : "PAUSED"), + vdev->ll_pause.q_pause_cnt, + vdev->ll_pause.q_unpause_cnt, + vdev->ll_pause.q_overflow_cnt, + ((vdev->ll_pause.is_q_timer_on == false) + ? "NOT-RUNNING" : "RUNNING")); return len; } @@ -3143,14 +3747,14 @@ static ol_txrx_vdev_handle ol_txrx_get_vdev_from_sta_id(uint8_t sta_id) if (sta_id >= WLAN_MAX_STA_COUNT) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "Invalid sta id passed"); + "Invalid sta id passed"); return NULL; } pdev = cds_get_context(QDF_MODULE_ID_TXRX); if (!pdev) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "PDEV not found for sta_id [%d]", sta_id); + "PDEV not found for sta_id [%d]", sta_id); return NULL; } @@ -3158,7 +3762,7 @@ static ol_txrx_vdev_handle ol_txrx_get_vdev_from_sta_id(uint8_t sta_id) if (!peer) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "PEER [%d] not found", sta_id); + "PEER [%d] not found", sta_id); return NULL; } @@ -3174,13 +3778,13 @@ static ol_txrx_vdev_handle ol_txrx_get_vdev_from_sta_id(uint8_t sta_id) * Return: 0 for sucess or error code */ int ol_txrx_register_tx_flow_control (uint8_t vdev_id, - ol_txrx_tx_flow_control_fp flowControl, - void *osif_fc_ctx) + ol_txrx_tx_flow_control_fp flowControl, + void *osif_fc_ctx) { ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_vdev_id(vdev_id); if (NULL == vdev) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "%s: Invalid vdev_id %d", __func__, vdev_id); + "%s: Invalid vdev_id %d", __func__, vdev_id); return -EINVAL; } @@ -3202,7 +3806,7 @@ int ol_txrx_deregister_tx_flow_control_cb(uint8_t vdev_id) ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_vdev_id(vdev_id); if (NULL == vdev) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "%s: Invalid vdev_id", __func__); + "%s: Invalid vdev_id", __func__); return -EINVAL; } @@ -3229,7 +3833,7 @@ ol_txrx_get_tx_resource(uint8_t sta_id, ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_sta_id(sta_id); if (NULL == vdev) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "%s: Invalid sta_id %d", __func__, sta_id); + "%s: Invalid sta_id %d", __func__, sta_id); /* Return true so caller do not understand that resource * is less than low_watermark. * sta_id validation will be done in ol_tx_send_data_frame @@ -3240,6 +3844,7 @@ ol_txrx_get_tx_resource(uint8_t sta_id, } qdf_spin_lock_bh(&vdev->pdev->tx_mutex); + if (vdev->pdev->tx_desc.num_free < (uint16_t) low_watermark) { vdev->tx_fl_lwm = (uint16_t) low_watermark; vdev->tx_fl_hwm = @@ -3266,7 +3871,7 @@ ol_txrx_ll_set_tx_pause_q_depth(uint8_t vdev_id, int pause_q_depth) ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_vdev_id(vdev_id); if (NULL == vdev) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "%s: Invalid vdev_id %d", __func__, vdev_id); + "%s: Invalid vdev_id %d", __func__, vdev_id); return -EINVAL; } @@ -3285,7 +3890,7 @@ ol_txrx_ll_set_tx_pause_q_depth(uint8_t vdev_id, int pause_q_depth) * Return: none */ inline void ol_txrx_flow_control_cb(ol_txrx_vdev_handle vdev, - bool tx_resume) + bool tx_resume) { qdf_spin_lock_bh(&vdev->flow_control_lock); if ((vdev->osif_flow_control_cb) && (vdev->osif_fc_ctx)) @@ -3429,7 +4034,7 @@ void ol_txrx_ipa_uc_op_response(ol_txrx_pdev_handle pdev, uint8_t *op_msg) pkt = cds_alloc_ol_rx_pkt(sched_ctx); if (qdf_unlikely(!pkt)) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "%s: Not able to allocate context", __func__); + "%s: Not able to allocate context", __func__); return; } @@ -3488,7 +4093,7 @@ void ol_txrx_display_stats(uint16_t value) pdev = cds_get_context(QDF_MODULE_ID_TXRX); if (!pdev) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "%s: pdev is NULL", __func__); + "%s: pdev is NULL", __func__); return; } @@ -3505,6 +4110,26 @@ void ol_txrx_display_stats(uint16_t value) case WLAN_TXRX_DESC_STATS: qdf_nbuf_tx_desc_count_display(); break; +#ifdef CONFIG_HL_SUPPORT + case WLAN_SCHEDULER_STATS: + ol_tx_sched_cur_state_display(pdev); + ol_tx_sched_stats_display(pdev); + break; + case WLAN_TX_QUEUE_STATS: + ol_tx_queue_log_display(pdev); + break; +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + case WLAN_CREDIT_STATS: + ol_tx_dump_group_credit_stats(pdev); + break; +#endif + +#ifdef DEBUG_HL_LOGGING + case WLAN_BUNDLE_STATS: + htt_dump_bundle_stats(pdev->htt_pdev); + break; +#endif +#endif default: QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, "%s: Unknown value", __func__); @@ -3519,7 +4144,7 @@ void ol_txrx_clear_stats(uint16_t value) pdev = cds_get_context(QDF_MODULE_ID_TXRX); if (!pdev) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "%s: pdev is NULL", __func__); + "%s: pdev is NULL", __func__); return; } @@ -3533,6 +4158,22 @@ void ol_txrx_clear_stats(uint16_t value) case WLAN_TXRX_DESC_STATS: qdf_nbuf_tx_desc_count_clear(); break; +#ifdef CONFIG_HL_SUPPORT + case WLAN_SCHEDULER_STATS: + ol_tx_sched_stats_clear(pdev); + break; + case WLAN_TX_QUEUE_STATS: + ol_tx_queue_log_clear(pdev); + break; +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + case WLAN_CREDIT_STATS: + ol_tx_clear_group_credit_stats(pdev); + break; +#endif + case WLAN_BUNDLE_STATS: + htt_clear_bundle_stats(pdev->htt_pdev); + break; +#endif default: QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, "%s: Unknown value", __func__); @@ -3692,7 +4333,7 @@ void ol_rx_data_process(struct ol_txrx_peer_t *peer, pkt = cds_alloc_ol_rx_pkt(sched_ctx); if (!pkt) { TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, - "No available Rx message buffer"); + "No available Rx message buffer"); goto drop_rx_buf; } pkt->callback = (cds_ol_rx_thread_cb) @@ -3889,14 +4530,14 @@ QDF_STATUS ol_txrx_register_pause_cb(ol_tx_pause_callback_fp pause_cb) * Return: none */ void ol_txrx_lro_flush_handler(void *context, - void *rxpkt, - uint16_t staid) + void *rxpkt, + uint16_t staid) { ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)context; if (qdf_unlikely(!pdev)) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "%s: Invalid context", __func__); + "%s: Invalid context", __func__); qdf_assert(0); return; } @@ -3905,7 +4546,7 @@ void ol_txrx_lro_flush_handler(void *context, pdev->lro_info.lro_flush_cb(pdev->lro_info.lro_data); else QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "%s: lro_flush_cb NULL", __func__); + "%s: lro_flush_cb NULL", __func__); } /** @@ -3932,7 +4573,7 @@ void ol_txrx_lro_flush(void *data) pkt = cds_alloc_ol_rx_pkt(sched_ctx); if (qdf_unlikely(!pkt)) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "%s: Not able to allocate context", __func__); + "%s: Not able to allocate context", __func__); return; } diff --git a/core/dp/txrx/ol_txrx.h b/core/dp/txrx/ol_txrx.h index 791a0ecb2395..e02647e09144 100644 --- a/core/dp/txrx/ol_txrx.h +++ b/core/dp/txrx/ol_txrx.h @@ -34,10 +34,100 @@ void ol_txrx_peer_unref_delete(struct ol_txrx_peer_t *peer); +/** + * ol_tx_desc_pool_size_hl() - allocate tx descriptor pool size for HL systems + * @ctrl_pdev: the control pdev handle + * + * Return: allocated pool size + */ +u_int16_t +ol_tx_desc_pool_size_hl(ol_pdev_handle ctrl_pdev); + #ifndef OL_TX_AVG_FRM_BYTES #define OL_TX_AVG_FRM_BYTES 1000 #endif +#ifndef OL_TX_DESC_POOL_SIZE_MIN_HL +#define OL_TX_DESC_POOL_SIZE_MIN_HL 500 +#endif + +#ifndef OL_TX_DESC_POOL_SIZE_MAX_HL +#define OL_TX_DESC_POOL_SIZE_MAX_HL 5000 +#endif + + +#ifdef CONFIG_PER_VDEV_TX_DESC_POOL +#define TXRX_HL_TX_FLOW_CTRL_VDEV_LOW_WATER_MARK 400 +#define TXRX_HL_TX_FLOW_CTRL_MGMT_RESERVED 100 +#endif + +#ifdef CONFIG_TX_DESC_HI_PRIO_RESERVE +#define TXRX_HL_TX_DESC_HI_PRIO_RESERVED 20 +#endif + +#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS) + +void +ol_txrx_hl_tdls_flag_reset(struct ol_txrx_vdev_t *vdev, bool flag); +#else + +static inline void +ol_txrx_hl_tdls_flag_reset(struct ol_txrx_vdev_t *vdev, bool flag) +{ + return; +} +#endif + +#ifdef CONFIG_HL_SUPPORT + +void +ol_txrx_copy_mac_addr_raw(ol_txrx_vdev_handle vdev, uint8_t *bss_addr); + +void +ol_txrx_add_last_real_peer(ol_txrx_pdev_handle pdev, + ol_txrx_vdev_handle vdev, + uint8_t *peer_id); + +bool +is_vdev_restore_last_peer(struct ol_txrx_peer_t *peer); + +void +ol_txrx_update_last_real_peer( + ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + uint8_t *peer_id, bool restore_last_peer); +#else + +static inline void +ol_txrx_copy_mac_addr_raw(ol_txrx_vdev_handle vdev, uint8_t *bss_addr) +{ + return; +} + +static inline void +ol_txrx_add_last_real_peer(ol_txrx_pdev_handle pdev, + ol_txrx_vdev_handle vdev, uint8_t *peer_id) +{ + return; +} + +static inline bool +is_vdev_restore_last_peer(struct ol_txrx_peer_t *peer) +{ + return false; +} + +static inline void +ol_txrx_update_last_real_peer( + ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + uint8_t *peer_id, bool restore_last_peer) + +{ + return; +} +#endif + ol_txrx_vdev_handle ol_txrx_get_vdev_from_vdev_id(uint8_t vdev_id); void htt_pkt_log_init(struct ol_txrx_pdev_t *handle, void *scn); diff --git a/core/dp/txrx/ol_txrx_internal.h b/core/dp/txrx/ol_txrx_internal.h index 25cf2a066391..e84632201042 100644 --- a/core/dp/txrx/ol_txrx_internal.h +++ b/core/dp/txrx/ol_txrx_internal.h @@ -559,6 +559,36 @@ NOT_IP_TCP: is_mcast); \ } while (false) +#ifdef CONFIG_HL_SUPPORT + + /** + * ol_rx_err_inv_get_wifi_header() - retrieve wifi header + * @pdev: handle to the physical device + * @rx_msdu: msdu of which header needs to be retrieved + * + * Return: wifi header + */ + static inline + struct ieee80211_frame *ol_rx_err_inv_get_wifi_header( + struct ol_pdev_t *pdev, qdf_nbuf_t rx_msdu) + { + return NULL; + } +#else + + static inline + struct ieee80211_frame *ol_rx_err_inv_get_wifi_header( + struct ol_pdev_t *pdev, qdf_nbuf_t rx_msdu) + { + struct ieee80211_frame *wh = NULL; + if (ol_cfg_frame_type(pdev) == wlan_frm_fmt_native_wifi) + /* For windows, it is always native wifi header .*/ + wh = (struct ieee80211_frame *)qdf_nbuf_data(rx_msdu); + + return wh; + } +#endif + #define OL_RX_ERR_INV_PEER_STATISTICS(pdev, rx_msdu) \ do { \ struct ieee80211_frame *wh = NULL; \ @@ -568,11 +598,7 @@ NOT_IP_TCP: /*wh = (struct ieee80211_frame *) */ \ /*htt_rx_mpdu_wifi_hdr_retrieve(pdev->htt_pdev, rx_desc);*/ \ /* this only apply to LL device.*/ \ - if (ol_cfg_frame_type(pdev->ctrl_pdev) == \ - wlan_frm_fmt_native_wifi) { \ - /* For windows, it is always native wifi header .*/ \ - wh = (struct ieee80211_frame *)qdf_nbuf_data(rx_msdu); \ - } \ + wh = ol_rx_err_inv_get_wifi_header(pdev->ctrl_pdev, rx_msdu); \ ol_rx_err_inv_peer_statistics(pdev->ctrl_pdev, \ wh, OL_RX_ERR_UNKNOWN_PEER); \ } while (false) @@ -734,4 +760,13 @@ NOT_IP_TCP: #endif /* FEATURE_TSO_DEBUG */ +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +void +ol_txrx_update_group_credit( + struct ol_tx_queue_group_t *group, + int32_t credit, + u_int8_t absolute); +#endif + #endif /* _OL_TXRX_INTERNAL__H_ */ diff --git a/core/dp/txrx/ol_txrx_peer_find.c b/core/dp/txrx/ol_txrx_peer_find.c index 072d2ebe5210..6f13af569689 100644 --- a/core/dp/txrx/ol_txrx_peer_find.c +++ b/core/dp/txrx/ol_txrx_peer_find.c @@ -398,18 +398,86 @@ void ol_txrx_peer_find_detach(struct ol_txrx_pdev_t *pdev) /*=== function definitions for message handling =============================*/ +#if defined(CONFIG_HL_SUPPORT) + void ol_rx_peer_map_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id, uint8_t vdev_id, uint8_t *peer_mac_addr, int tx_ready) { ol_txrx_peer_find_add_id(pdev, peer_mac_addr, peer_id); + if (!tx_ready) { + struct ol_txrx_peer_t *peer; + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (!peer) { + /* ol_txrx_peer_detach called before peer map arrived*/ + return; + } else { + if (tx_ready) { + int i; + /* unpause all tx queues now, since the + * target is ready + */ + for (i = 0; i < QDF_ARRAY_SIZE(peer->txqs); + i++) + ol_txrx_peer_tid_unpause(peer, i); + + } else { + /* walk through paused mgmt queue, + * update tx descriptors + */ + ol_tx_queue_decs_reinit(peer, peer_id); + + /* keep non-mgmt tx queues paused until assoc + * is finished tx queues were paused in + * ol_txrx_peer_attach*/ + /* unpause tx mgmt queue */ + ol_txrx_peer_tid_unpause(peer, + HTT_TX_EXT_TID_MGMT); + } + } + } +} + +void ol_txrx_peer_tx_ready_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id) +{ + struct ol_txrx_peer_t *peer; + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer) { + int i; + /* + * Unpause all data tx queues now that the target is ready. + * The mgmt tx queue was not paused, so skip it. + */ + for (i = 0; i < QDF_ARRAY_SIZE(peer->txqs); i++) { + if (i == HTT_TX_EXT_TID_MGMT) + continue; /* mgmt tx queue was not paused */ + + ol_txrx_peer_tid_unpause(peer, i); + } + } +} +#else + +void +ol_rx_peer_map_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t vdev_id, + uint8_t *peer_mac_addr, + int tx_ready) +{ + ol_txrx_peer_find_add_id(pdev, peer_mac_addr, peer_id); + } void ol_txrx_peer_tx_ready_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id) { + return; } +#endif + + void ol_rx_peer_unmap_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id) { struct ol_txrx_peer_t *peer; diff --git a/core/dp/txrx/ol_txrx_types.h b/core/dp/txrx/ol_txrx_types.h index 042715286577..25cdcff4a80f 100644 --- a/core/dp/txrx/ol_txrx_types.h +++ b/core/dp/txrx/ol_txrx_types.h @@ -123,6 +123,42 @@ enum ol_tx_frm_type { OL_TX_FRM_NO_FREE, /* frame requires special tx completion callback */ }; +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + +#define MAX_NO_PEERS_IN_LIMIT (2*10 + 2) + +enum ol_tx_peer_bal_state { + ol_tx_peer_bal_enable = 0, + ol_tx_peer_bal_disable, +}; + +enum ol_tx_peer_bal_timer_state { + ol_tx_peer_bal_timer_disable = 0, + ol_tx_peer_bal_timer_active, + ol_tx_peer_bal_timer_inactive, +}; + +struct ol_tx_limit_peer_t { + u_int16_t limit_flag; + u_int16_t peer_id; + u_int16_t limit; +}; + +enum tx_peer_level { + TXRX_IEEE11_B = 0, + TXRX_IEEE11_A_G, + TXRX_IEEE11_N, + TXRX_IEEE11_AC, + TXRX_IEEE11_MAX, +}; + +struct tx_peer_threshold { + u_int32_t tput_thresh; + u_int32_t tx_limit; +}; +#endif + + struct ol_tx_desc_t { qdf_nbuf_t netbuf; void *htt_tx_desc; @@ -151,11 +187,17 @@ struct ol_tx_desc_t { * This field is filled in with the ol_tx_frm_type enum. */ uint8_t pkt_type; +#if defined(CONFIG_HL_SUPPORT) + struct ol_txrx_vdev_t *vdev; +#endif + void *txq; + #ifdef QCA_SUPPORT_SW_TXRX_ENCAP /* used by tx encap, to restore the os buf start offset after tx complete */ uint8_t orig_l2_hdr_bytes; #endif + #ifdef QCA_LL_TX_FLOW_CONTROL_V2 struct ol_tx_flow_pool_t *pool; #endif @@ -197,6 +239,19 @@ struct ol_rx_reorder_timeout_list_elem_t { (((_tid) ^ ((_tid) >> 1)) & 0x1) ? TXRX_WMM_AC_BK : \ TXRX_WMM_AC_BE) +enum { + OL_TX_SCHED_WRR_ADV_CAT_BE, + OL_TX_SCHED_WRR_ADV_CAT_BK, + OL_TX_SCHED_WRR_ADV_CAT_VI, + OL_TX_SCHED_WRR_ADV_CAT_VO, + OL_TX_SCHED_WRR_ADV_CAT_NON_QOS_DATA, + OL_TX_SCHED_WRR_ADV_CAT_UCAST_MGMT, + OL_TX_SCHED_WRR_ADV_CAT_MCAST_DATA, + OL_TX_SCHED_WRR_ADV_CAT_MCAST_MGMT, + + OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES /* must be last */ +}; + struct ol_tx_reorder_cat_timeout_t { TAILQ_HEAD(, ol_rx_reorder_timeout_list_elem_t) virtual_timer_list; qdf_timer_t timer; @@ -204,6 +259,11 @@ struct ol_tx_reorder_cat_timeout_t { struct ol_txrx_pdev_t *pdev; }; +enum ol_tx_scheduler_status { + ol_tx_scheduler_idle = 0, + ol_tx_scheduler_running, +}; + enum ol_tx_queue_status { ol_tx_queue_empty = 0, ol_tx_queue_active, @@ -224,6 +284,19 @@ enum { ol_tx_aggr_in_progress, }; +#define OL_TX_MAX_GROUPS_PER_QUEUE 1 +#define OL_TX_MAX_VDEV_ID 16 +#define OL_TXQ_GROUP_VDEV_ID_MASK_GET(_membership) \ + (((_membership) & 0xffff0000) >> 16) +#define OL_TXQ_GROUP_VDEV_ID_BIT_MASK_GET(_mask, _vdev_id) \ + ((_mask >> _vdev_id) & 0x01) +#define OL_TXQ_GROUP_AC_MASK_GET(_membership) \ + ((_membership) & 0x0000ffff) +#define OL_TXQ_GROUP_AC_BIT_MASK_GET(_mask, _ac_mask) \ + ((_mask >> _ac_mask) & 0x01) +#define OL_TXQ_GROUP_MEMBERSHIP_GET(_vdev_mask, _ac_mask) \ + ((_vdev_mask << 16) | _ac_mask) + struct ol_tx_frms_queue_t { /* list_elem - * Allow individual tx frame queues to be linked together into @@ -241,6 +314,10 @@ struct ol_tx_frms_queue_t { uint32_t bytes; ol_tx_desc_list head; enum ol_tx_queue_status flag; + struct ol_tx_queue_group_t *group_ptrs[OL_TX_MAX_GROUPS_PER_QUEUE]; +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + struct ol_txrx_peer_t *peer; +#endif }; enum { @@ -272,6 +349,9 @@ struct ol_mac_addr { uint8_t mac_addr[OL_TXRX_MAC_ADDR_LEN]; }; +struct ol_tx_sched_t; + + #ifndef OL_TXRX_NUM_LOCAL_PEER_IDS #define OL_TXRX_NUM_LOCAL_PEER_IDS 33 /* default */ #endif @@ -322,6 +402,24 @@ enum throttle_phase { typedef void (*ipa_uc_op_cb_type)(uint8_t *op_msg, void *osif_ctxt); +struct ol_tx_queue_group_t { + qdf_atomic_t credit; + u_int32_t membership; +}; +#define OL_TX_MAX_TXQ_GROUPS 2 + +#define OL_TX_GROUP_STATS_LOG_SIZE 128 +struct ol_tx_group_credit_stats_t { + struct { + struct { + u_int16_t member_vdevs; + u_int16_t credit; + } grp[OL_TX_MAX_TXQ_GROUPS]; + } stats[OL_TX_GROUP_STATS_LOG_SIZE]; + u_int16_t last_valid_index; + u_int16_t wrap_around; +}; + #ifdef QCA_LL_TX_FLOW_CONTROL_V2 /** @@ -558,6 +656,7 @@ struct ol_txrx_pdev_t { struct { uint16_t pool_size; uint16_t num_free; + union ol_tx_desc_list_elem_t *array; union ol_tx_desc_list_elem_t *freelist; #ifdef QCA_LL_TX_FLOW_CONTROL_V2 uint8_t num_invalid_bin; @@ -677,6 +776,24 @@ struct ol_txrx_pdev_t { #endif /* + * tx_sched only applies for HL, but is defined unconditionally + * rather than only if defined(CONFIG_HL_SUPPORT). + * This is because the struct only + * occupies a few bytes, and to avoid the complexity of + * wrapping references + * to the struct members in "defined(CONFIG_HL_SUPPORT)" conditional + * compilation. + * If this struct gets expanded to a non-trivial size, + * then it should be + * conditionally compiled to only apply if defined(CONFIG_HL_SUPPORT). + */ + qdf_spinlock_t tx_queue_spinlock; + struct { + enum ol_tx_scheduler_status tx_sched_status; + struct ol_tx_sched_t *scheduler; + struct ol_tx_frms_queue_t *last_used_txq; + } tx_sched; + /* * tx_queue only applies for HL, but is defined unconditionally to avoid * wrapping references to tx_queue in "defined(CONFIG_HL_SUPPORT)" * conditional compilation. @@ -690,6 +807,20 @@ struct ol_txrx_pdev_t { uint16_t rsrc_threshold_hi; } tx_queue; +#if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) +#define OL_TXQ_LOG_SIZE 512 + qdf_spinlock_t txq_log_spinlock; + struct { + int size; + int oldest_record_offset; + int offset; + int allow_wrap; + u_int32_t wrapped; + /* aligned to u_int32_t boundary */ + u_int8_t data[OL_TXQ_LOG_SIZE]; + } txq_log; +#endif + #ifdef QCA_ENABLE_OL_TXRX_PEER_STATS qdf_spinlock_t peer_stat_mutex; #endif @@ -767,6 +898,35 @@ struct ol_txrx_pdev_t { OL_TX_MUTEX_TYPE tso_mutex; } tso_seg_pool; #endif + +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + struct { + enum ol_tx_peer_bal_state enabled; + qdf_spinlock_t mutex; + /* timer used to trigger more frames for bad peers */ + qdf_timer_t peer_bal_timer; + /*This is the time in ms of the peer balance timer period */ + u_int32_t peer_bal_period_ms; + /*This is the txq limit */ + u_int32_t peer_bal_txq_limit; + /*This is the state of the peer balance timer */ + enum ol_tx_peer_bal_timer_state peer_bal_timer_state; + /*This is the counter about active peers which are under + *tx flow control */ + u_int32_t peer_num; + /*This is peer list which are under tx flow control */ + struct ol_tx_limit_peer_t limit_list[MAX_NO_PEERS_IN_LIMIT]; + /*This is threshold configurationl */ + struct tx_peer_threshold ctl_thresh[TXRX_IEEE11_MAX]; + } tx_peer_bal; +#endif /* CONFIG_Hl_SUPPORT && QCA_BAD_PEER_TX_FLOW_CL */ + + struct ol_tx_queue_group_t txq_grps[OL_TX_MAX_TXQ_GROUPS]; +#ifdef DEBUG_HL_LOGGING + qdf_spinlock_t grp_stat_spinlock; + struct ol_tx_group_credit_stats_t grp_stats; +#endif + int tid_to_ac[OL_TX_NUM_TIDS + OL_TX_VDEV_NUM_QUEUES]; uint8_t ocb_peer_valid; struct ol_txrx_peer_t *ocb_peer; ol_tx_pause_callback_fp pause_cb; @@ -831,6 +991,10 @@ struct ol_txrx_vdev_t { int16_t ibss_peer_heart_beat_timer; /* for detecting peer departure */ #endif +#if defined(CONFIG_HL_SUPPORT) + struct ol_tx_frms_queue_t txqs[OL_TX_VDEV_NUM_QUEUES]; +#endif + struct { struct { qdf_nbuf_t head; @@ -854,6 +1018,16 @@ struct ol_txrx_vdev_t { qdf_spinlock_t flow_control_lock; ol_txrx_tx_flow_control_fp osif_flow_control_cb; void *osif_fc_ctx; + +#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS) + union ol_txrx_align_mac_addr_t hl_tdls_ap_mac_addr; + bool hlTdlsFlag; +#endif + +#if defined(CONFIG_PER_VDEV_TX_DESC_POOL) + qdf_atomic_t tx_desc_count; +#endif + uint16_t wait_on_peer_id; qdf_event_t wait_delete_comp; #if defined(FEATURE_TSO) @@ -917,6 +1091,10 @@ enum { typedef A_STATUS (*ol_tx_filter_func)(struct ol_txrx_msdu_info_t * tx_msdu_info); +#define OL_TXRX_PEER_SECURITY_MULTICAST 0 +#define OL_TXRX_PEER_SECURITY_UNICAST 1 +#define OL_TXRX_PEER_SECURITY_MAX 2 + struct ol_txrx_peer_t { struct ol_txrx_vdev_t *vdev; @@ -978,6 +1156,10 @@ struct ol_txrx_peer_t { struct ol_txrx_peer_t *peer, unsigned tid, qdf_nbuf_t msdu_list); +#if defined(CONFIG_HL_SUPPORT) + struct ol_tx_frms_queue_t txqs[OL_TX_NUM_TIDS]; +#endif + #ifdef QCA_ENABLE_OL_TXRX_PEER_STATS ol_txrx_peer_stats_t stats; #endif @@ -1013,6 +1195,11 @@ struct ol_txrx_peer_t { uint32_t last_pkt_tsf; uint8_t last_pkt_tid; uint16_t last_pkt_center_freq; +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + u_int16_t tx_limit; + u_int16_t tx_limit_flag; + u_int16_t tx_pause_flag; +#endif qdf_time_t last_assoc_rcvd; qdf_time_t last_disassoc_rcvd; qdf_time_t last_deauth_rcvd; diff --git a/core/hdd/inc/wlan_hdd_cfg.h b/core/hdd/inc/wlan_hdd_cfg.h index c0ce86421805..f0212b7476d3 100644 --- a/core/hdd/inc/wlan_hdd_cfg.h +++ b/core/hdd/inc/wlan_hdd_cfg.h @@ -1481,6 +1481,138 @@ typedef enum { #define CFG_ALLOW_MCC_GO_DIFF_BI_MAX (4) #define CFG_ALLOW_MCC_GO_DIFF_BI_DEFAULT (4) +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) +/* + * Enable/Disable Bad Peer TX CTL feature + * Default: Enable + */ +#define CFG_BAD_PEER_TX_CTL_ENABLE_NAME "gBadPeerTxCtlEnable" +#define CFG_BAD_PEER_TX_CTL_ENABLE_MIN (0) +#define CFG_BAD_PEER_TX_CTL_ENABLE_MAX (1) +#define CFG_BAD_PEER_TX_CTL_ENABLE_DEFAULT (1) + +#define CFG_BAD_PEER_TX_CTL_PERIOD_NAME "gBadPeerTxCtlPeriod" +#define CFG_BAD_PEER_TX_CTL_PERIOD_MIN (10) +#define CFG_BAD_PEER_TX_CTL_PERIOD_MAX (10000) +#define CFG_BAD_PEER_TX_CTL_PERIOD_DEFAULT (50) + +#define CFG_BAD_PEER_TX_CTL_TXQ_LIMIT_NAME "gBadPeerTxCtlTxqLimit" +#define CFG_BAD_PEER_TX_CTL_TXQ_LIMIT_MIN (1) +#define CFG_BAD_PEER_TX_CTL_TXQ_LIMIT_MAX (5000) +#define CFG_BAD_PEER_TX_CTL_TXQ_LIMIT_DEFAULT (100) + +#define CFG_BAD_PEER_TX_CTL_TGT_BACKOFF_T_NAME "gBadPeerTxCtlTgtBackoffTime" +#define CFG_BAD_PEER_TX_CTL_TGT_BACKOFF_T_MIN (1) +#define CFG_BAD_PEER_TX_CTL_TGT_BACKOFF_T_MAX (5000) +#define CFG_BAD_PEER_TX_CTL_TGT_BACKOFF_T_DEFAULT (20) + +#define CFG_BAD_PEER_TX_CTL_TGT_REPORT_PRD_NAME "gBadPeerTxCtlTgtReportPeriod" +#define CFG_BAD_PEER_TX_CTL_TGT_REPORT_PRD_MIN (1) +#define CFG_BAD_PEER_TX_CTL_TGT_REPORT_PRD_MAX (5000) +#define CFG_BAD_PEER_TX_CTL_TGT_REPORT_PRD_DEFAULT (500) + +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEB_NAME "gBadPeerTxCtlCondLevelIeeeB" +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEB_MIN (1) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEB_MAX (2) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEB_DEFAULT (2) + +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEB_NAME "gBadPeerTxCtlDeltaLevelIeeeB" +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEB_MIN (1) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEB_MAX (11) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEB_DEFAULT (2) + +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEB_NAME "gBadPeerTxCtlPctLevelIeeeB" +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEB_MIN (1) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEB_MAX (8) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEB_DEFAULT (1) + +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEB_NAME "gBadPeerTxCtlTputLevelIeeeB" +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEB_MIN (1) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEB_MAX (11) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEB_DEFAULT (2) + +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEB_NAME "gBadPeerTxCtlTxLimitLevelIeeeB" +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEB_MIN (0) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEB_MAX (50) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEB_DEFAULT (3) + +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAG_NAME "gBadPeerTxCtlCondLevelIeeeAG" +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAG_MIN (1) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAG_MAX (2) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAG_DEFAULT (2) + +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAG_NAME "gBadPeerTxCtlDeltaLevelIeeeAG" +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAG_MIN (6) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAG_MAX (54) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAG_DEFAULT (6) + +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAG_NAME "gBadPeerTxCtlPctLevelIeeeAG" +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAG_MIN (1) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAG_MAX (8) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAG_DEFAULT (1) + +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAG_NAME "gBadPeerTxCtlTputLevelIeeeAG" +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAG_MIN (6) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAG_MAX (54) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAG_DEFAULT (6) + +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAG_NAME "gBadPeerTxCtlTxLimitLevelIeeeAG" +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAG_MIN (0) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAG_MAX (50) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAG_DEFAULT (3) + +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEN_NAME "gBadPeerTxCtlCondLevelIeeeN" +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEN_MIN (1) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEN_MAX (2) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEN_DEFAULT (2) + +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEN_NAME "gBadPeerTxCtlDeltaLevelIeeeN" +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEN_MIN (6) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEN_MAX (72) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEN_DEFAULT (6) + +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEN_NAME "gBadPeerTxCtlPctLevelIeeeN" +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEN_MIN (1) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEN_MAX (8) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEN_DEFAULT (1) + +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEN_NAME "gBadPeerTxCtlTputLevelIeeeN" +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEN_MIN (6) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEN_MAX (72) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEN_DEFAULT (15) + +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEN_NAME "gBadPeerTxCtlTxLimitLevelIeeeN" +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEN_MIN (0) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEN_MAX (50) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEN_DEFAULT (3) + +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAC_NAME "gBadPeerTxCtlCondLevelIeeeAC" +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAC_MIN (1) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAC_MAX (2) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAC_DEFAULT (2) + +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAC_NAME "gBadPeerTxCtlDeltaLevelIeeeAC" +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAC_MIN (6) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAC_MAX (433) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAC_DEFAULT (6) + +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAC_NAME "gBadPeerTxCtlPctLevelIeeeAC" +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAC_MIN (1) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAC_MAX (8) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAC_DEFAULT (1) + +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAC_NAME "gBadPeerTxCtlTputLevelIeeeAC" +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAC_MIN (6) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAC_MAX (433) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAC_DEFAULT (15) + +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAC_NAME "gBadPeerTxCtlTxLimitLevelIeeeAC" +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAC_MIN (0) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAC_MAX (50) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAC_DEFAULT (3) +#endif + + /* * Enable/Disable Thermal Mitigation feature * Default: Enable @@ -3116,6 +3248,123 @@ enum dot11p_mode { #define CFG_ENABLE_DP_TRACE_MAX (1) #define CFG_ENABLE_DP_TRACE_DEFAULT (1) +/* + * This parameter will globally disable/enable the adaptive dwell config. + * Scan dwell time optimization + * Following parameters will set different values of attributes for dwell + * time optimization thus reducing total scan time. + */ + +/* + * This parameter will globally disable/enable the adaptive dwell config. + * Acceptable values for this: + * 0: Config is disabled + * 1: Config is enabled + */ +#define CFG_ADAPTIVE_DWELL_MODE_ENABLED_NAME "adaptive_dwell_mode_enabled" +#define CFG_ADAPTIVE_DWELL_MODE_ENABLED_MIN (0) +#define CFG_ADAPTIVE_DWELL_MODE_ENABLED_MAX (1) +#define CFG_ADAPTIVE_DWELL_MODE_ENABLED_DEFAULT (0) + +/* + * This parameter will set default adaptive mode, will be used if any of the + * scan dwell mode is set to default. + * For uses : see enum wmi_dwelltime_adaptive_mode + */ +#define CFG_GLOBAL_ADAPTIVE_DWELL_MODE_NAME "global_adapt_dwelltime_mode" +#define CFG_GLOBAL_ADAPTIVE_DWELL_MODE_MIN (0) +#define CFG_GLOBAL_ADAPTIVE_DWELL_MODE_MAX (4) +#define CFG_GLOBAL_ADAPTIVE_DWELL_MODE_DEFAULT (0) + +/* + * This parameter will set the weight to calculate the average low pass + * filter for channel congestion. + * Acceptable values for this: 0-100 (In %) + */ +#define CFG_ADAPT_DWELL_LPF_WEIGHT_NAME "adapt_dwell_lpf_weight" +#define CFG_ADAPT_DWELL_LPF_WEIGHT_MIN (0) +#define CFG_ADAPT_DWELL_LPF_WEIGHT_MAX (100) +#define CFG_ADAPT_DWELL_LPF_WEIGHT_DEFAULT (80) + +/* + * This parameter will set interval to monitor wifi activity + * in passive scan in msec. + * Acceptable values for this: 0-25 + */ +#define CFG_ADAPT_DWELL_PASMON_INTVAL_NAME "adapt_dwell_passive_mon_intval" +#define CFG_ADAPT_DWELL_PASMON_INTVAL_MIN (0) +#define CFG_ADAPT_DWELL_PASMON_INTVAL_MAX (10) +#define CFG_ADAPT_DWELL_PASMON_INTVAL_DEFAULT (25) + +/* + * This parameter will set % of wifi activity used in passive scan 0-100. + * Acceptable values for this: 0-100 (in %) + */ +#define CFG_ADAPT_DWELL_WIFI_THRESH_NAME "adapt_dwell_wifi_act_threshold" +#define CFG_ADAPT_DWELL_WIFI_THRESH_MIN (0) +#define CFG_ADAPT_DWELL_WIFI_THRESH_MAX (100) +#define CFG_ADAPT_DWELL_WIFI_THRESH_DEFAULT (10) + +/* + * This parameter will set the algo used in dwell time optimization during + * host scan. see enum wmi_dwelltime_adaptive_mode. + * Acceptable values for this: + * 0: Default (Use firmware default mode) + * 1: Conservative optimization + * 2: Moderate optimization + * 3: Aggressive optimization + * 4: Static + */ +#define CFG_ADAPTIVE_SCAN_DWELL_MODE_NAME "hostscan_adaptive_dwell_mode" +#define CFG_ADAPTIVE_SCAN_DWELL_MODE_MIN (0) +#define CFG_ADAPTIVE_SCAN_DWELL_MODE_MAX (4) +#define CFG_ADAPTIVE_SCAN_DWELL_MODE_DEFAULT (0) + +/* + * This parameter will set the algo used in dwell time optimization during + * roam scan. see enum wmi_dwelltime_adaptive_mode. + * Acceptable values for this: + * 0: Default (Use firmware default mode) + * 1: Conservative optimization + * 2: Moderate optimization + * 3: Aggressive optimization + * 4: Static + */ +#define CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_NAME "roamscan_adaptive_dwell_mode" +#define CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_MIN (0) +#define CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_MAX (4) +#define CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_DEFAULT (0) + +/* + * This parameter will set the algo used in dwell time optimization during + * ext scan. see enum wmi_dwelltime_adaptive_mode. + * Acceptable values for this: + * 0: Default (Use firmware default mode) + * 1: Conservative optimization + * 2: Moderate optimization + * 3: Aggressive optimization + * 4: Static + */ +#define CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_NAME "extscan_adaptive_dwell_mode" +#define CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_MIN (0) +#define CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_MAX (4) +#define CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_DEFAULT (0) + +/* + * This parameter will set the algo used in dwell time optimization during + * pno scan. see enum wmi_dwelltime_adaptive_mode. + * Acceptable values for this: + * 0: Default (Use firmware default mode) + * 1: Conservative optimization + * 2: Moderate optimization + * 3: Aggressive optimization + * 4: Static + */ +#define CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_NAME "pnoscan_adaptive_dwell_mode" +#define CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_MIN (0) +#define CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_MAX (4) +#define CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_DEFAULT (0) + /*--------------------------------------------------------------------------- Type declarations -------------------------------------------------------------------------*/ @@ -3395,6 +3644,33 @@ struct hdd_config { uint32_t throttle_dutycycle_level1; uint32_t throttle_dutycycle_level2; uint32_t throttle_dutycycle_level3; +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + bool bad_peer_txctl_enable; + uint32_t bad_peer_txctl_prd; + uint32_t bad_peer_txctl_txq_lmt; + uint32_t bad_peer_tgt_backoff; + uint32_t bad_peer_tgt_report_prd; + uint32_t bad_peer_cond_ieee80211b; + uint32_t bad_peer_delta_ieee80211b; + uint32_t bad_peer_pct_ieee80211b; + uint32_t bad_peer_tput_ieee80211b; + uint32_t bad_peer_limit_ieee80211b; + uint32_t bad_peer_cond_ieee80211ag; + uint32_t bad_peer_delta_ieee80211ag; + uint32_t bad_peer_pct_ieee80211ag; + uint32_t bad_peer_tput_ieee80211ag; + uint32_t bad_peer_limit_ieee80211ag; + uint32_t bad_peer_cond_ieee80211n; + uint32_t bad_peer_delta_ieee80211n; + uint32_t bad_peer_pct_ieee80211n; + uint32_t bad_peer_tput_ieee80211n; + uint32_t bad_peer_limit_ieee80211n; + uint32_t bad_peer_cond_ieee80211ac; + uint32_t bad_peer_delta_ieee80211ac; + uint32_t bad_peer_pct_ieee80211ac; + uint32_t bad_peer_tput_ieee80211ac; + uint32_t bad_peer_limit_ieee80211ac; +#endif uint8_t vhtChannelWidth; uint8_t vhtRxMCS; uint8_t vhtTxMCS; @@ -3736,6 +4012,15 @@ struct hdd_config { bool enable_fatal_event; bool bpf_enabled; bool enable_dp_trace; + bool adaptive_dwell_mode_enabled; + enum wmi_dwelltime_adaptive_mode scan_adaptive_dwell_mode; + enum wmi_dwelltime_adaptive_mode roamscan_adaptive_dwell_mode; + enum wmi_dwelltime_adaptive_mode extscan_adaptive_dwell_mode; + enum wmi_dwelltime_adaptive_mode pnoscan_adaptive_dwell_mode; + enum wmi_dwelltime_adaptive_mode global_adapt_dwelltime_mode; + uint8_t adapt_dwell_lpf_weight; + uint8_t adapt_dwell_passive_mon_intval; + uint8_t adapt_dwell_wifi_act_threshold; }; #define VAR_OFFSET(_Struct, _Var) (offsetof(_Struct, _Var)) diff --git a/core/hdd/inc/wlan_hdd_oemdata.h b/core/hdd/inc/wlan_hdd_oemdata.h index 61f3f5116a6e..fcfc4f148a2b 100644 --- a/core/hdd/inc/wlan_hdd_oemdata.h +++ b/core/hdd/inc/wlan_hdd_oemdata.h @@ -178,7 +178,8 @@ void hdd_send_peer_status_ind_to_oem_app(struct qdf_mac_addr *peerMac, uint8_t peerStatus, uint8_t peerTimingMeasCap, uint8_t sessionId, - tSirSmeChanInfo *chan_info); + tSirSmeChanInfo * chan_info, + enum tQDF_ADAPTER_MODE dev_mode); int iw_get_oem_data_cap(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra); diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c index fa2c758622df..85debbd99df0 100644 --- a/core/hdd/src/wlan_hdd_assoc.c +++ b/core/hdd/src/wlan_hdd_assoc.c @@ -781,6 +781,8 @@ static void hdd_send_association_event(struct net_device *dev, hddLog(LOG4, "LFR3:hdd_send_association_event"); #endif if (eConnectionState_Associated == pHddStaCtx->conn_info.connState) { + tSirSmeChanInfo chan_info; + if (!pCsrRoamInfo) { hddLog(LOGE, FL("STA in associated state but pCsrRoamInfo is null")); return; @@ -834,30 +836,28 @@ static void hdd_send_association_event(struct net_device *dev, ) { hdd_send_ft_assoc_response(dev, pAdapter, pCsrRoamInfo); } - if (pAdapter->device_mode == QDF_P2P_CLIENT_MODE) { - tSirSmeChanInfo chan_info; - qdf_copy_macaddr(&peerMacAddr, - &pHddStaCtx->conn_info.bssId); - chan_info.chan_id = pCsrRoamInfo->chan_info.chan_id; - chan_info.mhz = pCsrRoamInfo->chan_info.mhz; - chan_info.info = pCsrRoamInfo->chan_info.info; - chan_info.band_center_freq1 = - pCsrRoamInfo->chan_info.band_center_freq1; - chan_info.band_center_freq2 = - pCsrRoamInfo->chan_info.band_center_freq2; - chan_info.reg_info_1 = - pCsrRoamInfo->chan_info.reg_info_1; - chan_info.reg_info_2 = - pCsrRoamInfo->chan_info.reg_info_2; + qdf_copy_macaddr(&peerMacAddr, + &pHddStaCtx->conn_info.bssId); + chan_info.chan_id = pCsrRoamInfo->chan_info.chan_id; + chan_info.mhz = pCsrRoamInfo->chan_info.mhz; + chan_info.info = pCsrRoamInfo->chan_info.info; + chan_info.band_center_freq1 = + pCsrRoamInfo->chan_info.band_center_freq1; + chan_info.band_center_freq2 = + pCsrRoamInfo->chan_info.band_center_freq2; + chan_info.reg_info_1 = + pCsrRoamInfo->chan_info.reg_info_1; + chan_info.reg_info_2 = + pCsrRoamInfo->chan_info.reg_info_2; + /* send peer status indication to oem app */ + hdd_send_peer_status_ind_to_oem_app(&peerMacAddr, + ePeerConnected, + pCsrRoamInfo-> + timingMeasCap, + pAdapter->sessionId, + &chan_info, + pAdapter->device_mode); - /* send peer status indication to oem app */ - hdd_send_peer_status_ind_to_oem_app(&peerMacAddr, - ePeerConnected, - pCsrRoamInfo-> - timingMeasCap, - pAdapter->sessionId, - &chan_info); - } #ifdef MSM_PLATFORM #ifdef CONFIG_CNSS /* start timer in sta/p2p_cli */ @@ -890,15 +890,17 @@ static void hdd_send_association_event(struct net_device *dev, wlan_hdd_auto_shutdown_enable(pHddCtx, true); #endif - if (pAdapter->device_mode == QDF_P2P_CLIENT_MODE) { + if ((pAdapter->device_mode == QDF_STA_MODE) || + (pAdapter->device_mode == QDF_P2P_CLIENT_MODE)) { qdf_copy_macaddr(&peerMacAddr, &pHddStaCtx->conn_info.bssId); /* send peer status indication to oem app */ hdd_send_peer_status_ind_to_oem_app(&peerMacAddr, - ePeerDisconnected, 0, - pAdapter->sessionId, - NULL); + ePeerDisconnected, 0, + pAdapter->sessionId, + NULL, + pAdapter->device_mode); } #ifdef WLAN_FEATURE_LPSS pAdapter->rssi_send = false; diff --git a/core/hdd/src/wlan_hdd_cfg.c b/core/hdd/src/wlan_hdd_cfg.c index 08f868492155..137a719c1548 100644 --- a/core/hdd/src/wlan_hdd_cfg.c +++ b/core/hdd/src/wlan_hdd_cfg.c @@ -3646,6 +3646,14 @@ REG_TABLE_ENTRY g_registry_table[] = { CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_DEFAULT, CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_MIN, CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_MAX), + + REG_VARIABLE(CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_NAME, + WLAN_PARAM_Integer, + struct hdd_config, pnoscan_adaptive_dwell_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_DEFAULT, + CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_MIN, + CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_MAX), #endif REG_VARIABLE(CFG_TX_CHAIN_MASK_CCK, WLAN_PARAM_Integer, @@ -3904,6 +3912,62 @@ REG_TABLE_ENTRY g_registry_table[] = { CFG_ENABLE_DP_TRACE_DEFAULT, CFG_ENABLE_DP_TRACE_MIN, CFG_ENABLE_DP_TRACE_MAX), + + REG_VARIABLE(CFG_ADAPTIVE_SCAN_DWELL_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, scan_adaptive_dwell_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPTIVE_SCAN_DWELL_MODE_DEFAULT, + CFG_ADAPTIVE_SCAN_DWELL_MODE_MIN, + CFG_ADAPTIVE_SCAN_DWELL_MODE_MAX), + + REG_VARIABLE(CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, roamscan_adaptive_dwell_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_DEFAULT, + CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_MIN, + CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_MAX), + + REG_VARIABLE(CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, extscan_adaptive_dwell_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_DEFAULT, + CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_MIN, + CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_MAX), + + REG_VARIABLE(CFG_ADAPTIVE_DWELL_MODE_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, adaptive_dwell_mode_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPTIVE_DWELL_MODE_ENABLED_DEFAULT, + CFG_ADAPTIVE_DWELL_MODE_ENABLED_MIN, + CFG_ADAPTIVE_DWELL_MODE_ENABLED_MAX), + + REG_VARIABLE(CFG_GLOBAL_ADAPTIVE_DWELL_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, global_adapt_dwelltime_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_GLOBAL_ADAPTIVE_DWELL_MODE_DEFAULT, + CFG_GLOBAL_ADAPTIVE_DWELL_MODE_MIN, + CFG_GLOBAL_ADAPTIVE_DWELL_MODE_MAX), + + REG_VARIABLE(CFG_ADAPT_DWELL_LPF_WEIGHT_NAME, WLAN_PARAM_Integer, + struct hdd_config, adapt_dwell_lpf_weight, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPT_DWELL_LPF_WEIGHT_DEFAULT, + CFG_ADAPT_DWELL_LPF_WEIGHT_MIN, + CFG_ADAPT_DWELL_LPF_WEIGHT_MAX), + + REG_VARIABLE(CFG_ADAPT_DWELL_PASMON_INTVAL_NAME, WLAN_PARAM_Integer, + struct hdd_config, adapt_dwell_passive_mon_intval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPT_DWELL_PASMON_INTVAL_DEFAULT, + CFG_ADAPT_DWELL_PASMON_INTVAL_MIN, + CFG_ADAPT_DWELL_PASMON_INTVAL_MAX), + + REG_VARIABLE(CFG_ADAPT_DWELL_WIFI_THRESH_NAME, WLAN_PARAM_Integer, + struct hdd_config, adapt_dwell_wifi_act_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPT_DWELL_WIFI_THRESH_DEFAULT, + CFG_ADAPT_DWELL_WIFI_THRESH_MIN, + CFG_ADAPT_DWELL_WIFI_THRESH_MAX), }; @@ -5462,6 +5526,9 @@ void hdd_cfg_print(hdd_context_t *pHddCtx) hddLog(LOGE, "Name = [%s] Value = [%u]", CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_NAME, pHddCtx->config->channel_prediction_full_scan); + hddLog(LOGE, "Name = [%s] Value = [%u]", + CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_NAME, + pHddCtx->config->pnoscan_adaptive_dwell_mode); #endif hddLog(LOGE, "Name = [%s] Value = [%d]", CFG_EARLY_STOP_SCAN_ENABLE, @@ -5507,7 +5574,6 @@ void hdd_cfg_print(hdd_context_t *pHddCtx) CFG_IDLE_TIME_NAME, pHddCtx->config->idle_time_conc); - hdd_info("Name = [%s] Value = [%u]", CFG_ENABLE_EDCA_INI_NAME, pHddCtx->config->enable_edca_params); @@ -5553,6 +5619,30 @@ void hdd_cfg_print(hdd_context_t *pHddCtx) hdd_info("Name = [%s] Value = [%u]", CFG_ENABLE_DP_TRACE, pHddCtx->config->enable_dp_trace); + hdd_info("Name = [%s] Value = [%u]", + CFG_ADAPTIVE_SCAN_DWELL_MODE_NAME, + pHddCtx->config->scan_adaptive_dwell_mode); + hdd_info("Name = [%s] Value = [%u]", + CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_NAME, + pHddCtx->config->roamscan_adaptive_dwell_mode); + hdd_info("Name = [%s] Value = [%u]", + CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_NAME, + pHddCtx->config->extscan_adaptive_dwell_mode); + hdd_info("Name = [%s] Value = [%u]", + CFG_ADAPTIVE_DWELL_MODE_ENABLED_NAME, + pHddCtx->config->adaptive_dwell_mode_enabled); + hdd_info("Name = [%s] Value = [%u]", + CFG_GLOBAL_ADAPTIVE_DWELL_MODE_NAME, + pHddCtx->config->global_adapt_dwelltime_mode); + hdd_info("Name = [%s] Value = [%u]", + CFG_ADAPT_DWELL_LPF_WEIGHT_NAME, + pHddCtx->config->adapt_dwell_lpf_weight); + hdd_info("Name = [%s] Value = [%u]", + CFG_ADAPT_DWELL_PASMON_INTVAL_NAME, + pHddCtx->config->adapt_dwell_passive_mon_intval); + hdd_info("Name = [%s] Value = [%u]", + CFG_ADAPT_DWELL_WIFI_THRESH_NAME, + pHddCtx->config->adapt_dwell_wifi_act_threshold); } @@ -6735,6 +6825,8 @@ void hdd_set_pno_channel_prediction_config( hdd_ctx->config->stationary_thresh; sme_config->csrConfig.channel_prediction_full_scan = hdd_ctx->config->channel_prediction_full_scan; + sme_config->csrConfig.pnoscan_adaptive_dwell_mode = + hdd_ctx->config->pnoscan_adaptive_dwell_mode; } #endif /** @@ -7062,6 +7154,10 @@ QDF_STATUS hdd_set_sme_config(hdd_context_t *pHddCtx) pConfig->ignore_peer_ht_opmode; smeConfig->csrConfig.enable_fatal_event = pConfig->enable_fatal_event; + smeConfig->csrConfig.scan_adaptive_dwell_mode = + pHddCtx->config->scan_adaptive_dwell_mode; + smeConfig->csrConfig.roamscan_adaptive_dwell_mode = + pHddCtx->config->roamscan_adaptive_dwell_mode; smeConfig->csrConfig.enable_edca_params = pConfig->enable_edca_params; diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index dacef1027efd..fd05af138484 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -5438,9 +5438,7 @@ __wlan_hdd_cfg80211_sap_configuration_set(struct wiphy *wiphy, ap_ctx->sapConfig.ch_params.ch_width = ap_ctx->sapConfig.ch_width_orig; - sme_set_ch_params(hdd_ctx->hHal, - ap_ctx->sapConfig.SapHw_mode, - ap_ctx->sapConfig.channel, + cds_set_channel_params(ap_ctx->sapConfig.channel, ap_ctx->sapConfig.sec_ch, &ap_ctx->sapConfig.ch_params); @@ -6123,6 +6121,9 @@ int wlan_hdd_cfg80211_init(struct device *dev, wiphy->max_sched_scan_ssids = SIR_PNO_MAX_SUPP_NETWORKS; wiphy->max_match_sets = SIR_PNO_MAX_SUPP_NETWORKS; wiphy->max_sched_scan_ie_len = SIR_MAC_MAX_IE_LENGTH; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) || defined(WITH_BACKPORTS) + wiphy->max_sched_scan_plans = SIR_PNO_MAX_PLAN_REQUEST; +#endif } #endif /*FEATURE_WLAN_SCAN_PNO */ @@ -8206,9 +8207,10 @@ wlan_hdd_cfg80211_inform_bss_frame(hdd_adapter_t *pAdapter, /* Supplicant takes the signal strength in terms of mBm(100*dBm) */ rssi = QDF_MIN(rssi, 0) * 100; - hddLog(LOG1, FL("BSSID: " MAC_ADDRESS_STR " Channel:%d RSSI:%d"), + hddLog(LOG1, FL("BSSID: " MAC_ADDRESS_STR " Channel:%d RSSI:%d TSF %u"), MAC_ADDR_ARRAY(mgmt->bssid), chan->center_freq, - (int)(rssi / 100)); + (int)(rssi / 100), + bss_desc->timeStamp[0]); bss_status = cfg80211_inform_bss_frame(wiphy, chan, mgmt, frame_len, rssi, @@ -8530,8 +8532,8 @@ void hdd_select_cbmode(hdd_adapter_t *pAdapter, uint8_t operationChannel) eHddDot11Mode hddDot11Mode = iniDot11Mode; struct ch_params_s ch_params; hdd_station_ctx_t *station_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); - uint32_t cb_mode; struct hdd_mon_set_ch_info *ch_info = &station_ctx->ch_info; + uint8_t sec_ch = 0; ch_params.ch_width = (WLAN_HDD_GET_CTX(pAdapter))->config->vhtChannelWidth; @@ -8554,17 +8556,26 @@ void hdd_select_cbmode(hdd_adapter_t *pAdapter, uint8_t operationChannel) hddDot11Mode = iniDot11Mode; break; } + /* + * CDS api expects secondary channel for calculating + * the channel params + */ + if ((ch_params.ch_width == CH_WIDTH_40MHZ) && + (CDS_IS_CHANNEL_24GHZ(operationChannel))) { + if (operationChannel >= 1 && operationChannel <= 5) + sec_ch = operationChannel + 4; + else if (operationChannel >= 6 && operationChannel <= 13) + sec_ch = operationChannel - 4; + } + /* This call decides required channel bonding mode */ - cb_mode = sme_set_ch_params((WLAN_HDD_GET_CTX(pAdapter)->hHal), - hdd_cfg_xlate_to_csr_phy_mode(hddDot11Mode), - operationChannel, 0, - &ch_params); + cds_set_channel_params(operationChannel, sec_ch, &ch_params); if (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam()) { ch_info->channel_width = ch_params.ch_width; ch_info->phy_mode = hdd_cfg_xlate_to_csr_phy_mode(hddDot11Mode); ch_info->channel = operationChannel; - ch_info->cb_mode = cb_mode; + ch_info->cb_mode = ch_params.ch_width; hdd_info("ch_info width %d, phymode %d channel %d", ch_info->channel_width, ch_info->phy_mode, ch_info->channel); @@ -12158,6 +12169,7 @@ static int __wlan_hdd_cfg80211_set_mon_ch(struct wiphy *wiphy, struct qdf_mac_addr bssid; tCsrRoamProfile roam_profile; struct ch_params_s ch_params; + uint8_t sec_ch = 0; int ret; uint16_t chan_num = cds_freq_to_chan(chandef->chan->center_freq); @@ -12188,8 +12200,18 @@ static int __wlan_hdd_cfg80211_set_mon_ch(struct wiphy *wiphy, QDF_MAC_ADDR_SIZE); ch_params.ch_width = chandef->width; - sme_set_ch_params(hal_hdl, ch_info->phy_mode, chan_num, 0, - &ch_params); + /* + * CDS api expects secondary channel for calculating + * the channel params + */ + if ((ch_params.ch_width == CH_WIDTH_40MHZ) && + (CDS_IS_CHANNEL_24GHZ(chan_num))) { + if (chan_num >= 1 && chan_num <= 5) + sec_ch = chan_num + 4; + else if (chan_num >= 6 && chan_num <= 13) + sec_ch = chan_num - 4; + } + cds_set_channel_params(chan_num, sec_ch, &ch_params); status = sme_roam_channel_change_req(hal_hdl, bssid, &ch_params, &roam_profile); if (status) { diff --git a/core/hdd/src/wlan_hdd_ext_scan.c b/core/hdd/src/wlan_hdd_ext_scan.c index 34a943e47df4..c594b409664f 100644 --- a/core/hdd/src/wlan_hdd_ext_scan.c +++ b/core/hdd/src/wlan_hdd_ext_scan.c @@ -3231,6 +3231,9 @@ __wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy, hdd_extscan_map_usr_drv_config_flags( nla_get_u32(tb[PARAM_CONFIG_FLAGS])); + pReqMsg->extscan_adaptive_dwell_mode = + pHddCtx->config->extscan_adaptive_dwell_mode; + hddLog(LOG1, FL("Configuration flags: %u"), pReqMsg->configuration_flags); diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index 4bd65bc858d5..bd2cda48baae 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -1384,16 +1384,16 @@ QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent, if (pHostapdAdapter->device_mode == QDF_P2P_GO_MODE) { /* send peer status indication to oem app */ hdd_send_peer_status_ind_to_oem_app(&pSapEvent->sapevt. - sapStationAssocReassocCompleteEvent. - staMac, ePeerConnected, - pSapEvent->sapevt. - sapStationAssocReassocCompleteEvent. - timingMeasCap, - pHostapdAdapter-> - sessionId, - &pSapEvent->sapevt. - sapStationAssocReassocCompleteEvent. - chan_info); + sapStationAssocReassocCompleteEvent. + staMac, ePeerConnected, + pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + timingMeasCap, + pHostapdAdapter->sessionId, + &pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + chan_info, + pHostapdAdapter->device_mode); } hdd_wlan_green_ap_add_sta(pHddCtx); break; @@ -1502,11 +1502,12 @@ QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent, if (pHostapdAdapter->device_mode == QDF_P2P_GO_MODE) { /* send peer status indication to oem app */ hdd_send_peer_status_ind_to_oem_app(&pSapEvent->sapevt. - sapStationDisassocCompleteEvent. - staMac, ePeerDisconnected, - 0, - pHostapdAdapter-> - sessionId, NULL); + sapStationDisassocCompleteEvent. + staMac, ePeerDisconnected, + 0, + pHostapdAdapter->sessionId, + NULL, + pHostapdAdapter->device_mode); } #ifdef MSM_PLATFORM /*stop timer in sap/p2p_go */ @@ -7308,7 +7309,6 @@ int wlan_hdd_setup_driver_overrides(hdd_adapter_t *ap_adapter) { tsap_Config_t *sap_cfg = &ap_adapter->sessionCtx.ap.sapConfig; hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(ap_adapter); - tHalHandle h_hal = WLAN_HDD_GET_HAL_CTX(ap_adapter); if (ap_adapter->device_mode == QDF_SAP_MODE && hdd_ctx->config->force_sap_acs) @@ -7342,7 +7342,7 @@ int wlan_hdd_setup_driver_overrides(hdd_adapter_t *ap_adapter) eHT_CHANNEL_WIDTH_20MHZ; } sap_cfg->ch_params.ch_width = sap_cfg->ch_width_orig; - sme_set_ch_params(h_hal, sap_cfg->SapHw_mode, sap_cfg->channel, + cds_set_channel_params(sap_cfg->channel, sap_cfg->sec_ch, &sap_cfg->ch_params); return 0; diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 7d46b2d8e400..c1ae84d90920 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -5181,9 +5181,7 @@ void hdd_restart_sap(hdd_adapter_t *adapter, uint8_t channel) hdd_info("chan:%d width:%d", channel, hdd_ap_ctx->sapConfig.ch_width_orig); - sme_set_ch_params(hal_handle, - hdd_ap_ctx->sapConfig.SapHw_mode, - hdd_ap_ctx->sapConfig.channel, + cds_set_channel_params(hdd_ap_ctx->sapConfig.channel, hdd_ap_ctx->sapConfig.sec_ch, &hdd_ap_ctx->sapConfig.ch_params); @@ -6326,6 +6324,42 @@ out: } /** + * hdd_adaptive_dwelltime_init() - initialization for adaptive dwell time config + * @hdd_ctx: HDD context + * + * This function sends the adaptive dwell time config configuration to the + * firmware via WMA + * + * Return: 0 - success, < 0 - failure + */ +static int hdd_adaptive_dwelltime_init(hdd_context_t *hdd_ctx) +{ + QDF_STATUS status; + struct adaptive_dwelltime_params dwelltime_params; + + dwelltime_params.is_enabled = + hdd_ctx->config->adaptive_dwell_mode_enabled; + dwelltime_params.dwelltime_mode = + hdd_ctx->config->global_adapt_dwelltime_mode; + dwelltime_params.lpf_weight = + hdd_ctx->config->adapt_dwell_lpf_weight; + dwelltime_params.passive_mon_intval = + hdd_ctx->config->adapt_dwell_passive_mon_intval; + dwelltime_params.wifi_act_threshold = + hdd_ctx->config->adapt_dwell_wifi_act_threshold; + + status = sme_set_adaptive_dwelltime_config(hdd_ctx->hHal, + &dwelltime_params); + + hdd_debug("Sending Adaptive Dwelltime Configuration to fw"); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to send Adaptive Dwelltime configuration!"); + return -EAGAIN; + } + return 0; +} + +/** * hdd_wlan_startup() - HDD init function * @dev: Pointer to the underlying device * @@ -6509,6 +6543,9 @@ int hdd_wlan_startup(struct device *dev, void *hif_sc) if (0 != hdd_lro_init(hdd_ctx)) hdd_err("Unable to initialize LRO in fw"); + if (0 != hdd_adaptive_dwelltime_init(hdd_ctx)) + hdd_err("Unable to send adaptive dwelltime setting to FW"); + hddtxlimit.txPower2g = hdd_ctx->config->TxPower2g; hddtxlimit.txPower5g = hdd_ctx->config->TxPower5g; status = sme_txpower_limit(hdd_ctx->hHal, &hddtxlimit); diff --git a/core/hdd/src/wlan_hdd_oemdata.c b/core/hdd/src/wlan_hdd_oemdata.c index c3d4ec7dd519..7452022d8db9 100644 --- a/core/hdd/src/wlan_hdd_oemdata.c +++ b/core/hdd/src/wlan_hdd_oemdata.c @@ -415,6 +415,45 @@ static QDF_STATUS oem_process_data_req_msg(int oemDataLen, char *oemData) } /** + * update_channel_bw_info() - set bandwidth info for the chan + * @hdd_ctx: hdd context + * @chan: channel for which info are required + * @hdd_chan_info: struct where the bandwidth info is filled + * + * This function find the maximum bandwidth allowed, secondary + * channel offset and center freq for the channel as per regulatory + * domain and using these info calculate the phy mode for the + * channel. + * + * Return: void + */ +static void hdd_update_channel_bw_info(hdd_context_t *hdd_ctx, + uint16_t chan, tHddChannelInfo *hdd_chan_info) +{ + struct ch_params_s ch_params = {0}; + uint16_t sec_ch_2g = 0; + WLAN_PHY_MODE phy_mode; + uint32_t wni_dot11_mode; + + wni_dot11_mode = sme_get_wni_dot11_mode(hdd_ctx->hHal); + + /* Passing CH_WIDTH_MAX will give the max bandwidth supported */ + ch_params.ch_width = CH_WIDTH_MAX; + + cds_set_channel_params(chan, sec_ch_2g, &ch_params); + if (ch_params.center_freq_seg0) + hdd_chan_info->band_center_freq1 = + cds_chan_to_freq(ch_params.center_freq_seg0); + + hdd_info("chan %d dot11_mode %d ch_width %d sec offset %d freq_seg0 %d", + chan, wni_dot11_mode, ch_params.ch_width, + ch_params.sec_ch_offset, hdd_chan_info->band_center_freq1); + + phy_mode = wma_chan_phy_mode(chan, ch_params.ch_width, wni_dot11_mode); + WMI_SET_CHANNEL_MODE(hdd_chan_info, phy_mode); +} + +/** * oem_process_channel_info_req_msg() - process oem channel_info request * @numOfChannels: number of channels * @chanList: list of channel information @@ -494,6 +533,9 @@ static int oem_process_channel_info_req_msg(int numOfChannels, char *chanList) cds_get_channel_state(chanId)) WMI_SET_CHANNEL_FLAG(&hddChanInfo, WMI_CHAN_FLAG_DFS); + + hdd_update_channel_bw_info(p_hdd_ctx, + chanId, &hddChanInfo); hddChanInfo.reg_info_1 = reg_info_1; hddChanInfo.reg_info_2 = reg_info_2; } else { @@ -655,12 +697,13 @@ static int oem_process_get_cap_req_msg(void) /** * hdd_send_peer_status_ind_to_oem_app() - - * Function to send peer status to a registered application + * Function to send peer status to a registered application * @peerMac: MAC address of peer * @peerStatus: ePeerConnected or ePeerDisconnected * @peerTimingMeasCap: 0: RTT/RTT2, 1: RTT3. Default is 0 * @sessionId: SME session id, i.e. vdev_id * @chan_info: operating channel information + * @dev_mode: dev mode for which indication is sent * * Return: none */ @@ -668,7 +711,8 @@ void hdd_send_peer_status_ind_to_oem_app(struct qdf_mac_addr *peerMac, uint8_t peerStatus, uint8_t peerTimingMeasCap, uint8_t sessionId, - tSirSmeChanInfo *chan_info) + tSirSmeChanInfo *chan_info, + enum tQDF_ADAPTER_MODE dev_mode) { struct sk_buff *skb; struct nlmsghdr *nlh; @@ -719,6 +763,9 @@ void hdd_send_peer_status_ind_to_oem_app(struct qdf_mac_addr *peerMac, pPeerInfo->vdev_id = sessionId; pPeerInfo->peer_capability = peerTimingMeasCap; pPeerInfo->reserved0 = 0; + /* Set 0th bit of reserved0 for STA mode */ + if (QDF_STA_MODE == dev_mode) + pPeerInfo->reserved0 |= 0x01; if (chan_info) { pPeerInfo->peer_chan_info.chan_id = chan_info->chan_id; diff --git a/core/hdd/src/wlan_hdd_scan.c b/core/hdd/src/wlan_hdd_scan.c index 97abe664c558..7e3acd7d3e84 100644 --- a/core/hdd/src/wlan_hdd_scan.c +++ b/core/hdd/src/wlan_hdd_scan.c @@ -2250,9 +2250,10 @@ static int __wlan_hdd_cfg80211_sched_scan_start(struct wiphy *wiphy, * * After Kernel 4.4 * User can configure multiple scan_plans, each scan would have - * separate scan cycle and interval. For our use case, we would - * only have supplicant set one scan_plan, and firmware also support - * only one as well, so pick up the first index. + * separate scan cycle and interval. (interval is in unit of second.) + * For our use case, we would only have supplicant set one scan_plan, + * and firmware also support only one as well, so pick up the first + * index. * * Taking power consumption into account * firmware after gPNOScanTimerRepeatValue times fast_scan_period @@ -2260,7 +2261,18 @@ static int __wlan_hdd_cfg80211_sched_scan_start(struct wiphy *wiphy, * shall be in slow_scan_period mode until next PNO Start. */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) || defined(WITH_BACKPORTS) - pPnoRequest->fast_scan_period = request->scan_plans[0].interval; + if (WARN_ON(request->n_scan_plans > SIR_PNO_MAX_PLAN_REQUEST)) { + ret = -EINVAL; + goto error; + } + + /* TBD: only one sched_scan plan we can support now, so we only + * retrieve the first plan and ignore the rest of them. + * If there are more than 1 sched_pan request we can support, the + * PnoRequet structure will also need to be revised. + */ + pPnoRequest->fast_scan_period = request->scan_plans[0].interval * + MSEC_PER_SEC; #else pPnoRequest->fast_scan_period = request->interval; #endif diff --git a/core/hdd/src/wlan_hdd_softap_tx_rx.c b/core/hdd/src/wlan_hdd_softap_tx_rx.c index 1f8bf40c360d..a0dbea356d3b 100644 --- a/core/hdd/src/wlan_hdd_softap_tx_rx.c +++ b/core/hdd/src/wlan_hdd_softap_tx_rx.c @@ -117,6 +117,49 @@ void hdd_softap_tx_resume_timer_expired_handler(void *adapter_context) return; } +#if defined(CONFIG_PER_VDEV_TX_DESC_POOL) + +/** + * hdd_softap_tx_resume_false() - Resume OS TX Q false leads to queue disabling + * @pAdapter: pointer to hdd adapter + * @tx_resume: TX Q resume trigger + * + * + * Return: None + */ +static void +hdd_softap_tx_resume_false(hdd_adapter_t *pAdapter, bool tx_resume) +{ + if (true == tx_resume) + return; + + hdd_notice("Disabling queues"); + wlan_hdd_netif_queue_control(pAdapter, WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + + if (QDF_TIMER_STATE_STOPPED == + qdf_mc_timer_get_current_state(&pAdapter-> + tx_flow_control_timer)) { + QDF_STATUS status; + status = qdf_mc_timer_start(&pAdapter->tx_flow_control_timer, + WLAN_SAP_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME); + + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed to start tx_flow_control_timer"); + else + pAdapter->hdd_stats.hddTxRxStats.txflow_timer_cnt++; + } + return; +} +#else + +static inline void +hdd_softap_tx_resume_false(hdd_adapter_t *pAdapter, bool tx_resume) +{ + return; +} +#endif + /** * hdd_softap_tx_resume_cb() - Resume OS TX Q. * @adapter_context: pointer to vdev apdapter @@ -150,6 +193,8 @@ void hdd_softap_tx_resume_cb(void *adapter_context, bool tx_resume) WLAN_WAKE_ALL_NETIF_QUEUE, WLAN_DATA_FLOW_CONTROL); } + hdd_softap_tx_resume_false(pAdapter, tx_resume); + return; } #endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ diff --git a/core/hdd/src/wlan_hdd_stats.c b/core/hdd/src/wlan_hdd_stats.c index 6cf5a502e367..89c0791bc64d 100644 --- a/core/hdd/src/wlan_hdd_stats.c +++ b/core/hdd/src/wlan_hdd_stats.c @@ -233,8 +233,7 @@ static bool put_wifi_rate_stat(tpSirWifiRateStat stats, nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG, stats->retriesLong)) { - hddLog(QDF_TRACE_LEVEL_ERROR, - FL("QCA_WLAN_VENDOR_ATTR put fail")); + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); return false; } @@ -266,8 +265,7 @@ static bool put_wifi_peer_info(tpSirWifiPeerInfo stats, nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES, stats->numRate)) { - hddLog(QDF_TRACE_LEVEL_ERROR, - FL("QCA_WLAN_VENDOR_ATTR put fail")); + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); goto error; } @@ -292,8 +290,7 @@ static bool put_wifi_peer_info(tpSirWifiPeerInfo stats, if (false == put_wifi_rate_stat(pRateStats, vendor_event)) { - hddLog(QDF_TRACE_LEVEL_ERROR, - FL("QCA_WLAN_VENDOR_ATTR put fail")); + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); return false; } nla_nest_end(vendor_event, rates); @@ -360,8 +357,7 @@ static bool put_wifi_wmm_ac_stat(tpSirWifiWmmAcStat stats, nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES, stats->contentionNumSamples)) { - hddLog(QDF_TRACE_LEVEL_ERROR, - FL("QCA_WLAN_VENDOR_ATTR put fail")); + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); return false; } @@ -405,8 +401,7 @@ static bool put_wifi_interface_info(tpSirWifiInterfaceInfo stats, nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR, WNI_CFG_COUNTRY_CODE_LEN, stats->countryStr)) { - hddLog(QDF_TRACE_LEVEL_ERROR, - FL("QCA_WLAN_VENDOR_ATTR put fail")); + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); return false; } @@ -431,8 +426,7 @@ static bool put_wifi_iface_stats(tpSirWifiIfaceStat pWifiIfaceStat, if (false == put_wifi_interface_info(&pWifiIfaceStat->info, vendor_event)) { - hddLog(QDF_TRACE_LEVEL_ERROR, - FL("QCA_WLAN_VENDOR_ATTR put fail")); + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); return false; } @@ -480,8 +474,7 @@ static bool put_wifi_iface_stats(tpSirWifiIfaceStat pWifiIfaceStat, nla_put_u64(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET, average_tsf_offset)) { - hddLog(QDF_TRACE_LEVEL_ERROR, - FL("QCA_WLAN_VENDOR_ATTR put fail")); + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); return false; } @@ -498,8 +491,7 @@ static bool put_wifi_iface_stats(tpSirWifiIfaceStat pWifiIfaceStat, if (false == put_wifi_wmm_ac_stat(&pWifiIfaceStat->AccessclassStats[i], vendor_event)) { - hddLog(QDF_TRACE_LEVEL_ERROR, - FL("put_wifi_wmm_ac_stat Fail")); + hdd_err("put_wifi_wmm_ac_stat Fail"); return false; } @@ -563,9 +555,8 @@ static bool hdd_get_interface_info(hdd_adapter_t *pAdapter, } if (eConnectionState_Connecting == pHddStaCtx->conn_info.connState) { - hddLog(QDF_TRACE_LEVEL_ERROR, - "%s: Session ID %d, Connection is in progress", - __func__, pAdapter->sessionId); + hdd_err("Session ID %d, Connection is in progress", + pAdapter->sessionId); pInfo->state = WIFI_ASSOCIATING; } if ((eConnectionState_Associated == @@ -574,10 +565,9 @@ static bool hdd_get_interface_info(hdd_adapter_t *pAdapter, staMac = (uint8_t *) &(pAdapter->macAddressCurrent. bytes[0]); - hddLog(QDF_TRACE_LEVEL_ERROR, - "%s: client " MAC_ADDRESS_STR - " is in the middle of WPS/EAPOL exchange.", - __func__, MAC_ADDR_ARRAY(staMac)); + hdd_err("client " MAC_ADDRESS_STR + " is in the middle of WPS/EAPOL exchange.", + MAC_ADDR_ARRAY(staMac)); pInfo->state = WIFI_AUTHENTICATING; } if (eConnectionState_Associated == @@ -636,9 +626,8 @@ static void hdd_link_layer_process_peer_stats(hdd_adapter_t *pAdapter, if (0 != status) return; - hddLog(QDF_TRACE_LEVEL_INFO, - "LL_STATS_PEER_ALL : numPeers %u, more data = %u", - pWifiPeerStat->numPeers, more_data); + hdd_notice("LL_STATS_PEER_ALL : numPeers %u, more data = %u", + pWifiPeerStat->numPeers, more_data); /* * Allocate a size of 4096 for the peer stats comprising @@ -652,8 +641,7 @@ static void hdd_link_layer_process_peer_stats(hdd_adapter_t *pAdapter, LL_STATS_EVENT_BUF_SIZE); if (!vendor_event) { - hddLog(LOGE, - FL("cfg80211_vendor_cmd_alloc_reply_skb failed")); + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); return; } @@ -666,8 +654,7 @@ static void hdd_link_layer_process_peer_stats(hdd_adapter_t *pAdapter, nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS, pWifiPeerStat->numPeers)) { - hddLog(QDF_TRACE_LEVEL_ERROR, - "%s: QCA_WLAN_VENDOR_ATTR put fail", __func__); + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); kfree_skb(vendor_event); return; @@ -681,7 +668,7 @@ static void hdd_link_layer_process_peer_stats(hdd_adapter_t *pAdapter, peerInfo = nla_nest_start(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO); if (peerInfo == NULL) { - hddLog(LOGE, FL("nla_nest_start failed")); + hdd_err("nla_nest_start failed"); kfree_skb(vendor_event); return; } @@ -689,7 +676,7 @@ static void hdd_link_layer_process_peer_stats(hdd_adapter_t *pAdapter, for (i = 1; i <= pWifiPeerStat->numPeers; i++) { peers = nla_nest_start(vendor_event, i); if (peers == NULL) { - hddLog(LOGE, FL("nla_nest_start failed")); + hdd_err("nla_nest_start failed"); kfree_skb(vendor_event); return; } @@ -698,8 +685,7 @@ static void hdd_link_layer_process_peer_stats(hdd_adapter_t *pAdapter, if (false == put_wifi_peer_info(pWifiPeerInfo, vendor_event)) { - hddLog(QDF_TRACE_LEVEL_ERROR, - FL("put_wifi_peer_info fail")); + hdd_err("put_wifi_peer_info fail"); kfree_skb(vendor_event); return; } @@ -763,23 +749,21 @@ static void hdd_link_layer_process_iface_stats(hdd_adapter_t *pAdapter, LL_STATS_EVENT_BUF_SIZE); if (!vendor_event) { - hddLog(QDF_TRACE_LEVEL_ERROR, - FL("cfg80211_vendor_cmd_alloc_reply_skb failed")); + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); return; } - hddLog(QDF_TRACE_LEVEL_INFO, "WMI_LINK_STATS_IFACE Data"); + hdd_notice("WMI_LINK_STATS_IFACE Data"); if (false == hdd_get_interface_info(pAdapter, &pWifiIfaceStat->info)) { - hddLog(QDF_TRACE_LEVEL_ERROR, - FL("hdd_get_interface_info get fail")); + hdd_err("hdd_get_interface_info get fail"); kfree_skb(vendor_event); return; } if (false == put_wifi_iface_stats(pWifiIfaceStat, num_peers, vendor_event)) { - hddLog(QDF_TRACE_LEVEL_ERROR, FL("put_wifi_iface_stats fail")); + hdd_err("put_wifi_iface_stats fail"); kfree_skb(vendor_event); return; } @@ -820,8 +804,7 @@ static void hdd_link_layer_process_radio_stats(hdd_adapter_t *pAdapter, if (0 != status) return; - hddLog(QDF_TRACE_LEVEL_INFO, - "LL_STATS_RADIO" + hdd_notice("LL_STATS_RADIO" " number of radios = %u" " radio is %d onTime is %u" " txTime is %u rxTime is %u" @@ -854,8 +837,7 @@ static void hdd_link_layer_process_radio_stats(hdd_adapter_t *pAdapter, LL_STATS_EVENT_BUF_SIZE); if (!vendor_event) { - hddLog(LOGE, - FL("cfg80211_vendor_cmd_alloc_reply_skb failed")); + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); return; } @@ -901,8 +883,7 @@ static void hdd_link_layer_process_radio_stats(hdd_adapter_t *pAdapter, nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS, pWifiRadioStat->numChannels)) { - hddLog(QDF_TRACE_LEVEL_ERROR, - FL("QCA_WLAN_VENDOR_ATTR put fail")); + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); kfree_skb(vendor_event); return; @@ -915,7 +896,7 @@ static void hdd_link_layer_process_radio_stats(hdd_adapter_t *pAdapter, chList = nla_nest_start(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO); if (chList == NULL) { - hddLog(LOGE, FL("nla_nest_start failed")); + hdd_err("nla_nest_start failed"); kfree_skb(vendor_event); return; } @@ -930,7 +911,7 @@ static void hdd_link_layer_process_radio_stats(hdd_adapter_t *pAdapter, chInfo = nla_nest_start(vendor_event, i); if (chInfo == NULL) { - hddLog(LOGE, FL("nla_nest_start failed")); + hdd_err("nla_nest_start failed"); kfree_skb(vendor_event); return; } @@ -955,8 +936,7 @@ static void hdd_link_layer_process_radio_stats(hdd_adapter_t *pAdapter, nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME, pWifiChannelStats->ccaBusyTime)) { - hddLog(QDF_TRACE_LEVEL_ERROR, - FL("nla_put failed")); + hdd_err("nla_put failed"); kfree_skb(vendor_event); return; } @@ -997,20 +977,17 @@ static void wlan_hdd_cfg80211_link_layer_stats_callback(void *ctx, linkLayerStatsResults->ifaceId); if (NULL == pAdapter) { - QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, - "%s: vdev_id %d does not exist with host", - __func__, linkLayerStatsResults->ifaceId); + hdd_err("vdev_id %d does not exist with host", + linkLayerStatsResults->ifaceId); return; } - QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO, - "%s: Link Layer Indication indType: %d", __func__, indType); + hdd_notice("Link Layer Indication indType: %d", indType); switch (indType) { case SIR_HAL_LL_STATS_RESULTS_RSP: { - hddLog(QDF_TRACE_LEVEL_INFO, - "LL_STATS RESP paramID = 0x%x, ifaceId = %u, respId= %u , moreResultToFollow = %u, num radio = %u result = %p", + hdd_notice("LL_STATS RESP paramID = 0x%x, ifaceId = %u, respId= %u , moreResultToFollow = %u, num radio = %u result = %p", linkLayerStatsResults->paramId, linkLayerStatsResults->ifaceId, linkLayerStatsResults->rspId, @@ -1024,8 +1001,7 @@ static void wlan_hdd_cfg80211_link_layer_stats_callback(void *ctx, if ((context->request_id != linkLayerStatsResults->rspId) || !(context->request_bitmap & linkLayerStatsResults->paramId)) { spin_unlock(&context->context_lock); - hddLog(LOGE, - FL("Error : Request id %d response id %d request bitmap 0x%x response bitmap 0x%x"), + hdd_err("Error : Request id %d response id %d request bitmap 0x%x response bitmap 0x%x", context->request_id, linkLayerStatsResults->rspId, context->request_bitmap, linkLayerStatsResults->paramId); return; @@ -1074,8 +1050,7 @@ static void wlan_hdd_cfg80211_link_layer_stats_callback(void *ctx, spin_unlock(&context->context_lock); } else { - hddLog(LOGE, - FL("INVALID LL_STATS_NOTIFY RESPONSE")); + hdd_err("INVALID LL_STATS_NOTIFY RESPONSE"); } spin_lock(&context->context_lock); @@ -1087,7 +1062,7 @@ static void wlan_hdd_cfg80211_link_layer_stats_callback(void *ctx, break; } default: - hddLog(QDF_TRACE_LEVEL_ERROR, "invalid event type %d", indType); + hdd_err("invalid event type %d", indType); break; } @@ -1151,21 +1126,19 @@ __wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy, if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX, (struct nlattr *)data, data_len, qca_wlan_vendor_ll_set_policy)) { - hddLog(QDF_TRACE_LEVEL_ERROR, - FL("maximum attribute not present")); + hdd_err("maximum attribute not present"); return -EINVAL; } if (!tb_vendor [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]) { - hddLog(QDF_TRACE_LEVEL_ERROR, FL("MPDU size Not present")); + hdd_err("MPDU size Not present"); return -EINVAL; } if (!tb_vendor [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]) { - hddLog(QDF_TRACE_LEVEL_ERROR, - FL("Stats Gathering Not Present")); + hdd_err("Stats Gathering Not Present"); return -EINVAL; } @@ -1182,16 +1155,14 @@ __wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy, LinkLayerStatsSetReq.staId = pAdapter->sessionId; - hddLog(QDF_TRACE_LEVEL_INFO, - "LL_STATS_SET reqId = %d, staId = %d, mpduSizeThreshold = %d, Statistics Gathering = %d", + hdd_notice("LL_STATS_SET reqId = %d, staId = %d, mpduSizeThreshold = %d, Statistics Gathering = %d", LinkLayerStatsSetReq.reqId, LinkLayerStatsSetReq.staId, LinkLayerStatsSetReq.mpduSizeThreshold, LinkLayerStatsSetReq.aggressiveStatisticsGathering); if (QDF_STATUS_SUCCESS != sme_ll_stats_set_req(pHddCtx->hHal, &LinkLayerStatsSetReq)) { - hddLog(QDF_TRACE_LEVEL_ERROR, "%s:" - "sme_ll_stats_set_req Failed", __func__); + hdd_err("sme_ll_stats_set_req Failed"); return -EINVAL; } @@ -1275,24 +1246,25 @@ __wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy, return -EINVAL; if (!pAdapter->isLinkLayerStatsSet) { - hdd_warn("isLinkLayerStatsSet : %d", pAdapter->isLinkLayerStatsSet); + hdd_warn("isLinkLayerStatsSet: %d", + pAdapter->isLinkLayerStatsSet); return -EINVAL; } if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX, (struct nlattr *)data, data_len, qca_wlan_vendor_ll_get_policy)) { - hddLog(QDF_TRACE_LEVEL_ERROR, FL("max attribute not present")); + hdd_err("max attribute not present"); return -EINVAL; } if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]) { - hddLog(QDF_TRACE_LEVEL_ERROR, FL("Request Id Not present")); + hdd_err("Request Id Not present"); return -EINVAL; } if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]) { - hddLog(QDF_TRACE_LEVEL_ERROR, FL("Req Mask Not present")); + hdd_err("Req Mask Not present"); return -EINVAL; } @@ -1305,8 +1277,7 @@ __wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy, LinkLayerStatsGetReq.staId = pAdapter->sessionId; - hddLog(QDF_TRACE_LEVEL_INFO, - "LL_STATS_GET reqId = %d, staId = %d, paramIdMask = %d", + hdd_notice("LL_STATS_GET reqId = %d, staId = %d, paramIdMask = %d", LinkLayerStatsGetReq.reqId, LinkLayerStatsGetReq.staId, LinkLayerStatsGetReq.paramIdMask); @@ -1320,16 +1291,14 @@ __wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy, if (QDF_STATUS_SUCCESS != sme_ll_stats_get_req(pHddCtx->hHal, &LinkLayerStatsGetReq)) { - hddLog(QDF_TRACE_LEVEL_ERROR, "%s:" - "sme_ll_stats_get_req Failed", __func__); + hdd_err("sme_ll_stats_get_req Failed"); return -EINVAL; } rc = wait_for_completion_timeout(&context->response_event, msecs_to_jiffies(WLAN_WAIT_TIME_LL_STATS)); if (!rc) { - hddLog(LOGE, - FL("Target response timed out request id %d request bitmap 0x%x"), + hdd_err("Target response timed out request id %d request bitmap 0x%x", context->request_id, context->request_bitmap); return -ETIMEDOUT; } @@ -1406,24 +1375,21 @@ __wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy, return -EINVAL; if (!pAdapter->isLinkLayerStatsSet) { - hddLog(QDF_TRACE_LEVEL_FATAL, - "%s: isLinkLayerStatsSet : %d", - __func__, pAdapter->isLinkLayerStatsSet); + hdd_alert("isLinkLayerStatsSet : %d", + pAdapter->isLinkLayerStatsSet); return -EINVAL; } if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX, (struct nlattr *)data, data_len, qca_wlan_vendor_ll_clr_policy)) { - hddLog(QDF_TRACE_LEVEL_ERROR, - FL("STATS_CLR_MAX is not present")); + hdd_err("STATS_CLR_MAX is not present"); return -EINVAL; } if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] || !tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]) { - hddLog(QDF_TRACE_LEVEL_ERROR, - FL("Error in LL_STATS CLR CONFIG PARA")); + hdd_err("Error in LL_STATS CLR CONFIG PARA"); return -EINVAL; } @@ -1442,8 +1408,7 @@ __wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy, LinkLayerStatsClearReq.staId = pAdapter->sessionId; - hddLog(QDF_TRACE_LEVEL_INFO, - "LL_STATS_CLEAR reqId = %d, staId = %d, statsClearReqMask = 0x%X, stopReq = %d", + hdd_notice("LL_STATS_CLEAR reqId = %d, staId = %d, statsClearReqMask = 0x%X, stopReq = %d", LinkLayerStatsClearReq.reqId, LinkLayerStatsClearReq.staId, LinkLayerStatsClearReq.statsClearReqMask, @@ -1463,18 +1428,20 @@ __wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy, nla_put_u32(temp_skbuff, QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP, stopReq)) { - hddLog(QDF_TRACE_LEVEL_ERROR, - FL("LL_STATS_CLR put fail")); + hdd_err("LL_STATS_CLR put fail"); kfree_skb(temp_skbuff); return -EINVAL; } - /* If the ask is to stop the stats collection as part of clear - * (stopReq = 1) , ensure that no further requests of get - * go to the firmware by having isLinkLayerStatsSet set to 0. - * However it the stopReq as part of the clear request is 0 , - * the request to get the statistics are honoured as in this - * case the firmware is just asked to clear the statistics. + /* If the ask is to stop the stats collection + * as part of clear (stopReq = 1), ensure + * that no further requests of get go to the + * firmware by having isLinkLayerStatsSet set + * to 0. However it the stopReq as part of + * the clear request is 0, the request to get + * the statistics are honoured as in this case + * the firmware is just asked to clear the + * statistics. */ if (stopReq == 1) pAdapter->isLinkLayerStatsSet = 0; @@ -1603,13 +1570,10 @@ static void wlan_hdd_cfg80211_stats_ext_callback(void *ctx, if (status) return; - pAdapter = hdd_get_adapter_by_vdev(pHddCtx, data->vdev_id); if (NULL == pAdapter) { - QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, - "%s: vdev_id %d does not exist with host", - __func__, data->vdev_id); + hdd_err("vdev_id %d does not exist with host", data->vdev_id); return; } @@ -1622,17 +1586,14 @@ static void wlan_hdd_cfg80211_stats_ext_callback(void *ctx, GFP_KERNEL); if (!vendor_event) { - QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, - "%s: cfg80211_vendor_event_alloc failed", __func__); + hdd_err("cfg80211_vendor_event_alloc failed"); return; } ret_val = nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_IFINDEX, pAdapter->dev->ifindex); if (ret_val) { - QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, - "%s: QCA_WLAN_VENDOR_ATTR_IFINDEX put fail", - __func__); + hdd_err("QCA_WLAN_VENDOR_ATTR_IFINDEX put fail"); kfree_skb(vendor_event); return; @@ -1642,9 +1603,7 @@ static void wlan_hdd_cfg80211_stats_ext_callback(void *ctx, data->event_data_len, data->event_data); if (ret_val) { - QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, - "%s: QCA_WLAN_VENDOR_ATTR_STATS_EXT put fail", - __func__); + hdd_err("QCA_WLAN_VENDOR_ATTR_STATS_EXT put fail"); kfree_skb(vendor_event); return; @@ -1710,24 +1669,23 @@ static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, uint32_t vht_mcs_map; enum eDataRate11ACMaxMcs vhtMaxMcs; - ENTER(); + ENTER_DEV(dev); if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { - hddLog(LOGE, FL("Command not allowed in FTM mode")); + hdd_err("Command not allowed in FTM mode"); return -EINVAL; } if ((eConnectionState_Associated != pHddStaCtx->conn_info.connState) || (0 == ssidlen)) { - hddLog(LOG1, FL("Not associated or Invalid ssidlen, %d"), + hdd_notice("Not associated or Invalid ssidlen, %d", ssidlen); /*To keep GUI happy */ return 0; } if (true == pHddStaCtx->hdd_ReassocScenario) { - hddLog(LOG1, - FL("Roaming is in progress, cannot continue with this request")); + hdd_notice("Roaming is in progress, cannot continue with this request"); return 0; } @@ -1802,8 +1760,7 @@ static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, } } else { /* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */ - hddLog(LOGE, - FL("Invalid value for reportMaxLinkSpeed: %u"), + hdd_err("Invalid value for reportMaxLinkSpeed: %u", pCfg->reportMaxLinkSpeed); rssidx = 0; } @@ -1816,7 +1773,7 @@ static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, WNI_CFG_OPERATIONAL_RATE_SET, OperationalRates, &ORLeng)) { - hddLog(LOGE, FL("cfg get returned failure")); + hdd_err("cfg get returned failure"); /*To keep GUI happy */ return 0; } @@ -1843,7 +1800,7 @@ static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter), WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, ExtendedRates, &ERLeng)) { - hddLog(LOGE, FL("cfg get returned failure")); + hdd_err("cfg get returned failure"); /*To keep GUI happy */ return 0; } @@ -1871,7 +1828,7 @@ static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter), WNI_CFG_CURRENT_MCS_SET, MCSRates, &MCSLeng)) { - hddLog(LOGE, FL("cfg get returned failure")); + hdd_err("cfg get returned failure"); /*To keep GUI happy */ return 0; } @@ -2170,12 +2127,11 @@ static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, #endif if (rate_flags & eHAL_TX_RATE_LEGACY) - hddLog(LOG1, FL("Reporting legacy rate %d pkt cnt tx %d rx %d"), + hdd_notice("Reporting legacy rate %d pkt cnt tx %d rx %d", sinfo->txrate.legacy, sinfo->tx_packets, sinfo->rx_packets); else - hddLog(LOG1, - FL("Reporting MCS rate %d flags 0x%x pkt cnt tx %d rx %d"), + hdd_notice("Reporting MCS rate %d flags 0x%x pkt cnt tx %d rx %d", sinfo->txrate.mcs, sinfo->txrate.flags, sinfo->tx_packets, sinfo->rx_packets); @@ -2251,10 +2207,10 @@ static int __wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy, int8_t snr, rssi; int status, i, j, filled = 0; - ENTER(); + ENTER_DEV(dev); if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { - hddLog(LOGE, FL("Command not allowed in FTM mode")); + hdd_err("Command not allowed in FTM mode"); return -EINVAL; } diff --git a/core/hdd/src/wlan_hdd_tx_rx.c b/core/hdd/src/wlan_hdd_tx_rx.c index d3d8d712cd8c..10897f1d4160 100644 --- a/core/hdd/src/wlan_hdd_tx_rx.c +++ b/core/hdd/src/wlan_hdd_tx_rx.c @@ -96,6 +96,53 @@ void hdd_tx_resume_timer_expired_handler(void *adapter_context) WLAN_CONTROL_PATH); return; } +#if defined(CONFIG_PER_VDEV_TX_DESC_POOL) + +/** + * hdd_tx_resume_false() - Resume OS TX Q false leads to queue disabling + * @pAdapter: pointer to hdd adapter + * @tx_resume: TX Q resume trigger + * + * + * Return: None + */ +static void +hdd_tx_resume_false(hdd_adapter_t *pAdapter, bool tx_resume) +{ + if (true == tx_resume) + return; + + /* Pause TX */ + hdd_notice("Disabling queues"); + wlan_hdd_netif_queue_control(pAdapter, WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + + if (QDF_TIMER_STATE_STOPPED == + qdf_mc_timer_get_current_state(&pAdapter-> + tx_flow_control_timer)) { + QDF_STATUS status; + status = qdf_mc_timer_start(&pAdapter->tx_flow_control_timer, + WLAN_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME); + + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed to start tx_flow_control_timer"); + else + pAdapter->hdd_stats.hddTxRxStats.txflow_timer_cnt++; + } + + pAdapter->hdd_stats.hddTxRxStats.txflow_pause_cnt++; + pAdapter->hdd_stats.hddTxRxStats.is_txflow_paused = true; + + return; +} +#else + +static inline void +hdd_tx_resume_false(hdd_adapter_t *pAdapter, bool tx_resume) +{ + return; +} +#endif /** * hdd_tx_resume_cb() - Resume OS TX Q. @@ -135,6 +182,8 @@ void hdd_tx_resume_cb(void *adapter_context, bool tx_resume) WLAN_WAKE_ALL_NETIF_QUEUE, WLAN_DATA_FLOW_CONTROL); } + hdd_tx_resume_false(pAdapter, tx_resume); + return; } diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c index a85866498b58..1024e51715e3 100644 --- a/core/hdd/src/wlan_hdd_wext.c +++ b/core/hdd/src/wlan_hdd_wext.c @@ -9758,7 +9758,7 @@ static int wlan_hdd_set_mon_chan(hdd_adapter_t *adapter, uint32_t chan, QDF_MAC_ADDR_SIZE); ch_params.ch_width = bandwidth; - sme_set_ch_params(hal_hdl, ch_info->phy_mode, chan, 0, &ch_params); + cds_set_channel_params(chan, 0, &ch_params); status = sme_roam_channel_change_req(hal_hdl, bssid, &ch_params, &roam_profile); if (status) { diff --git a/core/mac/inc/qwlan_version.h b/core/mac/inc/qwlan_version.h index 25e1b060be98..b99b359f6dc0 100644 --- a/core/mac/inc/qwlan_version.h +++ b/core/mac/inc/qwlan_version.h @@ -42,8 +42,8 @@ #define QWLAN_VERSION_MINOR 1 #define QWLAN_VERSION_PATCH 0 #define QWLAN_VERSION_EXTRA "" -#define QWLAN_VERSION_BUILD 11 +#define QWLAN_VERSION_BUILD 12 -#define QWLAN_VERSIONSTR "5.1.0.11" +#define QWLAN_VERSIONSTR "5.1.0.12" #endif /* QWLAN_VERSION_H */ diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h index c36d69873465..c0b33c94f2a1 100644 --- a/core/mac/inc/sir_api.h +++ b/core/mac/inc/sir_api.h @@ -46,6 +46,7 @@ #include "ani_system_defs.h" #include "sir_params.h" #include "cds_regdomain.h" +#include "wmi_unified_param.h" #define OFFSET_OF(structType, fldName) (&((structType *)0)->fldName) @@ -761,6 +762,7 @@ typedef struct sSirSmeScanReq { * WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME) is used. */ uint32_t maxChannelTime; + enum wmi_dwelltime_adaptive_mode scan_adaptive_dwell_mode; /** * returnAfterFirstMatch can take following values: * 0x00 - Return SCAN_RSP message after complete channel scan @@ -2714,6 +2716,7 @@ typedef struct sAniIbssRouteTable { /* Set PNO */ +#define SIR_PNO_MAX_PLAN_REQUEST 1 #define SIR_PNO_MAX_NETW_CHANNELS 26 #define SIR_PNO_MAX_NETW_CHANNELS_EX 60 #define SIR_PNO_MAX_SUPP_NETWORKS 16 @@ -2778,6 +2781,7 @@ typedef struct sSirPNOScanReq { bool pno_channel_prediction; uint8_t top_k_num_of_channels; uint8_t stationary_thresh; + enum wmi_dwelltime_adaptive_mode pnoscan_adaptive_dwell_mode; uint32_t channel_prediction_full_scan; #endif } tSirPNOScanReq, *tpSirPNOScanReq; @@ -2952,6 +2956,7 @@ typedef struct sSirRoamOffloadScanReq { uint8_t early_stop_scan_enable; int8_t early_stop_scan_min_threshold; int8_t early_stop_scan_max_threshold; + enum wmi_dwelltime_adaptive_mode roamscan_adaptive_dwell_mode; } tSirRoamOffloadScanReq, *tpSirRoamOffloadScanReq; typedef struct sSirRoamOffloadScanRsp { @@ -3577,6 +3582,7 @@ typedef struct sSirScanOffloadReq { /*in units of milliseconds, ignored when not connected*/ uint32_t idle_time; tSirP2pScanType p2pScanType; + enum wmi_dwelltime_adaptive_mode scan_adaptive_dwell_mode; uint16_t uIEFieldLen; uint16_t uIEFieldOffset; tSirChannelList channelList; @@ -4024,6 +4030,34 @@ typedef struct sSirTxPowerLimit { uint32_t txPower5g; } tSirTxPowerLimit; +enum bad_peer_thresh_levels { + WLAN_WMA_IEEE80211_B_LEVEL = 0, + WLAN_WMA_IEEE80211_AG_LEVEL, + WLAN_WMA_IEEE80211_N_LEVEL, + WLAN_WMA_IEEE80211_AC_LEVEL, + WLAN_WMA_IEEE80211_AX_LEVEL, + WLAN_WMA_IEEE80211_MAX_LEVEL, +}; + +#define NUM_OF_RATE_THRESH_MAX (4) +struct t_bad_peer_info { + uint32_t cond; + uint32_t delta; + uint32_t percentage; + uint32_t thresh[NUM_OF_RATE_THRESH_MAX]; + uint32_t txlimit; +}; + +struct t_bad_peer_txtcl_config { + /* Array of thermal levels */ + struct t_bad_peer_info threshold[WLAN_WMA_IEEE80211_MAX_LEVEL]; + uint32_t enable; + uint32_t period; + uint32_t txq_limit; + uint32_t tgt_backoff; + uint32_t tgt_report_prd; +}; + /* notify MODEM power state to FW */ typedef struct { uint32_t param; @@ -4422,6 +4456,7 @@ typedef struct { uint32_t min_dwell_time_passive; uint32_t max_dwell_time_passive; uint32_t configuration_flags; + enum wmi_dwelltime_adaptive_mode extscan_adaptive_dwell_mode; tSirWifiScanBucketSpec buckets[WLAN_EXTSCAN_MAX_BUCKETS]; } tSirWifiScanCmdReqParams, *tpSirWifiScanCmdReqParams; @@ -5625,6 +5660,26 @@ struct beacon_filter_param { }; /** + * struct adaptive_dwelltime_params - the adaptive dwelltime params + * @vdev_id: vdev id + * @is_enabled: Adaptive dwell time is enabled/disabled + * @dwelltime_mode: global default adaptive dwell mode + * @lpf_weight: weight to calculate the average low pass + * filter for channel congestion + * @passive_mon_intval: intval to monitor wifi activity in passive scan in msec + * @wifi_act_threshold: % of wifi activity used in passive scan 0-100 + * + */ +struct adaptive_dwelltime_params { + uint32_t vdev_id; + bool is_enabled; + uint8_t dwelltime_mode; + uint8_t lpf_weight; + uint8_t passive_mon_intval; + uint8_t wifi_act_threshold; +}; + +/** * struct csa_offload_params - CSA offload request parameters * @channel: channel * @switch_mode: switch mode diff --git a/core/mac/src/include/sir_params.h b/core/mac/src/include/sir_params.h index acedd40e31f0..476e4a68b752 100644 --- a/core/mac/src/include/sir_params.h +++ b/core/mac/src/include/sir_params.h @@ -109,6 +109,7 @@ typedef enum eSriLinkState { eSIR_LINK_POSTASSOC_STATE = 2, eSIR_LINK_AP_STATE = 3, eSIR_LINK_IBSS_STATE = 4, + eSIR_LINK_DOWN_STATE = 5, } tSirLinkState; /* / Message queue structure used across Sirius project. */ @@ -591,6 +592,7 @@ typedef struct sSirMbMsgP2p { #define SIR_HAL_PDEV_SET_HW_MODE_RESP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 330) #define SIR_HAL_PDEV_HW_MODE_TRANS_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 331) +#define SIR_HAL_BAD_PEER_TX_CTL_INI_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 332) #define SIR_HAL_SET_RSSI_MONITOR_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 333) #define SIR_HAL_SET_IE_INFO (SIR_HAL_ITC_MSG_TYPES_BEGIN + 334) @@ -608,6 +610,7 @@ typedef struct sSirMbMsgP2p { #define SIR_HAL_BPF_SET_INSTRUCTIONS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 342) #define SIR_HAL_SET_WISA_PARAMS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 343) +#define SIR_HAL_SET_ADAPT_DWELLTIME_PARAMS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 344) #define SIR_HAL_MSG_TYPES_END (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF) /* CFG message types */ diff --git a/core/mac/src/pe/lim/lim_process_action_frame.c b/core/mac/src/pe/lim/lim_process_action_frame.c index e2f13bb66709..d1ba40d169ad 100644 --- a/core/mac/src/pe/lim/lim_process_action_frame.c +++ b/core/mac/src/pe/lim/lim_process_action_frame.c @@ -1345,7 +1345,7 @@ __lim_process_radio_measure_request(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, tpPESession psessionEntry) { tpSirMacMgmtHdr pHdr; - tDot11fRadioMeasurementRequest frm; + tDot11fRadioMeasurementRequest *frm; uint32_t frameLen, nStatus; uint8_t *pBody; @@ -1361,31 +1361,38 @@ __lim_process_radio_measure_request(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, frameLen + sizeof(tSirMacMgmtHdr), 0, WMA_GET_RX_CH(pRxPacketInfo), psessionEntry, 0); + frm = qdf_mem_malloc(sizeof(*frm)); + if (frm == NULL) { + lim_log(pMac, LOGE, + FL("Failed to alloc memory for tDot11fRadioMeasurementRequest")); + return; + } + /**Unpack the received frame */ - nStatus = - dot11f_unpack_radio_measurement_request(pMac, pBody, frameLen, &frm); + nStatus = dot11f_unpack_radio_measurement_request(pMac, + pBody, + frameLen, frm); if (DOT11F_FAILED(nStatus)) { lim_log(pMac, LOGE, - FL - ("Failed to unpack and parse a Radio Measure request (0x%08x, %d bytes):"), + FL("Failed to unpack and parse a Radio Measure request (0x%08x, %d bytes):"), nStatus, frameLen); PELOG2(sir_dump_buf - (pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen); - ) - return; + (pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen);) + goto err; } else if (DOT11F_WARNED(nStatus)) { lim_log(pMac, LOGW, - FL - ("There were warnings while unpacking a Radio Measure request (0x%08x, %d bytes):"), + FL("There were warnings while unpacking a Radio Measure request (0x%08x, %d bytes):"), nStatus, frameLen); PELOG2(sir_dump_buf - (pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen); - ) + (pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen);) } /* Call rrm function to handle the request. */ - rrm_process_radio_measurement_request(pMac, pHdr->sa, &frm, psessionEntry); + rrm_process_radio_measurement_request(pMac, pHdr->sa, frm, + psessionEntry); +err: + qdf_mem_free(frm); } static void diff --git a/core/mac/src/pe/lim/lim_process_assoc_req_frame.c b/core/mac/src/pe/lim/lim_process_assoc_req_frame.c index 4540bc132840..8fae7d389749 100644 --- a/core/mac/src/pe/lim/lim_process_assoc_req_frame.c +++ b/core/mac/src/pe/lim/lim_process_assoc_req_frame.c @@ -2048,7 +2048,7 @@ static void lim_fill_assoc_ind_vht_info(tpAniSirGlobal mac_ctx, if (session_entry->limRFBand == SIR_BAND_2_4_GHZ) { if (session_entry->vhtCapability && assoc_req->VHTCaps.present) - assoc_ind->chan_info.info = MODE_11AC_VHT20; + assoc_ind->chan_info.info = MODE_11AC_VHT20_2G; else if (session_entry->htCapability && assoc_req->HTCaps.present) assoc_ind->chan_info.info = MODE_11NG_HT20; diff --git a/core/mac/src/pe/lim/lim_process_mlm_req_messages.c b/core/mac/src/pe/lim/lim_process_mlm_req_messages.c index 897f3621a52e..fb43f581a2f7 100644 --- a/core/mac/src/pe/lim/lim_process_mlm_req_messages.c +++ b/core/mac/src/pe/lim/lim_process_mlm_req_messages.c @@ -2394,11 +2394,6 @@ static void lim_process_join_failure_timeout(tpAniSirGlobal mac_ctx) session->limMlmState = eLIM_MLM_IDLE_STATE; MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, session->peSessionId, session->limMlmState)); - if (lim_set_link_state(mac_ctx, eSIR_LINK_IDLE_STATE, - session->bssId, session->selfMacAddr, - NULL, NULL) != eSIR_SUCCESS) - lim_log(mac_ctx, LOGE, - ("Failed to set the LinkState")); /* Update PE session Id */ mlm_join_cnf.sessionId = session->peSessionId; /* Freeup buffer allocated to join request */ diff --git a/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c b/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c index 3f8b0fcdc1ae..99fc67e544d1 100644 --- a/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c +++ b/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c @@ -1436,7 +1436,7 @@ error: /* Delete teh session if JOIN failure occurred. */ if (result_code != eSIR_SME_SUCCESS) { if (lim_set_link_state - (mac_ctx, eSIR_LINK_IDLE_STATE, + (mac_ctx, eSIR_LINK_DOWN_STATE, session_entry->bssId, session_entry->selfMacAddr, NULL, NULL) != eSIR_SUCCESS) diff --git a/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/core/mac/src/pe/lim/lim_process_sme_req_messages.c index ffca2a72d7a8..e58f60020122 100644 --- a/core/mac/src/pe/lim/lim_process_sme_req_messages.c +++ b/core/mac/src/pe/lim/lim_process_sme_req_messages.c @@ -1300,6 +1300,8 @@ static QDF_STATUS lim_send_hal_start_scan_offload_req(tpAniSirGlobal pMac, pScanOffloadReq->restTime = pScanReq->restTime; pScanOffloadReq->min_rest_time = pScanReq->min_rest_time; pScanOffloadReq->idle_time = pScanReq->idle_time; + pScanOffloadReq->scan_adaptive_dwell_mode = + pScanReq->scan_adaptive_dwell_mode; /* for normal scan, the value for p2pScanType should be 0 always */ @@ -1309,6 +1311,8 @@ static QDF_STATUS lim_send_hal_start_scan_offload_req(tpAniSirGlobal pMac, pScanOffloadReq->sessionId = pScanReq->sessionId; pScanOffloadReq->scan_id = pScanReq->scan_id; pScanOffloadReq->scan_requestor_id = USER_SCAN_REQUESTOR_ID; + pScanOffloadReq->scan_adaptive_dwell_mode = + pScanReq->scan_adaptive_dwell_mode; if (pScanOffloadReq->sessionId >= pMac->lim.maxBssId) lim_log(pMac, LOGE, FL("Invalid pe sessionID : %d"), diff --git a/core/mac/src/pe/lim/lim_process_tdls.c b/core/mac/src/pe/lim/lim_process_tdls.c index 9016fbf2c412..53ec5b0ab084 100644 --- a/core/mac/src/pe/lim/lim_process_tdls.c +++ b/core/mac/src/pe/lim/lim_process_tdls.c @@ -846,10 +846,64 @@ static void populate_dotf_tdls_vht_aid(tpAniSirGlobal pMac, uint32_t selfDot11Mo } } +#ifdef CONFIG_HL_SUPPORT + +/** + * wma_tx_frame_with_tx_complete_send() - Send tx frames on Direct link or AP link + * depend on reason code + * @pMac: pointer to MAC Sirius parameter structure + * @pPacket: pointer to mgmt packet + * @nBytes: number of bytes to send + * @tid:tid value for AC + * @pFrame: pointer to tdls frame + * @smeSessionId:session id + * @flag: tdls flag + * + * Send TDLS Teardown frame on Direct link or AP link, depends on reason code. + * + * Return: None + */ +static inline QDF_STATUS +wma_tx_frame_with_tx_complete_send(tpAniSirGlobal pMac, void *pPacket, + uint16_t nBytes, + uint8_t tid, + uint8_t *pFrame, + uint8_t smeSessionId, bool flag) +{ + return wma_tx_frameWithTxComplete(pMac, pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_DATA, + ANI_TXDIR_TODS, + tid, + lim_tx_complete, pFrame, + lim_mgmt_tx_complete, + HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME, + smeSessionId, flag, 0); +} +#else + +static inline QDF_STATUS +wma_tx_frame_with_tx_complete_send(tpAniSirGlobal pMac, void *pPacket, + uint16_t nBytes, + uint8_t tid, + uint8_t *pFrame, + uint8_t smeSessionId, bool flag) +{ + return wma_tx_frameWithTxComplete(pMac, pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_DATA, + ANI_TXDIR_TODS, + tid, + lim_tx_complete, pFrame, + lim_mgmt_tx_complete, + HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME, + smeSessionId, false, 0); +} +#endif + /* * TDLS setup Request frame on AP link */ - tSirRetStatus lim_send_tdls_link_setup_req_frame(tpAniSirGlobal pMac, struct qdf_mac_addr peer_mac, uint8_t dialog, @@ -1108,14 +1162,11 @@ tSirRetStatus lim_send_tdls_link_setup_req_frame(tpAniSirGlobal pMac, pMac->lim.mgmtFrameSessionId = psessionEntry->peSessionId; - qdf_status = wma_tx_frameWithTxComplete(pMac, pPacket, (uint16_t) nBytes, - TXRX_FRM_802_11_DATA, - ANI_TXDIR_TODS, - TID_AC_VI, - lim_tx_complete, pFrame, - lim_mgmt_tx_complete, - HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME, - smeSessionId, false, 0); + qdf_status = wma_tx_frame_with_tx_complete_send(pMac, pPacket, + (uint16_t) nBytes, + TID_AC_VI, + pFrame, + smeSessionId, true); if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { pMac->lim.mgmtFrameSessionId = 0xff; @@ -1310,14 +1361,13 @@ tSirRetStatus lim_send_tdls_teardown_frame(tpAniSirGlobal pMac, pMac->lim.mgmtFrameSessionId = psessionEntry->peSessionId; - qdf_status = wma_tx_frameWithTxComplete(pMac, pPacket, (uint16_t) nBytes, - TXRX_FRM_802_11_DATA, - ANI_TXDIR_TODS, - TID_AC_VI, - lim_tx_complete, pFrame, - lim_mgmt_tx_complete, - HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME, - smeSessionId, false, 0); + qdf_status = wma_tx_frame_with_tx_complete_send(pMac, pPacket, + (uint16_t) nBytes, + TID_AC_VI, + pFrame, + smeSessionId, + (reason == eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE) + ? true : false); if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { pMac->lim.mgmtFrameSessionId = 0xff; @@ -1588,14 +1638,11 @@ static tSirRetStatus lim_send_tdls_setup_rsp_frame(tpAniSirGlobal pMac, pMac->lim.mgmtFrameSessionId = psessionEntry->peSessionId; - qdf_status = wma_tx_frameWithTxComplete(pMac, pPacket, (uint16_t) nBytes, - TXRX_FRM_802_11_DATA, - ANI_TXDIR_TODS, - TID_AC_VI, - lim_tx_complete, pFrame, - lim_mgmt_tx_complete, - HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME, - smeSessionId, false, 0); + qdf_status = wma_tx_frame_with_tx_complete_send(pMac, pPacket, + (uint16_t) nBytes, + TID_AC_VI, + pFrame, + smeSessionId, true); if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { pMac->lim.mgmtFrameSessionId = 0xff; @@ -1808,14 +1855,11 @@ tSirRetStatus lim_send_tdls_link_setup_cnf_frame(tpAniSirGlobal pMac, pMac->lim.mgmtFrameSessionId = psessionEntry->peSessionId; - qdf_status = wma_tx_frameWithTxComplete(pMac, pPacket, (uint16_t) nBytes, - TXRX_FRM_802_11_DATA, - ANI_TXDIR_TODS, - TID_AC_VI, - lim_tx_complete, pFrame, - lim_mgmt_tx_complete, - HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME, - smeSessionId, false, 0); + qdf_status = wma_tx_frame_with_tx_complete_send(pMac, pPacket, + (uint16_t) nBytes, + TID_AC_VI, + pFrame, + smeSessionId, true); if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { pMac->lim.mgmtFrameSessionId = 0xff; diff --git a/core/mac/src/pe/lim/lim_scan_result_utils.c b/core/mac/src/pe/lim/lim_scan_result_utils.c index b50b1ef49922..af0e93e5b1ac 100644 --- a/core/mac/src/pe/lim/lim_scan_result_utils.c +++ b/core/mac/src/pe/lim/lim_scan_result_utils.c @@ -180,8 +180,11 @@ lim_collect_bss_description(tpAniSirGlobal pMac, pBssDescr->nReceivedTime = (uint32_t) qdf_mc_timer_get_system_ticks(); pBssDescr->tsf_delta = WMA_GET_RX_TSF_DELTA(pRxPacketInfo); - lim_log(pMac, LOG2, FL("BSSID: "MAC_ADDRESS_STR " tsf_delta = %u"), - MAC_ADDR_ARRAY(pHdr->bssId), pBssDescr->tsf_delta); + lim_log(pMac, LOG1, + FL("BSSID: "MAC_ADDRESS_STR " tsf_delta = %u ReceivedTime = %u ssid = %s"), + MAC_ADDR_ARRAY(pHdr->bssId), pBssDescr->tsf_delta, + pBssDescr->nReceivedTime, + ((pBPR->ssidPresent) ? (char *)pBPR->ssId.ssId : "")); if (fScanning) { rrm_get_start_tsf(pMac, pBssDescr->startTSF); diff --git a/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c b/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c index d61aeb308648..0308f01cc0dd 100644 --- a/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c +++ b/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c @@ -2114,9 +2114,8 @@ void lim_handle_csa_offload_msg(tpAniSirGlobal mac_ctx, tpSirMsgQ msg) ch_params.ch_width = chnl_switch_info->newChanWidth; - cds_set_ch_params(csa_params->channel, - eCSR_DOT11_MODE_11ac, - &ch_params); + cds_set_channel_params(csa_params->channel, + 0, &ch_params); chnl_switch_info->newCenterChanFreq0 = ch_params.center_freq_seg0; /* @@ -2156,9 +2155,9 @@ void lim_handle_csa_offload_msg(tpAniSirGlobal mac_ctx, tpSirMsgQ msg) CH_WIDTH_40MHZ; ch_params.ch_width = chnl_switch_info->newChanWidth; - cds_set_ch_params(csa_params->channel, - eCSR_DOT11_MODE_11n, - &ch_params); + cds_set_channel_params( + csa_params->channel, + 0, &ch_params); lim_ch_switch->ch_center_freq_seg0 = ch_params.center_freq_seg0; lim_ch_switch->sec_ch_offset = @@ -2179,9 +2178,8 @@ void lim_handle_csa_offload_msg(tpAniSirGlobal mac_ctx, tpSirMsgQ msg) lim_ch_switch->state = eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; ch_params.ch_width = CH_WIDTH_40MHZ; - cds_set_ch_params(csa_params->channel, - eCSR_DOT11_MODE_11n, - &ch_params); + cds_set_channel_params(csa_params->channel, + 0, &ch_params); lim_ch_switch->ch_center_freq_seg0 = ch_params.center_freq_seg0; lim_ch_switch->sec_ch_offset = diff --git a/core/sap/dfs/src/dfs_phyerr_tlv.c b/core/sap/dfs/src/dfs_phyerr_tlv.c index 058e321d1c38..5a479edb3864 100644 --- a/core/sap/dfs/src/dfs_phyerr_tlv.c +++ b/core/sap/dfs/src/dfs_phyerr_tlv.c @@ -839,6 +839,7 @@ dfs_process_phyerr_bb_tlv(struct ath_dfs *dfs, void *buf, uint16_t datalen, /* * Try parsing the TLV set. */ + qdf_mem_zero(&rsfr, sizeof(rsfr)); if (!tlv_parse_frame(dfs, &rs, &rsfr, buf, datalen, rssi)) { invalid_phyerr_count++; /* diff --git a/core/sap/src/sap_api_link_cntl.c b/core/sap/src/sap_api_link_cntl.c index 7d76f9cd3cf1..a541031a9141 100644 --- a/core/sap/src/sap_api_link_cntl.c +++ b/core/sap/src/sap_api_link_cntl.c @@ -189,11 +189,9 @@ QDF_STATUS wlansap_scan_callback(tHalHandle hal_handle, } sap_ctx->ch_params.ch_width = sap_ctx->acs_cfg->ch_width; - sme_set_ch_params(hal_handle, - sap_ctx->csr_roamProfile.phyMode, - sap_ctx->channel, - sap_ctx->secondary_ch, - &sap_ctx->ch_params); + cds_set_channel_params(sap_ctx->channel, + sap_ctx->secondary_ch, + &sap_ctx->ch_params); #ifdef SOFTAP_CHANNEL_RANGE if (sap_ctx->channelList != NULL) { /* Always free up the memory for channel selection whatever @@ -241,9 +239,7 @@ void sap_config_acs_result(tHalHandle hal, ptSapContext sap_ctx, struct ch_params_s ch_params = {0}; ch_params.ch_width = sap_ctx->acs_cfg->ch_width; - sme_set_ch_params(hal, sap_ctx->csr_roamProfile.phyMode, channel, - sec_ch, &ch_params); - + cds_set_channel_params(channel, sec_ch, &ch_params); sap_ctx->acs_cfg->ch_width = ch_params.ch_width; if (sap_ctx->acs_cfg->ch_width > CH_WIDTH_40MHZ) sap_ctx->acs_cfg->vht_seg0_center_ch = @@ -525,7 +521,6 @@ wlansap_roam_process_dfs_chansw_update(tHalHandle hHal, uint8_t intf; QDF_STATUS qdf_status; tpAniSirGlobal mac_ctx = PMAC_STRUCT(hHal); - eCsrPhyMode phy_mode = sap_ctx->csr_roamProfile.phyMode; uint8_t dfs_beacon_start_req = 0; if (sap_ctx->csr_roamProfile.disableDFSChSwitch) { @@ -572,9 +567,9 @@ wlansap_roam_process_dfs_chansw_update(tHalHandle hHal, * currently. For e.g. 20/40/80 MHz operation */ if (mac_ctx->sap.SapDfsInfo.target_channel) - sme_set_ch_params(hHal, phy_mode, - mac_ctx->sap.SapDfsInfo.target_channel, 0, - &sap_ctx->ch_params); + cds_set_channel_params(mac_ctx->sap.SapDfsInfo.target_channel, + 0, &sap_ctx->ch_params); + /* * Fetch the number of SAP interfaces. If the number of sap Interface * more than one then we will make is_sap_ready_for_chnl_chng to true diff --git a/core/sap/src/sap_ch_select.c b/core/sap/src/sap_ch_select.c index a00c48db3a03..ceadb0bb37d8 100644 --- a/core/sap/src/sap_ch_select.c +++ b/core/sap/src/sap_ch_select.c @@ -1897,9 +1897,9 @@ bool sap_filter_over_lap_ch(ptSapContext pSapCtx, uint16_t chNum) */ static uint8_t sap_select_channel_no_scan_result(ptSapContext sap_ctx) { - enum channel_state ch_type; uint32_t start_ch_num, end_ch_num; #ifdef FEATURE_WLAN_CH_AVOID + enum channel_state ch_type; uint8_t i, first_safe_ch_in_range = SAP_CHANNEL_NOT_SELECTED; #endif start_ch_num = sap_ctx->acs_cfg->start_ch; diff --git a/core/sap/src/sap_fsm.c b/core/sap/src/sap_fsm.c index 99d634691299..0db2f1e618fc 100644 --- a/core/sap/src/sap_fsm.c +++ b/core/sap/src/sap_fsm.c @@ -3392,9 +3392,8 @@ static QDF_STATUS sap_fsm_state_ch_select(ptSapContext sap_ctx, sap_ctx->channel, ch); sap_ctx->channel = ch; - sme_set_ch_params(hal, sap_ctx->csr_roamProfile.phyMode, - sap_ctx->channel, sap_ctx->secondary_ch, - &sap_ctx->ch_params); + cds_set_channel_params(sap_ctx->channel, + sap_ctx->secondary_ch, &sap_ctx->ch_params); } if (sap_ctx->channel > 14 && (sap_ctx->csr_roamProfile.phyMode == eCSR_DOT11_MODE_11g || @@ -3499,13 +3498,12 @@ static QDF_STATUS sap_fsm_state_dfs_cac_wait(ptSapContext sap_ctx, * Radar found while performing channel availability * check, need to switch the channel again */ - eCsrPhyMode phymode = sap_ctx->csr_roamProfile.phyMode; QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, "ENTERTRED CAC WAIT STATE-->eSAP_DISCONNECTING\n"); if (mac_ctx->sap.SapDfsInfo.target_channel) { - sme_set_ch_params(hal, phymode, - mac_ctx->sap.SapDfsInfo.target_channel, 0, - &sap_ctx->ch_params); + cds_set_channel_params( + mac_ctx->sap.SapDfsInfo.target_channel, 0, + &sap_ctx->ch_params); } for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { diff --git a/core/sap/src/sap_module.c b/core/sap/src/sap_module.c index 89a59df2510c..b75f71e4d269 100644 --- a/core/sap/src/sap_module.c +++ b/core/sap/src/sap_module.c @@ -1565,13 +1565,8 @@ wlansap_set_channel_change_with_csa(void *p_cds_gctx, uint32_t targetChannel, new_ch_params.ch_width, target_bw); } - - sme_set_ch_params(hHal, - sapContext->csr_roamProfile.phyMode, - targetChannel, - 0, - &pMac->sap.SapDfsInfo.new_ch_params); - + cds_set_channel_params(targetChannel, + 0, &pMac->sap.SapDfsInfo.new_ch_params); /* * Set the CSA IE required flag. */ @@ -2303,7 +2298,7 @@ wlansap_channel_change_request(void *pSapCtx, uint8_t target_channel) * which will result in channel width changing dynamically. */ ch_params = &mac_ctx->sap.SapDfsInfo.new_ch_params; - sme_set_ch_params(hHal, phy_mode, target_channel, 0, ch_params); + cds_set_channel_params(target_channel, 0, ch_params); sapContext->ch_params.ch_width = ch_params->ch_width; /* Update the channel as this will be used to * send event to supplicant @@ -2445,10 +2440,8 @@ QDF_STATUS wlansap_dfs_send_csa_ie_request(void *pSapCtx) pMac->sap.SapDfsInfo.new_ch_params.ch_width = pMac->sap.SapDfsInfo.new_chanWidth; - - sme_set_ch_params(hHal, sapContext->csr_roamProfile.phyMode, - pMac->sap.SapDfsInfo.target_channel, 0, - &pMac->sap.SapDfsInfo.new_ch_params); + cds_set_channel_params(pMac->sap.SapDfsInfo.target_channel, + 0, &pMac->sap.SapDfsInfo.new_ch_params); QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, "%s: chan:%d req:%d width:%d off:%d", diff --git a/core/sme/inc/csr_api.h b/core/sme/inc/csr_api.h index 6ba1766660aa..ce4587162425 100644 --- a/core/sme/inc/csr_api.h +++ b/core/sme/inc/csr_api.h @@ -278,6 +278,7 @@ typedef struct tagCsrScanRequest { uint32_t idle_time; uint32_t uIEFieldLen; uint8_t *pIEField; + enum wmi_dwelltime_adaptive_mode scan_adaptive_dwell_mode; eCsrRequestType requestType; /* 11d scan or full scan */ bool p2pSearch; bool skipDfsChnlInP2pSearch; @@ -1203,6 +1204,7 @@ typedef struct tagCsrConfigParam { bool pno_channel_prediction; uint8_t top_k_num_of_channels; uint8_t stationary_thresh; + enum wmi_dwelltime_adaptive_mode pnoscan_adaptive_dwell_mode; uint32_t channel_prediction_full_scan; #endif bool early_stop_scan_enable; @@ -1244,6 +1246,8 @@ typedef struct tagCsrConfigParam { uint32_t edca_bk_aifs; uint32_t edca_be_aifs; bool enable_fatal_event; + enum wmi_dwelltime_adaptive_mode scan_adaptive_dwell_mode; + enum wmi_dwelltime_adaptive_mode roamscan_adaptive_dwell_mode; } tCsrConfigParam; /* Tush */ diff --git a/core/sme/inc/csr_internal.h b/core/sme/inc/csr_internal.h index daabe7656c25..8c3a658bebef 100644 --- a/core/sme/inc/csr_internal.h +++ b/core/sme/inc/csr_internal.h @@ -640,6 +640,7 @@ typedef struct tagCsrConfig { bool pno_channel_prediction; uint8_t top_k_num_of_channels; uint8_t stationary_thresh; + enum wmi_dwelltime_adaptive_mode pnoscan_adaptive_dwell_mode; uint32_t channel_prediction_full_scan; #endif bool early_stop_scan_enable; @@ -663,6 +664,8 @@ typedef struct tagCsrConfig { uint32_t edca_bk_aifs; uint32_t edca_be_aifs; bool enable_fatal_event; + enum wmi_dwelltime_adaptive_mode scan_adaptive_dwell_mode; + enum wmi_dwelltime_adaptive_mode roamscan_adaptive_dwell_mode; } tCsrConfig; typedef struct tagCsrChannelPowerInfo { diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index 1c133a8e5c83..6cebcff38770 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -690,13 +690,6 @@ QDF_STATUS sme_send_tdls_chan_switch_req( void sme_update_enable_ssr(tHalHandle hHal, bool enableSSR); QDF_STATUS sme_set_phy_mode(tHalHandle hHal, eCsrPhyMode phyMode); eCsrPhyMode sme_get_phy_mode(tHalHandle hHal); -/* - * SME API to determine the channel bonding mode - */ -QDF_STATUS sme_set_ch_params(tHalHandle hHal, eCsrPhyMode eCsrPhyMode, - uint8_t channel, uint8_t ht_sec_ch, - struct ch_params_s *ch_params); - QDF_STATUS sme_handoff_request(tHalHandle hHal, uint8_t sessionId, tCsrHandoffRequest *pHandoffInfo); QDF_STATUS sme_is_sta_p2p_client_connected(tHalHandle hHal); @@ -1126,6 +1119,8 @@ QDF_STATUS sme_bpf_offload_register_callback(tHalHandle hal, QDF_STATUS sme_get_bpf_offload_capabilities(tHalHandle hal); QDF_STATUS sme_set_bpf_instructions(tHalHandle hal, struct sir_bpf_set_offload *); - +uint32_t sme_get_wni_dot11_mode(tHalHandle hal); QDF_STATUS sme_create_mon_session(tHalHandle hal_handle, uint8_t *bssid); +QDF_STATUS sme_set_adaptive_dwelltime_config(tHalHandle hal, + struct adaptive_dwelltime_params *dwelltime_params); #endif /* #if !defined( __SME_API_H ) */ diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 3cc161dd5f60..011227bd8b6b 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -7187,6 +7187,8 @@ void sme_update_roam_pno_channel_prediction_config( csr_config->stationary_thresh; mac_ctx->roam.configParam.channel_prediction_full_scan = csr_config->channel_prediction_full_scan; + mac_ctx->roam.configParam.pnoscan_adaptive_dwell_mode = + csr_config->pnoscan_adaptive_dwell_mode; } else if (copy_from_to == ROAM_CONFIG_TO_SME_CONFIG) { csr_config->pno_channel_prediction = mac_ctx->roam.configParam.pno_channel_prediction; @@ -7196,6 +7198,8 @@ void sme_update_roam_pno_channel_prediction_config( mac_ctx->roam.configParam.stationary_thresh; csr_config->channel_prediction_full_scan = mac_ctx->roam.configParam.channel_prediction_full_scan; + csr_config->pnoscan_adaptive_dwell_mode = + mac_ctx->roam.configParam.pnoscan_adaptive_dwell_mode; } } @@ -10319,214 +10323,6 @@ QDF_STATUS sme_check_ch_in_band(tpAniSirGlobal mac_ctx, uint8_t start_ch, return QDF_STATUS_SUCCESS; } -void sme_set_160bw_params(tpAniSirGlobal mac_ctx, uint8_t channel, - struct ch_params_s *ch_params) -{ - uint8_t start_ch = 0; - QDF_STATUS status = QDF_STATUS_SUCCESS; - - if (channel >= 36 && channel <= 64) { - ch_params->center_freq_seg0 = 50; - start_ch = 36; - } else if (channel >= 100 && channel <= 128) { - ch_params->center_freq_seg0 = 114; - start_ch = 100; - } else { - ch_params->ch_width = CH_WIDTH_80MHZ; - } - - if (ch_params->ch_width == CH_WIDTH_160MHZ) - status = sme_check_ch_in_band(mac_ctx, start_ch, 8); - - if (QDF_STATUS_SUCCESS != status) - ch_params->ch_width = CH_WIDTH_80MHZ; -} - -void sme_set_80bw_params(tpAniSirGlobal mac_ctx, uint8_t channel, - struct ch_params_s *ch_params) -{ - uint8_t start_ch = 0; - QDF_STATUS status = QDF_STATUS_SUCCESS; - - if (channel >= 36 && channel <= 48) { - ch_params->center_freq_seg0 = 42; - start_ch = 36; - } else if (channel >= 52 && channel <= 64) { - ch_params->center_freq_seg0 = 58; - start_ch = 52; - } else if (channel >= 100 && channel <= 112) { - ch_params->center_freq_seg0 = 106; - start_ch = 100; - } else if (channel >= 116 && channel <= 128) { - ch_params->center_freq_seg0 = 122; - start_ch = 116; - } else if (channel >= 132 && channel <= 144) { - ch_params->center_freq_seg0 = 138; - start_ch = 132; - } else if (channel >= 149 && channel <= 161) { - ch_params->center_freq_seg0 = 155; - start_ch = 149; - } else { - ch_params->ch_width = CH_WIDTH_40MHZ; - } - - if (ch_params->ch_width == CH_WIDTH_80MHZ) - status = sme_check_ch_in_band(mac_ctx, start_ch, 4); - - if (QDF_STATUS_SUCCESS != status) - ch_params->ch_width = CH_WIDTH_40MHZ; -} - -void sme_set_40bw_params(tpAniSirGlobal mac_ctx, uint8_t channel, - struct ch_params_s *ch_params, uint8_t is_11ac_mode) -{ - uint8_t tmp; - uint8_t center_freq = 0; - uint8_t start_ch = 0; - QDF_STATUS status = QDF_STATUS_SUCCESS; - - if (channel == 165) { - ch_params->ch_width = CH_WIDTH_20MHZ; - ch_params->center_freq_seg0 = 0; - ch_params->sec_ch_offset = PHY_SINGLE_CHANNEL_CENTERED; - return; - } - tmp = channel % 2; - if ((channel - tmp) % 8) { - ch_params->sec_ch_offset = PHY_DOUBLE_CHANNEL_LOW_PRIMARY; - center_freq = channel + 2; - } else { - ch_params->sec_ch_offset = PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; - center_freq = channel - 2; - } - if ((!is_11ac_mode) || (is_11ac_mode && - (ch_params->ch_width == CH_WIDTH_40MHZ))) { - ch_params->ch_width = CH_WIDTH_40MHZ; - ch_params->center_freq_seg0 = center_freq; - - if (channel <= 40) - start_ch = 36; - else if (channel <= 48) - start_ch = 44; - else if (channel <= 56) - start_ch = 52; - else if (channel <= 64) - start_ch = 60; - else if (channel <= 104) - start_ch = 100; - else if (channel <= 112) - start_ch = 108; - else if (channel <= 120) - start_ch = 116; - else if (channel <= 128) - start_ch = 124; - else if (channel <= 136) - start_ch = 132; - else if (channel <= 144) - start_ch = 140; - else if (channel <= 153) - start_ch = 149; - else if (channel <= 161) - start_ch = 157; - - status = sme_check_ch_in_band(mac_ctx, start_ch, 2); - - if (QDF_STATUS_SUCCESS != status) { - ch_params->ch_width = CH_WIDTH_20MHZ; - ch_params->center_freq_seg0 = 0; - ch_params->sec_ch_offset = PHY_SINGLE_CHANNEL_CENTERED; - } - } -} - -/* - * SME API to determine the channel bonding mode - */ -QDF_STATUS sme_set_ch_params(tHalHandle hHal, eCsrPhyMode eCsrPhyMode, - uint8_t channel, uint8_t ht_sec_ch, - struct ch_params_s *ch_params) -{ - tpAniSirGlobal mac_ctx = PMAC_STRUCT(hHal); - int is_11ac_mode = CSR_IS_PHY_MODE_11ac(eCsrPhyMode); - - if (!CSR_IS_PHY_MODE_11n(eCsrPhyMode) || - ch_params->ch_width == CH_WIDTH_20MHZ || - QDF_STATUS_SUCCESS != csr_is_valid_channel(mac_ctx, channel)) { - QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, - "%s: Invalid Channel/phymode config: CB Mode disabled", - __func__); - ch_params->ch_width = CH_WIDTH_20MHZ; - ch_params->sec_ch_offset = PHY_SINGLE_CHANNEL_CENTERED; - if (channel <= 14) - mac_ctx->roam.configParam.channelBondingMode24GHz = - PHY_SINGLE_CHANNEL_CENTERED; - else - mac_ctx->roam.configParam.channelBondingMode5GHz = - PHY_SINGLE_CHANNEL_CENTERED; - return QDF_STATUS_SUCCESS; - } - - sms_log(mac_ctx, LOGW, "%s: channel - %d, vht channel width - %d", - __func__, channel, ch_params->ch_width); - - if (CDS_IS_CHANNEL_5GHZ(channel)) { - if (ch_params->ch_width == CH_WIDTH_160MHZ) - sme_set_160bw_params(mac_ctx, channel, ch_params); - if ((ch_params->ch_width == CH_WIDTH_80MHZ) || - (ch_params->ch_width == CH_WIDTH_80P80MHZ)) - sme_set_80bw_params(mac_ctx, channel, ch_params); - - sme_set_40bw_params(mac_ctx, channel, - ch_params, is_11ac_mode); - - mac_ctx->roam.configParam.channelBondingMode5GHz = - ch_params->sec_ch_offset; - } else if (CDS_IS_CHANNEL_24GHZ(channel)) { - if (channel >= 1 && channel < 5) { - ch_params->ch_width = CH_WIDTH_40MHZ; - ch_params->sec_ch_offset = - PHY_DOUBLE_CHANNEL_LOW_PRIMARY; - ch_params->center_freq_seg0 = channel + 2; - } else if (channel >= 5 && channel <= 9) { - ch_params->ch_width = CH_WIDTH_40MHZ; - if (0 != ht_sec_ch) { - if (ht_sec_ch > channel) { - ch_params->sec_ch_offset = - PHY_DOUBLE_CHANNEL_LOW_PRIMARY; - ch_params->center_freq_seg0 = - channel + 2; - } else { - ch_params->sec_ch_offset = - PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; - ch_params->center_freq_seg0 = - channel - 2; - } - } else { - /* in case ht_sec_ch is not set by ACS or - * calling function, set the secondary channel - * offset value to lower channel - */ - ch_params->sec_ch_offset = - PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; - ch_params->center_freq_seg0 = channel - 2; - } - } else if (channel > 9 && channel <= 13) { - ch_params->ch_width = CH_WIDTH_40MHZ; - ch_params->sec_ch_offset = - PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; - ch_params->center_freq_seg0 = channel - 2; - } else if (channel == 14) { - ch_params->ch_width = CH_WIDTH_20MHZ; - ch_params->sec_ch_offset = - PHY_SINGLE_CHANNEL_CENTERED; - ch_params->center_freq_seg0 = 0; - } - mac_ctx->roam.configParam.channelBondingMode24GHz = - ch_params->sec_ch_offset; - } - return QDF_STATUS_SUCCESS; -} - /*convert the ini value to the ENUM used in csr and MAC for CB state*/ ePhyChanBondState sme_get_cb_phy_state_from_cb_ini_value(uint32_t cb_ini_value) { @@ -15744,6 +15540,20 @@ QDF_STATUS sme_bpf_offload_register_callback(tHalHandle hal, } /** + * sme_get_wni_dot11_mode() - return configured wni dot11mode + * @hal: hal pointer + * + * Return: wni dot11 mode. + */ +uint32_t sme_get_wni_dot11_mode(tHalHandle hal) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + return csr_translate_to_wni_cfg_dot11_mode(mac_ctx, + mac_ctx->roam.configParam.uCfgDot11Mode); +} + +/** * sme_create_mon_session() - post message to create PE session for monitormode * operation * @hal_handle: Handle to the HAL @@ -15765,3 +15575,44 @@ QDF_STATUS sme_create_mon_session(tHalHandle hal_handle, tSirMacAddr bss_id) } return status; } + + +/** + * sme_set_adaptive_dwelltime_config() - Update Adaptive dwelltime configuration + * @hal: The handle returned by macOpen + * @params: adaptive_dwelltime_params config + * + * Return: QDF_STATUS if adaptive dwell time update + * configuration sucsess else failure status + */ +QDF_STATUS sme_set_adaptive_dwelltime_config(tHalHandle hal, + struct adaptive_dwelltime_params *params) +{ + cds_msg_t message; + QDF_STATUS status; + struct adaptive_dwelltime_params *dwelltime_params; + + dwelltime_params = qdf_mem_malloc(sizeof(*dwelltime_params)); + if (NULL == dwelltime_params) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: fail to alloc dwelltime_params", __func__); + return QDF_STATUS_E_NOMEM; + } + + dwelltime_params->is_enabled = params->is_enabled; + dwelltime_params->dwelltime_mode = params->dwelltime_mode; + dwelltime_params->lpf_weight = params->lpf_weight; + dwelltime_params->passive_mon_intval = params->passive_mon_intval; + dwelltime_params->wifi_act_threshold = params->wifi_act_threshold; + + message.type = WMA_SET_ADAPT_DWELLTIME_CONF_PARAMS; + message.bodyptr = dwelltime_params; + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post msg to WMA!", __func__); + + qdf_mem_free(dwelltime_params); + } + return status; +} diff --git a/core/sme/src/common/sme_power_save.c b/core/sme/src/common/sme_power_save.c index 9495600ab1fb..630122e4c132 100644 --- a/core/sme/src/common/sme_power_save.c +++ b/core/sme/src/common/sme_power_save.c @@ -710,6 +710,8 @@ void sme_set_pno_channel_prediction(tpSirPNOScanReq request_buf, mac_ctx->roam.configParam.stationary_thresh; request_buf->channel_prediction_full_scan = mac_ctx->roam.configParam.channel_prediction_full_scan; + request_buf->pnoscan_adaptive_dwell_mode = + mac_ctx->roam.configParam.pnoscan_adaptive_dwell_mode; QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, FL("channel_prediction: %d, top_k_num_of_channels: %d"), request_buf->pno_channel_prediction, @@ -799,6 +801,8 @@ QDF_STATUS sme_set_ps_preferred_network_list(tHalHandle hal_ctx, mac_ctx->roam.configParam.nPassiveMaxChnTimeConc; request_buf->passive_min_time = mac_ctx->roam.configParam.nPassiveMinChnTimeConc; + request_buf->pnoscan_adaptive_dwell_mode = + mac_ctx->roam.configParam.pnoscan_adaptive_dwell_mode; } else { request_buf->active_max_time = mac_ctx->roam.configParam.nActiveMaxChnTime; @@ -808,6 +812,8 @@ QDF_STATUS sme_set_ps_preferred_network_list(tHalHandle hal_ctx, mac_ctx->roam.configParam.nPassiveMaxChnTime; request_buf->passive_min_time = mac_ctx->roam.configParam.nPassiveMinChnTime; + request_buf->pnoscan_adaptive_dwell_mode = + mac_ctx->roam.configParam.pnoscan_adaptive_dwell_mode; } msg.type = WMA_SET_PNO_REQ; diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c index 2ebf78eed9aa..e2a35a7ca335 100644 --- a/core/sme/src/csr/csr_api_roam.c +++ b/core/sme/src/csr/csr_api_roam.c @@ -2338,6 +2338,11 @@ QDF_STATUS csr_change_default_config_param(tpAniSirGlobal pMac, pMac->roam.configParam.roam_params.traffic_threshold = pParam->roam_dense_traffic_thresh; + pMac->roam.configParam.scan_adaptive_dwell_mode = + pParam->scan_adaptive_dwell_mode; + pMac->roam.configParam.roamscan_adaptive_dwell_mode = + pParam->roamscan_adaptive_dwell_mode; + /* update p2p offload status */ pMac->pnoOffload = pParam->pnoOffload; @@ -2534,6 +2539,10 @@ QDF_STATUS csr_get_config_param(tpAniSirGlobal pMac, tCsrConfigParam *pParam) pParam->roam_dense_traffic_thresh = cfg_params->roam_params.traffic_threshold; + pParam->scan_adaptive_dwell_mode = + cfg_params->scan_adaptive_dwell_mode; + pParam->roamscan_adaptive_dwell_mode = + cfg_params->roamscan_adaptive_dwell_mode; pParam->conc_custom_rule1 = cfg_params->conc_custom_rule1; pParam->conc_custom_rule2 = cfg_params->conc_custom_rule2; pParam->is_sta_connection_in_5gz_enabled = @@ -3258,7 +3267,7 @@ QDF_STATUS csr_roam_call_callback(tpAniSirGlobal pMac, uint32_t sessionId, roamId, u1, u2); } /* - * EVENT_WLAN_STATUS: eCSR_ROAM_ASSOCIATION_COMPLETION, + * EVENT_WLAN_STATUS_V2: eCSR_ROAM_ASSOCIATION_COMPLETION, * eCSR_ROAM_LOSTLINK, * eCSR_ROAM_DISASSOCIATED, */ @@ -3292,13 +3301,14 @@ QDF_STATUS csr_roam_call_callback(tpAniSirGlobal pMac, uint32_t sessionId, (uint8_t) diag_enc_type_from_csr_type( pRoamInfo->u.pConnectedProfile->EncryptionType); qdf_mem_copy(connectionStatus.ssid, - pRoamInfo->u.pConnectedProfile->SSID.ssId, 6); + pRoamInfo->u.pConnectedProfile->SSID.ssId, + pRoamInfo->u.pConnectedProfile->SSID.length); connectionStatus.reason = eCSR_REASON_UNSPECIFIED; qdf_mem_copy(&pMac->sme.eventPayload, &connectionStatus, sizeof(host_event_wlan_status_payload_type)); WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus, - EVENT_WLAN_STATUS); + EVENT_WLAN_STATUS_V2); } if ((eCSR_ROAM_MIC_ERROR_IND == u1) || (eCSR_ROAM_RESULT_MIC_FAILURE == u2)) { @@ -3311,7 +3321,7 @@ QDF_STATUS csr_roam_call_callback(tpAniSirGlobal pMac, uint32_t sessionId, connectionStatus.eventId = eCSR_WLAN_STATUS_DISCONNECT; connectionStatus.reason = eCSR_REASON_MIC_ERROR; WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus, - EVENT_WLAN_STATUS); + EVENT_WLAN_STATUS_V2); } if (eCSR_ROAM_RESULT_FORCED == u2) { qdf_mem_copy(&connectionStatus, &pMac->sme.eventPayload, @@ -3323,7 +3333,7 @@ QDF_STATUS csr_roam_call_callback(tpAniSirGlobal pMac, uint32_t sessionId, connectionStatus.eventId = eCSR_WLAN_STATUS_DISCONNECT; connectionStatus.reason = eCSR_REASON_USER_REQUESTED; WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus, - EVENT_WLAN_STATUS); + EVENT_WLAN_STATUS_V2); } if (eCSR_ROAM_RESULT_DISASSOC_IND == u2) { qdf_mem_copy(&connectionStatus, &pMac->sme.eventPayload, @@ -3339,7 +3349,7 @@ QDF_STATUS csr_roam_call_callback(tpAniSirGlobal pMac, uint32_t sessionId, pRoamInfo->reasonCode; WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus, - EVENT_WLAN_STATUS); + EVENT_WLAN_STATUS_V2); } if (eCSR_ROAM_RESULT_DEAUTH_IND == u2) { qdf_mem_copy(&connectionStatus, &pMac->sme.eventPayload, @@ -3354,7 +3364,7 @@ QDF_STATUS csr_roam_call_callback(tpAniSirGlobal pMac, uint32_t sessionId, connectionStatus.reasonDisconnect = pRoamInfo->reasonCode; WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus, - EVENT_WLAN_STATUS); + EVENT_WLAN_STATUS_V2); } #endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ return status; @@ -9638,7 +9648,7 @@ QDF_STATUS csr_roam_process_set_key_command(tpAniSirGlobal pMac, tSmeCmd *pComma qdf_mem_set(&setKeyEvent, sizeof(host_event_wlan_security_payload_type), 0); if (qdf_is_macaddr_group(&pCommand->u.setKeyCmd.peermac)) { - setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_GTK_REQ; + setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_BCAST_REQ; setKeyEvent.encryptionModeMulticast = (uint8_t) diag_enc_type_from_csr_type(pCommand->u. setKeyCmd.encType); @@ -9647,7 +9657,8 @@ QDF_STATUS csr_roam_process_set_key_command(tpAniSirGlobal pMac, tSmeCmd *pComma connectedProfile. EncryptionType); } else { - setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_PTK_REQ; + setKeyEvent.eventId = + WLAN_SECURITY_EVENT_SET_UNICAST_REQ; setKeyEvent.encryptionModeUnicast = (uint8_t) diag_enc_type_from_csr_type(pCommand->u. setKeyCmd.encType); @@ -9709,10 +9720,10 @@ QDF_STATUS csr_roam_process_set_key_command(tpAniSirGlobal pMac, tSmeCmd *pComma if (qdf_is_macaddr_group( &pCommand->u.setKeyCmd.peermac)) { setKeyEvent.eventId = - WLAN_SECURITY_EVENT_SET_GTK_RSP; + WLAN_SECURITY_EVENT_SET_BCAST_RSP; } else { setKeyEvent.eventId = - WLAN_SECURITY_EVENT_SET_PTK_RSP; + WLAN_SECURITY_EVENT_SET_UNICAST_RSP; } setKeyEvent.status = WLAN_SECURITY_STATUS_FAILURE; WLAN_HOST_DIAG_EVENT_REPORT(&setKeyEvent, @@ -10842,9 +10853,11 @@ csr_roam_diag_set_ctx_rsp(tpAniSirGlobal mac_ctx, qdf_mem_set(&setKeyEvent, sizeof(host_event_wlan_security_payload_type), 0); if (qdf_is_macaddr_group(&pRsp->peer_macaddr)) - setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_GTK_RSP; + setKeyEvent.eventId = + WLAN_SECURITY_EVENT_SET_BCAST_RSP; else - setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_PTK_RSP; + setKeyEvent.eventId = + WLAN_SECURITY_EVENT_SET_UNICAST_RSP; setKeyEvent.encryptionModeMulticast = (uint8_t) diag_enc_type_from_csr_type( session->connectedProfile.mcEncryptionType); @@ -16695,6 +16708,8 @@ csr_create_roam_scan_offload_request(tpAniSirGlobal mac_ctx, req_buf->early_stop_scan_enable, req_buf->early_stop_scan_min_threshold, req_buf->early_stop_scan_max_threshold); + req_buf->roamscan_adaptive_dwell_mode = + mac_ctx->roam.configParam.roamscan_adaptive_dwell_mode; #ifdef WLAN_FEATURE_ROAM_OFFLOAD req_buf->RoamOffloadEnabled = csr_roamIsRoamOffloadEnabled(mac_ctx); req_buf->RoamKeyMgmtOffloadEnabled = session->RoamKeyMgmtOffloadEnabled; @@ -17942,7 +17957,7 @@ void csr_roaming_report_diag_event(tpAniSirGlobal mac_ctx, return; } roam_connection.reason = reason; - WLAN_HOST_DIAG_EVENT_REPORT(&roam_connection, EVENT_WLAN_STATUS); + WLAN_HOST_DIAG_EVENT_REPORT(&roam_connection, EVENT_WLAN_STATUS_V2); } #endif diff --git a/core/sme/src/csr/csr_api_scan.c b/core/sme/src/csr/csr_api_scan.c index 6a26de267058..498910c2a875 100644 --- a/core/sme/src/csr/csr_api_scan.c +++ b/core/sme/src/csr/csr_api_scan.c @@ -604,6 +604,7 @@ QDF_STATUS csr_scan_request(tpAniSirGlobal pMac, uint16_t sessionId, sms_log(pMac, LOG1, FL("updating dwell time for first scan %u"), scan_req->maxChnTime); } + scan_req->scan_adaptive_dwell_mode = cfg_prm->scan_adaptive_dwell_mode; status = csr_scan_copy_request(pMac, &scan_cmd->u.scanCmd.u.scanRequest, scan_req); @@ -4999,6 +5000,7 @@ QDF_STATUS csr_send_mb_scan_req(tpAniSirGlobal pMac, uint16_t sessionId, } } pMsg->scanType = scanType; + pMsg->scan_adaptive_dwell_mode = pScanReq->scan_adaptive_dwell_mode; pMsg->numSsid = (pScanReq->SSIDs.numOfSSIDs < SIR_SCAN_MAX_NUM_SSID) ? pScanReq->SSIDs.numOfSSIDs : SIR_SCAN_MAX_NUM_SSID; diff --git a/core/sme/src/csr/csr_inside_api.h b/core/sme/src/csr/csr_inside_api.h index 5537bf317f39..d2bb54b191eb 100644 --- a/core/sme/src/csr/csr_inside_api.h +++ b/core/sme/src/csr/csr_inside_api.h @@ -615,15 +615,16 @@ bool csr_is_profile_wapi(tCsrRoamProfile *pProfile); #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR /* Security */ -#define WLAN_SECURITY_EVENT_SET_PTK_REQ 1 -#define WLAN_SECURITY_EVENT_SET_PTK_RSP 2 -#define WLAN_SECURITY_EVENT_SET_GTK_REQ 3 -#define WLAN_SECURITY_EVENT_SET_GTK_RSP 4 #define WLAN_SECURITY_EVENT_REMOVE_KEY_REQ 5 #define WLAN_SECURITY_EVENT_REMOVE_KEY_RSP 6 #define WLAN_SECURITY_EVENT_PMKID_CANDIDATE_FOUND 7 #define WLAN_SECURITY_EVENT_PMKID_UPDATE 8 #define WLAN_SECURITY_EVENT_MIC_ERROR 9 +#define WLAN_SECURITY_EVENT_SET_UNICAST_REQ 10 +#define WLAN_SECURITY_EVENT_SET_UNICAST_RSP 11 +#define WLAN_SECURITY_EVENT_SET_BCAST_REQ 12 +#define WLAN_SECURITY_EVENT_SET_BCAST_RSP 13 + #define AUTH_OPEN 0 #define AUTH_SHARED 1 diff --git a/core/utils/epping/src/epping_main.c b/core/utils/epping/src/epping_main.c index 44ddc824b9ca..e7b6c6771492 100644 --- a/core/utils/epping/src/epping_main.c +++ b/core/utils/epping/src/epping_main.c @@ -110,6 +110,8 @@ int epping_open(void) void epping_disable(void) { epping_context_t *pEpping_ctx; + struct hif_opaque_softc *hif_ctx; + HTC_HANDLE htc_handle; pEpping_ctx = g_epping_ctx; if (pEpping_ctx == NULL) { @@ -117,15 +119,30 @@ void epping_disable(void) "%s: error: pEpping_ctx = NULL", __func__); return; } + if (pEpping_ctx->epping_adapter) { epping_destroy_adapter(pEpping_ctx->epping_adapter); pEpping_ctx->epping_adapter = NULL; } - hif_disable_isr(cds_get_context(QDF_MODULE_ID_HIF)); - hif_reset_soc(cds_get_context(QDF_MODULE_ID_HIF)); - htc_stop(cds_get_context(QDF_MODULE_ID_HTC)); + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (hif_ctx == NULL) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: error: hif_ctx = NULL", __func__); + return; + } + hif_disable_isr(hif_ctx); + hif_reset_soc(hif_ctx); + + htc_handle = cds_get_context(QDF_MODULE_ID_HTC); + if (htc_handle == NULL) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: error: htc_handle = NULL", __func__); + return; + } + htc_stop(htc_handle); epping_cookie_cleanup(pEpping_ctx); - htc_destroy(cds_get_context(QDF_MODULE_ID_HTC)); + htc_destroy(htc_handle); } /** diff --git a/core/utils/fwlog/dbglog_host.h b/core/utils/fwlog/dbglog_host.h index 3fb52acbca62..bbcf50a10b3c 100644 --- a/core/utils/fwlog/dbglog_host.h +++ b/core/utils/fwlog/dbglog_host.h @@ -116,6 +116,11 @@ dbglog_set_mod_enable_bitmap(wmi_unified_t wmi_handle, A_UINT32 *mod_enable_bitmap, A_UINT32 bitmap_len); +int +dbglog_parse_debug_logs(ol_scn_t scn, u_int8_t *datap, + u_int32_t len); + + /** Register the cnss_diag activate with the wlan driver */ int cnss_diag_activate_service(void); diff --git a/core/utils/host_diag_log/inc/host_diag_core_event.h b/core/utils/host_diag_log/inc/host_diag_core_event.h index c7cce228a80a..5e6d1ec62263 100644 --- a/core/utils/host_diag_log/inc/host_diag_core_event.h +++ b/core/utils/host_diag_log/inc/host_diag_core_event.h @@ -71,11 +71,11 @@ typedef struct { } host_event_wlan_security_payload_type; /*------------------------------------------------------------------------- - Event ID: EVENT_WLAN_STATUS + Event ID: EVENT_WLAN_STATUS_V2 ------------------------------------------------------------------------*/ typedef struct { uint8_t eventId; - uint8_t ssid[6]; + uint8_t ssid[32]; uint8_t bssType; uint8_t rssi; uint8_t channel; diff --git a/core/utils/host_diag_log/inc/host_diag_event_defs.h b/core/utils/host_diag_log/inc/host_diag_event_defs.h index 6b658ba37b81..31846008e73d 100644 --- a/core/utils/host_diag_log/inc/host_diag_event_defs.h +++ b/core/utils/host_diag_log/inc/host_diag_event_defs.h @@ -54,6 +54,7 @@ typedef enum { EVENT_WLAN_WAKE_LOCK = 0xAA2, /* 96 bytes payload */ EVENT_WLAN_BEACON_RECEIVED = 0xAA6, /* FW event: 2726 */ EVENT_WLAN_LOG_COMPLETE = 0xAA7, /* 16 bytes payload */ + EVENT_WLAN_STATUS_V2 = 0xAB3, EVENT_WLAN_TDLS_TEARDOWN = 0xAB5, EVENT_WLAN_TDLS_ENABLE_LINK = 0XAB6, EVENT_WLAN_SUSPEND_RESUME = 0xAB7, diff --git a/core/utils/logging/inc/wlan_logging_sock_svc.h b/core/utils/logging/inc/wlan_logging_sock_svc.h index d0b76d1aed9a..e2d0544f776a 100644 --- a/core/utils/logging/inc/wlan_logging_sock_svc.h +++ b/core/utils/logging/inc/wlan_logging_sock_svc.h @@ -43,10 +43,27 @@ int wlan_logging_sock_deinit_svc(void); int wlan_logging_sock_activate_svc(int log_fe_to_console, int num_buf); int wlan_logging_sock_deactivate_svc(void); int wlan_log_to_user(QDF_TRACE_LEVEL log_level, char *to_be_sent, int length); + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE void wlan_logging_set_per_pkt_stats(void); void wlan_logging_set_log_level(void); void wlan_logging_set_fw_flush_complete(void); void wlan_flush_host_logs_for_fatal(void); +#else +static inline void wlan_flush_host_logs_for_fatal(void) +{ +} +static inline void wlan_logging_set_log_level(void) +{ +} +static inline void wlan_logging_set_per_pkt_stats(void) +{ +} +static inline void wlan_logging_set_fw_flush_complete(void) +{ +} +#endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */ + #ifdef FEATURE_WLAN_DIAG_SUPPORT void wlan_report_log_completion(uint32_t is_fatal, uint32_t indicator, @@ -58,9 +75,6 @@ static inline void wlan_report_log_completion(uint32_t is_fatal, { return; } -static inline void wlan_flush_host_logs_for_fatal(void) -{ -} #endif /* FEATURE_WLAN_DIAG_SUPPORT */ #endif /* WLAN_LOGGING_SOCK_SVC_H */ diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h index ce07fd9bfca8..153cd68d7356 100644 --- a/core/wma/inc/wma.h +++ b/core/wma/inc/wma.h @@ -2060,3 +2060,5 @@ QDF_STATUS wma_set_bpf_instructions(tp_wma_handle wma, struct sir_bpf_set_offload *bpf_set_offload); #endif struct wma_ini_config *wma_get_ini_handle(tp_wma_handle wma_handle); +WLAN_PHY_MODE wma_chan_phy_mode(u8 chan, enum phy_ch_width chan_width, + u8 dot11_mode); diff --git a/core/wma/inc/wma_api.h b/core/wma/inc/wma_api.h index 0b72c211c025..6bd86bdc34e5 100644 --- a/core/wma/inc/wma_api.h +++ b/core/wma/inc/wma_api.h @@ -231,6 +231,8 @@ QDF_STATUS wma_remove_beacon_filter(WMA_HANDLE wma, QDF_STATUS wma_add_beacon_filter(WMA_HANDLE wma, struct beacon_filter_param *filter_params); +QDF_STATUS wma_send_adapt_dwelltime_params(WMA_HANDLE handle, + struct adaptive_dwelltime_params *dwelltime_params); #ifdef FEATURE_GREEN_AP void wma_setup_egap_support(struct wma_tgt_cfg *tgt_cfg, WMA_HANDLE handle); void wma_register_egap_event_handle(WMA_HANDLE handle); diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h index 1a403e63d9a8..3ea0fe060e0c 100644 --- a/core/wma/inc/wma_internal.h +++ b/core/wma/inc/wma_internal.h @@ -775,11 +775,20 @@ QDF_STATUS wma_tx_attach(tp_wma_handle wma_handle); QDF_STATUS wma_tx_detach(tp_wma_handle wma_handle); -#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || \ + defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(CONFIG_HL_SUPPORT) + int wma_mcc_vdev_tx_pause_evt_handler(void *handle, uint8_t *event, uint32_t len); #endif +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) +QDF_STATUS wma_process_init_bad_peer_tx_ctl_info(tp_wma_handle wma, + struct t_bad_peer_txtcl_config *config); + +#endif + + QDF_STATUS wma_process_init_thermal_info(tp_wma_handle wma, t_thermal_mgmt *pThermalParams); @@ -893,9 +902,6 @@ QDF_STATUS wma_process_lphb_conf_req(tp_wma_handle wma_handle, QDF_STATUS wma_process_dhcp_ind(tp_wma_handle wma_handle, tAniDHCPInd *ta_dhcp_ind); -WLAN_PHY_MODE wma_chan_phy_mode(u8 chan, enum phy_ch_width chan_width, - u8 dot11_mode); - QDF_STATUS wma_get_link_speed(WMA_HANDLE handle, tSirLinkSpeedInfo *pLinkSpeed); int wma_profile_data_report_event_handler(void *handle, uint8_t *event_buf, diff --git a/core/wma/inc/wma_types.h b/core/wma/inc/wma_types.h index 521d50b87e44..53af2d267a25 100644 --- a/core/wma/inc/wma_types.h +++ b/core/wma/inc/wma_types.h @@ -369,6 +369,8 @@ #define WMA_IBSS_CESIUM_ENABLE_IND SIR_HAL_IBSS_CESIUM_ENABLE_IND +#define WMA_INIT_BAD_PEER_TX_CTL_INFO_CMD SIR_HAL_BAD_PEER_TX_CTL_INI_CMD + #ifdef FEATURE_WLAN_TDLS #define WMA_UPDATE_FW_TDLS_STATE SIR_HAL_UPDATE_FW_TDLS_STATE #define WMA_UPDATE_TDLS_PEER_STATE SIR_HAL_UPDATE_TDLS_PEER_STATE @@ -468,6 +470,7 @@ #define WMA_SET_EGAP_CONF_PARAMS SIR_HAL_SET_EGAP_CONF_PARAMS #define WMA_ADD_BCN_FILTER_CMDID SIR_HAL_ADD_BCN_FILTER_CMDID #define WMA_REMOVE_BCN_FILTER_CMDID SIR_HAL_REMOVE_BCN_FILTER_CMDID +#define WMA_SET_ADAPT_DWELLTIME_CONF_PARAMS SIR_HAL_SET_ADAPT_DWELLTIME_PARAMS #define WDA_BPF_GET_CAPABILITIES_REQ SIR_HAL_BPF_GET_CAPABILITIES_REQ #define WDA_BPF_SET_INSTRUCTIONS_REQ SIR_HAL_BPF_SET_INSTRUCTIONS_REQ diff --git a/core/wma/src/wma_data.c b/core/wma/src/wma_data.c index 85b836bc5579..3f7aa65f05ca 100644 --- a/core/wma/src/wma_data.c +++ b/core/wma/src/wma_data.c @@ -44,8 +44,12 @@ #include "cfg_api.h" #include "ol_txrx_ctrl_api.h" #include <cdp_txrx_tx_throttle.h> +#if defined(CONFIG_HL_SUPPORT) +#include "wlan_tgt_def_config_hl.h" +#else #include "wlan_tgt_def_config.h" - +#endif +#include "ol_txrx.h" #include "qdf_nbuf.h" #include "qdf_types.h" #include "qdf_mem.h" @@ -72,6 +76,8 @@ #include "cdp_txrx_misc.h" #include <cdp_txrx_peer_ops.h> #include <cdp_txrx_cfg.h> +#include "cdp_txrx_stats.h" + typedef struct { int32_t rate; @@ -1165,7 +1171,8 @@ void wma_set_linkstate(tp_wma_handle wma, tpLinkStateParams params) params->status = true; WMA_LOGD("%s: state %d selfmac %pM", __func__, params->state, params->selfMacAddr); - if (params->state != eSIR_LINK_PREASSOC_STATE) { + if ((params->state != eSIR_LINK_PREASSOC_STATE) && + (params->state != eSIR_LINK_DOWN_STATE)) { WMA_LOGD("%s: unsupported link state %d", __func__, params->state); goto out; @@ -1564,7 +1571,9 @@ QDF_STATUS wma_tx_detach(tp_wma_handle wma_handle) return QDF_STATUS_SUCCESS; } -#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || \ + defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(CONFIG_HL_SUPPORT) + /** * wma_mcc_vdev_tx_pause_evt_handler() - pause event handler * @handle: wma handle @@ -1663,6 +1672,118 @@ int wma_mcc_vdev_tx_pause_evt_handler(void *handle, uint8_t *event, #endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + +/** + * wma_set_peer_rate_report_condition - + * this function set peer rate report + * condition info to firmware. + * @handle: Handle of WMA + * @config: Bad peer configuration from SIR module + * + * It is a wrapper function to sent WMI_PEER_SET_RATE_REPORT_CONDITION_CMDID + * to the firmare\target.If the command sent to firmware failed, free the + * buffer that allocated. + * + * Return: QDF_STATUS based on values sent to firmware + */ +static +QDF_STATUS wma_set_peer_rate_report_condition(WMA_HANDLE handle, + struct t_bad_peer_txtcl_config *config) +{ + tp_wma_handle wma_handle = (tp_wma_handle)handle; + struct wmi_peer_rate_report_params rate_report_params = {0}; + u_int32_t i, j; + + rate_report_params.rate_report_enable = config->enable; + rate_report_params.backoff_time = config->tgt_backoff; + rate_report_params.timer_period = config->tgt_report_prd; + for (i = 0; i < WMI_PEER_RATE_REPORT_COND_MAX_NUM; i++) { + rate_report_params.report_per_phy[i].cond_flags = + config->threshold[i].cond; + rate_report_params.report_per_phy[i].delta.delta_min = + config->threshold[i].delta; + rate_report_params.report_per_phy[i].delta.percent = + config->threshold[i].percentage; + for (j = 0; j < WMI_MAX_NUM_OF_RATE_THRESH; j++) { + rate_report_params.report_per_phy[i]. + report_rate_threshold[j] = + config->threshold[i].thresh[j]; + } + } + + return wmi_unified_peer_rate_report_cmd(wma_handle->wmi_handle, + &rate_report_params); +} + +/** + * wma_process_init_bad_peer_tx_ctl_info - + * this function to initialize peer rate report config info. + * @handle: Handle of WMA + * @config: Bad peer configuration from SIR module + * + * This function initializes the bad peer tx control data structure in WMA, + * sends down the initial configuration to the firmware and configures + * the peer status update seeting in the tx_rx module. + * + * Return: QDF_STATUS based on procedure status + */ + +QDF_STATUS wma_process_init_bad_peer_tx_ctl_info(tp_wma_handle wma, + struct t_bad_peer_txtcl_config *config) +{ + /* Parameter sanity check */ + ol_txrx_pdev_handle curr_pdev; + + if (NULL == wma || NULL == config) { + WMA_LOGE("%s Invalid input\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + curr_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (NULL == curr_pdev) { + WMA_LOGE("%s: Failed to get pdev\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGE("%s enable %d period %d txq limit %d\n", __func__, + config->enable, + config->period, + config->txq_limit); + + /* Only need to initialize the setting + when the feature is enabled */ + if (config->enable) { + int i = 0; + + ol_txrx_bad_peer_txctl_set_setting(curr_pdev, + config->enable, + config->period, + config->txq_limit); + + for (i = 0; i < WLAN_WMA_IEEE80211_MAX_LEVEL; i++) { + u_int32_t threshold, limit; + threshold = + config->threshold[i].thresh[0]; + limit = config->threshold[i].txlimit; + ol_txrx_bad_peer_txctl_update_threshold(curr_pdev, i, + threshold, + limit); + } + } + + return wma_set_peer_rate_report_condition(wma, config); +} +#else + +QDF_STATUS wma_process_init_bad_peer_tx_ctl_info(tp_wma_handle wma, + struct t_bad_peer_txtcl_config *config) +{ + return QDF_STATUS_E_FAILURE; +} +#endif /* defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) */ + + /** * wma_process_init_thermal_info() - initialize thermal info * @wma: Pointer to WMA handle @@ -2397,6 +2518,8 @@ QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen, return QDF_STATUS_E_FAILURE; } + ol_txrx_hl_tdls_flag_reset(txrx_vdev, false); + if (frmType >= TXRX_FRM_MAX) { WMA_LOGE("Invalid Frame Type Fail to send Frame"); return QDF_STATUS_E_FAILURE; @@ -2585,8 +2708,12 @@ QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen, wma_handle->last_umac_data_nbuf = skb; /* Send the Data frame to TxRx in Non Standard Path */ + ol_txrx_hl_tdls_flag_reset(txrx_vdev, tdlsFlag); + ret = ol_tx_non_std(txrx_vdev, OL_TX_SPEC_NO_FREE, skb); + ol_txrx_hl_tdls_flag_reset(txrx_vdev, false); + if (ret) { WMA_LOGE("TxRx Rejected. Fail to do Tx"); /* Call Download Cb so that umac can free the buffer */ @@ -2761,6 +2888,9 @@ QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen, * we didn't get Download Complete for almost * WMA_TX_FRAME_COMPLETE_TIMEOUT (1 sec) */ + + /* display scheduler stats */ + ol_txrx_display_stats(WLAN_SCHEDULER_STATS); } } else { /* diff --git a/core/wma/src/wma_dev_if.c b/core/wma/src/wma_dev_if.c index 6e69b56070ed..d7040f577fca 100644 --- a/core/wma/src/wma_dev_if.c +++ b/core/wma/src/wma_dev_if.c @@ -42,7 +42,6 @@ #include "wmi_unified.h" #include "wni_cfg.h" #include "cfg_api.h" -#include "wlan_tgt_def_config.h" #include "qdf_nbuf.h" #include "qdf_types.h" @@ -73,6 +72,8 @@ #include <cdp_txrx_peer_ops.h> #include <cdp_txrx_cfg.h> #include <cdp_txrx_cmn.h> +#include "ol_txrx.h" + #include "cds_concurrency.h" @@ -3488,6 +3489,7 @@ send_rsp: } #ifdef FEATURE_WLAN_TDLS + /** * wma_add_tdls_sta() - process add sta request in TDLS mode * @wma: wma handle @@ -3529,6 +3531,9 @@ static void wma_add_tdls_sta(tp_wma_handle wma, tpAddStaParams add_sta) if (0 == add_sta->updateSta) { /* its a add sta request * */ + + ol_txrx_copy_mac_addr_raw(vdev, add_sta->bssId); + WMA_LOGD("%s: addSta, calling wma_create_peer for %pM, vdev_id %hu", __func__, add_sta->staMac, add_sta->smesessionId); @@ -3549,6 +3554,9 @@ static void wma_add_tdls_sta(tp_wma_handle wma, tpAddStaParams add_sta) add_sta->status = QDF_STATUS_E_FAILURE; wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId, peer, false); + + ol_txrx_add_last_real_peer(pdev, vdev, &peer_id); + goto send_rsp; } @@ -3582,6 +3590,9 @@ static void wma_add_tdls_sta(tp_wma_handle wma, tpAddStaParams add_sta) add_sta->status = QDF_STATUS_E_FAILURE; wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId, peer, false); + + ol_txrx_add_last_real_peer(pdev, vdev, &peer_id); + goto send_rsp; } @@ -3616,6 +3627,8 @@ static void wma_add_tdls_sta(tp_wma_handle wma, tpAddStaParams add_sta) add_sta->status = QDF_STATUS_E_FAILURE; wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId, peer, false); + ol_txrx_add_last_real_peer(pdev, vdev, &peer_id); + goto send_rsp; } } diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c index 631224c48db3..d73b338bdb2b 100644 --- a/core/wma/src/wma_features.c +++ b/core/wma/src/wma_features.c @@ -45,7 +45,6 @@ #include "cfg_api.h" #include "ol_txrx_ctrl_api.h" #include <cdp_txrx_tx_delay.h> -#include "wlan_tgt_def_config.h" #include <cdp_txrx_peer_ops.h> #include "qdf_nbuf.h" @@ -70,6 +69,7 @@ #include "dfs.h" #include "radar_filters.h" #include "wma_internal.h" +#include "ol_txrx.h" #ifndef ARRAY_LENGTH #define ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0])) @@ -1174,6 +1174,33 @@ QDF_STATUS wma_remove_beacon_filter(WMA_HANDLE handle, return QDF_STATUS_SUCCESS; } +/** + * wma_send_adapt_dwelltime_params() - send adaptive dwelltime configuration + * params to firmware + * @wma_handle: wma handler + * @dwelltime_params: pointer to dwelltime_params + * + * Return: QDF_STATUS_SUCCESS on success and QDF failure reason code for failure + */ +QDF_STATUS wma_send_adapt_dwelltime_params(WMA_HANDLE handle, + struct adaptive_dwelltime_params *dwelltime_params) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + struct wmi_adaptive_dwelltime_params wmi_param = {0}; + int32_t err; + + wmi_param.is_enabled = dwelltime_params->is_enabled; + wmi_param.dwelltime_mode = dwelltime_params->dwelltime_mode; + wmi_param.lpf_weight = dwelltime_params->lpf_weight; + wmi_param.passive_mon_intval = dwelltime_params->passive_mon_intval; + wmi_param.wifi_act_threshold = dwelltime_params->wifi_act_threshold; + err = wmi_unified_send_adapt_dwelltime_params_cmd(wma_handle-> + wmi_handle, &wmi_param); + if (err) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} #ifdef FEATURE_GREEN_AP @@ -5303,20 +5330,33 @@ QDF_STATUS wma_process_del_periodic_tx_ptrn_ind(WMA_HANDLE handle, QDF_STATUS wma_stats_ext_req(void *wma_ptr, tpStatsExtRequest preq) { tp_wma_handle wma = (tp_wma_handle) wma_ptr; - struct stats_ext_params params = {0}; + struct stats_ext_params *params; + size_t params_len; + QDF_STATUS status; if (!wma) { WMA_LOGE("%s: wma handle is NULL", __func__); return QDF_STATUS_E_FAILURE; } - params.vdev_id = preq->vdev_id; - params.request_data_len = preq->request_data_len; - qdf_mem_copy(params.request_data, preq->request_data, - params.request_data_len); + params_len = sizeof(*params) + preq->request_data_len; + params = qdf_mem_malloc(params_len); - return wmi_unified_stats_ext_req_cmd(wma->wmi_handle, - ¶ms); + if (params == NULL) { + WMA_LOGE(FL("memory allocation failed")); + return QDF_STATUS_E_NOMEM; + } + + params->vdev_id = preq->vdev_id; + params->request_data_len = preq->request_data_len; + if (preq->request_data_len > 0) + qdf_mem_copy(params->request_data, preq->request_data, + params->request_data_len); + + status = wmi_unified_stats_ext_req_cmd(wma->wmi_handle, params); + qdf_mem_free(params); + + return status; } #endif /* WLAN_FEATURE_STATS_EXT */ @@ -5525,23 +5565,32 @@ QDF_STATUS wma_set_auto_shutdown_timer_req(tp_wma_handle wma_handle, QDF_STATUS wma_nan_req(void *wma_ptr, tpNanRequest nan_req) { tp_wma_handle wma_handle = (tp_wma_handle) wma_ptr; - struct nan_req_params params = {0}; + struct nan_req_params *params; + size_t params_len; + QDF_STATUS status; if (!wma_handle) { WMA_LOGE("%s: wma handle is NULL", __func__); return QDF_STATUS_E_FAILURE; } - if (!nan_req) { - WMA_LOGE("%s:nan req is not valid", __func__); - return QDF_STATUS_E_FAILURE; + + params_len = sizeof(*params) + nan_req->request_data_len; + params = qdf_mem_malloc(params_len); + + if (params == NULL) { + WMA_LOGE(FL("memory allocation failed")); + return QDF_STATUS_E_NOMEM; } - params.request_data_len = nan_req->request_data_len; - qdf_mem_copy(params.request_data, nan_req->request_data, - params.request_data_len); + params->request_data_len = nan_req->request_data_len; + if (params->request_data_len > 0) + qdf_mem_copy(params->request_data, nan_req->request_data, + params->request_data_len); - return wmi_unified_nan_req_cmd(wma_handle->wmi_handle, - ¶ms); + status = wmi_unified_nan_req_cmd(wma_handle->wmi_handle, params); + qdf_mem_free(params); + + return status; } #endif /* WLAN_FEATURE_NAN */ @@ -6400,6 +6449,7 @@ int wma_update_tdls_peer_state(WMA_HANDLE handle, uint8_t *peer_mac_addr; int ret = 0; uint32_t *ch_mhz; + bool restore_last_peer = false; if (!wma_handle || !wma_handle->wmi_handle) { WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); @@ -6451,6 +6501,7 @@ int wma_update_tdls_peer_state(WMA_HANDLE handle, goto end_tdls_peer_state; } peer_mac_addr = ol_txrx_peer_get_peer_mac_addr(peer); + restore_last_peer = is_vdev_restore_last_peer(peer); WMA_LOGD("%s: calling wma_remove_peer for peer " MAC_ADDRESS_STR " vdevId: %d", __func__, @@ -6458,6 +6509,8 @@ int wma_update_tdls_peer_state(WMA_HANDLE handle, peerStateParams->vdevId); wma_remove_peer(wma_handle, peer_mac_addr, peerStateParams->vdevId, peer, false); + ol_txrx_update_last_real_peer(pdev, peer, &peer_id, + restore_last_peer); } end_tdls_peer_state: diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index 2ae1f0f75233..da68b5df928c 100644 --- a/core/wma/src/wma_main.c +++ b/core/wma/src/wma_main.c @@ -44,8 +44,11 @@ #include "wmi_unified.h" #include "wni_cfg.h" #include "cfg_api.h" +#if defined(CONFIG_HL_SUPPORT) +#include "wlan_tgt_def_config_hl.h" +#else #include "wlan_tgt_def_config.h" - +#endif #include "qdf_nbuf.h" #include "qdf_types.h" #include "qdf_mem.h" @@ -2677,7 +2680,8 @@ QDF_STATUS wma_start(void *cds_ctx) } #endif /* FEATURE_WLAN_SCAN_PNO */ -#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || \ + defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(CONFIG_HL_SUPPORT) WMA_LOGE("MCC TX Pause Event Handler register"); status = wmi_unified_register_event_handler(wma_handle->wmi_handle, WMI_TX_PAUSE_EVENTID, @@ -4987,7 +4991,14 @@ QDF_STATUS wma_mc_process_msg(void *cds_context, cds_msg_t *msg) case WMA_SET_THERMAL_LEVEL: wma_process_set_thermal_level(wma_handle, msg->bodyval); break; - +#ifdef CONFIG_HL_SUPPORT + case WMA_INIT_BAD_PEER_TX_CTL_INFO_CMD: + wma_process_init_bad_peer_tx_ctl_info( + wma_handle, + (struct t_bad_peer_txtcl_config *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif case WMA_SET_P2P_GO_NOA_REQ: wma_process_set_p2pgo_noa_req(wma_handle, (tP2pPsParams *) msg->bodyptr); @@ -5316,6 +5327,11 @@ QDF_STATUS wma_mc_process_msg(void *cds_context, cds_msg_t *msg) (struct egap_conf_params *)msg->bodyptr); qdf_mem_free(msg->bodyptr); break; + case WMA_SET_ADAPT_DWELLTIME_CONF_PARAMS: + wma_send_adapt_dwelltime_params(wma_handle, + (struct adaptive_dwelltime_params *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; case WMA_HT40_OBSS_SCAN_IND: wma_send_ht40_obss_scanind(wma_handle, (struct obss_ht40_scanind *)msg->bodyptr); diff --git a/core/wma/src/wma_mgmt.c b/core/wma/src/wma_mgmt.c index 48ae5e971169..240fa73e1f81 100644 --- a/core/wma/src/wma_mgmt.c +++ b/core/wma/src/wma_mgmt.c @@ -43,7 +43,6 @@ #include "wmi_unified.h" #include "wni_cfg.h" #include "cfg_api.h" -#include "wlan_tgt_def_config.h" #include "qdf_nbuf.h" #include "qdf_types.h" @@ -743,6 +742,45 @@ static inline uint8_t wma_parse_mpdudensity(uint8_t mpdudensity) return 0; } +#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS) + +/** + * wma_unified_peer_state_update() - update peer state + * @pdev: pdev handle + * @sta_mac: pointer to sta mac addr + * @bss_addr: bss address + * @sta_type: sta entry type + * + * + * Return: None + */ +static void +wma_unified_peer_state_update( + struct ol_txrx_pdev_t *pdev, + uint8_t *sta_mac, + uint8_t *bss_addr, + uint8_t sta_type) +{ + if (STA_ENTRY_TDLS_PEER == sta_type) + ol_txrx_peer_state_update(pdev, sta_mac, + OL_TXRX_PEER_STATE_AUTH); + else + ol_txrx_peer_state_update(pdev, bss_addr, + OL_TXRX_PEER_STATE_AUTH); +} +#else + +static inline void +wma_unified_peer_state_update( + struct ol_txrx_pdev_t *pdev, + uint8_t *sta_mac, + uint8_t *bss_addr, + uint8_t sta_type) +{ + ol_txrx_peer_state_update(pdev, bss_addr, OL_TXRX_PEER_STATE_AUTH); +} +#endif + /** * wmi_unified_send_peer_assoc() - send peer assoc command to fw * @wma: wma handle @@ -963,7 +1001,8 @@ QDF_STATUS wma_send_peer_assoc(tp_wma_handle wma, if (params->wpa_rsn >> 1) cmd->peer_flags |= WMI_PEER_NEED_GTK_2_WAY; - ol_txrx_peer_state_update(pdev, params->bssId, OL_TXRX_PEER_STATE_AUTH); + wma_unified_peer_state_update(pdev, params->staMac, + params->bssId, params->staType); #ifdef FEATURE_WLAN_WAPI if (params->encryptType == eSIR_ED_WPI) { diff --git a/core/wma/src/wma_power.c b/core/wma/src/wma_power.c index bba2a4ed30cf..390d66acda2f 100644 --- a/core/wma/src/wma_power.c +++ b/core/wma/src/wma_power.c @@ -42,7 +42,6 @@ #include "wmi_unified.h" #include "wni_cfg.h" #include "cfg_api.h" -#include "wlan_tgt_def_config.h" #include "qdf_nbuf.h" #include "qdf_types.h" diff --git a/core/wma/src/wma_scan_roam.c b/core/wma/src/wma_scan_roam.c index 1d6b8c6ef717..6bab3975213e 100644 --- a/core/wma/src/wma_scan_roam.c +++ b/core/wma/src/wma_scan_roam.c @@ -43,7 +43,6 @@ #include "wmi_unified.h" #include "wni_cfg.h" #include "cfg_api.h" -#include "wlan_tgt_def_config.h" #include <cdp_txrx_peer_ops.h> #include <cdp_txrx_cfg.h> @@ -267,6 +266,9 @@ QDF_STATUS wma_get_buf_start_scan_cmd(tp_wma_handle wma_handle, else WMA_LOGD("OFDM_RATES not included in 11B mode"); + WMI_SCAN_SET_DWELL_MODE(cmd->scan_ctrl_flags, + scan_req->scan_adaptive_dwell_mode); + /* Do not combine multiple channels in a single burst. Come back * to home channel for data traffic after every foreign channel. * By default, prefer throughput performance over scan cycle time. @@ -1273,6 +1275,9 @@ void wma_roam_scan_fill_scan_params(tp_wma_handle wma_handle, WMI_SCAN_FLAG_FORCE_ACTIVE_ON_DFS; } } + WMI_SCAN_SET_DWELL_MODE(scan_params->scan_ctrl_flags, + roam_req->roamscan_adaptive_dwell_mode); + } else { /* roam_req = NULL during initial or pre-assoc invocation */ scan_params->dwell_time_active = @@ -2754,6 +2759,7 @@ QDF_STATUS wma_pno_start(tp_wma_handle wma, tpSirPNOScanReq pno) params->active_max_time = pno->active_max_time; params->passive_min_time = pno->passive_min_time; params->passive_max_time = pno->passive_max_time; + params->pnoscan_adaptive_dwell_mode = pno->pnoscan_adaptive_dwell_mode; #ifdef FEATURE_WLAN_SCAN_PNO params->pno_channel_prediction = pno->pno_channel_prediction; params->top_k_num_of_channels = pno->top_k_num_of_channels; @@ -4464,6 +4470,7 @@ QDF_STATUS wma_get_buf_extscan_start_cmd(tp_wma_handle wma_handle, WMI_SCAN_ADD_OFDM_RATES | WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ | WMI_SCAN_ADD_DS_IE_IN_PROBE_REQ; + cmd->scan_priority = WMI_SCAN_PRIORITY_HIGH; cmd->num_ssids = 0; cmd->num_bssid = 0; @@ -4622,6 +4629,8 @@ QDF_STATUS wma_start_extscan(tp_wma_handle wma, params->max_dwell_time_active = pstart->max_dwell_time_active; params->max_dwell_time_passive = pstart->max_dwell_time_passive; params->configuration_flags = pstart->configuration_flags; + params->extscan_adaptive_dwell_mode = + pstart->extscan_adaptive_dwell_mode; for (i = 0; i < WMI_WLAN_EXTSCAN_MAX_BUCKETS; i++) { params->buckets[i].bucket = pstart->buckets[i].bucket; params->buckets[i].band = @@ -5121,9 +5130,10 @@ QDF_STATUS wma_ipa_offload_enable_disable(tp_wma_handle wma, QDF_STATUS wma_set_epno_network_list(tp_wma_handle wma, struct wifi_epno_params *req) { - struct wifi_enhanched_pno_params params = {0}; + struct wifi_enhanched_pno_params *params; uint8_t i = 0; QDF_STATUS status; + size_t params_len; WMA_LOGD("wma_set_epno_network_list"); @@ -5137,23 +5147,32 @@ QDF_STATUS wma_set_epno_network_list(tp_wma_handle wma, return QDF_STATUS_E_NOSUPPORT; } - params.request_id = req->request_id; - params.session_id = req->session_id; - params.num_networks = req->num_networks; + params_len = sizeof(*params) + (req->num_networks * + sizeof(struct wifi_epno_network_params)); + params = qdf_mem_malloc(params_len); + if (params == NULL) { + WMA_LOGE(FL("memory allocation failed")); + return QDF_STATUS_E_NOMEM; + } + + params->request_id = req->request_id; + params->session_id = req->session_id; + params->num_networks = req->num_networks; for (i = 0; i < req->num_networks; i++) { - params.networks[i].rssi_threshold = + params->networks[i].rssi_threshold = req->networks[i].rssi_threshold; - params.networks[i].auth_bit_field = + params->networks[i].auth_bit_field = req->networks[i].auth_bit_field; - params.networks[i].flags = req->networks[i].flags; - params.networks[i].ssid.length = req->networks[i].ssid.length; - qdf_mem_copy(params.networks[i].ssid.mac_ssid, + params->networks[i].flags = req->networks[i].flags; + params->networks[i].ssid.length = req->networks[i].ssid.length; + qdf_mem_copy(params->networks[i].ssid.mac_ssid, req->networks[i].ssid.ssId, WMI_MAC_MAX_SSID_LENGTH); } - status = wmi_unified_set_epno_network_list_cmd(wma->wmi_handle, - ¶ms); + status = wmi_unified_set_epno_network_list_cmd(wma->wmi_handle, params); + qdf_mem_free(params); + if (QDF_IS_STATUS_ERROR(status)) return status; @@ -5176,9 +5195,10 @@ QDF_STATUS wma_set_epno_network_list(tp_wma_handle wma, QDF_STATUS wma_set_passpoint_network_list(tp_wma_handle wma, struct wifi_passpoint_req *req) { - struct wifi_passpoint_req_param params = {0}; + struct wifi_passpoint_req_param *params; int i = 0; QDF_STATUS status; + size_t params_len; WMA_LOGD("wma_set_passpoint_network_list"); @@ -5192,23 +5212,33 @@ QDF_STATUS wma_set_passpoint_network_list(tp_wma_handle wma, return QDF_STATUS_E_NOSUPPORT; } - params.request_id = req->request_id; - params.session_id = req->session_id; - params.num_networks = req->num_networks; + params_len = sizeof(*params) + (req->num_networks * + sizeof(struct wifi_passpoint_network_param)); + params = qdf_mem_malloc(params_len); + if (params == NULL) { + WMA_LOGE(FL("memory allocation failed")); + return QDF_STATUS_E_NOMEM; + } + + params->request_id = req->request_id; + params->session_id = req->session_id; + params->num_networks = req->num_networks; for (i = 0; i < req->num_networks; i++) { - params.networks[i].id = req->networks[i].id; - qdf_mem_copy(params.networks[i].realm, req->networks[i].realm, + params->networks[i].id = req->networks[i].id; + qdf_mem_copy(params->networks[i].realm, req->networks[i].realm, WMI_PASSPOINT_REALM_LEN); - qdf_mem_copy(params.networks[i].roaming_consortium_ids, + qdf_mem_copy(params->networks[i].roaming_consortium_ids, req->networks[i].roaming_consortium_ids, WMI_PASSPOINT_ROAMING_CONSORTIUM_ID_NUM * sizeof(int64_t)); - qdf_mem_copy(params.networks[i].plmn, req->networks[i].plmn, + qdf_mem_copy(params->networks[i].plmn, req->networks[i].plmn, WMI_PASSPOINT_PLMN_LEN); } status = wmi_unified_set_passpoint_network_list_cmd(wma->wmi_handle, - ¶ms); + params); + qdf_mem_free(params); + if (QDF_IS_STATUS_ERROR(status)) return status; @@ -5231,8 +5261,10 @@ QDF_STATUS wma_set_passpoint_network_list(tp_wma_handle wma, QDF_STATUS wma_reset_passpoint_network_list(tp_wma_handle wma, struct wifi_passpoint_req *req) { - struct wifi_passpoint_req_param params = {0}; + struct wifi_passpoint_req_param *params; int i = 0; + QDF_STATUS status; + size_t params_len; WMA_LOGD("wma_reset_passpoint_network_list"); @@ -5246,23 +5278,34 @@ QDF_STATUS wma_reset_passpoint_network_list(tp_wma_handle wma, return QDF_STATUS_E_NOSUPPORT; } - params.request_id = req->request_id; - params.session_id = req->session_id; - params.num_networks = req->num_networks; + params_len = sizeof(*params) + (req->num_networks * + sizeof(struct wifi_passpoint_network_param)); + params = qdf_mem_malloc(params_len); + if (params == NULL) { + WMA_LOGE(FL("memory allocation failed")); + return QDF_STATUS_E_NOMEM; + } + + params->request_id = req->request_id; + params->session_id = req->session_id; + params->num_networks = req->num_networks; for (i = 0; i < req->num_networks; i++) { - params.networks[i].id = req->networks[i].id; - qdf_mem_copy(params.networks[i].realm, req->networks[i].realm, + params->networks[i].id = req->networks[i].id; + qdf_mem_copy(params->networks[i].realm, req->networks[i].realm, WMI_PASSPOINT_REALM_LEN); - qdf_mem_copy(params.networks[i].roaming_consortium_ids, + qdf_mem_copy(params->networks[i].roaming_consortium_ids, req->networks[i].roaming_consortium_ids, WMI_PASSPOINT_ROAMING_CONSORTIUM_ID_NUM * sizeof(int64_t)); - qdf_mem_copy(params.networks[i].plmn, req->networks[i].plmn, + qdf_mem_copy(params->networks[i].plmn, req->networks[i].plmn, WMI_PASSPOINT_PLMN_LEN); } - return wmi_unified_reset_passpoint_network_list_cmd(wma->wmi_handle, - ¶ms); + status = wmi_unified_reset_passpoint_network_list_cmd(wma->wmi_handle, + params); + qdf_mem_free(params); + + return status; } /** diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c index 23abd574d9f5..d5cb5c1219d3 100644 --- a/core/wma/src/wma_utils.c +++ b/core/wma/src/wma_utils.c @@ -42,7 +42,6 @@ #include "wmi_unified.h" #include "wni_cfg.h" #include "cfg_api.h" -#include "wlan_tgt_def_config.h" #include "qdf_nbuf.h" #include "qdf_types.h" @@ -1142,7 +1141,7 @@ static void wma_update_vdev_stats(tp_wma_handle wma, } } - WMA_LOGD("vdev id %d beancon snr %d data snr %d", + WMA_LOGD("vdev id %d beacon snr %d data snr %d", vdev_stats->vdev_id, vdev_stats->vdev_snr.bcn_snr, vdev_stats->vdev_snr.dat_snr); @@ -1710,10 +1709,10 @@ WLAN_PHY_MODE wma_peer_phymode(tSirNwType nw_type, uint8_t sta_type, WMA_LOGE("80/160 MHz BW sent in 11G, configured 40MHz"); if (ch_width) phymode = (is_vht) ? - MODE_11AC_VHT40 : MODE_11NG_HT40; + MODE_11AC_VHT40_2G : MODE_11NG_HT40; else phymode = (is_vht) ? - MODE_11AC_VHT20 : MODE_11NG_HT20; + MODE_11AC_VHT20_2G : MODE_11NG_HT20; break; case eSIR_11A_NW_TYPE: if (!(is_ht || is_vht)) { diff --git a/target/inc/dbglog_id.h b/target/inc/dbglog_id.h index 917452931c58..65784369c0a9 100644 --- a/target/inc/dbglog_id.h +++ b/target/inc/dbglog_id.h @@ -616,7 +616,8 @@ extern "C" { #define SCAN_SM_CANCEL 46 #define SCAN_SM_PROBE_REQ_FRAME_SEND_FAILED 47 #define SCAN_SCH_BANNED_MODULE 48 -#define SCAN_DBGID_DEFINITION_END 49 +#define SCAN_SM_STATS_INFO 49 +#define SCAN_DBGID_DEFINITION_END 50 #define BEACON_EVENT_SWBA_SEND_FAILED 0 #define BEACON_EVENT_EARLY_RX_BMISS_STATUS 1 @@ -772,7 +773,9 @@ extern "C" { #define WAL_DBGID_TX_MGMT_FRAME_DESC_ALLOC_FAILED 87 #define WAL_DBGID_TX_MGMT_TID_STRUCT_NOT_FOUND 88 #define WAL_DBGID_TX_MGMT_ENQUEUE_FAILED 89 -#define WAL_DBGID_DEFINITION_END 90 +#define WAL_DBGID_TX_ARP 90 +#define WAL_DBGID_TX_DHCP 91 +#define WAL_DBGID_DEFINITION_END 92 #define ANI_DBGID_POLL 0 #define ANI_DBGID_CONTROL 1 @@ -804,7 +807,9 @@ extern "C" { #define OFFLOADMGR_DEREG_OFFLOAD_FAILED 6 #define OFFLOADMGR_ENTER_FAILED 7 #define OFFLOADMGR_EXIT_FAILED 8 -#define OFFLOADMGR_DBGID_DEFINITION_END 9 +#define OFFLOADMGR_GTK_FAILED 9 +#define OFFLOADMGR_GTK_REKEY_FAILED 10 +#define OFFLOADMGR_DBGID_DEFINITION_END 11 /*Resource Debug IDs*/ #define RESOURCE_DBGID_DEFINITION_START 0 diff --git a/target/inc/wlan_module_ids.h b/target/inc/wlan_module_ids.h index 29cf8c4b3e3e..0d4d2d6f4235 100644 --- a/target/inc/wlan_module_ids.h +++ b/target/inc/wlan_module_ids.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2011, 2014-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -31,75 +31,78 @@ /* Wlan module ids , global across all the modules */ typedef enum { WLAN_MODULE_ID_MIN = 0, - WLAN_MODULE_INF = WLAN_MODULE_ID_MIN, /* 0x00 */ - WLAN_MODULE_WMI, - WLAN_MODULE_STA_PWRSAVE, - WLAN_MODULE_WHAL, - WLAN_MODULE_COEX, - WLAN_MODULE_ROAM, - WLAN_MODULE_RESMGR_CHAN_MANAGER, - WLAN_MODULE_RESMGR, - WLAN_MODULE_VDEV_MGR, - WLAN_MODULE_SCAN, - WLAN_MODULE_RATECTRL, - WLAN_MODULE_AP_PWRSAVE, - WLAN_MODULE_BLOCKACK, - WLAN_MODULE_MGMT_TXRX, - WLAN_MODULE_DATA_TXRX, - WLAN_MODULE_HTT, - WLAN_MODULE_HOST, /* 0x10 */ - WLAN_MODULE_BEACON, - WLAN_MODULE_OFFLOAD, - WLAN_MODULE_WAL, - WAL_MODULE_DE, - WLAN_MODULE_PCIELP, - WLAN_MODULE_RTT, - WLAN_MODULE_RESOURCE, - WLAN_MODULE_DCS, - WLAN_MODULE_CACHEMGR, - WLAN_MODULE_ANI, - WLAN_MODULE_P2P, - WLAN_MODULE_CSA, - WLAN_MODULE_NLO, - WLAN_MODULE_CHATTER, - WLAN_MODULE_WOW, - WLAN_MODULE_WAL_VDEV, /* 0x20 */ - WLAN_MODULE_WAL_PDEV, - WLAN_MODULE_TEST, - WLAN_MODULE_STA_SMPS, - WLAN_MODULE_SWBMISS, - WLAN_MODULE_WMMAC, - WLAN_MODULE_TDLS, - WLAN_MODULE_HB, - WLAN_MODULE_TXBF, - WLAN_MODULE_BATCH_SCAN, - WLAN_MODULE_THERMAL_MGR, - WLAN_MODULE_PHYERR_DFS, - WLAN_MODULE_RMC, - WLAN_MODULE_STATS, - WLAN_MODULE_NAN, - WLAN_MODULE_IBSS_PWRSAVE, - WLAN_MODULE_HIF_UART, /* 0x30 */ - WLAN_MODULE_LPI, - WLAN_MODULE_EXTSCAN, - WLAN_MODULE_UNIT_TEST, - WLAN_MODULE_MLME, - WLAN_MODULE_SUPPL, - WLAN_MODULE_ERE, - WLAN_MODULE_OCB, - WLAN_MODULE_RSSI_MONITOR, - WLAN_MODULE_WPM, - WLAN_MODULE_CSS, - WLAN_MODULE_PPS, - WLAN_MODULE_SCAN_CH_PREDICT, - WLAN_MODULE_MAWC, - WLAN_MODULE_CMC_QMIC, - WLAN_MODULE_EGAP, /* 0x3f */ - WLAN_MODULE_NAN20, - WLAN_MODULE_QBOOST, + WLAN_MODULE_INF = WLAN_MODULE_ID_MIN, /* 0x0 */ + WLAN_MODULE_WMI, /* 0x1 */ + WLAN_MODULE_STA_PWRSAVE, /* 0x2 */ + WLAN_MODULE_WHAL, /* 0x3 */ + WLAN_MODULE_COEX, /* 0x4 */ + WLAN_MODULE_ROAM, /* 0x5 */ + WLAN_MODULE_RESMGR_CHAN_MANAGER, /* 0x6 */ + WLAN_MODULE_RESMGR, /* 0x7 */ + WLAN_MODULE_VDEV_MGR, /* 0x8 */ + WLAN_MODULE_SCAN, /* 0x9 */ + WLAN_MODULE_RATECTRL, /* 0xa */ + WLAN_MODULE_AP_PWRSAVE, /* 0xb */ + WLAN_MODULE_BLOCKACK, /* 0xc */ + WLAN_MODULE_MGMT_TXRX, /* 0xd */ + WLAN_MODULE_DATA_TXRX, /* 0xe */ + WLAN_MODULE_HTT, /* 0xf */ + WLAN_MODULE_HOST, /* 0x10 */ + WLAN_MODULE_BEACON, /* 0x11 */ + WLAN_MODULE_OFFLOAD, /* 0x12 */ + WLAN_MODULE_WAL, /* 0x13 */ + WAL_MODULE_DE, /* 0x14 */ + WLAN_MODULE_PCIELP, /* 0x15 */ + WLAN_MODULE_RTT, /* 0x16 */ + WLAN_MODULE_RESOURCE, /* 0x17 */ + WLAN_MODULE_DCS, /* 0x18 */ + WLAN_MODULE_CACHEMGR, /* 0x19 */ + WLAN_MODULE_ANI, /* 0x1a */ + WLAN_MODULE_P2P, /* 0x1b */ + WLAN_MODULE_CSA, /* 0x1c */ + WLAN_MODULE_NLO, /* 0x1d */ + WLAN_MODULE_CHATTER, /* 0x1e */ + WLAN_MODULE_WOW, /* 0x1f */ + WLAN_MODULE_WAL_VDEV, /* 0x20 */ + WLAN_MODULE_WAL_PDEV, /* 0x21 */ + WLAN_MODULE_TEST, /* 0x22 */ + WLAN_MODULE_STA_SMPS, /* 0x23 */ + WLAN_MODULE_SWBMISS, /* 0x24 */ + WLAN_MODULE_WMMAC, /* 0x25 */ + WLAN_MODULE_TDLS, /* 0x26 */ + WLAN_MODULE_HB, /* 0x27 */ + WLAN_MODULE_TXBF, /* 0x28 */ + WLAN_MODULE_BATCH_SCAN, /* 0x29 */ + WLAN_MODULE_THERMAL_MGR, /* 0x2a */ + WLAN_MODULE_PHYERR_DFS, /* 0x2b */ + WLAN_MODULE_RMC, /* 0x2c */ + WLAN_MODULE_STATS, /* 0x2d */ + WLAN_MODULE_NAN, /* 0x2e */ + WLAN_MODULE_IBSS_PWRSAVE, /* 0x2f */ + WLAN_MODULE_HIF_UART, /* 0x30 */ + WLAN_MODULE_LPI, /* 0x31 */ + WLAN_MODULE_EXTSCAN, /* 0x32 */ + WLAN_MODULE_UNIT_TEST, /* 0x33 */ + WLAN_MODULE_MLME, /* 0x34 */ + WLAN_MODULE_SUPPL, /* 0x35 */ + WLAN_MODULE_ERE, /* 0x36 */ + WLAN_MODULE_OCB, /* 0x37 */ + WLAN_MODULE_RSSI_MONITOR, /* 0x38 */ + WLAN_MODULE_WPM, /* 0x39 */ + WLAN_MODULE_CSS, /* 0x3a */ + WLAN_MODULE_PPS, /* 0x3b */ + WLAN_MODULE_SCAN_CH_PREDICT, /* 0x3c */ + WLAN_MODULE_MAWC, /* 0x3d */ + WLAN_MODULE_CMC_QMIC, /* 0x3e */ + WLAN_MODULE_EGAP, /* 0x3f */ + WLAN_MODULE_NAN20, /* 0x40 */ + WLAN_MODULE_QBOOST, /* 0x41 */ + WLAN_MODULE_P2P_LISTEN_OFFLOAD, /* 0x42 */ + WLAN_MODULE_HALPHY, /* 0x43 */ WLAN_MODULE_ID_MAX, WLAN_MODULE_ID_INVALID = WLAN_MODULE_ID_MAX, } WLAN_MODULE_ID; + #endif /* _WLAN_MODULE_IDS_H_ */ diff --git a/target/inc/wlan_tgt_def_config_hl.h b/target/inc/wlan_tgt_def_config_hl.h new file mode 100644 index 000000000000..92e81061493c --- /dev/null +++ b/target/inc/wlan_tgt_def_config_hl.h @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + + +#ifndef __WLAN_TGT_DEF_CONFIG_H__ +#define __WLAN_TGT_DEF_CONFIG_H__ + +/* + * TODO: please help to consider if we need a seperate config file from LL case. + */ + +/* + * set of default target config , that can be over written by platform + */ + +#ifdef QCA_SUPPORT_INTEGRATED_SOC +#define CFG_TGT_NUM_VDEV 3 /*STA, P2P device, P2P GO/Cli*/ +#else +/* + * default limit of VAPs per device. + */ +#define CFG_TGT_NUM_VDEV 3 +#endif +/* + * We would need 1 AST entry per peer. Scale it by a factor of 2 to minimize + * hash collisions. + * TODO: This scaling factor would be taken care inside the WAL in the future. + */ +#define CFG_TGT_NUM_PEER_AST 2 + +/* # of WDS entries to support. + */ +#define CFG_TGT_WDS_ENTRIES 0 + +/* MAC DMA burst size. 0: 128B - default, 1: 256B, 2: 64B + */ +#define CFG_TGT_DEFAULT_DMA_BURST_SIZE 0 + +/* Fixed delimiters to be inserted after every MPDU + */ +#define CFG_TGT_DEFAULT_MAC_AGGR_DELIM 0 + +/* + * This value may need to be fine tuned, but a constant value will + * probably always be appropriate; it is probably not necessary to + * determine this value dynamically. + */ +#define CFG_TGT_AST_SKID_LIMIT 6 +/* + * total number of peers per device. + * currently set to 8 to bring up IP3.9 for memory size problem + */ +#define CFG_TGT_NUM_PEERS 8 +/* + * max number of peers per device. + */ +#define CFG_TGT_NUM_PEERS_MAX 8 +/* + * In offload mode target supports features like WOW, chatter and other + * protocol offloads. In order to support them some functionalities like + * reorder buffering, PN checking need to be done in target. This determines + * maximum number of peers suported by target in offload mode + */ +#define CFG_TGT_NUM_OFFLOAD_PEERS 0 +/* + * Number of reorder buffers used in offload mode + */ +#define CFG_TGT_NUM_OFFLOAD_REORDER_BUFFS 0 +/* + * keys per peer node + */ +#define CFG_TGT_NUM_PEER_KEYS 2 +/* + * total number of TX/RX data TIDs + */ +#define CFG_TGT_NUM_TIDS (2 * (CFG_TGT_NUM_PEERS + \ + CFG_TGT_NUM_VDEV)) +/* + * max number of Tx TIDS + */ +#define CFG_TGT_NUM_TIDS_MAX (2 * (CFG_TGT_NUM_PEERS_MAX + \ + CFG_TGT_NUM_VDEV)) +/* + * number of multicast keys. + */ +#define CFG_TGT_NUM_MCAST_KEYS 8 +/* + * A value of 3 would probably suffice - one for the control stack, one for + * the data stack, and one for debugging. + * This value may need to be fine tuned, but a constant value will + * probably always be appropriate; it is probably not necessary to + * determine this value dynamically. + */ +#define CFG_TGT_NUM_PDEV_HANDLERS 8 +/* + * A value of 3 would probably suffice - one for the control stack, one for + * the data stack, and one for debugging. + * This value may need to be fine tuned, but a constant value will + * probably always be appropriate; it is probably not necessary to + * determine this value dynamically. + */ +#define CFG_TGT_NUM_VDEV_HANDLERS 4 +/* + * set this to 8: + * one for WAL interals (connection pause) + * one for the control stack, + * one for the data stack + * and one for debugging + * This value may need to be fine tuned, but a constant value will + * probably always be appropriate; it is probably not necessary to + * determine this value dynamically. + */ +#define CFG_TGT_NUM_HANDLERS 14 +/* + * set this to 3: one for the control stack, one for + * the data stack, and one for debugging. + * This value may need to be fine tuned, but a constant value will + * probably always be appropriate; it is probably not necessary to + * determine this value dynamically. + */ +#define CFG_TGT_NUM_PEER_HANDLERS 32 +/* + * set this to 0x7 (Peregrine = 3 chains). + * need to be set dynamically based on the HW capability. + * this is rome + */ +#define CFG_TGT_DEFAULT_TX_CHAIN_MASK 0x3 +/* + * set this to 0x7 (Peregrine = 3 chains). + * need to be set dynamically based on the HW capability. + * this is rome + */ +#define CFG_TGT_DEFAULT_RX_CHAIN_MASK 0x3 +/* 100 ms for video, best-effort, and background */ +#define CFG_TGT_RX_TIMEOUT_LO_PRI 100 +/* 40 ms for voice*/ +#define CFG_TGT_RX_TIMEOUT_HI_PRI 40 + +/* AR9888 unified is default in ethernet mode */ +#define CFG_TGT_RX_DECAP_MODE (0x2) +/* Decap to native Wifi header */ +#define CFG_TGT_RX_DECAP_MODE_NWIFI (0x1) + +/* Decap to raw mode header */ +#define CFG_TGT_RX_DECAP_MODE_RAW (0x0) + +/* maximum number of pending scan requests */ +#define CFG_TGT_DEFAULT_SCAN_MAX_REQS 0x4 + +/* maximum number of scan event handlers */ +#define CFG_TGT_DEFAULT_SCAN_MAX_HANDLERS 0x4 + +/* maximum number of VDEV that could use BMISS offload */ +#define CFG_TGT_DEFAULT_BMISS_OFFLOAD_MAX_VDEV 0x2 + +/* maximum number of VDEV offload Roaming to support */ +#define CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_VDEV 0x2 + +/* maximum number of AP profiles pushed to offload Roaming */ +#define CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_PROFILES 0x8 + +/* maximum number of VDEV offload GTK to support */ +#define CFG_TGT_DEFAULT_GTK_OFFLOAD_MAX_VDEV 0x2 +/* default: mcast->ucast disabled */ + +#define CFG_TGT_DEFAULT_NUM_MCAST_GROUPS 0 +#define CFG_TGT_DEFAULT_NUM_MCAST_TABLE_ELEMS 0 +#define CFG_TGT_DEFAULT_MCAST2UCAST_MODE 0 /* disabled */ + +/* + * Specify how much memory the target should allocate for a debug log of + * tx PPDU meta-information (how large the PPDU was, when it was sent, + * whether it was successful, etc.) + * The size of the log records is configurable, from a minimum of 28 bytes + * to a maximum of about 300 bytes. A typical configuration would result + * in each log record being about 124 bytes. + * Thus, 1KB of log space can hold about 30 small records, 3 large records, + * or about 8 typical-sized records. + */ +#define CFG_TGT_DEFAULT_TX_DBG_LOG_SIZE 1024 /* bytes */ + +/* target based fragment timeout and MPDU duplicate detection */ +#define CFG_TGT_DEFAULT_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK 0 +/* Default VoW configuration + */ +#define CFG_TGT_DEFAULT_VOW_CONFIG 0 + +/* + * total number of descriptors to use in the target + */ +#ifndef HIF_SDIO +#define CFG_TGT_NUM_MSDU_DESC (32) +#else +#define CFG_TGT_NUM_MSDU_DESC (0) +#endif +/* + * Maximum number of frag table entries + */ +#define CFG_TGT_MAX_FRAG_TABLE_ENTRIES 2 + +/* + * number of vdevs that can support tdls + */ +#define CFG_TGT_NUM_TDLS_VDEVS 1 + +/* + * number of peers that each Tdls vdev can track + */ +#define CFG_TGT_NUM_TDLS_CONN_TABLE_ENTRIES 32 +/* + * number of TDLS concurrent sleep STAs + */ +#define CFG_TGT_NUM_TDLS_CONC_SLEEP_STAS 1 + +/* + * number of TDLS concurrent buffer STAs + */ +#define CFG_TGT_NUM_TDLS_CONC_BUFFER_STAS 1 + +#define CFG_TGT_MAX_MULTICAST_FILTER_ENTRIES 5 +/* + * Maximum number of VDEV that beacon tx offload will support + */ +#ifdef HIF_SDIO +#define CFG_TGT_DEFAULT_BEACON_TX_OFFLOAD_MAX_VDEV 2 +#else +#define CFG_TGT_DEFAULT_BEACON_TX_OFFLOAD_MAX_VDEV 1 +#endif + +/* + * ht enable highest MCS by default + */ +#define CFG_TGT_DEFAULT_GTX_HT_MASK 0x8080 +/* + * vht enable highest MCS by default + */ +#define CFG_TGT_DEFAULT_GTX_VHT_MASK 0x80200 +/* + * resv for furture use, bit 30 is used for fix tpc, bit0-3 for Power save + * balance + */ +#define CFG_TGT_DEFAULT_GTX_USR_CFG 0xa +/* + * threshold to enable GTX + */ +#define CFG_TGT_DEFAULT_GTX_PER_THRESHOLD 3 +/* + * margin to move back when per > margin + threshold + */ +#define CFG_TGT_DEFAULT_GTX_PER_MARGIN 2 +/* + * step for every move + */ +#define CFG_TGT_DEFAULT_GTX_TPC_STEP 1 +/* + * lowest TPC + */ +#define CFG_TGT_DEFAULT_GTX_TPC_MIN 0 +/* + * enable all BW 20/40/80/160 + */ +#define CFG_TGT_DEFAULT_GTX_BW_MASK 0xf + +/* + * number of vdevs that can support OCB + */ +#define CFG_TGT_NUM_OCB_VDEVS 1 + +/* + * maximum number of channels that can do OCB + */ +#define CFG_TGT_NUM_OCB_CHANNELS 2 + +/* + * maximum number of channels in an OCB schedule + */ +#define CFG_TGT_NUM_OCB_SCHEDULES 2 + +#endif /*__WLAN_TGT_DEF_CONFIG_H__ */ diff --git a/target/inc/wmi_services.h b/target/inc/wmi_services.h index 281e232f0e31..3e31c74b9610 100644 --- a/target/inc/wmi_services.h +++ b/target/inc/wmi_services.h @@ -170,6 +170,17 @@ typedef enum { * bandwidth */ WMI_SERVICE_HALF_RATE_QUARTER_RATE_SUPPORT, + /* + * Support per-vdev specs of which rx frames + * to filter out + */ + WMI_SERVICE_VDEV_RX_FILTER, + WMI_SERVICE_P2P_LISTEN_OFFLOAD_SUPPORT, + /* + * FW supports marking the first data packet which wakes + * the host from suspend + */ + WMI_SERVICE_MARK_FIRST_WAKEUP_PACKET, WMI_MAX_SERVICE = 128 /* max service */ } WMI_SERVICE; diff --git a/target/inc/wmi_tlv_defs.h b/target/inc/wmi_tlv_defs.h index 469a0132b945..6d59985cb899 100644 --- a/target/inc/wmi_tlv_defs.h +++ b/target/inc/wmi_tlv_defs.h @@ -704,6 +704,16 @@ typedef enum { WMITLV_TAG_STRUC_wmi_scan_adaptive_dwell_config_fixed_param, WMITLV_TAG_STRUC_wmi_wow_set_action_wake_up_cmd_fixed_param, WMITLV_TAG_STRUC_wmi_ndp_end_rsp_per_ndi, + WMITLV_TAG_STRUC_wmi_peer_bwf_request_fixed_param, + WMITLV_TAG_STRUC_wmi_bwf_peer_info, + WMITLV_TAG_STRUC_wmi_dbglog_time_stamp_sync_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_place_holder_1, + WMITLV_TAG_STRUC_wmi_place_holder_2, + WMITLV_TAG_STRUC_wmi_per_chain_rssi_stats, + WMITLV_TAG_STRUC_wmi_rssi_stats, + WMITLV_TAG_STRUC_wmi_p2p_lo_start_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_p2p_lo_stop_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_p2p_lo_stopped_event_fixed_param, } WMITLV_TAG_ID; /* @@ -988,7 +998,12 @@ typedef enum { OP(WMI_PDEV_WAL_POWER_DEBUG_CMDID) \ OP(WMI_VDEV_WISA_CMDID) \ OP(WMI_SCAN_ADAPTIVE_DWELL_CONFIG_CMDID) \ - OP(WMI_WOW_SET_ACTION_WAKE_UP_CMDID) + OP(WMI_WOW_SET_ACTION_WAKE_UP_CMDID) \ + OP(WMI_PEER_BWF_REQUEST_CMDID) \ + OP(WMI_DBGLOG_TIME_STAMP_SYNC_CMDID) \ + OP(WMI_P2P_LISTEN_OFFLOAD_START_CMDID) \ + OP(WMI_P2P_LISTEN_OFFLOAD_STOP_CMDID) \ + /* add new CMD_LIST elements above this line */ /* * IMPORTANT: Please add _ALL_ WMI Events Here. @@ -1137,7 +1152,9 @@ typedef enum { OP(WMI_PDEV_SET_HW_MODE_RESP_EVENTID) \ OP(WMI_PDEV_HW_MODE_TRANSITION_EVENTID) \ OP(WMI_PDEV_SET_MAC_CONFIG_RESP_EVENTID) \ - OP(WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID) + OP(WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID) \ + OP(WMI_P2P_LISTEN_OFFLOAD_STOPPED_EVENTID) \ + /* add new EVT_LIST elements above this line */ /* TLV definitions of WMI commands */ @@ -1404,6 +1421,23 @@ WMITLV_CREATE_PARAM_STRUC(WMI_P2P_SET_VENDOR_IE_DATA_CMDID); WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_p2p_set_oppps_cmd_fixed_param, wmi_p2p_set_oppps_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) WMITLV_CREATE_PARAM_STRUC(WMI_P2P_SET_OPPPS_PARAM_CMDID); +/* P2P set listen offload start parameters Cmd */ +#define WMITLV_TABLE_WMI_P2P_LISTEN_OFFLOAD_START_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_p2p_lo_start_cmd_fixed_param, wmi_p2p_lo_start_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, device_types_data, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, prob_resp_data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_P2P_LISTEN_OFFLOAD_START_CMDID); + +/* P2P set listen offload stop parameters Cmd */ +#define WMITLV_TABLE_WMI_P2P_LISTEN_OFFLOAD_STOP_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_p2p_lo_stop_cmd_fixed_param, wmi_p2p_lo_stop_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_P2P_LISTEN_OFFLOAD_STOP_CMDID); + +/* P2P set listen offload stopped parameters Event */ +#define WMITLV_TABLE_WMI_P2P_LISTEN_OFFLOAD_STOPPED_EVENTID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_p2p_lo_stopped_event_fixed_param, wmi_p2p_lo_stopped_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_P2P_LISTEN_OFFLOAD_STOPPED_EVENTID); + /* Pdev set channel Cmd */ #define WMITLV_TABLE_WMI_PDEV_SET_CHANNEL_CMDID(id,op,buf,len) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_channel, wmi_channel, chan, WMITLV_SIZE_FIX) @@ -1763,6 +1797,11 @@ WMITLV_CREATE_PARAM_STRUC(WMI_FORCE_FW_HANG_CMDID); WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param, WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) WMITLV_CREATE_PARAM_STRUC(WMI_SET_MCASTBCAST_FILTER_CMDID); +/* Set dbglog time stamp sync cmd */ +#define WMITLV_TABLE_WMI_DBGLOG_TIME_STAMP_SYNC_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_dbglog_time_stamp_sync_cmd_fixed_param, WMI_DBGLOG_TIME_STAMP_SYNC_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_DBGLOG_TIME_STAMP_SYNC_CMDID); + /* GPIO config Cmd */ #define WMITLV_TABLE_WMI_GPIO_CONFIG_CMDID(id,op,buf,len) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_gpio_config_cmd_fixed_param, wmi_gpio_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) @@ -2832,6 +2871,12 @@ WMITLV_CREATE_PARAM_STRUC(WMI_SET_PERIODIC_CHANNEL_STATS_CONFIG_CMDID); WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, args, WMITLV_SIZE_VAR) WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_WAL_POWER_DEBUG_CMDID); +/* Bandwidth Fairness (BWF) peer configure commands */ +#define WMITLV_TABLE_WMI_PEER_BWF_REQUEST_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_peer_bwf_request_fixed_param, wmi_peer_bwf_request_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_STRUC, wmi_bwf_peer_info, peer_info, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_BWF_REQUEST_CMDID); + /************************** TLV definitions of WMI events *******************************/ @@ -3172,9 +3217,11 @@ WMITLV_CREATE_PARAM_STRUC(WMI_OEM_RESPONSE_EVENTID); WMITLV_CREATE_PARAM_STRUC(WMI_HOST_SWBA_EVENTID); /* Update stats Event */ -#define WMITLV_TABLE_WMI_UPDATE_STATS_EVENTID(id,op,buf,len) \ - WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_stats_event_fixed_param, wmi_stats_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ - WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +#define WMITLV_TABLE_WMI_UPDATE_STATS_EVENTID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_stats_event_fixed_param, wmi_stats_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_per_chain_rssi_stats, wmi_per_chain_rssi_stats, chain_stats, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_STRUC, wmi_rssi_stats, rssi_stats, WMITLV_SIZE_VAR) WMITLV_CREATE_PARAM_STRUC(WMI_UPDATE_STATS_EVENTID); /* For vdev based ht/vht info upload*/ @@ -3658,7 +3705,7 @@ WMITLV_CREATE_PARAM_STRUC(WMI_INST_RSSI_STATS_EVENTID); #define WMITLV_TABLE_WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID(id, op, buf, len) \ WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_tx_power_level_stats_evt_fixed_param, wmi_tx_power_level_stats_evt_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, tx_time_per_power_level, WMITLV_SIZE_VAR) -WMITLV_CREATE_PARAM_STRUC(WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID) +WMITLV_CREATE_PARAM_STRUC(WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID); #ifdef __cplusplus diff --git a/target/inc/wmi_unified.h b/target/inc/wmi_unified.h index 08372ac40467..a89ca17317e4 100644 --- a/target/inc/wmi_unified.h +++ b/target/inc/wmi_unified.h @@ -77,6 +77,7 @@ extern "C" { #define MAX_TX_RATE_VALUES 10 /*Max Tx Rates */ #define MAX_RSSI_VALUES 10 /*Max Rssi values */ +#define WMI_MAX_CHAINS 8 /* The WLAN_MAX_AC macro cannot be changed without breaking * WMI compatibility. @@ -180,60 +181,60 @@ typedef struct { typedef enum { /* 0 to 2 are reserved */ WMI_GRP_START = 0x3, - WMI_GRP_SCAN = WMI_GRP_START, - WMI_GRP_PDEV, - WMI_GRP_VDEV, - WMI_GRP_PEER, - WMI_GRP_MGMT, - WMI_GRP_BA_NEG, - WMI_GRP_STA_PS, - WMI_GRP_DFS, - WMI_GRP_ROAM, - WMI_GRP_OFL_SCAN, - WMI_GRP_P2P, - WMI_GRP_AP_PS, - WMI_GRP_RATE_CTRL, - WMI_GRP_PROFILE, - WMI_GRP_SUSPEND, - WMI_GRP_BCN_FILTER, - WMI_GRP_WOW, - WMI_GRP_RTT, - WMI_GRP_SPECTRAL, - WMI_GRP_STATS, - WMI_GRP_ARP_NS_OFL, - WMI_GRP_NLO_OFL, - WMI_GRP_GTK_OFL, - WMI_GRP_CSA_OFL, - WMI_GRP_CHATTER, - WMI_GRP_TID_ADDBA, - WMI_GRP_MISC, - WMI_GRP_GPIO, - WMI_GRP_FWTEST, - WMI_GRP_TDLS, - WMI_GRP_RESMGR, - WMI_GRP_STA_SMPS, - WMI_GRP_WLAN_HB, - WMI_GRP_RMC, - WMI_GRP_MHF_OFL, - WMI_GRP_LOCATION_SCAN, - WMI_GRP_OEM, - WMI_GRP_NAN, - WMI_GRP_COEX, - WMI_GRP_OBSS_OFL, - WMI_GRP_LPI, - WMI_GRP_EXTSCAN, - WMI_GRP_DHCP_OFL, - WMI_GRP_IPA, - WMI_GRP_MDNS_OFL, - WMI_GRP_SAP_OFL, - WMI_GRP_OCB, - WMI_GRP_SOC, - WMI_GRP_PKT_FILTER, - WMI_GRP_MAWC, - WMI_GRP_PMF_OFFLOAD, - WMI_GRP_BPF_OFFLOAD, /* Berkeley Packet Filter */ - WMI_GRP_NAN_DATA, - WMI_GRP_PROTOTYPE, + WMI_GRP_SCAN = WMI_GRP_START, /* 0x3 */ + WMI_GRP_PDEV, /* 0x4 */ + WMI_GRP_VDEV, /* 0x5 */ + WMI_GRP_PEER, /* 0x6 */ + WMI_GRP_MGMT, /* 0x7 */ + WMI_GRP_BA_NEG, /* 0x8 */ + WMI_GRP_STA_PS, /* 0x9 */ + WMI_GRP_DFS, /* 0xa */ + WMI_GRP_ROAM, /* 0xb */ + WMI_GRP_OFL_SCAN, /* 0xc */ + WMI_GRP_P2P, /* 0xd */ + WMI_GRP_AP_PS, /* 0xe */ + WMI_GRP_RATE_CTRL, /* 0xf */ + WMI_GRP_PROFILE, /* 0x10 */ + WMI_GRP_SUSPEND, /* 0x11 */ + WMI_GRP_BCN_FILTER, /* 0x12 */ + WMI_GRP_WOW, /* 0x13 */ + WMI_GRP_RTT, /* 0x14 */ + WMI_GRP_SPECTRAL, /* 0x15 */ + WMI_GRP_STATS, /* 0x16 */ + WMI_GRP_ARP_NS_OFL, /* 0x17 */ + WMI_GRP_NLO_OFL, /* 0x18 */ + WMI_GRP_GTK_OFL, /* 0x19 */ + WMI_GRP_CSA_OFL, /* 0x1a */ + WMI_GRP_CHATTER, /* 0x1b */ + WMI_GRP_TID_ADDBA, /* 0x1c */ + WMI_GRP_MISC, /* 0x1d */ + WMI_GRP_GPIO, /* 0x1e */ + WMI_GRP_FWTEST, /* 0x1f */ + WMI_GRP_TDLS, /* 0x20 */ + WMI_GRP_RESMGR, /* 0x21 */ + WMI_GRP_STA_SMPS, /* 0x22 */ + WMI_GRP_WLAN_HB, /* 0x23 */ + WMI_GRP_RMC, /* 0x24 */ + WMI_GRP_MHF_OFL, /* 0x25 */ + WMI_GRP_LOCATION_SCAN, /* 0x26 */ + WMI_GRP_OEM, /* 0x27 */ + WMI_GRP_NAN, /* 0x28 */ + WMI_GRP_COEX, /* 0x29 */ + WMI_GRP_OBSS_OFL, /* 0x2a */ + WMI_GRP_LPI, /* 0x2b */ + WMI_GRP_EXTSCAN, /* 0x2c */ + WMI_GRP_DHCP_OFL, /* 0x2d */ + WMI_GRP_IPA, /* 0x2e */ + WMI_GRP_MDNS_OFL, /* 0x2f */ + WMI_GRP_SAP_OFL, /* 0x30 */ + WMI_GRP_OCB, /* 0x31 */ + WMI_GRP_SOC, /* 0x32 */ + WMI_GRP_PKT_FILTER, /* 0x33 */ + WMI_GRP_MAWC, /* 0x34 */ + WMI_GRP_PMF_OFFLOAD, /* 0x35 */ + WMI_GRP_BPF_OFFLOAD, /* 0x36 Berkeley Packet Filter */ + WMI_GRP_NAN_DATA, /* 0x37 */ + WMI_GRP_PROTOTYPE, /* 0x38 */ } WMI_GRP_ID; #define WMI_CMD_GRP_START_ID(grp_id) (((grp_id) << 12) | 0x1) @@ -440,6 +441,8 @@ typedef enum { WMI_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID, /** ATF PEER REQUEST commands */ WMI_PEER_ATF_REQUEST_CMDID, + /** bandwidth fairness (BWF) peer configuration request command */ + WMI_PEER_BWF_REQUEST_CMDID, /* beacon/management specific commands */ @@ -558,6 +561,10 @@ typedef enum { WMI_P2P_DISC_OFFLOAD_PATTERN_CMDID, /** set OppPS related parameters **/ WMI_P2P_SET_OPPPS_PARAM_CMDID, + /** set listen offload start related parameters */ + WMI_P2P_LISTEN_OFFLOAD_START_CMDID, + /** set listen offload stop related parameters */ + WMI_P2P_LISTEN_OFFLOAD_STOP_CMDID, /** AP power save specific config */ /** set AP power save specific param */ @@ -782,6 +789,8 @@ typedef enum { WMI_CONFIG_ENHANCED_MCAST_FILTER_CMDID, /** Command to control WISA mode */ WMI_VDEV_WISA_CMDID, + /** set debug log time stamp sync up with host */ + WMI_DBGLOG_TIME_STAMP_SYNC_CMDID, /* GPIO Configuration */ WMI_GPIO_CONFIG_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_GPIO), @@ -1134,9 +1143,10 @@ typedef enum { /** P2P disc found */ WMI_P2P_DISC_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_P2P), - /*send noa info to host when noa is changed for beacon tx offload enable */ WMI_P2P_NOA_EVENTID, + /** send p2p listen offload stopped event with different reason */ + WMI_P2P_LISTEN_OFFLOAD_STOPPED_EVENTID, /** Send EGAP Info to host */ WMI_AP_PS_EGAP_INFO_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_AP_PS), @@ -1425,6 +1435,7 @@ typedef enum { #define WMI_CHAN_FLAG_QUARTER_RATE 15 /* Indicates quarter rate channel */ /* Enable radar event reporting for sec80 in VHT80p80 */ #define WMI_CHAN_FLAG_DFS_CFREQ2 16 +#define WMI_CHAN_FLAG_ALLOW_HE 17 /* HE (11ax) is allowed on this channel */ #define WMI_SET_CHANNEL_FLAG(pwmi_channel, flag) do { \ (pwmi_channel)->info |= (1 << flag); \ @@ -1604,12 +1615,12 @@ enum { * we pack PPET16 and PPT8 for four RU's in one element of array. * * ppet16_ppet8_ru3_ru0 array element 0 holds: - * | PPET16 | PPET8 | PPET16 | PPET8 | PPET16 | PPET8 | PPET16 | PPET8 | + * | PPET8 | PPET16 | PPET8 | PPET16 | PPET8 | PPET16 | PPET8 | PPET16 | *rsvd |NSS1,RU4|NSS1,RU4|NSS1,RU3|NSS1,RU3|NSS1,RU2|NSS1,RU2|NSS1,RU1|NSS1,RU1| *31:23| 22:20 | 19:17 | 17:15 | 14:12 | 11:9 | 8:6 | 5:3 | 2:0 | * * ppet16_ppet8_ru3_ru0 array element 1 holds: - * | PPET16 | PPET8 | PPET16 | PPET8 | PPET16 | PPET8 | PPET16 | PPET8 | + * | PPET8 | PPET16 | PPET8 | PPET16 | PPET8 | PPET16 | PPET8 | PPET16 | *rsvd |NSS2,RU4|NSS2,RU4|NSS2,RU3|NSS2,RU3|NSS2,RU2|NSS2,RU2|NSS2,RU1|NSS2,RU1| *31:23| 22:20 | 19:17 | 17:15 | 14:12 | 11:9 | 8:6 | 5:3 | 2:0 | * @@ -1620,22 +1631,22 @@ enum { * Note that in these macros, "ru" is one-based, not zero-based, while * nssm1 is zero-based. */ -#define WMI_SET_PPET8(ppet16_ppet8_ru3_ru0, ppet, ru, nssm1) \ +#define WMI_SET_PPET16(ppet16_ppet8_ru3_ru0, ppet, ru, nssm1) \ do { \ ppet16_ppet8_ru3_ru0[nssm1] &= ~(7 << (((ru-1)%4)*6)); \ ppet16_ppet8_ru3_ru0[nssm1] |= ((ppet&7) << (((ru-1)%4)*6)); \ } while (0) -#define WMI_GET_PPET8(ppet16_ppet8_ru3_ru0, ru, nssm1) \ +#define WMI_GET_PPET16(ppet16_ppet8_ru3_ru0, ru, nssm1) \ ((ppet16_ppet8_ru3_ru0[nssm1] >> (((ru-1)%4)*6))&7) -#define WMI_SET_PPET16(ppet16_ppet8_ru3_ru0, ppet, ru, nssm1) \ +#define WMI_SET_PPET8(ppet16_ppet8_ru3_ru0, ppet, ru, nssm1) \ do { \ ppet16_ppet8_ru3_ru0[nssm1] &= ~(7 << (((ru-1)%4)*6+3)); \ ppet16_ppet8_ru3_ru0[nssm1] |= ((ppet&7) << (((ru-1)%4)*6+3)); \ } while (0) -#define WMI_GET_PPET16(ppet16_ppet8_ru3_ru0, ru, nssm1) \ +#define WMI_GET_PPET8(ppet16_ppet8_ru3_ru0, ru, nssm1) \ ((ppet16_ppet8_ru3_ru0[nssm1] >> (((ru-1)%4)*6+3))&7) typedef struct _wmi_ppe_threshold { @@ -2854,8 +2865,6 @@ typedef struct { */ } wmi_mgmt_rx_hdr; -/* WMI PHY Error RX */ - typedef struct { /** TSF timestamp */ A_UINT32 tsf_timestamp; @@ -3740,6 +3749,32 @@ typedef struct { #define WMI_FAST_DIVERSITY_BIT_OFFSET 0 #define WMI_SLOW_DIVERSITY_BIT_OFFSET 1 +#define WMI_SLOW_DIVERSITY_CH0_WEIGHT_SHIFT 2 +#define WMI_SLOW_DIVERSITY_CH0_WEIGHT_MASK \ + (0xf << WMI_SLOW_DIVERSITY_CH0_WEIGHT_SHIFT) +#define WMI_SLOW_DIVERSITY_CH0_WEIGHT_GET_BITS(word32) \ + (((word32) & WMI_SLOW_DIVERSITY_CH0_WEIGHT_MASK) >> \ + WMI_SLOW_DIVERSITY_CH0_WEIGHT_SHIFT) +#define WMI_SLOW_DIVERSITY_CH0_WEIGHT_SET_BITS(word32, value) \ + do { \ + (word32) &= ~WMI_SLOW_DIVERSITY_CH0_WEIGHT_MASK; \ + (word32) |= ((value) << WMI_SLOW_DIVERSITY_CH0_WEIGHT_SHIFT) & \ + WMI_SLOW_DIVERSITY_CH0_WEIGHT_MASK; \ + } while (0) + +#define WMI_SLOW_DIVERSITY_CH1_WEIGHT_SHIFT 6 +#define WMI_SLOW_DIVERSITY_CH1_WEIGHT_MASK \ + (0xf << WMI_SLOW_DIVERSITY_CH1_WEIGHT_SHIFT) +#define WMI_SLOW_DIVERSITY_CH1_WEIGHT_GET_BITS(word32) \ + (((word32) & WMI_SLOW_DIVERSITY_CH1_WEIGHT_MASK) >> \ + WMI_SLOW_DIVERSITY_CH1_WEIGHT_SHIFT) +#define WMI_SLOW_DIVERSITY_CH1_WEIGHT_SET_BITS(word32, value) \ + do { \ + (word32) &= ~WMI_SLOW_DIVERSITY_CH1_WEIGHT_MASK; \ + (word32) |= ((value) << WMI_SLOW_DIVERSITY_CH1_WEIGHT_SHIFT) & \ + WMI_SLOW_DIVERSITY_CH1_WEIGHT_MASK; \ + } while (0) + typedef struct { /** TLV tag and len; tag equals * WMITLV_TAG_STRUC_wmi_pdev_set_antenna_diversity_cmd_fixed_param @@ -3753,10 +3788,16 @@ typedef struct { */ A_UINT32 pdev_id; }; - /** parameter */ - /** bit0 is for enable/disable FAST diversity, - * and bit1 is for enable/disable SLOW diversity, - * 0->disable, 1->enable + /* + * The following "value" field is divided into bit fields as follows: + * bits | purpose + * -----+--------------------------------------- + * 0 | enable/disable FAST diversity + * 1 | enable/disable SLOW diversity + * 5:2 | chain0 slow-diversity weighting factor + * 9:6 | chain1 slow-diversity weighting factor + * 31:10| currenty unused (set to 0x0) + * Refer to the above WMI_[FAST/SLOW]_DIVERSITY constants. */ A_UINT32 value; } wmi_pdev_set_antenna_diversity_cmd_fixed_param; @@ -4191,6 +4232,7 @@ typedef enum { WMI_REQUEST_VDEV_RATE_STAT = 0x20, WMI_REQUEST_INST_STAT = 0x40, WMI_REQUEST_MIB_STAT = 0x80, + WMI_REQUEST_RSSI_PER_CHAIN_STAT = 0x100, } wmi_stats_id; typedef struct { @@ -4896,6 +4938,28 @@ typedef struct { } wmi_mib_stats; typedef struct { + /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_rssi_stats */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_INT32 rssi_avg_beacon[WMI_MAX_CHAINS]; + A_INT32 rssi_avg_data[WMI_MAX_CHAINS]; + wmi_mac_addr peer_macaddr; +} wmi_rssi_stats; + +typedef struct { + /* + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_per_chain_rssi_stats + */ + A_UINT32 tlv_header; + A_UINT32 num_per_chain_rssi_stats; + /* + * This TLV is followed by another TLV of array of structs: + * wmi_rssi_stats rssi_stats[num_per_chain_rssi_stats]; + */ +} wmi_per_chain_rssi_stats; + +typedef struct { A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_create_cmd_fixed_param */ /** unique id identifying the VDEV, generated by the caller */ @@ -5489,13 +5553,78 @@ typedef enum { * to all vdevs sharing the TSF */ WMI_VDEV_PARAM_TSF_INCREMENT, + WMI_VDEV_PARAM_PLACE_HOLDER_1, + + /* + * Vdev level rx filter of from-ds / to-ds / no-ds / ta / ra frames. + * Used mainly for mesh-vap. + * The parameter value delivered with the RX_FILTER vdev param contains + * a bit-or mask of wmi_vdev_param_filter enum values. + */ + WMI_VDEV_PARAM_RX_FILTER, + /* vdev-specific mgmt tx power in dBm units (signed integer value) */ + WMI_VDEV_PARAM_MGMT_TX_POWER, + + /* + * Vdev level non aggregration/11g sw retry threshold. + * 0-disable, min:0, max:31, default:15 + */ + WMI_VDEV_PARAM_NON_AGG_SW_RETRY_TH, + /* + * Vdev level aggregration sw retry threshold. + * 0-disable, min:0, max:31, default:15 + */ + WMI_VDEV_PARAM_AGG_SW_RETRY_TH, + + /* + * === ADD NEW VDEV PARAM TYPES ABOVE THIS LINE === + * The below vdev param types are used for prototyping, and are + * prone to change. + */ + WMI_VDEV_PARAM_PROTOTYPE = 0x8000, + /* 11AX SPECIFIC defines */ + WMI_VDEV_PARAM_BSS_COLOR, + /* In case of AP this will enable / disable MU-MIMO mode */ + WMI_VDEV_PARAM_SET_UL_MU_MIMO, + /* + * set fragmentation level of the vdev's peers. + * Values can be WMI_HE_FRAG_SUPPORT_LEVEL0..WMI_HE_FRAG_SUPPORT_LEVEL3 + */ + WMI_VDEV_PARAM_SET_FRAG_LEVEL, + /* + * control different features of HEControl: + * Bit 0:- 1/0-> Enable/Disable transmssion of UL scheduling. + * Bit 1:- 1/0-> Enable / disable honoring of ROMI from a peer. + * Applicable in AP mode only. + */ + WMI_VDEV_PARAM_SET_HECONTROL, + /* + * enable / disable trigger access for a AP vdev's peers. + * For a STA mode vdev this will enable/disable triggered access + * and enable/disable Multi User mode of operation. + */ + WMI_VDEV_PARAM_SET_HEMU_MODE, + /* + * For Tx OFDMA this will set values of CP length or guard interval + * to be + * 0: Auto + * 1: 0.8 us + * 2: 1.6 us + * 3: 3.2 us + * Similar to Guard Interval + */ + WMI_VDEV_PARAM_TX_OFDMA_CPLEN, + /*=== END VDEV_PARAM_PROTOTYPE SECTION ===*/ } WMI_VDEV_PARAM; /* vdev capabilities bit mask */ -#define WMI_VDEV_BEACON_SUPPORT 0x1 +#define WMI_VDEV_BEACON_SUPPORT 0x1 #define WMI_VDEV_WDS_LRN_ENABLED 0x2 +#define WMI_VDEV_VOW_ENABLED 0x4 + #define WMI_VDEV_IS_BEACON_SUPPORTED(param) ((param) & WMI_VDEV_BEACON_SUPPORT) #define WMI_VDEV_IS_WDS_LRN_ENABLED(param) ((param) & WMI_VDEV_WDS_LRN_ENABLED) +#define WMI_VDEV_IS_VOW_ENABLED(param) ((param) & WMI_VDEV_VOW_ENABLED) /* TXBF capabilities masks */ #define WMI_TXBF_CONF_SU_TX_BFEE_S 0 @@ -5559,6 +5688,22 @@ typedef struct { A_UINT32 txbf_cap; } wmi_vdev_txbf_cap; +/* vdev rx filters (for mesh) */ +typedef enum { + /* Don't drop any frames - Default */ + WMI_VDEV_RX_ALLOW_ALL_FRAMES = 0x0, + /* Drop FromDS frames */ + WMI_VDEV_RX_FILTER_OUT_FROMDS = 0x1, + /* Drop ToDS frames */ + WMI_VDEV_RX_FILTER_OUT_TODS = 0x2, + /* Drop NODS frames */ + WMI_VDEV_RX_FILTER_OUT_NODS = 0x4, + /* Drop RA frames */ + WMI_VDEV_RX_FILTER_OUT_RA = 0x8, + /* Drop TA frames */ + WMI_VDEV_RX_FILTER_OUT_TA = 0x10, +} wmi_vdev_param_filter; + /* Length of ATIM Window in TU */ #define WMI_VDEV_PARAM_ATIM_WINDOW_LENGTH WMI_VDEV_PARAM_ATIM_WINDOW @@ -7253,7 +7398,7 @@ enum { WMI_AUTH_AUTO, /* Auto */ WMI_AUTH_WPA, /* WPA */ WMI_AUTH_RSNA, /* WPA2/RSNA */ - WMI_AUTH_CCKM, /* CCK */ + WMI_AUTH_CCKM, /* CCKM */ WMI_AUTH_WAPI, /* WAPI */ WMI_AUTH_AUTO_PSK, WMI_AUTH_WPA_PSK, @@ -7263,6 +7408,8 @@ enum { WMI_AUTH_FT_RSNA_PSK, WMI_AUTH_RSNA_PSK_SHA256, WMI_AUTH_RSNA_8021X_SHA256, + WMI_AUTH_CCKM_WPA, + WMI_AUTH_CCKM_RSNA, }; typedef struct { @@ -7955,6 +8102,72 @@ typedef struct { WMI_F_RMW((hdr)->oppps_attr, (v) & 0x7f, \ WMI_UNIFIED_OPPPS_ATTR_CTWIN); +typedef enum p2p_lo_start_ctrl_flags_e { + /* flush prob. req when host is awake */ + P2P_LO_START_CTRL_FLAG_FLUSH_LISTEN_RESULT = 1 << 0, +} p2p_lo_start_ctrl_flags; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 ctl_flags; /* refer to enum_p2p_lo_start_ctrl_flags_e */ + A_UINT32 channel; /* MHz */ + A_UINT32 period; /* ms */ + A_UINT32 interval; /* ms, interval should be larger than period */ + A_UINT32 count; /* 0 means forever */ + /* + * device_types_len specifies the number of bytes in the + * device_types_data[] byte-array TLV that follows this TLV. + * The data in device_types_data[] is in 8-byte elements, so + * device_types_len will be a multiple of 8. + */ + A_UINT32 device_types_len; + /* + * prob_resp_len specifies the number of bytes in the + * prob_resp_data[] byte-array TLV that follows this TLV. + */ + A_UINT32 prob_resp_len; + /* + * Two other TLVs follow this TLV: + * A_UINT8 device_types_data[device_types_len]; + * A_UINT8 prob_resp_data[prob_resp_len]; + * The information in device_types_data[] and prob_resp_data[] + * needs to be provided to the target in over-the-air byte order. + * On a big-endian host, if device_types_data and prob_resp_data + * are initially in the correct over-the-air byte order, + * the automatic byteswap for endianness-correction during WMI + * message download will mess up the byte order. + * Thus, a big-endian host needs to explicitly byte-swap the bytes + * within each quad-byte segment of device_types_data[] and + * prob_resp_data[], so that the automatic byte-swap applied during + * WMI download from a big-endian host to the little-endian target + * will restore device_types_data and prob_resp_data into the + * correct byte ordering. + */ +} wmi_p2p_lo_start_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; +} wmi_p2p_lo_stop_cmd_fixed_param; + +typedef enum p2p_lo_stopped_reason_e { + /* finished as scheduled */ + P2P_LO_STOPPED_REASON_COMPLETE = 0, + /* host stops it */ + P2P_LO_STOPPED_REASON_RECV_STOP_CMD, + /* invalid listen offload par */ + P2P_LO_STOPPED_REASON_INVALID_LO_PAR, + /* vdev cannot support it right now */ + P2P_LO_STOPPED_REASON_FW_NOT_SUPPORT, +} p2p_lo_stopped_reason; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 reason; /* refer to p2p_lo_stopped_reason_e */ +} wmi_p2p_lo_stopped_event_fixed_param; + typedef struct { A_UINT32 time32; /* upper 32 bits of time stamp */ A_UINT32 time0; /* lower 32 bits of time stamp */ @@ -8105,7 +8318,9 @@ typedef enum event_type_e { WOW_IOAC_SOCK_EVENT, WOW_NLO_SCAN_COMPLETE_EVENT, WOW_NAN_DATA_EVENT, - WOW_NAN_RTT_EVENT, + WOW_NAN_RTT_EVENT, /* DEPRECATED, UNUSED */ + /* reuse deprecated event value */ + WOW_OEM_RESPONSE_EVENT = WOW_NAN_RTT_EVENT, WOW_TDLS_CONN_TRACKER_EVENT, WOW_CRITICAL_LOG_EVENT, } WOW_WAKE_EVENT_TYPE; @@ -8153,9 +8368,12 @@ typedef enum wake_reason_e { WOW_REASON_ACTION_FRAME_RECV, WOW_REASON_BPF_ALLOW, WOW_REASON_NAN_DATA, - WOW_REASON_NAN_RTT, + WOW_REASON_NAN_RTT, /* DEPRECATED, UNUSED */ + /* reuse deprecated reason value */ + WOW_REASON_OEM_RESPONSE_EVENT = WOW_REASON_NAN_RTT, WOW_REASON_TDLS_CONN_TRACKER_EVENT, WOW_REASON_CRITICAL_LOG, + WOW_REASON_P2P_LISTEN_OFFLOAD, WOW_REASON_DEBUG_TEST = 0xFF, } WOW_WAKE_REASON_TYPE; @@ -8360,11 +8578,16 @@ typedef struct { A_UINT32 pattern_type; } WMI_WOW_DEL_PATTERN_CMD_fixed_param; +#define WMI_WOW_MAX_EVENT_BM_LEN 4 + typedef struct { A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_WOW_ADD_DEL_EVT_CMD_fixed_param */ A_UINT32 vdev_id; A_UINT32 is_add; - A_UINT32 event_bitmap; + union { + A_UINT32 event_bitmap; + A_UINT32 event_bitmaps[WMI_WOW_MAX_EVENT_BM_LEN]; + }; } WMI_WOW_ADD_DEL_EVT_CMD_fixed_param; /* @@ -9473,6 +9696,25 @@ typedef struct { wmi_mac_addr mcastbdcastaddr; } WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param; +/* WMI_DBGLOG_TIME_STAMP_SYNC_CMDID */ +typedef enum { + WMI_TIME_STAMP_SYNC_MODE_MS, /* millisecond units */ + WMI_TIME_STAMP_SYNC_MODE_US, /* microsecond units */ +} WMI_TIME_STAMP_SYNC_MODE; + +typedef struct { + /* + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dbglog_time_stamp_sync_cmd_fixed_param + */ + A_UINT32 tlv_header; + /* 0: millisec, 1: microsec (see WMI_TIME_STAMP_SYNC_MODE) */ + A_UINT32 mode; + A_UINT32 time_stamp_low; /* lower 32 bits of remote time stamp */ + A_UINT32 time_stamp_high; /* higher 32 bits of remote time stamp */ +} WMI_DBGLOG_TIME_STAMP_SYNC_CMD_fixed_param; + + /* GPIO Command and Event data structures */ /* WMI_GPIO_CONFIG_CMDID */ @@ -9617,6 +9859,11 @@ enum wmm_ac_downgrade_policy { WMM_AC_DOWNGRADE_INVALID, }; +/* WMM EDCA Params type */ +#define WMM_PARAM_TYPE_LEGACY 0 +/* Relaxed EDCA parameters for 11ax to be used in case of triggered access */ +#define WMM_PARAM_TYPE_11AX_EDCA 1 + typedef struct { A_UINT32 tlv_header; A_UINT32 cwmin; @@ -9631,6 +9878,7 @@ typedef struct { A_UINT32 tlv_header; A_UINT32 vdev_id; wmi_wmm_vparams wmm_params[4]; /* 0 be, 1 bk, 2 vi, 3 vo */ + A_UINT32 wmm_param_type; /* see WMM_PARAM_TYPE_xxx defs */ } wmi_vdev_set_wmm_params_cmd_fixed_param; typedef struct { @@ -11307,30 +11555,6 @@ typedef enum { #define wmi_ndp_cmd_rsp_status wmi_ndp_cmd_rsp_status_PROTOTYPE /** - * NDP command reason code - */ -typedef enum { - NDP_INVALID_VDEV_ID_PARAM = 0x00, - NDP_INVALID_SERVICE_INSTANCE_ID_PARAM = 0x01, - NDP_INVALID_PEER_DISC_MAC_ADDR_PARAM = 0x02, - NDP_INVALID_NDP_CFG_SECURITY_PARAM = 0x03, - NDP_INVALID_NDP_CFG_QOS_PARAM = 0x04, - NDP_INVALID_APP_INFO_LEN_PARAM = 0x05, - NDP_INVALID_NDP_INSTANCE_ID_PARAM = 0x06, - NDP_INVALID_RSP_CODE_PARAM = 0x07, - NDP_INVALID_CHANNEL_PARAM = 0x08, - NDP_INVALID_APP_INFO = 0x09, - NDP_INVALID_NDP_CFG = 0x0A, - NDP_INVALID_NDP_CFG_LEN_PARAM = 0x0B, - NDP_INVALID_NUM_NDP_INSTANCES_PARAM = 0x0C, - NDP_INVALID_NDP_END_REQ_LEN_PARAM = 0x0D, - NDP_INVALID_NDP_END_REQ = 0x0E, - NDP_REACHED_MAX_NDP_INSTANCES = 0x0F, -} wmi_ndp_cmd_reason_code_PROTOTYPE; - -#define wmi_ndp_cmd_reason_code wmi_ndp_cmd_reason_code_PROTOTYPE - -/** * Event response for wmi_ndp_initiator_req */ typedef struct { @@ -11345,7 +11569,6 @@ typedef struct { A_UINT32 transaction_id; /** Response status defined in wmi_ndp_cmd_rsp_status*/ A_UINT32 rsp_status; - /** Reason code defined in wmi_ndp_cmd_reason_code */ A_UINT32 reason_code; /* * Unique token Id generated on the initiator/responder @@ -11371,7 +11594,6 @@ typedef struct { A_UINT32 transaction_id; /** Response status defined in wmi_ndp_cmd_rsp_status*/ A_UINT32 rsp_status; - /** Reason code defined in wmi_ndp_cmd_reason_code */ A_UINT32 reason_code; /* * Unique token Id generated on the initiator/responder @@ -11430,7 +11652,6 @@ typedef struct { A_UINT32 transaction_id; /** Response status defined in wmi_ndp_cmd_rsp_status*/ A_UINT32 rsp_status; - /** Reason code defined in wmi_ndp_cmd_reason_code */ A_UINT32 reason_code; /** * TLV (tag length value ) parameters follow the ndp_end_rsp @@ -14343,7 +14564,7 @@ typedef struct { } wmi_roam_configure_mawc_cmd_fixed_param; #define WMI_PACKET_FILTER_COMPARE_DATA_LEN_DWORD 2 -#define WMI_PACKET_FILTER_MAX_CMP_PER_PACKET_FILTER 10 +#define WMI_PACKET_FILTER_MAX_CMP_PER_PACKET_FILTER 5 typedef enum { PACKET_FILTER_TYPE_INVALID = 0, @@ -14415,6 +14636,13 @@ typedef struct { A_UINT32 num_params; /* how many entries in paramsData are valid */ A_UINT32 coalesce_time; /* not currently used - fill with 0x0 */ WMI_PACKET_FILTER_PARAMS_TYPE paramsData[WMI_PACKET_FILTER_MAX_CMP_PER_PACKET_FILTER]; + /* + * deprecated0: + * This field simply provides filler space to retain the + * original message format while reducing + * WMI_PACKET_FILTER_MAX_CMP_PER_PACKET_FILTER from 10 to 5. + */ + WMI_PACKET_FILTER_PARAMS_TYPE deprecated0[5]; } WMI_PACKET_FILTER_CONFIG_CMD_fixed_param; /* enable / disable all filters within the specified vdev */ @@ -15031,10 +15259,44 @@ typedef struct { A_UINT32 num_peers; /* * Following this structure is the TLV: - * struct wmi_atf_peer_info peer_info[1]; + * struct wmi_atf_peer_info peer_info[num_peers]; */ } wmi_peer_atf_request_fixed_param; +/* Structure for Bandwidth Fairness peer information */ +typedef struct { + /* + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_bwf_peer_info + */ + A_UINT32 tlv_header; + wmi_mac_addr peer_macaddr; + /* BWF guaranteed_bandwidth for the peers in mbps */ + A_UINT32 bwf_guaranteed_bandwidth; + /* + * BWF Maximum airtime percentage that can be allocated + * to the peer to meet the guaranteed_bandwidth + */ + A_UINT32 bwf_max_airtime; + /* BWF priority of the peer to allocate the tokens dynamically */ + A_UINT32 bwf_peer_priority; +} wmi_bwf_peer_info; + +/* Structure for Bandwidth Fairness peer request */ +typedef struct { + /* + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_peer_bwf_request_fixed_param + */ + A_UINT32 tlv_header; + A_UINT32 num_peers; + /* + * Following this structure is the TLV: + * struct wmi_bwf_peer_info peer_info[num_peers]; + */ +} wmi_peer_bwf_request_fixed_param; + + /* Equal distribution of ATF air time within an VDEV. */ typedef struct { /* @@ -15346,6 +15608,10 @@ typedef enum wmi_coex_config_type { WMI_COEX_CONFIG_PAGE_STA_TDM = 2, /* config interval (arg1 BT, arg2 WLAN) for SAP + PAGE */ WMI_COEX_CONFIG_PAGE_SAP_TDM = 3, + /* config during WLAN connection */ + WMI_COEX_CONFIG_DURING_WLAN_CONN = 4, + /* config to enable/disable BTC */ + WMI_COEX_CONFIG_BTC_ENABLE = 5, } WMI_COEX_CONFIG_TYPE; typedef struct { @@ -15461,12 +15727,14 @@ typedef struct { A_UINT32 phy_id; /* supported modulations */ union { - A_UINT32 supports_11b:1, - supports_11g:1, - supports_11a:1, - supports_11n:1, - supports_11ac:1, - supports_11ax:1; + struct { + A_UINT32 supports_11b:1, + supports_11g:1, + supports_11a:1, + supports_11n:1, + supports_11ac:1, + supports_11ax:1; + }; A_UINT32 supported_flags; }; /* supported bands, enum WLAN_BAND_CAPABILITY */ diff --git a/target/inc/wmi_version.h b/target/inc/wmi_version.h index 9aedc072c3d8..039ae77ffc5e 100644 --- a/target/inc/wmi_version.h +++ b/target/inc/wmi_version.h @@ -36,7 +36,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility */ -#define __WMI_REVISION_ 241 +#define __WMI_REVISION_ 260 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work |
