brintos

brintos / linux-shallow public Read only

0
0
Text · 96.4 KiB · 2cf86fc Raw
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(&param->reg_info_1, min_power,982				  WCN36XX_HAL_CHAN_REG1_MIN_PWR_MASK);983		u32p_replace_bits(&param->reg_info_1, req->channels[i]->max_power,984				  WCN36XX_HAL_CHAN_REG1_MAX_PWR_MASK);985		u32p_replace_bits(&param->reg_info_1, req->channels[i]->max_reg_power,986				  WCN36XX_HAL_CHAN_REG1_REG_PWR_MASK);987		u32p_replace_bits(&param->reg_info_1, 0,988				  WCN36XX_HAL_CHAN_REG1_CLASS_ID_MASK);989		u32p_replace_bits(&param->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