summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xKbuild2
-rw-r--r--core/bmi/src/bmi_1.c9
-rw-r--r--core/bmi/src/ol_fw.c39
-rw-r--r--core/cds/inc/cds_regdomain.h3
-rw-r--r--core/cds/src/cds_concurrency.c13
-rw-r--r--core/cds/src/cds_reg_service.c54
-rw-r--r--core/cds/src/cds_sched.c2
-rw-r--r--core/dp/htt/htt.c294
-rw-r--r--core/dp/htt/htt_h2t.c198
-rw-r--r--core/dp/htt/htt_internal.h64
-rw-r--r--core/dp/htt/htt_rx.c529
-rw-r--r--core/dp/htt/htt_t2h.c128
-rw-r--r--core/dp/htt/htt_tx.c361
-rw-r--r--core/dp/htt/htt_types.h16
-rw-r--r--core/dp/ol/inc/ol_cfg.h5
-rw-r--r--core/dp/ol/inc/ol_htt_api.h19
-rw-r--r--core/dp/ol/inc/ol_htt_rx_api.h8
-rw-r--r--core/dp/ol/inc/ol_htt_tx_api.h10
-rw-r--r--core/dp/ol/inc/ol_txrx_ctrl_api.h157
-rw-r--r--core/dp/ol/inc/ol_txrx_dbg.h21
-rw-r--r--core/dp/ol/inc/ol_txrx_htt_api.h159
-rw-r--r--core/dp/txrx/ol_cfg.c55
-rw-r--r--core/dp/txrx/ol_rx.c4
-rw-r--r--core/dp/txrx/ol_rx_defrag.c233
-rw-r--r--core/dp/txrx/ol_rx_fwd.c15
-rw-r--r--core/dp/txrx/ol_tx.c508
-rw-r--r--core/dp/txrx/ol_tx.h29
-rw-r--r--core/dp/txrx/ol_tx_classify.c888
-rw-r--r--core/dp/txrx/ol_tx_classify.h103
-rw-r--r--core/dp/txrx/ol_tx_desc.c153
-rw-r--r--core/dp/txrx/ol_tx_desc.h25
-rw-r--r--core/dp/txrx/ol_tx_queue.c1842
-rw-r--r--core/dp/txrx/ol_tx_queue.h519
-rw-r--r--core/dp/txrx/ol_tx_sched.c1482
-rw-r--r--core/dp/txrx/ol_tx_sched.h198
-rw-r--r--core/dp/txrx/ol_tx_send.c350
-rw-r--r--core/dp/txrx/ol_tx_send.h9
-rw-r--r--core/dp/txrx/ol_txrx.c771
-rw-r--r--core/dp/txrx/ol_txrx.h90
-rw-r--r--core/dp/txrx/ol_txrx_internal.h45
-rw-r--r--core/dp/txrx/ol_txrx_peer_find.c68
-rw-r--r--core/dp/txrx/ol_txrx_types.h187
-rw-r--r--core/hdd/inc/wlan_hdd_cfg.h285
-rw-r--r--core/hdd/inc/wlan_hdd_oemdata.h3
-rw-r--r--core/hdd/src/wlan_hdd_assoc.c56
-rw-r--r--core/hdd/src/wlan_hdd_cfg.c98
-rw-r--r--core/hdd/src/wlan_hdd_cfg80211.c48
-rw-r--r--core/hdd/src/wlan_hdd_ext_scan.c3
-rw-r--r--core/hdd/src/wlan_hdd_hostapd.c34
-rw-r--r--core/hdd/src/wlan_hdd_main.c43
-rw-r--r--core/hdd/src/wlan_hdd_oemdata.c51
-rw-r--r--core/hdd/src/wlan_hdd_scan.c20
-rw-r--r--core/hdd/src/wlan_hdd_softap_tx_rx.c45
-rw-r--r--core/hdd/src/wlan_hdd_stats.c206
-rw-r--r--core/hdd/src/wlan_hdd_tx_rx.c49
-rw-r--r--core/hdd/src/wlan_hdd_wext.c2
-rw-r--r--core/mac/inc/qwlan_version.h4
-rw-r--r--core/mac/inc/sir_api.h55
-rw-r--r--core/mac/src/include/sir_params.h3
-rw-r--r--core/mac/src/pe/lim/lim_process_action_frame.c33
-rw-r--r--core/mac/src/pe/lim/lim_process_assoc_req_frame.c2
-rw-r--r--core/mac/src/pe/lim/lim_process_mlm_req_messages.c5
-rw-r--r--core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c2
-rw-r--r--core/mac/src/pe/lim/lim_process_sme_req_messages.c4
-rw-r--r--core/mac/src/pe/lim/lim_process_tdls.c110
-rw-r--r--core/mac/src/pe/lim/lim_scan_result_utils.c7
-rw-r--r--core/mac/src/pe/lim/lim_send_sme_rsp_messages.c16
-rw-r--r--core/sap/dfs/src/dfs_phyerr_tlv.c1
-rw-r--r--core/sap/src/sap_api_link_cntl.c19
-rw-r--r--core/sap/src/sap_ch_select.c2
-rw-r--r--core/sap/src/sap_fsm.c12
-rw-r--r--core/sap/src/sap_module.c17
-rw-r--r--core/sme/inc/csr_api.h4
-rw-r--r--core/sme/inc/csr_internal.h3
-rw-r--r--core/sme/inc/sme_api.h11
-rw-r--r--core/sme/src/common/sme_api.c267
-rw-r--r--core/sme/src/common/sme_power_save.c6
-rw-r--r--core/sme/src/csr/csr_api_roam.c43
-rw-r--r--core/sme/src/csr/csr_api_scan.c2
-rw-r--r--core/sme/src/csr/csr_inside_api.h9
-rw-r--r--core/utils/epping/src/epping_main.c25
-rw-r--r--core/utils/fwlog/dbglog_host.h5
-rw-r--r--core/utils/host_diag_log/inc/host_diag_core_event.h4
-rw-r--r--core/utils/host_diag_log/inc/host_diag_event_defs.h1
-rw-r--r--core/utils/logging/inc/wlan_logging_sock_svc.h20
-rw-r--r--core/wma/inc/wma.h2
-rw-r--r--core/wma/inc/wma_api.h2
-rw-r--r--core/wma/inc/wma_internal.h14
-rw-r--r--core/wma/inc/wma_types.h3
-rw-r--r--core/wma/src/wma_data.c136
-rw-r--r--core/wma/src/wma_dev_if.c15
-rw-r--r--core/wma/src/wma_features.c87
-rw-r--r--core/wma/src/wma_main.c22
-rw-r--r--core/wma/src/wma_mgmt.c43
-rw-r--r--core/wma/src/wma_power.c1
-rw-r--r--core/wma/src/wma_scan_roam.c105
-rw-r--r--core/wma/src/wma_utils.c7
-rw-r--r--target/inc/dbglog_id.h11
-rw-r--r--target/inc/wlan_module_ids.h137
-rw-r--r--target/inc/wlan_tgt_def_config_hl.h294
-rw-r--r--target/inc/wmi_services.h11
-rw-r--r--target/inc/wmi_tlv_defs.h59
-rw-r--r--target/inc/wmi_unified.h482
-rw-r--r--target/inc/wmi_version.h2
104 files changed, 11459 insertions, 1274 deletions
diff --git a/Kbuild b/Kbuild
index d57faa88bf0e..74e828b5ce7d 100755
--- a/Kbuild
+++ b/Kbuild
@@ -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, &notify_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, &notify_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, &notify_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, &notify_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, &notify_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,
- &params);
+ 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,
- &params);
+ 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,
- &params);
+ 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,
- &params);
+ 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,
- &params);
+ 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