| /* |
| * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. |
| * |
| * Previously licensed under the ISC license by Qualcomm Atheros, Inc. |
| * |
| * |
| * Permission to use, copy, modify, and/or distribute this software for |
| * any purpose with or without fee is hereby granted, provided that the |
| * above copyright notice and this permission notice appear in all |
| * copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL |
| * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE |
| * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL |
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR |
| * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
| * PERFORMANCE OF THIS SOFTWARE. |
| */ |
| |
| /* |
| * This file was originally distributed by Qualcomm Atheros, Inc. |
| * under proprietary terms before Copyright ownership was assigned |
| * to the Linux Foundation. |
| */ |
| |
| /**======================================================================== |
| |
| \file wma.c |
| \brief Implementation of WMA |
| |
| ========================================================================*/ |
| /**========================================================================= |
| EDIT HISTORY FOR FILE |
| |
| |
| This section contains comments describing changes made to the module. |
| Notice that changes are listed in reverse chronological order. |
| |
| $Header:$ $DateTime: $ $Author: $ |
| |
| |
| when who what, where, why |
| -------- --- ----------------------------------------- |
| 12/03/2013 Ganesh Implementation of WMA APIs. |
| Kondabattini |
| 27/03/2013 Ganesh Rx Management Support added |
| Babu |
| ==========================================================================*/ |
| |
| /* ################ Header files ################ */ |
| #include "ieee80211_common.h" /* ieee80211_frame */ |
| #include "wma.h" |
| #include "wma_api.h" |
| #include "vos_api.h" |
| #include "wmi_unified_api.h" |
| #include "wlan_qct_sys.h" |
| #include "wniApi.h" |
| #include "aniGlobal.h" |
| #include "wmi_unified.h" |
| #include "wni_cfg.h" |
| #include "cfgApi.h" |
| #include "ol_txrx_ctrl_api.h" |
| #if defined(CONFIG_HL_SUPPORT) |
| #include "wlan_tgt_def_config_hl.h" |
| #else |
| #include "wlan_tgt_def_config.h" |
| #endif |
| |
| #if defined(QCA_IBSS_SUPPORT) |
| #include "wlan_hdd_assoc.h" |
| #endif |
| |
| #include "adf_nbuf.h" |
| #include "adf_os_types.h" |
| #include "ol_txrx_api.h" |
| #include "vos_memory.h" |
| #include "ol_txrx_types.h" |
| #include "ol_txrx_peer_find.h" |
| |
| #include "wlan_qct_wda.h" |
| #include "wlan_qct_wda_msg.h" |
| #include "limApi.h" |
| #include "limSessionUtils.h" |
| |
| #include "wdi_out.h" |
| #include "wdi_in.h" |
| |
| #include "vos_cnss.h" |
| |
| #include "vos_utils.h" |
| #include "tl_shim.h" |
| #if defined(QCA_WIFI_FTM) |
| #include "testmode.h" |
| #endif |
| |
| #if !defined(REMOVE_PKT_LOG) |
| #include "pktlog_ac.h" |
| #endif |
| |
| #include "dbglog_host.h" |
| /* FIXME: Inclusion of .c looks odd but this is how it is in internal codebase */ |
| #include "wmi_version_whitelist.c" |
| #include "csrApi.h" |
| #include "ol_fw.h" |
| |
| #include "dfs.h" |
| #include "radar_filters.h" |
| #include "regdomain_common.h" |
| |
| #include "wma_ocb.h" |
| #include "wma_nan_datapath.h" |
| #include "adf_trace.h" |
| |
| /* ################### defines ################### */ |
| /* |
| * TODO: Following constant should be shared by firwmare in |
| * wmi_unified.h. This will be done once wmi_unified.h is updated. |
| */ |
| #define WMI_PEER_STATE_AUTHORIZED 0x2 |
| |
| #define WMA_2_4_GHZ_MAX_FREQ 3000 |
| #define WOW_CSA_EVENT_OFFSET 12 |
| |
| /* |
| * In the WMI_WOW_WAKEUP_HOST_EVENTID after the fixed param |
| * the wmi nan event is at an offset of 12 |
| * This is to extract and decode the NAN WMI event. |
| */ |
| #define WOW_NAN_EVENT_OFFSET 12 |
| |
| #define WMA_DEFAULT_SCAN_REQUESTER_ID 1 |
| #define WMI_SCAN_FINISH_EVENTS (WMI_SCAN_EVENT_START_FAILED |\ |
| WMI_SCAN_EVENT_COMPLETED |\ |
| WMI_SCAN_EVENT_DEQUEUED) |
| /* default value */ |
| #define DEFAULT_INFRA_STA_KEEP_ALIVE_PERIOD 20 |
| /* pdev vdev and peer stats*/ |
| #define FW_PDEV_STATS_SET 0x1 |
| #define FW_VDEV_STATS_SET 0x2 |
| #define FW_PEER_STATS_SET 0x4 |
| #define FW_RSSI_PER_CHAIN_STATS_SET 0x8 |
| #define FW_STATS_SET 0xf |
| /*AR9888/AR6320 noise floor approx value |
| * similar to the mentioned the TLSHIM |
| */ |
| #define WMA_TGT_NOISE_FLOOR_DBM (-96) |
| #define WMA_TGT_RSSI_INVALID 96 |
| |
| /* |
| * Make sure that link monitor and keep alive |
| * default values should be in sync with CFG. |
| */ |
| #define WMA_LINK_MONITOR_DEFAULT_TIME_SECS 10 |
| #define WMA_KEEP_ALIVE_DEFAULT_TIME_SECS 5 |
| |
| #define AGC_DUMP 1 |
| #define CHAN_DUMP 2 |
| #define WD_DUMP 3 |
| #ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG |
| #define PCIE_DUMP 4 |
| #endif |
| |
| /* conformance test limits */ |
| #define FCC 0x10 |
| #define MKK 0x40 |
| #define ETSI 0x30 |
| |
| /* Maximum Buffer length allowed for DFS phyerrors */ |
| #define DFS_MAX_BUF_LENGHT 4096 |
| |
| #define WMI_DEFAULT_NOISE_FLOOR_DBM (-96) |
| |
| /* Threshold to print tx time taken in ms*/ |
| #define WDA_TX_TIME_THRESHOLD 1000 |
| |
| #define WMI_MCC_MIN_CHANNEL_QUOTA 20 |
| #define WMI_MCC_MAX_CHANNEL_QUOTA 80 |
| #define WMI_MCC_MIN_NON_ZERO_CHANNEL_LATENCY 30 |
| |
| /* The maximum number of patterns that can be transmitted by the firmware |
| * and maximum patterns size. |
| */ |
| #define WMA_MAXNUM_PERIODIC_TX_PTRNS 6 |
| |
| #define WMI_MAX_HOST_CREDITS 2 |
| #define WMI_WOW_REQUIRED_CREDITS 1 |
| |
| #define WMI_MAX_MHF_ENTRIES 32 |
| |
| #ifdef FEATURE_WLAN_D0WOW |
| #define DISABLE_PCIE_POWER_COLLAPSE 1 |
| #define ENABLE_PCIE_POWER_COLLAPSE 0 |
| #endif |
| |
| #define MAX_HT_MCS_IDX 8 |
| #define MAX_VHT_MCS_IDX 10 |
| #define INVALID_MCS_IDX 255 |
| |
| #define LINK_STATUS_LEGACY 0 |
| #define LINK_STATUS_VHT 0x1 |
| #define LINK_STATUS_MIMO 0x2 |
| #define LINK_SUPPORT_VHT 0x4 |
| #define LINK_SUPPORT_MIMO 0x8 |
| |
| #define LINK_RATE_VHT 0x3 |
| |
| #define WMA_MCC_MIRACAST_REST_TIME 400 |
| |
| #define WMA_LOG_COMPLETION_TIMER 10000 /* 10 seconds */ |
| |
| #define WMA_FW_TIME_SYNC_TIMER 60000 /* 1 min */ |
| #define WMA_FW_TIME_STAMP_LOW_MASK 0xffffffff |
| |
| #define WMI_TLV_HEADROOM 128 |
| |
| #define WMA_SUSPEND_TIMEOUT_IN_SSR 1 |
| #define WMA_DEL_BSS_TIMEOUT_IN_SSR 10 |
| #ifdef FEATURE_WLAN_SCAN_PNO |
| static int wma_nlo_scan_cmp_evt_handler(void *handle, u_int8_t *event, |
| u_int32_t len); |
| #endif |
| |
| static enum powersave_qpower_mode wma_get_qpower_config(tp_wma_handle wma); |
| |
| #ifdef FEATURE_WLAN_DIAG_SUPPORT |
| /** |
| * wma_wow_wakeup_stats_event()- send wow wakeup stats |
| * tp_wma_handle wma: WOW wakeup packet counter |
| * |
| * This function sends wow wakeup stats diag event |
| * |
| * Return: void. |
| */ |
| static void wma_wow_wakeup_stats_event(tp_wma_handle wma) |
| { |
| WLAN_VOS_DIAG_EVENT_DEF(WowStats, |
| vos_event_wlan_powersave_wow_stats); |
| vos_mem_zero(&WowStats, sizeof(WowStats)); |
| |
| WowStats.wow_ucast_wake_up_count = wma->wow_ucast_wake_up_count; |
| WowStats.wow_bcast_wake_up_count = wma->wow_bcast_wake_up_count; |
| WowStats.wow_ipv4_mcast_wake_up_count = |
| wma->wow_ipv4_mcast_wake_up_count; |
| WowStats.wow_ipv6_mcast_wake_up_count = |
| wma->wow_ipv6_mcast_wake_up_count; |
| WowStats.wow_ipv6_mcast_ra_stats = wma->wow_ipv6_mcast_ra_stats; |
| WowStats.wow_ipv6_mcast_ns_stats = wma->wow_ipv6_mcast_ns_stats; |
| WowStats.wow_ipv6_mcast_na_stats = wma->wow_ipv6_mcast_na_stats; |
| WowStats.wow_pno_match_wake_up_count = wma->wow_pno_match_wake_up_count; |
| WowStats.wow_pno_complete_wake_up_count = |
| wma->wow_pno_complete_wake_up_count; |
| WowStats.wow_gscan_wake_up_count = wma->wow_gscan_wake_up_count; |
| WowStats.wow_low_rssi_wake_up_count = wma->wow_low_rssi_wake_up_count; |
| WowStats.wow_rssi_breach_wake_up_count = |
| wma->wow_rssi_breach_wake_up_count; |
| WowStats.wow_icmpv4_count = wma->wow_icmpv4_count; |
| WowStats.wow_icmpv6_count = wma->wow_icmpv6_count; |
| WowStats.wow_oem_response_wake_up_count = |
| wma->wow_oem_response_wake_up_count; |
| WLAN_VOS_DIAG_EVENT_REPORT(&WowStats, EVENT_WLAN_POWERSAVE_WOW_STATS); |
| } |
| #else |
| static void wma_wow_wakeup_stats_event(tp_wma_handle wma) |
| { |
| return; |
| } |
| #endif |
| |
| #ifdef FEATURE_WLAN_EXTSCAN |
| /** |
| * enum extscan_report_events_type - extscan report events type |
| * @EXTSCAN_REPORT_EVENTS_BUFFER_FULL: report only when scan history is % full |
| * @EXTSCAN_REPORT_EVENTS_EACH_SCAN: report a scan completion event after scan |
| * @EXTSCAN_REPORT_EVENTS_FULL_RESULTS: forward scan results |
| * (beacons/probe responses + IEs) |
| * in real time to HAL, in addition to completion events. |
| * Note: To keep backward compatibility, |
| * fire completion events regardless of REPORT_EVENTS_EACH_SCAN. |
| * @EXTSCAN_REPORT_EVENTS_NO_BATCH: controls batching, |
| * 0 => batching, 1 => no batching |
| */ |
| enum extscan_report_events_type { |
| EXTSCAN_REPORT_EVENTS_BUFFER_FULL = 0x00, |
| EXTSCAN_REPORT_EVENTS_EACH_SCAN = 0x01, |
| EXTSCAN_REPORT_EVENTS_FULL_RESULTS = 0x02, |
| EXTSCAN_REPORT_EVENTS_NO_BATCH = 0x04, |
| EXTSCAN_REPORT_EVENTS_CONTEXT_HUB = 0x08, |
| }; |
| |
| #define WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION (5 * 1000) /* in msec */ |
| |
| /* |
| * Maximum number of entires that could be present in the |
| * WMI_EXTSCAN_HOTLIST_MATCH_EVENT buffer from the firmware |
| */ |
| #define WMA_EXTSCAN_MAX_HOTLIST_ENTRIES 10 |
| |
| #endif |
| |
| /* Data rate 100KBPS based on IE Index */ |
| struct index_data_rate_type |
| { |
| v_U8_t mcs_index; |
| v_U16_t ht20_rate[2]; |
| v_U16_t ht40_rate[2]; |
| }; |
| |
| #ifdef WLAN_FEATURE_11AC |
| struct index_vht_data_rate_type |
| { |
| v_U8_t mcs_index; |
| v_U16_t ht20_rate[2]; |
| v_U16_t ht40_rate[2]; |
| v_U16_t ht80_rate[2]; |
| }; |
| #endif |
| |
| /* MCS Based rate table */ |
| /* HT MCS parameters with Nss = 1 */ |
| static struct index_data_rate_type mcs_nss1[] = |
| { |
| /* MCS L20 S20 L40 S40 */ |
| {0, {65, 72}, {135, 150 }}, |
| {1, {130, 144}, {270, 300 }}, |
| {2, {195, 217}, {405, 450 }}, |
| {3, {260, 289}, {540, 600 }}, |
| {4, {390, 433}, {815, 900 }}, |
| {5, {520, 578}, {1080, 1200}}, |
| {6, {585, 650}, {1215, 1350}}, |
| {7, {650, 722}, {1350, 1500}} |
| }; |
| /* HT MCS parameters with Nss = 2 */ |
| static struct index_data_rate_type mcs_nss2[] = |
| { |
| /* MCS L20 S20 L40 S40 */ |
| {0, {130, 144}, {270, 300 }}, |
| {1, {260, 289}, {540, 600 }}, |
| {2, {390, 433}, {810, 900 }}, |
| {3, {520, 578}, {1080, 1200}}, |
| {4, {780, 867}, {1620, 1800}}, |
| {5, {1040, 1156}, {2160, 2400}}, |
| {6, {1170, 1300}, {2430, 2700}}, |
| {7, {1300, 1440}, {2700, 3000}} |
| }; |
| |
| #ifdef WLAN_FEATURE_11AC |
| /* MCS Based VHT rate table */ |
| /* MCS parameters with Nss = 1*/ |
| static struct index_vht_data_rate_type vht_mcs_nss1[] = |
| { |
| /* MCS L20 S20 L40 S40 L80 S80 */ |
| {0, {65, 72 }, {135, 150}, {293, 325} }, |
| {1, {130, 144}, {270, 300}, {585, 650} }, |
| {2, {195, 217}, {405, 450}, {878, 975} }, |
| {3, {260, 289}, {540, 600}, {1170, 1300}}, |
| {4, {390, 433}, {810, 900}, {1755, 1950}}, |
| {5, {520, 578}, {1080, 1200}, {2340, 2600}}, |
| {6, {585, 650}, {1215, 1350}, {2633, 2925}}, |
| {7, {650, 722}, {1350, 1500}, {2925, 3250}}, |
| {8, {780, 867}, {1620, 1800}, {3510, 3900}}, |
| {9, {865, 960}, {1800, 2000}, {3900, 4333}} |
| }; |
| |
| /*MCS parameters with Nss = 2*/ |
| static struct index_vht_data_rate_type vht_mcs_nss2[] = |
| { |
| /* MCS L20 S20 L40 S40 L80 S80 */ |
| {0, {130, 144}, {270, 300}, { 585, 650}}, |
| {1, {260, 289}, {540, 600}, {1170, 1300}}, |
| {2, {390, 433}, {810, 900}, {1755, 1950}}, |
| {3, {520, 578}, {1080, 1200}, {2340, 2600}}, |
| {4, {780, 867}, {1620, 1800}, {3510, 3900}}, |
| {5, {1040, 1156}, {2160, 2400}, {4680, 5200}}, |
| {6, {1170, 1300}, {2430, 2700}, {5265, 5850}}, |
| {7, {1300, 1444}, {2700, 3000}, {5850, 6500}}, |
| {8, {1560, 1733}, {3240, 3600}, {7020, 7800}}, |
| {9, {1730, 1920}, {3600, 4000}, {7800, 8667}} |
| }; |
| #endif |
| |
| void wma_send_msg(tp_wma_handle wma_handle, u_int16_t msg_type, |
| void *body_ptr, u_int32_t body_val); |
| |
| #ifdef QCA_IBSS_SUPPORT |
| static void wma_data_tx_ack_comp_hdlr(void *wma_context, |
| adf_nbuf_t netbuf, |
| int32_t status); |
| #endif |
| static VOS_STATUS wma_vdev_detach(tp_wma_handle wma_handle, |
| tpDelStaSelfParams pdel_sta_self_req_param, |
| u_int8_t generateRsp); |
| static int32_t wmi_unified_vdev_stop_send(wmi_unified_t wmi, u_int8_t vdev_id); |
| |
| static tANI_U32 gFwWlanFeatCaps; |
| |
| static eHalStatus wma_set_ppsconfig(tANI_U8 vdev_id, tANI_U16 pps_param, |
| int value); |
| static eHalStatus wma_set_mimops(tp_wma_handle wma_handle, |
| tANI_U8 vdev_id, int value); |
| #ifdef FEATURE_WLAN_TDLS |
| static int wma_update_fw_tdls_state(WMA_HANDLE handle, void *pwmaTdlsparams); |
| static int wma_update_tdls_peer_state(WMA_HANDLE handle, |
| tTdlsPeerStateParams *peerStateParams); |
| static int wma_set_tdls_offchan_mode(WMA_HANDLE wma_handle, |
| tTdlsChanSwitchParams *pChanSwitchParams); |
| #endif |
| |
| static eHalStatus wma_set_smps_params(tp_wma_handle wma_handle, |
| tANI_U8 vdev_id, int value); |
| #if defined(QCA_WIFI_FTM) |
| void wma_utf_attach(tp_wma_handle wma_handle); |
| void wma_utf_detach(tp_wma_handle wma_handle); |
| static VOS_STATUS |
| wma_process_ftm_command(tp_wma_handle wma_handle, |
| struct ar6k_testmode_cmd_data *msg_buffer); |
| #endif |
| |
| VOS_STATUS wma_create_peer(tp_wma_handle wma, ol_txrx_pdev_handle pdev, |
| ol_txrx_vdev_handle vdev, u8 peer_addr[6], |
| u_int32_t peer_type, u_int8_t vdev_id, |
| v_BOOL_t roam_synch_in_progress); |
| static ol_txrx_vdev_handle wma_vdev_attach(tp_wma_handle wma_handle, |
| tpAddStaSelfParams self_sta_req, |
| u_int8_t generateRsp); |
| static void wma_set_bsskey(tp_wma_handle wma_handle, tpSetBssKeyParams key_info); |
| |
| /*DFS Attach*/ |
| struct ieee80211com* wma_dfs_attach(struct ieee80211com *ic); |
| static void wma_dfs_detach(struct ieee80211com *ic); |
| void wma_set_bss_rate_flags(struct wma_txrx_node *iface, |
| tpAddBssParams add_bss); |
| /*Configure DFS with radar tables and regulatory domain*/ |
| void wma_dfs_configure(struct ieee80211com *ic); |
| |
| /*Configure the current channel with the DFS*/ |
| struct ieee80211_channel * |
| wma_dfs_configure_channel(struct ieee80211com *dfs_ic, |
| wmi_channel *chan, |
| WLAN_PHY_MODE chanmode, |
| struct wma_vdev_start_req *req); |
| |
| /* VDEV UP */ |
| static int |
| wmi_unified_vdev_up_send(wmi_unified_t wmi, |
| u_int8_t vdev_id, u_int16_t aid, |
| u_int8_t bssid[IEEE80211_ADDR_LEN]); |
| #ifdef WLAN_FEATURE_ROAM_OFFLOAD |
| void wma_process_roam_synch_complete(WMA_HANDLE handle, |
| tSirSmeRoamOffloadSynchCnf *synchcnf); |
| void wma_process_roam_synch_fail(WMA_HANDLE handle, |
| tSirRoamOffloadSynchFail *synchfail); |
| #endif |
| |
| static VOS_STATUS wma_set_thermal_mgmt(tp_wma_handle wma_handle, |
| t_thermal_cmd_params thermal_info); |
| |
| #ifdef FEATURE_WLAN_CH_AVOID |
| VOS_STATUS wma_process_ch_avoid_update_req(tp_wma_handle wma_handle, |
| tSirChAvoidUpdateReq *ch_avoid_update_req); |
| #endif /* FEATURE_WLAN_CH_AVOID */ |
| |
| static void wma_set_stakey(tp_wma_handle wma_handle, tpSetStaKeyParams key_info); |
| |
| static void wma_beacon_miss_handler(tp_wma_handle wma, u_int32_t vdev_id, |
| uint32_t rssi); |
| static void wma_set_suspend_dtim(tp_wma_handle wma); |
| static void wma_set_resume_dtim(tp_wma_handle wma); |
| static int wma_roam_event_callback(WMA_HANDLE handle, u_int8_t *event_buf, |
| u_int32_t len); |
| static VOS_STATUS wma_stop_scan(tp_wma_handle wma_handle, |
| tAbortScanParams *abort_scan_req); |
| |
| static void wma_set_sap_keepalive(tp_wma_handle wma, u_int8_t vdev_id); |
| static void wma_set_vdev_mgmt_rate(tp_wma_handle wma, u_int8_t vdev_id); |
| static int wma_smps_force_mode_callback(WMA_HANDLE handle, uint8_t *event_buf, |
| uint32_t len); |
| |
| static void wma_send_time_stamp_sync_cmd(void *data); |
| |
| tANI_U8 wma_getCenterChannel(tANI_U8 chan, tANI_U8 chan_offset); |
| |
| |
| /* |
| * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing": |
| * 0 for no restriction |
| * 1 for 1/4 us - Our lower layer calculations limit our precision to 1 msec |
| * 2 for 1/2 us - Our lower layer calculations limit our precision to 1 msec |
| * 3 for 1 us |
| * 4 for 2 us |
| * 5 for 4 us |
| * 6 for 8 us |
| * 7 for 16 us |
| */ |
| static const u_int8_t wma_mpdu_spacing[] = {0, 1, 1, 1, 2, 4, 8, 16}; |
| |
| static inline uint8_t wma_parse_mpdudensity(u_int8_t mpdudensity) |
| { |
| if (mpdudensity < sizeof(wma_mpdu_spacing)) |
| return wma_mpdu_spacing[mpdudensity]; |
| else |
| return 0; |
| } |
| |
| /* Function : wma_get_vdev_count |
| * Discription : Returns number of active vdev. |
| * Args : @wma - wma handle |
| * Returns : Returns valid vdev count. |
| */ |
| static inline u_int8_t wma_get_vdev_count(tp_wma_handle wma) |
| { |
| u_int8_t vdev_count = 0, i; |
| |
| for (i = 0; i < wma->max_bssid; i++) { |
| if (wma->interfaces[i].handle) |
| vdev_count++; |
| } |
| return vdev_count; |
| } |
| |
| /** |
| * wma_did_ssr_happen() - Check if SSR happened by comparing current |
| * wma handle and new wma handle |
| * @wma: Pointer to wma handle |
| * |
| * This API will compare saved wma handle and new wma handle using global |
| * vos context. If both doesn't match implies that WMA handle got changed |
| * while waiting for command which will happen in SSR. |
| * |
| * Return: True if SSR happened else false |
| */ |
| static bool wma_did_ssr_happen(tp_wma_handle wma) |
| { |
| return vos_get_context(VOS_MODULE_ID_WDA, |
| vos_get_global_context(VOS_MODULE_ID_VOSS, NULL)) != wma; |
| } |
| |
| |
| /* Function : wma_is_vdev_in_ap_mode |
| * Description : Helper function to know whether given vdev id |
| * is in AP mode or not. |
| * Args : @wma - wma handle, @ vdev_id - vdev ID. |
| * Returns : True - if given vdev id is in AP mode. |
| * False - if given vdev id is not in AP mode. |
| */ |
| static bool wma_is_vdev_in_ap_mode(tp_wma_handle wma, u_int8_t vdev_id) |
| { |
| struct wma_txrx_node *intf = wma->interfaces; |
| |
| if (vdev_id >= wma->max_bssid) { |
| WMA_LOGP("%s: Invalid vdev_id %hu", __func__, vdev_id); |
| VOS_ASSERT(0); |
| return false; |
| } |
| |
| if ((intf[vdev_id].type == WMI_VDEV_TYPE_AP) && |
| ((intf[vdev_id].sub_type == WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO) || |
| (intf[vdev_id].sub_type == 0))) |
| return true; |
| |
| return false; |
| } |
| |
| #ifdef QCA_IBSS_SUPPORT |
| /* Function : wma_is_vdev_in_ibss_mode |
| s_vdev_in_ibss_mode* Description : Helper function to know whether given vdev id |
| * is in IBSS mode or not. |
| * Args : @wma - wma handle, @ vdev_id - vdev ID. |
| * Retruns : True - if given vdev id is in IBSS mode. |
| * False - if given vdev id is not in IBSS mode. |
| */ |
| static bool wma_is_vdev_in_ibss_mode(tp_wma_handle wma, u_int8_t vdev_id) |
| { |
| struct wma_txrx_node *intf = wma->interfaces; |
| |
| if (vdev_id >= wma->max_bssid) { |
| WMA_LOGP("%s: Invalid vdev_id %hu", __func__, vdev_id); |
| VOS_ASSERT(0); |
| return false; |
| } |
| |
| if (intf[vdev_id].type == WMI_VDEV_TYPE_IBSS) |
| return true; |
| |
| return false; |
| } |
| #endif |
| |
| /* |
| * Function : wma_find_bssid_by_vdev_id |
| * Description : Get the BSS ID corresponding to the vdev ID |
| * Args : @wma - wma handle, @vdev_id - vdev ID |
| * Returns : Returns pointer to bssid on success, |
| * otherwise returns NULL. |
| */ |
| static inline u_int8_t *wma_find_bssid_by_vdev_id(tp_wma_handle wma, |
| u_int8_t vdev_id) |
| { |
| if (vdev_id >= wma->max_bssid) |
| return NULL; |
| |
| return wma->interfaces[vdev_id].bssid; |
| } |
| |
| /* |
| * Function : wma_find_vdev_by_bssid |
| * Description : Get the VDEV ID corresponding from BSS ID |
| * Args : @wma - wma handle, @vdev_id - vdev ID |
| * Returns : Returns pointer to bssid on success, |
| * otherwise returns NULL. |
| */ |
| static void *wma_find_vdev_by_bssid(tp_wma_handle wma, u_int8_t *bssid, |
| u_int8_t *vdev_id) |
| { |
| int i; |
| |
| for (i = 0; i < wma->max_bssid; i++) { |
| if (vos_is_macaddr_equal( |
| (v_MACADDR_t *)wma->interfaces[i].bssid, |
| (v_MACADDR_t *)bssid) == VOS_TRUE) { |
| *vdev_id = i; |
| return wma->interfaces[i].handle; |
| } |
| } |
| |
| return NULL; |
| } |
| |
| #ifdef BIG_ENDIAN_HOST |
| |
| /* ############# function definitions ############ */ |
| |
| /* function : wma_swap_bytes |
| * Description : |
| * Args : |
| * Retruns : |
| */ |
| v_VOID_t wma_swap_bytes(v_VOID_t *pv, v_SIZE_t n) |
| { |
| v_SINT_t no_words; |
| v_SINT_t i; |
| v_U32_t *word_ptr; |
| |
| no_words = n/sizeof(v_U32_t); |
| word_ptr = (v_U32_t *)pv; |
| for (i=0; i<no_words; i++) { |
| *(word_ptr + i) = __cpu_to_le32(*(word_ptr + i)); |
| } |
| } |
| #define SWAPME(x, len) wma_swap_bytes(&x, len); |
| #endif |
| |
| /** |
| * mcs_rate_match() - find the match mcs rate |
| * @is_sgi: return if the SGI rate is found |
| * @nss: the nss in use |
| * @nss1_rate: the nss1 rate |
| * @nss1_srate: the nss1 SGI rate |
| * @nss2_rate: the nss2 rate |
| * @nss2_srate: the nss2 SGI rate |
| * |
| * This is a helper function to find the match of the tx_rate |
| * in terms of the nss1/nss2 rate with non-SGI/SGI. |
| * |
| * Return: the found rate or 0 otherwise |
| */ |
| static inline uint16_t mcs_rate_match(uint16_t match_rate, bool *is_sgi, |
| uint8_t nss, uint16_t nss1_rate, uint16_t nss1_srate, |
| uint16_t nss2_rate, uint16_t nss2_srate) |
| { |
| if (match_rate == nss1_rate) |
| return nss1_rate; |
| else if (match_rate == nss1_srate) { |
| *is_sgi = true; |
| return nss1_srate; |
| } else if (nss == 2 && match_rate == nss2_rate) |
| return nss2_rate; |
| else if (nss == 2 && match_rate == nss2_srate) { |
| *is_sgi = true; |
| return nss2_srate; |
| } else |
| return 0; |
| } |
| |
| static tANI_U8 wma_get_mcs_idx(tANI_U16 maxRate, tANI_U8 rate_flags, |
| tANI_U8 nss, |
| tANI_U8 *mcsRateFlag) |
| { |
| tANI_U8 curIdx = 0; |
| tANI_U16 cur_rate = 0; |
| bool is_sgi = false; |
| |
| WMA_LOGD("%s rate:%d rate_flgs: 0x%x, nss: %d", |
| __func__, maxRate,rate_flags, nss); |
| |
| *mcsRateFlag = rate_flags; |
| *mcsRateFlag &= ~eHAL_TX_RATE_SGI; |
| |
| #ifdef WLAN_FEATURE_11AC |
| for (curIdx = 0; curIdx < MAX_VHT_MCS_IDX; curIdx++) { |
| if (rate_flags & eHAL_TX_RATE_VHT80) { |
| /* check for vht80 nss1/2 rate set */ |
| cur_rate = mcs_rate_match(maxRate, &is_sgi, nss, |
| vht_mcs_nss1[curIdx].ht80_rate[0], |
| vht_mcs_nss1[curIdx].ht80_rate[1], |
| vht_mcs_nss2[curIdx].ht80_rate[0], |
| vht_mcs_nss2[curIdx].ht80_rate[1]); |
| if (cur_rate) |
| goto rate_found; |
| } |
| if ((rate_flags & eHAL_TX_RATE_VHT40) | |
| (rate_flags & eHAL_TX_RATE_VHT80)) { |
| /* check for vht40 nss1/2 rate set */ |
| cur_rate = mcs_rate_match(maxRate, &is_sgi, nss, |
| vht_mcs_nss1[curIdx].ht40_rate[0], |
| vht_mcs_nss1[curIdx].ht40_rate[1], |
| vht_mcs_nss2[curIdx].ht40_rate[0], |
| vht_mcs_nss2[curIdx].ht40_rate[1]); |
| if (cur_rate) { |
| *mcsRateFlag &= ~eHAL_TX_RATE_VHT80; |
| goto rate_found; |
| } |
| } |
| if ((rate_flags & eHAL_TX_RATE_VHT20) | |
| (rate_flags & eHAL_TX_RATE_VHT40) | |
| (rate_flags & eHAL_TX_RATE_VHT80)) { |
| /* check for vht20 nss1/2 rate set */ |
| cur_rate = mcs_rate_match(maxRate, &is_sgi, nss, |
| vht_mcs_nss1[curIdx].ht20_rate[0], |
| vht_mcs_nss1[curIdx].ht20_rate[1], |
| vht_mcs_nss2[curIdx].ht20_rate[0], |
| vht_mcs_nss2[curIdx].ht20_rate[1]); |
| if (cur_rate) { |
| *mcsRateFlag &= ~(eHAL_TX_RATE_VHT80 | |
| eHAL_TX_RATE_VHT40); |
| goto rate_found; |
| } |
| } |
| } |
| #endif |
| for (curIdx = 0; curIdx < MAX_HT_MCS_IDX; curIdx++) { |
| if (rate_flags & eHAL_TX_RATE_HT40) { |
| /* check for ht40 nss1/2 rate set */ |
| cur_rate = mcs_rate_match(maxRate, &is_sgi, nss, |
| mcs_nss1[curIdx].ht40_rate[0], |
| mcs_nss1[curIdx].ht40_rate[1], |
| mcs_nss2[curIdx].ht40_rate[0], |
| mcs_nss2[curIdx].ht40_rate[1]); |
| if (cur_rate) { |
| *mcsRateFlag = eHAL_TX_RATE_HT40; |
| goto rate_found; |
| } |
| } |
| if ((rate_flags & eHAL_TX_RATE_HT20) || |
| (rate_flags & eHAL_TX_RATE_HT40)) { |
| /* check for ht20 nss1/2 rate set */ |
| cur_rate = mcs_rate_match(maxRate, &is_sgi, nss, |
| mcs_nss1[curIdx].ht20_rate[0], |
| mcs_nss1[curIdx].ht20_rate[1], |
| mcs_nss2[curIdx].ht20_rate[0], |
| mcs_nss2[curIdx].ht20_rate[1]); |
| if (cur_rate) { |
| *mcsRateFlag = eHAL_TX_RATE_HT20; |
| goto rate_found; |
| } |
| } |
| } |
| |
| rate_found: |
| /* set SGI flag only if this is SGI rate */ |
| if (cur_rate && is_sgi == true) |
| *mcsRateFlag |= eHAL_TX_RATE_SGI; |
| |
| WMA_LOGD("%s - cur_rate: %d index: %d rate_flag: 0x%x is_sgi: %d", |
| __func__, cur_rate, curIdx, *mcsRateFlag, is_sgi); |
| |
| return (cur_rate ? curIdx : INVALID_MCS_IDX); |
| } |
| |
| static struct wma_target_req *wma_find_vdev_req(tp_wma_handle wma, |
| u_int8_t vdev_id, |
| u_int8_t type) |
| { |
| struct wma_target_req *req_msg = NULL, *tmp; |
| bool found = false; |
| |
| adf_os_spin_lock_bh(&wma->vdev_respq_lock); |
| list_for_each_entry_safe(req_msg, tmp, |
| &wma->vdev_resp_queue, node) { |
| if (req_msg->vdev_id != vdev_id) |
| continue; |
| if (req_msg->type != type) |
| continue; |
| |
| found = true; |
| list_del(&req_msg->node); |
| break; |
| } |
| adf_os_spin_unlock_bh(&wma->vdev_respq_lock); |
| if (!found) { |
| WMA_LOGP("%s: target request not found for vdev_id %d type %d", |
| __func__, vdev_id, type); |
| return NULL; |
| } |
| WMA_LOGD("%s: target request found for vdev id: %d type %d msg %d", |
| __func__, vdev_id, type, req_msg->msg_type); |
| return req_msg; |
| } |
| |
| /** |
| * wma_peek_vdev_req() - peek what request message is queued for response. |
| * the function does not delete the node after found |
| * @wma: WMA handle |
| * @vdev_id: vdev ID |
| * @type: request message type |
| * |
| * Return: the request message found |
| */ |
| static struct wma_target_req *wma_peek_vdev_req(tp_wma_handle wma, |
| uint8_t vdev_id, |
| uint8_t type) |
| { |
| struct wma_target_req *req_msg = NULL, *tmp; |
| bool found = false; |
| |
| adf_os_spin_lock_bh(&wma->vdev_respq_lock); |
| list_for_each_entry_safe(req_msg, tmp, &wma->vdev_resp_queue, node) { |
| if (req_msg->vdev_id != vdev_id) |
| continue; |
| if (req_msg->type != type) |
| continue; |
| |
| found = true; |
| break; |
| } |
| adf_os_spin_unlock_bh(&wma->vdev_respq_lock); |
| if (!found) { |
| WMA_LOGP("%s: target request not found for vdev_id %d type %d", |
| __func__, vdev_id, type); |
| return NULL; |
| } |
| WMA_LOGD("%s: target request found for vdev id: %d type %d msg %d", |
| __func__, vdev_id, type, req_msg->msg_type); |
| return req_msg; |
| } |
| |
| /** |
| * wma_get_bpf_caps_event_handler() - Event handler for get bpf capability |
| * @handle: WMA global handle |
| * @cmd_param_info: command event data |
| * @len: Length of @cmd_param_info |
| * |
| * Return: 0 on Success or Errno on failure |
| */ |
| static int wma_get_bpf_caps_event_handler(void *handle, |
| u_int8_t *cmd_param_info, |
| u_int32_t len) |
| { |
| tp_wma_handle wma = (tp_wma_handle)handle; |
| WMI_BPF_CAPABILIY_INFO_EVENTID_param_tlvs *param_buf; |
| wmi_bpf_capability_info_evt_fixed_param *event; |
| struct sir_bpf_get_offload *bpf_get_offload; |
| tpAniSirGlobal pmac = (tpAniSirGlobal)vos_get_context( |
| VOS_MODULE_ID_PE, wma->vos_context); |
| |
| if (!pmac) { |
| WMA_LOGE("%s: Invalid pmac", __func__); |
| return -EINVAL; |
| } |
| if (!pmac->sme.pbpf_get_offload_cb) { |
| WMA_LOGE("%s: Callback not registered", __func__); |
| return -EINVAL; |
| } |
| |
| param_buf = (WMI_BPF_CAPABILIY_INFO_EVENTID_param_tlvs *)cmd_param_info; |
| event = param_buf->fixed_param; |
| bpf_get_offload = vos_mem_malloc(sizeof(*bpf_get_offload)); |
| |
| if (!bpf_get_offload) { |
| WMA_LOGP("%s: Memory allocation failed.", __func__); |
| return -ENOMEM; |
| } |
| |
| bpf_get_offload->bpf_version = event->bpf_version; |
| bpf_get_offload->max_bpf_filters = event->max_bpf_filters; |
| bpf_get_offload->max_bytes_for_bpf_inst = |
| event->max_bytes_for_bpf_inst; |
| WMA_LOGD("%s: BPF capabilities version: %d max bpf filter size: %d", |
| __func__, bpf_get_offload->bpf_version, |
| bpf_get_offload->max_bytes_for_bpf_inst); |
| |
| WMA_LOGD("%s: sending bpf capabilities event to hdd", __func__); |
| pmac->sme.pbpf_get_offload_cb(pmac->hHdd, bpf_get_offload); |
| vos_mem_free(bpf_get_offload); |
| return 0; |
| } |
| |
| /** |
| * wma_lost_link_info_handler() - collect lost link information and inform SME |
| * when disconnection in STA mode. |
| * @wma: WMA handle |
| * @vdev_id: vdev ID |
| * @rssi: rssi at disconnection time |
| * |
| * Return: none |
| */ |
| static void wma_lost_link_info_handler(tp_wma_handle wma, uint32_t vdev_id, |
| int8_t rssi) |
| { |
| struct sir_lost_link_info *lost_link_info; |
| VOS_STATUS vos_status; |
| vos_msg_t sme_msg = {0}; |
| /* report lost link information only for STA mode */ |
| if (wma->interfaces[vdev_id].vdev_up && |
| (WMI_VDEV_TYPE_STA == wma->interfaces[vdev_id].type) && |
| (0 == wma->interfaces[vdev_id].sub_type)) { |
| lost_link_info = vos_mem_malloc(sizeof(*lost_link_info)); |
| if (NULL == lost_link_info) { |
| WMA_LOGE("%s: failed to allocate memory", __func__); |
| return; |
| } |
| lost_link_info->vdev_id = vdev_id; |
| lost_link_info->rssi = rssi; |
| sme_msg.type = eWNI_SME_LOST_LINK_INFO_IND; |
| sme_msg.bodyptr = lost_link_info; |
| sme_msg.bodyval = 0; |
| WMA_LOGI("%s: post msg to SME, bss_idx %d, rssi %d", |
| __func__, |
| lost_link_info->vdev_id, |
| lost_link_info->rssi); |
| |
| vos_status = vos_mq_post_message(VOS_MODULE_ID_SME, &sme_msg); |
| if (!VOS_IS_STATUS_SUCCESS(vos_status)) { |
| WMA_LOGE("%s: fail to post msg to SME", |
| __func__); |
| vos_mem_free(lost_link_info); |
| } |
| } |
| } |
| |
| tSmpsModeValue host_map_smps_mode (A_UINT32 fw_smps_mode) |
| { |
| tSmpsModeValue smps_mode = SMPS_MODE_DISABLED; |
| switch (fw_smps_mode) { |
| case WMI_SMPS_FORCED_MODE_STATIC: |
| smps_mode = STATIC_SMPS_MODE; |
| break; |
| case WMI_SMPS_FORCED_MODE_DYNAMIC: |
| smps_mode = DYNAMIC_SMPS_MODE; |
| break; |
| default: |
| smps_mode = SMPS_MODE_DISABLED; |
| } |
| |
| return smps_mode; |
| } |
| |
| /** |
| * wma_smps_mode_to_force_mode_param() - Map smps mode to force |
| * mode commmand param |
| * @smps_mode: SMPS mode according to the protocol |
| * |
| * Return: int > 0 for success else failure |
| */ |
| static int wma_smps_mode_to_force_mode_param(uint8_t smps_mode) |
| { |
| int param = -EINVAL; |
| |
| switch (smps_mode) { |
| case STATIC_SMPS_MODE: |
| param = WMI_SMPS_FORCED_MODE_STATIC; |
| break; |
| case DYNAMIC_SMPS_MODE: |
| param = WMI_SMPS_FORCED_MODE_DYNAMIC; |
| break; |
| case SMPS_MODE_DISABLED: |
| param = WMI_SMPS_FORCED_MODE_DISABLED; |
| break; |
| default: |
| WMA_LOGE(FL("smps mode cannot be mapped :%d "), |
| smps_mode); |
| } |
| return param; |
| } |
| |
| #ifdef FEATURE_WLAN_AUTO_SHUTDOWN |
| /* function : wma_post_auto_shutdown_msg |
| * Description : function to post auto shutdown event to sme |
| */ |
| static int wma_post_auto_shutdown_msg(void) |
| { |
| tSirAutoShutdownEvtParams *auto_sh_evt; |
| VOS_STATUS vos_status; |
| vos_msg_t sme_msg = {0} ; |
| |
| auto_sh_evt = (tSirAutoShutdownEvtParams *) |
| vos_mem_malloc(sizeof(tSirAutoShutdownEvtParams)); |
| if (!auto_sh_evt) { |
| WMA_LOGE("%s: No Mem", __func__); |
| return -ENOMEM; |
| } |
| |
| auto_sh_evt->shutdown_reason = |
| WMI_HOST_AUTO_SHUTDOWN_REASON_TIMER_EXPIRY; |
| sme_msg.type = eWNI_SME_AUTO_SHUTDOWN_IND; |
| sme_msg.bodyptr = auto_sh_evt; |
| sme_msg.bodyval = 0; |
| |
| vos_status = vos_mq_post_message(VOS_MODULE_ID_SME, &sme_msg); |
| if ( !VOS_IS_STATUS_SUCCESS(vos_status) ) { |
| WMA_LOGE("Fail to post eWNI_SME_AUTO_SHUTDOWN_IND msg to SME"); |
| vos_mem_free(auto_sh_evt); |
| return -EINVAL; |
| } |
| |
| return 0; |
| } |
| |
| /* function : wma_auto_shutdown_event_handler |
| * Description : function to process auto shutdown timer trigger |
| */ |
| static int wma_auto_shutdown_event_handler(void *handle, u_int8_t *event, |
| u_int32_t len) |
| { |
| wmi_host_auto_shutdown_event_fixed_param *wmi_auto_sh_evt; |
| WMI_HOST_AUTO_SHUTDOWN_EVENTID_param_tlvs *param_buf = |
| (WMI_HOST_AUTO_SHUTDOWN_EVENTID_param_tlvs *) |
| event; |
| |
| if (!param_buf || !param_buf->fixed_param) { |
| WMA_LOGE("%s:%d: Invalid Auto shutdown timer evt", __func__, |
| __LINE__); |
| return -EINVAL; |
| } |
| |
| |
| wmi_auto_sh_evt = param_buf->fixed_param; |
| |
| if (wmi_auto_sh_evt->shutdown_reason |
| != WMI_HOST_AUTO_SHUTDOWN_REASON_TIMER_EXPIRY) { |
| WMA_LOGE("%s:%d: Invalid Auto shutdown timer evt", __func__, |
| __LINE__); |
| return -EINVAL; |
| } |
| |
| WMA_LOGD("%s:%d: Auto Shutdown Evt: %d", __func__, __LINE__, |
| wmi_auto_sh_evt->shutdown_reason); |
| return(wma_post_auto_shutdown_msg()); |
| } |
| |
| /* function : wma_set_auto_shutdown_timer_req |
| * Description : function sets auto shutdown timer in firmware |
| * Args : wma handle, auto shutdown timer value |
| * Returns : status of wmi cmd |
| */ |
| static VOS_STATUS wma_set_auto_shutdown_timer_req(tp_wma_handle wma_handle, |
| tSirAutoShutdownCmdParams *auto_sh_cmd) |
| { |
| int status = 0; |
| wmi_buf_t buf = NULL; |
| u_int8_t *buf_ptr; |
| wmi_host_auto_shutdown_cfg_cmd_fixed_param *wmi_auto_sh_cmd; |
| int len = sizeof(wmi_host_auto_shutdown_cfg_cmd_fixed_param); |
| |
| if (auto_sh_cmd == NULL) { |
| WMA_LOGE("%s : Invalid Autoshutdown cfg cmd", __func__); |
| return VOS_STATUS_E_FAILURE; |
| } |
| |
| WMA_LOGD("%s: Set WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID:TIMER_VAL=%d", |
| __func__, auto_sh_cmd->timer_val); |
| |
| buf = wmi_buf_alloc(wma_handle->wmi_handle, len); |
| if (!buf) { |
| WMA_LOGE("%s : wmi_buf_alloc failed", __func__); |
| return VOS_STATUS_E_NOMEM; |
| } |
| |
| buf_ptr = (u_int8_t *) wmi_buf_data(buf); |
| wmi_auto_sh_cmd = (wmi_host_auto_shutdown_cfg_cmd_fixed_param *)buf_ptr; |
| wmi_auto_sh_cmd->timer_value = auto_sh_cmd->timer_val; |
| |
| WMITLV_SET_HDR(&wmi_auto_sh_cmd->tlv_header, |
| WMITLV_TAG_STRUC_wmi_host_auto_shutdown_cfg_cmd_fixed_param, |
| WMITLV_GET_STRUCT_TLVLEN(wmi_host_auto_shutdown_cfg_cmd_fixed_param)); |
| |
| status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, |
| len, WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID); |
| if (status != EOK) { |
| WMA_LOGE("%s: WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID Err %d", |
| __func__, status); |
| wmi_buf_free(buf); |
| return VOS_STATUS_E_FAILURE; |
| } |
| |
| return VOS_STATUS_SUCCESS; |
| } |
| #endif |
| |
| static void wma_vdev_start_rsp(tp_wma_handle wma, |
| tpAddBssParams add_bss, |
| wmi_vdev_start_response_event_fixed_param *resp_event) |
| { |
| struct beacon_info *bcn; |
| |
| #ifdef QCA_IBSS_SUPPORT |
| WMA_LOGD("%s: vdev start response received for %s mode", __func__, |
| add_bss->operMode == BSS_OPERATIONAL_MODE_IBSS ? "IBSS" : "non-IBSS"); |
| #endif |
| |
| if (resp_event->status) { |
| add_bss->status = VOS_STATUS_E_FAILURE; |
| goto send_fail_resp; |
| } |
| |
| if ((add_bss->operMode == BSS_OPERATIONAL_MODE_AP) |
| #ifdef QCA_IBSS_SUPPORT |
| || (add_bss->operMode == BSS_OPERATIONAL_MODE_IBSS) |
| #endif |
| ) { |
| wma->interfaces[resp_event->vdev_id].beacon = |
| vos_mem_malloc(sizeof(struct beacon_info)); |
| |
| bcn = wma->interfaces[resp_event->vdev_id].beacon; |
| if (!bcn) { |
| WMA_LOGE("%s: Failed alloc memory for beacon struct", |
| __func__); |
| add_bss->status = VOS_STATUS_E_FAILURE; |
| goto send_fail_resp; |
| } |
| vos_mem_zero(bcn, sizeof(*bcn)); |
| bcn->buf = adf_nbuf_alloc(NULL, WMA_BCN_BUF_MAX_SIZE, 0, |
| sizeof(u_int32_t), 0); |
| if (!bcn->buf) { |
| WMA_LOGE("%s: No memory allocated for beacon buffer", |
| __func__); |
| vos_mem_free(bcn); |
| add_bss->status = VOS_STATUS_E_FAILURE; |
| goto send_fail_resp; |
| } |
| bcn->seq_no = MIN_SW_SEQ; |
| adf_os_spinlock_init(&bcn->lock); |
| adf_os_atomic_set(&wma->interfaces[resp_event->vdev_id].bss_status, |
| WMA_BSS_STATUS_STARTED); |
| WMA_LOGD("%s: AP mode (type %d subtype %d) BSS is started", __func__, |
| wma->interfaces[resp_event->vdev_id].type, |
| wma->interfaces[resp_event->vdev_id].sub_type); |
| |
| WMA_LOGD("%s: Allocated beacon struct %pK, template memory %pK", |
| __func__, bcn, bcn->buf); |
| } |
| add_bss->status = VOS_STATUS_SUCCESS; |
| add_bss->bssIdx = resp_event->vdev_id; |
| add_bss->chainMask = resp_event->chain_mask; |
| add_bss->smpsMode = host_map_smps_mode(resp_event->smps_mode); |
| send_fail_resp: |
| WMA_LOGD("%s: Sending add bss rsp to umac(vdev %d status %d)", |
| __func__, resp_event->vdev_id, add_bss->status); |
| wma_send_msg(wma, WDA_ADD_BSS_RSP, (void *)add_bss, 0); |
| } |
| |
| static int wma_vdev_start_resp_handler(void *handle, u_int8_t *cmd_param_info, |
| u_int32_t len) |
| { |
| WMI_VDEV_START_RESP_EVENTID_param_tlvs *param_buf; |
| wmi_vdev_start_response_event_fixed_param *resp_event; |
| u_int8_t *buf; |
| vos_msg_t vos_msg = {0}; |
| tp_wma_handle wma = (tp_wma_handle) handle; |
| ol_txrx_pdev_handle pdev = NULL; |
| |
| WMA_LOGI("%s: Enter", __func__); |
| param_buf = (WMI_VDEV_START_RESP_EVENTID_param_tlvs *) cmd_param_info; |
| if (!param_buf) { |
| WMA_LOGE("Invalid start response event buffer"); |
| return -EINVAL; |
| } |
| |
| pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context); |
| |
| if (pdev == NULL) { |
| WMA_LOGE("vdev start resp fail as pdev is NULL"); |
| return -EINVAL; |
| } |
| |
| resp_event = param_buf->fixed_param; |
| buf = vos_mem_malloc(sizeof(wmi_vdev_start_response_event_fixed_param)); |
| if (!buf) { |
| WMA_LOGE("%s: Failed alloc memory for buf", __func__); |
| return -EINVAL; |
| } |
| |
| if (wma_is_vdev_in_ap_mode(wma, resp_event->vdev_id)) { |
| adf_os_spin_lock_bh(&wma->dfs_ic->chan_lock); |
| wma->dfs_ic->disable_phy_err_processing = false; |
| adf_os_spin_unlock_bh(&wma->dfs_ic->chan_lock); |
| } |
| |
| if (wma->pause_other_vdev_on_mcc_start) { |
| WMA_LOGD("%s: unpause other vdevs since paused when MCC start", __func__); |
| wma->pause_other_vdev_on_mcc_start = false; |
| wdi_in_pdev_unpause_other_vdev(pdev, |
| OL_TXQ_PAUSE_REASON_MCC_VDEV_START, |
| resp_event->vdev_id); |
| } |
| |
| vos_mem_zero(buf, sizeof(wmi_vdev_start_response_event_fixed_param)); |
| vos_mem_copy(buf, (u_int8_t *)resp_event, |
| sizeof(wmi_vdev_start_response_event_fixed_param)); |
| |
| vos_msg.type = WDA_VDEV_START_RSP_IND; |
| vos_msg.bodyptr = buf; |
| vos_msg.bodyval = 0; |
| |
| if (VOS_STATUS_SUCCESS != |
| vos_mq_post_message(VOS_MQ_ID_WDA, &vos_msg)) { |
| WMA_LOGP("%s: Failed to post WDA_VDEV_START_RSP_IND msg", __func__); |
| vos_mem_free(buf); |
| return -1; |
| } |
| WMA_LOGD("WDA_VDEV_START_RSP_IND posted"); |
| return 0; |
| } |
| |
| #ifdef FEATURE_AP_MCC_CH_AVOIDANCE |
| /** |
| * wma_find_mcc_ap() - finds if device is operating AP in MCC mode or not |
| * @wma: wma handle. |
| * @vdev_id: vdev ID of device for which MCC has to be checked |
| * @add: flag indicating if current device is added or deleted |
| * |
| * This function parses through all the interfaces in wma and finds if |
| * any of those devces are in MCC mode with AP. If such a vdev is found |
| * involved AP vdevs are sent WDA_UPDATE_Q2Q_IE_IND msg to update their |
| * beacon template to include Q2Q IE. |
| * |
| * Return: void |
| */ |
| void wma_find_mcc_ap(tp_wma_handle wma, |
| uint8_t vdev_id, |
| bool add) |
| { |
| uint8_t i; |
| uint16_t prev_ch_freq = 0; |
| bool is_ap = false; |
| bool result = false; |
| uint8_t * ap_vdev_ids = NULL; |
| uint8_t num_ch = 0; |
| |
| ap_vdev_ids = vos_mem_malloc(wma->max_bssid); |
| if (!ap_vdev_ids) { |
| return; |
| } |
| |
| for(i = 0; i < wma->max_bssid; i++) { |
| ap_vdev_ids[i] = -1; |
| if( add == false && i == vdev_id) |
| continue; |
| |
| if( wma->interfaces[i].vdev_up || (i == vdev_id && add) ) { |
| |
| if(wma->interfaces[i].type == WMI_VDEV_TYPE_AP) { |
| is_ap = true; |
| ap_vdev_ids[i] = i; |
| } |
| |
| if(wma->interfaces[i].mhz != prev_ch_freq) { |
| num_ch++; |
| prev_ch_freq = wma->interfaces[i].mhz; |
| } |
| } |
| } |
| |
| if( is_ap && (num_ch > 1) ) |
| result = true; |
| else |
| result = false; |
| |
| wma_send_msg(wma, WDA_UPDATE_Q2Q_IE_IND, (void*)ap_vdev_ids, result); |
| } |
| #endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ |
| |
| static const wmi_channel_width mode_to_width[MODE_MAX] = |
| { |
| [MODE_11A] = WMI_CHAN_WIDTH_20, |
| [MODE_11G] = WMI_CHAN_WIDTH_20, |
| [MODE_11B] = WMI_CHAN_WIDTH_20, |
| [MODE_11GONLY] = WMI_CHAN_WIDTH_20, |
| [MODE_11NA_HT20] = WMI_CHAN_WIDTH_20, |
| [MODE_11NG_HT20] = WMI_CHAN_WIDTH_20, |
| [MODE_11AC_VHT20] = WMI_CHAN_WIDTH_20, |
| [MODE_11AC_VHT20_2G] = WMI_CHAN_WIDTH_20, |
| [MODE_11NA_HT40] = WMI_CHAN_WIDTH_40, |
| [MODE_11NG_HT40] = WMI_CHAN_WIDTH_40, |
| [MODE_11AC_VHT40] = WMI_CHAN_WIDTH_40, |
| [MODE_11AC_VHT40_2G] = WMI_CHAN_WIDTH_40, |
| [MODE_11AC_VHT80] = WMI_CHAN_WIDTH_80, |
| #if CONFIG_160MHZ_SUPPORT |
| [MODE_11AC_VHT80_80] = WMI_CHAN_WIDTH_80P80, |
| [MODE_11AC_VHT160] = WMI_CHAN_WIDTH_160, |
| #endif |
| }; |
| |
| /** |
| * chanmode_to_chanwidth() - get channel width through channel mode |
| * @chanmode: channel phy mode |
| * |
| * Return: channel width |
| */ |
| static wmi_channel_width chanmode_to_chanwidth(WLAN_PHY_MODE chanmode) |
| { |
| wmi_channel_width chan_width; |
| |
| if (chanmode >= MODE_11A && chanmode < MODE_MAX) |
| chan_width = mode_to_width[chanmode]; |
| else |
| chan_width = WMI_CHAN_WIDTH_20; |
| |
| return chan_width; |
| } |
| |
| static int wma_vdev_start_rsp_ind(tp_wma_handle wma, u_int8_t *buf) |
| { |
| struct wma_target_req *req_msg; |
| struct wma_txrx_node *iface; |
| int err; |
| wmi_channel_width chanwidth; |
| |
| wmi_vdev_start_response_event_fixed_param *resp_event; |
| #ifdef FEATURE_AP_MCC_CH_AVOIDANCE |
| tpAniSirGlobal mac_ctx = (tpAniSirGlobal)vos_get_context( |
| VOS_MODULE_ID_PE, |
| wma->vos_context); |
| if (NULL == mac_ctx) { |
| WMA_LOGE("%s: Failed to get mac_ctx", __func__); |
| return -EINVAL; |
| } |
| #endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ |
| |
| resp_event = (wmi_vdev_start_response_event_fixed_param *)buf; |
| |
| if (!resp_event) { |
| WMA_LOGE("Invalid start response event buffer"); |
| return -EINVAL; |
| } |
| |
| if (resp_event->vdev_id >= wma->max_bssid) { |
| WMA_LOGE("%s: received invalid vdev_id %d", |
| __func__, resp_event->vdev_id); |
| return -EINVAL; |
| } |
| |
| iface = &wma->interfaces[resp_event->vdev_id]; |
| |
| if ((resp_event->vdev_id < wma->max_bssid) && |
| (adf_os_atomic_read( |
| &wma->interfaces[resp_event->vdev_id].vdev_restart_params.hidden_ssid_restart_in_progress)) && |
| (wma_is_vdev_in_ap_mode(wma, resp_event->vdev_id) == true)) { |
| WMA_LOGE( |
| "%s: vdev restart event recevied for hidden ssid set using IOCTL", |
| __func__); |
| |
| if (wmi_unified_vdev_up_send(wma->wmi_handle, resp_event->vdev_id, 0, |
| wma->interfaces[resp_event->vdev_id].bssid) < 0) { |
| WMA_LOGE("%s : failed to send vdev up", __func__); |
| return -EEXIST; |
| } |
| adf_os_atomic_set( |
| &wma->interfaces[resp_event->vdev_id].vdev_restart_params.hidden_ssid_restart_in_progress, 0); |
| wma->interfaces[resp_event->vdev_id].vdev_up = TRUE; |
| |
| /* |
| * Unpause TX queue in SAP case while configuring hidden ssid |
| * enable or disable, else the data path is paused forever |
| * causing data packets(starting from DHCP offer) to get stuck |
| */ |
| wdi_in_vdev_unpause(iface->handle, |
| OL_TXQ_PAUSE_REASON_VDEV_STOP); |
| iface->pause_bitmap &= ~(1 << PAUSE_TYPE_HOST); |
| |
| } |
| |
| req_msg = wma_find_vdev_req(wma, resp_event->vdev_id, |
| WMA_TARGET_REQ_TYPE_VDEV_START); |
| |
| if (!req_msg) { |
| WMA_LOGE("%s: Failed to lookup request message for vdev %d", |
| __func__, resp_event->vdev_id); |
| return -EINVAL; |
| } |
| |
| vos_timer_stop(&req_msg->event_timeout); |
| |
| #ifdef FEATURE_AP_MCC_CH_AVOIDANCE |
| if (resp_event->status == VOS_STATUS_SUCCESS |
| && mac_ctx->sap.sap_channel_avoidance) |
| wma_find_mcc_ap(wma, resp_event->vdev_id, true); |
| #endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ |
| |
| if (req_msg->msg_type == WDA_CHNL_SWITCH_REQ) { |
| tpSwitchChannelParams params = |
| (tpSwitchChannelParams) req_msg->user_data; |
| if(!params) { |
| WMA_LOGE("%s: channel switch params is NULL for vdev %d", |
| __func__, resp_event->vdev_id); |
| return -EINVAL; |
| } |
| |
| WMA_LOGD("%s: Send channel switch resp vdev %d status %d", |
| __func__, resp_event->vdev_id, resp_event->status); |
| params->chainMask = resp_event->chain_mask; |
| params->smpsMode = host_map_smps_mode(resp_event->smps_mode); |
| params->status = resp_event->status; |
| if (wma->interfaces[resp_event->vdev_id].is_channel_switch) |
| wma->interfaces[resp_event->vdev_id].is_channel_switch = |
| VOS_FALSE; |
| if (((resp_event->resp_type == WMI_VDEV_RESTART_RESP_EVENT) && |
| (iface->type == WMI_VDEV_TYPE_STA)) || |
| ((resp_event->resp_type == WMI_VDEV_START_RESP_EVENT) && |
| (iface->type == WMI_VDEV_TYPE_MONITOR))) { |
| |
| err = wma_set_peer_param(wma, iface->bssid, |
| WMI_PEER_PHYMODE, iface->chanmode, |
| resp_event->vdev_id); |
| |
| WMA_LOGD("%s:vdev_id %d chanmode %d status %d", |
| __func__, resp_event->vdev_id, |
| iface->chanmode, err); |
| |
| chanwidth = chanmode_to_chanwidth(iface->chanmode); |
| err = wma_set_peer_param(wma, iface->bssid, |
| WMI_PEER_CHWIDTH, chanwidth, |
| resp_event->vdev_id); |
| |
| WMA_LOGD("%s:vdev_id %d chanwidth %d status %d", |
| __func__, resp_event->vdev_id, |
| chanwidth, err); |
| |
| if (wmi_unified_vdev_up_send(wma->wmi_handle, |
| resp_event->vdev_id, iface->aid, |
| iface->bssid)) { |
| WMA_LOGE("%s:vdev_up failed vdev_id %d", |
| __func__, resp_event->vdev_id); |
| wma->interfaces[resp_event->vdev_id].vdev_up = |
| FALSE; |
| } else { |
| wma->interfaces[resp_event->vdev_id].vdev_up = |
| TRUE; |
| } |
| } |
| |
| wma_send_msg(wma, WDA_SWITCH_CHANNEL_RSP, (void *)params, 0); |
| } else if (req_msg->msg_type == WDA_ADD_BSS_REQ) { |
| tpAddBssParams bssParams = (tpAddBssParams) req_msg->user_data; |
| vos_mem_copy(iface->bssid, bssParams->bssId, ETH_ALEN); |
| wma_vdev_start_rsp(wma, bssParams, resp_event); |
| } else if (req_msg->msg_type == WDA_OCB_SET_CONFIG_CMD) { |
| if (wmi_unified_vdev_up_send(wma->wmi_handle, |
| resp_event->vdev_id, iface->aid, |
| iface->bssid) < 0) { |
| WMA_LOGE(FL("failed to send vdev up")); |
| return -EEXIST; |
| } |
| iface->vdev_up = TRUE; |
| |
| wma_ocb_start_resp_ind_cont(wma); |
| } |
| |
| |
| if ((wma->interfaces[resp_event->vdev_id].type == WMI_VDEV_TYPE_AP) && |
| wma->interfaces[resp_event->vdev_id].vdev_up) |
| wma_set_sap_keepalive(wma, resp_event->vdev_id); |
| |
| vos_timer_destroy(&req_msg->event_timeout); |
| adf_os_mem_free(req_msg); |
| |
| return 0; |
| } |
| |
| #define BIG_ENDIAN_MAX_DEBUG_BUF 500 |
| |
| /* function : wma_unified_debug_print_event_handler |
| * Description : |
| * Args : |
| * Returns : |
| */ |
| static int wma_unified_debug_print_event_handler(void *handle, u_int8_t *datap, |
| u_int32_t len) |
| { |
| WMI_DEBUG_PRINT_EVENTID_param_tlvs *param_buf; |
| u_int8_t *data; |
| u_int32_t datalen; |
| |
| param_buf = (WMI_DEBUG_PRINT_EVENTID_param_tlvs *)datap; |
| if (!param_buf) { |
| WMA_LOGE("Get NULL point message from FW"); |
| return -ENOMEM; |
| } |
| data = param_buf->data; |
| datalen = param_buf->num_data; |
| |
| #ifdef BIG_ENDIAN_HOST |
| { |
| 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; |
| } |
| |
| char dbgbuf[BIG_ENDIAN_MAX_DEBUG_BUF] = { 0 }; |
| memcpy(dbgbuf, data, datalen); |
| SWAPME(dbgbuf, datalen); |
| WMA_LOGD("FIRMWARE:%s", dbgbuf); |
| return 0; |
| } |
| #else |
| WMA_LOGD("FIRMWARE:%s", data); |
| return 0; |
| #endif |
| } |
| |
| int wmi_unified_vdev_set_param_send(wmi_unified_t wmi_handle, u_int32_t if_id, |
| u_int32_t param_id, u_int32_t param_value) |
| { |
| int ret; |
| wmi_vdev_set_param_cmd_fixed_param *cmd; |
| wmi_buf_t buf; |
| u_int16_t len = sizeof(*cmd); |
| |
| buf = wmi_buf_alloc(wmi_handle, len); |
| if (!buf) { |
| WMA_LOGE("%s:wmi_buf_alloc failed", __func__); |
| return -ENOMEM; |
| } |
| cmd = (wmi_vdev_set_param_cmd_fixed_param *) wmi_buf_data(buf); |
| WMITLV_SET_HDR(&cmd->tlv_header, |
| WMITLV_TAG_STRUC_wmi_vdev_set_param_cmd_fixed_param, |
| WMITLV_GET_STRUCT_TLVLEN( |
| wmi_vdev_set_param_cmd_fixed_param)); |
| cmd->vdev_id = if_id; |
| cmd->param_id = param_id; |
| cmd->param_value = param_value; |
| WMA_LOGD("Setting vdev %d param = %x, value = %u", |
| if_id, param_id, param_value); |
| ret = wmi_unified_cmd_send(wmi_handle, buf, len, |
| WMI_VDEV_SET_PARAM_CMDID); |
| if (ret < 0) { |
| WMA_LOGE("Failed to send set param command ret = %d", ret); |
| wmi_buf_free(buf); |
| } |
| return ret; |
| } |
| |
| VOS_STATUS wma_roam_scan_bmiss_cnt(tp_wma_handle wma_handle, |
| A_INT32 first_bcnt, |
| A_UINT32 final_bcnt, |
| u_int32_t vdev_id) |
| { |
| int status = 0; |
| |
| WMA_LOGI("%s: first_bcnt=%d, final_bcnt=%d", __func__, |
| first_bcnt, final_bcnt); |
| |
| status = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle, |
| vdev_id, |
| WMI_VDEV_PARAM_BMISS_FIRST_BCNT, |
| first_bcnt); |
| if (status != EOK) { |
| WMA_LOGE("wmi_unified_vdev_set_param_send" |
| "WMI_VDEV_PARAM_BMISS_FIRST_BCNT returned Error %d",status); |
| return VOS_STATUS_E_FAILURE; |
| } |
| |
| status = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle, |
| vdev_id, |
| WMI_VDEV_PARAM_BMISS_FINAL_BCNT, |
| final_bcnt); |
| if (status != EOK) { |
| WMA_LOGE("wmi_unified_vdev_set_param_send" |
| "WMI_VDEV_PARAM_BMISS_FINAL_BCNT returned Error %d",status); |
| return VOS_STATUS_E_FAILURE; |
| } |
| |
| return VOS_STATUS_SUCCESS; |
| } |
| |
| static v_VOID_t wma_set_default_tgt_config(tp_wma_handle wma_handle) |
| { |
| struct ol_softc *scn; |
| u_int8_t no_of_peers_supported; |
| wmi_resource_config tgt_cfg = { |
| 0, /* Filling zero for TLV Tag and Length fields */ |
| CFG_TGT_NUM_VDEV, |
| CFG_TGT_NUM_PEERS + CFG_TGT_NUM_VDEV + 2, |
| CFG_TGT_NUM_OFFLOAD_PEERS, |
| CFG_TGT_NUM_OFFLOAD_REORDER_BUFFS, |
| CFG_TGT_NUM_PEER_KEYS, |
| CFG_TGT_NUM_TIDS, |
| CFG_TGT_AST_SKID_LIMIT, |
| CFG_TGT_DEFAULT_TX_CHAIN_MASK, |
| CFG_TGT_DEFAULT_RX_CHAIN_MASK, |
| { CFG_TGT_RX_TIMEOUT_LO_PRI, CFG_TGT_RX_TIMEOUT_LO_PRI, CFG_TGT_RX_TIMEOUT_LO_PRI, CFG_TGT_RX_TIMEOUT_HI_PRI }, |
| CFG_TGT_RX_DECAP_MODE, |
| CFG_TGT_DEFAULT_SCAN_MAX_REQS, |
| CFG_TGT_DEFAULT_BMISS_OFFLOAD_MAX_VDEV, |
| CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_VDEV, |
| CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_PROFILES, |
| CFG_TGT_DEFAULT_NUM_MCAST_GROUPS, |
| CFG_TGT_DEFAULT_NUM_MCAST_TABLE_ELEMS, |
| CFG_TGT_DEFAULT_MCAST2UCAST_MODE, |
| CFG_TGT_DEFAULT_TX_DBG_LOG_SIZE, |
| CFG_TGT_WDS_ENTRIES, |
| CFG_TGT_DEFAULT_DMA_BURST_SIZE, |
| CFG_TGT_DEFAULT_MAC_AGGR_DELIM, |
| CFG_TGT_DEFAULT_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK, |
| CFG_TGT_DEFAULT_VOW_CONFIG, |
| CFG_TGT_DEFAULT_GTK_OFFLOAD_MAX_VDEV, |
| CFG_TGT_NUM_MSDU_DESC, |
| CFG_TGT_MAX_FRAG_TABLE_ENTRIES, |
| CFG_TGT_NUM_TDLS_VDEVS, |
| CFG_TGT_NUM_TDLS_CONN_TABLE_ENTRIES, |
| CFG_TGT_DEFAULT_BEACON_TX_OFFLOAD_MAX_VDEV, |
| CFG_TGT_MAX_MULTICAST_FILTER_ENTRIES, |
| 0, |
| 0, |
| 0, |
| CFG_TGT_NUM_TDLS_CONC_SLEEP_STAS, |
| CFG_TGT_NUM_TDLS_CONC_BUFFER_STAS, |
| 0, |
| CFG_TGT_NUM_OCB_VDEVS, |
| CFG_TGT_NUM_OCB_CHANNELS, |
| CFG_TGT_NUM_OCB_SCHEDULES, |
| }; |
| |
| /* Update the max number of peers */ |
| scn = vos_get_context(VOS_MODULE_ID_HIF, wma_handle->vos_context); |
| if (!scn) { |
| WMA_LOGE("%s: vos_context is NULL", __func__); |
| return; |
| } |
| no_of_peers_supported = ol_get_number_of_peers_supported(scn); |
| tgt_cfg.num_peers = no_of_peers_supported + CFG_TGT_NUM_VDEV + 2; |
| #if defined(CONFIG_HL_SUPPORT) |
| tgt_cfg.num_tids = 4 * no_of_peers_supported; |
| #else |
| tgt_cfg.num_tids = (2 * (no_of_peers_supported + CFG_TGT_NUM_VDEV + 2)); |
| #endif |
| |
| WMITLV_SET_HDR(&tgt_cfg.tlv_header,WMITLV_TAG_STRUC_wmi_resource_config, |
| WMITLV_GET_STRUCT_TLVLEN(wmi_resource_config)); |
| /* reduce the peer/vdev if CFG_TGT_NUM_MSDU_DESC exceeds 1000 */ |
| #ifdef PERE_IP_HDR_ALIGNMENT_WAR |
| if (scn->host_80211_enable) { |
| /* |
| * To make the IP header begins at dword aligned address, |
| * we make the decapsulation mode as Native Wifi. |
| */ |
| tgt_cfg.rx_decap_mode = CFG_TGT_RX_DECAP_MODE_NWIFI; |
| } |
| #endif |
| if (VOS_MONITOR_MODE == vos_get_conparam()) |
| tgt_cfg.rx_decap_mode = CFG_TGT_RX_DECAP_MODE_RAW; |
| |
| wma_handle->wlan_resource_config = tgt_cfg; |
| } |
| |
| static int32_t wmi_unified_peer_delete_send(wmi_unified_t wmi, |
| u_int8_t peer_addr[IEEE80211_ADDR_LEN], |
| u_int8_t vdev_id) |
| { |
| wmi_peer_delete_cmd_fixed_param *cmd; |
| wmi_buf_t buf; |
| int32_t len = sizeof(*cmd); |
| |
| buf = wmi_buf_alloc(wmi, len); |
| if (!buf) { |
| WMA_LOGP("%s: wmi_buf_alloc failed", __func__); |
| return -ENOMEM; |
| } |
| cmd = (wmi_peer_delete_cmd_fixed_param *) wmi_buf_data(buf); |
| WMITLV_SET_HDR(&cmd->tlv_header, |
| WMITLV_TAG_STRUC_wmi_peer_delete_cmd_fixed_param, |
| WMITLV_GET_STRUCT_TLVLEN( |
| wmi_peer_delete_cmd_fixed_param)); |
| WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr); |
| cmd->vdev_id = vdev_id; |
| |
| if (wmi_unified_cmd_send(wmi, buf, len, WMI_PEER_DELETE_CMDID)) { |
| WMA_LOGP("%s: Failed to send peer delete command", __func__); |
| wmi_buf_free(buf); |
| return -EIO; |
| } |
| WMA_LOGD("%s: peer_addr %pM vdev_id %d", __func__, peer_addr, vdev_id); |
| return 0; |
| } |
| |
| static int32_t wmi_unified_peer_flush_tids_send(wmi_unified_t wmi, |
| u_int8_t peer_addr |
| [IEEE80211_ADDR_LEN], |
| u_int32_t peer_tid_bitmap, |
| u_int8_t vdev_id) |
| { |
| wmi_peer_flush_tids_cmd_fixed_param *cmd; |
| wmi_buf_t buf; |
| int32_t len = sizeof(*cmd); |
| |
| buf = wmi_buf_alloc(wmi, len); |
| if (!buf) { |
| WMA_LOGP("%s: wmi_buf_alloc failed", __func__); |
| return -ENOMEM; |
| } |
| cmd = (wmi_peer_flush_tids_cmd_fixed_param *) wmi_buf_data(buf); |
| WMITLV_SET_HDR(&cmd->tlv_header, |
| WMITLV_TAG_STRUC_wmi_peer_flush_tids_cmd_fixed_param, |
| WMITLV_GET_STRUCT_TLVLEN( |
| wmi_peer_flush_tids_cmd_fixed_param)); |
| WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr); |
| cmd->peer_tid_bitmap = peer_tid_bitmap; |
| cmd->vdev_id = vdev_id; |
| |
| if (wmi_unified_cmd_send(wmi, buf, len, WMI_PEER_FLUSH_TIDS_CMDID)) { |
| WMA_LOGP("%s: Failed to send flush tid command", __func__); |
| wmi_buf_free(buf); |
| return -EIO; |
| } |
| WMA_LOGD("%s: peer_addr %pM vdev_id %d", __func__, peer_addr, vdev_id); |
| return 0; |
| } |
| |
| void wma_remove_peer(tp_wma_handle wma, u_int8_t *bssid, |
| u_int8_t vdev_id, ol_txrx_peer_handle peer, |
| v_BOOL_t roam_synch_in_progress) |
| { |
| #define PEER_ALL_TID_BITMASK 0xffffffff |
| u_int32_t peer_tid_bitmap = PEER_ALL_TID_BITMASK; |
| u_int8_t *peer_addr = bssid; |
| if (!wma->interfaces[vdev_id].peer_count) |
| { |
| WMA_LOGE("%s: Can't remove peer with peer_addr %pM vdevid %d peer_count %d", |
| __func__, bssid, vdev_id, wma->interfaces[vdev_id].peer_count); |
| return; |
| } |
| |
| #ifdef WLAN_FEATURE_ROAM_OFFLOAD |
| if (roam_synch_in_progress) { |
| WMA_LOGE("%s:LFR3:Removing peer with addr %pM vdevid %d peer_cnt %d", |
| __func__, bssid, vdev_id, wma->interfaces[vdev_id].peer_count); |
| goto peer_detach; |
| } else { |
| WMA_LOGI("%s: Removing peer with addr %pM vdevid %d peer_count %d", |
| __func__, bssid, vdev_id, wma->interfaces[vdev_id].peer_count); |
| } |
| #endif |
| /* Flush all TIDs except MGMT TID for this peer in Target */ |
| peer_tid_bitmap &= ~(0x1 << WMI_MGMT_TID); |
| wmi_unified_peer_flush_tids_send(wma->wmi_handle, bssid, |
| peer_tid_bitmap, vdev_id); |
| |
| #if defined(QCA_IBSS_SUPPORT) |
| if ((peer) && (wma_is_vdev_in_ibss_mode(wma, vdev_id))) { |
| WMA_LOGD("%s: bssid %pM peer->mac_addr %pM", __func__, |
| bssid, peer->mac_addr.raw); |
| peer_addr = peer->mac_addr.raw; |
| } |
| #endif |
| |
| wmi_unified_peer_delete_send(wma->wmi_handle, peer_addr, vdev_id); |
| |
| #ifdef WLAN_FEATURE_ROAM_OFFLOAD |
| peer_detach: |
| #endif |
| if (peer) |
| ol_txrx_peer_detach(peer); |
| wma->interfaces[vdev_id].peer_count--; |
| |
| #undef PEER_ALL_TID_BITMASK |
| } |
| |
| static int wma_peer_sta_kickout_event_handler(void *handle, u8 *event, u32 len) |
| { |
| tp_wma_handle wma = (tp_wma_handle)handle; |
| WMI_PEER_STA_KICKOUT_EVENTID_param_tlvs *param_buf = NULL; |
| wmi_peer_sta_kickout_event_fixed_param *kickout_event = NULL; |
| u_int8_t vdev_id, peer_id, macaddr[IEEE80211_ADDR_LEN]; |
| ol_txrx_peer_handle peer; |
| ol_txrx_pdev_handle pdev; |
| tpDeleteStaContext del_sta_ctx; |
| tpSirIbssPeerInactivityInd p_inactivity; |
| |
| WMA_LOGD("%s: Enter", __func__); |
| param_buf = (WMI_PEER_STA_KICKOUT_EVENTID_param_tlvs *) event; |
| kickout_event = param_buf->fixed_param; |
| pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context); |
| if (!pdev) { |
| WMA_LOGE("%s: pdev is NULL", __func__); |
| return -EINVAL; |
| } |
| WMI_MAC_ADDR_TO_CHAR_ARRAY(&kickout_event->peer_macaddr, macaddr); |
| peer = ol_txrx_find_peer_by_addr(pdev, macaddr, &peer_id); |
| if (!peer) { |
| WMA_LOGE("PEER [%pM] not found", macaddr); |
| return -EINVAL; |
| } |
| |
| if (tl_shim_get_vdevid(peer, &vdev_id) != VOS_STATUS_SUCCESS) { |
| WMA_LOGE("Not able to find BSSID for peer [%pM]", macaddr); |
| return -EINVAL; |
| } |
| |
| WMA_LOGA("%s: PEER:[%pM], ADDR:[%pN], INTERFACE:%d, peer_id:%d, reason:%d", |
| __func__, macaddr, |
| wma->interfaces[vdev_id].addr, vdev_id, |
| peer_id, kickout_event->reason); |
| |
| switch (kickout_event->reason) { |
| case WMI_PEER_STA_KICKOUT_REASON_IBSS_DISCONNECT: |
| p_inactivity = (tpSirIbssPeerInactivityInd) |
| vos_mem_malloc(sizeof(tSirIbssPeerInactivityInd)); |
| if (!p_inactivity) { |
| WMA_LOGE("VOS MEM Alloc Failed for tSirIbssPeerInactivity"); |
| return -EINVAL; |
| } |
| |
| p_inactivity->staIdx = peer_id; |
| vos_mem_copy(p_inactivity->peerAddr, macaddr, IEEE80211_ADDR_LEN); |
| wma_send_msg(wma, WDA_IBSS_PEER_INACTIVITY_IND, (void *)p_inactivity, 0); |
| goto exit_handler; |
| break; |
| |
| #ifdef FEATURE_WLAN_TDLS |
| case WMI_PEER_STA_KICKOUT_REASON_TDLS_DISCONNECT: |
| del_sta_ctx = |
| (tpDeleteStaContext)vos_mem_malloc(sizeof(tDeleteStaContext)); |
| if (!del_sta_ctx) { |
| WMA_LOGE("%s: mem alloc failed for tDeleteStaContext for TDLS peer: %pM", |
| __func__, macaddr); |
| return -EINVAL; |
| } |
| |
| del_sta_ctx->is_tdls = true; |
| del_sta_ctx->vdev_id = vdev_id; |
| del_sta_ctx->staId = peer_id; |
| vos_mem_copy(del_sta_ctx->addr2, macaddr, IEEE80211_ADDR_LEN); |
| vos_mem_copy(del_sta_ctx->bssId, wma->interfaces[vdev_id].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); |
| goto exit_handler; |
| break; |
| #endif /* FEATURE_WLAN_TDLS */ |
| |
| case WMI_PEER_STA_KICKOUT_REASON_XRETRY: |
| if(wma->interfaces[vdev_id].type == WMI_VDEV_TYPE_STA && |
| (wma->interfaces[vdev_id].sub_type == 0 || |
| wma->interfaces[vdev_id].sub_type == |
| WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT) && |
| vos_mem_compare(wma->interfaces[vdev_id].bssid, |
| macaddr, ETH_ALEN)) { |
| /* |
| * KICKOUT event is for current station-AP connection. |
| * Treat it like final beacon miss. Station may not have |
| * missed beacons but not able to transmit frames to AP |
| * for a long time. Must disconnect to get out of |
| * this sticky situation. |
| * In future implementation, roaming module will also |
| * handle this event and perform a scan. |
| */ |
| WMA_LOGW("%s: WMI_PEER_STA_KICKOUT_REASON_XRETRY event for STA", |
| __func__); |
| wma_beacon_miss_handler(wma, vdev_id, kickout_event->rssi); |
| goto exit_handler; |
| } |
| break; |
| |
| case WMI_PEER_STA_KICKOUT_REASON_UNSPECIFIED: |
| /* |
| * Default legacy value used by original firmware implementation. |
| */ |
| if(wma->interfaces[vdev_id].type == WMI_VDEV_TYPE_STA && |
| (wma->interfaces[vdev_id].sub_type == 0 || |
| wma->interfaces[vdev_id].sub_type == |
| WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT) && |
| vos_mem_compare(wma->interfaces[vdev_id].bssid, |
| macaddr, ETH_ALEN)) { |
| /* |
| * KICKOUT event is for current station-AP connection. |
| * Treat it like final beacon miss. Station may not have |
| * missed beacons but not able to transmit frames to AP |
| * for a long time. Must disconnect to get out of |
| * this sticky situation. |
| * In future implementation, roaming module will also |
| * handle this event and perform a scan. |
| */ |
| WMA_LOGW("%s: WMI_PEER_STA_KICKOUT_REASON_UNSPECIFIED event for STA", |
| __func__); |
| wma_beacon_miss_handler(wma, vdev_id, kickout_event->rssi); |
| goto exit_handler; |
| } |
| break; |
| |
| case WMI_PEER_STA_KICKOUT_REASON_INACTIVITY: |
| /* This could be for STA or SAP role */ |
| default: |
| break; |
| } |
| |
| /* |
| * default action is to send delete station context indication to LIM |
| */ |
| del_sta_ctx = (tpDeleteStaContext)vos_mem_malloc(sizeof(tDeleteStaContext)); |
| if (!del_sta_ctx) { |
| WMA_LOGE("VOS MEM Alloc Failed for tDeleteStaContext"); |
| return -EINVAL; |
| } |
| |
| del_sta_ctx->is_tdls = false; |
| del_sta_ctx->vdev_id = vdev_id; |
| del_sta_ctx->staId = peer_id; |
| vos_mem_copy(del_sta_ctx->addr2, macaddr, IEEE80211_ADDR_LEN); |
| vos_mem_copy(del_sta_ctx->bssId, wma->interfaces[vdev_id].addr, |
| IEEE80211_ADDR_LEN); |
| del_sta_ctx->reasonCode = HAL_DEL_STA_REASON_CODE_KEEP_ALIVE; |
| del_sta_ctx->rssi = kickout_event->rssi + WMA_TGT_NOISE_FLOOR_DBM; |
| wma_send_msg(wma, SIR_LIM_DELETE_STA_CONTEXT_IND, (void *)del_sta_ctx, 0); |
| wma_lost_link_info_handler(wma, vdev_id, kickout_event->rssi + |
| WMA_TGT_NOISE_FLOOR_DBM); |
| |
| exit_handler: |
| WMA_LOGD("%s: Exit", __func__); |
| return 0; |
| } |
| |
| static int wmi_unified_vdev_down_send(wmi_unified_t wmi, u_int8_t vdev_id) |
| { |
| wmi_vdev_down_cmd_fixed_param *cmd; |
| wmi_buf_t buf; |
| int32_t len = sizeof(*cmd); |
| |
| buf = wmi_buf_alloc(wmi, len); |
| if (!buf) { |
| WMA_LOGP("%s : wmi_buf_alloc failed", __func__); |
| return -ENOMEM; |
| } |
| cmd = (wmi_vdev_down_cmd_fixed_param *) wmi_buf_data(buf); |
| WMITLV_SET_HDR(&cmd->tlv_header, |
| WMITLV_TAG_STRUC_wmi_vdev_down_cmd_fixed_param, |
| WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_down_cmd_fixed_param)); |
| cmd->vdev_id = vdev_id; |
| if (wmi_unified_cmd_send(wmi, buf, len, WMI_VDEV_DOWN_CMDID)) { |
| WMA_LOGP("%s: Failed to send vdev down", __func__); |
| wmi_buf_free(buf); |
| return -EIO; |
| } |
| WMA_LOGD("%s: vdev_id %d", __func__, vdev_id); |
| return 0; |
| } |
| |
| #ifdef QCA_IBSS_SUPPORT |
| static void wma_delete_all_ibss_peers(tp_wma_handle wma, A_UINT32 vdev_id) |
| { |
| ol_txrx_vdev_handle vdev; |
| ol_txrx_peer_handle peer, temp; |
| |
| if (!wma || vdev_id >= wma->max_bssid) |
| return; |
| |
| vdev = wma->interfaces[vdev_id].handle; |
| if (!vdev) |
| return; |
| |
| /* remove all remote peers of IBSS */ |
| adf_os_spin_lock_bh(&vdev->pdev->peer_ref_mutex); |
| |
| temp = NULL; |
| TAILQ_FOREACH_REVERSE(peer, &vdev->peer_list, peer_list_t, peer_list_elem) { |
| if (temp) { |
| adf_os_spin_unlock_bh(&vdev->pdev->peer_ref_mutex); |
| if (adf_os_atomic_read(&temp->delete_in_progress) == 0){ |
| wma_remove_peer(wma, temp->mac_addr.raw, |
| vdev_id, temp, VOS_FALSE); |
| } |
| adf_os_spin_lock_bh(&vdev->pdev->peer_ref_mutex); |
| } |
| /* self peer is deleted last */ |
| if (peer == TAILQ_FIRST(&vdev->peer_list)) { |
| WMA_LOGE("%s: self peer removed by caller ", __func__); |
| break; |
| } else |
| temp = peer; |
| } |
| adf_os_spin_unlock_bh(&vdev->pdev->peer_ref_mutex); |
| |
| /* remove IBSS bss peer last */ |
| peer = TAILQ_FIRST(&vdev->peer_list); |
| wma_remove_peer(wma, wma->interfaces[vdev_id].bssid, vdev_id, peer, |
| VOS_FALSE); |
| |
| } |
| #endif //#ifdef QCA_IBSS_SUPPORT |
| |
| static void wma_delete_all_ap_remote_peers(tp_wma_handle wma, A_UINT32 vdev_id) |
| { |
| ol_txrx_vdev_handle vdev; |
| ol_txrx_peer_handle peer, temp; |
| |
| if (!wma || vdev_id >= wma->max_bssid) |
| return; |
| |
| vdev = wma->interfaces[vdev_id].handle; |
| if (!vdev) |
| return; |
| |
| WMA_LOGE("%s: vdev_id - %d", __func__, vdev_id); |
| /* remove all remote peers of SAP */ |
| adf_os_spin_lock_bh(&vdev->pdev->peer_ref_mutex); |
| |
| temp = NULL; |
| TAILQ_FOREACH_REVERSE(peer, &vdev->peer_list, peer_list_t, peer_list_elem) { |
| if (temp) { |
| adf_os_spin_unlock_bh(&vdev->pdev->peer_ref_mutex); |
| if (adf_os_atomic_read(&temp->delete_in_progress) == 0){ |
| wma_remove_peer(wma, temp->mac_addr.raw, |
| vdev_id, temp, VOS_FALSE); |
| } |
| adf_os_spin_lock_bh(&vdev->pdev->peer_ref_mutex); |
| } |
| /* self peer is deleted by caller */ |
| if (peer == TAILQ_FIRST(&vdev->peer_list)){ |
| WMA_LOGE("%s: self peer removed by caller ", __func__); |
| break; |
| } else |
| temp = peer; |
| } |
| |
| adf_os_spin_unlock_bh(&vdev->pdev->peer_ref_mutex); |
| } |
| |
| static int wma_vdev_stop_resp_handler(void *handle, u_int8_t *cmd_param_info, |
| u32 len) |
| { |
| WMI_VDEV_STOPPED_EVENTID_param_tlvs *param_buf; |
| wmi_vdev_stopped_event_fixed_param *event; |
| u_int8_t *buf; |
| vos_msg_t vos_msg = {0}; |
| |
| WMA_LOGI("%s: Enter", __func__); |
| param_buf = (WMI_VDEV_STOPPED_EVENTID_param_tlvs *) cmd_param_info; |
| if (!param_buf) { |
| WMA_LOGE("Invalid event buffer"); |
| return -EINVAL; |
| } |
| event = param_buf->fixed_param; |
| buf = vos_mem_malloc(sizeof(wmi_vdev_stopped_event_fixed_param)); |
| if (!buf) { |
| WMA_LOGE("%s: Failed alloc memory for buf", __func__); |
| return -EINVAL; |
| } |
| vos_mem_zero(buf, sizeof(wmi_vdev_stopped_event_fixed_param)); |
| vos_mem_copy(buf, (u_int8_t *)event, |
| sizeof(wmi_vdev_stopped_event_fixed_param)); |
| |
| vos_msg.type = WDA_VDEV_STOP_IND; |
| vos_msg.bodyptr = buf; |
| vos_msg.bodyval = 0; |
| |
| if (VOS_STATUS_SUCCESS != |
| vos_mq_post_message(VOS_MQ_ID_WDA, &vos_msg)) { |
| WMA_LOGP("%s: Failed to post WDA_VDEV_STOP_IND msg", __func__); |
| vos_mem_free(buf); |
| return -1; |
| } |
| WMA_LOGD("WDA_VDEV_STOP_IND posted"); |
| return 0; |
| } |
| |
| void wma_hidden_ssid_vdev_restart_on_vdev_stop(tp_wma_handle wma_handle, u_int8_t sessionId) |
| { |
| wmi_vdev_start_request_cmd_fixed_param *cmd; |
| wmi_buf_t buf; |
| wmi_channel *chan; |
| int32_t len; |
| u_int8_t *buf_ptr; |
| struct wma_txrx_node *intr = wma_handle->interfaces; |
| int32_t ret=0; |
| WLAN_PHY_MODE chanmode; |
| tpAniSirGlobal mac_ctx = (tpAniSirGlobal)vos_get_context( |
| VOS_MODULE_ID_PE, wma_handle->vos_context); |
| |
| if (!mac_ctx) { |
| WMA_LOGE("%s: Failed to get mac_ctx", __func__); |
| return; |
| } |
| len = sizeof(*cmd) + sizeof(wmi_channel) + |
| WMI_TLV_HDR_SIZE; |
| buf = wmi_buf_alloc(wma_handle->wmi_handle, len); |
| if (!buf) { |
| WMA_LOGE("%s : wmi_buf_alloc failed", __func__); |
| adf_os_atomic_set(&intr[sessionId].vdev_restart_params.hidden_ssid_restart_in_progress,0); |
| return; |
| } |
| buf_ptr = (u_int8_t *) wmi_buf_data(buf); |
| cmd = (wmi_vdev_start_request_cmd_fixed_param *) buf_ptr; |
| chan = (wmi_channel *) (buf_ptr + sizeof(*cmd)); |
| |
| WMITLV_SET_HDR(&cmd->tlv_header, |
| WMITLV_TAG_STRUC_wmi_vdev_start_request_cmd_fixed_param, |
| WMITLV_GET_STRUCT_TLVLEN( |
| wmi_vdev_start_request_cmd_fixed_param)); |
| |
| WMITLV_SET_HDR(&chan->tlv_header, |
| WMITLV_TAG_STRUC_wmi_channel, |
| WMITLV_GET_STRUCT_TLVLEN(wmi_channel)); |
| |
| cmd->vdev_id = sessionId; |
| cmd->ssid.ssid_len = intr[sessionId].vdev_restart_params.ssid.ssid_len; |
| vos_mem_copy(cmd->ssid.ssid, |
| intr[sessionId].vdev_restart_params.ssid.ssid, |
| cmd->ssid.ssid_len); |
| cmd->flags = intr[sessionId].vdev_restart_params.flags; |
| if (intr[sessionId].vdev_restart_params.ssidHidden) |
| cmd->flags |= WMI_UNIFIED_VDEV_START_HIDDEN_SSID; |
| else |
| cmd->flags &= (0xFFFFFFFE); |
| cmd->requestor_id = intr[sessionId].vdev_restart_params.requestor_id; |
| cmd->disable_hw_ack = intr[sessionId].vdev_restart_params.disable_hw_ack; |
| |
| chan->mhz = intr[sessionId].vdev_restart_params.chan.mhz; |
| chan->band_center_freq1 = intr[sessionId].vdev_restart_params.chan.band_center_freq1; |
| chan->band_center_freq2 = intr[sessionId].vdev_restart_params.chan.band_center_freq2; |
| chan->info = intr[sessionId].vdev_restart_params.chan.info; |
| chan->reg_info_1 = intr[sessionId].vdev_restart_params.chan.reg_info_1; |
| chan->reg_info_2 = intr[sessionId].vdev_restart_params.chan.reg_info_2; |
| if (chan->band_center_freq1 == 0) { |
| chan->band_center_freq1 = chan->mhz; |
| chanmode = intr[sessionId].chanmode; |
| if (chanmode == MODE_11AC_VHT80) |
| chan->band_center_freq1 = vos_chan_to_freq( |
| wma_getCenterChannel( |
| chan->mhz, |
| mac_ctx->roam.configParam.channelBondingMode5GHz)); |
| |
| if ((chanmode == MODE_11NA_HT40) || |
| (chanmode == MODE_11AC_VHT40)) { |
| if (mac_ctx->roam.configParam.channelBondingMode5GHz == |
| PHY_DOUBLE_CHANNEL_LOW_PRIMARY) |
| chan->band_center_freq1 += 10; |
| else |
| chan->band_center_freq1 -= 10; |
| } |
| |
| if ((chanmode == MODE_11NG_HT40) || |
| (chanmode == MODE_11AC_VHT40_2G)) { |
| if (mac_ctx->roam.configParam.channelBondingMode24GHz == |
| PHY_DOUBLE_CHANNEL_LOW_PRIMARY) |
| chan->band_center_freq1 += 10; |
| else |
| chan->band_center_freq1 -= 10; |
| } |
| } |
| |
| cmd->num_noa_descriptors = 0; |
| buf_ptr = (u_int8_t *)(((u_int8_t *) cmd) + sizeof(*cmd) + |
| sizeof(wmi_channel)); |
| WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, |
| cmd->num_noa_descriptors * |
| sizeof(wmi_p2p_noa_descriptor)); |
| |
| ret = wmi_unified_cmd_send(wma_handle->wmi_handle,buf,len, |
| WMI_VDEV_RESTART_REQUEST_CMDID); |
| if (ret < 0) { |
| WMA_LOGE("%s: Failed to send vdev restart command", __func__); |
| adf_os_atomic_set(&intr[sessionId].vdev_restart_params.hidden_ssid_restart_in_progress,0); |
| wmi_buf_free(buf); |
| } |
| } |
| |
| static int wma_vdev_stop_ind(tp_wma_handle wma, u_int8_t *buf) |
| { |
| wmi_vdev_stopped_event_fixed_param *resp_event; |
| struct wma_target_req *req_msg; |
| ol_txrx_peer_handle peer; |
| ol_txrx_pdev_handle pdev; |
| u_int8_t peer_id; |
| struct wma_txrx_node *iface; |
| int32_t status = 0; |
| #ifdef FEATURE_AP_MCC_CH_AVOIDANCE |
| tpAniSirGlobal mac_ctx = (tpAniSirGlobal)vos_get_context( |
| VOS_MODULE_ID_PE, |
| wma->vos_context); |
| if (NULL == mac_ctx) { |
| WMA_LOGE("%s: Failed to get mac_ctx", __func__); |
| return -EINVAL; |
| } |
| #endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ |
| |
| WMA_LOGI("%s: Enter", __func__); |
| if (!buf) { |
| WMA_LOGE("Invalid event buffer"); |
| return -EINVAL; |
| } |
| |
| resp_event = (wmi_vdev_stopped_event_fixed_param *)buf; |
| |
| if ((resp_event->vdev_id < wma->max_bssid) && |
| (adf_os_atomic_read(&wma->interfaces[resp_event->vdev_id].vdev_restart_params.hidden_ssid_restart_in_progress)) && |
| ((wma->interfaces[resp_event->vdev_id].type == WMI_VDEV_TYPE_AP) && |
| (wma->interfaces[resp_event->vdev_id].sub_type == 0))) { |
| WMA_LOGE("%s: vdev stop event recevied for hidden ssid set using IOCTL ", __func__); |
| |
| req_msg = wma_fill_vdev_req(wma, resp_event->vdev_id, |
| WDA_HIDDEN_SSID_VDEV_RESTART, |
| WMA_TARGET_REQ_TYPE_VDEV_START, resp_event, |
| WMA_VDEV_START_REQUEST_TIMEOUT); |
| if (!req_msg) { |
| WMA_LOGE("%s: Failed to fill vdev request, vdev_id %d", |
| __func__, resp_event->vdev_id); |
| return -EINVAL; |
| } |
| |
| wma_hidden_ssid_vdev_restart_on_vdev_stop(wma, resp_event->vdev_id); |
| } |
| |
| req_msg = wma_find_vdev_req(wma, resp_event->vdev_id, |
| WMA_TARGET_REQ_TYPE_VDEV_STOP); |
| if (!req_msg) { |
| WMA_LOGP("%s: Failed to lookup vdev request for vdev id %d", |
| __func__, resp_event->vdev_id); |
| return -EINVAL; |
| } |
| pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context); |
| if (!pdev) { |
| WMA_LOGE("%s: pdev is NULL", __func__); |
| status = -EINVAL; |
| vos_timer_stop(&req_msg->event_timeout); |
| goto free_req_msg; |
| } |
| |
| vos_timer_stop(&req_msg->event_timeout); |
| if (req_msg->msg_type == WDA_DELETE_BSS_REQ) { |
| tpDeleteBssParams params = |
| (tpDeleteBssParams)req_msg->user_data; |
| struct beacon_info *bcn; |
| if (resp_event->vdev_id >= wma->max_bssid) { |
| WMA_LOGE("%s: Invalid vdev_id %d", __func__, |
| resp_event->vdev_id); |
| vos_mem_free(params); |
| status = -EINVAL; |
| goto free_req_msg; |
| } |
| |
| iface = &wma->interfaces[resp_event->vdev_id]; |
| if (iface->handle == NULL) { |
| WMA_LOGE("%s vdev id %d is already deleted", |
| __func__, resp_event->vdev_id); |
| vos_mem_free(params); |
| status = -EINVAL; |
| goto free_req_msg; |
| } |
| |
| /* Clear arp and ns offload cache */ |
| vos_mem_zero(&iface->ns_offload_req, |
| sizeof(iface->ns_offload_req)); |
| vos_mem_zero(&iface->arp_offload_req, |
| sizeof(iface->arp_offload_req)); |
| |
| #ifdef QCA_IBSS_SUPPORT |
| if ( wma_is_vdev_in_ibss_mode(wma, resp_event->vdev_id)) |
| wma_delete_all_ibss_peers(wma, resp_event->vdev_id); |
| else |
| #endif |
| if (WMA_IS_VDEV_IN_NDI_MODE(wma->interfaces, |
| resp_event->vdev_id)) { |
| wma_delete_all_nan_remote_peers(wma, |
| resp_event->vdev_id); |
| } else { |
| if (wma_is_vdev_in_ap_mode(wma, resp_event->vdev_id)) |
| { |
| wma_delete_all_ap_remote_peers(wma, resp_event->vdev_id); |
| } |
| peer = ol_txrx_find_peer_by_addr(pdev, params->bssid, |
| &peer_id); |
| if (!peer) |
| WMA_LOGD("%s Failed to find peer %pM", |
| __func__, params->bssid); |
| wma_remove_peer(wma, params->bssid, resp_event->vdev_id, |
| peer, VOS_FALSE); |
| } |
| |
| if (wmi_unified_vdev_down_send(wma->wmi_handle, resp_event->vdev_id) < 0) { |
| WMA_LOGE("Failed to send vdev down cmd: vdev %d", |
| resp_event->vdev_id); |
| } else { |
| wma->interfaces[resp_event->vdev_id].vdev_up = FALSE; |
| #ifdef FEATURE_AP_MCC_CH_AVOIDANCE |
| if (mac_ctx->sap.sap_channel_avoidance) |
| wma_find_mcc_ap(wma, |
| resp_event->vdev_id, |
| false); |
| #endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ |
| } |
| ol_txrx_vdev_flush(iface->handle); |
| WMA_LOGD("%s, vdev_id: %d, un-pausing tx_ll_queue for VDEV_STOP rsp", |
| __func__, resp_event->vdev_id); |
| wdi_in_vdev_unpause(iface->handle, |
| OL_TXQ_PAUSE_REASON_VDEV_STOP); |
| iface->pause_bitmap &= ~(1 << PAUSE_TYPE_HOST); |
| adf_os_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STOPPED); |
| WMA_LOGD("%s: (type %d subtype %d) BSS is stopped", |
| __func__, iface->type, iface->sub_type); |
| bcn = wma->interfaces[resp_event->vdev_id].beacon; |
| |
| if (bcn) { |
| WMA_LOGD("%s: Freeing beacon struct %pK, " |
| "template memory %pK", __func__, |
| bcn, bcn->buf); |
| if (bcn->dma_mapped) |
| adf_nbuf_unmap_single(pdev->osdev, bcn->buf, |
| ADF_OS_DMA_TO_DEVICE); |
| adf_nbuf_free(bcn->buf); |
| vos_mem_free(bcn); |
| wma->interfaces[resp_event->vdev_id].beacon = NULL; |
| } |
| |
| /* Timeout status means its WMA generated DEL BSS REQ when ADD |
| BSS REQ was timed out to stop the VDEV in this case no need to |
| send response to UMAC */ |
| if (params->status == eHAL_STATUS_FW_MSG_TIMEDOUT){ |
| vos_mem_free(params); |
| WMA_LOGE("%s: DEL BSS from ADD BSS timeout do not send " |
| "resp to UMAC (vdev id %x)", |
| __func__, resp_event->vdev_id); |
| } else { |
| params->status = VOS_STATUS_SUCCESS; |
| wma_send_msg(wma, WDA_DELETE_BSS_RSP, (void *)params, 0); |
| } |
| |
| if (iface->del_staself_req) { |
| WMA_LOGA("scheduling defered deletion (vdev id %x)", |
| resp_event->vdev_id); |
| wma_vdev_detach(wma, iface->del_staself_req, 1); |
| } |
| } |
| free_req_msg: |
| vos_timer_destroy(&req_msg->event_timeout); |
| adf_os_mem_free(req_msg); |
| return status; |
| } |
| |
| #ifdef WLAN_FEATURE_EXTWOW_SUPPORT |
| static void wma_send_status_of_ext_wow(tp_wma_handle wma, boolean status) |
| { |
| tSirReadyToExtWoWInd *ready_to_extwow; |
| VOS_STATUS vstatus; |
| vos_msg_t vos_msg; |
| u_int8_t len; |
| |
| WMA_LOGD("Posting ready to suspend indication to umac"); |
| |
| len = sizeof(tSirReadyToExtWoWInd); |
| ready_to_extwow = (tSirReadyToExtWoWInd *) vos_mem_malloc(len); |
| |
| if (NULL == ready_to_extwow) { |
| WMA_LOGE("%s: Memory allocation failure", __func__); |
| return; |
| } |
| |
| ready_to_extwow->mesgType = eWNI_SME_READY_TO_EXTWOW_IND; |
| ready_to_extwow->mesgLen = len; |
| ready_to_extwow->status= status; |
| |
| vos_msg.type = eWNI_SME_READY_TO_EXTWOW_IND; |
| vos_msg.bodyptr = (void *) ready_to_extwow; |
| vos_msg.bodyval = 0; |
| |
| vstatus = vos_mq_post_message(VOS_MQ_ID_SME, &vos_msg); |
| if (vstatus != VOS_STATUS_SUCCESS) { |
| WMA_LOGE("Failed to post ready to suspend"); |
| vos_mem_free(ready_to_extwow); |
| } |
| } |
| |
| static int wma_enable_ext_wow(tp_wma_handle wma, |
| tpSirExtWoWParams params) |
| { |
| wmi_extwow_enable_cmd_fixed_param *cmd; |
| wmi_buf_t buf; |
| int32_t len; |
| int ret; |
| |
| len = sizeof(wmi_extwow_enable_cmd_fixed_param); |
| buf = wmi_buf_alloc(wma->wmi_handle, len); |
| if (!buf) { |
| WMA_LOGE("%s: Failed allocate wmi buffer", __func__); |
| return VOS_STATUS_E_NOMEM; |
| } |
| |
| cmd = (wmi_extwow_enable_cmd_fixed_param *) wmi_buf_data(buf); |
| |
| WMITLV_SET_HDR(&cmd->tlv_header, |
| WMITLV_TAG_STRUC_wmi_extwow_enable_cmd_fixed_param, |
| WMITLV_GET_STRUCT_TLVLEN( |
| wmi_extwow_enable_cmd_fixed_param)); |
| |
| cmd->vdev_id = params->vdev_id; |
| cmd->type = params->type; |
| cmd->wakeup_pin_num = params->wakeup_pin_num; |
| |
| WMA_LOGD("%s: vdev_id %d type %d Wakeup_pin_num %x", |
| __func__, cmd->vdev_id, |
| cmd->type, cmd->wakeup_pin_num); |
| |
| ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, |
| WMI_EXTWOW_ENABLE_CMDID); |
| if (ret) { |
| WMA_LOGE("%s: Failed to set EXTWOW Enable", __func__); |
| wmi_buf_free(buf); |
| wma_send_status_of_ext_wow(wma, FALSE); |
| return VOS_STATUS_E_FAILURE; |
| } |
| |
| wma_send_status_of_ext_wow(wma, TRUE); |
| return VOS_STATUS_SUCCESS; |
| |
| } |
| |
| static int wma_set_app_type1_params_in_fw(tp_wma_handle wma, |
| tpSirAppType1Params appType1Params) |
| { |
| wmi_extwow_set_app_type1_params_cmd_fixed_param *cmd; |
| wmi_buf_t buf; |
| int32_t len; |
| int ret; |
| |
| len = sizeof(wmi_extwow_set_app_type1_params_cmd_fixed_param); |
| buf = wmi_buf_alloc(wma->wmi_handle, len); |
| if (!buf) { |
| WMA_LOGE("%s: Failed allocate wmi buffer", __func__); |
| return VOS_STATUS_E_NOMEM; |
| } |
| |
| cmd = (wmi_extwow_set_app_type1_params_cmd_fixed_param *) |
| wmi_buf_data(buf); |
| |
| WMITLV_SET_HDR(&cmd->tlv_header, |
| WMITLV_TAG_STRUC_wmi_extwow_set_app_type1_params_cmd_fixed_param, |
| WMITLV_GET_STRUCT_TLVLEN( |
| wmi_extwow_set_app_type1_params_cmd_fixed_param)); |
| |
| cmd->vdev_id = appType1Params->vdev_id; |
| WMI_CHAR_ARRAY_TO_MAC_ADDR(appType1Params->wakee_mac_addr, |
| &cmd->wakee_mac); |
| vos_mem_copy(cmd->ident, appType1Params->identification_id, 8); |
| cmd->ident_len = appType1Params->id_length; |
| vos_mem_copy(cmd->passwd, appType1Params->password, 16); |
| cmd->passwd_len = appType1Params->pass_length; |
| |
| WMA_LOGD("%s: vdev_id %d wakee_mac_addr %pM " |
| "identification_id %.8s id_length %u " |
| "password %.16s pass_length %u", |
| __func__, cmd->vdev_id, appType1Params->wakee_mac_addr, |
| cmd->ident, cmd->ident_len, |
| cmd->passwd, cmd->passwd_len); |
| |
| ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, |
| WMI_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID); |
| if (ret) { |
| WMA_LOGE("%s: Failed to set APP TYPE1 PARAMS", __func__); |
| wmi_buf_free(buf); |
| return VOS_STATUS_E_FAILURE; |
| } |
| |
| return VOS_STATUS_SUCCESS; |
| } |
| |
| static int wma_set_app_type2_params_in_fw(tp_wma_handle wma, |
| tpSirAppType2Params appType2Params) |
| { |
| wmi_extwow_set_app_type2_params_cmd_fixed_param *cmd; |
| wmi_buf_t buf; |
| int32_t len; |
| int ret; |
| |
| len = sizeof(wmi_extwow_set_app_type2_params_cmd_fixed_param); |
| buf = wmi_buf_alloc(wma->wmi_handle, len); |
| if (!buf) { |
| WMA_LOGE("%s: Failed allocate wmi buffer", __func__); |
| return VOS_STATUS_E_NOMEM; |
| } |
| |
| cmd = (wmi_extwow_set_app_type2_params_cmd_fixed_param *) |
| wmi_buf_data(buf); |
| |
| WMITLV_SET_HDR(&cmd->tlv_header, |
| WMITLV_TAG_STRUC_wmi_extwow_set_app_type2_params_cmd_fixed_param, |
| WMITLV_GET_STRUCT_TLVLEN( |
| wmi_extwow_set_app_type2_params_cmd_fixed_param)); |
| |
| cmd->vdev_id = appType2Params->vdev_id; |
| |
| vos_mem_copy(cmd->rc4_key, appType2Params->rc4_key, 16); |
| cmd->rc4_key_len = appType2Params->rc4_key_len; |
| |
| cmd->ip_id = appType2Params->ip_id; |
| cmd->ip_device_ip = appType2Params->ip_device_ip; |
| cmd->ip_server_ip = appType2Params->ip_server_ip; |
| |
| cmd->tcp_src_port = appType2Params->tcp_src_port; |
| cmd->tcp_dst_port = appType2Params->tcp_dst_port; |
| cmd->tcp_seq = appType2Params->tcp_seq; |
| cmd->tcp_ack_seq = appType2Params->tcp_ack_seq; |
| |
| cmd->keepalive_init = appType2Params->keepalive_init; |
| cmd->keepalive_min = appType2Params->keepalive_min; |
| cmd->keepalive_max = appType2Params->keepalive_max; |
| cmd->keepalive_inc = appType2Params->keepalive_inc; |
| |
| WMI_CHAR_ARRAY_TO_MAC_ADDR(appType2Params->gateway_mac, |
| &cmd->gateway_mac); |
| cmd->tcp_tx_timeout_val = appType2Params->tcp_tx_timeout_val; |
| cmd->tcp_rx_timeout_val = appType2Params->tcp_rx_timeout_val; |
| |
| WMA_LOGD("%s: vdev_id %d gateway_mac %pM " |
| "rc4_key %.16s rc4_key_len %u " |
| "ip_id %x ip_device_ip %x ip_server_ip %x " |
| "tcp_src_port %u tcp_dst_port %u tcp_seq %u " |
| "tcp_ack_seq %u keepalive_init %u keepalive_min %u " |
| "keepalive_max %u keepalive_inc %u " |
| "tcp_tx_timeout_val %u tcp_rx_timeout_val %u", |
| __func__, cmd->vdev_id, appType2Params->gateway_mac, |
| cmd->rc4_key, cmd->rc4_key_len, |
| cmd->ip_id, cmd->ip_device_ip, cmd->ip_server_ip, |
| cmd->tcp_src_port, cmd->tcp_dst_port, cmd->tcp_seq, |
| cmd->tcp_ack_seq, cmd->keepalive_init, cmd->keepalive_min, |
| cmd->keepalive_max, cmd->keepalive_inc, |
| cmd->tcp_tx_timeout_val, cmd->tcp_rx_timeout_val); |
| |
| |
| ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, |
| WMI_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID); |
| if (ret) { |
| WMA_LOGE("%s: Failed to set APP TYPE2 PARAMS", __func__); |
| wmi_buf_free(buf); |
| return VOS_STATUS_E_FAILURE; |
| } |
| |
| return VOS_STATUS_SUCCESS; |
| |
| } |
| #endif |
| static void wma_update_pdev_stats(tp_wma_handle wma, |
| wmi_pdev_stats *pdev_stats) |
| { |
| tAniGetPEStatsRsp *stats_rsp_params; |
| tANI_U32 temp_mask; |
| tANI_U8 *stats_buf; |
| tCsrGlobalClassAStatsInfo *classa_stats = NULL; |
| struct wma_txrx_node *node; |
| u_int8_t i; |
| |
| for (i = 0; i < wma->max_bssid; i++) { |
| node = &wma->interfaces[i]; |
| stats_rsp_params = node->stats_rsp; |
| if (stats_rsp_params) { |
| node->fw_stats_set |= FW_PDEV_STATS_SET; |
| WMA_LOGD("<---FW PDEV STATS received for vdevId:%d", |
| i); |
| stats_buf = (tANI_U8 *) (stats_rsp_params + 1); |
| temp_mask = stats_rsp_params->statsMask; |
| if (temp_mask & (1 << eCsrSummaryStats)) |
| stats_buf += sizeof(tCsrSummaryStatsInfo); |
| |
| if (temp_mask & (1 << eCsrGlobalClassAStats)) { |
| classa_stats = |
| (tCsrGlobalClassAStatsInfo *) stats_buf; |
| classa_stats->max_pwr = pdev_stats->chan_tx_pwr; |
| } |
| } |
| } |
| } |
| |
| /** |
| * wma_vdev_stats_lost_link_helper() - helper function to extract |
| * lost link information from vdev statistics event while deleting BSS. |
| * @wma: WMA handle |
| * @vdev_stats: statistics information from firmware |
| * |
| * This is for informing HDD to collect lost link information while |
| * disconnection. Following conditions to check |
| * 1. vdev is up |
| * 2. bssid is zero. When handling DELETE_BSS request message, it sets bssid to |
| * zero, hence add the check here to indicate the event comes during deleting |
| * BSS |
| * 3. DELETE_BSS is the request message queued. Put this condition check on the |
| * last one as it consumes more resource searching entries in the list |
| * |
| * Return: none |
| */ |
| static void wma_vdev_stats_lost_link_helper(tp_wma_handle wma, |
| wmi_vdev_stats *vdev_stats) |
| { |
| struct wma_txrx_node *node; |
| int8_t rssi; |
| struct wma_target_req *req_msg; |
| uint8_t zero_mac[ETH_ALEN] = {0}; |
| int8_t bcn_snr, dat_snr; |
| |
| node = &wma->interfaces[vdev_stats->vdev_id]; |
| if (node->vdev_up && |
| vos_mem_compare(node->bssid, zero_mac, ETH_ALEN)) { |
| req_msg = wma_peek_vdev_req(wma, vdev_stats->vdev_id, |
| WMA_TARGET_REQ_TYPE_VDEV_STOP); |
| if ((NULL == req_msg) || |
| (WDA_DELETE_BSS_REQ != req_msg->msg_type)) { |
| WMA_LOGD("%s: cannot find DELETE_BSS request message", |
| __func__); |
| return; |
| } |
| bcn_snr = vdev_stats->vdev_snr.bcn_snr; |
| dat_snr = vdev_stats->vdev_snr.dat_snr; |
| WMA_LOGD("%s: get vdev id %d, beancon snr %d, data snr %d", |
| __func__, vdev_stats->vdev_id, bcn_snr, dat_snr); |
| if ((bcn_snr != WMA_TGT_INVALID_SNR_OLD) && |
| (bcn_snr != WMA_TGT_INVALID_SNR_NEW)) |
| rssi = bcn_snr; |
| else if ((dat_snr != WMA_TGT_INVALID_SNR_OLD) && |
| (dat_snr != WMA_TGT_INVALID_SNR_NEW)) |
| rssi = dat_snr; |
| else |
| rssi = WMA_TGT_INVALID_SNR_OLD; |
| |
| /* Get the absolute rssi value from the current rssi value */ |
| rssi = rssi + WMA_TGT_NOISE_FLOOR_DBM; |
| wma_lost_link_info_handler(wma, vdev_stats->vdev_id, rssi); |
| } |
| } |
| |
| static void wma_update_vdev_stats(tp_wma_handle wma, |
| wmi_vdev_stats *vdev_stats) |
| { |
| tAniGetPEStatsRsp *stats_rsp_params; |
| tCsrSummaryStatsInfo *summary_stats = NULL; |
| tANI_U8 *stats_buf; |
| struct wma_txrx_node *node; |
| tANI_U8 i; |
| v_S7_t rssi = 0; |
| VOS_STATUS vos_status; |
| tAniGetRssiReq *pGetRssiReq = (tAniGetRssiReq*)wma->pGetRssiReq; |
| vos_msg_t sme_msg = {0}; |
| int8_t bcn_snr, dat_snr; |
| |
| node = &wma->interfaces[vdev_stats->vdev_id]; |
| stats_rsp_params = node->stats_rsp; |
| if (stats_rsp_params) { |
| stats_buf = (tANI_U8 *) (stats_rsp_params + 1); |
| node->fw_stats_set |= FW_VDEV_STATS_SET; |
| WMA_LOGD("<---FW VDEV STATS received for vdevId:%d", |
| vdev_stats->vdev_id); |
| if (stats_rsp_params->statsMask & |
| (1 << eCsrSummaryStats)) { |
| summary_stats = (tCsrSummaryStatsInfo *) stats_buf; |
| for (i=0 ; i < 4 ; i++) { |
| summary_stats->tx_frm_cnt[i] = |
| vdev_stats->tx_frm_cnt[i]; |
| summary_stats->fail_cnt[i] = |
| vdev_stats->fail_cnt[i]; |
| summary_stats->multiple_retry_cnt[i] = |
| vdev_stats->multiple_retry_cnt[i]; |
| } |
| |
| summary_stats->rx_frm_cnt = vdev_stats->rx_frm_cnt; |
| summary_stats->rx_error_cnt = vdev_stats->rx_err_cnt; |
| summary_stats->rx_discard_cnt = |
| vdev_stats->rx_discard_cnt; |
| summary_stats->ack_fail_cnt = vdev_stats->ack_fail_cnt; |
| summary_stats->rts_succ_cnt = vdev_stats->rts_succ_cnt; |
| summary_stats->rts_fail_cnt = vdev_stats->rts_fail_cnt; |
| } |
| } |
| |
| bcn_snr = vdev_stats->vdev_snr.bcn_snr; |
| dat_snr = vdev_stats->vdev_snr.dat_snr; |
| WMA_LOGD("vdev id %d beancon snr %d data snr %d", |
| vdev_stats->vdev_id, bcn_snr, dat_snr); |
| |
| if (pGetRssiReq && |
| pGetRssiReq->sessionId == vdev_stats->vdev_id) { |
| if ((bcn_snr == WMA_TGT_INVALID_SNR_OLD || |
| bcn_snr == WMA_TGT_INVALID_SNR_NEW) && |
| (dat_snr == WMA_TGT_INVALID_SNR_OLD || |
| dat_snr == WMA_TGT_INVALID_SNR_NEW)) { |
| /* |
| * Firmware sends invalid snr till it sees |
| * Beacon/Data after connection since after |
| * vdev up fw resets the snr to invalid. |
| * In this duartion Host will return the last know |
| * rssi during connection. |
| */ |
| rssi = wma->first_rssi; |
| } else { |
| if (bcn_snr != WMA_TGT_INVALID_SNR_OLD && |
| bcn_snr != WMA_TGT_INVALID_SNR_NEW) { |
| rssi = bcn_snr; |
| } else if (dat_snr != WMA_TGT_INVALID_SNR_OLD && |
| dat_snr != WMA_TGT_INVALID_SNR_NEW) { |
| rssi = dat_snr; |
| } |
| |
| /* |
| * Get the absolute rssi value from the current rssi value |
| * the sinr value is hardcoded into 0 in the core stack |
| */ |
| rssi = rssi + WMA_TGT_NOISE_FLOOR_DBM; |
| } |
| |
| WMA_LOGD("Average Rssi = %d, vdev id= %d", rssi, |
| pGetRssiReq->sessionId); |
| |
| /* update the average rssi value to UMAC layer */ |
| if (NULL != pGetRssiReq->rssiCallback) { |
| ((tCsrRssiCallback)(pGetRssiReq->rssiCallback))(rssi,pGetRssiReq->staId, |
| pGetRssiReq->pDevContext); |
| } |
| |
| adf_os_mem_free(pGetRssiReq); |
| wma->pGetRssiReq = NULL; |
| } |
| |
| if (node->psnr_req) { |
| tAniGetSnrReq *p_snr_req = node->psnr_req; |
| |
| if ((bcn_snr != WMA_TGT_INVALID_SNR_OLD) && |
| (bcn_snr != WMA_TGT_INVALID_SNR_NEW)) |
| p_snr_req->snr = bcn_snr; |
| else if ((dat_snr != WMA_TGT_INVALID_SNR_OLD) && |
| (dat_snr != WMA_TGT_INVALID_SNR_NEW)) |
| p_snr_req->snr = dat_snr; |
| else |
| p_snr_req->snr = WMA_TGT_INVALID_SNR_OLD; |
| |
| sme_msg.type = eWNI_SME_SNR_IND; |
| sme_msg.bodyptr = p_snr_req; |
| sme_msg.bodyval = 0; |
| |
| vos_status = vos_mq_post_message(VOS_MODULE_ID_SME, &sme_msg); |
| if (!VOS_IS_STATUS_SUCCESS(vos_status)) { |
| WMA_LOGE("%s: Fail to post snr ind msg", __func__); |
| vos_mem_free(p_snr_req); |
| } |
| |
| node->psnr_req = NULL; |
| } |
| |
| wma_vdev_stats_lost_link_helper(wma, vdev_stats); |
| } |
| |
| static void wma_post_stats(tp_wma_handle wma, struct wma_txrx_node *node) |
| { |
| tAniGetPEStatsRsp *stats_rsp_params; |
| |
| stats_rsp_params = node->stats_rsp; |
| /* send response to UMAC*/ |
| wma_send_msg(wma, WDA_GET_STATISTICS_RSP, (void *)stats_rsp_params, 0) ; |
| node->stats_rsp = NULL; |
| node->fw_stats_set = 0; |
| } |
| |
| static void wma_update_peer_stats(tp_wma_handle wma, wmi_peer_stats *peer_stats) |
| { |
| tAniGetPEStatsRsp *stats_rsp_params; |
| tCsrGlobalClassAStatsInfo *classa_stats = NULL; |
| struct wma_txrx_node *node; |
| tANI_U8 *stats_buf, vdev_id, macaddr[IEEE80211_ADDR_LEN], mcsRateFlags; |
| tANI_U32 temp_mask; |
| |
| WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_stats->peer_macaddr, &macaddr[0]); |
| if (!wma_find_vdev_by_bssid(wma, macaddr, &vdev_id)) |
| return; |
| |
| node = &wma->interfaces[vdev_id]; |
| if (node->stats_rsp) { |
| node->fw_stats_set |= FW_PEER_STATS_SET; |
| WMA_LOGD("<-- FW PEER STATS received for vdevId:%d", vdev_id); |
| stats_rsp_params = (tAniGetPEStatsRsp *) node->stats_rsp; |
| stats_buf = (tANI_U8 *) (stats_rsp_params + 1); |
| temp_mask = stats_rsp_params->statsMask; |
| if (temp_mask & (1 << eCsrSummaryStats)) |
| stats_buf += sizeof(tCsrSummaryStatsInfo); |
| |
| if (temp_mask & (1 << eCsrGlobalClassAStats)) { |
| classa_stats = (tCsrGlobalClassAStatsInfo *) stats_buf; |
| WMA_LOGD("peer tx rate:%d", peer_stats->peer_tx_rate); |
| /*The linkspeed returned by fw is in kbps so convert |
| *it in to units of 500kbps which is expected by UMAC*/ |
| if (peer_stats->peer_tx_rate) { |
| classa_stats->tx_rate = |
| peer_stats->peer_tx_rate/500; |
| } |
| |
| classa_stats->tx_rate_flags = node->rate_flags; |
| if (!(node->rate_flags & eHAL_TX_RATE_LEGACY)) { |
| classa_stats->mcs_index = |
| wma_get_mcs_idx((peer_stats->peer_tx_rate/100), |
| node->rate_flags, |
| node->nss, |
| &mcsRateFlags); |
| /* rx_frag_cnt and promiscuous_rx_frag_cnt |
| * parameter is currently not used. lets use the |
| * same parameter to hold the nss value and mcs |
| * rate flags */ |
| classa_stats->rx_frag_cnt = node->nss; |
| classa_stats->promiscuous_rx_frag_cnt = mcsRateFlags; |
| } |
| /* FW returns tx power in intervals of 0.5 dBm |
| Convert it back to intervals of 1 dBm */ |
| classa_stats->max_pwr = |
| roundup(classa_stats->max_pwr, 2) >> 1; |
| } |
| } |
| } |
| |
| static void wma_post_link_status(tAniGetLinkStatus *pGetLinkStatus, |
| u_int8_t link_status) |
| { |
| VOS_STATUS vos_status = VOS_STATUS_SUCCESS; |
| vos_msg_t sme_msg = {0} ; |
| |
| pGetLinkStatus->linkStatus = link_status; |
| sme_msg.type = eWNI_SME_LINK_STATUS_IND; |
| sme_msg.bodyptr = pGetLinkStatus; |
| sme_msg.bodyval = 0; |
| |
| vos_status = vos_mq_post_message(VOS_MODULE_ID_SME, &sme_msg); |
| if (!VOS_IS_STATUS_SUCCESS(vos_status)) { |
| WMA_LOGE("%s: Fail to post link status ind msg", __func__); |
| vos_mem_free(pGetLinkStatus); |
| } |
| } |
| |
| /** |
| * wma_update_per_chain_rssi_stats() - to store per chain rssi stats for |
| * all vdevs for which the stats were requested into csr stats structure. |
| * @wma: wma handle |
| * @rssi_stats: rssi stats |
| * @rssi_per_chain_stats: buffer where rssi stats to be stored |
| * |
| * This function stores per chain rssi stats received from fw for all vdevs for |
| * which the stats were requested into a csr stats structure. |
| * |
| * Return: void |
| */ |
| static void wma_update_per_chain_rssi_stats(tp_wma_handle wma, |
| wmi_rssi_stats *rssi_stats, |
| struct csr_per_chain_rssi_stats_info *rssi_per_chain_stats) |
| { |
| int i; |
| int8_t bcn_snr, dat_snr; |
| |
| for (i = 0; i < NUM_CHAINS_MAX; i++) { |
| bcn_snr = rssi_stats->rssi_avg_beacon[i]; |
| dat_snr = rssi_stats->rssi_avg_data[i]; |
| WMA_LOGD("chain %d beacon snr %d data snr %d", |
| i, bcn_snr, dat_snr); |
| if ((dat_snr != WMA_TGT_INVALID_SNR_OLD && |
| dat_snr != WMA_TGT_INVALID_SNR_NEW)) |
| rssi_per_chain_stats->rssi[i] = dat_snr; |
| else if ((bcn_snr != WMA_TGT_INVALID_SNR_OLD && |
| bcn_snr != WMA_TGT_INVALID_SNR_NEW)) |
| rssi_per_chain_stats->rssi[i] = bcn_snr; |
| else |
| /* |
| * Firmware sends invalid snr till it sees |
| * Beacon/Data after connection since after |
| * vdev up fw resets the snr to invalid. |
| * In this duartion Host will return an invalid rssi |
| * value. |
| */ |
| rssi_per_chain_stats->rssi[i] = WMA_TGT_RSSI_INVALID; |
| |
| /* |
| * Get the absolute rssi value from the current rssi value the |
| * sinr value is hardcoded into 0 in the CORE stack |
| */ |
| rssi_per_chain_stats->rssi[i] += WMA_TGT_NOISE_FLOOR_DBM; |
| WMI_MAC_ADDR_TO_CHAR_ARRAY(&(rssi_stats->peer_macaddr), |
| rssi_per_chain_stats->peer_mac_addr); |
| } |
| } |
| |
| /** |
| * wma_update_rssi_stats() - to update rssi stats for all vdevs |
| * for which the stats were requested. |
| * @wma: wma handle |
| * @rssi_stats: rssi stats |
| * |
| * This function updates the rssi stats for all vdevs for which |
| * the stats were requested. |
| * |
| * Return: void |
| */ |
| static void wma_update_rssi_stats(tp_wma_handle wma, |
| wmi_rssi_stats *rssi_stats) |
| { |
| tAniGetPEStatsRsp *stats_rsp_params; |
| struct csr_per_chain_rssi_stats_info *rssi_per_chain_stats = NULL; |
| struct wma_txrx_node *node; |
| uint8_t *stats_buf; |
| uint32_t temp_mask; |
| uint8_t vdev_id; |
| |
| vdev_id = rssi_stats->vdev_id; |
| node = &wma->interfaces[vdev_id]; |
| if (node->stats_rsp) { |
| node->fw_stats_set |= FW_RSSI_PER_CHAIN_STATS_SET; |
| WMA_LOGD("<-- FW RSSI PER CHAIN STATS received for vdevId:%d", |
| vdev_id); |
| stats_rsp_params = (tAniGetPEStatsRsp *) node->stats_rsp; |
| stats_buf = (tANI_U8 *) (stats_rsp_params + 1); |
| temp_mask = stats_rsp_params->statsMask; |
| |
| if (temp_mask & (1 << eCsrSummaryStats)) |
| stats_buf += sizeof(tCsrSummaryStatsInfo); |
| if (temp_mask & (1 << eCsrGlobalClassAStats)) |
| stats_buf += sizeof(tCsrGlobalClassAStatsInfo); |
| if (temp_mask & (1 << eCsrGlobalClassBStats)) |
| stats_buf += sizeof(tCsrGlobalClassBStatsInfo); |
| if (temp_mask & (1 << eCsrGlobalClassCStats)) |
| stats_buf += sizeof(tCsrGlobalClassCStatsInfo); |
| if (temp_mask & (1 << eCsrGlobalClassDStats)) |
| stats_buf += sizeof(tCsrGlobalClassDStatsInfo); |
| if (temp_mask & (1 << eCsrPerStaStats)) |
| stats_buf += sizeof(tCsrPerStaStatsInfo); |
| |
| if (temp_mask & (1 << csr_per_chain_rssi_stats)) { |
| rssi_per_chain_stats = |
| (struct csr_per_chain_rssi_stats_info *)stats_buf; |
| wma_update_per_chain_rssi_stats(wma, rssi_stats, |
| rssi_per_chain_stats); |
| } |
| } |
| } |
| |
| |
| static int wma_link_status_rsp(tp_wma_handle wma, u_int8_t *buf) |
| { |
| wmi_vdev_rate_stats_event_fixed_param *event; |
| wmi_vdev_rate_ht_info *ht_info; |
| struct wma_txrx_node *intr = wma->interfaces; |
| u_int8_t link_status = LINK_STATUS_LEGACY; |
| int i; |
| |
| event = (wmi_vdev_rate_stats_event_fixed_param *)buf; |
| ht_info = (wmi_vdev_rate_ht_info *)(buf + sizeof(*event)); |
| |
| WMA_LOGD("num_vdev_stats: %d", event->num_vdev_stats); |
| for (i = 0; (i < event->num_vdev_stats) && ht_info; i++) { |
| WMA_LOGD( |
| "%s vdevId:%d tx_nss:%d rx_nss:%d tx_preamble:%d rx_preamble:%d", |
| __func__, |
| ht_info->vdevid, |
| ht_info->tx_nss, |
| ht_info->rx_nss, |
| ht_info->tx_preamble, |
| ht_info->rx_preamble); |
| if (ht_info->vdevid < wma->max_bssid && |
| intr[ht_info->vdevid].plink_status_req) { |
| if (ht_info->tx_nss || ht_info->rx_nss) |
| link_status = LINK_STATUS_MIMO; |
| |
| if ((ht_info->tx_preamble == LINK_RATE_VHT) || |
| (ht_info->rx_preamble == LINK_RATE_VHT)) |
| link_status |= LINK_STATUS_VHT; |
| |
| if (intr[ht_info->vdevid].nss == 2) |
| link_status |= LINK_SUPPORT_MIMO; |
| |
| if (intr[ht_info->vdevid].rate_flags & |
| (eHAL_TX_RATE_VHT20 | eHAL_TX_RATE_VHT40 | |
| eHAL_TX_RATE_VHT80)) |
| link_status |= LINK_SUPPORT_VHT; |
| |
| wma_post_link_status(intr[ht_info->vdevid].plink_status_req, |
| link_status); |
| intr[ht_info->vdevid].plink_status_req = NULL; |
| link_status = LINK_STATUS_LEGACY; |
| } |
| |
| ht_info++; |
| } |
| |
| return 0; |
| } |
| |
| static int wma_link_status_event_handler(void *handle, u_int8_t *cmd_param_info, |
| u_int32_t len) |
| { |
| WMI_UPDATE_VDEV_RATE_STATS_EVENTID_param_tlvs *param_buf; |
| wmi_vdev_rate_stats_event_fixed_param *event; |
| vos_msg_t vos_msg = {0}; |
| u_int32_t buf_size; |
| u_int8_t *buf; |
| |
| param_buf = |
| (WMI_UPDATE_VDEV_RATE_STATS_EVENTID_param_tlvs *)cmd_param_info; |
| if (!param_buf) { |
| WMA_LOGA("%s: Invalid stats event", __func__); |
| return -EINVAL; |
| } |
| |
| event = param_buf->fixed_param; |
| if (event->num_vdev_stats > ((WMA_SVC_MSG_MAX_SIZE - |
| sizeof(*event)) / sizeof(wmi_vdev_rate_ht_info))) { |
| WMA_LOGE("%s: excess vdev_stats buffers:%d", __func__, |
| event->num_vdev_stats); |
| VOS_ASSERT(0); |
| return -EINVAL; |
| } |
| buf_size = sizeof(wmi_vdev_rate_stats_event_fixed_param) + |
| sizeof(wmi_vdev_rate_ht_info) * event->num_vdev_stats; |
| buf = vos_mem_malloc(buf_size); |
| if (!buf) { |
| WMA_LOGE("%s: Failed alloc memory for buf", __func__); |
| return -ENOMEM; |
| } |
| |
| vos_mem_zero(buf, buf_size); |
| vos_mem_copy(buf, param_buf->fixed_param, |
| sizeof(wmi_vdev_rate_stats_event_fixed_param)); |
| vos_mem_copy((buf + sizeof(wmi_vdev_rate_stats_event_fixed_param)), |
| param_buf->ht_info, |
| sizeof(wmi_vdev_rate_ht_info) * event->num_vdev_stats); |
| |
| vos_msg.type = WDA_GET_LINK_STATUS_RSP_IND; |
| vos_msg.bodyptr = buf; |
| vos_msg.bodyval = 0; |
| |
| if (VOS_STATUS_SUCCESS != |
| vos_mq_post_message(VOS_MQ_ID_WDA, &vos_msg)) { |
| WMA_LOGP("%s: Failed to post WDA_GET_LINK_STATUS_RSP_IND msg", |
| __func__); |
| vos_mem_free(buf); |
| return -1; |
| } |
| WMA_LOGD("posted WDA_GET_LINK_STATUS_RSP_IND"); |
| |
| return 0; |
| } |
| |
| /** |
| * wma_update_mib_stats() - send mib stats to hdd |
| * @wma_handle: pointer to wma handle. |
| * @event: mib stats |
| * |
| * This API handles the requested Mib stats and calls the callback to |
| * update hdd |
| * |
| * Return: Success or error code |
| */ |
| static int wma_update_mib_stats(tp_wma_handle wma_handle , |
| wmi_mib_stats *event) |
| { |
| struct mib_stats_metrics mib_stats; |
| tpAniSirGlobal mac = (tpAniSirGlobal)vos_get_context( |
| VOS_MODULE_ID_PE, wma_handle->vos_context); |
| |
| if (!mac) { |
| WMA_LOGE("%s: Invalid mac context", __func__); |
| return -EINVAL; |
| } |
| if (!mac->sme.csr_mib_stats_callback) { |
| WMA_LOGE("%s: Callback not registered", __func__); |
| return -EINVAL; |
| } |
| |
| mib_stats.mib_counters.tx_frags = |
| event->tx_mpdu_grp_frag_cnt; |
| mib_stats.mib_counters.group_tx_frames = |
| event->tx_msdu_grp_frm_cnt; |
| mib_stats.mib_counters.failed_cnt = event->tx_msdu_fail_cnt; |
| mib_stats.mib_counters.rx_frags = event->rx_mpdu_frag_cnt; |
| mib_stats.mib_counters.group_rx_frames = |
| event->rx_msdu_grp_frm_cnt; |
| mib_stats.mib_counters.fcs_error_cnt = |
| event->rx_mpdu_fcs_err; |
| mib_stats.mib_counters.tx_frames = |
| event->tx_msdu_frm_cnt; |
| mib_stats.mib_mac_statistics.retry_cnt = |
| event->tx_msdu_retry_cnt; |
| mib_stats.mib_mac_statistics.frame_dup_cnt = |
| event->rx_frm_dup_cnt; |
| mib_stats.mib_mac_statistics.rts_success_cnt = |
| event->tx_rts_success_cnt; |
| mib_stats.mib_mac_statistics.rts_fail_cnt = |
| event->tx_rts_fail_cnt; |
| |
| mib_stats.mib_qos_counters.qos_tx_frag_cnt = |
| event->tx_Qos_mpdu_grp_frag_cnt; |
| mib_stats.mib_qos_counters.qos_retry_cnt = |
| event->tx_Qos_msdu_retry_UP; |
| mib_stats.mib_qos_counters.qos_failed_cnt = event->tx_Qos_msdu_fail_UP; |
| mib_stats.mib_qos_counters.qos_frame_dup_cnt = |
| event->rx_Qos_frm_dup_cnt_UP; |
|