diff options
70 files changed, 3749 insertions, 1923 deletions
@@ -59,6 +59,10 @@ ifeq ($(KERNEL_BUILD), 0) CONFIG_MOBILE_ROUTER := y endif + ifeq ($(CONFIG_ARCH_SDXPOORWILLS), y) + CONFIG_MOBILE_ROUTER := y + endif + # If platform wants to support two driver base on this source # code, below feature WLAN_DISABLE_EXPORT_SYMBOL needs to be # enabled, otherwise when loading the second the driver, diff --git a/core/cds/inc/cds_reg_service.h b/core/cds/inc/cds_reg_service.h index fb84151b01df..b64d9d6763c4 100644 --- a/core/cds/inc/cds_reg_service.h +++ b/core/cds/inc/cds_reg_service.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -385,6 +385,19 @@ QDF_STATUS cds_get_channel_list_with_power(struct channel_power *base_channels, uint8_t *num_base_channels); +/** + * cds_set_channel_state() - API to set the channel state in reg table + * @chan_num - input channel enum + * @state - state of the channel to be set + * CHANNEL_STATE_DISABLE + * CHANNEL_STATE_DFS + * CHANNEL_STATE_ENABLE + * CHANNEL_STATE_INVALID + * + * Return: Void + */ +void cds_set_channel_state(uint32_t chan_num, enum channel_state state); + enum channel_state cds_get_channel_state(uint32_t chan_num); QDF_STATUS cds_get_dfs_region(enum dfs_region *dfs_reg); QDF_STATUS cds_put_dfs_region(enum dfs_region dfs_reg); diff --git a/core/cds/src/cds_concurrency.c b/core/cds/src/cds_concurrency.c index 3d72e2bb57a1..54d9dea47abc 100644 --- a/core/cds/src/cds_concurrency.c +++ b/core/cds/src/cds_concurrency.c @@ -9907,6 +9907,8 @@ void cds_init_sap_mandatory_2g_chan(void) cds_err("Error in getting valid channels"); return; } + cds_ctx->sap_mandatory_channels_len = 0; + for (i = 0; i < len; i++) { if (CDS_IS_CHANNEL_24GHZ(chan_list[i])) { cds_err("Add chan %hu to mandatory list", chan_list[i]); diff --git a/core/cds/src/cds_reg_service.c b/core/cds/src/cds_reg_service.c index 4ebfe3cedafa..5e8cc979950d 100644 --- a/core/cds/src/cds_reg_service.c +++ b/core/cds/src/cds_reg_service.c @@ -224,6 +224,16 @@ enum channel_enum cds_get_channel_enum(uint32_t chan_num) return INVALID_CHANNEL; } +void cds_set_channel_state(uint32_t chan_num, enum channel_state state) +{ + enum channel_enum chan_enum; + + chan_enum = cds_get_channel_enum(chan_num); + if (INVALID_CHANNEL == chan_enum) + return; + + reg_channels[chan_enum].state = state; +} /** * cds_get_channel_state() - get the channel state diff --git a/core/cds/src/cds_sched.c b/core/cds/src/cds_sched.c index 221251ef625c..5b9a8d765a6a 100644 --- a/core/cds/src/cds_sched.c +++ b/core/cds/src/cds_sched.c @@ -358,7 +358,8 @@ __cds_cpu_hotplug_notify(struct notifier_block *block, if ((NULL == pSchedContext) || (NULL == pSchedContext->ol_rx_thread)) return NOTIFY_OK; - if (cds_is_load_or_unload_in_progress()) + if (cds_is_load_or_unload_in_progress() || + cds_is_module_stop_in_progress() || cds_is_driver_recovering()) return NOTIFY_OK; num_cpus = num_possible_cpus(); diff --git a/core/dp/htt/htt.c b/core/dp/htt/htt.c index ddad788f1d83..b717491c29c7 100644 --- a/core/dp/htt/htt.c +++ b/core/dp/htt/htt.c @@ -337,12 +337,20 @@ static int htt_htc_attach_all(struct htt_pdev_t *pdev) { if (htt_htc_attach(pdev, HTT_DATA_MSG_SVC)) - return -EIO; + goto flush_endpoint; + if (htt_htc_attach(pdev, HTT_DATA2_MSG_SVC)) - return -EIO; + goto flush_endpoint; + if (htt_htc_attach(pdev, HTT_DATA3_MSG_SVC)) - return -EIO; + goto flush_endpoint; + return 0; + +flush_endpoint: + htc_flush_endpoint(pdev->htc_pdev, ENDPOINT_0, HTC_TX_PACKET_TAG_ALL); + + return -EIO; } #else /** diff --git a/core/hdd/inc/wlan_hdd_assoc.h b/core/hdd/inc/wlan_hdd_assoc.h index 2e5248a6029b..f2e50a83a176 100644 --- a/core/hdd/inc/wlan_hdd_assoc.h +++ b/core/hdd/inc/wlan_hdd_assoc.h @@ -390,4 +390,26 @@ static inline void hdd_save_gtk_params(hdd_adapter_t *adapter, } #endif +/** + * hdd_copy_ht_caps()- copy ht caps info from roam info to + * hdd station context. + * @hdd_ht_cap: pointer to Source ht_cap info of type ieee80211_ht_cap + * @roam_ht_cap: pointer to roam ht_caps info + * + * Return: None + */ +void hdd_copy_ht_caps(struct ieee80211_ht_cap *hdd_ht_cap, + tDot11fIEHTCaps *roam_ht_cap); + +/** + * hdd_copy_vht_caps()- copy vht caps info from roam info to + * hdd station context. + * @hdd_vht_cap: pointer to Source vht_cap info of type ieee80211_vht_cap + * @roam_vht_cap: pointer to roam vht_caps info + * + * Return: None + */ +void hdd_copy_vht_caps(struct ieee80211_vht_cap *hdd_vht_cap, + tDot11fIEVHTCaps *roam_vht_cap); + #endif diff --git a/core/hdd/inc/wlan_hdd_cfg.h b/core/hdd/inc/wlan_hdd_cfg.h index 8e516c1a9631..69e5b1709847 100644 --- a/core/hdd/inc/wlan_hdd_cfg.h +++ b/core/hdd/inc/wlan_hdd_cfg.h @@ -2102,6 +2102,28 @@ enum hdd_dot11_mode { /* * <ini> + * enable_ftopen - enable/disable FT open feature + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This INI is used to enable/disable FT open feature + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * </ini> + */ +#define CFG_ROAM_FT_OPEN_ENABLE_NAME "enable_ftopen" +#define CFG_ROAM_FT_OPEN_ENABLE_MIN (0) +#define CFG_ROAM_FT_OPEN_ENABLE_MAX (1) +#define CFG_ROAM_FT_OPEN_ENABLE_DEFAULT (1) + +/* + * <ini> * groam_dense_min_aps - Sets minimum number of AP for dense roam * @Min: 1 * @Max: 5 @@ -5115,6 +5137,27 @@ enum hdd_link_speed_rpt_type { /* * <ini> + * enable_vht20_mcs9 - Enables VHT MCS9 in 20M BW operation + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * </ini> + */ + +#define CFG_ENABLE_VHT20_MCS9 "enable_vht20_mcs9" +#define CFG_ENABLE_VHT20_MCS9_MIN (0) +#define CFG_ENABLE_VHT20_MCS9_MAX (1) +#define CFG_ENABLE_VHT20_MCS9_DEFAULT (1) + +/* + * <ini> * gEnable2x2 - Enables/disables VHT Tx/Rx MCS values for 2x2 * @Min: 0 * @Max: 1 @@ -10847,7 +10890,7 @@ enum restart_beaconing_on_ch_avoid_rule { * gAutoBmpsTimerValue - Set Auto BMPS Timer value * @Min: 0 * @Max: 120 - * @Default: 0 + * @Default: 5 * * This ini is used to set Auto BMPS Timer value in seconds * @@ -10862,7 +10905,7 @@ enum restart_beaconing_on_ch_avoid_rule { #define CFG_AUTO_PS_ENABLE_TIMER_NAME "gAutoBmpsTimerValue" #define CFG_AUTO_PS_ENABLE_TIMER_MIN (0) #define CFG_AUTO_PS_ENABLE_TIMER_MAX (120) -#define CFG_AUTO_PS_ENABLE_TIMER_DEFAULT (0) +#define CFG_AUTO_PS_ENABLE_TIMER_DEFAULT (5) #ifdef WLAN_ICMP_DISABLE_PS /* @@ -14307,6 +14350,39 @@ enum hw_filter_mode { #define CFG_DTIM_SELECTION_DIVERSITY_MAX (30) #define CFG_DTIM_SELECTION_DIVERSITY_DEFAULT (5) +/* + * <ini> + * gTxSchDelay - Enable/Disable Tx sch delay + * @Min: 0 + * @Max: 5 + * @Default: 2 + * + * Usage: Internal/External + * + * </ini> + */ + +#define CFG_TX_SCH_DELAY_NAME "gTxSchDelay" +#define CFG_TX_SCH_DELAY_MIN (0) +#define CFG_TX_SCH_DELAY_MAX (5) +#define CFG_TX_SCH_DELAY_DEFAULT (2) + +/* + * <ini> + * enable_rtt_mac_randomization - Enable/Disable rtt mac randomization + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Usage: External + * + * </ini> + */ +#define CFG_ENABLE_RTT_MAC_RANDOMIZATION_NAME "enable_rtt_mac_randomization" +#define CFG_ENABLE_RTT_MAC_RANDOMIZATION_MIN (0) +#define CFG_ENABLE_RTT_MAC_RANDOMIZATION_MAX (1) +#define CFG_ENABLE_RTT_MAC_RANDOMIZATION_DEFAULT (0) + /*--------------------------------------------------------------------------- Type declarations -------------------------------------------------------------------------*/ @@ -14622,6 +14698,7 @@ struct hdd_config { bool enableTxBF; bool enable_subfee_vendor_vhtie; bool enable_txbf_sap_mode; + bool enable_vht20_mcs9; uint8_t txBFCsnValue; bool enable_su_tx_bformer; uint8_t vhtRxMCS2x2; @@ -15212,9 +15289,12 @@ struct hdd_config { uint32_t neighbor_report_offload_max_req_cap; uint32_t channel_select_logic_conc; bool enable_dtim_selection_diversity; + uint8_t enable_tx_sch_delay; #ifdef WLAN_FEATURE_SAE bool is_sae_enabled; #endif + bool enable_rtt_mac_randomization; + bool enable_ftopen; }; #define VAR_OFFSET(_Struct, _Var) (offsetof(_Struct, _Var)) diff --git a/core/hdd/inc/wlan_hdd_debugfs.h b/core/hdd/inc/wlan_hdd_debugfs.h index 9633e0018e4e..2ac5a8f37090 100644 --- a/core/hdd/inc/wlan_hdd_debugfs.h +++ b/core/hdd/inc/wlan_hdd_debugfs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -31,6 +31,43 @@ #ifdef WLAN_DEBUGFS QDF_STATUS hdd_debugfs_init(hdd_adapter_t *adapter); void hdd_debugfs_exit(hdd_adapter_t *adapter); + +/** + * hdd_wait_for_debugfs_threads_completion() - Wait for debugfs threads + * completion before proceeding further to stop modules + * + * Return: true if there is no debugfs open + * false if there is at least one debugfs open + */ +bool hdd_wait_for_debugfs_threads_completion(void); + +/** + * hdd_return_debugfs_threads_count() - Return active debugfs threads + * + * Return: total number of active debugfs threads in driver + */ +int hdd_return_debugfs_threads_count(void); + +/** + * hdd_debugfs_thread_increment() - Increment debugfs thread count + * + * This function is used to increment and keep track of debugfs thread count. + * This is invoked for every file open operation. + * + * Return: None + */ +void hdd_debugfs_thread_increment(void); + +/** + * hdd_debugfs_thread_decrement() - Decrement debugfs thread count + * + * This function is used to decrement and keep track of debugfs thread count. + * This is invoked for every file release operation. + * + * Return: None + */ +void hdd_debugfs_thread_decrement(void); + #else static inline QDF_STATUS hdd_debugfs_init(hdd_adapter_t *pAdapter) { @@ -40,5 +77,56 @@ static inline QDF_STATUS hdd_debugfs_init(hdd_adapter_t *pAdapter) static inline void hdd_debugfs_exit(hdd_adapter_t *adapter) { } + +/** + * hdd_wait_for_debugfs_threads_completion() - Wait for debugfs threads + * completion before proceeding further to stop modules + * + * Return: true if there is no debugfs open + * false if there is at least one debugfs open + */ +static inline +bool hdd_wait_for_debugfs_threads_completion(void) +{ + return true; +} + +/** + * hdd_return_debugfs_threads_count() - Return active debugfs threads + * + * Return: total number of active debugfs threads in driver + */ +static inline +int hdd_return_debugfs_threads_count(void) +{ + return 0; +} + +/** + * hdd_debugfs_thread_increment() - Increment debugfs thread count + * + * This function is used to increment and keep track of debugfs thread count. + * This is invoked for every file open operation. + * + * Return: None + */ +static inline +void hdd_debugfs_thread_increment(void) +{ +} + +/** + * hdd_debugfs_thread_decrement() - Decrement debugfs thread count + * + * This function is used to decrement and keep track of debugfs thread count. + * This is invoked for every file release operation. + * + * Return: None + */ +static inline +void hdd_debugfs_thread_decrement(void) +{ +} + #endif /* #ifdef WLAN_DEBUGFS */ #endif /* #ifndef _WLAN_HDD_DEBUGFS_H */ diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 4b158e31821b..6cf2fe2c27ea 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -1165,6 +1165,7 @@ struct hdd_ap_ctx_s { /* Fw txrx stats info */ struct hdd_fw_txrx_stats txrx_stats; + qdf_atomic_t acs_in_progress; }; typedef struct hdd_scaninfo_s { @@ -1882,6 +1883,33 @@ enum hdd_sta_smps_param { }; /** + * struct hdd_cache_channel_info - Structure of the channel info + * which needs to be cached + * @channel_num: channel number + * @reg_status: Current regulatory status of the channel + * Enable + * Disable + * DFS + * Invalid + * @wiphy_status: Current wiphy status + */ +struct hdd_cache_channel_info { + uint32_t channel_num; + enum channel_state reg_status; + uint32_t wiphy_status; +}; + +/** + * struct hdd_cache_channels - Structure of the channels to be cached + * @num_channels: Number of channels to be cached + * @channel_info: Structure of the channel info + */ +struct hdd_cache_channels { + uint32_t num_channels; + struct hdd_cache_channel_info *channel_info; +}; + +/** * struct hdd_context_s * @adapter_nodes: an array of adapter nodes for keeping track of hdd adapters */ @@ -2203,7 +2231,8 @@ struct hdd_context_s { /* mutex lock to block concurrent access */ struct mutex power_stats_lock; #endif - qdf_atomic_t is_acs_allowed; + struct hdd_cache_channels *original_channels; + qdf_mutex_t cache_channel_lock; }; int hdd_validate_channel_and_bandwidth(hdd_adapter_t *adapter, @@ -3088,4 +3117,12 @@ void hdd_driver_memdump_deinit(void); */ bool hdd_is_cli_iface_up(hdd_context_t *hdd_ctx); +/** + * wlan_hdd_free_cache_channels() - Free the cache channels list + * @hdd_ctx: Pointer to HDD context + * + * Return: None + */ +void wlan_hdd_free_cache_channels(hdd_context_t *hdd_ctx); + #endif /* end #if !defined(WLAN_HDD_MAIN_H) */ diff --git a/core/hdd/inc/wlan_hdd_power.h b/core/hdd/inc/wlan_hdd_power.h index e27e3cdbbadb..ecb062e9839d 100644 --- a/core/hdd/inc/wlan_hdd_power.h +++ b/core/hdd/inc/wlan_hdd_power.h @@ -42,6 +42,12 @@ #define HDD_WAKELOCK_TIMEOUT_CONNECT 1000 #define HDD_WAKELOCK_TIMEOUT_RESUME 1000 +/* + * HDD_WAKELOCK_CONNECT_COMPLETE = CSR_JOIN_FAILURE_TIMEOUT_DEFAULT (3000) + + * WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT_STADEF (1000) + + * WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT_STADEF (2000) + */ +#define HDD_WAKELOCK_CONNECT_COMPLETE 6000 /** * enum pkt_filter_protocol_layer - packet filter protocol layer diff --git a/core/hdd/inc/wlan_hdd_tx_rx.h b/core/hdd/inc/wlan_hdd_tx_rx.h index c5ff55f5fdcc..baaa1c28115a 100644 --- a/core/hdd/inc/wlan_hdd_tx_rx.h +++ b/core/hdd/inc/wlan_hdd_tx_rx.h @@ -45,6 +45,10 @@ #define HDD_ETHERTYPE_802_1_X_FRAME_OFFSET 12 #ifdef FEATURE_WLAN_WAPI #define HDD_ETHERTYPE_WAI 0x88b4 +#define IS_HDD_ETHERTYPE_WAI(_skb) (ntohs(_skb->protocol) == \ + HDD_ETHERTYPE_WAI) +#else +#define IS_HDD_ETHERTYPE_WAI(_skb) (false) #endif #define HDD_PSB_CFG_INVALID 0xFF @@ -62,6 +66,14 @@ QDF_STATUS hdd_deinit_tx_rx(hdd_adapter_t *pAdapter); QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf); /** + * hdd_reset_all_adapters_connectivity_stats() - reset connectivity stats + * @hdd_ctx: pointer to HDD Station Context + * + * Return: None + */ +void hdd_reset_all_adapters_connectivity_stats(hdd_context_t *hdd_ctx); + +/** * hdd_tx_rx_collect_connectivity_stats_info() - collect connectivity stats * @skb: pointer to skb data * @adapter: pointer to vdev apdapter diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c index e6b702bdf428..ad5d1029c3e5 100644 --- a/core/hdd/src/wlan_hdd_assoc.c +++ b/core/hdd/src/wlan_hdd_assoc.c @@ -118,6 +118,8 @@ uint8_t ccp_rsn_oui_0f[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x0F}; uint8_t ccp_rsn_oui_10[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x10}; uint8_t ccp_rsn_oui_11[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x11}; #endif +static const +uint8_t ccp_rsn_oui_12[HDD_RSN_OUI_SIZE] = {0x50, 0x6F, 0x9A, 0x02}; static const uint8_t ccp_rsn_oui_0b[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x0B}; @@ -467,14 +469,6 @@ static int hdd_add_beacon_filter(hdd_adapter_t *adapter) return 0; } -/** - * hdd_copy_vht_caps()- copy vht caps info from roam info to - * hdd station context. - * @hdd_sta_ctx: pointer to hdd station context - * @roam_info: pointer to roam info - * - * Return: None - */ void hdd_copy_ht_caps(struct ieee80211_ht_cap *hdd_ht_cap, tDot11fIEHTCaps *roam_ht_cap) { @@ -660,7 +654,7 @@ void hdd_copy_ht_caps(struct ieee80211_ht_cap *hdd_ht_cap, #define VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB_SHIFT 26 /** - * hdd_copy_ht_caps()- copy ht caps info from roam info to + * hdd_copy_vht_caps()- copy vht caps info from roam info to * hdd station context. * @hdd_sta_ctx: pointer to hdd station context * @roam_info: pointer to roam info @@ -1806,7 +1800,8 @@ static QDF_STATUS hdd_dis_connect_handler(hdd_adapter_t *pAdapter, } } else { sta_id = pHddStaCtx->conn_info.staId[0]; - hdd_debug("roamResult: %d", roamResult); + hdd_debug("roamResult is: %d %s", roamResult, + get_e_csr_roam_result_str(roamResult)); /* clear scan cache for Link Lost */ if (pRoamInfo && !pRoamInfo->reasonCode && @@ -2611,9 +2606,12 @@ static QDF_STATUS hdd_association_completion_handler(hdd_adapter_t *pAdapter, pHddStaCtx->conn_info.connState)) && ((eCSR_ROAM_RESULT_ASSOCIATED == roamResult) || (eCSR_ROAM_ASSOCIATION_FAILURE == roamStatus))) { - hdd_info("hddDisconInProgress state=%d, result=%d, status=%d", + hdd_info("hddDisconInProgress state=%d, result=%d %s, status=%d %s", pHddStaCtx->conn_info.connState, - roamResult, roamStatus); + roamResult, + get_e_csr_roam_result_str(roamResult), + roamStatus, + get_e_roam_cmd_status_str(roamStatus)); hddDisconInProgress = true; } @@ -2974,10 +2972,13 @@ static QDF_STATUS hdd_association_completion_handler(hdd_adapter_t *pAdapter, else { hdd_debug("sending connect indication to nl80211:for bssid " MAC_ADDRESS_STR - " result:%d and Status:%d", + " result:%d %s and Status:%d %s", MAC_ADDR_ARRAY (pRoamInfo->bssid.bytes), - roamResult, roamStatus); + roamResult, + get_e_csr_roam_result_str(roamResult), + roamStatus, + get_e_roam_cmd_status_str(roamStatus)); /* inform connect result to nl80211 */ hdd_connect_result(dev, @@ -3111,14 +3112,20 @@ static QDF_STATUS hdd_association_completion_handler(hdd_adapter_t *pAdapter, if (pRoamInfo) hdd_err("wlan: connection failed with " MAC_ADDRESS_STR - " result: %d and Status: %d", + " result: %d %s and Status: %d %s", MAC_ADDR_ARRAY(pRoamInfo->bssid.bytes), - roamResult, roamStatus); + roamResult, + get_e_csr_roam_result_str(roamResult), + roamStatus, + get_e_roam_cmd_status_str(roamStatus)); else hdd_err("wlan: connection failed with " MAC_ADDRESS_STR - " result: %d and Status: %d", + " result: %d %s and Status: %d %s", MAC_ADDR_ARRAY(pWextState->req_bssId.bytes), - roamResult, roamStatus); + roamResult, + get_e_csr_roam_result_str(roamResult), + roamStatus, + get_e_roam_cmd_status_str(roamStatus)); if ((eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE == roamResult) || (pRoamInfo && @@ -3148,18 +3155,24 @@ static QDF_STATUS hdd_association_completion_handler(hdd_adapter_t *pAdapter, if (pRoamInfo) { hdd_err("send connect failure to nl80211: for bssid " MAC_ADDRESS_STR - " result: %d and Status: %d reasoncode: %d", + " result: %d %s and Status: %d %s reasoncode: %d", MAC_ADDR_ARRAY(pRoamInfo->bssid.bytes), - roamResult, roamStatus, + roamResult, + get_e_csr_roam_result_str(roamResult), + roamStatus, + get_e_roam_cmd_status_str(roamStatus), pRoamInfo->reasonCode); pHddStaCtx->conn_info.assoc_status_code = pRoamInfo->statusCode; } else { hdd_err("connect failed: for bssid " MAC_ADDRESS_STR - " result: %d and status: %d ", + " result: %d %s and status: %d %s", MAC_ADDR_ARRAY(pWextState->req_bssId.bytes), - roamResult, roamStatus); + roamResult, + get_e_csr_roam_result_str(roamResult), + roamStatus, + get_e_roam_cmd_status_str(roamStatus)); } hdd_debug("Invoking packetdump deregistration API"); wlan_deregister_txrx_packetdump(); @@ -5015,8 +5028,12 @@ hdd_sme_roam_callback(void *pContext, tCsrRoamInfo *pRoamInfo, uint32_t roamId, hdd_context_t *pHddCtx; if (eCSR_ROAM_UPDATE_SCAN_RESULT != roamStatus) - hdd_debug("CSR Callback: status= %d result= %d roamID=%d", - roamStatus, roamResult, roamId); + hdd_debug("CSR Callback: status= %d %s result= %d %s roamID=%d", + roamStatus, + get_e_roam_cmd_status_str(roamStatus), + roamResult, + get_e_csr_roam_result_str(roamResult), + roamId); /* Sanity check */ if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) { hdd_err("Invalid adapter or adapter has invalid magic"); @@ -5484,6 +5501,8 @@ eCsrAuthType hdd_translate_rsn_to_csr_auth_type(uint8_t auth_suite[4]) } else if (memcmp(auth_suite, ccp_rsn_oui_0c, 4) == 0) { /* Check for Suite B EAP 384 */ auth_type = eCSR_AUTH_TYPE_SUITEB_EAP_SHA384; + } else if (memcmp(auth_suite, ccp_rsn_oui_12, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_DPP_RSN; } else { hdd_translate_fils_rsn_to_csr_auth(auth_suite, &auth_type); hdd_translate_owe_rsn_to_csr_auth(auth_suite, &auth_type); @@ -6000,8 +6019,10 @@ int hdd_set_csr_auth_type(hdd_adapter_t *pAdapter, eCsrAuthType RSNAuthType) eCSR_AUTH_TYPE_CCKM_RSN; } else #endif - - if ((RSNAuthType == eCSR_AUTH_TYPE_FT_RSN) && + if (RSNAuthType == eCSR_AUTH_TYPE_DPP_RSN) { + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_DPP_RSN; + } else if ((RSNAuthType == eCSR_AUTH_TYPE_FT_RSN) && ((pWextState-> authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X) == IW_AUTH_KEY_MGMT_802_1X)) { diff --git a/core/hdd/src/wlan_hdd_cfg.c b/core/hdd/src/wlan_hdd_cfg.c index 6e3450d3323b..746a6ce9fd28 100644 --- a/core/hdd/src/wlan_hdd_cfg.c +++ b/core/hdd/src/wlan_hdd_cfg.c @@ -2143,6 +2143,13 @@ struct reg_table_entry g_registry_table[] = { CFG_VHT_ENABLE_TX_MCS2x2_8_9_MIN, CFG_VHT_ENABLE_TX_MCS2x2_8_9_MAX), + REG_VARIABLE(CFG_ENABLE_VHT20_MCS9, WLAN_PARAM_Integer, + struct hdd_config, enable_vht20_mcs9, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_ENABLE_VHT20_MCS9_DEFAULT, + CFG_ENABLE_VHT20_MCS9_MIN, + CFG_ENABLE_VHT20_MCS9_MAX), + REG_VARIABLE(CFG_VHT_ENABLE_2x2_CAP_FEATURE, WLAN_PARAM_Integer, struct hdd_config, enable2x2, VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, @@ -4074,6 +4081,13 @@ struct reg_table_entry g_registry_table[] = { CFG_ROAM_DENSE_RSSI_THRE_OFFSET_MIN, CFG_ROAM_DENSE_RSSI_THRE_OFFSET_MAX), + REG_VARIABLE(CFG_ROAM_FT_OPEN_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_ftopen, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_FT_OPEN_ENABLE_DEFAULT, + CFG_ROAM_FT_OPEN_ENABLE_MIN, + CFG_ROAM_FT_OPEN_ENABLE_MAX), + REG_VARIABLE(CFG_IGNORE_PEER_HT_MODE_NAME, WLAN_PARAM_Integer, struct hdd_config, ignore_peer_ht_opmode, VAR_FLAGS_OPTIONAL | @@ -5538,6 +5552,14 @@ struct reg_table_entry g_registry_table[] = { CFG_DTIM_SELECTION_DIVERSITY_MIN, CFG_DTIM_SELECTION_DIVERSITY_MAX), + REG_VARIABLE(CFG_TX_SCH_DELAY_NAME, + WLAN_PARAM_Integer, + struct hdd_config, enable_tx_sch_delay, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_SCH_DELAY_DEFAULT, + CFG_TX_SCH_DELAY_MIN, + CFG_TX_SCH_DELAY_MAX), + #ifdef WLAN_FEATURE_SAE REG_VARIABLE(CFG_IS_SAE_ENABLED_NAME, WLAN_PARAM_Integer, struct hdd_config, is_sae_enabled, @@ -5546,6 +5568,14 @@ struct reg_table_entry g_registry_table[] = { CFG_IS_SAE_ENABLED_MIN, CFG_IS_SAE_ENABLED_MAX), #endif + + REG_VARIABLE(CFG_ENABLE_RTT_MAC_RANDOMIZATION_NAME, + WLAN_PARAM_Integer, + struct hdd_config, enable_rtt_mac_randomization, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_RTT_MAC_RANDOMIZATION_DEFAULT, + CFG_ENABLE_RTT_MAC_RANDOMIZATION_MIN, + CFG_ENABLE_RTT_MAC_RANDOMIZATION_MAX), }; /** @@ -7081,6 +7111,9 @@ void hdd_cfg_print(hdd_context_t *pHddCtx) CFG_ROAM_BG_SCAN_BAD_RSSI_OFFSET_2G_NAME, pHddCtx->config->roam_bad_rssi_thresh_offset_2g); hdd_debug("Name = [%s] Value = [%u]", + CFG_ROAM_FT_OPEN_ENABLE_NAME, + pHddCtx->config->enable_ftopen); + hdd_debug("Name = [%s] Value = [%u]", CFG_MIN_REST_TIME_NAME, pHddCtx->config->min_rest_time_conc); hdd_debug("Name = [%s] Value = [%u]", @@ -7429,6 +7462,9 @@ void hdd_cfg_print(hdd_context_t *pHddCtx) hdd_debug("Name = [%s] value = [%d]", CFG_DTIM_SELECTION_DIVERSITY_NAME, pHddCtx->config->enable_dtim_selection_diversity); + hdd_debug("Name = [%s] value = [%d]", + CFG_TX_SCH_DELAY_NAME, + pHddCtx->config->enable_tx_sch_delay); hdd_cfg_print_11k_offload_params(pHddCtx); hdd_debug("Name = [%s] value = [0x%x]", @@ -9845,6 +9881,7 @@ QDF_STATUS hdd_set_sme_config(hdd_context_t *pHddCtx) pConfig->disable_high_ht_mcs_2x2; smeConfig->csrConfig.rx_ldpc_support_for_2g = pConfig->rx_ldpc_support_for_2g; + smeConfig->csrConfig.enable_vht20_mcs9 = pConfig->enable_vht20_mcs9; #ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH smeConfig->csrConfig.cc_switch_mode = pConfig->WlanMccToSccSwitchMode; #endif @@ -9934,6 +9971,8 @@ QDF_STATUS hdd_set_sme_config(hdd_context_t *pHddCtx) pHddCtx->config->roam_bg_scan_client_bitmap; smeConfig->csrConfig.roam_bad_rssi_thresh_offset_2g = pHddCtx->config->roam_bad_rssi_thresh_offset_2g; + smeConfig->csrConfig.enable_ftopen = + pHddCtx->config->enable_ftopen; smeConfig->csrConfig.obss_width_interval = pHddCtx->config->obss_width_trigger_interval; smeConfig->csrConfig.obss_active_dwelltime = diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 129ba0c81f40..b4b96209afcc 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -1629,31 +1629,28 @@ static int __wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy, ret = wlan_hdd_validate_context(hdd_ctx); if (ret) - goto out; + return ret; if (cds_is_sub_20_mhz_enabled()) { hdd_err("ACS not supported in sub 20 MHz ch wd."); - ret = -EINVAL; - goto out; + return -EINVAL; } - - if (qdf_atomic_inc_return(&hdd_ctx->is_acs_allowed) > 1) { + if (qdf_atomic_read(&adapter->sessionCtx.ap.acs_in_progress) > 0) { hdd_err("ACS rejected as previous req already in progress"); - ret = -EINVAL; - goto out; + return -EINVAL; + } else { + qdf_atomic_set(&adapter->sessionCtx.ap.acs_in_progress, 1); } ret = hdd_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ACS_MAX, data, data_len, wlan_hdd_cfg80211_do_acs_policy); if (ret) { hdd_err("Invalid ATTR"); - qdf_atomic_set(&hdd_ctx->is_acs_allowed, 0); goto out; } if (!tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]) { hdd_err("Attr hw_mode failed"); - qdf_atomic_set(&hdd_ctx->is_acs_allowed, 0); goto out; } hw_mode = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]); @@ -1739,7 +1736,6 @@ static int __wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy, sizeof(uint8_t) * sap_config->acs_cfg.ch_list_count); if (sap_config->acs_cfg.ch_list == NULL) { - qdf_atomic_set(&hdd_ctx->is_acs_allowed, 0); ret = -ENOMEM; goto out; } @@ -1758,7 +1754,6 @@ static int __wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy, sap_config->acs_cfg.ch_list_count); if (sap_config->acs_cfg.ch_list == NULL) { hdd_err("ACS config alloc fail"); - qdf_atomic_set(&hdd_ctx->is_acs_allowed, 0); ret = -ENOMEM; goto out; } @@ -1771,6 +1766,8 @@ static int __wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy, } if (!sap_config->acs_cfg.ch_list_count) { + qdf_atomic_set(&adapter->sessionCtx.ap.acs_in_progress, 0); + hdd_err("acs config chan count 0"); ret = -EINVAL; goto out; } @@ -1850,6 +1847,8 @@ out: if (temp_skbuff != NULL) return cfg80211_vendor_cmd_reply(temp_skbuff); } + + qdf_atomic_set(&adapter->sessionCtx.ap.acs_in_progress, 0); wlan_hdd_undo_acs(adapter); clear_bit(ACS_IN_PROGRESS, &hdd_ctx->g_event_flags); @@ -16789,7 +16788,7 @@ static int wlan_hdd_cfg80211_connect_start(hdd_adapter_t *pAdapter, qdf_runtime_pm_prevent_suspend( &pHddCtx->runtime_context.connect); - hdd_prevent_suspend_timeout(HDD_WAKELOCK_TIMEOUT_CONNECT, + hdd_prevent_suspend_timeout(HDD_WAKELOCK_CONNECT_COMPLETE, WIFI_POWER_EVENT_WAKELOCK_CONNECT); qdf_status = sme_roam_connect(WLAN_HDD_GET_HAL_CTX(pAdapter), @@ -17165,6 +17164,7 @@ static int wlan_hdd_set_akm_suite(hdd_adapter_t *pAdapter, u32 key_mgmt) case WLAN_AKM_SUITE_PSK: case WLAN_AKM_SUITE_PSK_SHA256: case WLAN_AKM_SUITE_FT_PSK: + case WLAN_AKM_SUITE_DPP_RSN: hdd_debug("setting key mgmt type to PSK"); pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_PSK; break; @@ -19348,8 +19348,6 @@ int __wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, } pAdapter->aStaInfo[staId].isDeauthInProgress = true; - pAdapter->cache_sta_info[staId].reason_code = - pDelStaParams->reason_code; hdd_debug("Delete STA with MAC::" MAC_ADDRESS_STR, MAC_ADDR_ARRAY(mac)); @@ -20967,6 +20965,12 @@ static int __wlan_hdd_cfg80211_update_connect_params( fils_info->key_nai_length = req->fils_erp_username_len + sizeof(char) + req->fils_erp_realm_len; + if (fils_info->key_nai_length > + FILS_MAX_KEYNAME_NAI_LENGTH) { + hdd_err("Key NAI Length %d", + fils_info->key_nai_length); + return -EINVAL; + } if (req->fils_erp_username_len && req->fils_erp_username) { buf = fils_info->keyname_nai; qdf_mem_copy(buf, req->fils_erp_username, diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h index a07b47866c13..30259032470b 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.h +++ b/core/hdd/src/wlan_hdd_cfg80211.h @@ -155,6 +155,10 @@ typedef struct { #define WLAN_AKM_SUITE_SAE 0x000FAC08 #endif +#ifndef WLAN_AKM_SUITE_DPP_RSN +#define WLAN_AKM_SUITE_DPP_RSN 0x506F9A02 +#endif + #ifdef FEATURE_WLAN_TDLS #define WLAN_IS_TDLS_SETUP_ACTION(action) \ ((SIR_MAC_TDLS_SETUP_REQ <= action) && \ @@ -706,4 +710,14 @@ QDF_STATUS wlan_hdd_send_sta_authorized_event( hdd_adapter_t *pAdapter, hdd_context_t *pHddCtx, const struct qdf_mac_addr *mac_addr); + +/** + * wlan_hdd_restore_channels() - Restore the channels which were cached + * and disabled in wlan_hdd_disable_channels api. + * @hdd_ctx: Pointer to the HDD context + * + * Return: 0 on success, Error code on failure + */ +int wlan_hdd_restore_channels(hdd_context_t *hdd_ctx); + #endif diff --git a/core/hdd/src/wlan_hdd_debugfs.c b/core/hdd/src/wlan_hdd_debugfs.c index ace44d369bda..e0a65be053c8 100644 --- a/core/hdd/src/wlan_hdd_debugfs.c +++ b/core/hdd/src/wlan_hdd_debugfs.c @@ -49,6 +49,52 @@ #define POWER_DEBUGFS_BUFFER_MAX_LEN 4096 #endif +#define MAX_DEBUGFS_WAIT_ITERATIONS 20 +#define DEBUGFS_WAIT_SLEEP_TIME 100 + +static qdf_atomic_t debugfs_thread_count; + +void hdd_debugfs_thread_increment(void) +{ + qdf_atomic_inc(&debugfs_thread_count); +} + +void hdd_debugfs_thread_decrement(void) +{ + qdf_atomic_dec(&debugfs_thread_count); +} + +int hdd_return_debugfs_threads_count(void) +{ + return qdf_atomic_read(&debugfs_thread_count); +} + +bool hdd_wait_for_debugfs_threads_completion(void) +{ + int count = MAX_DEBUGFS_WAIT_ITERATIONS; + int r; + + while (count) { + + r = hdd_return_debugfs_threads_count(); + if (!r) + break; + + if (--count) { + hdd_debug("Waiting for %d debugfs threads to exit", r); + msleep(DEBUGFS_WAIT_SLEEP_TIME); + } + } + + /* at least one debugfs thread is executing */ + if (!count) { + hdd_err("Timed-out waiting for debugfs threads"); + return false; + } + + return true; +} + /** * __wcnss_wowenable_write() - wow_enable debugfs handler * @file: debugfs file handle diff --git a/core/hdd/src/wlan_hdd_debugfs_csr.c b/core/hdd/src/wlan_hdd_debugfs_csr.c index 02e5775d5af7..af1f579c2832 100644 --- a/core/hdd/src/wlan_hdd_debugfs_csr.c +++ b/core/hdd/src/wlan_hdd_debugfs_csr.c @@ -33,6 +33,7 @@ #include "qwlan_version.h" #include "wmi_unified_param.h" #include "wlan_hdd_request_manager.h" +#include "wlan_hdd_debugfs.h" ssize_t wlan_hdd_current_time_info_debugfs(uint8_t *buf, ssize_t buf_avail_len) @@ -132,6 +133,11 @@ __wlan_hdd_read_debugfs_csr(struct file *file, char __user *buf, if (ret) return 0; + if (!test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags)) { + hdd_err("Interface is not enabled"); + return 0; + } + if (*pos == 0) { info->length = wlan_hdd_debugfs_update_csr(hdd_ctx, adapter, @@ -183,6 +189,8 @@ static int __wlan_hdd_open_debugfs_csr(struct inode *inode, struct wlan_hdd_debugfs_buffer_info *info; struct hdd_debugfs_file_info *csr; hdd_adapter_t *adapter = NULL; + hdd_context_t *hdd_ctx; + int ret; ENTER(); @@ -199,6 +207,16 @@ static int __wlan_hdd_open_debugfs_csr(struct inode *inode, return -EINVAL; } + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return -EINVAL; + + if (!test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags)) { + hdd_err("Interface is not enabled"); + return -EINVAL; + } + info = qdf_mem_malloc(sizeof(*info)); if (!info) { hdd_err("Not enough memory for file private data"); @@ -222,7 +240,6 @@ static int __wlan_hdd_open_debugfs_csr(struct inode *inode, return 0; } - /** * wlan_hdd_open_debugfs_csr() - SSR wrapper function to allocate memory for * private data on file open @@ -237,7 +254,12 @@ static int wlan_hdd_open_debugfs_csr(struct inode *inode, int ret; cds_ssr_protect(__func__); + + hdd_debugfs_thread_increment(); ret = __wlan_hdd_open_debugfs_csr(inode, file); + if (ret) + hdd_debugfs_thread_decrement(); + cds_ssr_unprotect(__func__); return ret; @@ -284,6 +306,7 @@ static int wlan_hdd_release_debugfs_csr(struct inode *inode, struct file *file) cds_ssr_protect(__func__); ret = __wlan_hdd_release_debugfs_csr(inode, file); + hdd_debugfs_thread_decrement(); cds_ssr_unprotect(__func__); return ret; @@ -316,7 +339,8 @@ void wlan_hdd_debugfs_csr_init(hdd_adapter_t *adapter) adapter->debugfs_phy, csr, &fops_csr_debugfs); if (!csr->entry) - hdd_err("Failed to create connect_info debugfs file"); + hdd_err("Failed to create debugfs file: %s", + csr->name); } csr = &adapter->csr_file[HDD_DEBUFS_FILE_ID_OFFLOAD_INFO]; @@ -328,7 +352,8 @@ void wlan_hdd_debugfs_csr_init(hdd_adapter_t *adapter) adapter->debugfs_phy, csr, &fops_csr_debugfs); if (!csr->entry) - hdd_err("Failed to create generic_info debugfs file"); + hdd_err("Failed to create debugfs file: %s", + csr->name); } csr = &adapter->csr_file[HDD_DEBUFS_FILE_ID_ROAM_SCAN_STATS_INFO]; @@ -340,7 +365,8 @@ void wlan_hdd_debugfs_csr_init(hdd_adapter_t *adapter) adapter->debugfs_phy, csr, &fops_csr_debugfs); if (!csr->entry) - hdd_err("Failed to create generic_info debugfs file"); + hdd_err("Failed to create debugfs file: %s", + csr->name); } } diff --git a/core/hdd/src/wlan_hdd_driver_ops.c b/core/hdd/src/wlan_hdd_driver_ops.c index a73f3eacdb84..893ce2e4050f 100644 --- a/core/hdd/src/wlan_hdd_driver_ops.c +++ b/core/hdd/src/wlan_hdd_driver_ops.c @@ -48,6 +48,7 @@ #include "wlan_hdd_driver_ops.h" #include "wlan_hdd_scan.h" #include "wlan_hdd_ipa.h" +#include "wlan_hdd_debugfs.h" #ifdef MODULE #define WLAN_MODULE_NAME module_name(THIS_MODULE) @@ -476,6 +477,9 @@ static void wlan_hdd_remove(struct device *dev) if (!cds_wait_for_external_threads_completion(__func__)) hdd_warn("External threads are still active attempting driver unload anyway"); + if (!hdd_wait_for_debugfs_threads_completion()) + hdd_warn("Debugfs threads are still active attempting driver unload anyway"); + hdd_pld_driver_unloading(dev); if (QDF_IS_EPPING_ENABLED(cds_get_conparam())) { @@ -575,6 +579,9 @@ static void wlan_hdd_shutdown(void) if (!cds_wait_for_external_threads_completion(__func__)) hdd_err("Host is not ready for SSR, attempting anyway"); + if (!hdd_wait_for_debugfs_threads_completion()) + hdd_err("Debufs threads are still pending, attempting SSR anyway"); + if (!QDF_IS_EPPING_ENABLED(cds_get_conparam())) { hif_disable_isr(hif_ctx); hdd_wlan_shutdown(); diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index 1a879ff4eb68..d3f32319367d 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -203,7 +203,6 @@ int hdd_sap_context_init(hdd_context_t *hdd_ctx) qdf_spinlock_create(&hdd_ctx->sap_update_info_lock); qdf_atomic_init(&hdd_ctx->dfs_radar_found); - qdf_atomic_init(&hdd_ctx->is_acs_allowed); return 0; } @@ -1605,9 +1604,10 @@ QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent, struct ch_params_s sap_ch_param = {0}; eCsrPhyMode phy_mode; bool legacy_phymode; - tSap_StationDisassocCompleteEvent *disconnect_event; + tSap_StationDisassocCompleteEvent *disassoc_comp; hdd_station_info_t *stainfo; cds_context_type *cds_ctx; + hdd_adapter_t *sta_adapter; dev = (struct net_device *)usrDataForCallback; if (!dev) { @@ -1842,6 +1842,12 @@ QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent, we_custom_event_generic = we_custom_start_event; cds_dump_concurrency_info(); + sta_adapter = hdd_get_adapter(pHddCtx, QDF_STA_MODE); + if (sta_adapter != NULL) { + hdd_debug("check for SAP restart"); + cds_check_concurrent_intf_and_restart_sap(sta_adapter); + } + if (cds_is_hw_mode_change_after_vdev_up()) { hdd_debug("check for possible hw mode change"); status = cds_set_hw_mode_on_channel_switch( @@ -2206,34 +2212,21 @@ QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent, hdd_green_ap_add_sta(pHddCtx); break; - case eSAP_STA_LOSTLINK_DETECTED: - disconnect_event = - &pSapEvent->sapevt.sapStationDisassocCompleteEvent; - - wlan_hdd_get_peer_rssi(pHostapdAdapter, - &disconnect_event->staMac, - HDD_WLAN_GET_PEER_RSSI_SOURCE_DRIVER); - - /* - * For user initiated disconnect, reason_code is updated while - * issuing the disconnect from HDD. - */ - if (disconnect_event->reason != eSAP_USR_INITATED_DISASSOC) { - stainfo = hdd_get_stainfo( - pHostapdAdapter->cache_sta_info, - disconnect_event->staMac); - if (stainfo) - stainfo->reason_code = - disconnect_event->reason_code; - } - return QDF_STATUS_SUCCESS; - case eSAP_STA_DISASSOC_EVENT: + disassoc_comp = + &pSapEvent->sapevt.sapStationDisassocCompleteEvent; memcpy(wrqu.addr.sa_data, - &pSapEvent->sapevt.sapStationDisassocCompleteEvent. - staMac, QDF_MAC_ADDR_SIZE); + &disassoc_comp->staMac, QDF_MAC_ADDR_SIZE); hdd_notice(" disassociated " MAC_ADDRESS_STR, MAC_ADDR_ARRAY(wrqu.addr.sa_data)); + stainfo = hdd_get_stainfo(pHostapdAdapter->cache_sta_info, + disassoc_comp->staMac); + if (stainfo) { + stainfo->rssi = disassoc_comp->rssi; + stainfo->tx_rate = disassoc_comp->tx_rate; + stainfo->rx_rate = disassoc_comp->rx_rate; + stainfo->reason_code = disassoc_comp->reason_code; + } qdf_status = qdf_event_set(&pHostapdState->qdf_sta_disassoc_event); if (!QDF_IS_STATUS_SUCCESS(qdf_status)) @@ -2577,7 +2570,8 @@ QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent, /* send vendor event to hostapd only for hostapd based acs*/ if (!pHddCtx->config->force_sap_acs) wlan_hdd_cfg80211_acs_ch_select_evt(pHostapdAdapter); - qdf_atomic_set(&pHddCtx->is_acs_allowed, 0); + qdf_atomic_set( + &pHostapdAdapter->sessionCtx.ap.acs_in_progress, 0); return QDF_STATUS_SUCCESS; case eSAP_ECSA_CHANGE_CHAN_IND: hdd_debug("Channel change indication from peer for channel %d", @@ -4519,7 +4513,6 @@ static __iw_softap_disassoc_sta(struct net_device *dev, uint8_t *peerMacAddr; int ret; struct tagCsrDelStaParams del_sta_params; - hdd_station_info_t *stainfo; ENTER_DEV(dev); @@ -4546,11 +4539,6 @@ static __iw_softap_disassoc_sta(struct net_device *dev, &del_sta_params); hdd_softap_sta_disassoc(pHostapdAdapter, &del_sta_params); - stainfo = hdd_get_stainfo(pHostapdAdapter->cache_sta_info, - del_sta_params.peerMacAddr); - if (stainfo) - stainfo->reason_code = del_sta_params.reason_code; - EXIT(); return 0; } @@ -5290,7 +5278,7 @@ static int __iw_get_ap_freq(struct net_device *dev, return -EIO; } status = hdd_wlan_get_freq(channel, &freq); - if (true == status) { + if (0 == status) { /* Set Exponent parameter as 6 (MHZ) in struct * iw_freq * iwlist & iwconfig command * shows frequency into proper @@ -5302,7 +5290,7 @@ static int __iw_get_ap_freq(struct net_device *dev, } else { channel = pHddApCtx->operatingChannel; status = hdd_wlan_get_freq(channel, &freq); - if (true == status) { + if (0 == status) { /* Set Exponent parameter as 6 (MHZ) in struct iw_freq * iwlist & iwconfig command shows frequency into proper * format (2.412 GHz instead of 246.2 MHz) @@ -6522,7 +6510,7 @@ QDF_STATUS hdd_init_ap_mode(hdd_adapter_t *pAdapter, bool reinit) ENTER(); hdd_info("SSR in progress: %d", reinit); - + qdf_atomic_init(&pAdapter->sessionCtx.ap.acs_in_progress); if (reinit) sapContext = pAdapter->sessionCtx.ap.sapContext; else { @@ -7918,6 +7906,173 @@ static void hdd_check_and_disconnect_sta_on_invalid_channel( } /** + * wlan_hdd_get_wiphy_channel() - Get wiphy channel + * @wiphy: Pointer to wiphy structure + * @freq: Frequency of the channel for which the wiphy hw value is required + * + * Return: wiphy channel for valid frequency else return NULL + */ +static struct ieee80211_channel *wlan_hdd_get_wiphy_channel( + struct wiphy *wiphy, + uint32_t freq) +{ + uint32_t band_num, channel_num; + struct ieee80211_channel *wiphy_channel = NULL; + + for (band_num = 0; band_num < HDD_NUM_NL80211_BANDS; band_num++) { + for (channel_num = 0; channel_num < + wiphy->bands[band_num]->n_channels; + channel_num++) { + wiphy_channel = &(wiphy->bands[band_num]-> + channels[channel_num]); + if (wiphy_channel->center_freq == freq) + return wiphy_channel; + } + } + return wiphy_channel; +} + +int wlan_hdd_restore_channels(hdd_context_t *hdd_ctx) +{ + struct hdd_cache_channels *cache_chann; + struct wiphy *wiphy; + int freq, status, rf_channel; + int i; + struct ieee80211_channel *wiphy_channel = NULL; + + ENTER(); + + if (!hdd_ctx) { + hdd_err("HDD Context is NULL"); + return -EINVAL; + } + + wiphy = hdd_ctx->wiphy; + if (!wiphy) { + hdd_err("Wiphy is NULL"); + return -EINVAL; + } + + qdf_mutex_acquire(&hdd_ctx->cache_channel_lock); + + cache_chann = hdd_ctx->original_channels; + + if (!cache_chann || !cache_chann->num_channels) { + qdf_mutex_release(&hdd_ctx->cache_channel_lock); + hdd_err("channel list is NULL or num channels are zero"); + return -EINVAL; + } + + for (i = 0; i < cache_chann->num_channels; i++) { + status = hdd_wlan_get_freq( + cache_chann->channel_info[i].channel_num, + &freq); + if (status) + continue; + + wiphy_channel = wlan_hdd_get_wiphy_channel(wiphy, freq); + if (!wiphy_channel) + continue; + rf_channel = wiphy_channel->hw_value; + /* + * Restore the orginal states of the channels + * only if we have cached non zero values + */ + if (cache_chann->channel_info[i].reg_status) + cds_set_channel_state(rf_channel, + cache_chann-> + channel_info[i].reg_status); + + if (cache_chann->channel_info[i].wiphy_status && wiphy_channel) + wiphy_channel->flags = + cache_chann->channel_info[i].wiphy_status; + } + + qdf_mutex_release(&hdd_ctx->cache_channel_lock); + + status = sme_update_channel_list(hdd_ctx->hHal); + if (status) + hdd_err("Can't Restore channel list"); + EXIT(); + + return 0; +} + +/** + * wlan_hdd_disable_channels() - Cache the channels + * and current state of the channels from the channel list + * received in the command and disable the channels on the + * wiphy and reg table. + * @hdd_ctx: Pointer to hdd context + * + * Return: 0 on success, Error code on failure + */ +static int wlan_hdd_disable_channels(hdd_context_t *hdd_ctx) +{ + struct hdd_cache_channels *cache_chann; + struct wiphy *wiphy; + int freq, status, rf_channel; + int i; + struct ieee80211_channel *wiphy_channel = NULL; + + ENTER(); + + if (!hdd_ctx) { + hdd_err("HDD Context is NULL"); + return -EINVAL; + } + + wiphy = hdd_ctx->wiphy; + if (!wiphy) { + hdd_err("Wiphy is NULL"); + return -EINVAL; + } + + qdf_mutex_acquire(&hdd_ctx->cache_channel_lock); + cache_chann = hdd_ctx->original_channels; + + if (!cache_chann || !cache_chann->num_channels) { + qdf_mutex_release(&hdd_ctx->cache_channel_lock); + hdd_err("channel list is NULL or num channels are zero"); + return -EINVAL; + } + + for (i = 0; i < cache_chann->num_channels; i++) { + status = hdd_wlan_get_freq( + cache_chann->channel_info[i].channel_num, + &freq); + if (status) + continue; + wiphy_channel = wlan_hdd_get_wiphy_channel(wiphy, freq); + if (!wiphy_channel) + continue; + rf_channel = wiphy_channel->hw_value; + /* + * Cache the current states of + * the channels + */ + cache_chann->channel_info[i].reg_status = + cds_get_channel_state( + rf_channel); + cache_chann->channel_info[i].wiphy_status = + wiphy_channel->flags; + hdd_debug("Disable channel %d reg_stat %d wiphy_stat 0x%x", + cache_chann->channel_info[i].channel_num, + cache_chann->channel_info[i].reg_status, + wiphy_channel->flags); + + cds_set_channel_state(rf_channel, CHANNEL_STATE_DISABLE); + wiphy_channel->flags |= IEEE80211_CHAN_DISABLED; + } + + qdf_mutex_release(&hdd_ctx->cache_channel_lock); + status = sme_update_channel_list(hdd_ctx->hHal); + + EXIT(); + return status; +} + +/** * wlan_hdd_cfg80211_start_bss() - start bss * @pHostapdAdapter: Pointer to hostapd adapter * @params: Pointer to start bss beacon parameters @@ -8029,6 +8184,17 @@ int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter, pHddCtx); } + if (pHostapdAdapter->device_mode == QDF_SAP_MODE) { + /* + * Disable the channels received in command + * SET_DISABLE_CHANNEL_LIST + */ + status = wlan_hdd_disable_channels(pHddCtx); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Disable channel list fail"); + hdd_check_and_disconnect_sta_on_invalid_channel(pHddCtx); + } + pConfig = &pHostapdAdapter->sessionCtx.ap.sapConfig; pBeacon = pHostapdAdapter->sessionCtx.ap.beacon; @@ -8635,6 +8801,8 @@ int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter, return 0; error: + if (pHostapdAdapter->device_mode == QDF_SAP_MODE) + wlan_hdd_restore_channels(pHddCtx); /* Revert the indoor to passive marking if START BSS fails */ if (iniConfig->disable_indoor_channel) { hdd_update_indoor_channel(pHddCtx, false); @@ -8643,6 +8811,8 @@ error: if (sme_config) qdf_mem_free(sme_config); clear_bit(SOFTAP_INIT_DONE, &pHostapdAdapter->event_flags); + qdf_atomic_set( + &pHostapdAdapter->sessionCtx.ap.acs_in_progress, 0); wlan_hdd_undo_acs(pHostapdAdapter); ret_status: @@ -8779,6 +8949,8 @@ static int __wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy, pConfig = &pAdapter->sessionCtx.ap.sapConfig; pConfig->acs_cfg.acs_mode = false; + qdf_atomic_set( + &pAdapter->sessionCtx.ap.acs_in_progress, 0); wlan_hdd_undo_acs(pAdapter); qdf_mem_zero(&pConfig->acs_cfg, sizeof(struct sap_acs_cfg)); @@ -9092,13 +9264,14 @@ static int __wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy, } if (cds_is_sap_mandatory_chan_list_enabled()) { - if (!cds_get_sap_mandatory_chan_list_len()) - cds_init_sap_mandatory_2g_chan(); - if (CDS_IS_CHANNEL_5GHZ(channel)) { hdd_debug("channel %hu, sap mandatory chan list enabled", channel); + if (!cds_get_sap_mandatory_chan_list_len()) + cds_init_sap_mandatory_2g_chan(); cds_add_sap_mandatory_chan(channel); + } else { + cds_init_sap_mandatory_2g_chan(); } } diff --git a/core/hdd/src/wlan_hdd_hostapd.h b/core/hdd/src/wlan_hdd_hostapd.h index ebc6a7763114..6bff97de826e 100644 --- a/core/hdd/src/wlan_hdd_hostapd.h +++ b/core/hdd/src/wlan_hdd_hostapd.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -137,9 +137,5 @@ bool hdd_is_peer_associated(hdd_adapter_t *adapter, struct qdf_mac_addr *mac_addr); void hdd_sap_indicate_disconnect_for_sta(hdd_adapter_t *adapter); void hdd_sap_destroy_events(hdd_adapter_t *adapter); -void hdd_copy_ht_caps(struct ieee80211_ht_cap *hdd_ht_cap, - tDot11fIEHTCaps *roam_ht_cap); -void hdd_copy_vht_caps(struct ieee80211_vht_cap *hdd_vht_cap, - tDot11fIEVHTCaps *roam_vht_cap); #endif /* end #if !defined(WLAN_HDD_HOSTAPD_H) */ diff --git a/core/hdd/src/wlan_hdd_ioctl.c b/core/hdd/src/wlan_hdd_ioctl.c index daf7cd8f4fe5..3cbd92566d33 100644 --- a/core/hdd/src/wlan_hdd_ioctl.c +++ b/core/hdd/src/wlan_hdd_ioctl.c @@ -566,8 +566,9 @@ static QDF_STATUS hdd_parse_get_ibss_peer_info(uint8_t *pValue, struct qdf_mac_addr *pPeerMacAddr) { uint8_t *inPtr = pValue; + size_t in_ptr_len = strlen(pValue); - inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + inPtr = strnchr(pValue, in_ptr_len, SPACE_ASCII_VALUE); if (NULL == inPtr) return QDF_STATUS_E_FAILURE; @@ -580,10 +581,14 @@ hdd_parse_get_ibss_peer_info(uint8_t *pValue, struct qdf_mac_addr *pPeerMacAddr) if ('\0' == *inPtr) return QDF_STATUS_E_FAILURE; + in_ptr_len -= (inPtr - pValue); + if (in_ptr_len < 17) + return QDF_STATUS_E_FAILURE; + if (inPtr[2] != ':' || inPtr[5] != ':' || inPtr[8] != ':' || - inPtr[11] != ':' || inPtr[14] != ':') { + inPtr[11] != ':' || inPtr[14] != ':') return QDF_STATUS_E_FAILURE; - } + sscanf(inPtr, "%2x:%2x:%2x:%2x:%2x:%2x", (unsigned int *)&pPeerMacAddr->bytes[0], (unsigned int *)&pPeerMacAddr->bytes[1], @@ -5156,9 +5161,6 @@ static int drv_cmd_get_ibss_peer_info_all(hdd_adapter_t *adapter, } hdd_debug("%s", &extra[numOfBytestoPrint]); } - - /* Free temporary buffer */ - qdf_mem_free(extra); } else { /* Command failed, log error */ hdd_err("GETIBSSPEERINFOALL command failed with status code %d", @@ -6858,6 +6860,310 @@ static int drv_cmd_set_channel_switch(hdd_adapter_t *adapter, return 0; } +void wlan_hdd_free_cache_channels(hdd_context_t *hdd_ctx) +{ + ENTER(); + + if (!hdd_ctx->original_channels) + return; + + qdf_mutex_acquire(&hdd_ctx->cache_channel_lock); + hdd_ctx->original_channels->num_channels = 0; + qdf_mem_free(hdd_ctx->original_channels->channel_info); + hdd_ctx->original_channels->channel_info = NULL; + qdf_mem_free(hdd_ctx->original_channels); + hdd_ctx->original_channels = NULL; + qdf_mutex_release(&hdd_ctx->cache_channel_lock); + + EXIT(); +} + +/** + * hdd_alloc_chan_cache() - Allocate the memory to cache the channel + * info for the channels received in command SET_DISABLE_CHANNEL_LIST + * @hdd_ctx: Pointer to HDD context + * @num_chan: Number of channels for which memory needs to + * be allocated + * + * Return: 0 on success and error code on failure + */ +static int hdd_alloc_chan_cache(hdd_context_t *hdd_ctx, int num_chan) +{ + hdd_ctx->original_channels = + qdf_mem_malloc(sizeof(struct hdd_cache_channels)); + if (!hdd_ctx->original_channels) { + hdd_err("QDF_MALLOC_ERR"); + return -ENOMEM; + } + hdd_ctx->original_channels->num_channels = num_chan; + hdd_ctx->original_channels->channel_info = + qdf_mem_malloc(num_chan * + sizeof(struct hdd_cache_channel_info)); + if (!hdd_ctx->original_channels->channel_info) { + hdd_err("QDF_MALLOC_ERR"); + hdd_ctx->original_channels->num_channels = 0; + qdf_mem_free(hdd_ctx->original_channels); + hdd_ctx->original_channels = NULL; + return -ENOMEM; + } + return 0; +} + +/** + * hdd_parse_disable_chan_cmd() - Parse the channel list received + * in command. + * @adapter: pointer to hdd adapter + * @ptr: Pointer to the command string + * + * This function parses the channel list received in the command. + * command should be a string having format + * SET_DISABLE_CHANNEL_LIST <num of channels> + * <channels separated by spaces>. + * If the command comes multiple times than this function will compare + * the channels received in the command with the channles cached in the + * first command, if the channel list matches with the cached channles, + * it returns success otherwise returns failure. + * + * Return: 0 on success, Error code on failure + */ + +static int hdd_parse_disable_chan_cmd(hdd_adapter_t *adapter, uint8_t *ptr) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint8_t *param; + int j, i, temp_int, ret = 0, num_channels; + int parsed_channels[MAX_CHANNEL]; + bool is_command_repeated = false; + + if (NULL == hdd_ctx) { + hdd_err("HDD Context is NULL"); + return -EINVAL; + } + + param = strnchr(ptr, strlen(ptr), ' '); + /*no argument after the command*/ + if (NULL == param) + return -EINVAL; + + /*no space after the command*/ + else if (SPACE_ASCII_VALUE != *param) + return -EINVAL; + + param++; + + /*removing empty spaces*/ + while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param)) + param++; + + /*no argument followed by spaces*/ + if ('\0' == *param) + return -EINVAL; + + /*getting the first argument ie the number of channels*/ + if (sscanf(param, "%d ", &temp_int) != 1) { + hdd_err("Cannot get number of channels from input"); + return -EINVAL; + } + + if (temp_int < 0 || temp_int > MAX_CHANNEL) { + hdd_err("Invalid Number of channel received"); + return -EINVAL; + } + + hdd_debug("Number of channel to disable are: %d", temp_int); + + if (!temp_int) { + if (!wlan_hdd_restore_channels(hdd_ctx)) { + /* + * Free the cache channels only when the command is + * received with num channels as 0 + */ + wlan_hdd_free_cache_channels(hdd_ctx); + } + return 0; + } + + qdf_mutex_acquire(&hdd_ctx->cache_channel_lock); + + if (!hdd_ctx->original_channels) { + if (hdd_alloc_chan_cache(hdd_ctx, temp_int)) { + ret = -ENOMEM; + goto mem_alloc_failed; + } + } else if (hdd_ctx->original_channels->num_channels != temp_int) { + hdd_err("Invalid Number of channels"); + ret = -EINVAL; + is_command_repeated = true; + goto parse_failed; + } else { + is_command_repeated = true; + } + num_channels = temp_int; + for (j = 0; j < num_channels; j++) { + /* + * param pointing to the beginning of first space + * after number of channels + */ + param = strpbrk(param, " "); + /*no channel list after the number of channels argument*/ + if (NULL == param) { + hdd_err("Invalid No of channel provided in the list"); + ret = -EINVAL; + goto parse_failed; + } + + param++; + + /*removing empty space*/ + while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param)) + param++; + + if ('\0' == *param) { + hdd_err("No channel is provided in the list"); + ret = -EINVAL; + goto parse_failed; + } + + if (sscanf(param, "%d ", &temp_int) != 1) { + hdd_err("Cannot read channel number"); + ret = -EINVAL; + goto parse_failed; + } + + if (!IS_CHANNEL_VALID(temp_int)) { + hdd_err("Invalid channel number received"); + ret = -EINVAL; + goto parse_failed; + } + + hdd_debug("channel[%d] = %d", j, temp_int); + parsed_channels[j] = temp_int; + } + + /*extra arguments check*/ + param = strpbrk(param, " "); + if (NULL != param) { + while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param)) + param++; + + if ('\0' != *param) { + hdd_err("Invalid argument received"); + ret = -EINVAL; + goto parse_failed; + } + } + + /* + * If command is received first time, cache the channels to + * be disabled else compare the channels received in the + * command with the cached channels, if channel list matches + * return success otherewise return failure. + */ + if (!is_command_repeated) + for (j = 0; j < num_channels; j++) + hdd_ctx->original_channels-> + channel_info[j].channel_num = + parsed_channels[j]; + else { + for (i = 0; i < num_channels; i++) { + for (j = 0; j < num_channels; j++) + if (hdd_ctx->original_channels-> + channel_info[i].channel_num == + parsed_channels[j]) + break; + if (j == num_channels) { + ret = -EINVAL; + goto parse_failed; + } + } + ret = 0; + } +mem_alloc_failed: + + qdf_mutex_release(&hdd_ctx->cache_channel_lock); + EXIT(); + + return ret; + +parse_failed: + qdf_mutex_release(&hdd_ctx->cache_channel_lock); + if (!is_command_repeated) + wlan_hdd_free_cache_channels(hdd_ctx); + EXIT(); + + return ret; +} + +static int drv_cmd_set_disable_chan_list(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + return hdd_parse_disable_chan_cmd(adapter, command); +} + +/** + * hdd_get_disable_ch_list() - get disable channel list + * @hdd_ctx: hdd context + * @buf: buffer to hold disable channel list + * @buf_len: buffer length + * + * Return: length of data copied to buf + */ +static int hdd_get_disable_ch_list(hdd_context_t *hdd_ctx, uint8_t *buf, + uint32_t buf_len) +{ + struct hdd_cache_channel_info *ch_list; + unsigned char i, num_ch; + int len = 0; + + qdf_mutex_acquire(&hdd_ctx->cache_channel_lock); + if (hdd_ctx->original_channels && + hdd_ctx->original_channels->num_channels && + hdd_ctx->original_channels->channel_info) { + num_ch = hdd_ctx->original_channels->num_channels; + + len = scnprintf(buf, buf_len, "%s %hhu", + "GET_DISABLE_CHANNEL_LIST", num_ch); + ch_list = hdd_ctx->original_channels->channel_info; + for (i = 0; (i < num_ch) && len <= buf_len; i++) { + len += scnprintf(buf + len, buf_len - len, + " %d", ch_list[i].channel_num); + } + } + qdf_mutex_release(&hdd_ctx->cache_channel_lock); + + return len; +} + +static int drv_cmd_get_disable_chan_list(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + char extra[512] = {0}; + int max_len, copied_length; + + hdd_debug("Received Command to get disable Channels list"); + + max_len = QDF_MIN(priv_data->total_len, sizeof(extra)); + copied_length = hdd_get_disable_ch_list(hdd_ctx, extra, max_len); + if (copied_length == 0) { + hdd_err("disable channel list is not yet programmed"); + return -EINVAL; + } + + if (copy_to_user(priv_data->buf, &extra, copied_length + 1)) { + hdd_err("failed to copy data to user buffer"); + return -EFAULT; + } + + hdd_debug("data:%s", extra); + return 0; +} + /* * The following table contains all supported WLAN HDD * IOCTL driver commands and the handler for each of them. @@ -6968,6 +7274,8 @@ static const struct hdd_drv_cmd hdd_drv_cmds[] = { {"CHANNEL_SWITCH", drv_cmd_set_channel_switch, true}, {"SETANTENNAMODE", drv_cmd_set_antenna_mode, true}, {"GETANTENNAMODE", drv_cmd_get_antenna_mode, false}, + {"SET_DISABLE_CHANNEL_LIST", drv_cmd_set_disable_chan_list, true}, + {"GET_DISABLE_CHANNEL_LIST", drv_cmd_get_disable_chan_list, false}, {"STOP", drv_cmd_dummy, false}, }; diff --git a/core/hdd/src/wlan_hdd_ipa.c b/core/hdd/src/wlan_hdd_ipa.c index 2e3420219b88..00022a92d97c 100644 --- a/core/hdd/src/wlan_hdd_ipa.c +++ b/core/hdd/src/wlan_hdd_ipa.c @@ -35,7 +35,12 @@ #ifdef IPA_OFFLOAD /* Include Files */ +#ifdef CONFIG_IPA_WDI_UNIFIED_API +#include <linux/ipa_wdi3.h> +#else #include <linux/ipa.h> +#endif + #include <wlan_hdd_includes.h> #include <wlan_hdd_ipa.h> @@ -92,6 +97,8 @@ #define IPA_WLAN_RX_SOFTIRQ_THRESH 16 +#define HDD_IPA_MAX_BANDWIDTH 800 + enum hdd_ipa_uc_op_code { HDD_IPA_UC_OPCODE_TX_SUSPEND = 0, HDD_IPA_UC_OPCODE_TX_RESUME = 1, @@ -502,6 +509,9 @@ struct hdd_ipa_priv { struct completion ipa_uc_set_quota_comp; #endif struct completion ipa_resource_comp; + + uint32_t wdi_version; + bool is_smmu_enabled; /* IPA caps returned from ipa_wdi_init */ }; #define HDD_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header) @@ -623,22 +633,6 @@ struct hdd_ipa_uc_tx_hdr ipa_uc_tx_hdr = { }; #endif -/* For Tx pipes, use 802.3 Header format */ -static struct hdd_ipa_tx_hdr ipa_tx_hdr = { - { - {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF}, - {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF}, - 0x00 /* length can be zero */ - }, - { - /* LLC SNAP header 8 bytes */ - 0xaa, 0xaa, - {0x03, 0x00, 0x00, 0x00}, - 0x0008 /* type value(2 bytes) ,filled by wlan */ - /* 0x0800 - IPV4, 0x86dd - IPV6 */ - } -}; - #ifdef FEATURE_METERING #define IPA_UC_SHARING_STATES_WAIT_TIME 500 #define IPA_UC_SET_QUOTA_WAIT_TIME 500 @@ -658,30 +652,8 @@ static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type); static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context); static void hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa, bool is_loading); - -#if ((defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)) || \ - defined(IPA_CLIENT_IS_MHI_CONS)) -/** - * hdd_ipa_uc_get_db_paddr() - Get Doorbell physical address - * @db_paddr: Doorbell physical address should be given bu IPA - * @client: IPA client type - * - * Query doorbell physical address from IPA - * IPA will give physical address for TX COMP and RX READY - * - * Return: None - */ -static void hdd_ipa_uc_get_db_paddr(qdf_dma_addr_t *db_paddr, - enum ipa_client_type client) -{ - struct ipa_wdi_db_params dbpa; - - dbpa.client = client; - ipa_uc_wdi_get_dbpa(&dbpa); - *db_paddr = dbpa.uc_door_bell_pa; - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "PROD DB get dbpa 0x%x", - (unsigned int)dbpa.uc_door_bell_pa); -} +static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa); +static int hdd_ipa_wdi_init(struct hdd_ipa_priv *hdd_ipa); /** * hdd_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback @@ -775,58 +747,6 @@ static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl) } /** - * hdd_ipa_uc_register_uc_ready() - Register UC ready callback function to IPA - * @hdd_ipa: HDD IPA local context - * - * Register IPA UC ready callback function to IPA kernel driver - * Even IPA UC loaded later than WLAN kernel driver, WLAN kernel driver will - * open WDI pipe after WLAN driver loading finished - * - * Return: 0 Success - * -EPERM Registration fail - */ -static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa) -{ - struct ipa_wdi_uc_ready_params uc_ready_param; - int ret = 0; - - hdd_ipa->uc_loaded = false; - uc_ready_param.priv = (void *)hdd_ipa; - uc_ready_param.notify = hdd_ipa_uc_loaded_uc_cb; - if (ipa_uc_reg_rdyCB(&uc_ready_param)) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "UC Ready CB register fail"); - return -EPERM; - } - if (true == uc_ready_param.is_uC_ready) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "UC Ready"); - hdd_ipa->uc_loaded = true; - } else { - ret = hdd_ipa_uc_send_wdi_control_msg(false); - } - - return ret; -} -#else -static void hdd_ipa_uc_get_db_paddr(qdf_dma_addr_t *db_paddr, - enum ipa_client_type client) -{ - /* Do nothing */ -} - -static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa) -{ - hdd_ipa->uc_loaded = true; - return 0; -} - -static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl) -{ - return 0; -} -#endif - -/** * hdd_ipa_is_enabled() - Is IPA enabled? * @hdd_ctx: Global HDD context * @@ -947,6 +867,1790 @@ bool hdd_ipa_is_fw_wdi_actived(hdd_context_t *hdd_ctx) return (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe); } +#ifdef FEATURE_METERING +/** + * __hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler. + * IPA calls to get WLAN stats or set quota limit. + * @priv: pointer to private data registered with IPA (we register a + *» pointer to the global IPA context) + * @evt: the IPA event which triggered the callback + * @data: data associated with the event + * + * Return: None + */ +static void __hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt, + void *data) +{ + struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; + hdd_adapter_t *adapter = NULL; + struct ipa_get_wdi_sap_stats *wdi_sap_stats; + struct ipa_set_wifi_quota *ipa_set_quota; + int ret = 0; + + if (wlan_hdd_validate_context(hdd_ipa->hdd_ctx)) + return; + + adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE); + + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "event=%d", evt); + + switch (evt) { + case IPA_GET_WDI_SAP_STATS: + /* fill-up ipa_get_wdi_sap_stats structure after getting + * ipa_uc_fw_stats from FW + */ + wdi_sap_stats = data; + + if (!adapter) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "IPA uC share stats failed - no adapter"); + wdi_sap_stats->stats_valid = 0; + return; + } + + INIT_COMPLETION(hdd_ipa->ipa_uc_sharing_stats_comp); + hdd_ipa_uc_sharing_stats_request(adapter, + wdi_sap_stats->reset_stats); + ret = wait_for_completion_timeout( + &hdd_ipa->ipa_uc_sharing_stats_comp, + msecs_to_jiffies(IPA_UC_SHARING_STATES_WAIT_TIME)); + if (!ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "IPA uC share stats request timed out"); + wdi_sap_stats->stats_valid = 0; + } else { + wdi_sap_stats->stats_valid = 1; + + wdi_sap_stats->ipv4_rx_packets = + hdd_ipa->ipa_sharing_stats.ipv4_rx_packets; + wdi_sap_stats->ipv4_rx_bytes = + hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes; + wdi_sap_stats->ipv6_rx_packets = + hdd_ipa->ipa_sharing_stats.ipv6_rx_packets; + wdi_sap_stats->ipv6_rx_bytes = + hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes; + wdi_sap_stats->ipv4_tx_packets = + hdd_ipa->ipa_sharing_stats.ipv4_tx_packets; + wdi_sap_stats->ipv4_tx_bytes = + hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes; + wdi_sap_stats->ipv6_tx_packets = + hdd_ipa->ipa_sharing_stats.ipv6_tx_packets; + wdi_sap_stats->ipv6_tx_bytes = + hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes; + HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, + "%s:%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu", + "IPA_GET_WDI_SAP_STATS", + wdi_sap_stats->stats_valid, + wdi_sap_stats->ipv4_rx_packets, + wdi_sap_stats->ipv4_rx_bytes, + wdi_sap_stats->ipv6_rx_packets, + wdi_sap_stats->ipv6_rx_bytes, + wdi_sap_stats->ipv4_tx_packets, + wdi_sap_stats->ipv4_tx_bytes, + wdi_sap_stats->ipv6_tx_packets, + wdi_sap_stats->ipv6_tx_bytes); + } + break; + case IPA_SET_WIFI_QUOTA: + /* Get ipa_set_wifi_quota structure from IPA and pass to FW + * through quota_exceeded field in ipa_uc_fw_stats + */ + ipa_set_quota = data; + + if (!adapter) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "IPA uC set quota failed - no adapter"); + ipa_set_quota->set_valid = 0; + return; + } + + INIT_COMPLETION(hdd_ipa->ipa_uc_set_quota_comp); + hdd_ipa_uc_set_quota(adapter, ipa_set_quota->set_quota, + ipa_set_quota->quota_bytes); + + ret = wait_for_completion_timeout( + &hdd_ipa->ipa_uc_set_quota_comp, + msecs_to_jiffies(IPA_UC_SET_QUOTA_WAIT_TIME)); + if (!ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "IPA uC set quota request timed out"); + ipa_set_quota->set_valid = 0; + } else { + ipa_set_quota->quota_bytes = + ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi) + <<32)|hdd_ipa->ipa_quota_rsp.quota_lo; + ipa_set_quota->set_valid = + hdd_ipa->ipa_quota_rsp.success; + } + + HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "SET_QUOTA: %llu, %d", + ipa_set_quota->quota_bytes, + ipa_set_quota->set_valid); + break; + } +} + +/** + * hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler. + * IPA calls to get WLAN stats or set quota limit. + * @priv: pointer to private data registered with IPA (we register a + *» pointer to the global IPA context) + * @evt: the IPA event which triggered the callback + * @data: data associated with the event + * + * Return: None + */ +static void hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt, + void *data) +{ + cds_ssr_protect(__func__); + __hdd_ipa_wdi_meter_notifier_cb(evt, data); + cds_ssr_unprotect(__func__); +} + +#else /* FEATURE_METERING */ +static void hdd_ipa_wdi_init_metering(struct hdd_ipa_priv *ipa_ctxt, void *in) +{ +} +#endif /* FEATURE_METERING */ + +#ifdef CONFIG_IPA_WDI_UNIFIED_API +/* + * TODO: Get WDI version through FW capabilities + */ +#ifdef QCA_WIFI_3_0 +static inline void hdd_ipa_wdi_get_wdi_version(struct hdd_ipa_priv *hdd_ipa) +{ + hdd_ipa->wdi_version = IPA_WDI_2; +} +#else +static inline void hdd_ipa_wdi_get_wdi_version(struct hdd_ipa_priv *hdd_ipa) +{ + hdd_ipa->wdi_version = IPA_WDI_1; +} +#endif + +static bool hdd_ipa_wdi_is_smmu_enabled(struct hdd_ipa_priv *hdd_ipa, + qdf_device_t osdev) +{ + return hdd_ipa->is_smmu_enabled && qdf_mem_smmu_s1_enabled(osdev); +} + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +static bool hdd_ipa_wdi_is_mcc_mode_enabled(struct hdd_ipa_priv *hdd_ipa) +{ + return false; +} +#else +static bool hdd_ipa_wdi_is_mcc_mode_enabled(struct hdd_ipa_priv *hdd_ipa) +{ + return hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx); +} +#endif + +#ifdef FEATURE_METERING +static void hdd_ipa_wdi_init_metering(struct hdd_ipa_priv *ipa_ctxt, void *in) +{ + struct ipa_wdi_init_in_params *wdi3_in; + + wdi3_in = (struct ipa_wdi_init_in_params *)in; + wdi3_in->wdi_notify = hdd_ipa_wdi_meter_notifier_cb; + + init_completion(&ipa_ctxt->ipa_uc_sharing_stats_comp); + init_completion(&ipa_ctxt->ipa_uc_set_quota_comp); +} +#endif + +static int hdd_ipa_wdi_init(struct hdd_ipa_priv *hdd_ipa) +{ + struct ipa_wdi_init_in_params in; + struct ipa_wdi_init_out_params out; + int ret; + + hdd_ipa->uc_loaded = false; + + in.wdi_version = hdd_ipa->wdi_version; + in.notify = hdd_ipa_uc_loaded_uc_cb; + in.priv = (void *)hdd_ipa; + hdd_ipa_wdi_init_metering(hdd_ipa, (void *)&in); + + ret = ipa_wdi_init(&in, &out); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "ipa_wdi_init failed with ret=%d", ret); + return -EPERM; + } + + if (out.is_uC_ready) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "IPA uC READY"); + hdd_ipa->uc_loaded = true; + hdd_ipa->is_smmu_enabled = out.is_smmu_enabled; + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "is_smmu_enabled=%d", + hdd_ipa->is_smmu_enabled); + } else { + ret = -EACCES; + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "IPA uC NOT READY ret=%d", ret); + } + + return ret; +} + +static int hdd_ipa_wdi_cleanup(void) +{ + int ret; + + ret = ipa_wdi_cleanup(); + if (ret) + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "ipa_wdi_cleanup failed ret=%d", ret); + return ret; +} + +static int hdd_ipa_wdi_conn_pipes(struct hdd_ipa_priv *hdd_ipa, + struct ol_txrx_ipa_resources *ipa_res) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *)hdd_ipa->hdd_ctx; + qdf_device_t osdev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + struct ipa_wdi_conn_in_params *in; + struct ipa_wdi_conn_out_params out; + struct ipa_wdi_pipe_setup_info *info; + struct ipa_wdi_pipe_setup_info_smmu *info_smmu; + struct ipa_ep_cfg *tx_cfg; + struct ipa_ep_cfg *rx_cfg; + int ret; + int i; + + in = qdf_mem_malloc(sizeof(*in)); + if (!in) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "failed to alloc ipa_wdi_conn_in_params"); + return -ENOMEM; + } + + /* IPA RX exception packets callback */ + in->notify = hdd_ipa_w2i_cb; + in->priv = hdd_ctx->hdd_ipa; + + if (hdd_ipa_wdi_is_mcc_mode_enabled(hdd_ipa)) { + in->num_sys_pipe_needed = HDD_IPA_MAX_IFACE; + for (i = 0; i < in->num_sys_pipe_needed; i++) + memcpy(&in->sys_in[i], + &hdd_ipa->sys_pipe[i].ipa_sys_params, + sizeof(struct ipa_sys_connect_params)); + } else { + in->num_sys_pipe_needed = 0; + } + + if (hdd_ipa_wdi_is_smmu_enabled(hdd_ipa, osdev)) + in->is_smmu_enabled = true; + else + in->is_smmu_enabled = false; + + if (in->is_smmu_enabled) { + tx_cfg = &in->u_tx.tx_smmu.ipa_ep_cfg; + rx_cfg = &in->u_rx.rx_smmu.ipa_ep_cfg; + } else { + tx_cfg = &in->u_tx.tx.ipa_ep_cfg; + rx_cfg = &in->u_rx.rx.ipa_ep_cfg; + } + + tx_cfg->nat.nat_en = IPA_BYPASS_NAT; + tx_cfg->hdr.hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN; + tx_cfg->hdr.hdr_ofst_pkt_size_valid = 1; + tx_cfg->hdr.hdr_ofst_pkt_size = 0; + tx_cfg->hdr.hdr_additional_const_len = + HDD_IPA_UC_WLAN_8023_HDR_SIZE; + tx_cfg->hdr_ext.hdr_little_endian = true; + tx_cfg->mode.mode = IPA_BASIC; + + rx_cfg->nat.nat_en = IPA_BYPASS_NAT; + rx_cfg->hdr.hdr_len = HDD_IPA_UC_WLAN_RX_HDR_LEN; + rx_cfg->hdr.hdr_ofst_pkt_size_valid = 1; + rx_cfg->hdr.hdr_ofst_pkt_size = 0; + rx_cfg->hdr.hdr_additional_const_len = + HDD_IPA_UC_WLAN_8023_HDR_SIZE; + rx_cfg->hdr_ext.hdr_little_endian = true; + rx_cfg->hdr.hdr_ofst_metadata_valid = 0; + rx_cfg->hdr.hdr_metadata_reg_valid = 1; + rx_cfg->mode.mode = IPA_BASIC; + + if (in->is_smmu_enabled) { + /* TX */ + info_smmu = &in->u_tx.tx_smmu; + info_smmu->client = IPA_CLIENT_WLAN1_CONS; + + qdf_mem_copy(&info_smmu->transfer_ring_base, + &ipa_res->tx_comp_ring->sgtable, + sizeof(sgtable_t)); + info_smmu->transfer_ring_size = + ipa_res->tx_comp_ring->mem_info.size; + + qdf_mem_copy(&info_smmu->event_ring_base, + &ipa_res->ce_sr->sgtable, sizeof(sgtable_t)); + info_smmu->event_ring_size = ipa_res->ce_sr_ring_size; + info_smmu->event_ring_doorbell_pa = ipa_res->ce_reg_paddr; + info_smmu->num_pkt_buffers = ipa_res->tx_num_alloc_buffer; + + /* RX */ + info_smmu = &in->u_rx.rx_smmu; + info_smmu->client = IPA_CLIENT_WLAN1_PROD; + + qdf_mem_copy(&info_smmu->transfer_ring_base, + &ipa_res->rx_rdy_ring->sgtable, + sizeof(sgtable_t)); + info_smmu->transfer_ring_size = + ipa_res->rx_rdy_ring->mem_info.size; + info_smmu->transfer_ring_doorbell_pa = + ipa_res->rx_proc_done_idx->mem_info.pa; + + qdf_mem_copy(&info_smmu->event_ring_base, + &ipa_res->rx2_rdy_ring->sgtable, + sizeof(sgtable_t)); + info_smmu->event_ring_size = + ipa_res->rx2_rdy_ring->mem_info.size; + info_smmu->event_ring_doorbell_pa = + ipa_res->rx2_proc_done_idx->mem_info.pa; + } else { + /* TX */ + info = &in->u_tx.tx; + + info->client = IPA_CLIENT_WLAN1_CONS; + + info->transfer_ring_base_pa = qdf_mem_get_dma_addr(osdev, + &ipa_res->tx_comp_ring->mem_info); + info->transfer_ring_size = + ipa_res->tx_comp_ring->mem_info.size; + + info->event_ring_base_pa = qdf_mem_get_dma_addr(osdev, + &ipa_res->ce_sr->mem_info); + info->event_ring_size = ipa_res->ce_sr_ring_size; + info->event_ring_doorbell_pa = ipa_res->ce_reg_paddr; + info->num_pkt_buffers = ipa_res->tx_num_alloc_buffer; + + /* RX */ + info = &in->u_rx.rx; + + info->client = IPA_CLIENT_WLAN1_PROD; + + info->transfer_ring_base_pa = + ipa_res->rx_rdy_ring->mem_info.pa; + info->transfer_ring_size = + ipa_res->rx_rdy_ring->mem_info.size; + info->transfer_ring_doorbell_pa = + ipa_res->rx_proc_done_idx->mem_info.pa; + + if (hdd_ipa->wdi_version == IPA_WDI_2) { + info->event_ring_base_pa = qdf_mem_get_dma_addr(osdev, + &ipa_res->rx2_rdy_ring->mem_info); + info->event_ring_size = + ipa_res->rx2_rdy_ring->mem_info.size; + info->event_ring_doorbell_pa = + qdf_mem_get_dma_addr(osdev, + &ipa_res->rx2_proc_done_idx->mem_info); + } + } + + ret = ipa_wdi_conn_pipes(in, &out); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "ipa_wdi_conn_pipes failed ret=%d", ret); + qdf_mem_free(in); + return ret; + } + + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "out.tx_uc_db_pa 0x%x out.rx_uc_db_pa 0x%x", + out.tx_uc_db_pa, out.rx_uc_db_pa); + + hdd_ipa->tx_comp_doorbell_dmaaddr = out.tx_uc_db_pa; + hdd_ipa->rx_ready_doorbell_dmaaddr = out.rx_uc_db_pa; + + qdf_mem_free(in); + + return 0; +} + +static int hdd_ipa_wdi_disconn_pipes(struct hdd_ipa_priv *hdd_ipa) +{ + int ret; + + ret = ipa_wdi_disconn_pipes(); + if (ret) + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "ipa_wdi_disconn_pipes failed ret=%d", ret); + return ret; +} + +static int hdd_ipa_wdi_reg_intf(struct hdd_ipa_priv *hdd_ipa, + struct hdd_ipa_iface_context *iface_context) +{ + hdd_adapter_t *adapter = iface_context->adapter; + struct ipa_wdi_reg_intf_in_params in; + struct hdd_ipa_uc_tx_hdr uc_tx_hdr; + struct hdd_ipa_uc_tx_hdr uc_tx_hdr_v6; + int ret; + + memcpy(&uc_tx_hdr, &ipa_uc_tx_hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN); + memcpy(&uc_tx_hdr.eth.h_source, adapter->dev->dev_addr, ETH_ALEN); + uc_tx_hdr.ipa_hd.vdev_id = iface_context->adapter->sessionId; + + in.netdev_name = adapter->dev->name; + in.hdr_info[IPA_IP_v4].hdr = (u8 *)&uc_tx_hdr; + in.hdr_info[IPA_IP_v4].hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN; + in.hdr_info[IPA_IP_v4].dst_mac_addr_offset = + HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET; + in.hdr_info[IPA_IP_v4].hdr_type = IPA_HDR_L2_ETHERNET_II; + + if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) { + memcpy(&uc_tx_hdr_v6, &ipa_uc_tx_hdr, + HDD_IPA_UC_WLAN_TX_HDR_LEN); + memcpy(&uc_tx_hdr_v6.eth.h_source, adapter->dev->dev_addr, + ETH_ALEN); + uc_tx_hdr_v6.ipa_hd.vdev_id = iface_context->adapter->sessionId; + uc_tx_hdr_v6.eth.h_proto = cpu_to_be16(ETH_P_IPV6); + + in.netdev_name = adapter->dev->name; + in.hdr_info[IPA_IP_v6].hdr = (u8 *)&uc_tx_hdr_v6; + in.hdr_info[IPA_IP_v6].hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN; + in.hdr_info[IPA_IP_v6].dst_mac_addr_offset = + HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET; + in.hdr_info[IPA_IP_v6].hdr_type = IPA_HDR_L2_ETHERNET_II; + } + + in.alt_dst_pipe = iface_context->cons_client; + in.is_meta_data_valid = 1; + in.meta_data = htonl(iface_context->adapter->sessionId << 16); + in.meta_data_mask = htonl(0x00FF0000); + + ret = ipa_wdi_reg_intf(&in); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "ipa_wdi_reg_intf failed ret=%d", ret); + return ret; + } + + return 0; +} + +static int hdd_ipa_wdi_dereg_intf(struct hdd_ipa_priv *hdd_ipa, + const char *devname) +{ + int ret; + + ret = ipa_wdi_dereg_intf(devname); + if (ret) + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "ipa_wdi_dereg_intf failed ret=%d", ret); + return ret; +} + +static int hdd_ipa_wdi_enable_pipes(struct hdd_ipa_priv *hdd_ipa) +{ + int ret; + + ret = ipa_wdi_enable_pipes(); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "ipa_wdi_enable_pipes failed ret=%d", ret); + return ret; + } + + return 0; +} + +static int hdd_ipa_wdi_disable_pipes(struct hdd_ipa_priv *hdd_ipa) +{ + int ret; + + ret = ipa_wdi_disable_pipes(); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "ipa_wdi_disable_pipes failed ret=%d", ret); + return ret; + } + + return 0; +} + +static inline int hdd_ipa_wdi_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa, + struct ipa_sys_connect_params *sys, uint32_t *handle) +{ + return 0; +} + +static inline int hdd_ipa_wdi_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa, + uint32_t handle) +{ + return 0; +} + +static inline int hdd_ipa_wdi_rm_set_perf_profile(struct hdd_ipa_priv *hdd_ipa, + enum ipa_rm_resource_name resource_name, + struct ipa_rm_perf_profile *profile) +{ + return 0; +} + +static inline int hdd_ipa_wdi_rm_request_resource(struct hdd_ipa_priv *hdd_ipa, + enum ipa_rm_resource_name res_name) +{ + return 0; +} + +static inline int hdd_ipa_wdi_rm_release_resource(struct hdd_ipa_priv *hdd_ipa, + enum ipa_rm_resource_name res_name) +{ + return 0; +} + +static inline int hdd_ipa_wdi_setup_rm(struct hdd_ipa_priv *hdd_ipa) +{ + return 0; +} + +static inline int hdd_ipa_wdi_destroy_rm(struct hdd_ipa_priv *hdd_ipa) +{ + return 0; +} + +static inline int hdd_ipa_wdi_rm_request(struct hdd_ipa_priv *hdd_ipa) +{ + return 0; +} + +static inline int hdd_ipa_wdi_rm_try_release(struct hdd_ipa_priv *hdd_ipa) +{ + return 0; +} + +static inline int hdd_ipa_wdi_rm_notify_completion(enum ipa_rm_event event, + enum ipa_rm_resource_name resource_name) +{ + return 0; +} +#else /* CONFIG_IPA_WDI_UNIFIED_API */ +static inline void hdd_ipa_wdi_get_wdi_version(struct hdd_ipa_priv *hdd_ipa) +{ +} + +static int hdd_ipa_wdi_is_smmu_enabled(struct hdd_ipa_priv *hdd_ipa, + qdf_device_t osdev) +{ + return qdf_mem_smmu_s1_enabled(osdev); +} + +#ifdef FEATURE_METERING +static void hdd_ipa_wdi_init_metering(struct hdd_ipa_priv *ipa_ctxt, void *in) +{ + struct ipa_wdi_in_params *wdi_in; + + wdi_in = (struct ipa_wdi_in_params *)in; + wdi_in->wdi_notify = hdd_ipa_wdi_meter_notifier_cb; + + init_completion(&ipa_ctxt->ipa_uc_sharing_stats_comp); + init_completion(&ipa_ctxt->ipa_uc_set_quota_comp); +} +#endif + +static int hdd_ipa_wdi_init(struct hdd_ipa_priv *hdd_ipa) +{ + struct ipa_wdi_uc_ready_params uc_ready_param; + int ret = 0; + + hdd_ipa->uc_loaded = false; + uc_ready_param.priv = (void *)hdd_ipa; + uc_ready_param.notify = hdd_ipa_uc_loaded_uc_cb; + if (ipa_uc_reg_rdyCB(&uc_ready_param)) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "UC Ready CB register fail"); + return -EPERM; + } + + if (true == uc_ready_param.is_uC_ready) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "UC Ready"); + hdd_ipa->uc_loaded = true; + } else { + ret = -EACCES; + } + + return ret; +} + +static int hdd_ipa_wdi_cleanup(void) +{ + int ret; + + ret = ipa_uc_dereg_rdyCB(); + if (ret) + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "UC Ready CB deregister fail"); + return ret; +} + +static int hdd_ipa_wdi_conn_pipes(struct hdd_ipa_priv *hdd_ipa, + struct ol_txrx_ipa_resources *ipa_res) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *)hdd_ipa->hdd_ctx; + struct ipa_wdi_in_params pipe_in; + struct ipa_wdi_out_params pipe_out; + QDF_STATUS stat = QDF_STATUS_SUCCESS; + qdf_device_t osdev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + int ret; + + qdf_mem_zero(&hdd_ipa->cons_pipe_in, sizeof(struct ipa_wdi_in_params)); + qdf_mem_zero(&hdd_ipa->prod_pipe_in, sizeof(struct ipa_wdi_in_params)); + qdf_mem_zero(&pipe_in, sizeof(struct ipa_wdi_in_params)); + qdf_mem_zero(&pipe_out, sizeof(struct ipa_wdi_out_params)); + + /* TX PIPE */ + pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_additional_const_len = + HDD_IPA_UC_WLAN_8023_HDR_SIZE; + pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC; + pipe_in.sys.client = IPA_CLIENT_WLAN1_CONS; + pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize; + pipe_in.sys.priv = hdd_ctx->hdd_ipa; + pipe_in.sys.ipa_ep_cfg.hdr_ext.hdr_little_endian = true; + pipe_in.sys.notify = hdd_ipa_i2w_cb; + if (!hdd_ipa_is_rm_enabled(hdd_ctx)) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, + "IPA RM DISABLED, IPA AWAKE"); + pipe_in.sys.keep_ipa_awake = true; + } + + pipe_in.smmu_enabled = hdd_ipa_wdi_is_smmu_enabled(hdd_ipa, osdev); + if (pipe_in.smmu_enabled) { + qdf_mem_copy(&pipe_in.u.dl_smmu.comp_ring, + &ipa_res->tx_comp_ring->sgtable, + sizeof(sgtable_t)); + + qdf_mem_copy(&pipe_in.u.dl_smmu.ce_ring, + &ipa_res->ce_sr->sgtable, + sizeof(sgtable_t)); + pipe_in.u.dl_smmu.comp_ring_size = + ipa_res->tx_comp_ring->mem_info.size; + pipe_in.u.dl_smmu.ce_ring_size = + ipa_res->ce_sr_ring_size; + pipe_in.u.dl_smmu.ce_door_bell_pa = + ipa_res->ce_reg_paddr; + pipe_in.u.dl_smmu.num_tx_buffers = + ipa_res->tx_num_alloc_buffer; + } else { + pipe_in.u.dl.comp_ring_base_pa = + qdf_mem_get_dma_addr(osdev, + &ipa_res->tx_comp_ring->mem_info); + pipe_in.u.dl.ce_ring_base_pa = + qdf_mem_get_dma_addr(osdev, + &ipa_res->ce_sr->mem_info); + pipe_in.u.dl.comp_ring_size = + ipa_res->tx_comp_ring->mem_info.size; + pipe_in.u.dl.ce_door_bell_pa = ipa_res->ce_reg_paddr; + pipe_in.u.dl.ce_ring_size = + ipa_res->ce_sr_ring_size; + pipe_in.u.dl.num_tx_buffers = + ipa_res->tx_num_alloc_buffer; + } + + qdf_mem_copy(&hdd_ipa->cons_pipe_in, &pipe_in, + sizeof(struct ipa_wdi_in_params)); + + /* Connect WDI IPA PIPE */ + ret = ipa_connect_wdi_pipe(&hdd_ipa->cons_pipe_in, &pipe_out); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "ipa_connect_wdi_pipe failed for Tx: ret=%d", + ret); + stat = QDF_STATUS_E_FAILURE; + goto fail_return; + } + + /* Micro Controller Doorbell register */ + hdd_ipa->tx_comp_doorbell_dmaaddr = pipe_out.uc_door_bell_pa; + + /* WLAN TX PIPE Handle */ + hdd_ipa->tx_pipe_handle = pipe_out.clnt_hdl; + + if (hdd_ipa->tx_pipe_handle == 0) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "TX Handle zero"); + QDF_BUG(0); + } + + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "CONS DB pipe out 0x%x TX PIPE Handle 0x%x", + (unsigned int)pipe_out.uc_door_bell_pa, + hdd_ipa->tx_pipe_handle); + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, + "TX : CRBPA 0x%x, CRS %d, CERBPA 0x%x, CEDPA 0x%x," + " CERZ %d, NB %d, CDBPAD 0x%x", + (unsigned int)pipe_in.u.dl.comp_ring_base_pa, + pipe_in.u.dl.comp_ring_size, + (unsigned int)pipe_in.u.dl.ce_ring_base_pa, + (unsigned int)pipe_in.u.dl.ce_door_bell_pa, + pipe_in.u.dl.ce_ring_size, + pipe_in.u.dl.num_tx_buffers, + (unsigned int)hdd_ipa->tx_comp_doorbell_dmaaddr); + + /* RX PIPE */ + pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_RX_HDR_LEN; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 0; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_metadata_reg_valid = 1; + pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC; + pipe_in.sys.client = IPA_CLIENT_WLAN1_PROD; + pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize + + sizeof(struct sps_iovec); + pipe_in.sys.notify = hdd_ipa_w2i_cb; + if (!hdd_ipa_is_rm_enabled(hdd_ctx)) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "IPA RM DISABLED, IPA AWAKE"); + pipe_in.sys.keep_ipa_awake = true; + } + + pipe_in.smmu_enabled = hdd_ipa_wdi_is_smmu_enabled(hdd_ipa, osdev); + if (pipe_in.smmu_enabled) { + qdf_mem_copy(&pipe_in.u.ul_smmu.rdy_ring, + &ipa_res->rx_rdy_ring->sgtable, + sizeof(sgtable_t)); + pipe_in.u.ul_smmu.rdy_ring_size = + ipa_res->rx_rdy_ring->mem_info.size; + pipe_in.u.ul_smmu.rdy_ring_rp_pa = + ipa_res->rx_proc_done_idx->mem_info.pa; + + pipe_in.u.ul_smmu.rdy_ring_rp_va = + ipa_res->rx_proc_done_idx->vaddr; + + qdf_mem_copy(&pipe_in.u.ul_smmu.rdy_comp_ring, + &ipa_res->rx2_rdy_ring->sgtable, + sizeof(sgtable_t)); + + pipe_in.u.ul_smmu.rdy_comp_ring_size = + ipa_res->rx2_rdy_ring->mem_info.size; + + pipe_in.u.ul_smmu.rdy_comp_ring_wp_pa = + ipa_res->rx2_proc_done_idx->mem_info.pa; + + pipe_in.u.ul_smmu.rdy_comp_ring_wp_va = + ipa_res->rx2_proc_done_idx->vaddr; + } else { + pipe_in.u.ul.rdy_ring_base_pa = + ipa_res->rx_rdy_ring->mem_info.pa; + pipe_in.u.ul.rdy_ring_size = + ipa_res->rx_rdy_ring->mem_info.size; + pipe_in.u.ul.rdy_ring_rp_pa = + ipa_res->rx_proc_done_idx->mem_info.pa; + HDD_IPA_WDI2_SET(pipe_in, hdd_ipa, osdev); + } + + hdd_ipa_wdi_init_metering(hdd_ipa, (void *)&pipe_in); + + qdf_mem_copy(&hdd_ipa->prod_pipe_in, &pipe_in, + sizeof(struct ipa_wdi_in_params)); + + ret = ipa_connect_wdi_pipe(&hdd_ipa->prod_pipe_in, &pipe_out); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "ipa_connect_wdi_pipe failed for Rx: ret=%d", + ret); + stat = QDF_STATUS_E_FAILURE; + ret = ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle); + if (ret) + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "disconnect failed for TX: ret=%d", + ret); + goto fail_return; + } + hdd_ipa->rx_ready_doorbell_dmaaddr = pipe_out.uc_door_bell_pa; + hdd_ipa->rx_pipe_handle = pipe_out.clnt_hdl; + if (hdd_ipa->rx_pipe_handle == 0) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "RX Handle zero"); + QDF_BUG(0); + } + + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "PROD DB pipe out 0x%x RX PIPE Handle 0x%x", + (unsigned int)pipe_out.uc_door_bell_pa, + hdd_ipa->rx_pipe_handle); + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, + "RX : RRBPA 0x%x, RRS %d, PDIPA 0x%x, RDY_DB_PAD 0x%x", + (unsigned int)pipe_in.u.ul.rdy_ring_base_pa, + pipe_in.u.ul.rdy_ring_size, + (unsigned int)pipe_in.u.ul.rdy_ring_rp_pa, + (unsigned int)hdd_ipa->rx_ready_doorbell_dmaaddr); + +fail_return: + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit: stat=%d", stat); + return stat; +} + +static int hdd_ipa_wdi_disconn_pipes(struct hdd_ipa_priv *hdd_ipa) +{ + int ret; + + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "Disconnect TX PIPE tx_pipe_handle=0x%x", + hdd_ipa->tx_pipe_handle); + ret = ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle); + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "Disconnect RX PIPE rx_pipe_handle=0x%x", + hdd_ipa->rx_pipe_handle); + ret = ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle); + + return ret; +} + +/** + * hdd_remove_ipa_header() - Remove a specific header from IPA + * @name: Name of the header to be removed + * + * Return: None + */ +static void hdd_ipa_remove_header(char *name) +{ + struct ipa_ioc_get_hdr hdrlookup; + int ret = 0, len; + struct ipa_ioc_del_hdr *ipa_hdr; + + qdf_mem_zero(&hdrlookup, sizeof(hdrlookup)); + strlcpy(hdrlookup.name, name, sizeof(hdrlookup.name)); + ret = ipa_get_hdr(&hdrlookup); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Hdr deleted already %s, %d", + name, ret); + return; + } + + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "hdl: 0x%x", hdrlookup.hdl); + len = sizeof(struct ipa_ioc_del_hdr) + sizeof(struct ipa_hdr_del) * 1; + ipa_hdr = (struct ipa_ioc_del_hdr *)qdf_mem_malloc(len); + if (ipa_hdr == NULL) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "ipa_hdr allocation failed"); + return; + } + ipa_hdr->num_hdls = 1; + ipa_hdr->commit = 0; + ipa_hdr->hdl[0].hdl = hdrlookup.hdl; + ipa_hdr->hdl[0].status = -1; + ret = ipa_del_hdr(ipa_hdr); + if (ret != 0) + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Delete header failed: %d", + ret); + + qdf_mem_free(ipa_hdr); +} + +/** + * wlan_ipa_add_hdr() - Add IPA Tx header + * @ipa_hdr: pointer to IPA header addition parameters + * + * Call IPA API to add IPA Tx header descriptor + * and dump Tx header struct + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_ipa_add_hdr(struct ipa_ioc_add_hdr *ipa_hdr) +{ + int ret; + + hdd_debug("==== IPA Tx Header ====\n" + "name: %s\n" + "hdr_len: %d\n" + "type: %d\n" + "is_partial: %d\n" + "hdr_hdl: 0x%x\n" + "status: %d\n" + "is_eth2_ofst_valid: %d\n" + "eth2_ofst: %d\n", + ipa_hdr->hdr[0].name, + ipa_hdr->hdr[0].hdr_len, + ipa_hdr->hdr[0].type, + ipa_hdr->hdr[0].is_partial, + ipa_hdr->hdr[0].hdr_hdl, + ipa_hdr->hdr[0].status, + ipa_hdr->hdr[0].is_eth2_ofst_valid, + ipa_hdr->hdr[0].eth2_ofst); + + HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG, "hdr:", + ipa_hdr->hdr[0].hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN); + + ret = ipa_add_hdr(ipa_hdr); + return ret; +} + +/* For Tx pipes, use 802.3 Header format */ +static struct hdd_ipa_tx_hdr ipa_tx_hdr = { + { + {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF}, + {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF}, + 0x00 /* length can be zero */ + }, + { + /* LLC SNAP header 8 bytes */ + 0xaa, 0xaa, + {0x03, 0x00, 0x00, 0x00}, + 0x0008 /* type value(2 bytes) ,filled by wlan */ + /* 0x0800 - IPV4, 0x86dd - IPV6 */ + } +}; + +/** + * hdd_ipa_add_header_info() - Add IPA header for a given interface + * @hdd_ipa: Global HDD IPA context + * @iface_context: Interface-specific HDD IPA context + * @mac_addr: Interface MAC address + * + * Return: 0 on success, negativer errno value on error + */ +static int hdd_ipa_add_header_info(struct hdd_ipa_priv *hdd_ipa, + struct hdd_ipa_iface_context *iface_context, + uint8_t *mac_addr) +{ + hdd_adapter_t *adapter = iface_context->adapter; + char *ifname; + struct ipa_ioc_add_hdr *ipa_hdr = NULL; + int ret = -EINVAL; + struct hdd_ipa_tx_hdr *tx_hdr = NULL; + struct hdd_ipa_uc_tx_hdr *uc_tx_hdr = NULL; + + ifname = adapter->dev->name; + + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Add Partial hdr: %s, %pM", + ifname, mac_addr); + + /* dynamically allocate the memory to add the hdrs */ + ipa_hdr = qdf_mem_malloc(sizeof(struct ipa_ioc_add_hdr) + + sizeof(struct ipa_hdr_add)); + if (!ipa_hdr) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: ipa_hdr allocation failed", ifname); + ret = -ENOMEM; + goto end; + } + + ipa_hdr->commit = 0; + ipa_hdr->num_hdrs = 1; + + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + uc_tx_hdr = (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr; + memcpy(uc_tx_hdr, &ipa_uc_tx_hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN); + memcpy(uc_tx_hdr->eth.h_source, mac_addr, ETH_ALEN); + uc_tx_hdr->ipa_hd.vdev_id = iface_context->adapter->sessionId; + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, + "ifname=%s, vdev_id=%d", + ifname, uc_tx_hdr->ipa_hd.vdev_id); + snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, HDD_IPA_IPV4_NAME_EXT); + ipa_hdr->hdr[0].hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN; + ipa_hdr->hdr[0].type = IPA_HDR_L2_ETHERNET_II; + ipa_hdr->hdr[0].is_partial = 1; + ipa_hdr->hdr[0].hdr_hdl = 0; + ipa_hdr->hdr[0].is_eth2_ofst_valid = 1; + ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET; + + ret = wlan_ipa_add_hdr(ipa_hdr); + } else { + tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr; + + /* Set the Source MAC */ + memcpy(tx_hdr, &ipa_tx_hdr, HDD_IPA_WLAN_TX_HDR_LEN); + memcpy(tx_hdr->eth.h_source, mac_addr, ETH_ALEN); + + snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, HDD_IPA_IPV4_NAME_EXT); + ipa_hdr->hdr[0].hdr_len = HDD_IPA_WLAN_TX_HDR_LEN; + ipa_hdr->hdr[0].is_partial = 1; + ipa_hdr->hdr[0].hdr_hdl = 0; + ipa_hdr->hdr[0].is_eth2_ofst_valid = 1; + ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_WLAN_HDR_DES_MAC_OFFSET; + + /* Set the type to IPV4 in the header */ + tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IP); + + ret = ipa_add_hdr(ipa_hdr); + } + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: IPv4 add hdr failed: %d", ifname, ret); + goto end; + } + + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: IPv4 hdr_hdl: 0x%x", + ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl); + + if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) { + snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, HDD_IPA_IPV6_NAME_EXT); + + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + uc_tx_hdr = + (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr; + uc_tx_hdr->eth.h_proto = cpu_to_be16(ETH_P_IPV6); + ret = wlan_ipa_add_hdr(ipa_hdr); + } else { + /* Set the type to IPV6 in the header */ + tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr; + tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IPV6); + ret = ipa_add_hdr(ipa_hdr); + } + + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: IPv6 add hdr failed: %d", ifname, ret); + goto clean_ipv4_hdr; + } + + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: IPv6 hdr_hdl: 0x%x", + ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl); + } + + qdf_mem_free(ipa_hdr); + + return ret; + +clean_ipv4_hdr: + snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, HDD_IPA_IPV4_NAME_EXT); + hdd_ipa_remove_header(ipa_hdr->hdr[0].name); +end: + if (ipa_hdr) + qdf_mem_free(ipa_hdr); + + return ret; +} + +/** + * hdd_ipa_register_interface() - register IPA interface + * @hdd_ipa: Global IPA context + * @iface_context: Per-interface IPA context + * + * Return: 0 on success, negative errno on error + */ +static int hdd_ipa_register_interface(struct hdd_ipa_priv *hdd_ipa, + struct hdd_ipa_iface_context + *iface_context) +{ + struct ipa_tx_intf tx_intf; + struct ipa_rx_intf rx_intf; + struct ipa_ioc_tx_intf_prop *tx_prop = NULL; + struct ipa_ioc_rx_intf_prop *rx_prop = NULL; + char *ifname = iface_context->adapter->dev->name; + + char ipv4_hdr_name[IPA_RESOURCE_NAME_MAX]; + char ipv6_hdr_name[IPA_RESOURCE_NAME_MAX]; + + int num_prop = 1; + int ret = 0; + + if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) + num_prop++; + + /* Allocate TX properties for TOS categories, 1 each for IPv4 & IPv6 */ + tx_prop = + qdf_mem_malloc(sizeof(struct ipa_ioc_tx_intf_prop) * num_prop); + if (!tx_prop) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "tx_prop allocation failed"); + goto register_interface_fail; + } + + /* Allocate RX properties, 1 each for IPv4 & IPv6 */ + rx_prop = + qdf_mem_malloc(sizeof(struct ipa_ioc_rx_intf_prop) * num_prop); + if (!rx_prop) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "rx_prop allocation failed"); + goto register_interface_fail; + } + + qdf_mem_zero(&tx_intf, sizeof(tx_intf)); + qdf_mem_zero(&rx_intf, sizeof(rx_intf)); + + snprintf(ipv4_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, HDD_IPA_IPV4_NAME_EXT); + snprintf(ipv6_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, HDD_IPA_IPV6_NAME_EXT); + + rx_prop[IPA_IP_v4].ip = IPA_IP_v4; + rx_prop[IPA_IP_v4].src_pipe = iface_context->prod_client; + rx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; + rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA; + + /* + * Interface ID is 3rd byte in the CLD header. Add the meta data and + * mask to identify the interface in IPA hardware + */ + rx_prop[IPA_IP_v4].attrib.meta_data = + htonl(iface_context->adapter->sessionId << 16); + rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000); + + rx_intf.num_props++; + if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) { + rx_prop[IPA_IP_v6].ip = IPA_IP_v6; + rx_prop[IPA_IP_v6].src_pipe = iface_context->prod_client; + rx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; + rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA; + rx_prop[IPA_IP_v4].attrib.meta_data = + htonl(iface_context->adapter->sessionId << 16); + rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000); + + rx_intf.num_props++; + } + + tx_prop[IPA_IP_v4].ip = IPA_IP_v4; + tx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; + tx_prop[IPA_IP_v4].dst_pipe = IPA_CLIENT_WLAN1_CONS; + tx_prop[IPA_IP_v4].alt_dst_pipe = iface_context->cons_client; + strlcpy(tx_prop[IPA_IP_v4].hdr_name, ipv4_hdr_name, + IPA_RESOURCE_NAME_MAX); + tx_intf.num_props++; + + if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) { + tx_prop[IPA_IP_v6].ip = IPA_IP_v6; + tx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; + tx_prop[IPA_IP_v6].dst_pipe = IPA_CLIENT_WLAN1_CONS; + tx_prop[IPA_IP_v6].alt_dst_pipe = iface_context->cons_client; + strlcpy(tx_prop[IPA_IP_v6].hdr_name, ipv6_hdr_name, + IPA_RESOURCE_NAME_MAX); + tx_intf.num_props++; + } + + tx_intf.prop = tx_prop; + rx_intf.prop = rx_prop; + + /* Call the ipa api to register interface */ + ret = ipa_register_intf(ifname, &tx_intf, &rx_intf); + +register_interface_fail: + qdf_mem_free(tx_prop); + qdf_mem_free(rx_prop); + return ret; +} + +static int hdd_ipa_wdi_reg_intf(struct hdd_ipa_priv *hdd_ipa, + struct hdd_ipa_iface_context *iface_context) +{ + int ret; + + ret = hdd_ipa_add_header_info(hdd_ipa, iface_context, + iface_context->adapter->dev->dev_addr); + + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "ipa add header failed ret=%d", ret); + return ret; + } + + /* Configure the TX and RX pipes filter rules */ + ret = hdd_ipa_register_interface(hdd_ipa, iface_context); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "ipa register interface failed ret=%d", ret); + return ret; + } + + return 0; +} + +static int hdd_ipa_wdi_dereg_intf(struct hdd_ipa_priv *hdd_ipa, + const char *devname) +{ + char name_ipa[IPA_RESOURCE_NAME_MAX]; + int ret; + + /* Remove the headers */ + snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s", devname, + HDD_IPA_IPV4_NAME_EXT); + hdd_ipa_remove_header(name_ipa); + + if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) { + snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s", devname, + HDD_IPA_IPV6_NAME_EXT); + hdd_ipa_remove_header(name_ipa); + } + + /* unregister the interface with IPA */ + ret = ipa_deregister_intf(devname); + if (ret) + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, + "%s: ipa_deregister_intf fail: %d", devname, ret); + return ret; +} + +static int hdd_ipa_wdi_enable_pipes(struct hdd_ipa_priv *hdd_ipa) +{ + int result; + + /* ACTIVATE TX PIPE */ + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, + "Enable TX PIPE(tx_pipe_handle=%d)", + hdd_ipa->tx_pipe_handle); + result = ipa_enable_wdi_pipe(hdd_ipa->tx_pipe_handle); + if (result) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Enable TX PIPE fail, code %d", + result); + return result; + } + + result = ipa_resume_wdi_pipe(hdd_ipa->tx_pipe_handle); + if (result) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Resume TX PIPE fail, code %d", + result); + return result; + } + + /* ACTIVATE RX PIPE */ + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, + "Enable RX PIPE(rx_pipe_handle=%d)", + hdd_ipa->rx_pipe_handle); + result = ipa_enable_wdi_pipe(hdd_ipa->rx_pipe_handle); + if (result) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Enable RX PIPE fail, code %d", + result); + return result; + } + + result = ipa_resume_wdi_pipe(hdd_ipa->rx_pipe_handle); + if (result) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Resume RX PIPE fail, code %d", + result); + return result; + } + + return 0; +} + +static int hdd_ipa_wdi_disable_pipes(struct hdd_ipa_priv *hdd_ipa) +{ + int result; + + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Disable RX PIPE"); + result = ipa_suspend_wdi_pipe(hdd_ipa->rx_pipe_handle); + if (result) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Suspend RX PIPE fail, code %d", result); + return result; + } + + result = ipa_disable_wdi_pipe(hdd_ipa->rx_pipe_handle); + if (result) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Disable RX PIPE fail, code %d", result); + return result; + } + + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Disable TX PIPE"); + result = ipa_suspend_wdi_pipe(hdd_ipa->tx_pipe_handle); + if (result) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Suspend TX PIPE fail, code %d", result); + return result; + } + + result = ipa_disable_wdi_pipe(hdd_ipa->tx_pipe_handle); + if (result) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Disable TX PIPE fail, code %d", result); + return result; + } + + return 0; +} + +static int hdd_ipa_wdi_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa, + struct ipa_sys_connect_params *sys, uint32_t *handle) +{ + return ipa_setup_sys_pipe(sys, handle); +} + +static int hdd_ipa_wdi_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa, + uint32_t handle) +{ + return ipa_teardown_sys_pipe(handle); +} + +static int hdd_ipa_wdi_rm_set_perf_profile(struct hdd_ipa_priv *hdd_ipa, + enum ipa_rm_resource_name resource_name, + struct ipa_rm_perf_profile *profile) +{ + return ipa_rm_set_perf_profile(resource_name, profile); +} + +static int hdd_ipa_wdi_rm_request_resource(struct hdd_ipa_priv *hdd_ipa, + enum ipa_rm_resource_name res_name) +{ + return ipa_rm_request_resource(res_name); +} + +static int hdd_ipa_wdi_rm_release_resource(struct hdd_ipa_priv *hdd_ipa, + enum ipa_rm_resource_name res_name) +{ + return ipa_rm_release_resource(res_name); +} + +/** + * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work + * @work: struct work_struct + * @work_handler: work_handler + * + * Return: none + */ +static void hdd_ipa_init_uc_rm_work(struct work_struct *work, + work_func_t work_handler) +{ + INIT_WORK(work, work_handler); +} + +/** + * hdd_ipa_wake_lock_timer_func() - Wake lock work handler + * @work: scheduled work + * + * When IPA resources are released in hdd_ipa_wdi_rm_try_release() we do + * not want to immediately release the wake lock since the system + * would then potentially try to suspend when there is a healthy data + * rate. Deferred work is scheduled and this function handles the + * work. When this function is called, if the IPA resource is still + * released then we release the wake lock. + * + * Return: None + */ +static void hdd_ipa_wake_lock_timer_func(struct work_struct *work) +{ + struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work), + struct hdd_ipa_priv, + wake_lock_work); + + qdf_spin_lock_bh(&hdd_ipa->rm_lock); + + if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) + goto end; + + hdd_ipa->wake_lock_released = true; + qdf_wake_lock_release(&hdd_ipa->wake_lock, + WIFI_POWER_EVENT_WAKELOCK_IPA); + +end: + qdf_spin_unlock_bh(&hdd_ipa->rm_lock); +} + +/** + * hdd_ipa_wdi_rm_request() - Request resource from IPA + * @hdd_ipa: Global HDD IPA context + * + * Return: 0 on success, negative errno on error + */ +static int hdd_ipa_wdi_rm_request(struct hdd_ipa_priv *hdd_ipa) +{ + int ret = 0; + + if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + return 0; + + qdf_spin_lock_bh(&hdd_ipa->rm_lock); + + switch (hdd_ipa->rm_state) { + case HDD_IPA_RM_GRANTED: + qdf_spin_unlock_bh(&hdd_ipa->rm_lock); + return 0; + case HDD_IPA_RM_GRANT_PENDING: + qdf_spin_unlock_bh(&hdd_ipa->rm_lock); + return -EINPROGRESS; + case HDD_IPA_RM_RELEASED: + hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING; + break; + } + + qdf_spin_unlock_bh(&hdd_ipa->rm_lock); + + ret = ipa_rm_inactivity_timer_request_resource( + IPA_RM_RESOURCE_WLAN_PROD); + + qdf_spin_lock_bh(&hdd_ipa->rm_lock); + if (ret == 0) { + hdd_ipa->rm_state = HDD_IPA_RM_GRANTED; + hdd_ipa->stats.num_rm_grant_imm++; + } + + cancel_delayed_work(&hdd_ipa->wake_lock_work); + if (hdd_ipa->wake_lock_released) { + qdf_wake_lock_acquire(&hdd_ipa->wake_lock, + WIFI_POWER_EVENT_WAKELOCK_IPA); + hdd_ipa->wake_lock_released = false; + } + qdf_spin_unlock_bh(&hdd_ipa->rm_lock); + + return ret; +} + +/** + * hdd_ipa_wdi_rm_try_release() - Attempt to release IPA resource + * @hdd_ipa: Global HDD IPA context + * + * Return: 0 if resources released, negative errno otherwise + */ +static int hdd_ipa_wdi_rm_try_release(struct hdd_ipa_priv *hdd_ipa) +{ + int ret = 0; + + if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + return 0; + + if (atomic_read(&hdd_ipa->tx_ref_cnt)) + return -EAGAIN; + + qdf_spin_lock_bh(&hdd_ipa->pm_lock); + + if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) { + qdf_spin_unlock_bh(&hdd_ipa->pm_lock); + return -EAGAIN; + } + qdf_spin_unlock_bh(&hdd_ipa->pm_lock); + + qdf_spin_lock_bh(&hdd_ipa->rm_lock); + switch (hdd_ipa->rm_state) { + case HDD_IPA_RM_GRANTED: + break; + case HDD_IPA_RM_GRANT_PENDING: + qdf_spin_unlock_bh(&hdd_ipa->rm_lock); + return -EINPROGRESS; + case HDD_IPA_RM_RELEASED: + qdf_spin_unlock_bh(&hdd_ipa->rm_lock); + return 0; + } + + /* IPA driver returns immediately so set the state here to avoid any + * race condition. + */ + hdd_ipa->rm_state = HDD_IPA_RM_RELEASED; + hdd_ipa->stats.num_rm_release++; + qdf_spin_unlock_bh(&hdd_ipa->rm_lock); + + ret = ipa_rm_inactivity_timer_release_resource( + IPA_RM_RESOURCE_WLAN_PROD); + + qdf_spin_lock_bh(&hdd_ipa->rm_lock); + if (unlikely(ret != 0)) { + hdd_ipa->rm_state = HDD_IPA_RM_GRANTED; + WARN_ON(1); + HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, + "ipa_rm_inactivity_timer_release_resource returnied fail"); + } + + /* + * If wake_lock is released immediately, kernel would try to suspend + * immediately as well, Just avoid ping-pong between suspend-resume + * while there is healthy amount of data transfer going on by + * releasing the wake_lock after some delay. + */ + schedule_delayed_work(&hdd_ipa->wake_lock_work, + msecs_to_jiffies + (HDD_IPA_RX_INACTIVITY_MSEC_DELAY)); + + qdf_spin_unlock_bh(&hdd_ipa->rm_lock); + + return ret; +} + +/** + * hdd_ipa_rm_notify() - IPA resource manager notifier callback + * @user_data: user data registered with IPA + * @event: the IPA resource manager event that occurred + * @data: the data associated with the event + * + * Return: None + */ +static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event, + unsigned long data) +{ + struct hdd_ipa_priv *hdd_ipa = user_data; + + if (unlikely(!hdd_ipa)) + return; + + if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + return; + + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Evt: %d", event); + + switch (event) { + case IPA_RM_RESOURCE_GRANTED: + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + /* RM Notification comes with ISR context + * it should be serialized into work queue to avoid + * ISR sleep problem + */ + hdd_ipa->uc_rm_work.event = event; + schedule_work(&hdd_ipa->uc_rm_work.work); + break; + } + qdf_spin_lock_bh(&hdd_ipa->rm_lock); + hdd_ipa->rm_state = HDD_IPA_RM_GRANTED; + qdf_spin_unlock_bh(&hdd_ipa->rm_lock); + hdd_ipa->stats.num_rm_grant++; + break; + + case IPA_RM_RESOURCE_RELEASED: + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "RM Release"); + hdd_ipa->resource_unloading = false; + break; + + default: + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event); + break; + } +} + +/** + * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler + * + * Callback function registered with IPA that is called when IPA wants + * to release the WLAN consumer resource + * + * Return: 0 if the request is granted, negative errno otherwise + */ +static int hdd_ipa_rm_cons_release(void) +{ + return 0; +} + +/** + * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler + * + * Callback function registered with IPA that is called when IPA wants + * to access the WLAN consumer resource + * + * Return: 0 if the request is granted, negative errno otherwise + */ +static int hdd_ipa_rm_cons_request(void) +{ + int ret = 0; + + if (ghdd_ipa->resource_loading) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, + "IPA resource loading in progress"); + ghdd_ipa->pending_cons_req = true; + ret = -EINPROGRESS; + } else if (ghdd_ipa->resource_unloading) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, + "IPA resource unloading in progress"); + ghdd_ipa->pending_cons_req = true; + ret = -EPERM; + } + + return ret; +} + +/** + * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler + * @context: User context registered with TL (the IPA Global context is + * registered + * @rxpkt: Packet containing the notification + * @staid: ID of the station associated with the packet + * + * Return: None + */ +static void +hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event) +{ + struct hdd_ipa_priv *hdd_ipa = context; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* + * When SSR is going on or driver is unloading, just return. + */ + status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx); + if (status) + return; + + if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + return; + + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "event code %d", + event); + + switch (event) { + case IPA_RM_RESOURCE_GRANTED: + /* Differed RM Granted */ + qdf_mutex_acquire(&hdd_ipa->ipa_lock); + if ((false == hdd_ipa->resource_unloading) && + (!hdd_ipa->activated_fw_pipe)) { + hdd_ipa_uc_enable_pipes(hdd_ipa); + hdd_ipa->resource_loading = false; + } + qdf_mutex_release(&hdd_ipa->ipa_lock); + break; + + case IPA_RM_RESOURCE_RELEASED: + /* Differed RM Released */ + hdd_ipa->resource_unloading = false; + break; + + default: + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "invalid event code %d", event); + break; + } +} + +/** + * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification + * @hdd_ipa: Global HDD IPA context + * @event: IPA resource manager event to be deferred + * + * This function is called when a resource manager event is received + * from firmware in interrupt context. This function will defer the + * handling to the OL RX thread + * + * Return: None + */ +static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work) +{ + enum ipa_rm_event event; + struct uc_rm_work_struct *uc_rm_work = container_of(work, + struct uc_rm_work_struct, work); + struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work, + struct hdd_ipa_priv, uc_rm_work); + + cds_ssr_protect(__func__); + event = uc_rm_work->event; + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, + "posted event %d", event); + + hdd_ipa_uc_rm_notify_handler(hdd_ipa, event); + cds_ssr_unprotect(__func__); +} + +/** + * hdd_ipa_wdi_setup_rm() - Setup IPA resource management + * @hdd_ipa: Global HDD IPA context + * + * Return: 0 on success, negative errno on error + */ +static int hdd_ipa_wdi_setup_rm(struct hdd_ipa_priv *hdd_ipa) +{ + struct ipa_rm_create_params create_params = { 0 }; + int ret; + + if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + return 0; + + hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work, + hdd_ipa_uc_rm_notify_defer); + memset(&create_params, 0, sizeof(create_params)); + create_params.name = IPA_RM_RESOURCE_WLAN_PROD; + create_params.reg_params.user_data = hdd_ipa; + create_params.reg_params.notify_cb = hdd_ipa_rm_notify; + create_params.floor_voltage = IPA_VOLTAGE_SVS; + + ret = ipa_rm_create_resource(&create_params); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Create RM resource failed: %d", ret); + goto setup_rm_fail; + } + + memset(&create_params, 0, sizeof(create_params)); + create_params.name = IPA_RM_RESOURCE_WLAN_CONS; + create_params.request_resource = hdd_ipa_rm_cons_request; + create_params.release_resource = hdd_ipa_rm_cons_release; + create_params.floor_voltage = IPA_VOLTAGE_SVS; + + ret = ipa_rm_create_resource(&create_params); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Create RM CONS resource failed: %d", ret); + goto delete_prod; + } + + ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD, + IPA_RM_RESOURCE_APPS_CONS); + + ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD, + HDD_IPA_RX_INACTIVITY_MSEC_DELAY); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d", + ret); + goto timer_init_failed; + } + + /* Set the lowest bandwidth to start with */ + ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0); + + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Set perf level failed: %d", ret); + goto set_perf_failed; + } + + qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa"); + INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work, + hdd_ipa_wake_lock_timer_func); + qdf_spinlock_create(&hdd_ipa->rm_lock); + hdd_ipa->rm_state = HDD_IPA_RM_RELEASED; + hdd_ipa->wake_lock_released = true; + atomic_set(&hdd_ipa->tx_ref_cnt, 0); + + return ret; + +set_perf_failed: + ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD); + +timer_init_failed: + ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS); + +delete_prod: + ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD); + +setup_rm_fail: + return ret; +} + +/** + * hdd_ipa_wdi_destroy_rm() - Destroy IPA resources + * @hdd_ipa: Global HDD IPA context + * + * Destroys all resources associated with the IPA resource manager + * + * Return: None + */ +static void hdd_ipa_wdi_destroy_rm(struct hdd_ipa_priv *hdd_ipa) +{ + int ret; + + if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + return; + + cancel_delayed_work_sync(&hdd_ipa->wake_lock_work); + qdf_wake_lock_destroy(&hdd_ipa->wake_lock); + cancel_work_sync(&hdd_ipa->uc_rm_work.work); + qdf_spinlock_destroy(&hdd_ipa->rm_lock); + + ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD); + + ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD); + if (ret) + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "RM PROD resource delete failed %d", ret); + + ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS); + if (ret) + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "RM CONS resource delete failed %d", ret); +} + +static int hdd_ipa_wdi_rm_notify_completion(enum ipa_rm_event event, + enum ipa_rm_resource_name resource_name) +{ + return ipa_rm_notify_completion(event, resource_name); +} +#endif /* CONFIG_IPA_WDI_UNIFIED_API */ + /** * hdd_ipa_uc_rt_debug_host_fill - fill rt debug buffer * @ctext: pointer to hdd context. @@ -1749,8 +3453,8 @@ static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa, */ static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa) { + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); int result = 0; - p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context; HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter"); @@ -1765,46 +3469,17 @@ static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa) goto end; } - /* ACTIVATE TX PIPE */ - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, - "Enable TX PIPE(tx_pipe_handle=%d)", - hdd_ipa->tx_pipe_handle); - result = ipa_enable_wdi_pipe(hdd_ipa->tx_pipe_handle); - if (result) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "Enable TX PIPE fail, code %d", - result); - goto end; - } - result = ipa_resume_wdi_pipe(hdd_ipa->tx_pipe_handle); + result = hdd_ipa_wdi_enable_pipes(hdd_ipa); if (result) { HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "Resume TX PIPE fail, code %d", - result); + "Enable IPA WDI pipes failed ret=%d", result); goto end; } - ol_txrx_ipa_uc_set_active(cds_ctx->pdev_txrx_ctx, true, true); - /* ACTIVATE RX PIPE */ - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, - "Enable RX PIPE(rx_pipe_handle=%d)", - hdd_ipa->rx_pipe_handle); - result = ipa_enable_wdi_pipe(hdd_ipa->rx_pipe_handle); - if (result) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "Enable RX PIPE fail, code %d", - result); - goto end; - } - result = ipa_resume_wdi_pipe(hdd_ipa->rx_pipe_handle); - if (result) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "Resume RX PIPE fail, code %d", - result); - goto end; - } + ol_txrx_ipa_uc_set_active(pdev, true, true); + ol_txrx_ipa_uc_set_active(pdev, true, false); + INIT_COMPLETION(hdd_ipa->ipa_resource_comp); - ol_txrx_ipa_uc_set_active(cds_ctx->pdev_txrx_ctx, true, false); hdd_ipa->ipa_pipes_down = false; end: @@ -1836,35 +3511,10 @@ static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa) goto end; } - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Disable RX PIPE"); - result = ipa_suspend_wdi_pipe(hdd_ipa->rx_pipe_handle); + result = hdd_ipa_wdi_disable_pipes(hdd_ipa); if (result) { HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "Suspend RX PIPE fail, code %d", - result); - goto end; - } - result = ipa_disable_wdi_pipe(hdd_ipa->rx_pipe_handle); - if (result) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "Disable RX PIPE fail, code %d", - result); - goto end; - } - - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Disable TX PIPE"); - result = ipa_suspend_wdi_pipe(hdd_ipa->tx_pipe_handle); - if (result) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "Suspend TX PIPE fail, code %d", - result); - goto end; - } - result = ipa_disable_wdi_pipe(hdd_ipa->tx_pipe_handle); - if (result) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "Disable TX PIPE fail, code %d", - result); + "Disable IPA WDI pipes failed ret=%d", result); goto end; } @@ -1894,7 +3544,8 @@ static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa) * PROD resource may return sync or async manners */ if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) { - if (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD)) { + if (!hdd_ipa_wdi_rm_request_resource(hdd_ipa, + IPA_RM_RESOURCE_WLAN_PROD)) { /* RM PROD request sync return * enable pipe immediately */ @@ -1933,11 +3584,11 @@ static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa) */ static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa) { - p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context; + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "enter"); - if (!cds_ctx || !cds_ctx->pdev_txrx_ctx) { + if (!pdev) { HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "txrx context is NULL"); QDF_ASSERT(0); return; @@ -1946,90 +3597,11 @@ static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa) hdd_ipa->resource_unloading = true; INIT_COMPLETION(hdd_ipa->ipa_resource_comp); HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Disable FW RX PIPE"); - ol_txrx_ipa_uc_set_active(cds_ctx->pdev_txrx_ctx, false, false); + ol_txrx_ipa_uc_set_active(pdev, false, false); HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "exit: IPA WDI Pipes deactivated"); } -/** - * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler - * @context: User context registered with TL (the IPA Global context is - * registered - * @rxpkt: Packet containing the notification - * @staid: ID of the station associated with the packet - * - * Return: None - */ -static void -hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event) -{ - struct hdd_ipa_priv *hdd_ipa = context; - QDF_STATUS status = QDF_STATUS_SUCCESS; - - /* - * When SSR is going on or driver is unloading, just return. - */ - status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx); - if (status) - return; - - if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) - return; - - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "event code %d", - event); - - switch (event) { - case IPA_RM_RESOURCE_GRANTED: - /* Differed RM Granted */ - qdf_mutex_acquire(&hdd_ipa->ipa_lock); - if ((false == hdd_ipa->resource_unloading) && - (!hdd_ipa->activated_fw_pipe)) { - hdd_ipa_uc_enable_pipes(hdd_ipa); - hdd_ipa->resource_loading = false; - } - qdf_mutex_release(&hdd_ipa->ipa_lock); - break; - - case IPA_RM_RESOURCE_RELEASED: - /* Differed RM Released */ - hdd_ipa->resource_unloading = false; - break; - - default: - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "invalid event code %d", event); - break; - } -} - -/** - * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification - * @hdd_ipa: Global HDD IPA context - * @event: IPA resource manager event to be deferred - * - * This function is called when a resource manager event is received - * from firmware in interrupt context. This function will defer the - * handling to the OL RX thread - * - * Return: None - */ -static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work) -{ - enum ipa_rm_event event; - struct uc_rm_work_struct *uc_rm_work = container_of(work, - struct uc_rm_work_struct, work); - struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work, - struct hdd_ipa_priv, uc_rm_work); - - cds_ssr_protect(__func__); - event = uc_rm_work->event; - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, - "posted event %d", event); - - hdd_ipa_uc_rm_notify_handler(hdd_ipa, event); - cds_ssr_unprotect(__func__); -} /** * hdd_ipa_uc_op_metering() - IPA uC operation for stats and quota limit @@ -2132,7 +3704,12 @@ static QDF_STATUS hdd_ipa_uc_op_metering(hdd_context_t *hdd_ctx, */ static void hdd_ipa_uc_loaded_handler(struct hdd_ipa_priv *ipa_ctxt) { - struct ipa_wdi_out_params pipe_out; + struct ol_txrx_ipa_resources *ipa_res = &ipa_ctxt->ipa_resource; + qdf_device_t osdev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + struct ol_txrx_pdev_t *pdev; + uint32_t tx_comp_db_dmaaddr = 0; + uint32_t rx_rdy_db_dmaaddr = 0; + int ret; HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "UC READY"); if (true == ipa_ctxt->uc_loaded) { @@ -2140,22 +3717,42 @@ static void hdd_ipa_uc_loaded_handler(struct hdd_ipa_priv *ipa_ctxt) return; } + if (!osdev) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "invalid qdf dev context"); + return; + } + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "invalid txrx context"); + return; + } + /* Connect pipe */ - ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out); - ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl; - ipa_ctxt->tx_comp_doorbell_dmaaddr = pipe_out.uc_door_bell_pa; - HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, - "TX PIPE Handle %d, DBPA 0x%llx", - ipa_ctxt->tx_pipe_handle, - (unsigned long long) pipe_out.uc_door_bell_pa); + ret = hdd_ipa_wdi_conn_pipes(ipa_ctxt, ipa_res); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "ipa wdi conn pipes failed ret=%d", ret); + return; + } - ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out); - ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl; - ipa_ctxt->rx_ready_doorbell_dmaaddr = pipe_out.uc_door_bell_pa; - HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, - "RX PIPE Handle %d, DBPA 0x%llx", - ipa_ctxt->rx_pipe_handle, - (unsigned long long) pipe_out.uc_door_bell_pa); + if (hdd_ipa_wdi_is_smmu_enabled(ipa_ctxt, osdev)) { + pld_smmu_map(osdev->dev, + ipa_ctxt->tx_comp_doorbell_dmaaddr, + &tx_comp_db_dmaaddr, + sizeof(uint32_t)); + ipa_ctxt->tx_comp_doorbell_dmaaddr = tx_comp_db_dmaaddr; + + pld_smmu_map(osdev->dev, + ipa_ctxt->rx_ready_doorbell_dmaaddr, + &rx_rdy_db_dmaaddr, + sizeof(uint32_t)); + ipa_ctxt->rx_ready_doorbell_dmaaddr = rx_rdy_db_dmaaddr; + } + + ol_txrx_ipa_uc_set_doorbell_paddr(pdev, + ipa_ctxt->tx_comp_doorbell_dmaaddr, + ipa_ctxt->rx_ready_doorbell_dmaaddr); /* If already any STA connected, enable IPA/FW PIPEs */ if (ipa_ctxt->sap_num_connected_sta) { @@ -2678,7 +4275,7 @@ static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt) } hdd_ipa_uc_proc_pending_event(hdd_ipa, true); if (hdd_ipa->pending_cons_req) - ipa_rm_notify_completion( + hdd_ipa_wdi_rm_notify_completion( IPA_RM_RESOURCE_GRANTED, IPA_RM_RESOURCE_WLAN_CONS); hdd_ipa->pending_cons_req = false; @@ -2704,7 +4301,7 @@ static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt) hdd_ipa->resource_unloading = false; complete(&hdd_ipa->ipa_resource_comp); if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) - ipa_rm_release_resource( + hdd_ipa_wdi_rm_release_resource(hdd_ipa, IPA_RM_RESOURCE_WLAN_PROD); hdd_ipa_uc_proc_pending_event(hdd_ipa, false); hdd_ipa->pending_cons_req = false; @@ -2911,162 +4508,6 @@ static void hdd_ipa_init_uc_op_work(struct work_struct *work, INIT_WORK(work, work_handler); } -#ifdef FEATURE_METERING -/** - * __hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler. - * IPA calls to get WLAN stats or set quota limit. - * @priv: pointer to private data registered with IPA (we register a - *» pointer to the global IPA context) - * @evt: the IPA event which triggered the callback - * @data: data associated with the event - * - * Return: None - */ -static void __hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt, - void *data) -{ - struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; - hdd_adapter_t *adapter = NULL; - struct ipa_get_wdi_sap_stats *wdi_sap_stats; - struct ipa_set_wifi_quota *ipa_set_quota; - int ret = 0; - - if (wlan_hdd_validate_context(hdd_ipa->hdd_ctx)) - return; - - adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE); - - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "event=%d", evt); - - switch (evt) { - case IPA_GET_WDI_SAP_STATS: - /* fill-up ipa_get_wdi_sap_stats structure after getting - * ipa_uc_fw_stats from FW - */ - wdi_sap_stats = data; - - if (!adapter) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "IPA uC share stats failed - no adapter"); - wdi_sap_stats->stats_valid = 0; - return; - } - - INIT_COMPLETION(hdd_ipa->ipa_uc_sharing_stats_comp); - hdd_ipa_uc_sharing_stats_request(adapter, - wdi_sap_stats->reset_stats); - ret = wait_for_completion_timeout( - &hdd_ipa->ipa_uc_sharing_stats_comp, - msecs_to_jiffies(IPA_UC_SHARING_STATES_WAIT_TIME)); - if (!ret) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "IPA uC share stats request timed out"); - wdi_sap_stats->stats_valid = 0; - } else { - wdi_sap_stats->stats_valid = 1; - - wdi_sap_stats->ipv4_rx_packets = - hdd_ipa->ipa_sharing_stats.ipv4_rx_packets; - wdi_sap_stats->ipv4_rx_bytes = - hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes; - wdi_sap_stats->ipv6_rx_packets = - hdd_ipa->ipa_sharing_stats.ipv6_rx_packets; - wdi_sap_stats->ipv6_rx_bytes = - hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes; - wdi_sap_stats->ipv4_tx_packets = - hdd_ipa->ipa_sharing_stats.ipv4_tx_packets; - wdi_sap_stats->ipv4_tx_bytes = - hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes; - wdi_sap_stats->ipv6_tx_packets = - hdd_ipa->ipa_sharing_stats.ipv6_tx_packets; - wdi_sap_stats->ipv6_tx_bytes = - hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes; - HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, - "%s:%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu", - "IPA_GET_WDI_SAP_STATS", - wdi_sap_stats->stats_valid, - wdi_sap_stats->ipv4_rx_packets, - wdi_sap_stats->ipv4_rx_bytes, - wdi_sap_stats->ipv6_rx_packets, - wdi_sap_stats->ipv6_rx_bytes, - wdi_sap_stats->ipv4_tx_packets, - wdi_sap_stats->ipv4_tx_bytes, - wdi_sap_stats->ipv6_tx_packets, - wdi_sap_stats->ipv6_tx_bytes); - } - break; - case IPA_SET_WIFI_QUOTA: - /* Get ipa_set_wifi_quota structure from IPA and pass to FW - * through quota_exceeded field in ipa_uc_fw_stats - */ - ipa_set_quota = data; - - if (!adapter) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "IPA uC set quota failed - no adapter"); - ipa_set_quota->set_valid = 0; - return; - } - - INIT_COMPLETION(hdd_ipa->ipa_uc_set_quota_comp); - hdd_ipa_uc_set_quota(adapter, ipa_set_quota->set_quota, - ipa_set_quota->quota_bytes); - - ret = wait_for_completion_timeout( - &hdd_ipa->ipa_uc_set_quota_comp, - msecs_to_jiffies(IPA_UC_SET_QUOTA_WAIT_TIME)); - if (!ret) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "IPA uC set quota request timed out"); - ipa_set_quota->set_valid = 0; - } else { - ipa_set_quota->quota_bytes = - ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi) - <<32)|hdd_ipa->ipa_quota_rsp.quota_lo; - ipa_set_quota->set_valid = - hdd_ipa->ipa_quota_rsp.success; - } - - HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "SET_QUOTA: %llu, %d", - ipa_set_quota->quota_bytes, - ipa_set_quota->set_valid); - break; - } -} - -/** - * hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler. - * IPA calls to get WLAN stats or set quota limit. - * @priv: pointer to private data registered with IPA (we register a - *» pointer to the global IPA context) - * @evt: the IPA event which triggered the callback - * @data: data associated with the event - * - * Return: None - */ -static void hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt, - void *data) -{ - cds_ssr_protect(__func__); - __hdd_ipa_wdi_meter_notifier_cb(evt, data); - cds_ssr_unprotect(__func__); -} - -static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt, - struct ipa_wdi_in_params *pipe_in) -{ - pipe_in->wdi_notify = hdd_ipa_wdi_meter_notifier_cb; - - init_completion(&ipa_ctxt->ipa_uc_sharing_stats_comp); - init_completion(&ipa_ctxt->ipa_uc_set_quota_comp); -} -#else -static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt, - struct ipa_wdi_in_params *pipe_in) -{ -} -#endif - /** * hdd_ipa_uc_ol_init() - Initialize IPA uC offload * @hdd_ctx: Global HDD context @@ -3079,12 +4520,10 @@ static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt, */ QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx) { - struct ipa_wdi_in_params pipe_in; - struct ipa_wdi_out_params pipe_out; struct hdd_ipa_priv *ipa_ctxt = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; struct ol_txrx_ipa_resources *ipa_res = &ipa_ctxt->ipa_resource; struct ol_txrx_pdev_t *pdev = NULL; - int i, ret; + int i; QDF_STATUS stat = QDF_STATUS_SUCCESS; qdf_device_t osdev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); uint32_t tx_comp_db_dmaaddr = 0, rx_rdy_db_dmaaddr = 0; @@ -3124,207 +4563,32 @@ QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx) stat = QDF_STATUS_E_FAILURE; goto fail_return; } - qdf_mem_zero(&ipa_ctxt->cons_pipe_in, sizeof(struct ipa_wdi_in_params)); - qdf_mem_zero(&ipa_ctxt->prod_pipe_in, sizeof(struct ipa_wdi_in_params)); - qdf_mem_zero(&pipe_in, sizeof(struct ipa_wdi_in_params)); - qdf_mem_zero(&pipe_out, sizeof(struct ipa_wdi_out_params)); - - /* TX PIPE */ - pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; - pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN; - pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1; - pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0; - pipe_in.sys.ipa_ep_cfg.hdr.hdr_additional_const_len = - HDD_IPA_UC_WLAN_8023_HDR_SIZE; - pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC; - pipe_in.sys.client = IPA_CLIENT_WLAN1_CONS; - pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize; - pipe_in.sys.priv = hdd_ctx->hdd_ipa; - pipe_in.sys.ipa_ep_cfg.hdr_ext.hdr_little_endian = true; - pipe_in.sys.notify = hdd_ipa_i2w_cb; - if (!hdd_ipa_is_rm_enabled(hdd_ctx)) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, - "IPA RM DISABLED, IPA AWAKE"); - pipe_in.sys.keep_ipa_awake = true; - } - - pipe_in.smmu_enabled = qdf_mem_smmu_s1_enabled(osdev); - if (pipe_in.smmu_enabled) { - qdf_mem_copy(&pipe_in.u.dl_smmu.comp_ring, - &ipa_res->tx_comp_ring->sgtable, - sizeof(sgtable_t)); - - qdf_mem_copy(&pipe_in.u.dl_smmu.ce_ring, - &ipa_res->ce_sr->sgtable, - sizeof(sgtable_t)); - pipe_in.u.dl_smmu.comp_ring_size = - ipa_res->tx_comp_ring->mem_info.size; - pipe_in.u.dl_smmu.ce_ring_size = - ipa_res->ce_sr_ring_size; - pipe_in.u.dl_smmu.ce_door_bell_pa = - ipa_res->ce_reg_paddr; - pipe_in.u.dl_smmu.num_tx_buffers = - ipa_res->tx_num_alloc_buffer; - } else { - pipe_in.u.dl.comp_ring_base_pa = - qdf_mem_get_dma_addr(osdev, - &ipa_res->tx_comp_ring->mem_info); - pipe_in.u.dl.ce_ring_base_pa = - qdf_mem_get_dma_addr(osdev, - &ipa_res->ce_sr->mem_info); - pipe_in.u.dl.comp_ring_size = - ipa_res->tx_comp_ring->mem_info.size; - pipe_in.u.dl.ce_door_bell_pa = ipa_res->ce_reg_paddr; - pipe_in.u.dl.ce_ring_size = - ipa_res->ce_sr_ring_size; - pipe_in.u.dl.num_tx_buffers = - ipa_res->tx_num_alloc_buffer; - } - - qdf_mem_copy(&ipa_ctxt->cons_pipe_in, &pipe_in, - sizeof(struct ipa_wdi_in_params)); - hdd_ipa_uc_get_db_paddr(&ipa_ctxt->tx_comp_doorbell_dmaaddr, - IPA_CLIENT_WLAN1_CONS); - if (true == ipa_ctxt->uc_loaded) { - /* Connect WDI IPA PIPE */ - ret = ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out); - if (ret) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "ipa_connect_wdi_pipe failed for Tx: ret=%d", - ret); + if (ipa_ctxt->uc_loaded) { + if (hdd_ipa_wdi_conn_pipes(ipa_ctxt, ipa_res)) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, + "IPA CONN PIPES failed"); stat = QDF_STATUS_E_FAILURE; goto fail_return; } - /* Micro Controller Doorbell register */ - ipa_ctxt->tx_comp_doorbell_dmaaddr = pipe_out.uc_door_bell_pa; - - /* WLAN TX PIPE Handle */ - ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl; - - if (ipa_ctxt->tx_pipe_handle == 0) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "TX Handle zero"); - QDF_BUG(0); + if (hdd_ipa_wdi_is_smmu_enabled(ipa_ctxt, osdev)) { + pld_smmu_map(osdev->dev, + ipa_ctxt->tx_comp_doorbell_dmaaddr, + &tx_comp_db_dmaaddr, + sizeof(uint32_t)); + ipa_ctxt->tx_comp_doorbell_dmaaddr = tx_comp_db_dmaaddr; + + pld_smmu_map(osdev->dev, + ipa_ctxt->rx_ready_doorbell_dmaaddr, + &rx_rdy_db_dmaaddr, + sizeof(uint32_t)); + ipa_ctxt->rx_ready_doorbell_dmaaddr = rx_rdy_db_dmaaddr; } - HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, - "CONS DB pipe out 0x%x TX PIPE Handle 0x%x", - (unsigned int)pipe_out.uc_door_bell_pa, - ipa_ctxt->tx_pipe_handle); - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, - "TX : CRBPA 0x%x, CRS %d, CERBPA 0x%x, CEDPA 0x%x," - " CERZ %d, NB %d, CDBPAD 0x%x", - (unsigned int)pipe_in.u.dl.comp_ring_base_pa, - pipe_in.u.dl.comp_ring_size, - (unsigned int)pipe_in.u.dl.ce_ring_base_pa, - (unsigned int)pipe_in.u.dl.ce_door_bell_pa, - pipe_in.u.dl.ce_ring_size, - pipe_in.u.dl.num_tx_buffers, - (unsigned int)ipa_ctxt->tx_comp_doorbell_dmaaddr); - } - - /* RX PIPE */ - pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; - pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_RX_HDR_LEN; - pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 0; - pipe_in.sys.ipa_ep_cfg.hdr.hdr_metadata_reg_valid = 1; - pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC; - pipe_in.sys.client = IPA_CLIENT_WLAN1_PROD; - pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize + - sizeof(struct sps_iovec); - pipe_in.sys.notify = hdd_ipa_w2i_cb; - if (!hdd_ipa_is_rm_enabled(hdd_ctx)) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, - "IPA RM DISABLED, IPA AWAKE"); - pipe_in.sys.keep_ipa_awake = true; - } - - pipe_in.smmu_enabled = qdf_mem_smmu_s1_enabled(osdev); - if (pipe_in.smmu_enabled) { - qdf_mem_copy(&pipe_in.u.ul_smmu.rdy_ring, - &ipa_res->rx_rdy_ring->sgtable, - sizeof(sgtable_t)); - pipe_in.u.ul_smmu.rdy_ring_size = - ipa_res->rx_rdy_ring->mem_info.size; - pipe_in.u.ul_smmu.rdy_ring_rp_pa = - ipa_res->rx_proc_done_idx->mem_info.pa; - - pipe_in.u.ul_smmu.rdy_ring_rp_va = - ipa_res->rx_proc_done_idx->vaddr; - - qdf_mem_copy(&pipe_in.u.ul_smmu.rdy_comp_ring, - &ipa_res->rx2_rdy_ring->sgtable, - sizeof(sgtable_t)); - - pipe_in.u.ul_smmu.rdy_comp_ring_size = - ipa_res->rx2_rdy_ring->mem_info.size; - - pipe_in.u.ul_smmu.rdy_comp_ring_wp_pa = - ipa_res->rx2_proc_done_idx->mem_info.pa; - - pipe_in.u.ul_smmu.rdy_comp_ring_wp_va = - ipa_res->rx2_proc_done_idx->vaddr; - } else { - pipe_in.u.ul.rdy_ring_base_pa = - ipa_res->rx_rdy_ring->mem_info.pa; - pipe_in.u.ul.rdy_ring_size = - ipa_res->rx_rdy_ring->mem_info.size; - pipe_in.u.ul.rdy_ring_rp_pa = - ipa_res->rx_proc_done_idx->mem_info.pa; - HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt, osdev); - } - - hdd_ipa_init_metering(ipa_ctxt, &pipe_in); - - qdf_mem_copy(&ipa_ctxt->prod_pipe_in, &pipe_in, - sizeof(struct ipa_wdi_in_params)); - hdd_ipa_uc_get_db_paddr(&ipa_ctxt->rx_ready_doorbell_dmaaddr, - IPA_CLIENT_WLAN1_PROD); - - if (true == ipa_ctxt->uc_loaded) { - ret = ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out); - if (ret) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "ipa_connect_wdi_pipe failed for Rx: ret=%d", - ret); - stat = QDF_STATUS_E_FAILURE; - ret = ipa_disconnect_wdi_pipe(ipa_ctxt->tx_pipe_handle); - if (ret) - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "disconnect failed for TX: ret=%d", - ret); - goto fail_return; - } - ipa_ctxt->rx_ready_doorbell_dmaaddr = pipe_out.uc_door_bell_pa; - ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl; - if (ipa_ctxt->rx_pipe_handle == 0) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "RX Handle zero"); - QDF_BUG(0); - } - - HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, - "PROD DB pipe out 0x%x RX PIPE Handle 0x%x", - (unsigned int)pipe_out.uc_door_bell_pa, - ipa_ctxt->rx_pipe_handle); - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, - "RX : RRBPA 0x%x, RRS %d, PDIPA 0x%x, RDY_DB_PAD 0x%x", - (unsigned int)pipe_in.u.ul.rdy_ring_base_pa, - pipe_in.u.ul.rdy_ring_size, - (unsigned int)pipe_in.u.ul.rdy_ring_rp_pa, - (unsigned int)ipa_ctxt->rx_ready_doorbell_dmaaddr); - } - - if (qdf_mem_smmu_s1_enabled(osdev)) { - pld_smmu_map(osdev->dev, ipa_ctxt->tx_comp_doorbell_dmaaddr, - &tx_comp_db_dmaaddr, sizeof(uint32_t)); - ipa_ctxt->tx_comp_doorbell_dmaaddr = tx_comp_db_dmaaddr; - - pld_smmu_map(osdev->dev, ipa_ctxt->rx_ready_doorbell_dmaaddr, - &rx_rdy_db_dmaaddr, sizeof(uint32_t)); - ipa_ctxt->rx_ready_doorbell_dmaaddr = rx_rdy_db_dmaaddr; + ol_txrx_ipa_uc_set_doorbell_paddr(pdev, + ipa_ctxt->tx_comp_doorbell_dmaaddr, + ipa_ctxt->rx_ready_doorbell_dmaaddr); } for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) { @@ -3333,10 +4597,6 @@ QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx) ipa_ctxt->uc_op_work[i].msg = NULL; } - ol_txrx_ipa_uc_set_doorbell_paddr(pdev, - ipa_ctxt->tx_comp_doorbell_dmaaddr, - ipa_ctxt->rx_ready_doorbell_dmaaddr); - ol_txrx_ipa_uc_register_op_cb(pdev, hdd_ipa_uc_op_event_handler, (void *)hdd_ctx); @@ -3386,16 +4646,8 @@ int hdd_ipa_uc_ol_deinit(hdd_context_t *hdd_ctx) if (!hdd_ipa->ipa_pipes_down) hdd_ipa_uc_disable_pipes(hdd_ipa); - if (true == hdd_ipa->uc_loaded) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, - "Disconnect TX PIPE tx_pipe_handle=0x%x", - hdd_ipa->tx_pipe_handle); - ret = ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle); - HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, - "Disconnect RX PIPE rx_pipe_handle=0x%x", - hdd_ipa->rx_pipe_handle); - ret = ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle); - } + if (true == hdd_ipa->uc_loaded) + ret = hdd_ipa_wdi_disconn_pipes(hdd_ipa); qdf_mutex_acquire(&hdd_ipa->ipa_lock); hdd_ipa_cleanup_pending_event(hdd_ipa); @@ -3871,245 +5123,6 @@ struct sk_buff *hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx, } /** - * hdd_ipa_wake_lock_timer_func() - Wake lock work handler - * @work: scheduled work - * - * When IPA resources are released in hdd_ipa_rm_try_release() we do - * not want to immediately release the wake lock since the system - * would then potentially try to suspend when there is a healthy data - * rate. Deferred work is scheduled and this function handles the - * work. When this function is called, if the IPA resource is still - * released then we release the wake lock. - * - * Return: None - */ -static void hdd_ipa_wake_lock_timer_func(struct work_struct *work) -{ - struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work), - struct hdd_ipa_priv, - wake_lock_work); - - qdf_spin_lock_bh(&hdd_ipa->rm_lock); - - if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) - goto end; - - hdd_ipa->wake_lock_released = true; - qdf_wake_lock_release(&hdd_ipa->wake_lock, - WIFI_POWER_EVENT_WAKELOCK_IPA); - -end: - qdf_spin_unlock_bh(&hdd_ipa->rm_lock); -} - -/** - * hdd_ipa_rm_request() - Request resource from IPA - * @hdd_ipa: Global HDD IPA context - * - * Return: 0 on success, negative errno on error - */ -static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa) -{ - int ret = 0; - - if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) - return 0; - - qdf_spin_lock_bh(&hdd_ipa->rm_lock); - - switch (hdd_ipa->rm_state) { - case HDD_IPA_RM_GRANTED: - qdf_spin_unlock_bh(&hdd_ipa->rm_lock); - return 0; - case HDD_IPA_RM_GRANT_PENDING: - qdf_spin_unlock_bh(&hdd_ipa->rm_lock); - return -EINPROGRESS; - case HDD_IPA_RM_RELEASED: - hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING; - break; - } - - qdf_spin_unlock_bh(&hdd_ipa->rm_lock); - - ret = ipa_rm_inactivity_timer_request_resource( - IPA_RM_RESOURCE_WLAN_PROD); - - qdf_spin_lock_bh(&hdd_ipa->rm_lock); - if (ret == 0) { - hdd_ipa->rm_state = HDD_IPA_RM_GRANTED; - hdd_ipa->stats.num_rm_grant_imm++; - } - - cancel_delayed_work(&hdd_ipa->wake_lock_work); - if (hdd_ipa->wake_lock_released) { - qdf_wake_lock_acquire(&hdd_ipa->wake_lock, - WIFI_POWER_EVENT_WAKELOCK_IPA); - hdd_ipa->wake_lock_released = false; - } - qdf_spin_unlock_bh(&hdd_ipa->rm_lock); - - return ret; -} - -/** - * hdd_ipa_rm_try_release() - Attempt to release IPA resource - * @hdd_ipa: Global HDD IPA context - * - * Return: 0 if resources released, negative errno otherwise - */ -static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa) -{ - int ret = 0; - - if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) - return 0; - - if (atomic_read(&hdd_ipa->tx_ref_cnt)) - return -EAGAIN; - - qdf_spin_lock_bh(&hdd_ipa->pm_lock); - - if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) { - qdf_spin_unlock_bh(&hdd_ipa->pm_lock); - return -EAGAIN; - } - qdf_spin_unlock_bh(&hdd_ipa->pm_lock); - - qdf_spin_lock_bh(&hdd_ipa->rm_lock); - switch (hdd_ipa->rm_state) { - case HDD_IPA_RM_GRANTED: - break; - case HDD_IPA_RM_GRANT_PENDING: - qdf_spin_unlock_bh(&hdd_ipa->rm_lock); - return -EINPROGRESS; - case HDD_IPA_RM_RELEASED: - qdf_spin_unlock_bh(&hdd_ipa->rm_lock); - return 0; - } - - /* IPA driver returns immediately so set the state here to avoid any - * race condition. - */ - hdd_ipa->rm_state = HDD_IPA_RM_RELEASED; - hdd_ipa->stats.num_rm_release++; - qdf_spin_unlock_bh(&hdd_ipa->rm_lock); - - ret = ipa_rm_inactivity_timer_release_resource( - IPA_RM_RESOURCE_WLAN_PROD); - - qdf_spin_lock_bh(&hdd_ipa->rm_lock); - if (unlikely(ret != 0)) { - hdd_ipa->rm_state = HDD_IPA_RM_GRANTED; - WARN_ON(1); - HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, - "ipa_rm_inactivity_timer_release_resource returnied fail"); - } - - /* - * If wake_lock is released immediately, kernel would try to suspend - * immediately as well, Just avoid ping-pong between suspend-resume - * while there is healthy amount of data transfer going on by - * releasing the wake_lock after some delay. - */ - schedule_delayed_work(&hdd_ipa->wake_lock_work, - msecs_to_jiffies - (HDD_IPA_RX_INACTIVITY_MSEC_DELAY)); - - qdf_spin_unlock_bh(&hdd_ipa->rm_lock); - - return ret; -} - -/** - * hdd_ipa_rm_notify() - IPA resource manager notifier callback - * @user_data: user data registered with IPA - * @event: the IPA resource manager event that occurred - * @data: the data associated with the event - * - * Return: None - */ -static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event, - unsigned long data) -{ - struct hdd_ipa_priv *hdd_ipa = user_data; - - if (unlikely(!hdd_ipa)) - return; - - if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) - return; - - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Evt: %d", event); - - switch (event) { - case IPA_RM_RESOURCE_GRANTED: - if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { - /* RM Notification comes with ISR context - * it should be serialized into work queue to avoid - * ISR sleep problem - */ - hdd_ipa->uc_rm_work.event = event; - schedule_work(&hdd_ipa->uc_rm_work.work); - break; - } - qdf_spin_lock_bh(&hdd_ipa->rm_lock); - hdd_ipa->rm_state = HDD_IPA_RM_GRANTED; - qdf_spin_unlock_bh(&hdd_ipa->rm_lock); - hdd_ipa->stats.num_rm_grant++; - break; - - case IPA_RM_RESOURCE_RELEASED: - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "RM Release"); - hdd_ipa->resource_unloading = false; - break; - - default: - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event); - break; - } -} - -/** - * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler - * - * Callback function registered with IPA that is called when IPA wants - * to release the WLAN consumer resource - * - * Return: 0 if the request is granted, negative errno otherwise - */ -static int hdd_ipa_rm_cons_release(void) -{ - return 0; -} - -/** - * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler - * - * Callback function registered with IPA that is called when IPA wants - * to access the WLAN consumer resource - * - * Return: 0 if the request is granted, negative errno otherwise - */ -static int hdd_ipa_rm_cons_request(void) -{ - int ret = 0; - - if (ghdd_ipa->resource_loading) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, - "IPA resource loading in progress"); - ghdd_ipa->pending_cons_req = true; - ret = -EINPROGRESS; - } else if (ghdd_ipa->resource_unloading) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, - "IPA resource unloading in progress"); - ghdd_ipa->pending_cons_req = true; - ret = -EPERM; - } - - return ret; -} - -/** * __hdd_ipa_set_perf_level() - Set IPA performance level * @hdd_ctx: Global HDD context * @tx_packets: Number of packets transmitted in the last sample period @@ -4163,8 +5176,8 @@ static int __hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets, hdd_debug("Requesting CONS perf curr: %d, next: %d", hdd_ipa->curr_cons_bw, next_cons_bw); profile.max_supported_bandwidth_mbps = next_cons_bw; - ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS, - &profile); + ret = hdd_ipa_wdi_rm_set_perf_profile(hdd_ipa, + IPA_RM_RESOURCE_WLAN_CONS, &profile); if (ret) { hdd_err("RM CONS set perf profile failed: %d", ret); @@ -4178,8 +5191,8 @@ static int __hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets, hdd_debug("Requesting PROD perf curr: %d, next: %d", hdd_ipa->curr_prod_bw, next_prod_bw); profile.max_supported_bandwidth_mbps = next_prod_bw; - ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD, - &profile); + ret = hdd_ipa_wdi_rm_set_perf_profile(hdd_ipa, + IPA_RM_RESOURCE_WLAN_PROD, &profile); if (ret) { hdd_err("RM PROD set perf profile failed: %d", ret); return ret; @@ -4211,138 +5224,7 @@ int hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets, return ret; } -/** - * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work - * @work: struct work_struct - * @work_handler: work_handler - * - * Return: none - */ -static void hdd_ipa_init_uc_rm_work(struct work_struct *work, - work_func_t work_handler) -{ - INIT_WORK(work, work_handler); -} - -/** - * hdd_ipa_setup_rm() - Setup IPA resource management - * @hdd_ipa: Global HDD IPA context - * - * Return: 0 on success, negative errno on error - */ -static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa) -{ - struct ipa_rm_create_params create_params = { 0 }; - int ret; - - if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) - return 0; - - hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work, - hdd_ipa_uc_rm_notify_defer); - memset(&create_params, 0, sizeof(create_params)); - create_params.name = IPA_RM_RESOURCE_WLAN_PROD; - create_params.reg_params.user_data = hdd_ipa; - create_params.reg_params.notify_cb = hdd_ipa_rm_notify; - create_params.floor_voltage = IPA_VOLTAGE_SVS; - - ret = ipa_rm_create_resource(&create_params); - if (ret) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "Create RM resource failed: %d", ret); - goto setup_rm_fail; - } - - memset(&create_params, 0, sizeof(create_params)); - create_params.name = IPA_RM_RESOURCE_WLAN_CONS; - create_params.request_resource = hdd_ipa_rm_cons_request; - create_params.release_resource = hdd_ipa_rm_cons_release; - create_params.floor_voltage = IPA_VOLTAGE_SVS; - - ret = ipa_rm_create_resource(&create_params); - if (ret) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "Create RM CONS resource failed: %d", ret); - goto delete_prod; - } - - ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD, - IPA_RM_RESOURCE_APPS_CONS); - - ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD, - HDD_IPA_RX_INACTIVITY_MSEC_DELAY); - if (ret) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d", - ret); - goto timer_init_failed; - } - - /* Set the lowest bandwidth to start with */ - ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0); - - if (ret) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "Set perf level failed: %d", ret); - goto set_perf_failed; - } - - qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa"); - INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work, - hdd_ipa_wake_lock_timer_func); - qdf_spinlock_create(&hdd_ipa->rm_lock); - hdd_ipa->rm_state = HDD_IPA_RM_RELEASED; - hdd_ipa->wake_lock_released = true; - atomic_set(&hdd_ipa->tx_ref_cnt, 0); - - return ret; - -set_perf_failed: - ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD); - -timer_init_failed: - ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS); - -delete_prod: - ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD); - -setup_rm_fail: - return ret; -} - -/** - * hdd_ipa_destroy_rm_resource() - Destroy IPA resources - * @hdd_ipa: Global HDD IPA context - * - * Destroys all resources associated with the IPA resource manager - * - * Return: None - */ -static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa) -{ - int ret; - - if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) - return; - - cancel_delayed_work_sync(&hdd_ipa->wake_lock_work); - qdf_wake_lock_destroy(&hdd_ipa->wake_lock); - cancel_work_sync(&hdd_ipa->uc_rm_work.work); - qdf_spinlock_destroy(&hdd_ipa->rm_lock); - - ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD); - - ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD); - if (ret) - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "RM PROD resource delete failed %d", ret); - - ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS); - if (ret) - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "RM CONS resource delete failed %d", ret); -} - -#ifdef PF_WAKE_UP_IDLE +#ifdef QCA_CONFIG_SMP /** * hdd_ipa_get_wake_up_idle() - Get PF_WAKE_UP_IDLE flag in the task structure * @@ -4368,7 +5250,12 @@ static void hdd_ipa_set_wake_up_idle(bool wake_up_idle) sched_set_wake_up_idle(current, wake_up_idle); } -#else + +static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb) +{ + return netif_rx_ni(skb); +} +#else /* QCA_CONFIG_SMP */ static uint32_t hdd_ipa_get_wake_up_idle(void) { return 0; @@ -4377,14 +5264,7 @@ static uint32_t hdd_ipa_get_wake_up_idle(void) static void hdd_ipa_set_wake_up_idle(bool wake_up_idle) { } -#endif -#ifdef QCA_CONFIG_SMP -static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb) -{ - return netif_rx_ni(skb); -} -#else static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb) { struct iphdr *ip_h; @@ -4411,7 +5291,7 @@ static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb) return result; } -#endif +#endif /* QCA_CONFIG_SMP */ /** * hdd_ipa_send_skb_to_network() - Send skb to kernel @@ -4757,7 +5637,7 @@ void hdd_ipa_nbuf_cb(qdf_nbuf_t skb) atomic_dec(&hdd_ipa->tx_ref_cnt); - hdd_ipa_rm_try_release(hdd_ipa); + hdd_ipa_wdi_rm_try_release(hdd_ipa); } /** @@ -4783,7 +5663,7 @@ static void hdd_ipa_send_pkt_to_tl( ipa_free_skb(ipa_tx_desc); iface_context->stats.num_tx_drop++; qdf_spin_unlock_bh(&iface_context->interface_lock); - hdd_ipa_rm_try_release(hdd_ipa); + hdd_ipa_wdi_rm_try_release(hdd_ipa); return; } @@ -4797,7 +5677,7 @@ static void hdd_ipa_send_pkt_to_tl( ipa_free_skb(ipa_tx_desc); qdf_spin_unlock_bh(&iface_context->interface_lock); iface_context->stats.num_tx_cac_drop++; - hdd_ipa_rm_try_release(hdd_ipa); + hdd_ipa_wdi_rm_try_release(hdd_ipa); return; } } @@ -4837,7 +5717,7 @@ static void hdd_ipa_send_pkt_to_tl( hdd_ipa->stats.num_tx_desc_error++; qdf_spin_unlock_bh(&hdd_ipa->q_lock); ipa_free_skb(ipa_tx_desc); - hdd_ipa_rm_try_release(hdd_ipa); + hdd_ipa_wdi_rm_try_release(hdd_ipa); return; } @@ -4979,7 +5859,7 @@ static void __hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt, * workaround to request PROD resource while data is going over CONS * pipe to prevent the IPA hardware clockdown. */ - hdd_ipa_rm_request(hdd_ipa); + hdd_ipa_wdi_rm_request(hdd_ipa); qdf_spin_lock_bh(&hdd_ipa->pm_lock); /* @@ -5233,7 +6113,8 @@ static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa) if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) ipa->keep_ipa_awake = 1; - ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl)); + ret = hdd_ipa_wdi_setup_sys_pipe(hdd_ipa, ipa, + &(hdd_ipa->sys_pipe[i].conn_hdl)); if (ret) { HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed for pipe %d ret: %d", i, ret); @@ -5270,7 +6151,8 @@ static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa) if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) ipa->keep_ipa_awake = 1; - ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl)); + ret = hdd_ipa_wdi_setup_sys_pipe(hdd_ipa, ipa, + &(hdd_ipa->sys_pipe[i].conn_hdl)); if (ret) { HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed for RX pipe: %d", ret); @@ -5293,7 +6175,8 @@ static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa) setup_sys_pipe_fail: while (--i >= 0) { - ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].conn_hdl); + hdd_ipa_wdi_teardown_sys_pipe(hdd_ipa, + hdd_ipa->sys_pipe[i].conn_hdl); qdf_mem_zero(&hdd_ipa->sys_pipe[i], sizeof(struct hdd_ipa_sys_pipe)); } @@ -5315,9 +6198,8 @@ static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa) for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) { if (hdd_ipa->sys_pipe[i].conn_hdl_valid) { - ret = - ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i]. - conn_hdl); + ret = hdd_ipa_wdi_teardown_sys_pipe(hdd_ipa, + hdd_ipa->sys_pipe[i].conn_hdl); if (ret) HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d", ret); @@ -5344,348 +6226,6 @@ static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa) } /** - * hdd_ipa_register_interface() - register IPA interface - * @hdd_ipa: Global IPA context - * @iface_context: Per-interface IPA context - * - * Return: 0 on success, negative errno on error - */ -static int hdd_ipa_register_interface(struct hdd_ipa_priv *hdd_ipa, - struct hdd_ipa_iface_context - *iface_context) -{ - struct ipa_tx_intf tx_intf; - struct ipa_rx_intf rx_intf; - struct ipa_ioc_tx_intf_prop *tx_prop = NULL; - struct ipa_ioc_rx_intf_prop *rx_prop = NULL; - char *ifname = iface_context->adapter->dev->name; - - char ipv4_hdr_name[IPA_RESOURCE_NAME_MAX]; - char ipv6_hdr_name[IPA_RESOURCE_NAME_MAX]; - - int num_prop = 1; - int ret = 0; - - if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) - num_prop++; - - /* Allocate TX properties for TOS categories, 1 each for IPv4 & IPv6 */ - tx_prop = - qdf_mem_malloc(sizeof(struct ipa_ioc_tx_intf_prop) * num_prop); - if (!tx_prop) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "tx_prop allocation failed"); - goto register_interface_fail; - } - - /* Allocate RX properties, 1 each for IPv4 & IPv6 */ - rx_prop = - qdf_mem_malloc(sizeof(struct ipa_ioc_rx_intf_prop) * num_prop); - if (!rx_prop) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "rx_prop allocation failed"); - goto register_interface_fail; - } - - qdf_mem_zero(&tx_intf, sizeof(tx_intf)); - qdf_mem_zero(&rx_intf, sizeof(rx_intf)); - - snprintf(ipv4_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s", - ifname, HDD_IPA_IPV4_NAME_EXT); - snprintf(ipv6_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s", - ifname, HDD_IPA_IPV6_NAME_EXT); - - rx_prop[IPA_IP_v4].ip = IPA_IP_v4; - rx_prop[IPA_IP_v4].src_pipe = iface_context->prod_client; - rx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; - rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA; - - /* - * Interface ID is 3rd byte in the CLD header. Add the meta data and - * mask to identify the interface in IPA hardware - */ - rx_prop[IPA_IP_v4].attrib.meta_data = - htonl(iface_context->adapter->sessionId << 16); - rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000); - - rx_intf.num_props++; - if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) { - rx_prop[IPA_IP_v6].ip = IPA_IP_v6; - rx_prop[IPA_IP_v6].src_pipe = iface_context->prod_client; - rx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; - rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA; - rx_prop[IPA_IP_v4].attrib.meta_data = - htonl(iface_context->adapter->sessionId << 16); - rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000); - - rx_intf.num_props++; - } - - tx_prop[IPA_IP_v4].ip = IPA_IP_v4; - tx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; - tx_prop[IPA_IP_v4].dst_pipe = IPA_CLIENT_WLAN1_CONS; - tx_prop[IPA_IP_v4].alt_dst_pipe = iface_context->cons_client; - strlcpy(tx_prop[IPA_IP_v4].hdr_name, ipv4_hdr_name, - IPA_RESOURCE_NAME_MAX); - tx_intf.num_props++; - - if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) { - tx_prop[IPA_IP_v6].ip = IPA_IP_v6; - tx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; - tx_prop[IPA_IP_v6].dst_pipe = IPA_CLIENT_WLAN1_CONS; - tx_prop[IPA_IP_v6].alt_dst_pipe = iface_context->cons_client; - strlcpy(tx_prop[IPA_IP_v6].hdr_name, ipv6_hdr_name, - IPA_RESOURCE_NAME_MAX); - tx_intf.num_props++; - } - - tx_intf.prop = tx_prop; - rx_intf.prop = rx_prop; - - /* Call the ipa api to register interface */ - ret = ipa_register_intf(ifname, &tx_intf, &rx_intf); - - /* Register IPA Tx desc free callback */ - qdf_nbuf_reg_free_cb(hdd_ipa_nbuf_cb); - -register_interface_fail: - qdf_mem_free(tx_prop); - qdf_mem_free(rx_prop); - return ret; -} - -/** - * hdd_remove_ipa_header() - Remove a specific header from IPA - * @name: Name of the header to be removed - * - * Return: None - */ -static void hdd_ipa_remove_header(char *name) -{ - struct ipa_ioc_get_hdr hdrlookup; - int ret = 0, len; - struct ipa_ioc_del_hdr *ipa_hdr; - - qdf_mem_zero(&hdrlookup, sizeof(hdrlookup)); - strlcpy(hdrlookup.name, name, sizeof(hdrlookup.name)); - ret = ipa_get_hdr(&hdrlookup); - if (ret) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Hdr deleted already %s, %d", - name, ret); - return; - } - - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "hdl: 0x%x", hdrlookup.hdl); - len = sizeof(struct ipa_ioc_del_hdr) + sizeof(struct ipa_hdr_del) * 1; - ipa_hdr = (struct ipa_ioc_del_hdr *)qdf_mem_malloc(len); - if (ipa_hdr == NULL) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "ipa_hdr allocation failed"); - return; - } - ipa_hdr->num_hdls = 1; - ipa_hdr->commit = 0; - ipa_hdr->hdl[0].hdl = hdrlookup.hdl; - ipa_hdr->hdl[0].status = -1; - ret = ipa_del_hdr(ipa_hdr); - if (ret != 0) - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Delete header failed: %d", - ret); - - qdf_mem_free(ipa_hdr); -} - -/** - * wlan_ipa_add_hdr() - Add IPA Tx header - * @ipa_hdr: pointer to IPA header addition parameters - * - * Call IPA API to add IPA Tx header descriptor - * and dump Tx header struct - * - * Return: 0 for success, non-zero for failure - */ -static int wlan_ipa_add_hdr(struct ipa_ioc_add_hdr *ipa_hdr) -{ - int ret; - - hdd_debug("==== IPA Tx Header ====\n" - "name: %s\n" - "hdr_len: %d\n" - "type: %d\n" - "is_partial: %d\n" - "hdr_hdl: 0x%x\n" - "status: %d\n" - "is_eth2_ofst_valid: %d\n" - "eth2_ofst: %d\n", - ipa_hdr->hdr[0].name, - ipa_hdr->hdr[0].hdr_len, - ipa_hdr->hdr[0].type, - ipa_hdr->hdr[0].is_partial, - ipa_hdr->hdr[0].hdr_hdl, - ipa_hdr->hdr[0].status, - ipa_hdr->hdr[0].is_eth2_ofst_valid, - ipa_hdr->hdr[0].eth2_ofst); - - HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG, "hdr:", - ipa_hdr->hdr[0].hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN); - - ret = ipa_add_hdr(ipa_hdr); - return ret; -} - -/** - * hdd_ipa_add_header_info() - Add IPA header for a given interface - * @hdd_ipa: Global HDD IPA context - * @iface_context: Interface-specific HDD IPA context - * @mac_addr: Interface MAC address - * - * Return: 0 on success, negativer errno value on error - */ -static int hdd_ipa_add_header_info(struct hdd_ipa_priv *hdd_ipa, - struct hdd_ipa_iface_context *iface_context, - uint8_t *mac_addr) -{ - hdd_adapter_t *adapter = iface_context->adapter; - char *ifname; - struct ipa_ioc_add_hdr *ipa_hdr = NULL; - int ret = -EINVAL; - struct hdd_ipa_tx_hdr *tx_hdr = NULL; - struct hdd_ipa_uc_tx_hdr *uc_tx_hdr = NULL; - - ifname = adapter->dev->name; - - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Add Partial hdr: %s, %pM", - ifname, mac_addr); - - /* dynamically allocate the memory to add the hdrs */ - ipa_hdr = qdf_mem_malloc(sizeof(struct ipa_ioc_add_hdr) - + sizeof(struct ipa_hdr_add)); - if (!ipa_hdr) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "%s: ipa_hdr allocation failed", ifname); - ret = -ENOMEM; - goto end; - } - - ipa_hdr->commit = 0; - ipa_hdr->num_hdrs = 1; - - if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { - uc_tx_hdr = (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr; - memcpy(uc_tx_hdr, &ipa_uc_tx_hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN); - memcpy(uc_tx_hdr->eth.h_source, mac_addr, ETH_ALEN); - uc_tx_hdr->ipa_hd.vdev_id = iface_context->adapter->sessionId; - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, - "ifname=%s, vdev_id=%d", - ifname, uc_tx_hdr->ipa_hd.vdev_id); - snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", - ifname, HDD_IPA_IPV4_NAME_EXT); - ipa_hdr->hdr[0].hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN; - ipa_hdr->hdr[0].type = IPA_HDR_L2_ETHERNET_II; - ipa_hdr->hdr[0].is_partial = 1; - ipa_hdr->hdr[0].hdr_hdl = 0; - ipa_hdr->hdr[0].is_eth2_ofst_valid = 1; - ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET; - - ret = wlan_ipa_add_hdr(ipa_hdr); - } else { - tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr; - - /* Set the Source MAC */ - memcpy(tx_hdr, &ipa_tx_hdr, HDD_IPA_WLAN_TX_HDR_LEN); - memcpy(tx_hdr->eth.h_source, mac_addr, ETH_ALEN); - - snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", - ifname, HDD_IPA_IPV4_NAME_EXT); - ipa_hdr->hdr[0].hdr_len = HDD_IPA_WLAN_TX_HDR_LEN; - ipa_hdr->hdr[0].is_partial = 1; - ipa_hdr->hdr[0].hdr_hdl = 0; - ipa_hdr->hdr[0].is_eth2_ofst_valid = 1; - ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_WLAN_HDR_DES_MAC_OFFSET; - - /* Set the type to IPV4 in the header */ - tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IP); - - ret = ipa_add_hdr(ipa_hdr); - } - if (ret) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "%s: IPv4 add hdr failed: %d", ifname, ret); - goto end; - } - - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: IPv4 hdr_hdl: 0x%x", - ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl); - - if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) { - snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", - ifname, HDD_IPA_IPV6_NAME_EXT); - - if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { - uc_tx_hdr = - (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr; - uc_tx_hdr->eth.h_proto = cpu_to_be16(ETH_P_IPV6); - ret = wlan_ipa_add_hdr(ipa_hdr); - } else { - /* Set the type to IPV6 in the header */ - tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr; - tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IPV6); - ret = ipa_add_hdr(ipa_hdr); - } - - if (ret) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "%s: IPv6 add hdr failed: %d", ifname, ret); - goto clean_ipv4_hdr; - } - - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: IPv6 hdr_hdl: 0x%x", - ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl); - } - - qdf_mem_free(ipa_hdr); - - return ret; - -clean_ipv4_hdr: - snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", - ifname, HDD_IPA_IPV4_NAME_EXT); - hdd_ipa_remove_header(ipa_hdr->hdr[0].name); -end: - if (ipa_hdr) - qdf_mem_free(ipa_hdr); - - return ret; -} - -/** - * hdd_ipa_clean_hdr() - Cleanup IPA on a given adapter - * @adapter: Adapter upon which IPA was previously configured - * - * Return: None - */ -static void hdd_ipa_clean_hdr(hdd_adapter_t *adapter) -{ - struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; - int ret; - char name_ipa[IPA_RESOURCE_NAME_MAX]; - - /* Remove the headers */ - snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s", - adapter->dev->name, HDD_IPA_IPV4_NAME_EXT); - hdd_ipa_remove_header(name_ipa); - - if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) { - snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s", - adapter->dev->name, HDD_IPA_IPV6_NAME_EXT); - hdd_ipa_remove_header(name_ipa); - } - /* unregister the interface with IPA */ - ret = ipa_deregister_intf(adapter->dev->name); - if (ret) - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, - "%s: ipa_deregister_intf fail: %d", - adapter->dev->name, ret); -} - -/** * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface * @iface_context: interface-specific IPA context * @@ -5705,7 +6245,8 @@ static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context) return; } - hdd_ipa_clean_hdr(iface_context->adapter); + hdd_ipa_wdi_dereg_intf(iface_context->hdd_ipa, + iface_context->adapter->dev->name); qdf_spin_lock_bh(&iface_context->interface_lock); /* @@ -5713,7 +6254,7 @@ static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context) * and check if the address has been already cleared by the * other thread */ - if (iface_context->adapter) { + if (!iface_context->adapter) { qdf_spin_unlock_bh(&iface_context->interface_lock); HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Already cleared"); goto end; @@ -5789,16 +6330,15 @@ static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa, iface_context->tl_context = tl_context; - ret = hdd_ipa_add_header_info(hdd_ipa, iface_context, - adapter->dev->dev_addr); - - if (ret) + ret = hdd_ipa_wdi_reg_intf(hdd_ipa, iface_context); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "IPA WDI reg intf failed ret=%d", ret); goto end; + } - /* Configure the TX and RX pipes filter rules */ - ret = hdd_ipa_register_interface(hdd_ipa, iface_context); - if (ret) - goto cleanup_header; + /* Register IPA Tx desc free callback */ + qdf_nbuf_reg_free_cb(hdd_ipa_nbuf_cb); hdd_ipa->num_iface++; @@ -5806,9 +6346,6 @@ static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa, hdd_ipa->num_iface); return ret; -cleanup_header: - - hdd_ipa_clean_hdr(adapter); end: if (iface_context) hdd_ipa_cleanup_iface(iface_context); @@ -6563,6 +7100,8 @@ static QDF_STATUS __hdd_ipa_init(hdd_context_t *hdd_ctx) hdd_ipa->hdd_ctx = hdd_ctx; hdd_ipa->num_iface = 0; + hdd_ipa_wdi_get_wdi_version(hdd_ipa); + /* Create the interface context */ for (i = 0; i < HDD_IPA_MAX_IFACE; i++) { iface_context = &hdd_ipa->iface_context[i]; @@ -6584,7 +7123,7 @@ static QDF_STATUS __hdd_ipa_init(hdd_context_t *hdd_ctx) qdf_mutex_create(&hdd_ipa->event_lock); qdf_mutex_create(&hdd_ipa->ipa_lock); - ret = hdd_ipa_setup_rm(hdd_ipa); + ret = hdd_ipa_wdi_setup_rm(hdd_ipa); if (ret) goto fail_setup_rm; @@ -6609,8 +7148,18 @@ static QDF_STATUS __hdd_ipa_init(hdd_context_t *hdd_ctx) INIT_WORK(&hdd_ipa->mcc_work, hdd_ipa_mcc_work_handler); } - if (hdd_ipa_uc_register_uc_ready(hdd_ipa)) - goto fail_create_sys_pipe; + + ret = hdd_ipa_wdi_init(hdd_ipa); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "ipa wdi init failed ret=%d", ret); + if (ret == -EACCES) { + if (hdd_ipa_uc_send_wdi_control_msg(false)) + goto fail_create_sys_pipe; + } else { + goto fail_create_sys_pipe; + } + } } else { ret = hdd_ipa_setup_sys_pipe(hdd_ipa); if (ret) @@ -6619,19 +7168,19 @@ static QDF_STATUS __hdd_ipa_init(hdd_context_t *hdd_ctx) /* When IPA clock scaling is disabled, initialze maximum clock */ if (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx)) { - profile.max_supported_bandwidth_mbps = 800; + profile.max_supported_bandwidth_mbps = HDD_IPA_MAX_BANDWIDTH; hdd_debug("IPA clock scaling is disabled."); hdd_debug("Set initial CONS/PROD perf: %d", profile.max_supported_bandwidth_mbps); - ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS, - &profile); + ret = hdd_ipa_wdi_rm_set_perf_profile(hdd_ipa, + IPA_RM_RESOURCE_WLAN_CONS, &profile); if (ret) { hdd_err("RM CONS set perf profile failed: %d", ret); goto fail_create_sys_pipe; } - ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD, - &profile); + ret = hdd_ipa_wdi_rm_set_perf_profile(hdd_ipa, + IPA_RM_RESOURCE_WLAN_PROD, &profile); if (ret) { hdd_err("RM PROD set perf profile failed: %d", ret); goto fail_create_sys_pipe; @@ -6644,7 +7193,7 @@ static QDF_STATUS __hdd_ipa_init(hdd_context_t *hdd_ctx) return QDF_STATUS_SUCCESS; fail_create_sys_pipe: - hdd_ipa_destroy_rm_resource(hdd_ipa); + hdd_ipa_wdi_destroy_rm(hdd_ipa); fail_setup_rm: qdf_spinlock_destroy(&hdd_ipa->pm_lock); qdf_mem_free(hdd_ipa); @@ -6734,8 +7283,7 @@ static QDF_STATUS __hdd_ipa_cleanup(hdd_context_t *hdd_ctx) cancel_work_sync(&hdd_ipa->mcc_work); } - hdd_ipa_destroy_rm_resource(hdd_ipa); - + hdd_ipa_wdi_destroy_rm(hdd_ipa); __hdd_ipa_flush(hdd_ctx); @@ -6749,9 +7297,7 @@ static QDF_STATUS __hdd_ipa_cleanup(hdd_context_t *hdd_ctx) } if (hdd_ipa_uc_is_enabled(hdd_ctx)) { - if (ipa_uc_dereg_rdyCB()) - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "UC Ready CB deregister fail"); + hdd_ipa_wdi_cleanup(); hdd_ipa_uc_rt_debug_deinit(hdd_ctx); qdf_mutex_destroy(&hdd_ipa->event_lock); qdf_mutex_destroy(&hdd_ipa->ipa_lock); diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 7daec3f41fcd..7a5bd1ac3677 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -730,13 +730,13 @@ int wlan_hdd_validate_context(hdd_context_t *hdd_ctx) if (cds_is_driver_in_bad_state()) { hdd_debug("%pS driver in bad State: 0x%x Ignore!!!", (void *)_RET_IP_, cds_get_driver_state()); - return -ENODEV; + return -EAGAIN; } if (cds_is_fw_down()) { hdd_debug("%pS FW is down: 0x%x Ignore!!!", (void *)_RET_IP_, cds_get_driver_state()); - return -ENODEV; + return -EAGAIN; } return 0; @@ -968,7 +968,10 @@ void hdd_update_macaddr(hdd_context_t *hdd_ctx, MAC_ADDRESS_STR, MAC_ADDR_ARRAY(hdd_ctx->derived_mac_addr[0].bytes)); } - for (i = 1; i < QDF_MAX_CONCURRENCY_PERSONA; i++) { + + for (i = hdd_ctx->num_derived_addr; + i < QDF_MAX_CONCURRENCY_PERSONA - hdd_ctx->num_provisioned_addr; + i++) { qdf_mem_copy(hdd_ctx->derived_mac_addr[i].bytes, hw_macaddr.bytes, QDF_MAC_ADDR_SIZE); @@ -3293,6 +3296,17 @@ QDF_STATUS hdd_init_station_mode(hdd_adapter_t *adapter) } } + if (adapter->device_mode == QDF_STA_MODE) { + hdd_debug("setting RTT mac randomization param: %d", + hdd_ctx->config->enable_rtt_mac_randomization); + ret_val = sme_cli_set_command(adapter->sessionId, + WMI_VDEV_PARAM_ENABLE_DISABLE_RTT_INITIATOR_RANDOM_MAC, + hdd_ctx->config->enable_rtt_mac_randomization, + VDEV_CMD); + if (0 != ret_val) + hdd_err("RTT mac randomization param set failed %d", + ret_val); + } /* * 1) When DBS hwmode is disabled from INI then send HT/VHT IE as per * non-dbs hw mode, so that there is no limitation applied for 2G/5G. @@ -3530,6 +3544,7 @@ static void hdd_ap_adapter_deinit(hdd_context_t *hdd_ctx, hdd_wmm_adapter_close(adapter); clear_bit(WMM_INIT_DONE, &adapter->event_flags); } + qdf_atomic_set(&adapter->sessionCtx.ap.acs_in_progress, 0); wlan_hdd_undo_acs(adapter); hdd_cleanup_actionframe(hdd_ctx, adapter); @@ -3568,6 +3583,50 @@ void hdd_deinit_adapter(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter, EXIT(); } +#ifdef WLAN_NS_OFFLOAD +/** + * hdd_ns_offload_info_lock_create() - Create mutex lock for ns offload info + * @adapter: pointer to adapter for which lock is to be created + * + * Return: None + */ +static void hdd_ns_offload_info_lock_create(hdd_adapter_t *adapter) +{ + qdf_mutex_create(&adapter->ns_offload_info_lock); +} + +/** + * hdd_ns_offload_info_lock_destroy() - Destroy mutex lock for ns offload info + * @adapter: pointer to adapter for which lock is to be destroyed + * + * Return: None + */ +static void hdd_ns_offload_info_lock_destroy(hdd_adapter_t *adapter) +{ + qdf_mutex_destroy(&adapter->ns_offload_info_lock); +} +#else +/** + * hdd_ns_offload_info_lock_create() - Create mutex lock for ns offload info + * @adapter: pointer to adapter for which lock is to be created + * + * Return: None + */ +static void hdd_ns_offload_info_lock_create(hdd_adapter_t *adapter) +{ +} + +/** + * hdd_ns_offload_info_lock_destroy() - Destroy mutex lock for ns offload info + * @adapter: pointer to adapter for which lock is to be destroyed + * + * Return: None + */ +static void hdd_ns_offload_info_lock_destroy(hdd_adapter_t *adapter) +{ +} +#endif + static void hdd_cleanup_adapter(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter, bool rtnl_held) { @@ -3580,6 +3639,10 @@ static void hdd_cleanup_adapter(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter, return; } + wlan_hdd_debugfs_csr_deinit(adapter); + qdf_mutex_destroy(&adapter->arp_offload_info_lock); + hdd_ns_offload_info_lock_destroy(adapter); + hdd_debugfs_exit(adapter); /* @@ -3725,50 +3788,6 @@ static void hdd_set_fw_log_params(hdd_context_t *hdd_ctx, #endif -#ifdef WLAN_NS_OFFLOAD -/** - * hdd_ns_offload_info_lock_create() - Create mutex lock for ns offload info - * @adapter: pointer to adapter for which lock is to be created - * - * Return: None - */ -static void hdd_ns_offload_info_lock_create(hdd_adapter_t *adapter) -{ - qdf_mutex_create(&adapter->ns_offload_info_lock); -} - -/** - * hdd_ns_offload_info_lock_destroy() - Destroy mutex lock for ns offload info - * @adapter: pointer to adapter for which lock is to be destroyed - * - * Return: None - */ -static void hdd_ns_offload_info_lock_destroy(hdd_adapter_t *adapter) -{ - qdf_mutex_destroy(&adapter->ns_offload_info_lock); -} -#else -/** - * hdd_ns_offload_info_lock_create() - Create mutex lock for ns offload info - * @adapter: pointer to adapter for which lock is to be created - * - * Return: None - */ -static void hdd_ns_offload_info_lock_create(hdd_adapter_t *adapter) -{ -} - -/** - * hdd_ns_offload_info_lock_destroy() - Destroy mutex lock for ns offload info - * @adapter: pointer to adapter for which lock is to be destroyed - * - * Return: None - */ -static void hdd_ns_offload_info_lock_destroy(hdd_adapter_t *adapter) -{ -} -#endif - /** * hdd_configure_chain_mask() - programs chain mask to firmware * @adapter: HDD adapter @@ -3933,6 +3952,16 @@ int hdd_set_fw_params(hdd_adapter_t *adapter) goto error; } + ret = sme_cli_set_command( + adapter->sessionId, + WMI_PDEV_PARAM_TX_SCH_DELAY, + hdd_ctx->config->enable_tx_sch_delay, + PDEV_CMD); + if (ret) { + hdd_err("Failed to set WMI_PDEV_PARAM_TX_SCH_DELAY"); + goto error; + } + if (adapter->device_mode == QDF_STA_MODE) { sme_set_smps_cfg(adapter->sessionId, HDD_STA_SMPS_PARAM_UPPER_BRSSI_THRESH, @@ -4292,6 +4321,9 @@ hdd_adapter_t *hdd_open_adapter(hdd_context_t *hdd_ctx, uint8_t session_type, qdf_mutex_create(&adapter->arp_offload_info_lock); hdd_ns_offload_info_lock_create(adapter); + if (adapter->device_mode == QDF_STA_MODE) + wlan_hdd_debugfs_csr_init(adapter); + return adapter; err_free_netdev: @@ -4329,9 +4361,6 @@ QDF_STATUS hdd_close_adapter(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter, hdd_bus_bw_compute_timer_stop(hdd_ctx); cancel_work_sync(&hdd_ctx->bus_bw_work); - qdf_mutex_destroy(&adapter->arp_offload_info_lock); - hdd_ns_offload_info_lock_destroy(adapter); - /* cleanup adapter */ cds_clear_concurrency_mode(adapter->device_mode); hdd_cleanup_adapter(hdd_ctx, adapterNode->pAdapter, rtnl_held); @@ -4567,11 +4596,6 @@ QDF_STATUS hdd_stop_adapter(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter, case QDF_P2P_DEVICE_MODE: case QDF_NDI_MODE: - if (adapter->device_mode == QDF_STA_MODE) { - hdd_debug("Destroy CSR debugfs files"); - wlan_hdd_debugfs_csr_deinit(adapter); - } - if ((QDF_NDI_MODE == adapter->device_mode) || hdd_conn_is_connected( WLAN_HDD_GET_STATION_CTX_PTR(adapter)) || @@ -4678,6 +4702,7 @@ QDF_STATUS hdd_stop_adapter(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter, /* Any softap specific cleanup here... */ sap_config = &adapter->sessionCtx.ap.sapConfig; wlansap_reset_sap_config_add_ie(sap_config, eUPDATE_IE_ALL); + qdf_atomic_set(&adapter->sessionCtx.ap.acs_in_progress, 0); wlan_hdd_undo_acs(adapter); if (adapter->device_mode == QDF_P2P_GO_MODE) wlan_hdd_cleanup_remain_on_channel_ctx(adapter); @@ -6405,6 +6430,7 @@ static void hdd_wlan_exit(hdd_context_t *hdd_ctx) qdf_spinlock_destroy(&hdd_ctx->hdd_adapter_lock); qdf_spinlock_destroy(&hdd_ctx->sta_update_info_lock); qdf_spinlock_destroy(&hdd_ctx->connection_status_lock); + qdf_mutex_destroy(&hdd_ctx->cache_channel_lock); /* * Close CDS @@ -8197,6 +8223,8 @@ void hdd_indicate_mgmt_frame(tSirSmeMgmtFrameInd *frame_ind) hdd_adapter_t *adapter = NULL; void *cds_context = NULL; int i; + hdd_adapter_list_node_t *adapter_node, *next; + QDF_STATUS status = QDF_STATUS_SUCCESS; /* Get the global VOSS context.*/ cds_context = cds_get_global_context(); @@ -8217,6 +8245,24 @@ void hdd_indicate_mgmt_frame(tSirSmeMgmtFrameInd *frame_ind) if (adapter) break; } + } else if (SME_SESSION_ID_BROADCAST == frame_ind->sessionId) { + status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) { + adapter = adapter_node->pAdapter; + if ((NULL != adapter) && + (WLAN_HDD_ADAPTER_MAGIC == adapter->magic)) { + __hdd_indicate_mgmt_frame(adapter, + frame_ind->frame_len, + frame_ind->frameBuf, + frame_ind->frameType, + frame_ind->rxChan, + frame_ind->rxRssi); + } + status = hdd_get_next_adapter(hdd_ctx, + adapter_node, &next); + adapter_node = next; + } + adapter = NULL; } else { adapter = hdd_get_adapter_by_sme_session_id(hdd_ctx, frame_ind->sessionId); @@ -8737,11 +8783,6 @@ int hdd_start_station_adapter(hdd_adapter_t *adapter) hdd_tx_resume_cb, hdd_tx_flow_control_is_pause); - if (adapter->device_mode == QDF_STA_MODE) { - hdd_debug("Create CSR debugfs files"); - wlan_hdd_debugfs_csr_init(adapter); - } - EXIT(); return 0; } @@ -10420,6 +10461,7 @@ int hdd_wlan_stop_modules(hdd_context_t *hdd_ctx, bool ftm_mode) bool is_recover_stop = cds_is_driver_recovering(); bool is_idle_stop = !is_unload_stop && !is_recover_stop; int active_threads; + int debugfs_threads; ENTER(); hdd_alert("stop WLAN module: entering driver status=%d", @@ -10436,11 +10478,15 @@ int hdd_wlan_stop_modules(hdd_context_t *hdd_ctx, bool ftm_mode) cds_set_module_stop_in_progress(true); active_threads = cds_return_external_threads_count(); - if (active_threads > 0 || hdd_ctx->isWiphySuspended) { - hdd_warn("External threads %d wiphy suspend %d", - active_threads, hdd_ctx->isWiphySuspended); + debugfs_threads = hdd_return_debugfs_threads_count(); + if (active_threads > 0 || debugfs_threads > 0 || + hdd_ctx->isWiphySuspended) { + hdd_warn("External threads %d, Debugfs threads %d, wiphy suspend %d", + active_threads, debugfs_threads, + hdd_ctx->isWiphySuspended); - cds_print_external_threads(); + if (active_threads) + cds_print_external_threads(); if (is_idle_stop && !ftm_mode) { mutex_unlock(&hdd_ctx->iface_change_lock); @@ -10533,6 +10579,8 @@ int hdd_wlan_stop_modules(hdd_context_t *hdd_ctx, bool ftm_mode) hdd_err("CNSS power down failed put device into Low power mode:%d", ret); } + /* Free the cache channels of the command SET_DISABLE_CHANNEL_LIST */ + wlan_hdd_free_cache_channels(hdd_ctx); /* many adapter resources are not freed by design in SSR case */ if (!is_recover_stop) @@ -10728,6 +10776,10 @@ int hdd_wlan_startup(struct device *dev) if (ret) goto err_hdd_free_context; + ret = qdf_mutex_create(&hdd_ctx->cache_channel_lock); + if (QDF_IS_STATUS_ERROR(ret)) + goto err_hdd_free_context; + hdd_request_manager_init(); hdd_green_ap_init(hdd_ctx); @@ -11162,8 +11214,6 @@ void hdd_softap_sta_disassoc(hdd_adapter_t *adapter, if (pDelStaParams->peerMacAddr.bytes[0] & 0x1) return; - wlan_hdd_get_peer_rssi(adapter, &pDelStaParams->peerMacAddr, - HDD_WLAN_GET_PEER_RSSI_SOURCE_DRIVER); wlansap_disassoc_sta(WLAN_HDD_GET_SAP_CTX_PTR(adapter), pDelStaParams); } diff --git a/core/hdd/src/wlan_hdd_nan_datapath.c b/core/hdd/src/wlan_hdd_nan_datapath.c index 95bb70f14d59..67b5bc8dccde 100644 --- a/core/hdd/src/wlan_hdd_nan_datapath.c +++ b/core/hdd/src/wlan_hdd_nan_datapath.c @@ -250,13 +250,11 @@ static int hdd_ndi_start_bss(hdd_adapter_t *adapter, roam_profile->csrPersona = adapter->device_mode; + if (!operating_channel) + operating_channel = NAN_SOCIAL_CHANNEL_2_4GHZ; + roam_profile->ChannelInfo.numOfChannels = 1; - if (operating_channel) { - roam_profile->ChannelInfo.ChannelList = &operating_channel; - } else { - roam_profile->ChannelInfo.ChannelList[0] = - NAN_SOCIAL_CHANNEL_2_4GHZ; - } + roam_profile->ChannelInfo.ChannelList = &operating_channel; roam_profile->SSIDs.numOfSSIDs = 1; roam_profile->SSIDs.SSIDList->SSID.length = 0; @@ -789,27 +787,36 @@ static int hdd_ndp_responder_req_handler(hdd_context_t *hdd_ctx, ENTER(); - if (tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]) { - iface_name = nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]); + /* First validate the response code from the user space */ + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE]) { + hdd_err("ndp_rsp code is unavailable"); + return -EINVAL; + } + req.ndp_rsp = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE]); - /* Check if iface exists */ + if (req.ndp_rsp == NDP_RESPONSE_ACCEPT) { + /* iface on which NDP is requested to be created */ + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]) { + hdd_err("NAN iface name not provided"); + return -ENODEV; + } + iface_name = nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]); adapter = hdd_get_adapter_by_iface_name(hdd_ctx, iface_name); if (!adapter) { - hdd_err("NAN data iface %s is unavailable", iface_name); + hdd_err("NAN iface %s unavailable", iface_name); return -ENODEV; } - if (!WLAN_HDD_IS_NDI(adapter)) { - hdd_err("Interface %s is not in NDI mode", iface_name); + hdd_err("Iface %s not in NDI mode", iface_name); return -ENODEV; } } else { /* - * If the data indication is rejected, the userspace - * may not send the iface name. Use the first available NDI - * in that case + * If the data indication is rejected, iface name in cmd is not + * required, hence the user provided iface name is discarded and + * first available NDI is used. */ - hdd_info("Iface name string is unavailable, use first NDI"); + hdd_debug("ndp response rejected, use first available NDI"); adapter = hdd_get_adapter(hdd_ctx, QDF_NDI_MODE); if (!adapter) { @@ -850,12 +857,6 @@ static int hdd_ndp_responder_req_handler(hdd_context_t *hdd_ctx, req.ndp_instance_id = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID]); - if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE]) { - hdd_err("ndp_rsp is unavailable"); - return -EINVAL; - } - req.ndp_rsp = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE]); - if (tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]) { req.ndp_info.ndp_app_info_len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]); diff --git a/core/hdd/src/wlan_hdd_p2p.c b/core/hdd/src/wlan_hdd_p2p.c index dfb623f7bdd8..fbcb9d3fff8f 100644 --- a/core/hdd/src/wlan_hdd_p2p.c +++ b/core/hdd/src/wlan_hdd_p2p.c @@ -1946,8 +1946,6 @@ static int __wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, uint8_t home_ch = 0; bool enb_random_mac = false; uint32_t mgmt_hdr_len = sizeof(struct ieee80211_hdr_3addr); - tHalHandle hHal = pHddCtx->hHal; - uint32_t scan_id; QDF_STATUS qdf_status; ENTER(); @@ -2261,11 +2259,18 @@ static int __wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, * but is not yet processed clean the roc ctx * and send response to upper layer. */ - scan_id = pRemainChanCtx->scan_id; mutex_unlock( &cfgState->remain_on_chan_ctx_lock); - wlan_hdd_remain_on_channel_callback(hHal, - pAdapter, QDF_STATUS_SUCCESS, scan_id); + INIT_COMPLETION(pAdapter-> + cancel_rem_on_chan_var); + rc = wait_for_completion_timeout(&pAdapter-> + cancel_rem_on_chan_var, + msecs_to_jiffies( + WAIT_CANCEL_REM_CHAN)); + if (!rc) { + hdd_err("Timeout waiting for cancel ROC indication"); + goto err_rem_channel; + } } mutex_lock(&cfgState->remain_on_chan_ctx_lock); pRemainChanCtx = cfgState->remain_on_chan_ctx; diff --git a/core/hdd/src/wlan_hdd_power.c b/core/hdd/src/wlan_hdd_power.c index 915beaef2788..1fa5285f6ca0 100644 --- a/core/hdd/src/wlan_hdd_power.c +++ b/core/hdd/src/wlan_hdd_power.c @@ -1474,6 +1474,20 @@ QDF_STATUS hdd_wlan_shutdown(void) hdd_debug("Invoking packetdump deregistration API"); wlan_deregister_txrx_packetdump(); + /* + * After SSR, FW clear its txrx stats. In host, + * as adapter is intact so those counts are still + * available. Now if agains Set stats command comes, + * then host will increment its counts start from its + * last saved value, i.e., count before SSR, and FW will + * increment its count from 0. This will finally sends a + * mismatch of packet counts b/w host and FW to framework + * that will create ambiquity. Therfore, Resetting the host + * counts here so that after SSR both FW and host start + * increment their counts from 0. + */ + hdd_reset_all_adapters_connectivity_stats(pHddCtx); + hdd_reset_all_adapters(pHddCtx); /* Flush cached rx frame queue */ diff --git a/core/hdd/src/wlan_hdd_scan.c b/core/hdd/src/wlan_hdd_scan.c index 31c9cb3fad1f..948986339295 100644 --- a/core/hdd/src/wlan_hdd_scan.c +++ b/core/hdd/src/wlan_hdd_scan.c @@ -626,6 +626,14 @@ static void hdd_update_dbs_scan_ctrl_ext_flag(hdd_context_t *hdd_ctx, /* Resetting the scan_ctrl_flags_ext to 0 */ scan_req->scan_ctrl_flags_ext = 0; + if ((hdd_ctx->config->dual_mac_feature_disable == + DISABLE_DBS_CXN_AND_SCAN) || + (hdd_ctx->config->dual_mac_feature_disable == + ENABLE_DBS_CXN_AND_DISABLE_DBS_SCAN)) { + hdd_debug("DBS is disabled"); + goto end; + } + if (scan_req->scan_flags & SME_SCAN_FLAG_HIGH_ACCURACY) { hdd_debug("DBS disabled due to high accuracy scan request"); goto end; @@ -644,14 +652,6 @@ static void hdd_update_dbs_scan_ctrl_ext_flag(hdd_context_t *hdd_ctx, goto end; } - if ((hdd_ctx->config->dual_mac_feature_disable == - DISABLE_DBS_CXN_AND_SCAN) || - (hdd_ctx->config->dual_mac_feature_disable == - ENABLE_DBS_CXN_AND_DISABLE_DBS_SCAN)) { - hdd_debug("DBS is disabled"); - goto end; - } - conn_cnt = cds_get_connection_count(); if (conn_cnt > 0) { hdd_debug("%d active connections, go for DBS scan", conn_cnt); diff --git a/core/hdd/src/wlan_hdd_softap_tx_rx.c b/core/hdd/src/wlan_hdd_softap_tx_rx.c index 390dc97aac93..44d19d64622a 100644 --- a/core/hdd/src/wlan_hdd_softap_tx_rx.c +++ b/core/hdd/src/wlan_hdd_softap_tx_rx.c @@ -1015,6 +1015,8 @@ QDF_STATUS hdd_softap_stop_bss(hdd_adapter_t *pAdapter) } } } + if (pAdapter->device_mode == QDF_SAP_MODE) + wlan_hdd_restore_channels(pHddCtx); /* Mark the indoor channel (passive) to enable */ if (pHddCtx->config->disable_indoor_channel) { diff --git a/core/hdd/src/wlan_hdd_tsf.c b/core/hdd/src/wlan_hdd_tsf.c index a9ef1a231960..5bacd90cf155 100644 --- a/core/hdd/src/wlan_hdd_tsf.c +++ b/core/hdd/src/wlan_hdd_tsf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -274,18 +274,19 @@ static enum hdd_tsf_op_result hdd_indicate_tsf_internal( #ifdef WLAN_FEATURE_TSF_PLUS /* unit for target time: us; host time: ns */ #define HOST_TO_TARGET_TIME_RATIO NSEC_PER_USEC -#define MAX_ALLOWED_DEVIATION_NS (20 * NSEC_PER_MSEC) +#define MAX_ALLOWED_DEVIATION_NS (100 * NSEC_PER_USEC) #define MAX_CONTINUOUS_ERROR_CNT 3 /* to distinguish 32-bit overflow case, this inverval should: * equal or less than (1/2 * OVERFLOW_INDICATOR32 us) */ -#define WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC 500 +#define WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC 10 #define WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS 100 #define NORMAL_INTERVAL_TARGET \ ((int64_t)((int64_t)WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC * \ NSEC_PER_SEC / HOST_TO_TARGET_TIME_RATIO)) #define OVERFLOW_INDICATOR32 (((int64_t)0x1) << 32) +#define CAP_TSF_TIMER_FIX_SEC 1 /** * TS_STATUS - timestamp status @@ -466,8 +467,21 @@ static void hdd_update_timestamp(hdd_adapter_t *adapter, hdd_info("ts-pair updated: target: %llu; host: %llu", adapter->last_target_time, adapter->last_host_time); - interval = WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC * - MSEC_PER_SEC; + + /* + * TSF-HOST need to be updated in at most + * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC, it couldn't be achieved + * if the timer interval is also + * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC, due to processing or + * schedule delay. So deduct several seconds from + * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC. + * Without this change, hdd_get_hosttime_from_targettime() will + * get wrong host time when it's longer than + * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC from last + * TSF-HOST update. + */ + interval = (WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC - + CAP_TSF_TIMER_FIX_SEC) * MSEC_PER_SEC; adapter->continuous_error_count = 0; break; case HDD_TS_STATUS_WAITING: diff --git a/core/hdd/src/wlan_hdd_tx_rx.c b/core/hdd/src/wlan_hdd_tx_rx.c index 154000ef57f2..4a29abd36e83 100644 --- a/core/hdd/src/wlan_hdd_tx_rx.c +++ b/core/hdd/src/wlan_hdd_tx_rx.c @@ -506,6 +506,56 @@ static void hdd_get_transmit_sta_id(hdd_adapter_t *adapter, } /** + * hdd_clear_tx_rx_connectivity_stats() - clear connectivity stats + * @hdd_ctx: pointer to HDD Station Context + * + * Return: None + */ +static void hdd_clear_tx_rx_connectivity_stats(hdd_adapter_t *adapter) +{ + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, + "Clear txrx connectivity stats"); + qdf_mem_zero(&adapter->hdd_stats.hdd_arp_stats, + sizeof(adapter->hdd_stats.hdd_arp_stats)); + qdf_mem_zero(&adapter->hdd_stats.hdd_dns_stats, + sizeof(adapter->hdd_stats.hdd_dns_stats)); + qdf_mem_zero(&adapter->hdd_stats.hdd_tcp_stats, + sizeof(adapter->hdd_stats.hdd_tcp_stats)); + qdf_mem_zero(&adapter->hdd_stats.hdd_icmpv4_stats, + sizeof(adapter->hdd_stats.hdd_icmpv4_stats)); + adapter->pkt_type_bitmap = 0; + adapter->track_arp_ip = 0; + qdf_mem_zero(adapter->dns_payload, adapter->track_dns_domain_len); + adapter->track_dns_domain_len = 0; + adapter->track_src_port = 0; + adapter->track_dest_port = 0; + adapter->track_dest_ipv4 = 0; +} + +void hdd_reset_all_adapters_connectivity_stats(hdd_context_t *hdd_ctx) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + QDF_STATUS status; + hdd_adapter_t *adapter; + + ENTER(); + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + hdd_clear_tx_rx_connectivity_stats(adapter); + + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + + EXIT(); + +} + + +/** * hdd_tx_rx_is_dns_domain_name_match() - function to check whether dns * domain name in the received skb matches with the tracking dns domain * name or not @@ -790,7 +840,8 @@ static inline bool hdd_is_tx_allowed(struct sk_buff *skb, uint8_t peer_id) if (OL_TXRX_PEER_STATE_AUTH == peer_state) return true; else if (OL_TXRX_PEER_STATE_CONN == peer_state && - ntohs(skb->protocol) == HDD_ETHERTYPE_802_1_X) + (ntohs(skb->protocol) == HDD_ETHERTYPE_802_1_X + || IS_HDD_ETHERTYPE_WAI(skb))) return true; DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_DROP_PACKET_RECORD, (uint8_t *)skb->data, @@ -996,6 +1047,10 @@ static netdev_tx_t __hdd_hard_start_xmit(struct sk_buff *skb, goto drop_pkt_and_release_skb; } if (!hdd_is_tx_allowed(skb, STAId)) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Tx is not allowed. drop the pkt", + __func__); ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac]; goto drop_pkt_and_release_skb; } diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c index b0d92b833d69..f987db26b0ed 100644 --- a/core/hdd/src/wlan_hdd_wext.c +++ b/core/hdd/src/wlan_hdd_wext.c @@ -3367,7 +3367,7 @@ int hdd_wlan_get_frag_threshold(hdd_adapter_t *pAdapter, * @channel: channel to be converted * @pfreq: where to store the frequency * - * Return: 1 on success, otherwise a negative errno + * Return: 0 on success, otherwise a negative errno */ int hdd_wlan_get_freq(uint32_t channel, uint32_t *pfreq) { @@ -3377,7 +3377,7 @@ int hdd_wlan_get_freq(uint32_t channel, uint32_t *pfreq) for (i = 0; i < FREQ_CHAN_MAP_TABLE_SIZE; i++) { if (channel == freq_chan_map[i].chan) { *pfreq = freq_chan_map[i].freq; - return 1; + return 0; } } } @@ -3431,6 +3431,7 @@ static bool hdd_is_auth_type_rsn(eCsrAuthType authType) case eCSR_AUTH_TYPE_RSN_PSK_SHA256: case eCSR_AUTH_TYPE_RSN_8021X_SHA256: #endif + case eCSR_AUTH_TYPE_DPP_RSN: rsnType = true; break; /* case eCSR_AUTH_TYPE_FAILED: */ @@ -3937,9 +3938,8 @@ static void hdd_get_peer_rssi_cb(struct sir_peer_info_resp *sta_rssi, { struct statsContext *get_rssi_context; struct sir_peer_info *rssi_info; - uint8_t peer_num, i; + uint8_t peer_num; hdd_adapter_t *padapter; - hdd_station_info_t *stainfo; if ((sta_rssi == NULL) || (context == NULL)) { hdd_err("Bad param, sta_rssi [%pK] context [%pK]", @@ -3983,19 +3983,6 @@ static void hdd_get_peer_rssi_cb(struct sir_peer_info_resp *sta_rssi, peer_num * sizeof(*rssi_info)); padapter->peer_sta_info.sta_num = peer_num; - for (i = 0; i < peer_num; i++) { - stainfo = hdd_get_stainfo(padapter->cache_sta_info, - rssi_info[i].peer_macaddr); - if (stainfo) { - stainfo->rssi = rssi_info[i].rssi; - stainfo->tx_rate = rssi_info[i].tx_rate; - stainfo->rx_rate = rssi_info[i].rx_rate; - hdd_info("rssi:%d tx_rate:%u rx_rate:%u %pM", - stainfo->rssi, stainfo->tx_rate, - stainfo->rx_rate, stainfo->macAddrSTA.bytes); - } - } - /* notify the caller */ complete(&get_rssi_context->completion); @@ -4879,7 +4866,7 @@ static int __iw_get_freq(struct net_device *dev, struct iw_request_info *info, return -EIO; } status = hdd_wlan_get_freq(channel, &freq); - if (true == status) { + if (0 == status) { /* Set Exponent parameter as 6 (MHZ) * in struct iw_freq iwlist & iwconfig * command shows frequency into proper diff --git a/core/mac/inc/ani_global.h b/core/mac/inc/ani_global.h index e3b484a7849a..fdc6cf84cb27 100644 --- a/core/mac/inc/ani_global.h +++ b/core/mac/inc/ani_global.h @@ -1019,6 +1019,10 @@ typedef struct sAniSirGlobal { /* 11k Offload Support */ bool is_11k_offload_supported; + + uint32_t peer_rssi; + uint32_t peer_txrate; + uint32_t peer_rxrate; } tAniSirGlobal; typedef enum { diff --git a/core/mac/inc/qwlan_version.h b/core/mac/inc/qwlan_version.h index 4a79a097a8ce..d76af685d152 100644 --- a/core/mac/inc/qwlan_version.h +++ b/core/mac/inc/qwlan_version.h @@ -41,9 +41,9 @@ #define QWLAN_VERSION_MAJOR 5 #define QWLAN_VERSION_MINOR 1 #define QWLAN_VERSION_PATCH 1 -#define QWLAN_VERSION_EXTRA "H" -#define QWLAN_VERSION_BUILD 51 +#define QWLAN_VERSION_EXTRA "R" +#define QWLAN_VERSION_BUILD 52 -#define QWLAN_VERSIONSTR "5.1.1.51H" +#define QWLAN_VERSIONSTR "5.1.1.52R" #endif /* QWLAN_VERSION_H */ diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h index c43a179c4be5..4873e98b3a87 100644 --- a/core/mac/inc/sir_api.h +++ b/core/mac/inc/sir_api.h @@ -783,7 +783,6 @@ typedef struct sSirSmeStartBssReq { uint8_t sap_dot11mc; uint16_t beacon_tx_rate; bool vendor_vht_sap; - } tSirSmeStartBssReq, *tpSirSmeStartBssReq; #define GET_IE_LEN_IN_BSS(lenInBss) (lenInBss + sizeof(lenInBss) - \ @@ -3608,6 +3607,7 @@ typedef struct sSirRoamOffloadScanReq { uint8_t ValidChannelCount; uint8_t ValidChannelList[SIR_ROAM_MAX_CHANNELS]; bool IsESEAssoc; + bool is_11r_assoc; uint8_t nProbes; uint16_t HomeAwayTime; tSirRoamNetworkType ConnectedNetwork; diff --git a/core/mac/inc/sir_mac_prot_def.h b/core/mac/inc/sir_mac_prot_def.h index c47b500d8e5c..6613670b3700 100644 --- a/core/mac/inc/sir_mac_prot_def.h +++ b/core/mac/inc/sir_mac_prot_def.h @@ -217,6 +217,11 @@ #define SIR_MAC_ACTION_EXT_CHANNEL_SWITCH_ID 4 #define SIR_MAC_ACTION_MEASUREMENT_PILOT 7 +/* Public Action frames for GAS */ +#define SIR_MAC_ACTION_GAS_INITIAL_REQUEST 0x0A +#define SIR_MAC_ACTION_GAS_INITIAL_RESPONSE 0x0B +#define SIR_MAC_ACTION_GAS_COMEBACK_REQUEST 0x0C +#define SIR_MAC_ACTION_GAS_COMEBACK_RESPONSE 0x0D #ifdef WLAN_FEATURE_11W /* 11w SA query request/response action frame category code */ diff --git a/core/mac/src/include/dph_global.h b/core/mac/src/include/dph_global.h index 55779288ef7c..d5e38e4293da 100644 --- a/core/mac/src/include/dph_global.h +++ b/core/mac/src/include/dph_global.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -173,6 +173,11 @@ typedef struct sDphHashNode { tDphQosParams qos; /* station version info - valid only if versionPresent is set */ tSirMacPropVersion version; + /* Previous authentication packet sequence number */ + uint16_t prev_auth_seq_no; + /* Previous association packet sequence number */ + uint16_t prev_assoc_seq_no; + #ifdef PLM_WDS uint8_t wdsIndex; uint8_t wdsPeerBeaconSeen; diff --git a/core/mac/src/include/parser_api.h b/core/mac/src/include/parser_api.h index 8affc7789f8c..fdc879c9d77d 100644 --- a/core/mac/src/include/parser_api.h +++ b/core/mac/src/include/parser_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -54,6 +54,14 @@ #define IS_5G_CH(__chNum) ((__chNum >= 36) && (__chNum <= 165)) #define IS_2X2_CHAIN(__chain) ((__chain & 0x3) == 0x3) #define DISABLE_NSS2_MCS 0xC +#define VHT_1x1_MCS9_MAP 0x2 +#define VHT_2x2_MCS9_MAP 0xA +#define VHT_1x1_MCS8_VAL 0xFFFD +#define VHT_2x2_MCS8_VAL 0xFFF5 +#define VHT_1x1_MCS_MASK 0x3 +#define VHT_2x2_MCS_MASK 0xF +#define DISABLE_VHT_MCS_9(mcs, nss) \ + (mcs = (nss > 1) ? VHT_2x2_MCS8_VAL : VHT_1x1_MCS8_VAL) #define NSS_1x1_MODE 1 #define NSS_2x2_MODE 2 diff --git a/core/mac/src/pe/include/rrm_global.h b/core/mac/src/pe/include/rrm_global.h index d8afcfa50e7f..e963ca276ed8 100644 --- a/core/mac/src/pe/include/rrm_global.h +++ b/core/mac/src/pe/include/rrm_global.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2012, 2014-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2012, 2014-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -217,6 +217,7 @@ typedef struct sRrmPEContext { int8_t txMgmtPower; /* Dialog token for the request initiated from station. */ uint8_t DialogToken; + uint16_t prev_rrm_report_seq_num; tpRRMReq pCurrentReq; } tRrmPEContext, *tpRrmPEContext; diff --git a/core/mac/src/pe/lim/lim_api.c b/core/mac/src/pe/lim/lim_api.c index 97f192bcfcdf..2d6f092bb19e 100644 --- a/core/mac/src/pe/lim/lim_api.c +++ b/core/mac/src/pe/lim/lim_api.c @@ -2011,6 +2011,21 @@ static inline void lim_copy_and_free_hlp_data_from_session( {} #endif +static const char *pe_roam_op_code_to_string(uint8_t roam_op_code) +{ + switch (roam_op_code) { + CASE_RETURN_STRING(SIR_ROAM_SYNCH_PROPAGATION); + CASE_RETURN_STRING(SIR_ROAMING_DEREGISTER_STA); + CASE_RETURN_STRING(SIR_ROAMING_START); + CASE_RETURN_STRING(SIR_ROAMING_ABORT); + CASE_RETURN_STRING(SIR_ROAM_SYNCH_COMPLETE); + CASE_RETURN_STRING(SIR_ROAM_SYNCH_NAPI_OFF); + CASE_RETURN_STRING(SIR_ROAMING_INVOKE_FAIL); + default: + return "none"; + } +} + /** * pe_roam_synch_callback() - PE level callback for roam synch propagation * @mac_ctx: MAC Context @@ -2053,7 +2068,8 @@ QDF_STATUS pe_roam_synch_callback(tpAniSirGlobal mac_ctx, return status; } - pe_debug("LFR3: PE callback reason: %d", reason); + pe_debug("LFR3: PE callback reason: %d %s", reason, + pe_roam_op_code_to_string(reason)); switch (reason) { case SIR_ROAMING_START: session_ptr->fw_roaming_started = true; @@ -2085,10 +2101,6 @@ QDF_STATUS pe_roam_synch_callback(tpAniSirGlobal mac_ctx, return status; } - pe_debug("LFR3:Received WMA_ROAM_OFFLOAD_SYNCH_IND LFR3:auth: %d vdevId: %d", - roam_sync_ind_ptr->authStatus, roam_sync_ind_ptr->roamedVdevId); - lim_print_mac_addr(mac_ctx, roam_sync_ind_ptr->bssid.bytes, - QDF_TRACE_LEVEL_DEBUG); /* * If deauth from AP already in progress, ignore Roam Synch Indication * from firmware. diff --git a/core/mac/src/pe/lim/lim_assoc_utils.c b/core/mac/src/pe/lim/lim_assoc_utils.c index e7ca136f209a..427252ee9c2d 100644 --- a/core/mac/src/pe/lim/lim_assoc_utils.c +++ b/core/mac/src/pe/lim/lim_assoc_utils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1396,6 +1396,25 @@ tSirRetStatus lim_populate_vht_mcs_set(tpAniSirGlobal mac_ctx, VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1; rates->vhtRxHighestDataRate = VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + if (!session_entry->ch_width && + !mac_ctx->roam.configParam.enable_vht20_mcs9 && + ((rates->vhtRxMCSMap & VHT_1x1_MCS_MASK) == + VHT_1x1_MCS9_MAP)) { + DISABLE_VHT_MCS_9(rates->vhtRxMCSMap, + NSS_1x1_MODE); + DISABLE_VHT_MCS_9(rates->vhtTxMCSMap, + NSS_1x1_MODE); + } + } else { + if (!session_entry->ch_width && + !mac_ctx->roam.configParam.enable_vht20_mcs9 && + ((rates->vhtRxMCSMap & VHT_2x2_MCS_MASK) == + VHT_2x2_MCS9_MAP)) { + DISABLE_VHT_MCS_9(rates->vhtRxMCSMap, + NSS_2x2_MODE); + DISABLE_VHT_MCS_9(rates->vhtTxMCSMap, + NSS_2x2_MODE); + } } if ((peer_vht_caps == NULL) || (!peer_vht_caps->present)) diff --git a/core/mac/src/pe/lim/lim_p2p.c b/core/mac/src/pe/lim/lim_p2p.c index 50aef50354f5..2b58f5799caa 100644 --- a/core/mac/src/pe/lim/lim_p2p.c +++ b/core/mac/src/pe/lim/lim_p2p.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -395,6 +395,13 @@ void lim_send_sme_mgmt_frame_ind(tpAniSirGlobal pMac, uint8_t frameType, return; } + if (qdf_is_macaddr_broadcast( + (struct qdf_mac_addr *) pSirSmeMgmtFrame->frameBuf + 4) && + !sessionId) { + pe_debug("Broadcast action frame"); + sessionId = SME_SESSION_ID_BROADCAST; + } + pSirSmeMgmtFrame->frame_len = frameLen; pSirSmeMgmtFrame->sessionId = sessionId; pSirSmeMgmtFrame->frameType = frameType; 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 d0cb44918a0e..583d0542c655 100644 --- a/core/mac/src/pe/lim/lim_process_action_frame.c +++ b/core/mac/src/pe/lim/lim_process_action_frame.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1295,6 +1295,7 @@ __lim_process_radio_measure_request(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, tDot11fRadioMeasurementRequest *frm; uint32_t frameLen, nStatus; uint8_t *pBody; + uint16_t curr_seq_num; pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); @@ -1304,6 +1305,17 @@ __lim_process_radio_measure_request(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, return; } + curr_seq_num = ((pHdr->seqControl.seqNumHi << + HIGH_SEQ_NUM_OFFSET) | + pHdr->seqControl.seqNumLo); + if (curr_seq_num == pMac->rrm.rrmPEContext.prev_rrm_report_seq_num && + pMac->rrm.rrmPEContext.pCurrentReq) { + pe_err("rrm report req frame, seq num: %d is already in progress, drop it", + curr_seq_num); + return; + } + /* Save seq no of currently processing rrm report req frame */ + pMac->rrm.rrmPEContext.prev_rrm_report_seq_num = curr_seq_num; lim_send_sme_mgmt_frame_ind(pMac, pHdr->fc.subType, (uint8_t *)pHdr, frameLen + sizeof(tSirMacMgmtHdr), 0, WMA_GET_RX_CH(pRxPacketInfo), psessionEntry, @@ -1938,7 +1950,13 @@ void lim_process_action_frame(tpAniSirGlobal mac_ctx, } break; case SIR_MAC_ACTION_PUBLIC_USAGE: + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); switch (action_hdr->actionID) { + case SIR_MAC_ACTION_EXT_CHANNEL_SWITCH_ID: + lim_process_ext_channel_switch_action_frame(mac_ctx, + rx_pkt_info, session); + break; case SIR_MAC_ACTION_VENDOR_SPECIFIC: pub_action = (tpSirMacVendorSpecificPublicActionFrameHdr) @@ -1947,58 +1965,30 @@ void lim_process_action_frame(tpAniSirGlobal mac_ctx, lim_process_action_vendor_specific(mac_ctx, rx_pkt_info, pub_action, session); break; - /* Handle vendor specific action */ case SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY: - { - tpSirMacMgmtHdr header; - uint32_t frame_len; - - header = WMA_GET_RX_MAC_HEADER(rx_pkt_info); - frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); - lim_send_sme_mgmt_frame_ind(mac_ctx, header->fc.subType, - (uint8_t *)header, frame_len + sizeof(tSirMacMgmtHdr), 0, - WMA_GET_RX_CH(rx_pkt_info), NULL, - WMA_GET_RX_RSSI_RAW(rx_pkt_info)); - break; - } - case SIR_MAC_ACTION_2040_BSS_COEXISTENCE: - mac_hdr = NULL; - frame_len = 0; - - mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); - frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); - - lim_send_sme_mgmt_frame_ind(mac_ctx, - mac_hdr->fc.subType, - (uint8_t *) mac_hdr, - frame_len + sizeof(tSirMacMgmtHdr), - session->smeSessionId, - WMA_GET_RX_CH(rx_pkt_info), session, - WMA_GET_RX_RSSI_NORMALIZED( - rx_pkt_info)); - break; + case SIR_MAC_ACTION_GAS_INITIAL_REQUEST: + case SIR_MAC_ACTION_GAS_INITIAL_RESPONSE: + case SIR_MAC_ACTION_GAS_COMEBACK_REQUEST: + case SIR_MAC_ACTION_GAS_COMEBACK_RESPONSE: #ifdef FEATURE_WLAN_TDLS case SIR_MAC_TDLS_DIS_RSP: - mac_hdr = NULL; - frame_len = 0; - - mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); - frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); - rssi = WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info); - pe_debug("Public Action TDLS Discovery RSP"); +#endif + /* + * Frame forwarded to SME to HDD to supplicant + * type is action + */ + pe_debug("Public Action Frame %d received", + action_hdr->actionID); lim_send_sme_mgmt_frame_ind(mac_ctx, - mac_hdr->fc.subType, (uint8_t *) mac_hdr, + mac_hdr->fc.subType, + (uint8_t *) mac_hdr, frame_len + sizeof(tSirMacMgmtHdr), session->smeSessionId, WMA_GET_RX_CH(rx_pkt_info), session, WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info)); break; -#endif - case SIR_MAC_ACTION_EXT_CHANNEL_SWITCH_ID: - lim_process_ext_channel_switch_action_frame(mac_ctx, - rx_pkt_info, session); - break; + default: pe_warn("Unhandled public action frame: %x", action_hdr->actionID); @@ -2118,31 +2108,52 @@ void lim_process_action_frame(tpAniSirGlobal mac_ctx, void lim_process_action_frame_no_session(tpAniSirGlobal pMac, uint8_t *pBd) { + tpSirMacMgmtHdr mac_hdr = WMA_GET_RX_MAC_HEADER(pBd); + uint32_t frame_len = WMA_GET_RX_PAYLOAD_LEN(pBd); uint8_t *pBody = WMA_GET_RX_MPDU_DATA(pBd); - tpSirMacVendorSpecificPublicActionFrameHdr pActionHdr = - (tpSirMacVendorSpecificPublicActionFrameHdr) pBody; + tpSirMacActionFrameHdr action_hdr = (tpSirMacActionFrameHdr) pBody; + tpSirMacVendorSpecificPublicActionFrameHdr vendor_specific; pe_debug("Received a Action frame -- no session"); - switch (pActionHdr->category) { + switch (action_hdr->category) { case SIR_MAC_ACTION_PUBLIC_USAGE: - switch (pActionHdr->actionID) { + switch (action_hdr->actionID) { case SIR_MAC_ACTION_VENDOR_SPECIFIC: - { + vendor_specific = + (tpSirMacVendorSpecificPublicActionFrameHdr) + action_hdr; lim_process_action_vendor_specific(pMac, pBd, - pActionHdr, NULL); - } + vendor_specific, + NULL); + break; + case SIR_MAC_ACTION_GAS_INITIAL_REQUEST: + case SIR_MAC_ACTION_GAS_INITIAL_RESPONSE: + case SIR_MAC_ACTION_GAS_COMEBACK_REQUEST: + case SIR_MAC_ACTION_GAS_COMEBACK_RESPONSE: + /* + * Frame forwarded to SME to HDD to supplicant + * type is action + */ + pe_debug("Public Action Frame %d received", + action_hdr->actionID); + lim_send_sme_mgmt_frame_ind(pMac, + mac_hdr->fc.subType, + (uint8_t *) mac_hdr, + frame_len + sizeof(tSirMacMgmtHdr), 0, + WMA_GET_RX_CH(pBd), NULL, + WMA_GET_RX_RSSI_NORMALIZED(pBd)); + break; default: pe_warn("Unhandled public action frame: %x", - pActionHdr->actionID); + action_hdr->actionID); break; } break; default: pe_warn("Unhandled action frame without session: %x", - pActionHdr->category); + action_hdr->category); break; - } } 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 3e3345768882..dfbe6cbc95ca 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 @@ -1102,6 +1102,7 @@ static bool lim_process_assoc_req_sta_ctx(tpAniSirGlobal mac_ctx, eLIM_MLM_AUTHENTICATED_STATE)) { /* STA has triggered pre-auth again */ *auth_type = sta_pre_auth_ctx->authType; + sta_ds->prev_auth_seq_no = sta_pre_auth_ctx->seq_num; lim_delete_pre_auth_node(mac_ctx, hdr->sa); } else { *auth_type = sta_ds->mlmStaContext.authType; @@ -1248,6 +1249,9 @@ static bool lim_update_sta_ds(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, sta_ds->qos.addts = assoc_req->addtsReq; sta_ds->qos.capability = assoc_req->qosCapability; sta_ds->versionPresent = 0; + sta_ds->prev_assoc_seq_no = (((hdr->seqControl.seqNumHi << + HIGH_SEQ_NUM_OFFSET) | + hdr->seqControl.seqNumLo)); /* * short slot and short preamble should be updated before doing * limaddsta @@ -1768,19 +1772,21 @@ void lim_process_assoc_req_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, } /* - * If a STA is already present in DPH and it is initiating a Assoc - * re-transmit, do not process it. This can happen when first Assoc Req - * frame is received but ACK lost at STA side. The ACK for this dropped - * Assoc Req frame should be sent by HW. Host simply does not process it - * once the entry for the STA is already present in DPH. + * If a STA is already present in DPH and the host receives an assoc + * request with the same sequence number , do not process it, as the + * previous assoc has already been processed and the response will be + * retried by the firmware if the peer hasnt received the response yet */ sta_ds = dph_lookup_hash_entry(mac_ctx, hdr->sa, &assoc_id, &session->dph.dphHashTable); if (NULL != sta_ds) { - if (hdr->fc.retry > 0) { - pe_err("STA is initiating Assoc Req after ACK lost. Do not process sessionid: %d sys sub_type=%d for role=%d from: " - MAC_ADDRESS_STR, session->peSessionId, - sub_type, GET_LIM_SYSTEM_ROLE(session), + if (sta_ds->prev_assoc_seq_no == (((hdr->seqControl.seqNumHi << + HIGH_SEQ_NUM_OFFSET) | + hdr->seqControl.seqNumLo))) { + pe_err("Got an Assoc Req with same seq no. SN:%d .Do not process sessionid: %d sys sub_type=%d for role=%d from: " + MAC_ADDRESS_STR, sta_ds->prev_assoc_seq_no, + session->peSessionId, + sub_type, GET_LIM_SYSTEM_ROLE(session), MAC_ADDR_ARRAY(hdr->sa)); return; } else if (!sta_ds->rmfEnabled && (sub_type == LIM_REASSOC)) { diff --git a/core/mac/src/pe/lim/lim_process_auth_frame.c b/core/mac/src/pe/lim/lim_process_auth_frame.c index 5758561e39b5..6c1a99e4b4af 100644 --- a/core/mac/src/pe/lim/lim_process_auth_frame.c +++ b/core/mac/src/pe/lim/lim_process_auth_frame.c @@ -364,8 +364,11 @@ static void lim_process_auth_frame_type1(tpAniSirGlobal mac_ctx, * modify the state of the existing association until the * SA-Query procedure determines that the original SA is * invalid. + * If the Auth sequence number is same as the previous auth seq + * number, dont send a deauth as the auth packet is just the + * duplicate of previous auth. */ - if (isConnected + if (isConnected && sta_ds_ptr->prev_auth_seq_no != curr_seq_num #ifdef WLAN_FEATURE_11W && !sta_ds_ptr->rmfEnabled #endif @@ -385,14 +388,15 @@ static void lim_process_auth_frame_type1(tpAniSirGlobal mac_ctx, auth_node = lim_search_pre_auth_list(mac_ctx, mac_hdr->sa); if (auth_node) { /* Pre-auth context exists for the STA */ - if (!(mac_hdr->fc.retry == 0 || - auth_node->seq_num != curr_seq_num)) { + if (auth_node->seq_num == curr_seq_num) { /* - * This can happen when first authentication frame is - * received but ACK lost at STA side, in this case 2nd - * auth frame is already in transmission queue + * If a STA is already present in authnode and the host receives an auth + * request with the same sequence number , do not process it, as the + * previous auth has already been processed and the response will be + * retried by the firmware if the peer hasnt received the response yet */ - pe_warn("STA is initiating Auth after ACK lost"); + pe_warn("STA is initiating Auth with SN: %d after ACK lost", + auth_node->seq_num); return; } /* @@ -1144,8 +1148,7 @@ lim_process_auth_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, pe_session->limMlmState, MAC_ADDR_ARRAY(mac_hdr->bssId), (uint) abs((int8_t) WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info))); - if (pe_session->prev_auth_seq_num == curr_seq_num && - mac_hdr->fc.retry) { + if (pe_session->prev_auth_seq_num == curr_seq_num) { pe_err("auth frame, seq num: %d is already processed, drop it", curr_seq_num); return; diff --git a/core/mac/src/pe/lim/lim_sme_req_utils.c b/core/mac/src/pe/lim/lim_sme_req_utils.c index a4d36d070f08..98529fbde2c3 100644 --- a/core/mac/src/pe/lim/lim_sme_req_utils.c +++ b/core/mac/src/pe/lim/lim_sme_req_utils.c @@ -298,7 +298,7 @@ lim_set_rs_nie_wp_aiefrom_sme_start_bss_req_message(tpAniSirGlobal mac_ctx, && (rsn_ie->rsnIEdata[0] == SIR_MAC_WPA_EID)) { pe_debug("Only WPA IE is present"); ret = dot11f_unpack_ie_wpa(mac_ctx, &rsn_ie->rsnIEdata[6], - (uint8_t) rsn_ie->length - 4, + rsn_ie->rsnIEdata[1] - 4, &session->gStartBssWPAIe, false); if (!DOT11F_SUCCEEDED(ret)) { pe_err("unpack failed, ret: %d", ret); diff --git a/core/mac/src/pe/lim/lim_types.h b/core/mac/src/pe/lim/lim_types.h index 8865b75e4fdb..973666b60746 100644 --- a/core/mac/src/pe/lim/lim_types.h +++ b/core/mac/src/pe/lim/lim_types.h @@ -496,10 +496,9 @@ void lim_perform_disassoc(tpAniSirGlobal mac_ctx, int32_t frame_rssi, void lim_disassoc_tdls_peers(tpAniSirGlobal mac_ctx, tpPESession pe_session, tSirMacAddr addr); #else -void lim_disassoc_tdls_peers(tpAniSirGlobal mac_ctx, +static inline void lim_disassoc_tdls_peers(tpAniSirGlobal mac_ctx, tpPESession pe_session, tSirMacAddr addr) { - return; } #endif void lim_process_deauth_frame(tpAniSirGlobal, uint8_t *, tpPESession); diff --git a/core/mac/src/pe/rrm/rrm_api.c b/core/mac/src/pe/rrm/rrm_api.c index fed9077b6532..6c351e8d1367 100644 --- a/core/mac/src/pe/rrm/rrm_api.c +++ b/core/mac/src/pe/rrm/rrm_api.c @@ -1253,6 +1253,7 @@ tSirRetStatus rrm_initialize(tpAniSirGlobal pMac) pMac->rrm.rrmPEContext.DialogToken = 0; pMac->rrm.rrmPEContext.rrmEnable = 0; + pMac->rrm.rrmPEContext.prev_rrm_report_seq_num = 0xFFFF; qdf_mem_set(pRRMCaps, sizeof(tRRMCaps), 0); pRRMCaps->LinkMeasurement = 1; diff --git a/core/mac/src/sys/legacy/src/system/src/sys_entry_func.c b/core/mac/src/sys/legacy/src/system/src/sys_entry_func.c index 9f36260402c5..030221f92d97 100644 --- a/core/mac/src/sys/legacy/src/system/src/sys_entry_func.c +++ b/core/mac/src/sys/legacy/src/system/src/sys_entry_func.c @@ -166,8 +166,19 @@ sys_bbt_process_message_core(tpAniSirGlobal mac_ctx, tpSirMsgQ msg, mac_ctx->sys.gSysFrameCount[type][subtype]); } - /* Post the message to PE Queue */ - ret = (tSirRetStatus) lim_post_msg_api(mac_ctx, msg); + /* + * Post the message to PE Queue. Prioritize the + * Auth and assoc frames. + */ + if ((subtype == SIR_MAC_MGMT_AUTH) || + (subtype == SIR_MAC_MGMT_ASSOC_RSP) || + (subtype == SIR_MAC_MGMT_REASSOC_RSP) || + (subtype == SIR_MAC_MGMT_ASSOC_REQ) || + (subtype == SIR_MAC_MGMT_REASSOC_REQ)) + ret = (tSirRetStatus) + lim_post_msg_high_priority(mac_ctx, msg); + else + ret = (tSirRetStatus) lim_post_msg_api(mac_ctx, msg); if (ret != eSIR_SUCCESS) { pe_err("posting to LIM2 failed, ret %d\n", ret); goto fail; diff --git a/core/mac/src/sys/legacy/src/utils/src/parser_api.c b/core/mac/src/sys/legacy/src/utils/src/parser_api.c index 7e7d13d0f511..0d49d5e0de65 100644 --- a/core/mac/src/sys/legacy/src/utils/src/parser_api.c +++ b/core/mac/src/sys/legacy/src/utils/src/parser_api.c @@ -1068,6 +1068,25 @@ populate_dot11f_vht_caps(tpAniSirGlobal pMac, VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1; pDot11f->rxHighSupDataRate = VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + if (!psessionEntry->ch_width && + !pMac->roam.configParam.enable_vht20_mcs9 && + ((pDot11f->txMCSMap & VHT_1x1_MCS_MASK) == + VHT_1x1_MCS9_MAP)) { + DISABLE_VHT_MCS_9(pDot11f->txMCSMap, + NSS_1x1_MODE); + DISABLE_VHT_MCS_9(pDot11f->rxMCSMap, + NSS_1x1_MODE); + } + } else { + if (!psessionEntry->ch_width && + !pMac->roam.configParam.enable_vht20_mcs9 && + ((pDot11f->txMCSMap & VHT_2x2_MCS_MASK) == + VHT_2x2_MCS9_MAP)) { + DISABLE_VHT_MCS_9(pDot11f->txMCSMap, + NSS_2x2_MODE); + DISABLE_VHT_MCS_9(pDot11f->rxMCSMap, + NSS_2x2_MODE); + } } } lim_log_vht_cap(pMac, pDot11f); diff --git a/core/pld/src/pld_snoc.c b/core/pld/src/pld_snoc.c index 2f6b84fa123a..f11982d39b7d 100644 --- a/core/pld/src/pld_snoc.c +++ b/core/pld/src/pld_snoc.c @@ -325,7 +325,6 @@ void pld_snoc_unregister_driver(void) * Non zero failure code for errors */ -#ifdef ICNSS_API_WITH_DEV int pld_snoc_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config, enum pld_driver_mode mode, const char *host_version) { @@ -359,38 +358,6 @@ int pld_snoc_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config, return icnss_wlan_enable(dev, &cfg, icnss_mode, host_version); } -#else -int pld_snoc_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config, - enum pld_driver_mode mode, const char *host_version) -{ - struct icnss_wlan_enable_cfg cfg; - enum icnss_driver_mode icnss_mode; - - cfg.num_ce_tgt_cfg = config->num_ce_tgt_cfg; - cfg.ce_tgt_cfg = (struct ce_tgt_pipe_cfg *) - config->ce_tgt_cfg; - cfg.num_ce_svc_pipe_cfg = config->num_ce_svc_pipe_cfg; - cfg.ce_svc_cfg = (struct ce_svc_pipe_cfg *) - config->ce_svc_cfg; - cfg.num_shadow_reg_cfg = config->num_shadow_reg_cfg; - cfg.shadow_reg_cfg = (struct icnss_shadow_reg_cfg *) - config->shadow_reg_cfg; - - switch (mode) { - case PLD_FTM: - icnss_mode = ICNSS_FTM; - break; - case PLD_EPPING: - icnss_mode = ICNSS_EPPING; - break; - default: - icnss_mode = ICNSS_MISSION; - break; - } - - return icnss_wlan_enable(&cfg, icnss_mode, host_version); -} -#endif /** * pld_snoc_wlan_disable() - Disable WLAN @@ -402,7 +369,6 @@ int pld_snoc_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config, * Return: 0 for success * Non zero failure code for errors */ -#ifdef ICNSS_API_WITH_DEV int pld_snoc_wlan_disable(struct device *dev, enum pld_driver_mode mode) { if (!dev) @@ -410,12 +376,6 @@ int pld_snoc_wlan_disable(struct device *dev, enum pld_driver_mode mode) return icnss_wlan_disable(dev, ICNSS_OFF); } -#else -int pld_snoc_wlan_disable(struct device *dev, enum pld_driver_mode mode) -{ - return icnss_wlan_disable(ICNSS_OFF); -} -#endif /** * pld_snoc_get_soc_info() - Get SOC information @@ -427,7 +387,6 @@ int pld_snoc_wlan_disable(struct device *dev, enum pld_driver_mode mode) * Return: 0 for success * Non zero failure code for errors */ -#ifdef ICNSS_API_WITH_DEV int pld_snoc_get_soc_info(struct device *dev, struct pld_soc_info *info) { int ret = 0; @@ -443,21 +402,4 @@ int pld_snoc_get_soc_info(struct device *dev, struct pld_soc_info *info) memcpy(info, &icnss_info, sizeof(*info)); return 0; } -#else -int pld_snoc_get_soc_info(struct device *dev, struct pld_soc_info *info) -{ - int ret = 0; - struct icnss_soc_info icnss_info; - - if (info == NULL) - return -ENODEV; - - ret = icnss_get_soc_info(&icnss_info); - if (0 != ret) - return ret; - - memcpy(info, &icnss_info, sizeof(*info)); - return 0; -} -#endif #endif diff --git a/core/pld/src/pld_snoc.h b/core/pld/src/pld_snoc.h index aa0dcbd6c956..e3b1bf7e574b 100644 --- a/core/pld/src/pld_snoc.h +++ b/core/pld/src/pld_snoc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -143,7 +143,6 @@ int pld_snoc_wlan_enable(struct device *dev, int pld_snoc_wlan_disable(struct device *dev, enum pld_driver_mode mode); int pld_snoc_get_soc_info(struct device *dev, struct pld_soc_info *info); -#ifdef ICNSS_API_WITH_DEV static inline int pld_snoc_ce_request_irq(struct device *dev, unsigned int ce_id, irqreturn_t (*handler)(int, void *), @@ -192,42 +191,6 @@ static inline int pld_snoc_get_irq(struct device *dev, int ce_id) return icnss_get_irq(dev, ce_id); } -#else -static inline int pld_snoc_ce_request_irq(struct device *dev, - unsigned int ce_id, - irqreturn_t (*handler)(int, void *), - unsigned long flags, - const char *name, void *ctx) -{ - return icnss_ce_request_irq(ce_id, handler, flags, name, ctx); -} - -static inline void pld_snoc_enable_irq(struct device *dev, unsigned int ce_id) -{ - icnss_enable_irq(ce_id); -} - -static inline void pld_snoc_disable_irq(struct device *dev, unsigned int ce_id) -{ - icnss_disable_irq(ce_id); -} - -static inline int pld_snoc_ce_free_irq(struct device *dev, - unsigned int ce_id, void *ctx) -{ - return icnss_ce_free_irq(ce_id, ctx); -} - -static inline int pld_snoc_get_ce_id(struct device *dev, int irq) -{ - return icnss_get_ce_id(irq); -} - -static inline int pld_snoc_get_irq(struct device *dev, int ce_id) -{ - return icnss_get_irq(ce_id); -} -#endif static inline int pld_snoc_power_on(struct device *dev) { @@ -269,7 +232,6 @@ static inline int pld_snoc_is_fw_down(void) return icnss_is_fw_down(); } -#ifdef ICNSS_API_WITH_DEV static inline int pld_snoc_is_qmi_disable(struct device *dev) { if (!dev) @@ -285,17 +247,6 @@ static inline int pld_snoc_set_fw_log_mode(struct device *dev, u8 fw_log_mode) return icnss_set_fw_log_mode(dev, fw_log_mode); } -#else -static inline int pld_snoc_is_qmi_disable(struct device *dev) -{ - return icnss_is_qmi_disable(); -} - -static inline int pld_snoc_set_fw_log_mode(struct device *dev, u8 fw_log_mode) -{ - return icnss_set_fw_log_mode(fw_log_mode); -} -#endif static inline int pld_snoc_force_assert_target(struct device *dev) { diff --git a/core/sap/dfs/src/dfs_init.c b/core/sap/dfs/src/dfs_init.c index 70fd9202a7bc..250f5cec1eed 100644 --- a/core/sap/dfs/src/dfs_init.c +++ b/core/sap/dfs/src/dfs_init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2002-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -92,8 +92,8 @@ void dfs_reset_alldelaylines(struct ath_dfs *dfs, int seg_id) } if (dfs->ic->dfs_hw_bd_id != DFS_HWBD_QCA6174) { - if (((seg_id == 0) ? - dfs->dfs_b5radars : dfs->dfs_b5radars_ext_seg) == NULL) { + if (dfs->dfs_rinfo.rn_numbin5radars && (((seg_id == 0) ? + dfs->dfs_b5radars : dfs->dfs_b5radars_ext_seg) == NULL)) { DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "%s: pl==NULL, b5radars=%pK\n", __func__, @@ -102,7 +102,8 @@ void dfs_reset_alldelaylines(struct ath_dfs *dfs, int seg_id) return; } } else { - if (dfs->dfs_b5radars == NULL) { + if (dfs->dfs_rinfo.rn_numbin5radars && + (dfs->dfs_b5radars == NULL)) { QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, "%s[%d]: pl==NULL, b5radars=%pK", __func__, __LINE__, dfs->dfs_b5radars); diff --git a/core/sap/inc/sap_api.h b/core/sap/inc/sap_api.h index 2292d8e438a2..cc6252caa65e 100644 --- a/core/sap/inc/sap_api.h +++ b/core/sap/inc/sap_api.h @@ -145,7 +145,6 @@ typedef enum { */ eSAP_STA_DISASSOC_EVENT, - eSAP_STA_LOSTLINK_DETECTED, /* Event sent when user called wlansap_set_key_sta */ eSAP_STA_SET_KEY_EVENT, /* Event sent whenever there is MIC failure detected */ @@ -304,6 +303,9 @@ typedef struct sap_StationDisassocCompleteEvent_s { uint32_t statusCode; uint32_t reason_code; eSapDisassocReason reason; + int rssi; + int tx_rate; + int rx_rate; } tSap_StationDisassocCompleteEvent; typedef struct sap_StationSetKeyCompleteEvent_s { diff --git a/core/sap/src/sap_api_link_cntl.c b/core/sap/src/sap_api_link_cntl.c index ba83cd8a6abe..38aa0694b1b3 100644 --- a/core/sap/src/sap_api_link_cntl.c +++ b/core/sap/src/sap_api_link_cntl.c @@ -1098,11 +1098,7 @@ wlansap_roam_callback(void *ctx, tCsrRoamInfo *csr_roam_info, uint32_t roamId, eSAP_UPDATE_SCAN_RESULT, (void *) eSAP_STATUS_SUCCESS); break; - case eCSR_ROAM_LOSTLINK_DETECTED: - sap_signal_hdd_event(sap_ctx, csr_roam_info, - eSAP_STA_LOSTLINK_DETECTED, - (void *)eSAP_STATUS_SUCCESS); - break; + default: break; } diff --git a/core/sap/src/sap_fsm.c b/core/sap/src/sap_fsm.c index d33ee91381a7..0f3483b955d2 100644 --- a/core/sap/src/sap_fsm.c +++ b/core/sap/src/sap_fsm.c @@ -3103,22 +3103,6 @@ QDF_STATUS sap_signal_hdd_event(ptSapContext sap_ctx, break; - case eSAP_STA_LOSTLINK_DETECTED: - if (!csr_roaminfo) { - QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, - FL("Invalid CSR Roam Info")); - return QDF_STATUS_E_INVAL; - } - sap_ap_event.sapHddEventCode = eSAP_STA_LOSTLINK_DETECTED; - disassoc_comp = - &sap_ap_event.sapevt.sapStationDisassocCompleteEvent; - - qdf_copy_macaddr(&disassoc_comp->staMac, - &csr_roaminfo->peerMac); - disassoc_comp->reason_code = csr_roaminfo->reasonCode; - - break; - case eSAP_STA_DISASSOC_EVENT: if (!csr_roaminfo) { @@ -3140,6 +3124,10 @@ QDF_STATUS sap_signal_hdd_event(ptSapContext sap_ctx, disassoc_comp->statusCode = csr_roaminfo->statusCode; disassoc_comp->status = (eSapStatus) context; + disassoc_comp->rssi = csr_roaminfo->rssi; + disassoc_comp->rx_rate = csr_roaminfo->rx_rate; + disassoc_comp->tx_rate = csr_roaminfo->tx_rate; + disassoc_comp->reason_code = csr_roaminfo->disassoc_reason; break; case eSAP_STA_SET_KEY_EVENT: @@ -4004,6 +3992,11 @@ static QDF_STATUS sap_fsm_state_dfs_cac_wait(ptSapContext sap_ctx, cds_set_channel_params( mac_ctx->sap.SapDfsInfo.target_channel, 0, &sap_ctx->ch_params); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid target channel %d"), + mac_ctx->sap.SapDfsInfo.target_channel); + return qdf_status; } for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { @@ -4242,6 +4235,13 @@ static QDF_STATUS sap_fsm_state_started(ptSapContext sap_ctx, qdf_status = sap_goto_disconnecting(sap_ctx); } else if (eSAP_DFS_CHNL_SWITCH_ANNOUNCEMENT_START == msg) { uint8_t intf; + + if (!mac_ctx->sap.SapDfsInfo.target_channel) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid target channel %d"), + mac_ctx->sap.SapDfsInfo.target_channel); + return qdf_status; + } /* * Radar is seen on the current operating channel * send CSA IE for all associated stations @@ -4949,6 +4949,13 @@ static QDF_STATUS sap_get_channel_list(ptSapContext sap_ctx, CDS_CHANNEL_NUM(loop_count), sap_ctx, &spect_info_obj)) continue; + /* Dont scan DFS channels in case of MCC disallowed + * As it can result in SAP starting on DFS channel + * resulting MCC on DFS channel + */ + if (CDS_IS_DFS_CH(CDS_CHANNEL_NUM(loop_count)) && + cds_disallow_mcc(CDS_CHANNEL_NUM(loop_count))) + continue; /* * If we have any 5Ghz channel in the channel list diff --git a/core/sap/src/sap_module.c b/core/sap/src/sap_module.c index 9e5c0aadb253..2144cba81c50 100644 --- a/core/sap/src/sap_module.c +++ b/core/sap/src/sap_module.c @@ -2680,6 +2680,12 @@ wlansap_channel_change_request(void *pSapCtx, uint8_t target_channel) sapContext = (ptSapContext) pSapCtx; + if (!target_channel) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: channel 0 requested", __func__); + return QDF_STATUS_E_FAULT; + } + if (NULL == sapContext) { QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, "%s: Invalid SAP pointer", __func__); diff --git a/core/sme/inc/csr_api.h b/core/sme/inc/csr_api.h index d7892b839860..6b1530aad3e8 100644 --- a/core/sme/inc/csr_api.h +++ b/core/sme/inc/csr_api.h @@ -74,6 +74,7 @@ typedef enum { eCSR_AUTH_TYPE_OWE, eCSR_AUTH_TYPE_SUITEB_EAP_SHA256, eCSR_AUTH_TYPE_SUITEB_EAP_SHA384, + eCSR_AUTH_TYPE_DPP_RSN, eCSR_NUM_OF_SUPPORT_AUTH_TYPE, eCSR_AUTH_TYPE_FAILED = 0xff, eCSR_AUTH_TYPE_UNKNOWN = eCSR_AUTH_TYPE_FAILED, @@ -363,9 +364,8 @@ typedef struct tagCsrEseCckmInfo { #endif } tCsrEseCckmInfo; -#define CSR_DOT11F_IE_RSN_MAX_LEN (114) typedef struct tagCsrEseCckmIe { - uint8_t cckmIe[CSR_DOT11F_IE_RSN_MAX_LEN]; + uint8_t cckmIe[DOT11F_IE_RSN_MAX_LEN]; uint8_t cckmIeLen; } tCsrEseCckmIe; #endif /* FEATURE_WLAN_ESE */ @@ -1308,6 +1308,7 @@ typedef struct tagCsrConfigParam { uint8_t enable_rx_ldpc; uint8_t disable_high_ht_mcs_2x2; uint8_t rx_ldpc_support_for_2g; + bool enable_vht20_mcs9; uint8_t max_amsdu_num; uint8_t nSelect5GHzMargin; uint8_t isCoalesingInIBSSAllowed; @@ -1405,6 +1406,7 @@ typedef struct tagCsrConfigParam { uint8_t oce_feature_bitmap; uint32_t offload_11k_enable_bitmask; struct csr_neighbor_report_offload_params neighbor_report_offload; + bool enable_ftopen; } tCsrConfigParam; /* Tush */ @@ -1451,6 +1453,7 @@ typedef struct tagCsrRoamInfo { tSirResultCodes statusCode; /* this'd be our own defined or sent from otherBSS(per 802.11spec) */ uint32_t reasonCode; + uint8_t disassoc_reason; uint8_t staId; /* Peer stationId when connected */ /* * The DPU signatures will be sent eventually to TL to help it @@ -1563,6 +1566,9 @@ typedef struct tagCsrRoamInfo { #ifdef WLAN_FEATURE_SAE struct sir_sae_info *sae_info; #endif + int rssi; + int tx_rate; + int rx_rate; } tCsrRoamInfo; typedef struct tagCsrFreqScanInfo { diff --git a/core/sme/inc/csr_internal.h b/core/sme/inc/csr_internal.h index 6ce321ae7b79..62ed7329ee8e 100644 --- a/core/sme/inc/csr_internal.h +++ b/core/sme/inc/csr_internal.h @@ -593,6 +593,7 @@ typedef struct tagCsrConfig { uint32_t nVhtChannelWidth; bool enable_subfee_vendor_vhtie; uint8_t enable_txbf_sap_mode; + bool enable_vht20_mcs9; uint8_t enable2x2; bool enableVhtFor24GHz; uint8_t enableVhtpAid; @@ -683,6 +684,7 @@ typedef struct tagCsrConfig { uint8_t oce_feature_bitmap; uint32_t offload_11k_enable_bitmask; struct csr_neighbor_report_offload_params neighbor_report_offload; + bool enable_ftopen; } tCsrConfig; typedef struct tagCsrChannelPowerInfo { diff --git a/core/sme/inc/csr_support.h b/core/sme/inc/csr_support.h index 532fe5aa227b..db47ec47c13f 100644 --- a/core/sme/inc/csr_support.h +++ b/core/sme/inc/csr_support.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -366,8 +366,9 @@ QDF_STATUS csr_reassoc(tpAniSirGlobal pMac, uint32_t sessionId, QDF_STATUS csr_validate_mcc_beacon_interval(tpAniSirGlobal pMac, uint8_t channelId, uint16_t *beaconInterval, uint32_t cursessionId, enum tQDF_ADAPTER_MODE currBssPersona); -bool csr_is_profile11r(tCsrRoamProfile *pProfile); -bool csr_is_auth_type11r(eCsrAuthType AuthType, uint8_t mdiePresent); +bool csr_is_profile11r(tpAniSirGlobal mac, tCsrRoamProfile *pProfile); +bool csr_is_auth_type11r(tpAniSirGlobal mac, eCsrAuthType AuthType, + uint8_t mdiePresent); #ifdef FEATURE_WLAN_ESE bool csr_is_profile_ese(tCsrRoamProfile *pProfile); #endif diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index 34c34f51f6ac..9a529d6ff54a 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -107,6 +107,7 @@ #define SME_SCAN_REJECT_RATE_LIMIT 5 #define SME_SESSION_ID_ANY 50 +#define SME_SESSION_ID_BROADCAST 0xFF #define SME_INVALID_COUNTRY_CODE "XX" #define INVALID_ROAM_ID 0 @@ -1969,6 +1970,17 @@ QDF_STATUS sme_ipa_uc_stat_request(tHalHandle hal, QDF_STATUS sme_set_smps_cfg(uint32_t vdev_id, uint32_t param_id, uint32_t param_val); + +/** + * sme_get_peer_stats() - sme api to post peer info request + * @mac: mac handle + * @req: peer info request struct send to wma + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS sme_get_peer_stats(tpAniSirGlobal mac, + struct sir_peer_info_req req); + /** * sme_get_peer_info() - sme api to get peer info * @hal: hal handle for getting global mac struct diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 3ea5c99a229f..7053a2e1c19d 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -2460,6 +2460,9 @@ QDF_STATUS sme_process_msg(tHalHandle hHal, cds_msg_t *pMsg) { QDF_STATUS status = QDF_STATUS_E_FAILURE; tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct sir_peer_info *peer_stats; + struct sir_peer_info_resp *peer_info_rsp; + #ifdef WLAN_FEATURE_ROAM_OFFLOAD tSmeCmd *sme_cmd = NULL; #endif @@ -2782,6 +2785,17 @@ QDF_STATUS sme_process_msg(tHalHandle hHal, cds_msg_t *pMsg) if (pMac->sme.pget_peer_info_ind_cb) pMac->sme.pget_peer_info_ind_cb(pMsg->bodyptr, pMac->sme.pget_peer_info_cb_context); + if (pMsg->bodyptr) { + peer_info_rsp = (struct sir_peer_info_resp *) + (pMsg->bodyptr); + peer_stats = (struct sir_peer_info *) + (peer_info_rsp->info); + if (peer_stats) { + pMac->peer_rssi = peer_stats[0].rssi; + pMac->peer_txrate = peer_stats[0].tx_rate; + pMac->peer_rxrate = peer_stats[0].rx_rate; + } + } qdf_mem_free(pMsg->bodyptr); break; case eWNI_SME_GET_PEER_INFO_EXT_IND: @@ -11057,6 +11071,38 @@ QDF_STATUS sme_get_link_speed(tHalHandle hHal, tSirLinkSpeedInfo *lsReq, return status; } +QDF_STATUS sme_get_peer_stats(tpAniSirGlobal mac, struct sir_peer_info_req req) +{ + QDF_STATUS qdf_status; + cds_msg_t message; + + qdf_status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + sme_debug("Failed to get Lock"); + return qdf_status; + } + /* serialize the req through MC thread */ + message.bodyptr = qdf_mem_malloc(sizeof(req)); + if (NULL == message.bodyptr) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Memory allocation failed.", __func__); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(message.bodyptr, &req, sizeof(req)); + message.type = WMA_GET_PEER_INFO; + message.reserved = 0; + qdf_status = cds_mq_post_message(QDF_MODULE_ID_WMA, &message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Post get peer info msg fail", __func__); + qdf_mem_free(message.bodyptr); + qdf_status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + return qdf_status; +} + QDF_STATUS sme_get_peer_info(tHalHandle hal, struct sir_peer_info_req req, void *context, void (*callbackfn)(struct sir_peer_info_resp *param, diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c index 4f601e5e0c0f..10110443d77a 100644 --- a/core/sme/src/csr/csr_api_roam.c +++ b/core/sme/src/csr/csr_api_roam.c @@ -1998,7 +1998,6 @@ bool csr_roam_is_ese_assoc(tpAniSirGlobal mac_ctx, uint32_t session_id) return mac_ctx->roam.neighborRoamInfo[session_id].isESEAssoc; } - /** * csr_roam_is_ese_ini_feature_enabled() - is ese feature enabled * @mac_ctx: Global MAC context @@ -2806,6 +2805,8 @@ QDF_STATUS csr_change_default_config_param(tpAniSirGlobal pMac, pParam->enable_subfee_vendor_vhtie; pMac->roam.configParam.enable_txbf_sap_mode = pParam->enable_txbf_sap_mode; + pMac->roam.configParam.enable_vht20_mcs9 = + pParam->enable_vht20_mcs9; pMac->roam.configParam.enable2x2 = pParam->enable2x2; pMac->roam.configParam.enableVhtFor24GHz = pParam->enableVhtFor24GHz; @@ -2875,7 +2876,8 @@ QDF_STATUS csr_change_default_config_param(tpAniSirGlobal pMac, pMac->roam.configParam.roam_params. roam_bad_rssi_thresh_offset_2g = pParam->roam_bad_rssi_thresh_offset_2g; - + pMac->roam.configParam.enable_ftopen = + pParam->enable_ftopen; pMac->roam.configParam.scan_adaptive_dwell_mode = pParam->scan_adaptive_dwell_mode; pMac->roam.configParam.scan_adaptive_dwell_mode_nc = @@ -3120,6 +3122,7 @@ QDF_STATUS csr_get_config_param(tpAniSirGlobal pMac, tCsrConfigParam *pParam) cfg_params->enable_subfee_vendor_vhtie; pParam->enable_txbf_sap_mode = cfg_params->enable_txbf_sap_mode; + pParam->enable_vht20_mcs9 = cfg_params->enable_vht20_mcs9; pParam->enableVhtFor24GHz = cfg_params->enableVhtFor24GHz; pParam->ignore_peer_erp_info = cfg_params->ignore_peer_erp_info; pParam->enable2x2 = cfg_params->enable2x2; @@ -3189,7 +3192,7 @@ QDF_STATUS csr_get_config_param(tpAniSirGlobal pMac, tCsrConfigParam *pParam) cfg_params->roam_params.bg_scan_client_bitmap; pParam->roam_bad_rssi_thresh_offset_2g = cfg_params->roam_params.roam_bad_rssi_thresh_offset_2g; - + pParam->enable_ftopen = cfg_params->enable_ftopen; pParam->scan_adaptive_dwell_mode = cfg_params->scan_adaptive_dwell_mode; pParam->scan_adaptive_dwell_mode_nc = @@ -3946,11 +3949,6 @@ QDF_STATUS csr_roam_call_callback(tpAniSirGlobal pMac, uint32_t sessionId, pSession->connectedProfile.operationChannel = pRoamInfo->channelChangeRespEvent->newChannelNumber; - if (eCSR_ROAM_RESULT_LOSTLINK == u2 || - eCSR_ROAM_LOSTLINK_DETECTED == u1) { - sme_debug("eCSR_ROAM_RESULT_LOSTLINK "); - } - if (NULL != pSession->callback) { if (pRoamInfo) { pRoamInfo->sessionId = (uint8_t) sessionId; @@ -6939,6 +6937,10 @@ static void csr_roam_process_results_default(tpAniSirGlobal mac_ctx, break; case eCsrForcedDisassocSta: case eCsrForcedDeauthSta: + roam_info.rssi = mac_ctx->peer_rssi; + roam_info.tx_rate = mac_ctx->peer_txrate; + roam_info.rx_rate = mac_ctx->peer_rxrate; + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_JOINED, session_id); session = CSR_GET_SESSION(mac_ctx, session_id); @@ -6950,6 +6952,9 @@ static void csr_roam_process_results_default(tpAniSirGlobal mac_ctx, cmd->u.roamCmd.peerMac, sizeof(tSirMacAddr)); roam_info.reasonCode = eCSR_ROAM_RESULT_FORCED; + /* Update the MAC reason code */ + roam_info.disassoc_reason = cmd->u.roamCmd.reason; + roam_info.statusCode = eSIR_SME_SUCCESS; status = csr_roam_call_callback(mac_ctx, session_id, &roam_info, cmd->u.roamCmd.roamId, @@ -11606,6 +11611,11 @@ csr_roam_send_disconnect_done_indication(tpAniSirGlobal mac_ctx, tSirSmeRsp roam_info.statusCode = eSIR_SME_STA_NOT_ASSOCIATED; qdf_mem_copy(roam_info.peerMac.bytes, discon_ind->peer_mac, ETH_ALEN); + roam_info.rssi = mac_ctx->peer_rssi; + roam_info.tx_rate = mac_ctx->peer_txrate; + roam_info.rx_rate = mac_ctx->peer_rxrate; + roam_info.disassoc_reason = discon_ind->reason_code; + csr_roam_call_callback(mac_ctx, discon_ind->session_id, &roam_info, 0, eCSR_ROAM_LOSTLINK, eCSR_ROAM_RESULT_DISASSOC_IND); @@ -12945,12 +12955,16 @@ QDF_STATUS csr_roam_lost_link(tpAniSirGlobal pMac, uint32_t sessionId, sme_debug("RC: %d", roamInfo.reasonCode); - if (type == eWNI_SME_DISASSOC_IND || type == eWNI_SME_DEAUTH_IND) - csr_roam_call_callback(pMac, sessionId, &roamInfo, 0, - eCSR_ROAM_LOSTLINK_DETECTED, result); - else - csr_roam_call_callback(pMac, sessionId, NULL, 0, - eCSR_ROAM_LOSTLINK_DETECTED, result); + if (type == eWNI_SME_DISASSOC_IND || type == eWNI_SME_DEAUTH_IND) { + struct sir_peer_info_req req; + + req.sessionid = sessionId; + req.peer_macaddr = roamInfo.peerMac; + sme_get_peer_stats(pMac, req); + } + + csr_roam_call_callback(pMac, sessionId, NULL, 0, + eCSR_ROAM_LOSTLINK_DETECTED, result); if (eWNI_SME_DISASSOC_IND == type) status = csr_send_mb_disassoc_cnf_msg(pMac, pDisassocIndMsg); @@ -15487,7 +15501,7 @@ QDF_STATUS csr_send_join_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, ese_config = pMac->roam.configParam.isEseIniFeatureEnabled; #endif pProfile->MDID.mdiePresent = pBssDescription->mdiePresent; - if (csr_is_profile11r(pProfile) + if (csr_is_profile11r(pMac, pProfile) #ifdef FEATURE_WLAN_ESE && !((pProfile->negotiatedAuthType == @@ -16447,8 +16461,18 @@ QDF_STATUS csr_send_mb_set_context_req_msg(tpAniSirGlobal pMac, pKey, keyLength); cds_msg.type = eWNI_SME_SETCONTEXT_REQ; cds_msg.bodyptr = pMsg; - status = cds_mq_post_message_by_priority(QDF_MODULE_ID_PE, &cds_msg, + + /* + * Post to PE queue in high priority only for unicast key + */ + if (fUnicast) + status = cds_mq_post_message_by_priority( + QDF_MODULE_ID_PE, &cds_msg, HIGH_PRIORITY); + else + status = cds_mq_post_message_by_priority( + QDF_MODULE_ID_PE, &cds_msg, + LOW_PRIORITY); if (QDF_IS_STATUS_ERROR(status)) qdf_mem_free(pMsg); } while (0); @@ -18784,6 +18808,7 @@ csr_create_roam_scan_offload_request(tpAniSirGlobal mac_ctx, eCSR_AUTH_TYPE_OPEN_SYSTEM) || (csr_is_auth_type_ese(req_buf-> ConnectedNetwork.authentication))); + req_buf->is_11r_assoc = roam_info->is11rAssoc; QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, "IsEseAssoc: %d middle of roaming: %d ese_neighbor_list_recvd: %d cur no of chan: %d", req_buf->IsESEAssoc, diff --git a/core/sme/src/csr/csr_neighbor_roam.c b/core/sme/src/csr/csr_neighbor_roam.c index 8dd6bda7ef6c..0e6d736d18ab 100644 --- a/core/sme/src/csr/csr_neighbor_roam.c +++ b/core/sme/src/csr/csr_neighbor_roam.c @@ -989,7 +989,7 @@ static void csr_neighbor_roam_info_ctx_init( /* Based on the auth scheme tell if we are 11r */ if (csr_is_auth_type11r - (session->connectedProfile.AuthType, + (pMac, session->connectedProfile.AuthType, session->connectedProfile.MDID.mdiePresent)) { if (pMac->roam.configParam.isFastTransitionEnabled) init_ft_flag = true; diff --git a/core/sme/src/csr/csr_util.c b/core/sme/src/csr/csr_util.c index fafb217e30df..75c056a97da5 100644 --- a/core/sme/src/csr/csr_util.c +++ b/core/sme/src/csr/csr_util.c @@ -117,15 +117,18 @@ uint8_t csr_rsn_oui[][CSR_RSN_OUI_SIZE] = { {0x00, 0x0F, 0xAC, 0x0C}, #ifdef WLAN_FEATURE_SAE #define ENUM_SAE 18 - /* SAE */ - {0x00, 0x0F, 0xAC, 0x08}, + /* SAE */ + {0x00, 0x0F, 0xAC, 0x08}, #define ENUM_FT_SAE 19 - /* FT SAE */ - {0x00, 0x0F, 0xAC, 0x09}, + /* FT SAE */ + {0x00, 0x0F, 0xAC, 0x09}, #else - {0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, #endif +#define ENUM_DPP_RSN 20 + /* DPP RSN */ + {0x50, 0x6F, 0x9A, 0x02}, /* define new oui here, update #define CSR_OUI_***_INDEX */ }; @@ -1983,6 +1986,7 @@ bool csr_is_profile_rsn(tCsrRoamProfile *pProfile) case eCSR_AUTH_TYPE_SUITEB_EAP_SHA256: case eCSR_AUTH_TYPE_SUITEB_EAP_SHA384: case eCSR_AUTH_TYPE_SAE: + case eCSR_AUTH_TYPE_DPP_RSN: fRSNProfile = true; break; @@ -2405,17 +2409,20 @@ QDF_STATUS csr_validate_mcc_beacon_interval(tpAniSirGlobal mac_ctx, /** * csr_is_auth_type11r() - Check if Authentication type is 11R + * @mac: pointer to mac context * @auth_type: The authentication type that is used to make the connection * @mdie_present: Is MDIE IE present * * Return: true if is 11R auth type, false otherwise */ -bool csr_is_auth_type11r(eCsrAuthType auth_type, uint8_t mdie_present) +bool csr_is_auth_type11r(tpAniSirGlobal mac, eCsrAuthType auth_type, + uint8_t mdie_present) { switch (auth_type) { case eCSR_AUTH_TYPE_OPEN_SYSTEM: - if (mdie_present) - return true; + if (mdie_present && + mac->roam.configParam.enable_ftopen) + return true; break; case eCSR_AUTH_TYPE_FT_RSN_PSK: case eCSR_AUTH_TYPE_FT_RSN: @@ -2427,9 +2434,9 @@ bool csr_is_auth_type11r(eCsrAuthType auth_type, uint8_t mdie_present) } /* Function to return true if the profile is 11r */ -bool csr_is_profile11r(tCsrRoamProfile *pProfile) +bool csr_is_profile11r(tpAniSirGlobal mac, tCsrRoamProfile *pProfile) { - return csr_is_auth_type11r(pProfile->negotiatedAuthType, + return csr_is_auth_type11r(mac, pProfile->negotiatedAuthType, pProfile->MDID.mdiePresent); } @@ -2818,6 +2825,23 @@ static bool csr_is_auth_wpa_sae(tpAniSirGlobal mac, } #endif +/* + * csr_is_auth_dpp_rsn() - check whether oui is dpp rsn + * @mac: Global MAC context + * @all_suites: pointer to all supported akm suites + * @suite_count: all supported akm suites count + * @oui: Oui needs to be matched + * + * Return: True if OUI is dpp rsn, false otherwise + */ +static bool csr_is_auth_dpp_rsn(tpAniSirGlobal mac, + uint8_t all_suites[][CSR_RSN_OUI_SIZE], + uint8_t suite_count, uint8_t oui[]) +{ + return csr_is_oui_match(mac, all_suites, suite_count, + csr_rsn_oui[ENUM_DPP_RSN], oui); +} + static bool csr_is_auth_wpa(tpAniSirGlobal pMac, uint8_t AllSuites[][CSR_WPA_OUI_SIZE], uint8_t cAllSuites, uint8_t Oui[]) @@ -3179,6 +3203,12 @@ static bool csr_get_rsn_information(tHalHandle hal, tCsrAuthList *auth_type, authentication, auth_type, i, &neg_authtype); if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) && + csr_is_auth_dpp_rsn(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_DPP_RSN == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_DPP_RSN; + } + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) && csr_is_ft_auth_rsn(mac_ctx, authsuites, c_auth_suites, authentication)) { if (eCSR_AUTH_TYPE_FT_RSN == auth_type->authType[i]) diff --git a/core/wma/src/wma_dev_if.c b/core/wma/src/wma_dev_if.c index 440a47dfbae4..3c6d9ec12bb0 100644 --- a/core/wma/src/wma_dev_if.c +++ b/core/wma/src/wma_dev_if.c @@ -1841,7 +1841,7 @@ wma_remove_peer_by_reference(ol_txrx_pdev_handle pdev, struct wma_target_req *del_req; QDF_STATUS status; - status = QDF_STATUS_SUCCESS; + status = QDF_STATUS_E_FAILURE; peer = ol_txrx_find_peer_by_addr_inc_ref(pdev, bssid, peer_id); @@ -1872,6 +1872,8 @@ wma_remove_peer_by_reference(ol_txrx_pdev_handle pdev, WMA_LOGE(FL("Failed to allocate request. vdev_id %d"), vdev_id); status = QDF_STATUS_E_NOMEM; + } else { + status = QDF_STATUS_SUCCESS; } } @@ -1917,6 +1919,10 @@ int wma_vdev_stop_resp_handler(void *handle, uint8_t *cmd_param_info, } iface = &wma->interfaces[resp_event->vdev_id]; + + /* vdev in stopped state, no more waiting for key */ + iface->is_waiting_for_key = false; + wma_release_wakelock(&iface->vdev_stop_wakelock); req_msg = wma_find_vdev_req(wma, resp_event->vdev_id, @@ -2458,6 +2464,12 @@ QDF_STATUS wma_vdev_start(tp_wma_handle wma, return QDF_STATUS_E_FAILURE; } + if (req->chan == 0) { + WMA_LOGE("%s: invalid channel: %d", __func__, req->chan); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + params.band_center_freq1 = cds_chan_to_freq(req->chan); ch_width = req->chan_width; bw_val = cds_bw_value(ch_width); @@ -4100,8 +4112,11 @@ static void wma_add_bss_sta_mode(tp_wma_handle wma, tpAddBssParams add_bss) pps_val, status); wma_send_peer_assoc(wma, add_bss->nwType, &add_bss->staContext); + /* we just had peer assoc, so install key will be done later */ - iface->is_waiting_for_key = true; + if (add_bss->staContext.encryptType != eSIR_ED_NONE) + iface->is_waiting_for_key = true; + peer_assoc_sent = true; if (add_bss->rmfEnabled) diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c index 24405759d76c..97a6fae28e33 100644 --- a/core/wma/src/wma_features.c +++ b/core/wma/src/wma_features.c @@ -4680,6 +4680,11 @@ int wma_d0_wow_disable_ack_event(void *handle, u_int8_t *event, int wma_wow_wakeup_host_event(void *handle, uint8_t *event, uint32_t len) { + uint8_t *bssid; + uint8_t peer_id; + ol_txrx_peer_handle peer; + ol_txrx_pdev_handle pdev; + tpDeleteStaContext del_sta_ctx; tp_wma_handle wma = (tp_wma_handle) handle; struct wma_txrx_node *wma_vdev = NULL; WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs *param_buf; @@ -4690,6 +4695,7 @@ int wma_wow_wakeup_host_event(void *handle, uint8_t *event, uint8_t *wow_buf_data = NULL; int tlv_ok_status; + pdev = cds_get_context(QDF_MODULE_ID_TXRX); param_buf = (WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs *) event; if (!param_buf) { WMA_LOGE("Invalid wow wakeup host event buf"); @@ -4697,6 +4703,8 @@ int wma_wow_wakeup_host_event(void *handle, uint8_t *event, } wake_info = param_buf->fixed_param; + bssid = wma->interfaces[wake_info->vdev_id].bssid; + peer = ol_txrx_find_peer_by_addr(pdev, bssid, &peer_id); /* unspecified means apps-side wakeup, so there won't be a vdev */ if (wake_info->wake_reason != WOW_REASON_UNSPECIFIED) { @@ -4967,16 +4975,20 @@ int wma_wow_wakeup_host_event(void *handle, uint8_t *event, * programmed. So do not check for cookie. */ WMA_LOGE("WOW_REASON_TIMER_INTR_RECV received, indicating key exchange did not finish. Initiate disconnect"); - if (param_buf->wow_packet_buffer) { - WMA_LOGD("wow_packet_buffer dump"); - qdf_trace_hex_dump(QDF_MODULE_ID_WMA, - QDF_TRACE_LEVEL_DEBUG, - param_buf->wow_packet_buffer, wow_buf_pkt_len); - wma_peer_sta_kickout_event_handler(handle, - wmi_cmd_struct_ptr, wow_buf_pkt_len); - } else { - WMA_LOGD("No wow_packet_buffer present"); + + del_sta_ctx = (tpDeleteStaContext) qdf_mem_malloc(sizeof(*del_sta_ctx)); + if (!del_sta_ctx) { + WMA_LOGE("%s: mem alloc failed ", __func__); + break; } + del_sta_ctx->is_tdls = false; + del_sta_ctx->vdev_id = wake_info->vdev_id; + del_sta_ctx->staId = peer_id; + qdf_mem_copy(del_sta_ctx->addr2, bssid, IEEE80211_ADDR_LEN); + qdf_mem_copy(del_sta_ctx->bssId, bssid, IEEE80211_ADDR_LEN); + del_sta_ctx->reasonCode = HAL_DEL_STA_REASON_CODE_KEEP_ALIVE; + wma_send_msg(wma, SIR_LIM_DELETE_STA_CONTEXT_IND, + (void *)del_sta_ctx, 0); break; default: break; diff --git a/core/wma/src/wma_mgmt.c b/core/wma/src/wma_mgmt.c index 3823ff2fc3e3..6fb37f3e8951 100644 --- a/core/wma/src/wma_mgmt.c +++ b/core/wma/src/wma_mgmt.c @@ -593,10 +593,11 @@ static inline void wma_get_link_probe_timeout(struct sAniSirGlobal *mac, /** * wma_verify_rate_code() - verify if rate code is valid. * @rate_code: rate code + * @band: band information * * Return: verify result */ -static bool wma_verify_rate_code(u_int32_t rate_code) +static bool wma_verify_rate_code(u_int32_t rate_code, enum cds_band_type band) { uint8_t preamble, nss, rate; bool valid = true; @@ -607,7 +608,7 @@ static bool wma_verify_rate_code(u_int32_t rate_code) switch (preamble) { case WMI_RATE_PREAMBLE_CCK: - if (nss != 0 || rate > 3) + if (nss != 0 || rate > 3 || band == CDS_BAND_5GHZ) valid = false; break; case WMI_RATE_PREAMBLE_OFDM: @@ -615,11 +616,11 @@ static bool wma_verify_rate_code(u_int32_t rate_code) valid = false; break; case WMI_RATE_PREAMBLE_HT: - if (nss > 1 || rate > 7) + if (nss != 0 || rate > 7) valid = false; break; case WMI_RATE_PREAMBLE_VHT: - if (nss > 1 || rate > 9) + if (nss != 0 || rate > 9) valid = false; break; default: @@ -645,6 +646,7 @@ void wma_set_vdev_mgmt_rate(tp_wma_handle wma, uint8_t vdev_id) uint32_t cfg_val; int ret; uint32_t per_band_mgmt_tx_rate = 0; + enum cds_band_type band = 0; struct sAniSirGlobal *mac = cds_get_context(QDF_MODULE_ID_PE); if (NULL == mac) { @@ -654,8 +656,9 @@ void wma_set_vdev_mgmt_rate(tp_wma_handle wma, uint8_t vdev_id) if (wlan_cfg_get_int(mac, WNI_CFG_RATE_FOR_TX_MGMT, &cfg_val) == eSIR_SUCCESS) { + band = CDS_BAND_ALL; if ((cfg_val == WNI_CFG_RATE_FOR_TX_MGMT_STADEF) || - !wma_verify_rate_code(cfg_val)) { + !wma_verify_rate_code(cfg_val, band)) { WMA_LOGD("default WNI_CFG_RATE_FOR_TX_MGMT, ignore"); } else { ret = wma_vdev_set_param( @@ -674,8 +677,10 @@ void wma_set_vdev_mgmt_rate(tp_wma_handle wma, uint8_t vdev_id) if (wlan_cfg_get_int(mac, WNI_CFG_RATE_FOR_TX_MGMT_2G, &cfg_val) == eSIR_SUCCESS) { + band = CDS_BAND_2GHZ; if ((cfg_val == WNI_CFG_RATE_FOR_TX_MGMT_2G_STADEF) || - !wma_verify_rate_code(cfg_val)) { + !wma_verify_rate_code(cfg_val, band)) { + WMA_LOGD("use default 2G MGMT rate."); per_band_mgmt_tx_rate &= ~(1 << TX_MGMT_RATE_2G_ENABLE_OFFSET); } else { @@ -690,8 +695,10 @@ void wma_set_vdev_mgmt_rate(tp_wma_handle wma, uint8_t vdev_id) if (wlan_cfg_get_int(mac, WNI_CFG_RATE_FOR_TX_MGMT_5G, &cfg_val) == eSIR_SUCCESS) { + band = CDS_BAND_5GHZ; if ((cfg_val == WNI_CFG_RATE_FOR_TX_MGMT_5G_STADEF) || - !wma_verify_rate_code(cfg_val)) { + !wma_verify_rate_code(cfg_val, band)) { + WMA_LOGD("use default 5G MGMT rate."); per_band_mgmt_tx_rate &= ~(1 << TX_MGMT_RATE_5G_ENABLE_OFFSET); } else { @@ -1326,12 +1333,12 @@ QDF_STATUS wma_send_peer_assoc(tp_wma_handle wma, intr->nss = cmd->peer_nss; cmd->peer_phymode = phymode; - WMA_LOGD("%s: vdev_id %d associd %d peer_flags %x rate_caps %x peer_caps %x", - __func__, cmd->vdev_id, cmd->peer_associd, cmd->peer_flags, + WMA_LOGI("%s: vdev_id %d associd %d peer_flags %x nss %d phymode %d ht_caps %x", + __func__, cmd->vdev_id, cmd->peer_associd, cmd->peer_flags, + cmd->peer_nss, cmd->peer_phymode, cmd->peer_ht_caps); + WMA_LOGD("%s:listen_intval %d max_mpdu %d rate_caps %x peer_caps %x", + __func__, cmd->peer_listen_intval, cmd->peer_max_mpdu, cmd->peer_rate_caps, cmd->peer_caps); - WMA_LOGD("%s:listen_intval %d ht_caps %x max_mpdu %d nss %d phymode %d", - __func__, cmd->peer_listen_intval, cmd->peer_ht_caps, - cmd->peer_max_mpdu, cmd->peer_nss, cmd->peer_phymode); WMA_LOGD("%s: peer_mpdu_density %d encr_type %d cmd->peer_vht_caps %x", __func__, cmd->peer_mpdu_density, params->encryptType, cmd->peer_vht_caps); @@ -2904,7 +2911,6 @@ void wma_process_update_opmode(tp_wma_handle wma_handle, tUpdateVHTOpMode *update_vht_opmode) { struct wma_txrx_node *iface; - uint16_t chan_mode; wmi_channel_width ch_width; @@ -2920,24 +2926,12 @@ void wma_process_update_opmode(tp_wma_handle wma_handle, return; } - chan_mode = wma_chan_phy_mode(cds_freq_to_chan(iface->mhz), - update_vht_opmode->opMode, - update_vht_opmode->dot11_mode); - if (MODE_UNKNOWN == chan_mode) - return; - - WMA_LOGD("%s: opMode = %d, chanMode = %d, dot11mode = %d ", - __func__, - update_vht_opmode->opMode, chan_mode, - update_vht_opmode->dot11_mode); + WMA_LOGD("%s: opMode = %d, current_ch_width: %d", __func__, + update_vht_opmode->opMode, ch_width); wma_set_peer_param(wma_handle, update_vht_opmode->peer_mac, WMI_PEER_CHWIDTH, update_vht_opmode->opMode, update_vht_opmode->smesessionId); - - wma_set_peer_param(wma_handle, update_vht_opmode->peer_mac, - WMI_PEER_PHYMODE, chan_mode, - update_vht_opmode->smesessionId); } /** diff --git a/core/wma/src/wma_scan_roam.c b/core/wma/src/wma_scan_roam.c index a1d4e7350b02..35742442a5cc 100644 --- a/core/wma/src/wma_scan_roam.c +++ b/core/wma/src/wma_scan_roam.c @@ -969,6 +969,7 @@ QDF_STATUS wma_roam_scan_offload_mode(tp_wma_handle wma_handle, params->fw_pmksa_cache = roam_req->pmkid_modes.fw_pmksa_cache; #endif params->is_ese_assoc = roam_req->IsESEAssoc; + params->is_11r_assoc = roam_req->is_11r_assoc; params->mdid.mdie_present = roam_req->MDID.mdiePresent; params->mdid.mobility_domain = roam_req->MDID.mobilityDomain; params->assoc_ie_length = roam_req->assoc_ie.length; @@ -1124,6 +1125,63 @@ QDF_STATUS wma_roam_scan_offload_rssi_thresh(tp_wma_handle wma_handle, return status; } +static const char *wma_roam_reason_to_string(uint32_t roam_reason) +{ + switch (roam_reason) { + CASE_RETURN_STRING(WMI_ROAM_TRIGGER_REASON_NONE); + CASE_RETURN_STRING(WMI_ROAM_TRIGGER_REASON_PER); + CASE_RETURN_STRING(WMI_ROAM_TRIGGER_REASON_BMISS); + CASE_RETURN_STRING(WMI_ROAM_TRIGGER_REASON_LOW_RSSI); + CASE_RETURN_STRING(WMI_ROAM_TRIGGER_REASON_HIGH_RSSI); + CASE_RETURN_STRING(WMI_ROAM_TRIGGER_REASON_PERIODIC); + CASE_RETURN_STRING(WMI_ROAM_TRIGGER_REASON_MAWC); + CASE_RETURN_STRING(WMI_ROAM_TRIGGER_REASON_DENSE); + CASE_RETURN_STRING(WMI_ROAM_TRIGGER_REASON_BACKGROUND); + CASE_RETURN_STRING(WMI_ROAM_TRIGGER_REASON_FORCED); + CASE_RETURN_STRING(WMI_ROAM_TRIGGER_REASON_BTM); + CASE_RETURN_STRING(WMI_ROAM_TRIGGER_REASON_UNIT_TEST); + CASE_RETURN_STRING(WMI_ROAM_TRIGGER_REASON_MAX); + + default: + return "unknown"; + } +} + +static const char *wma_roam_event_to_string(uint32_t roam_reason) +{ + switch (roam_reason) { + CASE_RETURN_STRING(WMI_ROAM_REASON_INVALID); + CASE_RETURN_STRING(WMI_ROAM_REASON_BETTER_AP); + CASE_RETURN_STRING(WMI_ROAM_REASON_BMISS); + CASE_RETURN_STRING(WMI_ROAM_REASON_LOW_RSSI); + CASE_RETURN_STRING(WMI_ROAM_REASON_SUITABLE_AP); + CASE_RETURN_STRING(WMI_ROAM_REASON_HO_FAILED); + CASE_RETURN_STRING(WMI_ROAM_REASON_INVOKE_ROAM_FAIL); + CASE_RETURN_STRING(WMI_ROAM_REASON_RSO_STATUS); + CASE_RETURN_STRING(WMI_ROAM_REASON_BTM); + + default: + return "unknown"; + } +} + +static const char *wma_roam_notif_to_string(uint32_t notif) +{ + switch (notif) { + CASE_RETURN_STRING(WMI_ROAM_NOTIF_INVALID); + CASE_RETURN_STRING(WMI_ROAM_NOTIF_ROAM_START); + CASE_RETURN_STRING(WMI_ROAM_NOTIF_ROAM_ABORT); + CASE_RETURN_STRING(WMI_ROAM_NOTIF_ROAM_REASSOC); + CASE_RETURN_STRING(WMI_ROAM_NOTIF_SCAN_MODE_SUCCESS); + CASE_RETURN_STRING(WMI_ROAM_NOTIF_SCAN_MODE_FAIL); + CASE_RETURN_STRING(WMI_ROAM_NOTIF_DISCONNECT); + CASE_RETURN_STRING(WMI_ROAM_NOTIF_SUBNET_CHANGED); + + default: + return "unknown"; + } +} + /** * wma_roam_scan_offload_scan_period() - set roam offload scan period * @wma_handle: wma handle @@ -2599,9 +2657,11 @@ static int wma_fill_roam_synch_buffer(tp_wma_handle wma, roam_synch_ind_ptr->rssi = synch_event->rssi; WMI_MAC_ADDR_TO_CHAR_ARRAY(&synch_event->bssid, roam_synch_ind_ptr->bssid.bytes); - WMA_LOGD("%s: roamedVdevId %d authStatus %d roamReason %d rssi %d isBeacon %d", - __func__, roam_synch_ind_ptr->roamedVdevId, + WMA_LOGD(FL("LFR3:- BSSID:- "MAC_ADDRESS_STR" roamedVdevId %d authStatus %d roamReason %d %s rssi %d isBeacon %d"), + MAC_ADDR_ARRAY(roam_synch_ind_ptr->bssid.bytes), + roam_synch_ind_ptr->roamedVdevId, roam_synch_ind_ptr->authStatus, roam_synch_ind_ptr->roamReason, + wma_roam_reason_to_string(roam_synch_ind_ptr->roamReason), roam_synch_ind_ptr->rssi, roam_synch_ind_ptr->isBeacon); if (!QDF_IS_STATUS_SUCCESS( @@ -2832,6 +2892,12 @@ int wma_roam_synch_event_handler(void *handle, uint8_t *event, goto cleanup_label; } + if (synch_event->vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: received invalid vdev_id %d", + __func__, synch_event->vdev_id); + return status; + } + if (synch_event->bcn_probe_rsp_len > param_buf->num_bcn_probe_rsp_frame || synch_event->reassoc_req_len > @@ -2844,11 +2910,6 @@ int wma_roam_synch_event_handler(void *handle, uint8_t *event, synch_event->reassoc_rsp_len); goto cleanup_label; } - if (synch_event->vdev_id >= wma->max_bssid) { - WMA_LOGE("%s: received invalid vdev_id %d", - __func__, synch_event->vdev_id); - goto cleanup_label; - } wma_peer_debug_log(synch_event->vdev_id, DEBUG_ROAM_SYNCH_IND, DEBUG_INVALID_PEER_ID, NULL, NULL, @@ -6611,8 +6672,11 @@ int wma_roam_event_callback(WMA_HANDLE handle, uint8_t *event_buf, } wmi_event = param_buf->fixed_param; - WMA_LOGD("%s: Reason %x, Notif %x for vdevid %x, rssi %d", - __func__, wmi_event->reason, wmi_event->notif, + WMA_LOGD("%s: Reason %x %s, Notif %x %s for vdevid %x, rssi %d", + __func__, wmi_event->reason, + wma_roam_event_to_string(wmi_event->reason), + wmi_event->notif, + wma_roam_notif_to_string(wmi_event->notif), wmi_event->vdev_id, wmi_event->rssi); wma_peer_debug_log(wmi_event->vdev_id, DEBUG_ROAM_EVENT, DEBUG_INVALID_PEER_ID, NULL, NULL, diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c index d3d7b4cbdf44..f575c06e9251 100644 --- a/core/wma/src/wma_utils.c +++ b/core/wma/src/wma_utils.c @@ -3604,31 +3604,43 @@ int wma_unified_debug_print_event_handler(void *handle, uint8_t *datap, WMI_DEBUG_PRINT_EVENTID_param_tlvs *param_buf; uint8_t *data; uint32_t datalen; + char dbgbuf[WMI_SVC_MSG_MAX_SIZE] = { 0 }; param_buf = (WMI_DEBUG_PRINT_EVENTID_param_tlvs *) datap; - if (!param_buf) { + if (!param_buf || !param_buf->data) { WMA_LOGE("Get NULL point message from FW"); return -ENOMEM; } data = param_buf->data; datalen = param_buf->num_data; + if (datalen > WMI_SVC_MSG_MAX_SIZE) { + WMA_LOGE("Received data len %d exceeds max value %d", + datalen, WMI_SVC_MSG_MAX_SIZE); + return QDF_STATUS_E_FAILURE; + } #ifdef BIG_ENDIAN_HOST { - if (datalen > BIG_ENDIAN_MAX_DEBUG_BUF) { + if (datalen >= BIG_ENDIAN_MAX_DEBUG_BUF) { WMA_LOGE("%s Invalid data len %d, limiting to max", __func__, datalen); - datalen = BIG_ENDIAN_MAX_DEBUG_BUF; + datalen = BIG_ENDIAN_MAX_DEBUG_BUF-1; } - char dbgbuf[BIG_ENDIAN_MAX_DEBUG_BUF] = { 0 }; - memcpy(dbgbuf, data, datalen); + strlcpy(dbgbuf, data, datalen); SWAPME(dbgbuf, datalen); WMA_LOGD("FIRMWARE:%s", dbgbuf); return 0; } #else - WMA_LOGD("FIRMWARE:%s", data); + if (datalen == WMI_SVC_MSG_MAX_SIZE) { + WMA_LOGE("%s Invalid data len %d, limiting to max", + __func__, datalen); + datalen = WMI_SVC_MSG_MAX_SIZE -1 ; + } + + strlcpy(dbgbuf, data, datalen); + WMA_LOGD("FIRMWARE:%s", dbgbuf); return 0; #endif /* BIG_ENDIAN_HOST */ } |
