3479 lines · c
1/*2 * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com>3 *4 * Permission to use, copy, modify, and/or distribute this software for any5 * purpose with or without fee is hereby granted, provided that the above6 * copyright notice and this permission notice appear in all copies.7 *8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.15 */16 17#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt18 19#include <linux/bitfield.h>20#include <linux/etherdevice.h>21#include <linux/firmware.h>22#include <linux/bitops.h>23#include <linux/rpmsg.h>24#include "smd.h"25#include "firmware.h"26 27struct wcn36xx_cfg_val {28 u32 cfg_id;29 u32 value;30};31 32#define WCN36XX_CFG_VAL(id, val) \33{ \34 .cfg_id = WCN36XX_HAL_CFG_ ## id, \35 .value = val \36}37 38static struct wcn36xx_cfg_val wcn36xx_cfg_vals[] = {39 WCN36XX_CFG_VAL(CURRENT_TX_ANTENNA, 1),40 WCN36XX_CFG_VAL(CURRENT_RX_ANTENNA, 1),41 WCN36XX_CFG_VAL(LOW_GAIN_OVERRIDE, 0),42 WCN36XX_CFG_VAL(POWER_STATE_PER_CHAIN, 785),43 WCN36XX_CFG_VAL(CAL_PERIOD, 5),44 WCN36XX_CFG_VAL(CAL_CONTROL, 1),45 WCN36XX_CFG_VAL(PROXIMITY, 0),46 WCN36XX_CFG_VAL(NETWORK_DENSITY, 3),47 WCN36XX_CFG_VAL(MAX_MEDIUM_TIME, 6000),48 WCN36XX_CFG_VAL(MAX_MPDUS_IN_AMPDU, 64),49 WCN36XX_CFG_VAL(RTS_THRESHOLD, 2347),50 WCN36XX_CFG_VAL(SHORT_RETRY_LIMIT, 15),51 WCN36XX_CFG_VAL(LONG_RETRY_LIMIT, 15),52 WCN36XX_CFG_VAL(FRAGMENTATION_THRESHOLD, 8000),53 WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ZERO, 5),54 WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ONE, 10),55 WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_TWO, 15),56 WCN36XX_CFG_VAL(FIXED_RATE, 0),57 WCN36XX_CFG_VAL(RETRYRATE_POLICY, 4),58 WCN36XX_CFG_VAL(RETRYRATE_SECONDARY, 0),59 WCN36XX_CFG_VAL(RETRYRATE_TERTIARY, 0),60 WCN36XX_CFG_VAL(FORCE_POLICY_PROTECTION, 5),61 WCN36XX_CFG_VAL(FIXED_RATE_MULTICAST_24GHZ, 1),62 WCN36XX_CFG_VAL(FIXED_RATE_MULTICAST_5GHZ, 5),63 WCN36XX_CFG_VAL(DEFAULT_RATE_INDEX_5GHZ, 5),64 WCN36XX_CFG_VAL(MAX_BA_SESSIONS, 40),65 WCN36XX_CFG_VAL(PS_DATA_INACTIVITY_TIMEOUT, 200),66 WCN36XX_CFG_VAL(PS_ENABLE_BCN_FILTER, 1),67 WCN36XX_CFG_VAL(PS_ENABLE_RSSI_MONITOR, 1),68 WCN36XX_CFG_VAL(NUM_BEACON_PER_RSSI_AVERAGE, 20),69 WCN36XX_CFG_VAL(STATS_PERIOD, 10),70 WCN36XX_CFG_VAL(CFP_MAX_DURATION, 30000),71 WCN36XX_CFG_VAL(FRAME_TRANS_ENABLED, 0),72 WCN36XX_CFG_VAL(BA_THRESHOLD_HIGH, 128),73 WCN36XX_CFG_VAL(MAX_BA_BUFFERS, 2560),74 WCN36XX_CFG_VAL(DYNAMIC_PS_POLL_VALUE, 0),75 WCN36XX_CFG_VAL(TX_PWR_CTRL_ENABLE, 1),76 WCN36XX_CFG_VAL(ENABLE_CLOSE_LOOP, 1),77 WCN36XX_CFG_VAL(ENABLE_LPWR_IMG_TRANSITION, 0),78 WCN36XX_CFG_VAL(BTC_STATIC_LEN_LE_BT, 120000),79 WCN36XX_CFG_VAL(BTC_STATIC_LEN_LE_WLAN, 30000),80 WCN36XX_CFG_VAL(MAX_ASSOC_LIMIT, 10),81 WCN36XX_CFG_VAL(ENABLE_MCC_ADAPTIVE_SCHEDULER, 0),82 WCN36XX_CFG_VAL(ENABLE_DYNAMIC_RA_START_RATE, 133), /* MCS 5 */83 WCN36XX_CFG_VAL(LINK_FAIL_TX_CNT, 1000),84};85 86static struct wcn36xx_cfg_val wcn3680_cfg_vals[] = {87 WCN36XX_CFG_VAL(CURRENT_TX_ANTENNA, 1),88 WCN36XX_CFG_VAL(CURRENT_RX_ANTENNA, 1),89 WCN36XX_CFG_VAL(LOW_GAIN_OVERRIDE, 0),90 WCN36XX_CFG_VAL(POWER_STATE_PER_CHAIN, 785),91 WCN36XX_CFG_VAL(CAL_PERIOD, 5),92 WCN36XX_CFG_VAL(CAL_CONTROL, 1),93 WCN36XX_CFG_VAL(PROXIMITY, 0),94 WCN36XX_CFG_VAL(NETWORK_DENSITY, 3),95 WCN36XX_CFG_VAL(MAX_MEDIUM_TIME, 4096),96 WCN36XX_CFG_VAL(MAX_MPDUS_IN_AMPDU, 64),97 WCN36XX_CFG_VAL(RTS_THRESHOLD, 2347),98 WCN36XX_CFG_VAL(SHORT_RETRY_LIMIT, 15),99 WCN36XX_CFG_VAL(LONG_RETRY_LIMIT, 15),100 WCN36XX_CFG_VAL(FRAGMENTATION_THRESHOLD, 8000),101 WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ZERO, 5),102 WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ONE, 10),103 WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_TWO, 15),104 WCN36XX_CFG_VAL(FIXED_RATE, 0),105 WCN36XX_CFG_VAL(RETRYRATE_POLICY, 4),106 WCN36XX_CFG_VAL(RETRYRATE_SECONDARY, 0),107 WCN36XX_CFG_VAL(RETRYRATE_TERTIARY, 0),108 WCN36XX_CFG_VAL(FORCE_POLICY_PROTECTION, 5),109 WCN36XX_CFG_VAL(FIXED_RATE_MULTICAST_24GHZ, 1),110 WCN36XX_CFG_VAL(FIXED_RATE_MULTICAST_5GHZ, 5),111 WCN36XX_CFG_VAL(DEFAULT_RATE_INDEX_24GHZ, 1),112 WCN36XX_CFG_VAL(DEFAULT_RATE_INDEX_5GHZ, 5),113 WCN36XX_CFG_VAL(MAX_BA_SESSIONS, 40),114 WCN36XX_CFG_VAL(PS_DATA_INACTIVITY_TIMEOUT, 200),115 WCN36XX_CFG_VAL(PS_ENABLE_BCN_FILTER, 1),116 WCN36XX_CFG_VAL(PS_ENABLE_RSSI_MONITOR, 1),117 WCN36XX_CFG_VAL(NUM_BEACON_PER_RSSI_AVERAGE, 20),118 WCN36XX_CFG_VAL(STATS_PERIOD, 10),119 WCN36XX_CFG_VAL(CFP_MAX_DURATION, 30000),120 WCN36XX_CFG_VAL(FRAME_TRANS_ENABLED, 0),121 WCN36XX_CFG_VAL(BA_THRESHOLD_HIGH, 128),122 WCN36XX_CFG_VAL(MAX_BA_BUFFERS, 2560),123 WCN36XX_CFG_VAL(DYNAMIC_PS_POLL_VALUE, 0),124 WCN36XX_CFG_VAL(TX_PWR_CTRL_ENABLE, 1),125 WCN36XX_CFG_VAL(ENABLE_CLOSE_LOOP, 1),126 WCN36XX_CFG_VAL(ENABLE_LPWR_IMG_TRANSITION, 0),127 WCN36XX_CFG_VAL(BTC_STATIC_LEN_LE_BT, 120000),128 WCN36XX_CFG_VAL(BTC_STATIC_LEN_LE_WLAN, 30000),129 WCN36XX_CFG_VAL(MAX_ASSOC_LIMIT, 10),130 WCN36XX_CFG_VAL(ENABLE_MCC_ADAPTIVE_SCHEDULER, 0),131 WCN36XX_CFG_VAL(TDLS_PUAPSD_MASK, 0),132 WCN36XX_CFG_VAL(TDLS_PUAPSD_BUFFER_STA_CAPABLE, 1),133 WCN36XX_CFG_VAL(TDLS_PUAPSD_INACTIVITY_TIME, 0),134 WCN36XX_CFG_VAL(TDLS_PUAPSD_RX_FRAME_THRESHOLD, 10),135 WCN36XX_CFG_VAL(TDLS_OFF_CHANNEL_CAPABLE, 1),136 WCN36XX_CFG_VAL(ENABLE_ADAPTIVE_RX_DRAIN, 1),137 WCN36XX_CFG_VAL(FLEXCONNECT_POWER_FACTOR, 0),138 WCN36XX_CFG_VAL(ANTENNA_DIVERSITY, 3),139 WCN36XX_CFG_VAL(ATH_DISABLE, 0),140 WCN36XX_CFG_VAL(BTC_STATIC_OPP_WLAN_ACTIVE_WLAN_LEN, 60000),141 WCN36XX_CFG_VAL(BTC_STATIC_OPP_WLAN_ACTIVE_BT_LEN, 90000),142 WCN36XX_CFG_VAL(BTC_SAP_STATIC_OPP_ACTIVE_WLAN_LEN, 30000),143 WCN36XX_CFG_VAL(BTC_SAP_STATIC_OPP_ACTIVE_BT_LEN, 30000),144 WCN36XX_CFG_VAL(ASD_PROBE_INTERVAL, 50),145 WCN36XX_CFG_VAL(ASD_TRIGGER_THRESHOLD, -60),146 WCN36XX_CFG_VAL(ASD_RTT_RSSI_HYST_THRESHOLD, 3),147 WCN36XX_CFG_VAL(BTC_CTS2S_ON_STA_DURING_SCO, 0),148 WCN36XX_CFG_VAL(RA_FILTER_ENABLE, 0),149 WCN36XX_CFG_VAL(RA_RATE_LIMIT_INTERVAL, 60),150 WCN36XX_CFG_VAL(BTC_FATAL_HID_NSNIFF_BLK, 2),151 WCN36XX_CFG_VAL(BTC_CRITICAL_HID_NSNIFF_BLK, 1),152 WCN36XX_CFG_VAL(BTC_DYN_A2DP_TX_QUEUE_THOLD, 0),153 WCN36XX_CFG_VAL(BTC_DYN_OPP_TX_QUEUE_THOLD, 1),154 WCN36XX_CFG_VAL(MAX_UAPSD_CONSEC_SP, 10),155 WCN36XX_CFG_VAL(MAX_UAPSD_CONSEC_RX_CNT, 50),156 WCN36XX_CFG_VAL(MAX_UAPSD_CONSEC_TX_CNT, 50),157 WCN36XX_CFG_VAL(MAX_UAPSD_CONSEC_TX_CNT_MEAS_WINDOW, 500),158 WCN36XX_CFG_VAL(MAX_UAPSD_CONSEC_RX_CNT_MEAS_WINDOW, 500),159 WCN36XX_CFG_VAL(MAX_PSPOLL_IN_WMM_UAPSD_PS_MODE, 0),160 WCN36XX_CFG_VAL(MAX_UAPSD_INACTIVITY_INTERVALS, 10),161 WCN36XX_CFG_VAL(ENABLE_DYNAMIC_WMMPS, 1),162 WCN36XX_CFG_VAL(BURST_MODE_BE_TXOP_VALUE, 0),163 WCN36XX_CFG_VAL(ENABLE_DYNAMIC_RA_START_RATE, 136),164 WCN36XX_CFG_VAL(BTC_FAST_WLAN_CONN_PREF, 1),165 WCN36XX_CFG_VAL(ENABLE_RTSCTS_HTVHT, 0),166 WCN36XX_CFG_VAL(BTC_STATIC_OPP_WLAN_IDLE_WLAN_LEN, 30000),167 WCN36XX_CFG_VAL(BTC_STATIC_OPP_WLAN_IDLE_BT_LEN, 120000),168 WCN36XX_CFG_VAL(LINK_FAIL_TX_CNT, 1000),169 WCN36XX_CFG_VAL(TOGGLE_ARP_BDRATES, 0),170 WCN36XX_CFG_VAL(OPTIMIZE_CA_EVENT, 0),171 WCN36XX_CFG_VAL(EXT_SCAN_CONC_MODE, 0),172 WCN36XX_CFG_VAL(BAR_WAKEUP_HOST_DISABLE, 0),173 WCN36XX_CFG_VAL(SAR_BOFFSET_CORRECTION_ENABLE, 0),174 WCN36XX_CFG_VAL(BTC_DISABLE_WLAN_LINK_CRITICAL, 5),175 WCN36XX_CFG_VAL(DISABLE_SCAN_DURING_SCO, 2),176 WCN36XX_CFG_VAL(CONS_BCNMISS_COUNT, 0),177 WCN36XX_CFG_VAL(UNITS_OF_BCN_WAIT_TIME, 0),178 WCN36XX_CFG_VAL(TRIGGER_NULLFRAME_BEFORE_HB, 0),179 WCN36XX_CFG_VAL(ENABLE_POWERSAVE_OFFLOAD, 0),180};181 182static int put_cfg_tlv_u32(struct wcn36xx *wcn, size_t *len, u32 id, u32 value)183{184 struct wcn36xx_hal_cfg *entry;185 u32 *val;186 187 if (*len + sizeof(*entry) + sizeof(u32) >= WCN36XX_HAL_BUF_SIZE) {188 wcn36xx_err("Not enough room for TLV entry\n");189 return -ENOMEM;190 }191 192 entry = (struct wcn36xx_hal_cfg *) (wcn->hal_buf + *len);193 entry->id = id;194 entry->len = sizeof(u32);195 entry->pad_bytes = 0;196 entry->reserve = 0;197 198 val = (u32 *) (entry + 1);199 *val = value;200 201 *len += sizeof(*entry) + sizeof(u32);202 203 return 0;204}205 206static void wcn36xx_smd_set_bss_nw_type(struct wcn36xx *wcn,207 struct ieee80211_sta *sta,208 struct wcn36xx_hal_config_bss_params *bss_params)209{210 if (NL80211_BAND_5GHZ == WCN36XX_BAND(wcn))211 bss_params->nw_type = WCN36XX_HAL_11A_NW_TYPE;212 else if (sta && sta->deflink.ht_cap.ht_supported)213 bss_params->nw_type = WCN36XX_HAL_11N_NW_TYPE;214 else if (sta && (sta->deflink.supp_rates[NL80211_BAND_2GHZ] & 0x7f))215 bss_params->nw_type = WCN36XX_HAL_11G_NW_TYPE;216 else217 bss_params->nw_type = WCN36XX_HAL_11B_NW_TYPE;218}219 220static inline u8 is_cap_supported(unsigned long caps, unsigned long flag)221{222 return caps & flag ? 1 : 0;223}224 225static void wcn36xx_smd_set_bss_ht_params(struct ieee80211_vif *vif,226 struct ieee80211_sta *sta,227 struct wcn36xx_hal_config_bss_params *bss_params)228{229 if (sta && sta->deflink.ht_cap.ht_supported) {230 unsigned long caps = sta->deflink.ht_cap.cap;231 232 bss_params->ht = sta->deflink.ht_cap.ht_supported;233 bss_params->tx_channel_width_set = is_cap_supported(caps,234 IEEE80211_HT_CAP_SUP_WIDTH_20_40);235 bss_params->lsig_tx_op_protection_full_support =236 is_cap_supported(caps,237 IEEE80211_HT_CAP_LSIG_TXOP_PROT);238 239 bss_params->ht_oper_mode = vif->bss_conf.ht_operation_mode;240 bss_params->lln_non_gf_coexist =241 !!(vif->bss_conf.ht_operation_mode &242 IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);243 /* IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT */244 bss_params->dual_cts_protection = 0;245 /* IEEE80211_HT_OP_MODE_PROTECTION_20MHZ */246 bss_params->ht20_coexist = 0;247 }248}249 250static void251wcn36xx_smd_set_bss_vht_params(struct ieee80211_vif *vif,252 struct ieee80211_sta *sta,253 struct wcn36xx_hal_config_bss_params_v1 *bss)254{255 if (sta && sta->deflink.vht_cap.vht_supported)256 bss->vht_capable = 1;257}258 259static void wcn36xx_smd_set_sta_ht_params(struct ieee80211_sta *sta,260 struct wcn36xx_hal_config_sta_params *sta_params)261{262 if (sta->deflink.ht_cap.ht_supported) {263 unsigned long caps = sta->deflink.ht_cap.cap;264 265 sta_params->ht_capable = sta->deflink.ht_cap.ht_supported;266 sta_params->tx_channel_width_set = is_cap_supported(caps,267 IEEE80211_HT_CAP_SUP_WIDTH_20_40);268 sta_params->lsig_txop_protection = is_cap_supported(caps,269 IEEE80211_HT_CAP_LSIG_TXOP_PROT);270 271 sta_params->max_ampdu_size = sta->deflink.ht_cap.ampdu_factor;272 sta_params->max_ampdu_density = sta->deflink.ht_cap.ampdu_density;273 /* max_amsdu_size: 1 : 3839 bytes, 0 : 7935 bytes (max) */274 sta_params->max_amsdu_size = !is_cap_supported(caps,275 IEEE80211_HT_CAP_MAX_AMSDU);276 sta_params->sgi_20Mhz = is_cap_supported(caps,277 IEEE80211_HT_CAP_SGI_20);278 sta_params->sgi_40mhz = is_cap_supported(caps,279 IEEE80211_HT_CAP_SGI_40);280 sta_params->green_field_capable = is_cap_supported(caps,281 IEEE80211_HT_CAP_GRN_FLD);282 sta_params->delayed_ba_support = is_cap_supported(caps,283 IEEE80211_HT_CAP_DELAY_BA);284 sta_params->dsss_cck_mode_40mhz = is_cap_supported(caps,285 IEEE80211_HT_CAP_DSSSCCK40);286 }287}288 289static void wcn36xx_smd_set_sta_vht_params(struct wcn36xx *wcn,290 struct ieee80211_sta *sta,291 struct wcn36xx_hal_config_sta_params_v1 *sta_params)292{293 if (sta->deflink.vht_cap.vht_supported) {294 unsigned long caps = sta->deflink.vht_cap.cap;295 296 sta_params->vht_capable = sta->deflink.vht_cap.vht_supported;297 sta_params->vht_ldpc_enabled =298 is_cap_supported(caps, IEEE80211_VHT_CAP_RXLDPC);299 if (wcn36xx_firmware_get_feat_caps(wcn->fw_feat_caps, MU_MIMO)) {300 sta_params->vht_tx_mu_beamformee_capable =301 is_cap_supported(caps, IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE);302 if (sta_params->vht_tx_mu_beamformee_capable)303 sta_params->vht_tx_bf_enabled = 1;304 } else {305 sta_params->vht_tx_mu_beamformee_capable = 0;306 }307 sta_params->vht_tx_channel_width_set = 0;308 }309}310 311static void wcn36xx_smd_set_sta_ht_ldpc_params(struct ieee80211_sta *sta,312 struct wcn36xx_hal_config_sta_params_v1 *sta_params)313{314 if (sta->deflink.ht_cap.ht_supported) {315 sta_params->ht_ldpc_enabled =316 is_cap_supported(sta->deflink.ht_cap.cap,317 IEEE80211_HT_CAP_LDPC_CODING);318 }319}320 321static void wcn36xx_smd_set_sta_default_ht_params(322 struct wcn36xx_hal_config_sta_params *sta_params)323{324 sta_params->ht_capable = 1;325 sta_params->tx_channel_width_set = 1;326 sta_params->lsig_txop_protection = 1;327 sta_params->max_ampdu_size = 3;328 sta_params->max_ampdu_density = 5;329 sta_params->max_amsdu_size = 0;330 sta_params->sgi_20Mhz = 1;331 sta_params->sgi_40mhz = 1;332 sta_params->green_field_capable = 1;333 sta_params->delayed_ba_support = 0;334 sta_params->dsss_cck_mode_40mhz = 1;335}336 337static void wcn36xx_smd_set_sta_default_vht_params(struct wcn36xx *wcn,338 struct wcn36xx_hal_config_sta_params_v1 *sta_params)339{340 if (wcn->rf_id == RF_IRIS_WCN3680) {341 sta_params->vht_capable = 1;342 sta_params->vht_tx_mu_beamformee_capable = 1;343 } else {344 sta_params->vht_capable = 0;345 sta_params->vht_tx_mu_beamformee_capable = 0;346 }347 348 sta_params->vht_ldpc_enabled = 0;349 sta_params->vht_tx_channel_width_set = 0;350 sta_params->vht_tx_bf_enabled = 0;351}352 353static void wcn36xx_smd_set_sta_default_ht_ldpc_params(struct wcn36xx *wcn,354 struct wcn36xx_hal_config_sta_params_v1 *sta_params)355{356 if (wcn->rf_id == RF_IRIS_WCN3680)357 sta_params->ht_ldpc_enabled = 1;358 else359 sta_params->ht_ldpc_enabled = 0;360}361 362static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn,363 struct ieee80211_vif *vif,364 struct ieee80211_sta *sta,365 struct wcn36xx_hal_config_sta_params *sta_params)366{367 struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);368 struct wcn36xx_sta *sta_priv = NULL;369 if (vif->type == NL80211_IFTYPE_ADHOC ||370 vif->type == NL80211_IFTYPE_AP ||371 vif->type == NL80211_IFTYPE_MESH_POINT) {372 sta_params->type = 1;373 sta_params->sta_index = WCN36XX_HAL_STA_INVALID_IDX;374 } else {375 sta_params->type = 0;376 sta_params->sta_index = vif_priv->self_sta_index;377 }378 379 sta_params->listen_interval = WCN36XX_LISTEN_INTERVAL(wcn);380 381 /*382 * In STA mode ieee80211_sta contains bssid and ieee80211_vif383 * contains our mac address. In AP mode we are bssid so vif384 * contains bssid and ieee80211_sta contains mac.385 */386 if (NL80211_IFTYPE_STATION == vif->type)387 memcpy(&sta_params->mac, vif->addr, ETH_ALEN);388 else389 memcpy(&sta_params->bssid, vif->addr, ETH_ALEN);390 391 sta_params->encrypt_type = vif_priv->encrypt_type;392 sta_params->short_preamble_supported = true;393 394 sta_params->rifs_mode = 0;395 sta_params->rmf = 0;396 sta_params->action = 0;397 sta_params->uapsd = 0;398 sta_params->mimo_ps = WCN36XX_HAL_HT_MIMO_PS_STATIC;399 sta_params->max_ampdu_duration = 0;400 sta_params->bssid_index = vif_priv->bss_index;401 sta_params->p2p = 0;402 403 if (sta) {404 sta_priv = wcn36xx_sta_to_priv(sta);405 if (NL80211_IFTYPE_STATION == vif->type)406 memcpy(&sta_params->bssid, sta->addr, ETH_ALEN);407 else408 memcpy(&sta_params->mac, sta->addr, ETH_ALEN);409 sta_params->wmm_enabled = sta->wme;410 sta_params->max_sp_len = sta->max_sp;411 sta_params->aid = sta_priv->aid;412 wcn36xx_smd_set_sta_ht_params(sta, sta_params);413 memcpy(&sta_params->supported_rates, &sta_priv->supported_rates,414 sizeof(struct wcn36xx_hal_supported_rates));415 } else {416 wcn36xx_set_default_rates((struct wcn36xx_hal_supported_rates *)417 &sta_params->supported_rates);418 wcn36xx_smd_set_sta_default_ht_params(sta_params);419 }420}421 422static int wcn36xx_smd_send_and_wait(struct wcn36xx *wcn, size_t len)423{424 int ret;425 unsigned long start;426 struct wcn36xx_hal_msg_header *hdr =427 (struct wcn36xx_hal_msg_header *)wcn->hal_buf;428 u16 req_type = hdr->msg_type;429 430 wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "HAL >>> ", wcn->hal_buf, len);431 432 init_completion(&wcn->hal_rsp_compl);433 start = jiffies;434 ret = rpmsg_send(wcn->smd_channel, wcn->hal_buf, len);435 if (ret) {436 wcn36xx_err("HAL TX failed for req %d\n", req_type);437 goto out;438 }439 if (wait_for_completion_timeout(&wcn->hal_rsp_compl,440 msecs_to_jiffies(HAL_MSG_TIMEOUT)) <= 0) {441 wcn36xx_err("Timeout! No SMD response to req %d in %dms\n",442 req_type, HAL_MSG_TIMEOUT);443 ret = -ETIME;444 goto out;445 }446 wcn36xx_dbg(WCN36XX_DBG_SMD,447 "SMD command (req %d, rsp %d) completed in %dms\n",448 req_type, hdr->msg_type,449 jiffies_to_msecs(jiffies - start));450out:451 return ret;452}453 454#define __INIT_HAL_MSG(msg_body, type, version) \455 do { \456 memset(&(msg_body), 0, sizeof(msg_body)); \457 (msg_body).header.msg_type = type; \458 (msg_body).header.msg_version = version; \459 (msg_body).header.len = sizeof(msg_body); \460 } while (0) \461 462#define INIT_HAL_MSG(msg_body, type) \463 __INIT_HAL_MSG(msg_body, type, WCN36XX_HAL_MSG_VERSION0)464 465#define INIT_HAL_MSG_V1(msg_body, type) \466 __INIT_HAL_MSG(msg_body, type, WCN36XX_HAL_MSG_VERSION1)467 468#define INIT_HAL_PTT_MSG(p_msg_body, ppt_msg_len) \469 do { \470 memset(p_msg_body, 0, sizeof(*p_msg_body) + ppt_msg_len); \471 p_msg_body->header.msg_type = WCN36XX_HAL_PROCESS_PTT_REQ; \472 p_msg_body->header.msg_version = WCN36XX_HAL_MSG_VERSION0; \473 p_msg_body->header.len = sizeof(*p_msg_body) + ppt_msg_len; \474 } while (0)475 476#define PREPARE_HAL_BUF(send_buf, msg_body) \477 do { \478 memcpy_and_pad(send_buf, msg_body.header.len, \479 &msg_body, sizeof(msg_body), 0); \480 } while (0) \481 482#define PREPARE_HAL_PTT_MSG_BUF(send_buf, p_msg_body) \483 do { \484 memcpy(send_buf, p_msg_body, p_msg_body->header.len); \485 } while (0)486 487static int wcn36xx_smd_rsp_status_check(void *buf, size_t len)488{489 struct wcn36xx_fw_msg_status_rsp *rsp;490 491 if (len < sizeof(struct wcn36xx_hal_msg_header) +492 sizeof(struct wcn36xx_fw_msg_status_rsp))493 return -EIO;494 495 rsp = (struct wcn36xx_fw_msg_status_rsp *)496 (buf + sizeof(struct wcn36xx_hal_msg_header));497 498 if (WCN36XX_FW_MSG_RESULT_SUCCESS != rsp->status)499 return rsp->status;500 501 return 0;502}503 504int wcn36xx_smd_load_nv(struct wcn36xx *wcn)505{506 struct nv_data *nv_d;507 struct wcn36xx_hal_nv_img_download_req_msg msg_body;508 int fw_bytes_left;509 int ret;510 u16 fm_offset = 0;511 512 if (!wcn->nv) {513 ret = request_firmware(&wcn->nv, wcn->nv_file, wcn->dev);514 if (ret) {515 wcn36xx_err("Failed to load nv file %s: %d\n",516 wcn->nv_file, ret);517 goto out;518 }519 }520 521 nv_d = (struct nv_data *)wcn->nv->data;522 INIT_HAL_MSG(msg_body, WCN36XX_HAL_DOWNLOAD_NV_REQ);523 524 msg_body.header.len += WCN36XX_NV_FRAGMENT_SIZE;525 526 msg_body.frag_number = 0;527 /* hal_buf must be protected with mutex */528 mutex_lock(&wcn->hal_mutex);529 530 do {531 fw_bytes_left = wcn->nv->size - fm_offset - 4;532 if (fw_bytes_left > WCN36XX_NV_FRAGMENT_SIZE) {533 msg_body.last_fragment = 0;534 msg_body.nv_img_buffer_size = WCN36XX_NV_FRAGMENT_SIZE;535 } else {536 msg_body.last_fragment = 1;537 msg_body.nv_img_buffer_size = fw_bytes_left;538 539 /* Do not forget update general message len */540 msg_body.header.len = sizeof(msg_body) + fw_bytes_left;541 542 }543 544 /* Add load NV request message header */545 memcpy(wcn->hal_buf, &msg_body, sizeof(msg_body));546 547 /* Add NV body itself */548 memcpy(wcn->hal_buf + sizeof(msg_body),549 &nv_d->table + fm_offset,550 msg_body.nv_img_buffer_size);551 552 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);553 if (ret)554 goto out_unlock;555 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf,556 wcn->hal_rsp_len);557 if (ret) {558 wcn36xx_err("hal_load_nv response failed err=%d\n",559 ret);560 goto out_unlock;561 }562 msg_body.frag_number++;563 fm_offset += WCN36XX_NV_FRAGMENT_SIZE;564 565 } while (msg_body.last_fragment != 1);566 567out_unlock:568 mutex_unlock(&wcn->hal_mutex);569out: return ret;570}571 572static int wcn36xx_smd_start_rsp(struct wcn36xx *wcn, void *buf, size_t len)573{574 struct wcn36xx_hal_mac_start_rsp_msg *rsp;575 576 if (len < sizeof(*rsp))577 return -EIO;578 579 rsp = buf;580 581 if (WCN36XX_FW_MSG_RESULT_SUCCESS != rsp->start_rsp_params.status)582 return -EIO;583 584 memcpy(wcn->crm_version, rsp->start_rsp_params.crm_version,585 WCN36XX_HAL_VERSION_LENGTH);586 memcpy(wcn->wlan_version, rsp->start_rsp_params.wlan_version,587 WCN36XX_HAL_VERSION_LENGTH);588 589 /* null terminate the strings, just in case */590 wcn->crm_version[WCN36XX_HAL_VERSION_LENGTH] = '\0';591 wcn->wlan_version[WCN36XX_HAL_VERSION_LENGTH] = '\0';592 593 wcn->fw_revision = rsp->start_rsp_params.version.revision;594 wcn->fw_version = rsp->start_rsp_params.version.version;595 wcn->fw_minor = rsp->start_rsp_params.version.minor;596 wcn->fw_major = rsp->start_rsp_params.version.major;597 598 if (wcn->first_boot) {599 wcn->first_boot = false;600 wcn36xx_info("firmware WLAN version '%s' and CRM version '%s'\n",601 wcn->wlan_version, wcn->crm_version);602 603 wcn36xx_info("firmware API %u.%u.%u.%u, %u stations, %u bssids\n",604 wcn->fw_major, wcn->fw_minor,605 wcn->fw_version, wcn->fw_revision,606 rsp->start_rsp_params.stations,607 rsp->start_rsp_params.bssids);608 }609 return 0;610}611 612int wcn36xx_smd_start(struct wcn36xx *wcn)613{614 struct wcn36xx_hal_mac_start_req_msg msg_body, *body;615 int ret;616 int i;617 size_t len;618 int cfg_elements;619 static struct wcn36xx_cfg_val *cfg_vals;620 621 mutex_lock(&wcn->hal_mutex);622 INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_REQ);623 624 msg_body.params.type = DRIVER_TYPE_PRODUCTION;625 msg_body.params.len = 0;626 627 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);628 629 body = (struct wcn36xx_hal_mac_start_req_msg *)wcn->hal_buf;630 len = body->header.len;631 632 if (wcn->rf_id == RF_IRIS_WCN3680) {633 cfg_vals = wcn3680_cfg_vals;634 cfg_elements = ARRAY_SIZE(wcn3680_cfg_vals);635 } else {636 cfg_vals = wcn36xx_cfg_vals;637 cfg_elements = ARRAY_SIZE(wcn36xx_cfg_vals);638 }639 640 for (i = 0; i < cfg_elements; i++) {641 ret = put_cfg_tlv_u32(wcn, &len, cfg_vals[i].cfg_id,642 cfg_vals[i].value);643 if (ret)644 goto out;645 }646 body->header.len = len;647 body->params.len = len - sizeof(*body);648 649 wcn36xx_dbg(WCN36XX_DBG_HAL, "hal start type %d\n",650 msg_body.params.type);651 652 ret = wcn36xx_smd_send_and_wait(wcn, body->header.len);653 if (ret) {654 wcn36xx_err("Sending hal_start failed\n");655 goto out;656 }657 658 ret = wcn36xx_smd_start_rsp(wcn, wcn->hal_buf, wcn->hal_rsp_len);659 if (ret) {660 wcn36xx_err("hal_start response failed err=%d\n", ret);661 goto out;662 }663 664out:665 mutex_unlock(&wcn->hal_mutex);666 return ret;667}668 669int wcn36xx_smd_stop(struct wcn36xx *wcn)670{671 struct wcn36xx_hal_mac_stop_req_msg msg_body;672 int ret;673 674 mutex_lock(&wcn->hal_mutex);675 INIT_HAL_MSG(msg_body, WCN36XX_HAL_STOP_REQ);676 677 msg_body.stop_req_params.reason = HAL_STOP_TYPE_RF_KILL;678 679 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);680 681 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);682 if (ret) {683 wcn36xx_err("Sending hal_stop failed\n");684 goto out;685 }686 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);687 if (ret) {688 wcn36xx_err("hal_stop response failed err=%d\n", ret);689 goto out;690 }691out:692 mutex_unlock(&wcn->hal_mutex);693 return ret;694}695 696int wcn36xx_smd_init_scan(struct wcn36xx *wcn, enum wcn36xx_hal_sys_mode mode,697 struct ieee80211_vif *vif)698{699 struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);700 struct wcn36xx_hal_init_scan_req_msg msg_body;701 int ret;702 703 mutex_lock(&wcn->hal_mutex);704 INIT_HAL_MSG(msg_body, WCN36XX_HAL_INIT_SCAN_REQ);705 706 msg_body.mode = mode;707 if (vif_priv->bss_index != WCN36XX_HAL_BSS_INVALID_IDX) {708 /* Notify BSSID with null DATA packet */709 msg_body.frame_type = 2;710 msg_body.notify = 1;711 msg_body.scan_entry.bss_index[0] = vif_priv->bss_index;712 msg_body.scan_entry.active_bss_count = 1;713 }714 715 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);716 717 wcn36xx_dbg(WCN36XX_DBG_HAL, "hal init scan mode %d\n", msg_body.mode);718 719 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);720 if (ret) {721 wcn36xx_err("Sending hal_init_scan failed\n");722 goto out;723 }724 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);725 if (ret) {726 wcn36xx_err("hal_init_scan response failed err=%d\n", ret);727 goto out;728 }729 wcn->sw_scan_init = true;730out:731 mutex_unlock(&wcn->hal_mutex);732 return ret;733}734 735int wcn36xx_smd_start_scan(struct wcn36xx *wcn, u8 scan_channel)736{737 struct wcn36xx_hal_start_scan_req_msg msg_body;738 int ret;739 740 mutex_lock(&wcn->hal_mutex);741 INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_SCAN_REQ);742 743 msg_body.scan_channel = scan_channel;744 745 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);746 747 wcn36xx_dbg(WCN36XX_DBG_HAL, "hal start scan channel %d\n",748 msg_body.scan_channel);749 750 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);751 if (ret) {752 wcn36xx_err("Sending hal_start_scan failed\n");753 goto out;754 }755 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);756 if (ret) {757 wcn36xx_err("hal_start_scan response failed err=%d\n", ret);758 goto out;759 }760 wcn->sw_scan_channel = scan_channel;761out:762 mutex_unlock(&wcn->hal_mutex);763 return ret;764}765 766int wcn36xx_smd_end_scan(struct wcn36xx *wcn, u8 scan_channel)767{768 struct wcn36xx_hal_end_scan_req_msg msg_body;769 int ret;770 771 mutex_lock(&wcn->hal_mutex);772 INIT_HAL_MSG(msg_body, WCN36XX_HAL_END_SCAN_REQ);773 774 msg_body.scan_channel = scan_channel;775 776 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);777 778 wcn36xx_dbg(WCN36XX_DBG_HAL, "hal end scan channel %d\n",779 msg_body.scan_channel);780 781 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);782 if (ret) {783 wcn36xx_err("Sending hal_end_scan failed\n");784 goto out;785 }786 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);787 if (ret) {788 wcn36xx_err("hal_end_scan response failed err=%d\n", ret);789 goto out;790 }791 wcn->sw_scan_channel = 0;792out:793 mutex_unlock(&wcn->hal_mutex);794 return ret;795}796 797int wcn36xx_smd_finish_scan(struct wcn36xx *wcn,798 enum wcn36xx_hal_sys_mode mode,799 struct ieee80211_vif *vif)800{801 struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);802 struct wcn36xx_hal_finish_scan_req_msg msg_body;803 int ret;804 805 mutex_lock(&wcn->hal_mutex);806 INIT_HAL_MSG(msg_body, WCN36XX_HAL_FINISH_SCAN_REQ);807 808 msg_body.mode = mode;809 msg_body.oper_channel = WCN36XX_HW_CHANNEL(wcn);810 if (vif_priv->bss_index != WCN36XX_HAL_BSS_INVALID_IDX) {811 /* Notify BSSID with null data packet */812 msg_body.notify = 1;813 msg_body.frame_type = 2;814 msg_body.scan_entry.bss_index[0] = vif_priv->bss_index;815 msg_body.scan_entry.active_bss_count = 1;816 }817 818 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);819 820 wcn36xx_dbg(WCN36XX_DBG_HAL, "hal finish scan mode %d\n",821 msg_body.mode);822 823 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);824 if (ret) {825 wcn36xx_err("Sending hal_finish_scan failed\n");826 goto out;827 }828 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);829 if (ret) {830 wcn36xx_err("hal_finish_scan response failed err=%d\n", ret);831 goto out;832 }833 wcn->sw_scan_init = false;834out:835 mutex_unlock(&wcn->hal_mutex);836 return ret;837}838 839int wcn36xx_smd_start_hw_scan(struct wcn36xx *wcn, struct ieee80211_vif *vif,840 struct cfg80211_scan_request *req)841{842 struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);843 struct wcn36xx_hal_start_scan_offload_req_msg *msg_body;844 int ret, i;845 846 if (req->ie_len > WCN36XX_MAX_SCAN_IE_LEN)847 return -EINVAL;848 849 mutex_lock(&wcn->hal_mutex);850 msg_body = kzalloc(sizeof(*msg_body), GFP_KERNEL);851 if (!msg_body) {852 ret = -ENOMEM;853 goto out;854 }855 856 INIT_HAL_MSG((*msg_body), WCN36XX_HAL_START_SCAN_OFFLOAD_REQ);857 858 msg_body->scan_type = WCN36XX_HAL_SCAN_TYPE_ACTIVE;859 msg_body->min_ch_time = 30;860 msg_body->max_ch_time = 100;861 msg_body->scan_hidden = 1;862 memcpy(msg_body->mac, vif->addr, ETH_ALEN);863 msg_body->bss_type = vif_priv->bss_type;864 msg_body->p2p_search = vif->p2p;865 866 msg_body->num_ssid = min_t(u8, req->n_ssids, ARRAY_SIZE(msg_body->ssids));867 for (i = 0; i < msg_body->num_ssid; i++) {868 msg_body->ssids[i].length = min_t(u8, req->ssids[i].ssid_len,869 sizeof(msg_body->ssids[i].ssid));870 memcpy(msg_body->ssids[i].ssid, req->ssids[i].ssid,871 msg_body->ssids[i].length);872 }873 874 msg_body->num_channel = min_t(u8, req->n_channels,875 sizeof(msg_body->channels));876 for (i = 0; i < msg_body->num_channel; i++) {877 msg_body->channels[i] =878 HW_VALUE_CHANNEL(req->channels[i]->hw_value);879 }880 881 msg_body->header.len -= WCN36XX_MAX_SCAN_IE_LEN;882 883 if (req->ie_len > 0) {884 msg_body->ie_len = req->ie_len;885 msg_body->header.len += req->ie_len;886 memcpy(msg_body->ie, req->ie, req->ie_len);887 }888 889 PREPARE_HAL_BUF(wcn->hal_buf, (*msg_body));890 891 wcn36xx_dbg(WCN36XX_DBG_HAL,892 "hal start hw-scan (channels: %u; ssids: %u; p2p: %s)\n",893 msg_body->num_channel, msg_body->num_ssid,894 msg_body->p2p_search ? "yes" : "no");895 896 ret = wcn36xx_smd_send_and_wait(wcn, msg_body->header.len);897 if (ret) {898 wcn36xx_err("Sending hal_start_scan_offload failed\n");899 goto out;900 }901 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);902 if (ret) {903 wcn36xx_err("hal_start_scan_offload response failed err=%d\n",904 ret);905 goto out;906 }907out:908 kfree(msg_body);909 mutex_unlock(&wcn->hal_mutex);910 return ret;911}912 913int wcn36xx_smd_stop_hw_scan(struct wcn36xx *wcn)914{915 struct wcn36xx_hal_stop_scan_offload_req_msg msg_body;916 int ret;917 918 mutex_lock(&wcn->hal_mutex);919 INIT_HAL_MSG(msg_body, WCN36XX_HAL_STOP_SCAN_OFFLOAD_REQ);920 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);921 922 wcn36xx_dbg(WCN36XX_DBG_HAL, "hal stop hw-scan\n");923 924 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);925 if (ret) {926 wcn36xx_err("Sending hal_stop_scan_offload failed\n");927 goto out;928 }929 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);930 if (ret) {931 wcn36xx_err("hal_stop_scan_offload response failed err=%d\n",932 ret);933 goto out;934 }935out:936 mutex_unlock(&wcn->hal_mutex);937 return ret;938}939 940int wcn36xx_smd_update_channel_list(struct wcn36xx *wcn, struct cfg80211_scan_request *req)941{942 struct wcn36xx_hal_update_channel_list_req_msg *msg_body;943 int ret, i;944 945 msg_body = kzalloc(sizeof(*msg_body), GFP_KERNEL);946 if (!msg_body)947 return -ENOMEM;948 949 INIT_HAL_MSG((*msg_body), WCN36XX_HAL_UPDATE_CHANNEL_LIST_REQ);950 951 msg_body->num_channel = min_t(u8, req->n_channels, ARRAY_SIZE(msg_body->channels));952 for (i = 0; i < msg_body->num_channel; i++) {953 struct wcn36xx_hal_channel_param *param = &msg_body->channels[i];954 u32 min_power = WCN36XX_HAL_DEFAULT_MIN_POWER;955 u32 ant_gain = WCN36XX_HAL_DEFAULT_ANT_GAIN;956 957 param->mhz = req->channels[i]->center_freq;958 param->band_center_freq1 = req->channels[i]->center_freq;959 param->band_center_freq2 = 0;960 961 if (req->channels[i]->flags & IEEE80211_CHAN_NO_IR)962 param->channel_info |= WCN36XX_HAL_CHAN_INFO_FLAG_PASSIVE;963 964 if (req->channels[i]->flags & IEEE80211_CHAN_RADAR)965 param->channel_info |= WCN36XX_HAL_CHAN_INFO_FLAG_DFS;966 967 if (req->channels[i]->band == NL80211_BAND_5GHZ) {968 param->channel_info |= WCN36XX_HAL_CHAN_INFO_FLAG_HT;969 param->channel_info |= WCN36XX_HAL_CHAN_INFO_FLAG_VHT;970 param->channel_info |= WCN36XX_HAL_CHAN_INFO_PHY_11A;971 } else {972 param->channel_info |= WCN36XX_HAL_CHAN_INFO_PHY_11BG;973 }974 975 if (min_power > req->channels[i]->max_power)976 min_power = req->channels[i]->max_power;977 978 if (req->channels[i]->max_antenna_gain)979 ant_gain = req->channels[i]->max_antenna_gain;980 981 u32p_replace_bits(¶m->reg_info_1, min_power,982 WCN36XX_HAL_CHAN_REG1_MIN_PWR_MASK);983 u32p_replace_bits(¶m->reg_info_1, req->channels[i]->max_power,984 WCN36XX_HAL_CHAN_REG1_MAX_PWR_MASK);985 u32p_replace_bits(¶m->reg_info_1, req->channels[i]->max_reg_power,986 WCN36XX_HAL_CHAN_REG1_REG_PWR_MASK);987 u32p_replace_bits(¶m->reg_info_1, 0,988 WCN36XX_HAL_CHAN_REG1_CLASS_ID_MASK);989 u32p_replace_bits(¶m->reg_info_2, ant_gain,990 WCN36XX_HAL_CHAN_REG2_ANT_GAIN_MASK);991 992 wcn36xx_dbg(WCN36XX_DBG_HAL,993 "%s: freq=%u, channel_info=%08x, reg_info1=%08x, reg_info2=%08x\n",994 __func__, param->mhz, param->channel_info, param->reg_info_1,995 param->reg_info_2);996 }997 998 mutex_lock(&wcn->hal_mutex);999 1000 PREPARE_HAL_BUF(wcn->hal_buf, (*msg_body));1001 1002 ret = wcn36xx_smd_send_and_wait(wcn, msg_body->header.len);1003 if (ret) {1004 wcn36xx_err("Sending hal_update_channel_list failed\n");1005 goto out;1006 }1007 1008 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);1009 if (ret) {1010 wcn36xx_err("hal_update_channel_list response failed err=%d\n", ret);1011 goto out;1012 }1013 1014out:1015 kfree(msg_body);1016 mutex_unlock(&wcn->hal_mutex);1017 return ret;1018}1019 1020static int wcn36xx_smd_switch_channel_rsp(void *buf, size_t len)1021{1022 struct wcn36xx_hal_switch_channel_rsp_msg *rsp;1023 int ret;1024 1025 ret = wcn36xx_smd_rsp_status_check(buf, len);1026 if (ret)1027 return ret;1028 rsp = buf;1029 wcn36xx_dbg(WCN36XX_DBG_HAL, "channel switched to: %d, status: %d\n",1030 rsp->channel_number, rsp->status);1031 return ret;1032}1033 1034int wcn36xx_smd_switch_channel(struct wcn36xx *wcn,1035 struct ieee80211_vif *vif, int ch)1036{1037 struct wcn36xx_hal_switch_channel_req_msg msg_body;1038 int ret;1039 1040 mutex_lock(&wcn->hal_mutex);1041 INIT_HAL_MSG(msg_body, WCN36XX_HAL_CH_SWITCH_REQ);1042 1043 msg_body.channel_number = (u8)ch;1044 msg_body.tx_mgmt_power = 0xbf;1045 msg_body.max_tx_power = 0xbf;1046 memcpy(msg_body.self_sta_mac_addr, vif->addr, ETH_ALEN);1047 1048 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);1049 1050 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);1051 if (ret) {1052 wcn36xx_err("Sending hal_switch_channel failed\n");1053 goto out;1054 }1055 ret = wcn36xx_smd_switch_channel_rsp(wcn->hal_buf, wcn->hal_rsp_len);1056 if (ret) {1057 wcn36xx_err("hal_switch_channel response failed err=%d\n", ret);1058 goto out;1059 }1060out:1061 mutex_unlock(&wcn->hal_mutex);1062 return ret;1063}1064 1065static int wcn36xx_smd_process_ptt_msg_rsp(void *buf, size_t len,1066 void **p_ptt_rsp_msg)1067{1068 struct wcn36xx_hal_process_ptt_msg_rsp_msg *rsp;1069 int ret;1070 1071 ret = wcn36xx_smd_rsp_status_check(buf, len);1072 if (ret)1073 return ret;1074 1075 rsp = buf;1076 1077 wcn36xx_dbg(WCN36XX_DBG_HAL, "process ptt msg responded with length %d\n",1078 rsp->header.len);1079 wcn36xx_dbg_dump(WCN36XX_DBG_HAL_DUMP, "HAL_PTT_MSG_RSP:", rsp->ptt_msg,1080 rsp->header.len - sizeof(rsp->ptt_msg_resp_status));1081 1082 if (rsp->header.len > 0) {1083 *p_ptt_rsp_msg = kmemdup(rsp->ptt_msg, rsp->header.len,1084 GFP_ATOMIC);1085 if (!*p_ptt_rsp_msg)1086 return -ENOMEM;1087 }1088 return ret;1089}1090 1091int wcn36xx_smd_process_ptt_msg(struct wcn36xx *wcn,1092 struct ieee80211_vif *vif, void *ptt_msg, size_t len,1093 void **ptt_rsp_msg)1094{1095 struct wcn36xx_hal_process_ptt_msg_req_msg *p_msg_body;1096 int ret;1097 1098 mutex_lock(&wcn->hal_mutex);1099 p_msg_body = kmalloc(1100 sizeof(struct wcn36xx_hal_process_ptt_msg_req_msg) + len,1101 GFP_ATOMIC);1102 if (!p_msg_body) {1103 ret = -ENOMEM;1104 goto out_nomem;1105 }1106 INIT_HAL_PTT_MSG(p_msg_body, len);1107 1108 memcpy(&p_msg_body->ptt_msg, ptt_msg, len);1109 1110 PREPARE_HAL_PTT_MSG_BUF(wcn->hal_buf, p_msg_body);1111 1112 ret = wcn36xx_smd_send_and_wait(wcn, p_msg_body->header.len);1113 if (ret) {1114 wcn36xx_err("Sending hal_process_ptt_msg failed\n");1115 goto out;1116 }1117 ret = wcn36xx_smd_process_ptt_msg_rsp(wcn->hal_buf, wcn->hal_rsp_len,1118 ptt_rsp_msg);1119 if (ret) {1120 wcn36xx_err("process_ptt_msg response failed err=%d\n", ret);1121 goto out;1122 }1123out:1124 kfree(p_msg_body);1125out_nomem:1126 mutex_unlock(&wcn->hal_mutex);1127 return ret;1128}1129 1130static int wcn36xx_smd_update_scan_params_rsp(void *buf, size_t len)1131{1132 struct wcn36xx_hal_update_scan_params_resp *rsp;1133 1134 rsp = buf;1135 1136 /* Remove the PNO version bit */1137 rsp->status &= (~(WCN36XX_FW_MSG_PNO_VERSION_MASK));1138 1139 if (WCN36XX_FW_MSG_RESULT_SUCCESS != rsp->status) {1140 wcn36xx_warn("error response from update scan\n");1141 return rsp->status;1142 }1143 1144 return 0;1145}1146 1147int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn,1148 u8 *channels, size_t channel_count)1149{1150 struct wcn36xx_hal_update_scan_params_req_ex msg_body;1151 int ret;1152 1153 mutex_lock(&wcn->hal_mutex);1154 INIT_HAL_MSG(msg_body, WCN36XX_HAL_UPDATE_SCAN_PARAM_REQ);1155 1156 msg_body.dot11d_enabled = false;1157 msg_body.dot11d_resolved = true;1158 1159 msg_body.channel_count = channel_count;1160 memcpy(msg_body.channels, channels, channel_count);1161 msg_body.active_min_ch_time = 60;1162 msg_body.active_max_ch_time = 120;1163 msg_body.passive_min_ch_time = 60;1164 msg_body.passive_max_ch_time = 110;1165 msg_body.state = PHY_SINGLE_CHANNEL_CENTERED;1166 1167 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);1168 1169 wcn36xx_dbg(WCN36XX_DBG_HAL,1170 "hal update scan params channel_count %d\n",1171 msg_body.channel_count);1172 1173 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);1174 if (ret) {1175 wcn36xx_err("Sending hal_update_scan_params failed\n");1176 goto out;1177 }1178 ret = wcn36xx_smd_update_scan_params_rsp(wcn->hal_buf,1179 wcn->hal_rsp_len);1180 if (ret) {1181 wcn36xx_err("hal_update_scan_params response failed err=%d\n",1182 ret);1183 goto out;1184 }1185out:1186 mutex_unlock(&wcn->hal_mutex);1187 return ret;1188}1189 1190static int wcn36xx_smd_add_sta_self_rsp(struct wcn36xx *wcn,1191 struct ieee80211_vif *vif,1192 void *buf,1193 size_t len)1194{1195 struct wcn36xx_hal_add_sta_self_rsp_msg *rsp;1196 struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);1197 1198 if (len < sizeof(*rsp))1199 return -EINVAL;1200 1201 rsp = buf;1202 1203 if (rsp->status != WCN36XX_FW_MSG_RESULT_SUCCESS) {1204 wcn36xx_warn("hal add sta self failure: %d\n",1205 rsp->status);1206 return rsp->status;1207 }1208 1209 wcn36xx_dbg(WCN36XX_DBG_HAL,1210 "hal add sta self status %d self_sta_index %d dpu_index %d\n",1211 rsp->status, rsp->self_sta_index, rsp->dpu_index);1212 1213 vif_priv->self_sta_index = rsp->self_sta_index;1214 vif_priv->self_dpu_desc_index = rsp->dpu_index;1215 1216 return 0;1217}1218 1219int wcn36xx_smd_add_sta_self(struct wcn36xx *wcn, struct ieee80211_vif *vif)1220{1221 struct wcn36xx_hal_add_sta_self_req msg_body;1222 int ret;1223 1224 mutex_lock(&wcn->hal_mutex);1225 INIT_HAL_MSG(msg_body, WCN36XX_HAL_ADD_STA_SELF_REQ);1226 1227 memcpy(&msg_body.self_addr, vif->addr, ETH_ALEN);1228 1229 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);1230 1231 wcn36xx_dbg(WCN36XX_DBG_HAL,1232 "hal add sta self self_addr %pM status %d\n",1233 msg_body.self_addr, msg_body.status);1234 1235 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);1236 if (ret) {1237 wcn36xx_err("Sending hal_add_sta_self failed\n");1238 goto out;1239 }1240 ret = wcn36xx_smd_add_sta_self_rsp(wcn,1241 vif,1242 wcn->hal_buf,1243 wcn->hal_rsp_len);1244 if (ret) {1245 wcn36xx_err("hal_add_sta_self response failed err=%d\n", ret);1246 goto out;1247 }1248out:1249 mutex_unlock(&wcn->hal_mutex);1250 return ret;1251}1252 1253int wcn36xx_smd_delete_sta_self(struct wcn36xx *wcn, u8 *addr)1254{1255 struct wcn36xx_hal_del_sta_self_req_msg msg_body;1256 int ret;1257 1258 mutex_lock(&wcn->hal_mutex);1259 INIT_HAL_MSG(msg_body, WCN36XX_HAL_DEL_STA_SELF_REQ);1260 1261 memcpy(&msg_body.self_addr, addr, ETH_ALEN);1262 1263 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);1264 1265 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);1266 if (ret) {1267 wcn36xx_err("Sending hal_delete_sta_self failed\n");1268 goto out;1269 }1270 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);1271 if (ret) {1272 wcn36xx_err("hal_delete_sta_self response failed err=%d\n",1273 ret);1274 goto out;1275 }1276out:1277 mutex_unlock(&wcn->hal_mutex);1278 return ret;1279}1280 1281int wcn36xx_smd_delete_sta(struct wcn36xx *wcn, u8 sta_index)1282{1283 struct wcn36xx_hal_delete_sta_req_msg msg_body;1284 int ret;1285 1286 mutex_lock(&wcn->hal_mutex);1287 INIT_HAL_MSG(msg_body, WCN36XX_HAL_DELETE_STA_REQ);1288 1289 msg_body.sta_index = sta_index;1290 1291 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);1292 1293 wcn36xx_dbg(WCN36XX_DBG_HAL,1294 "hal delete sta sta_index %d\n",1295 msg_body.sta_index);1296 1297 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);1298 if (ret) {1299 wcn36xx_err("Sending hal_delete_sta failed\n");1300 goto out;1301 }1302 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);1303 if (ret) {1304 wcn36xx_err("hal_delete_sta response failed err=%d\n", ret);1305 goto out;1306 }1307out:1308 mutex_unlock(&wcn->hal_mutex);1309 return ret;1310}1311 1312static int wcn36xx_smd_join_rsp(void *buf, size_t len)1313{1314 struct wcn36xx_hal_join_rsp_msg *rsp;1315 1316 if (wcn36xx_smd_rsp_status_check(buf, len))1317 return -EIO;1318 1319 rsp = buf;1320 1321 wcn36xx_dbg(WCN36XX_DBG_HAL,1322 "hal rsp join status %d tx_mgmt_power %d\n",1323 rsp->status, rsp->tx_mgmt_power);1324 1325 return 0;1326}1327 1328int wcn36xx_smd_join(struct wcn36xx *wcn, const u8 *bssid, u8 *vif, u8 ch)1329{1330 struct wcn36xx_hal_join_req_msg msg_body;1331 int ret;1332 1333 mutex_lock(&wcn->hal_mutex);1334 INIT_HAL_MSG(msg_body, WCN36XX_HAL_JOIN_REQ);1335 1336 memcpy(&msg_body.bssid, bssid, ETH_ALEN);1337 memcpy(&msg_body.self_sta_mac_addr, vif, ETH_ALEN);1338 msg_body.channel = ch;1339 1340 if (conf_is_ht40_minus(&wcn->hw->conf))1341 msg_body.secondary_channel_offset =1342 PHY_DOUBLE_CHANNEL_HIGH_PRIMARY;1343 else if (conf_is_ht40_plus(&wcn->hw->conf))1344 msg_body.secondary_channel_offset =1345 PHY_DOUBLE_CHANNEL_LOW_PRIMARY;1346 else1347 msg_body.secondary_channel_offset =1348 PHY_SINGLE_CHANNEL_CENTERED;1349 1350 msg_body.link_state = WCN36XX_HAL_LINK_PREASSOC_STATE;1351 1352 msg_body.max_tx_power = 0xbf;1353 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);1354 1355 wcn36xx_dbg(WCN36XX_DBG_HAL,1356 "hal join req bssid %pM self_sta_mac_addr %pM channel %d link_state %d\n",1357 msg_body.bssid, msg_body.self_sta_mac_addr,1358 msg_body.channel, msg_body.link_state);1359 1360 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);1361 if (ret) {1362 wcn36xx_err("Sending hal_join failed\n");1363 goto out;1364 }1365 ret = wcn36xx_smd_join_rsp(wcn->hal_buf, wcn->hal_rsp_len);1366 if (ret) {1367 wcn36xx_err("hal_join response failed err=%d\n", ret);1368 goto out;1369 }1370out:1371 mutex_unlock(&wcn->hal_mutex);1372 return ret;1373}1374 1375int wcn36xx_smd_set_link_st(struct wcn36xx *wcn, const u8 *bssid,1376 const u8 *sta_mac,1377 enum wcn36xx_hal_link_state state)1378{1379 struct wcn36xx_hal_set_link_state_req_msg msg_body;1380 int ret;1381 1382 mutex_lock(&wcn->hal_mutex);1383 INIT_HAL_MSG(msg_body, WCN36XX_HAL_SET_LINK_ST_REQ);1384 1385 memcpy(&msg_body.bssid, bssid, ETH_ALEN);1386 memcpy(&msg_body.self_mac_addr, sta_mac, ETH_ALEN);1387 msg_body.state = state;1388 1389 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);1390 1391 wcn36xx_dbg(WCN36XX_DBG_HAL,1392 "hal set link state bssid %pM self_mac_addr %pM state %d\n",1393 msg_body.bssid, msg_body.self_mac_addr, msg_body.state);1394 1395 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);1396 if (ret) {1397 wcn36xx_err("Sending hal_set_link_st failed\n");1398 goto out;1399 }1400 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);1401 if (ret) {1402 wcn36xx_err("hal_set_link_st response failed err=%d\n", ret);1403 goto out;1404 }1405out:1406 mutex_unlock(&wcn->hal_mutex);1407 return ret;1408}1409 1410static void wcn36xx_smd_convert_sta_to_v1(struct wcn36xx *wcn,1411 const struct wcn36xx_hal_config_sta_params *orig,1412 struct wcn36xx_hal_config_sta_params_v1 *v1)1413{1414 /* convert orig to v1 format */1415 memcpy(&v1->bssid, orig->bssid, ETH_ALEN);1416 memcpy(&v1->mac, orig->mac, ETH_ALEN);1417 v1->aid = orig->aid;1418 v1->type = orig->type;1419 v1->short_preamble_supported = orig->short_preamble_supported;1420 v1->listen_interval = orig->listen_interval;1421 v1->wmm_enabled = orig->wmm_enabled;1422 v1->ht_capable = orig->ht_capable;1423 v1->tx_channel_width_set = orig->tx_channel_width_set;1424 v1->rifs_mode = orig->rifs_mode;1425 v1->lsig_txop_protection = orig->lsig_txop_protection;1426 v1->max_ampdu_size = orig->max_ampdu_size;1427 v1->max_ampdu_density = orig->max_ampdu_density;1428 v1->sgi_40mhz = orig->sgi_40mhz;1429 v1->sgi_20Mhz = orig->sgi_20Mhz;1430 v1->rmf = orig->rmf;1431 v1->encrypt_type = orig->encrypt_type;1432 v1->action = orig->action;1433 v1->uapsd = orig->uapsd;1434 v1->max_sp_len = orig->max_sp_len;1435 v1->green_field_capable = orig->green_field_capable;1436 v1->mimo_ps = orig->mimo_ps;1437 v1->delayed_ba_support = orig->delayed_ba_support;1438 v1->max_ampdu_duration = orig->max_ampdu_duration;1439 v1->dsss_cck_mode_40mhz = orig->dsss_cck_mode_40mhz;1440 memcpy(&v1->supported_rates, &orig->supported_rates,1441 sizeof(orig->supported_rates));1442 v1->sta_index = orig->sta_index;1443 v1->bssid_index = orig->bssid_index;1444 v1->p2p = orig->p2p;1445}1446 1447static void1448wcn36xx_smd_set_sta_params_v1(struct wcn36xx *wcn,1449 struct ieee80211_vif *vif,1450 struct ieee80211_sta *sta,1451 struct wcn36xx_hal_config_sta_params_v1 *sta_par)1452{1453 struct wcn36xx_sta *sta_priv = NULL;1454 struct wcn36xx_hal_config_sta_params sta_par_v0;1455 1456 wcn36xx_smd_set_sta_params(wcn, vif, sta, &sta_par_v0);1457 wcn36xx_smd_convert_sta_to_v1(wcn, &sta_par_v0, sta_par);1458 1459 if (sta) {1460 sta_priv = wcn36xx_sta_to_priv(sta);1461 wcn36xx_smd_set_sta_vht_params(wcn, sta, sta_par);1462 wcn36xx_smd_set_sta_ht_ldpc_params(sta, sta_par);1463 memcpy(&sta_par->supported_rates, &sta_priv->supported_rates,1464 sizeof(sta_par->supported_rates));1465 } else {1466 wcn36xx_set_default_rates_v1(&sta_par->supported_rates);1467 wcn36xx_smd_set_sta_default_vht_params(wcn, sta_par);1468 wcn36xx_smd_set_sta_default_ht_ldpc_params(wcn, sta_par);1469 }1470}1471 1472static int wcn36xx_smd_config_sta_rsp(struct wcn36xx *wcn,1473 struct ieee80211_sta *sta,1474 void *buf,1475 size_t len)1476{1477 struct wcn36xx_hal_config_sta_rsp_msg *rsp;1478 struct config_sta_rsp_params *params;1479 struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);1480 1481 if (len < sizeof(*rsp))1482 return -EINVAL;1483 1484 rsp = buf;1485 params = &rsp->params;1486 1487 if (params->status != WCN36XX_FW_MSG_RESULT_SUCCESS) {1488 wcn36xx_warn("hal config sta response failure: %d\n",1489 params->status);1490 return -EIO;1491 }1492 1493 sta_priv->sta_index = params->sta_index;1494 sta_priv->dpu_desc_index = params->dpu_index;1495 sta_priv->ucast_dpu_sign = params->uc_ucast_sig;1496 1497 wcn36xx_dbg(WCN36XX_DBG_HAL,1498 "hal config sta rsp status %d sta_index %d bssid_index %d uc_ucast_sig %d p2p %d\n",1499 params->status, params->sta_index, params->bssid_index,1500 params->uc_ucast_sig, params->p2p);1501 1502 return 0;1503}1504 1505static int wcn36xx_smd_config_sta_v1(struct wcn36xx *wcn,1506 struct ieee80211_vif *vif,1507 struct ieee80211_sta *sta)1508{1509 struct wcn36xx_hal_config_sta_req_msg_v1 msg_body;1510 struct wcn36xx_hal_config_sta_params_v1 *sta_params;1511 1512 if (wcn->rf_id == RF_IRIS_WCN3680) {1513 INIT_HAL_MSG_V1(msg_body, WCN36XX_HAL_CONFIG_STA_REQ);1514 } else {1515 INIT_HAL_MSG(msg_body, WCN36XX_HAL_CONFIG_STA_REQ);1516 msg_body.header.len -= WCN36XX_DIFF_STA_PARAMS_V1_NOVHT;1517 }1518 1519 sta_params = &msg_body.sta_params;1520 1521 wcn36xx_smd_set_sta_params_v1(wcn, vif, sta, sta_params);1522 1523 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);1524 1525 wcn36xx_dbg(WCN36XX_DBG_HAL,1526 "hal config sta v1 action %d sta_index %d bssid_index %d bssid %pM type %d mac %pM aid %d\n",1527 sta_params->action, sta_params->sta_index, sta_params->bssid_index,1528 sta_params->bssid, sta_params->type, sta_params->mac, sta_params->aid);1529 1530 return wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);1531}1532 1533static int wcn36xx_smd_config_sta_v0(struct wcn36xx *wcn,1534 struct ieee80211_vif *vif,1535 struct ieee80211_sta *sta)1536{1537 struct wcn36xx_hal_config_sta_req_msg msg;1538 struct wcn36xx_hal_config_sta_params *sta_params;1539 1540 INIT_HAL_MSG(msg, WCN36XX_HAL_CONFIG_STA_REQ);1541 1542 sta_params = &msg.sta_params;1543 1544 wcn36xx_smd_set_sta_params(wcn, vif, sta, sta_params);1545 1546 PREPARE_HAL_BUF(wcn->hal_buf, msg);1547 1548 wcn36xx_dbg(WCN36XX_DBG_HAL,1549 "hal config sta action %d sta_index %d bssid_index %d bssid %pM type %d mac %pM aid %d\n",1550 sta_params->action, sta_params->sta_index,1551 sta_params->bssid_index, sta_params->bssid,1552 sta_params->type, sta_params->mac, sta_params->aid);1553 1554 return wcn36xx_smd_send_and_wait(wcn, msg.header.len);1555}1556 1557int wcn36xx_smd_config_sta(struct wcn36xx *wcn, struct ieee80211_vif *vif,1558 struct ieee80211_sta *sta)1559{1560 int ret;1561 1562 mutex_lock(&wcn->hal_mutex);1563 1564 if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24))1565 ret = wcn36xx_smd_config_sta_v1(wcn, vif, sta);1566 else1567 ret = wcn36xx_smd_config_sta_v0(wcn, vif, sta);1568 1569 if (ret) {1570 wcn36xx_err("Sending hal_config_sta failed\n");1571 goto out;1572 }1573 ret = wcn36xx_smd_config_sta_rsp(wcn,1574 sta,1575 wcn->hal_buf,1576 wcn->hal_rsp_len);1577 if (ret) {1578 wcn36xx_err("hal_config_sta response failed err=%d\n", ret);1579 goto out;1580 }1581out:1582 mutex_unlock(&wcn->hal_mutex);1583 return ret;1584}1585 1586static void wcn36xx_smd_set_bss_params(struct wcn36xx *wcn,1587 struct ieee80211_vif *vif,1588 struct ieee80211_sta *sta,1589 const u8 *bssid,1590 bool update,1591 struct wcn36xx_hal_config_bss_params *bss)1592{1593 struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);1594 1595 WARN_ON(is_zero_ether_addr(bssid));1596 1597 memcpy(&bss->bssid, bssid, ETH_ALEN);1598 1599 memcpy(bss->self_mac_addr, vif->addr, ETH_ALEN);1600 1601 if (vif->type == NL80211_IFTYPE_STATION) {1602 bss->bss_type = WCN36XX_HAL_INFRASTRUCTURE_MODE;1603 1604 /* STA */1605 bss->oper_mode = 1;1606 bss->wcn36xx_hal_persona = WCN36XX_HAL_STA_MODE;1607 } else if (vif->type == NL80211_IFTYPE_AP ||1608 vif->type == NL80211_IFTYPE_MESH_POINT) {1609 bss->bss_type = WCN36XX_HAL_INFRA_AP_MODE;1610 1611 /* AP */1612 bss->oper_mode = 0;1613 bss->wcn36xx_hal_persona = WCN36XX_HAL_STA_SAP_MODE;1614 } else if (vif->type == NL80211_IFTYPE_ADHOC) {1615 bss->bss_type = WCN36XX_HAL_IBSS_MODE;1616 1617 /* STA */1618 bss->oper_mode = 1;1619 } else {1620 wcn36xx_warn("Unknown type for bss config: %d\n", vif->type);1621 }1622 1623 if (vif->type == NL80211_IFTYPE_STATION)1624 wcn36xx_smd_set_bss_nw_type(wcn, sta, bss);1625 else1626 bss->nw_type = WCN36XX_HAL_11N_NW_TYPE;1627 1628 bss->short_slot_time_supported = vif->bss_conf.use_short_slot;1629 bss->lla_coexist = 0;1630 bss->llb_coexist = 0;1631 bss->llg_coexist = 0;1632 bss->rifs_mode = 0;1633 bss->beacon_interval = vif->bss_conf.beacon_int;1634 bss->dtim_period = vif_priv->dtim_period;1635 1636 wcn36xx_smd_set_bss_ht_params(vif, sta, bss);1637 1638 bss->oper_channel = WCN36XX_HW_CHANNEL(wcn);1639 1640 if (conf_is_ht40_minus(&wcn->hw->conf))1641 bss->ext_channel = IEEE80211_HT_PARAM_CHA_SEC_BELOW;1642 else if (conf_is_ht40_plus(&wcn->hw->conf))1643 bss->ext_channel = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;1644 else1645 bss->ext_channel = IEEE80211_HT_PARAM_CHA_SEC_NONE;1646 1647 bss->reserved = 0;1648 1649 /* wcn->ssid is only valid in AP and IBSS mode */1650 bss->ssid.length = vif_priv->ssid.length;1651 memcpy(bss->ssid.ssid, vif_priv->ssid.ssid, vif_priv->ssid.length);1652 1653 bss->obss_prot_enabled = 0;1654 bss->rmf = 0;1655 bss->max_probe_resp_retry_limit = 0;1656 bss->hidden_ssid = vif->bss_conf.hidden_ssid;1657 bss->proxy_probe_resp = 0;1658 bss->edca_params_valid = 0;1659 1660 /* FIXME: set acbe, acbk, acvi and acvo */1661 1662 bss->ext_set_sta_key_param_valid = 0;1663 1664 /* FIXME: set ext_set_sta_key_param */1665 1666 bss->spectrum_mgt_enable = 0;1667 bss->tx_mgmt_power = 0;1668 bss->max_tx_power = WCN36XX_MAX_POWER(wcn);1669 bss->action = update;1670 1671 vif_priv->bss_type = bss->bss_type;1672}1673 1674static int wcn36xx_smd_config_bss_v1(struct wcn36xx *wcn,1675 struct ieee80211_vif *vif,1676 struct ieee80211_sta *sta_80211,1677 const u8 *bssid,1678 bool update)1679{1680 struct wcn36xx_hal_config_bss_req_msg_v1 *msg_body;1681 struct wcn36xx_hal_config_bss_params_v1 *bss;1682 struct wcn36xx_hal_config_bss_params bss_v0;1683 struct wcn36xx_hal_config_sta_params_v1 *sta;1684 struct cfg80211_chan_def *chandef;1685 int ret;1686 1687 msg_body = kzalloc(sizeof(*msg_body), GFP_KERNEL);1688 if (!msg_body)1689 return -ENOMEM;1690 1691 if (wcn->rf_id == RF_IRIS_WCN3680) {1692 INIT_HAL_MSG_V1((*msg_body), WCN36XX_HAL_CONFIG_BSS_REQ);1693 } else {1694 INIT_HAL_MSG((*msg_body), WCN36XX_HAL_CONFIG_BSS_REQ);1695 msg_body->header.len -= WCN36XX_DIFF_BSS_PARAMS_V1_NOVHT;1696 }1697 1698 bss = &msg_body->bss_params;1699 sta = &bss->sta;1700 1701 memset(&bss_v0, 0x00, sizeof(bss_v0));1702 wcn36xx_smd_set_bss_params(wcn, vif, sta_80211, bssid, update, &bss_v0);1703 wcn36xx_smd_set_sta_params_v1(wcn, vif, sta_80211, sta);1704 1705 /* convert orig to v1 */1706 memcpy(bss->bssid, &bss_v0.bssid, ETH_ALEN);1707 memcpy(bss->self_mac_addr, &bss_v0.self_mac_addr, ETH_ALEN);1708 1709 bss->bss_type = bss_v0.bss_type;1710 bss->oper_mode = bss_v0.oper_mode;1711 bss->nw_type = bss_v0.nw_type;1712 1713 bss->short_slot_time_supported =1714 bss_v0.short_slot_time_supported;1715 bss->lla_coexist = bss_v0.lla_coexist;1716 bss->llb_coexist = bss_v0.llb_coexist;1717 bss->llg_coexist = bss_v0.llg_coexist;1718 bss->ht20_coexist = bss_v0.ht20_coexist;1719 bss->lln_non_gf_coexist = bss_v0.lln_non_gf_coexist;1720 1721 bss->lsig_tx_op_protection_full_support =1722 bss_v0.lsig_tx_op_protection_full_support;1723 bss->rifs_mode = bss_v0.rifs_mode;1724 bss->beacon_interval = bss_v0.beacon_interval;1725 bss->dtim_period = bss_v0.dtim_period;1726 bss->tx_channel_width_set = bss_v0.tx_channel_width_set;1727 bss->oper_channel = bss_v0.oper_channel;1728 1729 if (wcn->hw->conf.chandef.width == NL80211_CHAN_WIDTH_80) {1730 chandef = &wcn->hw->conf.chandef;1731 bss->ext_channel = HW_VALUE_PHY(chandef->chan->hw_value);1732 } else {1733 bss->ext_channel = bss_v0.ext_channel;1734 }1735 1736 bss->reserved = bss_v0.reserved;1737 1738 memcpy(&bss->ssid, &bss_v0.ssid,1739 sizeof(bss_v0.ssid));1740 1741 bss->action = bss_v0.action;1742 bss->rateset = bss_v0.rateset;1743 bss->ht = bss_v0.ht;1744 bss->obss_prot_enabled = bss_v0.obss_prot_enabled;1745 bss->rmf = bss_v0.rmf;1746 bss->ht_oper_mode = bss_v0.ht_oper_mode;1747 bss->dual_cts_protection = bss_v0.dual_cts_protection;1748 1749 bss->max_probe_resp_retry_limit =1750 bss_v0.max_probe_resp_retry_limit;1751 bss->hidden_ssid = bss_v0.hidden_ssid;1752 bss->proxy_probe_resp = bss_v0.proxy_probe_resp;1753 bss->edca_params_valid = bss_v0.edca_params_valid;1754 1755 memcpy(&bss->acbe, &bss_v0.acbe,1756 sizeof(bss_v0.acbe));1757 memcpy(&bss->acbk, &bss_v0.acbk,1758 sizeof(bss_v0.acbk));1759 memcpy(&bss->acvi, &bss_v0.acvi,1760 sizeof(bss_v0.acvi));1761 memcpy(&bss->acvo, &bss_v0.acvo,1762 sizeof(bss_v0.acvo));1763 1764 bss->ext_set_sta_key_param_valid =1765 bss_v0.ext_set_sta_key_param_valid;1766 1767 memcpy(&bss->ext_set_sta_key_param,1768 &bss_v0.ext_set_sta_key_param,1769 sizeof(bss_v0.acvo));1770 1771 bss->wcn36xx_hal_persona = bss_v0.wcn36xx_hal_persona;1772 bss->spectrum_mgt_enable = bss_v0.spectrum_mgt_enable;1773 bss->tx_mgmt_power = bss_v0.tx_mgmt_power;1774 bss->max_tx_power = bss_v0.max_tx_power;1775 1776 wcn36xx_smd_set_bss_vht_params(vif, sta_80211, bss);1777 1778 PREPARE_HAL_BUF(wcn->hal_buf, (*msg_body));1779 1780 wcn36xx_dbg(WCN36XX_DBG_HAL,1781 "hal config bss v1 bssid %pM self_mac_addr %pM bss_type %d oper_mode %d nw_type %d\n",1782 bss->bssid, bss->self_mac_addr, bss->bss_type,1783 bss->oper_mode, bss->nw_type);1784 1785 wcn36xx_dbg(WCN36XX_DBG_HAL,1786 "- sta bssid %pM action %d sta_index %d bssid_index %d aid %d type %d mac %pM\n",1787 sta->bssid, sta->action, sta->sta_index,1788 sta->bssid_index, sta->aid, sta->type, sta->mac);1789 1790 ret = wcn36xx_smd_send_and_wait(wcn, msg_body->header.len);1791 kfree(msg_body);1792 1793 return ret;1794}1795 1796static int wcn36xx_smd_config_bss_v0(struct wcn36xx *wcn,1797 struct ieee80211_vif *vif,1798 struct ieee80211_sta *sta,1799 const u8 *bssid,1800 bool update)1801{1802 struct wcn36xx_hal_config_bss_req_msg *msg;1803 struct wcn36xx_hal_config_bss_params *bss;1804 struct wcn36xx_hal_config_sta_params *sta_params;1805 int ret;1806 1807 msg = kzalloc(sizeof(*msg), GFP_KERNEL);1808 if (!msg)1809 return -ENOMEM;1810 1811 INIT_HAL_MSG((*msg), WCN36XX_HAL_CONFIG_BSS_REQ);1812 1813 bss = &msg->bss_params;1814 sta_params = &bss->sta;1815 1816 wcn36xx_smd_set_bss_params(wcn, vif, sta, bssid, update, bss);1817 wcn36xx_smd_set_sta_params(wcn, vif, sta, sta_params);1818 1819 PREPARE_HAL_BUF(wcn->hal_buf, (*msg));1820 1821 wcn36xx_dbg(WCN36XX_DBG_HAL,1822 "hal config bss bssid %pM self_mac_addr %pM bss_type %d oper_mode %d nw_type %d\n",1823 bss->bssid, bss->self_mac_addr, bss->bss_type,1824 bss->oper_mode, bss->nw_type);1825 1826 wcn36xx_dbg(WCN36XX_DBG_HAL,1827 "- sta bssid %pM action %d sta_index %d bssid_index %d aid %d type %d mac %pM\n",1828 sta_params->bssid, sta_params->action,1829 sta_params->sta_index, sta_params->bssid_index,1830 sta_params->aid, sta_params->type,1831 sta_params->mac);1832 1833 ret = wcn36xx_smd_send_and_wait(wcn, msg->header.len);1834 kfree(msg);1835 1836 return ret;1837}1838 1839static int wcn36xx_smd_config_bss_rsp(struct wcn36xx *wcn,1840 struct ieee80211_vif *vif,1841 struct ieee80211_sta *sta,1842 void *buf,1843 size_t len)1844{1845 struct wcn36xx_hal_config_bss_rsp_msg *rsp;1846 struct wcn36xx_hal_config_bss_rsp_params *params;1847 struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);1848 1849 if (len < sizeof(*rsp))1850 return -EINVAL;1851 1852 rsp = buf;1853 params = &rsp->bss_rsp_params;1854 1855 if (params->status != WCN36XX_FW_MSG_RESULT_SUCCESS) {1856 wcn36xx_warn("hal config bss response failure: %d\n",1857 params->status);1858 return -EIO;1859 }1860 1861 wcn36xx_dbg(WCN36XX_DBG_HAL,1862 "hal config bss rsp status %d bss_idx %d dpu_desc_index %d"1863 " sta_idx %d self_idx %d bcast_idx %d mac %pM"1864 " power %d ucast_dpu_signature %d\n",1865 params->status, params->bss_index, params->dpu_desc_index,1866 params->bss_sta_index, params->bss_self_sta_index,1867 params->bss_bcast_sta_idx, params->mac,1868 params->tx_mgmt_power, params->ucast_dpu_signature);1869 1870 vif_priv->bss_index = params->bss_index;1871 1872 if (sta) {1873 struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);1874 sta_priv->bss_sta_index = params->bss_sta_index;1875 sta_priv->bss_dpu_desc_index = params->dpu_desc_index;1876 }1877 1878 vif_priv->self_ucast_dpu_sign = params->ucast_dpu_signature;1879 1880 return 0;1881}1882 1883int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif,1884 struct ieee80211_sta *sta, const u8 *bssid,1885 bool update)1886{1887 int ret;1888 1889 mutex_lock(&wcn->hal_mutex);1890 1891 if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24))1892 ret = wcn36xx_smd_config_bss_v1(wcn, vif, sta, bssid, update);1893 else1894 ret = wcn36xx_smd_config_bss_v0(wcn, vif, sta, bssid, update);1895 1896 if (ret) {1897 wcn36xx_err("Sending hal_config_bss failed\n");1898 goto out;1899 }1900 ret = wcn36xx_smd_config_bss_rsp(wcn,1901 vif,1902 sta,1903 wcn->hal_buf,1904 wcn->hal_rsp_len);1905 if (ret)1906 wcn36xx_err("hal_config_bss response failed err=%d\n", ret);1907 1908out:1909 mutex_unlock(&wcn->hal_mutex);1910 return ret;1911}1912 1913int wcn36xx_smd_delete_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif)1914{1915 struct wcn36xx_hal_delete_bss_req_msg msg_body;1916 struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);1917 int ret = 0;1918 1919 mutex_lock(&wcn->hal_mutex);1920 1921 if (vif_priv->bss_index == WCN36XX_HAL_BSS_INVALID_IDX)1922 goto out;1923 1924 INIT_HAL_MSG(msg_body, WCN36XX_HAL_DELETE_BSS_REQ);1925 1926 msg_body.bss_index = vif_priv->bss_index;1927 1928 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);1929 1930 wcn36xx_dbg(WCN36XX_DBG_HAL, "hal delete bss %d\n", msg_body.bss_index);1931 1932 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);1933 if (ret) {1934 wcn36xx_err("Sending hal_delete_bss failed\n");1935 goto out;1936 }1937 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);1938 if (ret) {1939 wcn36xx_err("hal_delete_bss response failed err=%d\n", ret);1940 goto out;1941 }1942 1943 vif_priv->bss_index = WCN36XX_HAL_BSS_INVALID_IDX;1944out:1945 mutex_unlock(&wcn->hal_mutex);1946 return ret;1947}1948 1949int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct ieee80211_vif *vif,1950 struct sk_buff *skb_beacon, u16 tim_off,1951 u16 p2p_off)1952{1953 struct wcn36xx_hal_send_beacon_req_msg msg_body;1954 int ret, pad, pvm_len;1955 1956 mutex_lock(&wcn->hal_mutex);1957 INIT_HAL_MSG(msg_body, WCN36XX_HAL_SEND_BEACON_REQ);1958 1959 pvm_len = skb_beacon->data[tim_off + 1] - 3;1960 pad = TIM_MIN_PVM_SIZE - pvm_len;1961 1962 /* Padding is irrelevant to mesh mode since tim_off is always 0. */1963 if (vif->type == NL80211_IFTYPE_MESH_POINT)1964 pad = 0;1965 1966 msg_body.beacon_length = skb_beacon->len + pad;1967 /* TODO need to find out why + 6 is needed */1968 msg_body.beacon_length6 = msg_body.beacon_length + 6;1969 1970 if (msg_body.beacon_length > BEACON_TEMPLATE_SIZE) {1971 wcn36xx_err("Beacon is too big: beacon size=%d\n",1972 msg_body.beacon_length);1973 ret = -ENOMEM;1974 goto out;1975 }1976 memcpy(msg_body.beacon, skb_beacon->data, skb_beacon->len);1977 memcpy(msg_body.bssid, vif->addr, ETH_ALEN);1978 1979 if (pad > 0) {1980 /*1981 * The wcn36xx FW has a fixed size for the PVM in the TIM. If1982 * given the beacon template from mac80211 with a PVM shorter1983 * than the FW expectes it will overwrite the data after the1984 * TIM.1985 */1986 wcn36xx_dbg(WCN36XX_DBG_HAL, "Pad TIM PVM. %d bytes at %d\n",1987 pad, pvm_len);1988 memmove(&msg_body.beacon[tim_off + 5 + pvm_len + pad],1989 &msg_body.beacon[tim_off + 5 + pvm_len],1990 skb_beacon->len - (tim_off + 5 + pvm_len));1991 memset(&msg_body.beacon[tim_off + 5 + pvm_len], 0, pad);1992 msg_body.beacon[tim_off + 1] += pad;1993 }1994 1995 /* TODO need to find out why this is needed? */1996 if (vif->type == NL80211_IFTYPE_MESH_POINT)1997 /* mesh beacon don't need this, so push further down */1998 msg_body.tim_ie_offset = 256;1999 else2000 msg_body.tim_ie_offset = tim_off+4;2001 msg_body.p2p_ie_offset = p2p_off;2002 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);2003 2004 wcn36xx_dbg(WCN36XX_DBG_HAL,2005 "hal send beacon beacon_length %d\n",2006 msg_body.beacon_length);2007 2008 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);2009 if (ret) {2010 wcn36xx_err("Sending hal_send_beacon failed\n");2011 goto out;2012 }2013 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);2014 if (ret) {2015 wcn36xx_err("hal_send_beacon response failed err=%d\n", ret);2016 goto out;2017 }2018out:2019 mutex_unlock(&wcn->hal_mutex);2020 return ret;2021}2022 2023int wcn36xx_smd_update_proberesp_tmpl(struct wcn36xx *wcn,2024 struct ieee80211_vif *vif,2025 struct sk_buff *skb)2026{2027 struct wcn36xx_hal_send_probe_resp_req_msg msg;2028 int ret;2029 2030 mutex_lock(&wcn->hal_mutex);2031 INIT_HAL_MSG(msg, WCN36XX_HAL_UPDATE_PROBE_RSP_TEMPLATE_REQ);2032 2033 if (skb->len > BEACON_TEMPLATE_SIZE) {2034 wcn36xx_warn("probe response template is too big: %d\n",2035 skb->len);2036 ret = -E2BIG;2037 goto out;2038 }2039 2040 msg.probe_resp_template_len = skb->len;2041 memcpy(&msg.probe_resp_template, skb->data, skb->len);2042 2043 memcpy(msg.bssid, vif->addr, ETH_ALEN);2044 2045 PREPARE_HAL_BUF(wcn->hal_buf, msg);2046 2047 wcn36xx_dbg(WCN36XX_DBG_HAL,2048 "hal update probe rsp len %d bssid %pM\n",2049 msg.probe_resp_template_len, msg.bssid);2050 2051 ret = wcn36xx_smd_send_and_wait(wcn, msg.header.len);2052 if (ret) {2053 wcn36xx_err("Sending hal_update_proberesp_tmpl failed\n");2054 goto out;2055 }2056 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);2057 if (ret) {2058 wcn36xx_err("hal_update_proberesp_tmpl response failed err=%d\n",2059 ret);2060 goto out;2061 }2062out:2063 mutex_unlock(&wcn->hal_mutex);2064 return ret;2065}2066 2067int wcn36xx_smd_set_stakey(struct wcn36xx *wcn,2068 enum ani_ed_type enc_type,2069 u8 keyidx,2070 u8 keylen,2071 u8 *key,2072 u8 sta_index)2073{2074 struct wcn36xx_hal_set_sta_key_req_msg msg_body;2075 int ret;2076 2077 mutex_lock(&wcn->hal_mutex);2078 INIT_HAL_MSG(msg_body, WCN36XX_HAL_SET_STAKEY_REQ);2079 2080 msg_body.set_sta_key_params.sta_index = sta_index;2081 msg_body.set_sta_key_params.enc_type = enc_type;2082 2083 if (enc_type == WCN36XX_HAL_ED_WEP104 ||2084 enc_type == WCN36XX_HAL_ED_WEP40) {2085 /* Use bss key for wep (static) */2086 msg_body.set_sta_key_params.def_wep_idx = keyidx;2087 msg_body.set_sta_key_params.wep_type = 0;2088 } else {2089 msg_body.set_sta_key_params.key[0].id = keyidx;2090 msg_body.set_sta_key_params.key[0].unicast = 1;2091 msg_body.set_sta_key_params.key[0].direction = WCN36XX_HAL_TX_RX;2092 msg_body.set_sta_key_params.key[0].pae_role = 0;2093 msg_body.set_sta_key_params.key[0].length = keylen;2094 memcpy(msg_body.set_sta_key_params.key[0].key, key, keylen);2095 }2096 2097 msg_body.set_sta_key_params.single_tid_rc = 1;2098 2099 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);2100 2101 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);2102 if (ret) {2103 wcn36xx_err("Sending hal_set_stakey failed\n");2104 goto out;2105 }2106 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);2107 if (ret) {2108 wcn36xx_err("hal_set_stakey response failed err=%d\n", ret);2109 goto out;2110 }2111out:2112 mutex_unlock(&wcn->hal_mutex);2113 return ret;2114}2115 2116int wcn36xx_smd_set_bsskey(struct wcn36xx *wcn,2117 enum ani_ed_type enc_type,2118 u8 bssidx,2119 u8 keyidx,2120 u8 keylen,2121 u8 *key)2122{2123 struct wcn36xx_hal_set_bss_key_req_msg msg_body;2124 int ret;2125 2126 mutex_lock(&wcn->hal_mutex);2127 INIT_HAL_MSG(msg_body, WCN36XX_HAL_SET_BSSKEY_REQ);2128 msg_body.bss_idx = bssidx;2129 msg_body.enc_type = enc_type;2130 msg_body.num_keys = 1;2131 msg_body.keys[0].id = keyidx;2132 msg_body.keys[0].unicast = 0;2133 msg_body.keys[0].direction = WCN36XX_HAL_RX_ONLY;2134 msg_body.keys[0].pae_role = 0;2135 msg_body.keys[0].length = keylen;2136 memcpy(msg_body.keys[0].key, key, keylen);2137 2138 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);2139 2140 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);2141 if (ret) {2142 wcn36xx_err("Sending hal_set_bsskey failed\n");2143 goto out;2144 }2145 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);2146 if (ret) {2147 wcn36xx_err("hal_set_bsskey response failed err=%d\n", ret);2148 goto out;2149 }2150out:2151 mutex_unlock(&wcn->hal_mutex);2152 return ret;2153}2154 2155int wcn36xx_smd_remove_stakey(struct wcn36xx *wcn,2156 enum ani_ed_type enc_type,2157 u8 keyidx,2158 u8 sta_index)2159{2160 struct wcn36xx_hal_remove_sta_key_req_msg msg_body;2161 int ret;2162 2163 mutex_lock(&wcn->hal_mutex);2164 INIT_HAL_MSG(msg_body, WCN36XX_HAL_RMV_STAKEY_REQ);2165 2166 msg_body.sta_idx = sta_index;2167 msg_body.enc_type = enc_type;2168 msg_body.key_id = keyidx;2169 2170 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);2171 2172 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);2173 if (ret) {2174 wcn36xx_err("Sending hal_remove_stakey failed\n");2175 goto out;2176 }2177 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);2178 if (ret) {2179 wcn36xx_err("hal_remove_stakey response failed err=%d\n", ret);2180 goto out;2181 }2182out:2183 mutex_unlock(&wcn->hal_mutex);2184 return ret;2185}2186 2187int wcn36xx_smd_remove_bsskey(struct wcn36xx *wcn,2188 enum ani_ed_type enc_type,2189 u8 bssidx,2190 u8 keyidx)2191{2192 struct wcn36xx_hal_remove_bss_key_req_msg msg_body;2193 int ret;2194 2195 mutex_lock(&wcn->hal_mutex);2196 INIT_HAL_MSG(msg_body, WCN36XX_HAL_RMV_BSSKEY_REQ);2197 msg_body.bss_idx = bssidx;2198 msg_body.enc_type = enc_type;2199 msg_body.key_id = keyidx;2200 2201 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);2202 2203 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);2204 if (ret) {2205 wcn36xx_err("Sending hal_remove_bsskey failed\n");2206 goto out;2207 }2208 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);2209 if (ret) {2210 wcn36xx_err("hal_remove_bsskey response failed err=%d\n", ret);2211 goto out;2212 }2213out:2214 mutex_unlock(&wcn->hal_mutex);2215 return ret;2216}2217 2218int wcn36xx_smd_enter_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif)2219{2220 struct wcn36xx_hal_enter_bmps_req_msg msg_body;2221 struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);2222 int ret;2223 2224 mutex_lock(&wcn->hal_mutex);2225 INIT_HAL_MSG(msg_body, WCN36XX_HAL_ENTER_BMPS_REQ);2226 2227 msg_body.bss_index = vif_priv->bss_index;2228 msg_body.tbtt = vif->bss_conf.sync_tsf;2229 msg_body.dtim_period = vif_priv->dtim_period;2230 2231 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);2232 2233 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);2234 if (ret) {2235 wcn36xx_err("Sending hal_enter_bmps failed\n");2236 goto out;2237 }2238 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);2239 if (ret) {2240 wcn36xx_err("hal_enter_bmps response failed err=%d\n", ret);2241 goto out;2242 }2243out:2244 mutex_unlock(&wcn->hal_mutex);2245 return ret;2246}2247 2248int wcn36xx_smd_exit_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif)2249{2250 struct wcn36xx_hal_exit_bmps_req_msg msg_body;2251 struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);2252 int ret;2253 2254 mutex_lock(&wcn->hal_mutex);2255 INIT_HAL_MSG(msg_body, WCN36XX_HAL_EXIT_BMPS_REQ);2256 2257 msg_body.bss_index = vif_priv->bss_index;2258 msg_body.send_data_null = 1;2259 2260 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);2261 2262 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);2263 if (ret) {2264 wcn36xx_err("Sending hal_exit_bmps failed\n");2265 goto out;2266 }2267 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);2268 if (ret) {2269 wcn36xx_err("hal_exit_bmps response failed err=%d\n", ret);2270 goto out;2271 }2272out:2273 mutex_unlock(&wcn->hal_mutex);2274 return ret;2275}2276 2277int wcn36xx_smd_enter_imps(struct wcn36xx *wcn)2278{2279 struct wcn36xx_hal_enter_imps_req_msg msg_body;2280 int ret;2281 2282 mutex_lock(&wcn->hal_mutex);2283 INIT_HAL_MSG(msg_body, WCN36XX_HAL_ENTER_IMPS_REQ);2284 2285 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);2286 2287 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);2288 if (ret) {2289 wcn36xx_err("Sending hal_enter_imps failed\n");2290 goto out;2291 }2292 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);2293 if (ret) {2294 wcn36xx_err("hal_enter_imps response failed err=%d\n", ret);2295 goto out;2296 }2297 2298 wcn36xx_dbg(WCN36XX_DBG_HAL, "Entered idle mode\n");2299out:2300 mutex_unlock(&wcn->hal_mutex);2301 return ret;2302}2303 2304int wcn36xx_smd_exit_imps(struct wcn36xx *wcn)2305{2306 struct wcn36xx_hal_exit_imps_req_msg msg_body;2307 int ret;2308 2309 mutex_lock(&wcn->hal_mutex);2310 INIT_HAL_MSG(msg_body, WCN36XX_HAL_EXIT_IMPS_REQ);2311 2312 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);2313 2314 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);2315 if (ret) {2316 wcn36xx_err("Sending hal_exit_imps failed\n");2317 goto out;2318 }2319 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);2320 if (ret) {2321 wcn36xx_err("hal_exit_imps response failed err=%d\n", ret);2322 goto out;2323 }2324 wcn36xx_dbg(WCN36XX_DBG_HAL, "Exited idle mode\n");2325out:2326 mutex_unlock(&wcn->hal_mutex);2327 return ret;2328}2329 2330int wcn36xx_smd_set_power_params(struct wcn36xx *wcn, bool ignore_dtim)2331{2332 struct wcn36xx_hal_set_power_params_req_msg msg_body;2333 int ret;2334 2335 mutex_lock(&wcn->hal_mutex);2336 INIT_HAL_MSG(msg_body, WCN36XX_HAL_SET_POWER_PARAMS_REQ);2337 2338 /*2339 * When host is down ignore every second dtim2340 */2341 if (ignore_dtim) {2342 msg_body.ignore_dtim = 1;2343 msg_body.dtim_period = 2;2344 }2345 msg_body.listen_interval = WCN36XX_LISTEN_INTERVAL(wcn);2346 2347 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);2348 2349 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);2350 if (ret) {2351 wcn36xx_err("Sending hal_set_power_params failed\n");2352 goto out;2353 }2354 2355out:2356 mutex_unlock(&wcn->hal_mutex);2357 return ret;2358}2359 2360/* Notice: This function should be called after associated, or else it2361 * will be invalid2362 */2363int wcn36xx_smd_keep_alive_req(struct wcn36xx *wcn,2364 struct ieee80211_vif *vif,2365 int packet_type)2366{2367 struct wcn36xx_hal_keep_alive_req_msg msg_body;2368 struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);2369 int ret;2370 2371 mutex_lock(&wcn->hal_mutex);2372 INIT_HAL_MSG(msg_body, WCN36XX_HAL_KEEP_ALIVE_REQ);2373 2374 if (packet_type == WCN36XX_HAL_KEEP_ALIVE_NULL_PKT) {2375 msg_body.bss_index = vif_priv->bss_index;2376 msg_body.packet_type = WCN36XX_HAL_KEEP_ALIVE_NULL_PKT;2377 msg_body.time_period = WCN36XX_KEEP_ALIVE_TIME_PERIOD;2378 } else if (packet_type == WCN36XX_HAL_KEEP_ALIVE_UNSOLICIT_ARP_RSP) {2379 /* TODO: it also support ARP response type */2380 } else {2381 wcn36xx_warn("unknown keep alive packet type %d\n", packet_type);2382 ret = -EINVAL;2383 goto out;2384 }2385 2386 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);2387 2388 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);2389 if (ret) {2390 wcn36xx_err("Sending hal_keep_alive failed\n");2391 goto out;2392 }2393 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);2394 if (ret) {2395 wcn36xx_err("hal_keep_alive response failed err=%d\n", ret);2396 goto out;2397 }2398out:2399 mutex_unlock(&wcn->hal_mutex);2400 return ret;2401}2402 2403int wcn36xx_smd_dump_cmd_req(struct wcn36xx *wcn, u32 arg1, u32 arg2,2404 u32 arg3, u32 arg4, u32 arg5)2405{2406 struct wcn36xx_hal_dump_cmd_req_msg msg_body;2407 int ret;2408 2409 mutex_lock(&wcn->hal_mutex);2410 INIT_HAL_MSG(msg_body, WCN36XX_HAL_DUMP_COMMAND_REQ);2411 2412 msg_body.arg1 = arg1;2413 msg_body.arg2 = arg2;2414 msg_body.arg3 = arg3;2415 msg_body.arg4 = arg4;2416 msg_body.arg5 = arg5;2417 2418 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);2419 2420 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);2421 if (ret) {2422 wcn36xx_err("Sending hal_dump_cmd failed\n");2423 goto out;2424 }2425 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);2426 if (ret) {2427 wcn36xx_err("hal_dump_cmd response failed err=%d\n", ret);2428 goto out;2429 }2430out:2431 mutex_unlock(&wcn->hal_mutex);2432 return ret;2433}2434 2435int wcn36xx_smd_feature_caps_exchange(struct wcn36xx *wcn)2436{2437 struct wcn36xx_hal_feat_caps_msg msg_body, *rsp;2438 int ret, i;2439 2440 mutex_lock(&wcn->hal_mutex);2441 INIT_HAL_MSG(msg_body, WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_REQ);2442 2443 wcn36xx_firmware_set_feat_caps(msg_body.feat_caps, STA_POWERSAVE);2444 if (wcn->rf_id == RF_IRIS_WCN3680) {2445 wcn36xx_firmware_set_feat_caps(msg_body.feat_caps, DOT11AC);2446 wcn36xx_firmware_set_feat_caps(msg_body.feat_caps, WLAN_CH144);2447 wcn36xx_firmware_set_feat_caps(msg_body.feat_caps,2448 ANTENNA_DIVERSITY_SELECTION);2449 }2450 2451 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);2452 2453 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);2454 if (ret) {2455 wcn36xx_err("Sending hal_feature_caps_exchange failed\n");2456 goto out;2457 }2458 if (wcn->hal_rsp_len != sizeof(*rsp)) {2459 wcn36xx_err("Invalid hal_feature_caps_exchange response");2460 goto out;2461 }2462 2463 rsp = (struct wcn36xx_hal_feat_caps_msg *) wcn->hal_buf;2464 2465 for (i = 0; i < WCN36XX_HAL_CAPS_SIZE; i++)2466 wcn->fw_feat_caps[i] = rsp->feat_caps[i];2467out:2468 mutex_unlock(&wcn->hal_mutex);2469 return ret;2470}2471 2472static int wcn36xx_smd_add_ba_session_rsp(void *buf, int len, u8 *session)2473{2474 struct wcn36xx_hal_add_ba_session_rsp_msg *rsp;2475 2476 if (len < sizeof(*rsp))2477 return -EINVAL;2478 2479 rsp = buf;2480 if (rsp->status != WCN36XX_FW_MSG_RESULT_SUCCESS)2481 return rsp->status;2482 2483 *session = rsp->ba_session_id;2484 2485 return 0;2486}2487 2488int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn,2489 struct ieee80211_sta *sta,2490 u16 tid,2491 u16 *ssn,2492 u8 direction,2493 u8 sta_index)2494{2495 struct wcn36xx_hal_add_ba_session_req_msg msg_body;2496 u8 session_id;2497 int ret;2498 2499 mutex_lock(&wcn->hal_mutex);2500 INIT_HAL_MSG(msg_body, WCN36XX_HAL_ADD_BA_SESSION_REQ);2501 2502 msg_body.sta_index = sta_index;2503 memcpy(&msg_body.mac_addr, sta->addr, ETH_ALEN);2504 msg_body.dialog_token = 0x10;2505 msg_body.tid = tid;2506 2507 /* Immediate BA because Delayed BA is not supported */2508 msg_body.policy = 1;2509 msg_body.buffer_size = WCN36XX_AGGR_BUFFER_SIZE;2510 msg_body.timeout = 0;2511 if (ssn)2512 msg_body.ssn = *ssn;2513 msg_body.direction = direction;2514 2515 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);2516 2517 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);2518 if (ret) {2519 wcn36xx_err("Sending hal_add_ba_session failed\n");2520 goto out;2521 }2522 ret = wcn36xx_smd_add_ba_session_rsp(wcn->hal_buf, wcn->hal_rsp_len,2523 &session_id);2524 if (ret) {2525 wcn36xx_err("hal_add_ba_session response failed err=%d\n", ret);2526 ret = -EINVAL;2527 goto out;2528 }2529 2530 ret = session_id;2531out:2532 mutex_unlock(&wcn->hal_mutex);2533 return ret;2534}2535 2536int wcn36xx_smd_add_ba(struct wcn36xx *wcn, u8 session_id)2537{2538 struct wcn36xx_hal_add_ba_req_msg msg_body;2539 int ret;2540 2541 mutex_lock(&wcn->hal_mutex);2542 INIT_HAL_MSG(msg_body, WCN36XX_HAL_ADD_BA_REQ);2543 2544 msg_body.session_id = session_id;2545 msg_body.win_size = WCN36XX_AGGR_BUFFER_SIZE;2546 2547 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);2548 2549 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);2550 if (ret) {2551 wcn36xx_err("Sending hal_add_ba failed\n");2552 goto out;2553 }2554 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);2555 if (ret) {2556 wcn36xx_err("hal_add_ba response failed err=%d\n", ret);2557 goto out;2558 }2559out:2560 mutex_unlock(&wcn->hal_mutex);2561 return ret;2562}2563 2564int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 direction, u8 sta_index)2565{2566 struct wcn36xx_hal_del_ba_req_msg msg_body;2567 int ret;2568 2569 mutex_lock(&wcn->hal_mutex);2570 INIT_HAL_MSG(msg_body, WCN36XX_HAL_DEL_BA_REQ);2571 2572 msg_body.sta_index = sta_index;2573 msg_body.tid = tid;2574 msg_body.direction = direction;2575 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);2576 2577 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);2578 if (ret) {2579 wcn36xx_err("Sending hal_del_ba failed\n");2580 goto out;2581 }2582 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);2583 if (ret) {2584 wcn36xx_err("hal_del_ba response failed err=%d\n", ret);2585 goto out;2586 }2587out:2588 mutex_unlock(&wcn->hal_mutex);2589 return ret;2590}2591 2592int wcn36xx_smd_get_stats(struct wcn36xx *wcn, u8 sta_index, u32 stats_mask,2593 struct station_info *sinfo)2594{2595 struct wcn36xx_hal_stats_req_msg msg_body;2596 struct wcn36xx_hal_stats_rsp_msg *rsp;2597 void *rsp_body;2598 int ret;2599 2600 if (stats_mask & ~HAL_GLOBAL_CLASS_A_STATS_INFO) {2601 wcn36xx_err("stats_mask 0x%x contains unimplemented types\n",2602 stats_mask);2603 return -EINVAL;2604 }2605 2606 mutex_lock(&wcn->hal_mutex);2607 INIT_HAL_MSG(msg_body, WCN36XX_HAL_GET_STATS_REQ);2608 2609 msg_body.sta_id = sta_index;2610 msg_body.stats_mask = stats_mask;2611 2612 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);2613 2614 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);2615 if (ret) {2616 wcn36xx_err("sending hal_get_stats failed\n");2617 goto out;2618 }2619 2620 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);2621 if (ret) {2622 wcn36xx_err("hal_get_stats response failed err=%d\n", ret);2623 goto out;2624 }2625 2626 rsp = (struct wcn36xx_hal_stats_rsp_msg *)wcn->hal_buf;2627 rsp_body = (wcn->hal_buf + sizeof(struct wcn36xx_hal_stats_rsp_msg));2628 2629 if (rsp->stats_mask != stats_mask) {2630 wcn36xx_err("stats_mask 0x%x differs from requested 0x%x\n",2631 rsp->stats_mask, stats_mask);2632 goto out;2633 }2634 2635 if (rsp->stats_mask & HAL_GLOBAL_CLASS_A_STATS_INFO) {2636 struct ani_global_class_a_stats_info *stats_info = rsp_body;2637 2638 wcn36xx_process_tx_rate(stats_info, &sinfo->txrate);2639 sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);2640 rsp_body += sizeof(struct ani_global_class_a_stats_info);2641 }2642out:2643 mutex_unlock(&wcn->hal_mutex);2644 2645 return ret;2646}2647 2648static int wcn36xx_smd_trigger_ba_rsp(void *buf, int len, struct add_ba_info *ba_info)2649{2650 struct wcn36xx_hal_trigger_ba_rsp_candidate *candidate;2651 struct wcn36xx_hal_trigger_ba_rsp_msg *rsp;2652 int i;2653 2654 if (len < sizeof(*rsp))2655 return -EINVAL;2656 2657 rsp = buf;2658 2659 if (rsp->candidate_cnt < 1)2660 return rsp->status ? rsp->status : -EINVAL;2661 2662 candidate = (struct wcn36xx_hal_trigger_ba_rsp_candidate *)(buf + sizeof(*rsp));2663 2664 for (i = 0; i < STACFG_MAX_TC; i++) {2665 ba_info[i] = candidate->ba_info[i];2666 }2667 2668 return rsp->status;2669}2670 2671int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index, u16 tid, u16 *ssn)2672{2673 struct wcn36xx_hal_trigger_ba_req_msg msg_body;2674 struct wcn36xx_hal_trigger_ba_req_candidate *candidate;2675 struct add_ba_info ba_info[STACFG_MAX_TC];2676 int ret;2677 2678 if (tid >= STACFG_MAX_TC)2679 return -EINVAL;2680 2681 mutex_lock(&wcn->hal_mutex);2682 INIT_HAL_MSG(msg_body, WCN36XX_HAL_TRIGGER_BA_REQ);2683 2684 msg_body.session_id = 0; /* not really used */2685 msg_body.candidate_cnt = 1;2686 msg_body.header.len += sizeof(*candidate);2687 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);2688 2689 candidate = (struct wcn36xx_hal_trigger_ba_req_candidate *)2690 (wcn->hal_buf + sizeof(msg_body));2691 candidate->sta_index = sta_index;2692 candidate->tid_bitmap = 1 << tid;2693 2694 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);2695 if (ret) {2696 wcn36xx_err("Sending hal_trigger_ba failed\n");2697 goto out;2698 }2699 ret = wcn36xx_smd_trigger_ba_rsp(wcn->hal_buf, wcn->hal_rsp_len, ba_info);2700 if (ret) {2701 wcn36xx_err("hal_trigger_ba response failed err=%d\n", ret);2702 goto out;2703 }2704out:2705 mutex_unlock(&wcn->hal_mutex);2706 2707 if (ssn)2708 *ssn = ba_info[tid].starting_seq_num;2709 2710 return ret;2711}2712 2713static int wcn36xx_smd_tx_compl_ind(struct wcn36xx *wcn, void *buf, size_t len)2714{2715 struct wcn36xx_hal_tx_compl_ind_msg *rsp = buf;2716 2717 if (len != sizeof(*rsp)) {2718 wcn36xx_warn("Bad TX complete indication\n");2719 return -EIO;2720 }2721 2722 wcn36xx_dxe_tx_ack_ind(wcn, rsp->status);2723 2724 return 0;2725}2726 2727static int wcn36xx_smd_hw_scan_ind(struct wcn36xx *wcn, void *buf, size_t len)2728{2729 struct wcn36xx_hal_scan_offload_ind *rsp = buf;2730 struct cfg80211_scan_info scan_info = {};2731 2732 if (len != sizeof(*rsp)) {2733 wcn36xx_warn("Corrupted delete scan indication\n");2734 return -EIO;2735 }2736 2737 wcn36xx_dbg(WCN36XX_DBG_HAL, "scan indication (type %x)\n", rsp->type);2738 2739 switch (rsp->type) {2740 case WCN36XX_HAL_SCAN_IND_FAILED:2741 case WCN36XX_HAL_SCAN_IND_DEQUEUED:2742 scan_info.aborted = true;2743 fallthrough;2744 case WCN36XX_HAL_SCAN_IND_COMPLETED:2745 mutex_lock(&wcn->scan_lock);2746 wcn->scan_req = NULL;2747 if (wcn->scan_aborted)2748 scan_info.aborted = true;2749 mutex_unlock(&wcn->scan_lock);2750 ieee80211_scan_completed(wcn->hw, &scan_info);2751 break;2752 case WCN36XX_HAL_SCAN_IND_STARTED:2753 case WCN36XX_HAL_SCAN_IND_FOREIGN_CHANNEL:2754 case WCN36XX_HAL_SCAN_IND_PREEMPTED:2755 case WCN36XX_HAL_SCAN_IND_RESTARTED:2756 break;2757 default:2758 wcn36xx_warn("Unknown scan indication type %x\n", rsp->type);2759 }2760 2761 return 0;2762}2763 2764static int wcn36xx_smd_missed_beacon_ind(struct wcn36xx *wcn,2765 void *buf,2766 size_t len)2767{2768 struct wcn36xx_hal_missed_beacon_ind_msg *rsp = buf;2769 struct ieee80211_vif *vif = NULL;2770 struct wcn36xx_vif *tmp;2771 2772 /* Old FW does not have bss index */2773 if (wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) {2774 list_for_each_entry(tmp, &wcn->vif_list, list) {2775 wcn36xx_dbg(WCN36XX_DBG_HAL, "beacon missed bss_index %d\n",2776 tmp->bss_index);2777 vif = wcn36xx_priv_to_vif(tmp);2778 ieee80211_beacon_loss(vif);2779 }2780 return 0;2781 }2782 2783 if (len != sizeof(*rsp)) {2784 wcn36xx_warn("Corrupted missed beacon indication\n");2785 return -EIO;2786 }2787 2788 list_for_each_entry(tmp, &wcn->vif_list, list) {2789 if (tmp->bss_index == rsp->bss_index) {2790 wcn36xx_dbg(WCN36XX_DBG_HAL, "beacon missed bss_index %d\n",2791 rsp->bss_index);2792 vif = wcn36xx_priv_to_vif(tmp);2793 ieee80211_beacon_loss(vif);2794 return 0;2795 }2796 }2797 2798 wcn36xx_warn("BSS index %d not found\n", rsp->bss_index);2799 return -ENOENT;2800}2801 2802static int wcn36xx_smd_delete_sta_context_ind(struct wcn36xx *wcn,2803 void *buf,2804 size_t len)2805{2806 struct wcn36xx_hal_delete_sta_context_ind_msg *rsp = buf;2807 struct wcn36xx_vif *vif_priv;2808 struct ieee80211_vif *vif;2809 struct ieee80211_bss_conf *bss_conf;2810 struct ieee80211_sta *sta;2811 bool found = false;2812 2813 if (len != sizeof(*rsp)) {2814 wcn36xx_warn("Corrupted delete sta indication\n");2815 return -EIO;2816 }2817 2818 wcn36xx_dbg(WCN36XX_DBG_HAL,2819 "delete station indication %pM index %d reason %d\n",2820 rsp->addr2, rsp->sta_id, rsp->reason_code);2821 2822 list_for_each_entry(vif_priv, &wcn->vif_list, list) {2823 rcu_read_lock();2824 vif = wcn36xx_priv_to_vif(vif_priv);2825 2826 if (vif->type == NL80211_IFTYPE_STATION) {2827 /* We could call ieee80211_find_sta too, but checking2828 * bss_conf is clearer.2829 */2830 bss_conf = &vif->bss_conf;2831 if (vif_priv->sta_assoc &&2832 !memcmp(bss_conf->bssid, rsp->addr2, ETH_ALEN)) {2833 found = true;2834 wcn36xx_dbg(WCN36XX_DBG_HAL,2835 "connection loss bss_index %d\n",2836 vif_priv->bss_index);2837 ieee80211_connection_loss(vif);2838 }2839 } else {2840 sta = ieee80211_find_sta(vif, rsp->addr2);2841 if (sta) {2842 found = true;2843 ieee80211_report_low_ack(sta, 0);2844 }2845 }2846 2847 rcu_read_unlock();2848 if (found)2849 return 0;2850 }2851 2852 wcn36xx_warn("BSS or STA with addr %pM not found\n", rsp->addr2);2853 return -ENOENT;2854}2855 2856static int wcn36xx_smd_print_reg_info_ind(struct wcn36xx *wcn,2857 void *buf,2858 size_t len)2859{2860 struct wcn36xx_hal_print_reg_info_ind *rsp = buf;2861 int i;2862 2863 if (len < sizeof(*rsp)) {2864 wcn36xx_warn("Corrupted print reg info indication\n");2865 return -EIO;2866 }2867 2868 wcn36xx_dbg(WCN36XX_DBG_HAL,2869 "reginfo indication, scenario: 0x%x reason: 0x%x\n",2870 rsp->scenario, rsp->reason);2871 2872 for (i = 0; i < rsp->count; i++) {2873 wcn36xx_dbg(WCN36XX_DBG_HAL, "\t0x%x: 0x%x\n",2874 rsp->regs[i].addr, rsp->regs[i].value);2875 }2876 2877 return 0;2878}2879 2880int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value)2881{2882 struct wcn36xx_hal_update_cfg_req_msg msg_body, *body;2883 size_t len;2884 int ret;2885 2886 mutex_lock(&wcn->hal_mutex);2887 INIT_HAL_MSG(msg_body, WCN36XX_HAL_UPDATE_CFG_REQ);2888 2889 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);2890 2891 body = (struct wcn36xx_hal_update_cfg_req_msg *) wcn->hal_buf;2892 len = msg_body.header.len;2893 2894 put_cfg_tlv_u32(wcn, &len, cfg_id, value);2895 body->header.len = len;2896 body->len = len - sizeof(*body);2897 2898 ret = wcn36xx_smd_send_and_wait(wcn, body->header.len);2899 if (ret) {2900 wcn36xx_err("Sending hal_update_cfg failed\n");2901 goto out;2902 }2903 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);2904 if (ret) {2905 wcn36xx_err("hal_update_cfg response failed err=%d\n", ret);2906 goto out;2907 }2908out:2909 mutex_unlock(&wcn->hal_mutex);2910 return ret;2911}2912 2913int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn,2914 struct ieee80211_vif *vif,2915 struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp)2916{2917 struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);2918 struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_req_msg *msg_body = NULL;2919 int ret;2920 2921 mutex_lock(&wcn->hal_mutex);2922 2923 msg_body = (struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_req_msg *)2924 wcn->hal_buf;2925 INIT_HAL_MSG(*msg_body, WCN36XX_HAL_8023_MULTICAST_LIST_REQ);2926 2927 /* An empty list means all mc traffic will be received */2928 if (fp)2929 memcpy(&msg_body->mc_addr_list, fp,2930 sizeof(msg_body->mc_addr_list));2931 else2932 msg_body->mc_addr_list.mc_addr_count = 0;2933 2934 msg_body->mc_addr_list.bss_index = vif_priv->bss_index;2935 2936 ret = wcn36xx_smd_send_and_wait(wcn, msg_body->header.len);2937 if (ret) {2938 wcn36xx_err("Sending HAL_8023_MULTICAST_LIST failed\n");2939 goto out;2940 }2941 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);2942 if (ret) {2943 wcn36xx_err("HAL_8023_MULTICAST_LIST rsp failed err=%d\n", ret);2944 goto out;2945 }2946out:2947 mutex_unlock(&wcn->hal_mutex);2948 return ret;2949}2950 2951int wcn36xx_smd_arp_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif,2952 bool enable)2953{2954 struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);2955 struct wcn36xx_hal_host_offload_req_msg msg_body;2956 int ret;2957 2958 mutex_lock(&wcn->hal_mutex);2959 2960 INIT_HAL_MSG(msg_body, WCN36XX_HAL_HOST_OFFLOAD_REQ);2961 msg_body.host_offload_params.offload_type =2962 WCN36XX_HAL_IPV4_ARP_REPLY_OFFLOAD;2963 if (enable) {2964 msg_body.host_offload_params.enable =2965 WCN36XX_HAL_OFFLOAD_ARP_AND_BCAST_FILTER_ENABLE;2966 memcpy(&msg_body.host_offload_params.u,2967 &vif->cfg.arp_addr_list[0], sizeof(__be32));2968 }2969 msg_body.ns_offload_params.bss_index = vif_priv->bss_index;2970 2971 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);2972 2973 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);2974 if (ret) {2975 wcn36xx_err("Sending host_offload_arp failed\n");2976 goto out;2977 }2978 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);2979 if (ret) {2980 wcn36xx_err("host_offload_arp failed err=%d\n", ret);2981 goto out;2982 }2983out:2984 mutex_unlock(&wcn->hal_mutex);2985 return ret;2986}2987 2988#if IS_ENABLED(CONFIG_IPV6)2989int wcn36xx_smd_ipv6_ns_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif,2990 bool enable)2991{2992 struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);2993 struct wcn36xx_hal_host_offload_req_msg msg_body;2994 struct wcn36xx_hal_ns_offload_params *ns_params;2995 struct wcn36xx_hal_host_offload_req *ho_params;2996 int ret;2997 2998 mutex_lock(&wcn->hal_mutex);2999 3000 INIT_HAL_MSG(msg_body, WCN36XX_HAL_HOST_OFFLOAD_REQ);3001 ho_params = &msg_body.host_offload_params;3002 ns_params = &msg_body.ns_offload_params;3003 3004 ho_params->offload_type = WCN36XX_HAL_IPV6_NS_OFFLOAD;3005 if (enable) {3006 ho_params->enable =3007 WCN36XX_HAL_OFFLOAD_NS_AND_MCAST_FILTER_ENABLE;3008 if (vif_priv->num_target_ipv6_addrs) {3009 memcpy(&ho_params->u,3010 &vif_priv->target_ipv6_addrs[0].in6_u,3011 sizeof(struct in6_addr));3012 memcpy(&ns_params->target_ipv6_addr1,3013 &vif_priv->target_ipv6_addrs[0].in6_u,3014 sizeof(struct in6_addr));3015 ns_params->target_ipv6_addr1_valid = 1;3016 }3017 if (vif_priv->num_target_ipv6_addrs > 1) {3018 memcpy(&ns_params->target_ipv6_addr2,3019 &vif_priv->target_ipv6_addrs[1].in6_u,3020 sizeof(struct in6_addr));3021 ns_params->target_ipv6_addr2_valid = 1;3022 }3023 }3024 memcpy(&ns_params->self_addr, vif->addr, ETH_ALEN);3025 ns_params->bss_index = vif_priv->bss_index;3026 3027 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);3028 3029 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);3030 if (ret) {3031 wcn36xx_err("Sending host_offload_arp failed\n");3032 goto out;3033 }3034 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);3035 if (ret) {3036 wcn36xx_err("host_offload_arp failed err=%d\n", ret);3037 goto out;3038 }3039out:3040 mutex_unlock(&wcn->hal_mutex);3041 return ret;3042}3043#else3044int wcn36xx_smd_ipv6_ns_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif,3045 bool enable)3046{3047 return 0;3048}3049#endif3050 3051int wcn36xx_smd_gtk_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif,3052 bool enable)3053{3054 struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);3055 struct wcn36xx_hal_gtk_offload_req_msg msg_body;3056 int ret;3057 3058 mutex_lock(&wcn->hal_mutex);3059 3060 INIT_HAL_MSG(msg_body, WCN36XX_HAL_GTK_OFFLOAD_REQ);3061 3062 if (enable) {3063 memcpy(&msg_body.kek, vif_priv->rekey_data.kek, NL80211_KEK_LEN);3064 memcpy(&msg_body.kck, vif_priv->rekey_data.kck, NL80211_KCK_LEN);3065 msg_body.key_replay_counter =3066 le64_to_cpu(vif_priv->rekey_data.replay_ctr);3067 msg_body.bss_index = vif_priv->bss_index;3068 } else {3069 msg_body.flags = WCN36XX_HAL_GTK_OFFLOAD_FLAGS_DISABLE;3070 }3071 3072 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);3073 3074 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);3075 if (ret) {3076 wcn36xx_err("Sending host_offload_arp failed\n");3077 goto out;3078 }3079 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);3080 if (ret) {3081 wcn36xx_err("host_offload_arp failed err=%d\n", ret);3082 goto out;3083 }3084out:3085 mutex_unlock(&wcn->hal_mutex);3086 return ret;3087}3088 3089static int wcn36xx_smd_gtk_offload_get_info_rsp(struct wcn36xx *wcn,3090 struct ieee80211_vif *vif)3091{3092 struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);3093 struct wcn36xx_hal_gtk_offload_get_info_rsp_msg *rsp;3094 __be64 replay_ctr;3095 3096 if (wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len))3097 return -EIO;3098 3099 rsp = (struct wcn36xx_hal_gtk_offload_get_info_rsp_msg *)wcn->hal_buf;3100 3101 if (rsp->bss_index != vif_priv->bss_index) {3102 wcn36xx_err("gtk_offload_info invalid response bss index %d\n",3103 rsp->bss_index);3104 return -ENOENT;3105 }3106 3107 if (vif_priv->rekey_data.replay_ctr != cpu_to_le64(rsp->key_replay_counter)) {3108 replay_ctr = cpu_to_be64(rsp->key_replay_counter);3109 vif_priv->rekey_data.replay_ctr =3110 cpu_to_le64(rsp->key_replay_counter);3111 ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid,3112 (void *)&replay_ctr, GFP_KERNEL);3113 wcn36xx_dbg(WCN36XX_DBG_HAL,3114 "GTK replay counter increment %llu\n",3115 rsp->key_replay_counter);3116 }3117 3118 wcn36xx_dbg(WCN36XX_DBG_HAL,3119 "gtk offload info status %d last_rekey_status %d "3120 "replay_counter %llu total_rekey_count %d gtk_rekey_count %d "3121 "igtk_rekey_count %d bss_index %d\n",3122 rsp->status, rsp->last_rekey_status,3123 rsp->key_replay_counter, rsp->total_rekey_count,3124 rsp->gtk_rekey_count, rsp->igtk_rekey_count,3125 rsp->bss_index);3126 3127 return 0;3128}3129 3130int wcn36xx_smd_gtk_offload_get_info(struct wcn36xx *wcn,3131 struct ieee80211_vif *vif)3132{3133 struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);3134 struct wcn36xx_hal_gtk_offload_get_info_req_msg msg_body;3135 int ret;3136 3137 mutex_lock(&wcn->hal_mutex);3138 3139 INIT_HAL_MSG(msg_body, WCN36XX_HAL_GTK_OFFLOAD_GETINFO_REQ);3140 3141 msg_body.bss_index = vif_priv->bss_index;3142 3143 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);3144 3145 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);3146 if (ret) {3147 wcn36xx_err("Sending gtk_offload_get_info failed\n");3148 goto out;3149 }3150 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);3151 if (ret) {3152 wcn36xx_err("gtk_offload_get_info failed err=%d\n", ret);3153 goto out;3154 }3155 ret = wcn36xx_smd_gtk_offload_get_info_rsp(wcn, vif);3156out:3157 mutex_unlock(&wcn->hal_mutex);3158 return ret;3159}3160 3161int wcn36xx_smd_wlan_host_suspend_ind(struct wcn36xx *wcn)3162{3163 struct wcn36xx_hal_wlan_host_suspend_ind_msg msg_body;3164 int ret;3165 3166 mutex_lock(&wcn->hal_mutex);3167 3168 INIT_HAL_MSG(msg_body, WCN36XX_HAL_HOST_SUSPEND_IND);3169 msg_body.configured_mcst_bcst_filter_setting = 0;3170 msg_body.active_session_count = 1;3171 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);3172 3173 ret = rpmsg_send(wcn->smd_channel, wcn->hal_buf, msg_body.header.len);3174 3175 mutex_unlock(&wcn->hal_mutex);3176 3177 return ret;3178}3179 3180int wcn36xx_smd_host_resume(struct wcn36xx *wcn)3181{3182 struct wcn36xx_hal_wlan_host_resume_req_msg msg_body;3183 struct wcn36xx_hal_host_resume_rsp_msg *rsp;3184 int ret;3185 3186 mutex_lock(&wcn->hal_mutex);3187 3188 INIT_HAL_MSG(msg_body, WCN36XX_HAL_HOST_RESUME_REQ);3189 msg_body.configured_mcst_bcst_filter_setting = 0;3190 3191 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);3192 3193 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);3194 if (ret) {3195 wcn36xx_err("Sending wlan_host_resume failed\n");3196 goto out;3197 }3198 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);3199 if (ret) {3200 wcn36xx_err("wlan_host_resume err=%d\n", ret);3201 goto out;3202 }3203 3204 rsp = (struct wcn36xx_hal_host_resume_rsp_msg *)wcn->hal_buf;3205 if (rsp->status)3206 wcn36xx_warn("wlan_host_resume status=%d\n", rsp->status);3207 3208out:3209 mutex_unlock(&wcn->hal_mutex);3210 3211 return ret;3212}3213 3214#define BEACON_FILTER(eid, presence, offs, val, mask, ref_val) \3215 { \3216 .element_id = eid, \3217 .check_ie_presence = presence, \3218 .offset = offs, \3219 .value = val, \3220 .bitmask = mask, \3221 .ref = ref_val, \3222 }3223 3224static const struct beacon_filter_ie bcn_filter_ies[] = {3225 BEACON_FILTER(WLAN_EID_DS_PARAMS, 0, 0, 0,3226 WCN36XX_FILTER_IE_DS_CHANNEL_MASK, 0),3227 BEACON_FILTER(WLAN_EID_ERP_INFO, 0, 0, 0,3228 WCN36XX_FILTER_IE_ERP_FILTER_MASK, 0),3229 BEACON_FILTER(WLAN_EID_EDCA_PARAM_SET, 0, 0, 0,3230 WCN36XX_FILTER_IE_EDCA_FILTER_MASK, 0),3231 BEACON_FILTER(WLAN_EID_QOS_CAPA, 0, 0, 0,3232 WCN36XX_FILTER_IE_QOS_FILTER_MASK, 0),3233 BEACON_FILTER(WLAN_EID_CHANNEL_SWITCH, 1, 0, 0,3234 WCN36XX_FILTER_IE_CHANNEL_SWITCH_MASK, 0),3235 BEACON_FILTER(WLAN_EID_HT_OPERATION, 0, 0, 0,3236 WCN36XX_FILTER_IE_HT_BYTE0_FILTER_MASK, 0),3237 BEACON_FILTER(WLAN_EID_HT_OPERATION, 0, 2, 0,3238 WCN36XX_FILTER_IE_HT_BYTE2_FILTER_MASK, 0),3239 BEACON_FILTER(WLAN_EID_HT_OPERATION, 0, 5, 0,3240 WCN36XX_FILTER_IE_HT_BYTE5_FILTER_MASK, 0),3241 BEACON_FILTER(WLAN_EID_PWR_CONSTRAINT, 0, 0, 0,3242 WCN36XX_FILTER_IE_PWR_CONSTRAINT_MASK, 0),3243 BEACON_FILTER(WLAN_EID_OPMODE_NOTIF, 0, 0, 0,3244 WCN36XX_FILTER_IE_OPMODE_NOTIF_MASK, 0),3245 BEACON_FILTER(WLAN_EID_VHT_OPERATION, 0, 0, 0,3246 WCN36XX_FILTER_IE_VHTOP_CHWIDTH_MASK, 0),3247 BEACON_FILTER(WLAN_EID_RSN, 1, 0, 0,3248 WCN36XX_FILTER_IE_RSN_MASK, 0),3249 BEACON_FILTER(WLAN_EID_VENDOR_SPECIFIC, 1, 0, 0,3250 WCN36XX_FILTER_IE_VENDOR_MASK, 0),3251};3252 3253int wcn36xx_smd_add_beacon_filter(struct wcn36xx *wcn,3254 struct ieee80211_vif *vif)3255{3256 struct wcn36xx_hal_add_bcn_filter_req_msg msg_body, *body;3257 struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);3258 u8 *payload;3259 size_t payload_size;3260 int ret;3261 3262 if (!wcn36xx_firmware_get_feat_caps(wcn->fw_feat_caps, BCN_FILTER))3263 return -EOPNOTSUPP;3264 3265 mutex_lock(&wcn->hal_mutex);3266 INIT_HAL_MSG(msg_body, WCN36XX_HAL_ADD_BCN_FILTER_REQ);3267 3268 PREPARE_HAL_BUF(wcn->hal_buf, msg_body);3269 3270 body = (struct wcn36xx_hal_add_bcn_filter_req_msg *)wcn->hal_buf;3271 body->capability_info = vif->bss_conf.assoc_capability;3272 body->capability_mask = WCN36XX_FILTER_CAPABILITY_MASK;3273 body->beacon_interval = vif->bss_conf.beacon_int;3274 body->ie_num = ARRAY_SIZE(bcn_filter_ies);3275 body->bss_index = vif_priv->bss_index;3276 3277 payload = ((u8 *)body) + body->header.len;3278 payload_size = sizeof(bcn_filter_ies);3279 memcpy(payload, &bcn_filter_ies, payload_size);3280 3281 body->header.len += payload_size;3282 3283 ret = wcn36xx_smd_send_and_wait(wcn, body->header.len);3284 if (ret) {3285 wcn36xx_err("Sending add bcn_filter failed\n");3286 goto out;3287 }3288 3289 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);3290 if (ret) {3291 wcn36xx_err("add bcn filter response failed err=%d\n", ret);3292 goto out;3293 }3294out:3295 mutex_unlock(&wcn->hal_mutex);3296 return ret;3297}3298 3299int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev,3300 void *buf, int len, void *priv, u32 addr)3301{3302 const struct wcn36xx_hal_msg_header *msg_header = buf;3303 struct ieee80211_hw *hw = priv;3304 struct wcn36xx *wcn = hw->priv;3305 struct wcn36xx_hal_ind_msg *msg_ind;3306 wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "SMD <<< ", buf, len);3307 3308 switch (msg_header->msg_type) {3309 case WCN36XX_HAL_START_RSP:3310 case WCN36XX_HAL_CONFIG_STA_RSP:3311 case WCN36XX_HAL_CONFIG_BSS_RSP:3312 case WCN36XX_HAL_ADD_STA_SELF_RSP:3313 case WCN36XX_HAL_STOP_RSP:3314 case WCN36XX_HAL_DEL_STA_SELF_RSP:3315 case WCN36XX_HAL_DELETE_STA_RSP:3316 case WCN36XX_HAL_INIT_SCAN_RSP:3317 case WCN36XX_HAL_START_SCAN_RSP:3318 case WCN36XX_HAL_END_SCAN_RSP:3319 case WCN36XX_HAL_FINISH_SCAN_RSP:3320 case WCN36XX_HAL_DOWNLOAD_NV_RSP:3321 case WCN36XX_HAL_DELETE_BSS_RSP:3322 case WCN36XX_HAL_SEND_BEACON_RSP:3323 case WCN36XX_HAL_SET_LINK_ST_RSP:3324 case WCN36XX_HAL_UPDATE_PROBE_RSP_TEMPLATE_RSP:3325 case WCN36XX_HAL_SET_BSSKEY_RSP:3326 case WCN36XX_HAL_SET_STAKEY_RSP:3327 case WCN36XX_HAL_RMV_STAKEY_RSP:3328 case WCN36XX_HAL_RMV_BSSKEY_RSP:3329 case WCN36XX_HAL_ENTER_BMPS_RSP:3330 case WCN36XX_HAL_SET_POWER_PARAMS_RSP:3331 case WCN36XX_HAL_EXIT_BMPS_RSP:3332 case WCN36XX_HAL_KEEP_ALIVE_RSP:3333 case WCN36XX_HAL_DUMP_COMMAND_RSP:3334 case WCN36XX_HAL_ADD_BA_SESSION_RSP:3335 case WCN36XX_HAL_ADD_BA_RSP:3336 case WCN36XX_HAL_DEL_BA_RSP:3337 case WCN36XX_HAL_GET_STATS_RSP:3338 case WCN36XX_HAL_TRIGGER_BA_RSP:3339 case WCN36XX_HAL_UPDATE_CFG_RSP:3340 case WCN36XX_HAL_JOIN_RSP:3341 case WCN36XX_HAL_UPDATE_SCAN_PARAM_RSP:3342 case WCN36XX_HAL_CH_SWITCH_RSP:3343 case WCN36XX_HAL_PROCESS_PTT_RSP:3344 case WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_RSP:3345 case WCN36XX_HAL_8023_MULTICAST_LIST_RSP:3346 case WCN36XX_HAL_START_SCAN_OFFLOAD_RSP:3347 case WCN36XX_HAL_STOP_SCAN_OFFLOAD_RSP:3348 case WCN36XX_HAL_HOST_OFFLOAD_RSP:3349 case WCN36XX_HAL_GTK_OFFLOAD_RSP:3350 case WCN36XX_HAL_GTK_OFFLOAD_GETINFO_RSP:3351 case WCN36XX_HAL_HOST_RESUME_RSP:3352 case WCN36XX_HAL_ENTER_IMPS_RSP:3353 case WCN36XX_HAL_EXIT_IMPS_RSP:3354 case WCN36XX_HAL_UPDATE_CHANNEL_LIST_RSP:3355 case WCN36XX_HAL_ADD_BCN_FILTER_RSP:3356 memcpy(wcn->hal_buf, buf, len);3357 wcn->hal_rsp_len = len;3358 complete(&wcn->hal_rsp_compl);3359 break;3360 3361 case WCN36XX_HAL_COEX_IND:3362 case WCN36XX_HAL_AVOID_FREQ_RANGE_IND:3363 case WCN36XX_HAL_DEL_BA_IND:3364 case WCN36XX_HAL_OTA_TX_COMPL_IND:3365 case WCN36XX_HAL_MISSED_BEACON_IND:3366 case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:3367 case WCN36XX_HAL_PRINT_REG_INFO_IND:3368 case WCN36XX_HAL_SCAN_OFFLOAD_IND:3369 msg_ind = kmalloc(struct_size(msg_ind, msg, len), GFP_ATOMIC);3370 if (!msg_ind) {3371 wcn36xx_err("Run out of memory while handling SMD_EVENT (%d)\n",3372 msg_header->msg_type);3373 return -ENOMEM;3374 }3375 3376 msg_ind->msg_len = len;3377 memcpy(msg_ind->msg, buf, len);3378 3379 spin_lock(&wcn->hal_ind_lock);3380 list_add_tail(&msg_ind->list, &wcn->hal_ind_queue);3381 queue_work(wcn->hal_ind_wq, &wcn->hal_ind_work);3382 spin_unlock(&wcn->hal_ind_lock);3383 wcn36xx_dbg(WCN36XX_DBG_HAL, "indication arrived\n");3384 break;3385 default:3386 wcn36xx_err("SMD_EVENT (%d) not supported\n",3387 msg_header->msg_type);3388 }3389 3390 return 0;3391}3392 3393static void wcn36xx_ind_smd_work(struct work_struct *work)3394{3395 struct wcn36xx *wcn =3396 container_of(work, struct wcn36xx, hal_ind_work);3397 3398 for (;;) {3399 struct wcn36xx_hal_msg_header *msg_header;3400 struct wcn36xx_hal_ind_msg *hal_ind_msg;3401 unsigned long flags;3402 3403 spin_lock_irqsave(&wcn->hal_ind_lock, flags);3404 3405 if (list_empty(&wcn->hal_ind_queue)) {3406 spin_unlock_irqrestore(&wcn->hal_ind_lock, flags);3407 return;3408 }3409 3410 hal_ind_msg = list_first_entry(&wcn->hal_ind_queue,3411 struct wcn36xx_hal_ind_msg,3412 list);3413 list_del(&hal_ind_msg->list);3414 spin_unlock_irqrestore(&wcn->hal_ind_lock, flags);3415 3416 msg_header = (struct wcn36xx_hal_msg_header *)hal_ind_msg->msg;3417 3418 switch (msg_header->msg_type) {3419 case WCN36XX_HAL_COEX_IND:3420 case WCN36XX_HAL_DEL_BA_IND:3421 case WCN36XX_HAL_AVOID_FREQ_RANGE_IND:3422 break;3423 case WCN36XX_HAL_OTA_TX_COMPL_IND:3424 wcn36xx_smd_tx_compl_ind(wcn,3425 hal_ind_msg->msg,3426 hal_ind_msg->msg_len);3427 break;3428 case WCN36XX_HAL_MISSED_BEACON_IND:3429 wcn36xx_smd_missed_beacon_ind(wcn,3430 hal_ind_msg->msg,3431 hal_ind_msg->msg_len);3432 break;3433 case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:3434 wcn36xx_smd_delete_sta_context_ind(wcn,3435 hal_ind_msg->msg,3436 hal_ind_msg->msg_len);3437 break;3438 case WCN36XX_HAL_PRINT_REG_INFO_IND:3439 wcn36xx_smd_print_reg_info_ind(wcn,3440 hal_ind_msg->msg,3441 hal_ind_msg->msg_len);3442 break;3443 case WCN36XX_HAL_SCAN_OFFLOAD_IND:3444 wcn36xx_smd_hw_scan_ind(wcn, hal_ind_msg->msg,3445 hal_ind_msg->msg_len);3446 break;3447 default:3448 wcn36xx_err("SMD_EVENT (%d) not supported\n",3449 msg_header->msg_type);3450 }3451 3452 kfree(hal_ind_msg);3453 }3454}3455 3456int wcn36xx_smd_open(struct wcn36xx *wcn)3457{3458 wcn->hal_ind_wq = create_freezable_workqueue("wcn36xx_smd_ind");3459 if (!wcn->hal_ind_wq)3460 return -ENOMEM;3461 3462 INIT_WORK(&wcn->hal_ind_work, wcn36xx_ind_smd_work);3463 INIT_LIST_HEAD(&wcn->hal_ind_queue);3464 spin_lock_init(&wcn->hal_ind_lock);3465 3466 return 0;3467}3468 3469void wcn36xx_smd_close(struct wcn36xx *wcn)3470{3471 struct wcn36xx_hal_ind_msg *msg, *tmp;3472 3473 cancel_work_sync(&wcn->hal_ind_work);3474 destroy_workqueue(wcn->hal_ind_wq);3475 3476 list_for_each_entry_safe(msg, tmp, &wcn->hal_ind_queue, list)3477 kfree(msg);3478}3479