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 any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 18 19 #include <linux/etherdevice.h> 20 #include <linux/firmware.h> 21 #include <linux/bitops.h> 22 #include "smd.h" 23 24 struct wcn36xx_cfg_val { 25 u32 cfg_id; 26 u32 value; 27 }; 28 29 #define WCN36XX_CFG_VAL(id, val) \ 30 { \ 31 .cfg_id = WCN36XX_HAL_CFG_ ## id, \ 32 .value = val \ 33 } 34 35 static struct wcn36xx_cfg_val wcn36xx_cfg_vals[] = { 36 WCN36XX_CFG_VAL(CURRENT_TX_ANTENNA, 1), 37 WCN36XX_CFG_VAL(CURRENT_RX_ANTENNA, 1), 38 WCN36XX_CFG_VAL(LOW_GAIN_OVERRIDE, 0), 39 WCN36XX_CFG_VAL(POWER_STATE_PER_CHAIN, 785), 40 WCN36XX_CFG_VAL(CAL_PERIOD, 5), 41 WCN36XX_CFG_VAL(CAL_CONTROL, 1), 42 WCN36XX_CFG_VAL(PROXIMITY, 0), 43 WCN36XX_CFG_VAL(NETWORK_DENSITY, 3), 44 WCN36XX_CFG_VAL(MAX_MEDIUM_TIME, 6000), 45 WCN36XX_CFG_VAL(MAX_MPDUS_IN_AMPDU, 64), 46 WCN36XX_CFG_VAL(RTS_THRESHOLD, 2347), 47 WCN36XX_CFG_VAL(SHORT_RETRY_LIMIT, 6), 48 WCN36XX_CFG_VAL(LONG_RETRY_LIMIT, 6), 49 WCN36XX_CFG_VAL(FRAGMENTATION_THRESHOLD, 8000), 50 WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ZERO, 5), 51 WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ONE, 10), 52 WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_TWO, 15), 53 WCN36XX_CFG_VAL(FIXED_RATE, 0), 54 WCN36XX_CFG_VAL(RETRYRATE_POLICY, 4), 55 WCN36XX_CFG_VAL(RETRYRATE_SECONDARY, 0), 56 WCN36XX_CFG_VAL(RETRYRATE_TERTIARY, 0), 57 WCN36XX_CFG_VAL(FORCE_POLICY_PROTECTION, 5), 58 WCN36XX_CFG_VAL(FIXED_RATE_MULTICAST_24GHZ, 1), 59 WCN36XX_CFG_VAL(FIXED_RATE_MULTICAST_5GHZ, 5), 60 WCN36XX_CFG_VAL(DEFAULT_RATE_INDEX_5GHZ, 5), 61 WCN36XX_CFG_VAL(MAX_BA_SESSIONS, 40), 62 WCN36XX_CFG_VAL(PS_DATA_INACTIVITY_TIMEOUT, 200), 63 WCN36XX_CFG_VAL(PS_ENABLE_BCN_FILTER, 1), 64 WCN36XX_CFG_VAL(PS_ENABLE_RSSI_MONITOR, 1), 65 WCN36XX_CFG_VAL(NUM_BEACON_PER_RSSI_AVERAGE, 20), 66 WCN36XX_CFG_VAL(STATS_PERIOD, 10), 67 WCN36XX_CFG_VAL(CFP_MAX_DURATION, 30000), 68 WCN36XX_CFG_VAL(FRAME_TRANS_ENABLED, 0), 69 WCN36XX_CFG_VAL(BA_THRESHOLD_HIGH, 128), 70 WCN36XX_CFG_VAL(MAX_BA_BUFFERS, 2560), 71 WCN36XX_CFG_VAL(DYNAMIC_PS_POLL_VALUE, 0), 72 WCN36XX_CFG_VAL(TX_PWR_CTRL_ENABLE, 1), 73 WCN36XX_CFG_VAL(ENABLE_CLOSE_LOOP, 1), 74 WCN36XX_CFG_VAL(ENABLE_LPWR_IMG_TRANSITION, 0), 75 WCN36XX_CFG_VAL(MAX_ASSOC_LIMIT, 10), 76 WCN36XX_CFG_VAL(ENABLE_MCC_ADAPTIVE_SCHEDULER, 0), 77 }; 78 79 static int put_cfg_tlv_u32(struct wcn36xx *wcn, size_t *len, u32 id, u32 value) 80 { 81 struct wcn36xx_hal_cfg *entry; 82 u32 *val; 83 84 if (*len + sizeof(*entry) + sizeof(u32) >= WCN36XX_HAL_BUF_SIZE) { 85 wcn36xx_err("Not enough room for TLV entry\n"); 86 return -ENOMEM; 87 } 88 89 entry = (struct wcn36xx_hal_cfg *) (wcn->hal_buf + *len); 90 entry->id = id; 91 entry->len = sizeof(u32); 92 entry->pad_bytes = 0; 93 entry->reserve = 0; 94 95 val = (u32 *) (entry + 1); 96 *val = value; 97 98 *len += sizeof(*entry) + sizeof(u32); 99 100 return 0; 101 } 102 103 static void wcn36xx_smd_set_bss_nw_type(struct wcn36xx *wcn, 104 struct ieee80211_sta *sta, 105 struct wcn36xx_hal_config_bss_params *bss_params) 106 { 107 if (IEEE80211_BAND_5GHZ == WCN36XX_BAND(wcn)) 108 bss_params->nw_type = WCN36XX_HAL_11A_NW_TYPE; 109 else if (sta && sta->ht_cap.ht_supported) 110 bss_params->nw_type = WCN36XX_HAL_11N_NW_TYPE; 111 else if (sta && (sta->supp_rates[IEEE80211_BAND_2GHZ] & 0x7f)) 112 bss_params->nw_type = WCN36XX_HAL_11G_NW_TYPE; 113 else 114 bss_params->nw_type = WCN36XX_HAL_11B_NW_TYPE; 115 } 116 117 static inline u8 is_cap_supported(unsigned long caps, unsigned long flag) 118 { 119 return caps & flag ? 1 : 0; 120 } 121 static void wcn36xx_smd_set_bss_ht_params(struct ieee80211_vif *vif, 122 struct ieee80211_sta *sta, 123 struct wcn36xx_hal_config_bss_params *bss_params) 124 { 125 if (sta && sta->ht_cap.ht_supported) { 126 unsigned long caps = sta->ht_cap.cap; 127 bss_params->ht = sta->ht_cap.ht_supported; 128 bss_params->tx_channel_width_set = is_cap_supported(caps, 129 IEEE80211_HT_CAP_SUP_WIDTH_20_40); 130 bss_params->lsig_tx_op_protection_full_support = 131 is_cap_supported(caps, 132 IEEE80211_HT_CAP_LSIG_TXOP_PROT); 133 134 bss_params->ht_oper_mode = vif->bss_conf.ht_operation_mode; 135 bss_params->lln_non_gf_coexist = 136 !!(vif->bss_conf.ht_operation_mode & 137 IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); 138 /* IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT */ 139 bss_params->dual_cts_protection = 0; 140 /* IEEE80211_HT_OP_MODE_PROTECTION_20MHZ */ 141 bss_params->ht20_coexist = 0; 142 } 143 } 144 145 static void wcn36xx_smd_set_sta_ht_params(struct ieee80211_sta *sta, 146 struct wcn36xx_hal_config_sta_params *sta_params) 147 { 148 if (sta->ht_cap.ht_supported) { 149 unsigned long caps = sta->ht_cap.cap; 150 sta_params->ht_capable = sta->ht_cap.ht_supported; 151 sta_params->tx_channel_width_set = is_cap_supported(caps, 152 IEEE80211_HT_CAP_SUP_WIDTH_20_40); 153 sta_params->lsig_txop_protection = is_cap_supported(caps, 154 IEEE80211_HT_CAP_LSIG_TXOP_PROT); 155 156 sta_params->max_ampdu_size = sta->ht_cap.ampdu_factor; 157 sta_params->max_ampdu_density = sta->ht_cap.ampdu_density; 158 sta_params->max_amsdu_size = is_cap_supported(caps, 159 IEEE80211_HT_CAP_MAX_AMSDU); 160 sta_params->sgi_20Mhz = is_cap_supported(caps, 161 IEEE80211_HT_CAP_SGI_20); 162 sta_params->sgi_40mhz = is_cap_supported(caps, 163 IEEE80211_HT_CAP_SGI_40); 164 sta_params->green_field_capable = is_cap_supported(caps, 165 IEEE80211_HT_CAP_GRN_FLD); 166 sta_params->delayed_ba_support = is_cap_supported(caps, 167 IEEE80211_HT_CAP_DELAY_BA); 168 sta_params->dsss_cck_mode_40mhz = is_cap_supported(caps, 169 IEEE80211_HT_CAP_DSSSCCK40); 170 } 171 } 172 173 static void wcn36xx_smd_set_sta_default_ht_params( 174 struct wcn36xx_hal_config_sta_params *sta_params) 175 { 176 sta_params->ht_capable = 1; 177 sta_params->tx_channel_width_set = 1; 178 sta_params->lsig_txop_protection = 1; 179 sta_params->max_ampdu_size = 3; 180 sta_params->max_ampdu_density = 5; 181 sta_params->max_amsdu_size = 0; 182 sta_params->sgi_20Mhz = 1; 183 sta_params->sgi_40mhz = 1; 184 sta_params->green_field_capable = 1; 185 sta_params->delayed_ba_support = 0; 186 sta_params->dsss_cck_mode_40mhz = 1; 187 } 188 189 static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn, 190 struct ieee80211_vif *vif, 191 struct ieee80211_sta *sta, 192 struct wcn36xx_hal_config_sta_params *sta_params) 193 { 194 struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv; 195 struct wcn36xx_sta *priv_sta = NULL; 196 if (vif->type == NL80211_IFTYPE_ADHOC || 197 vif->type == NL80211_IFTYPE_AP || 198 vif->type == NL80211_IFTYPE_MESH_POINT) { 199 sta_params->type = 1; 200 sta_params->sta_index = 0xFF; 201 } else { 202 sta_params->type = 0; 203 sta_params->sta_index = 1; 204 } 205 206 sta_params->listen_interval = WCN36XX_LISTEN_INTERVAL(wcn); 207 208 /* 209 * In STA mode ieee80211_sta contains bssid and ieee80211_vif 210 * contains our mac address. In AP mode we are bssid so vif 211 * contains bssid and ieee80211_sta contains mac. 212 */ 213 if (NL80211_IFTYPE_STATION == vif->type) 214 memcpy(&sta_params->mac, vif->addr, ETH_ALEN); 215 else 216 memcpy(&sta_params->bssid, vif->addr, ETH_ALEN); 217 218 sta_params->encrypt_type = priv_vif->encrypt_type; 219 sta_params->short_preamble_supported = 220 !(WCN36XX_FLAGS(wcn) & 221 IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE); 222 223 sta_params->rifs_mode = 0; 224 sta_params->rmf = 0; 225 sta_params->action = 0; 226 sta_params->uapsd = 0; 227 sta_params->mimo_ps = WCN36XX_HAL_HT_MIMO_PS_STATIC; 228 sta_params->max_ampdu_duration = 0; 229 sta_params->bssid_index = priv_vif->bss_index; 230 sta_params->p2p = 0; 231 232 if (sta) { 233 priv_sta = (struct wcn36xx_sta *)sta->drv_priv; 234 if (NL80211_IFTYPE_STATION == vif->type) 235 memcpy(&sta_params->bssid, sta->addr, ETH_ALEN); 236 else 237 memcpy(&sta_params->mac, sta->addr, ETH_ALEN); 238 sta_params->wmm_enabled = sta->wme; 239 sta_params->max_sp_len = sta->max_sp; 240 sta_params->aid = priv_sta->aid; 241 wcn36xx_smd_set_sta_ht_params(sta, sta_params); 242 memcpy(&sta_params->supported_rates, &priv_sta->supported_rates, 243 sizeof(priv_sta->supported_rates)); 244 } else { 245 wcn36xx_set_default_rates(&sta_params->supported_rates); 246 wcn36xx_smd_set_sta_default_ht_params(sta_params); 247 } 248 } 249 250 static int wcn36xx_smd_send_and_wait(struct wcn36xx *wcn, size_t len) 251 { 252 int ret = 0; 253 unsigned long start; 254 wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "HAL >>> ", wcn->hal_buf, len); 255 256 init_completion(&wcn->hal_rsp_compl); 257 start = jiffies; 258 ret = wcn->ctrl_ops->tx(wcn->hal_buf, len); 259 if (ret) { 260 wcn36xx_err("HAL TX failed\n"); 261 goto out; 262 } 263 if (wait_for_completion_timeout(&wcn->hal_rsp_compl, 264 msecs_to_jiffies(HAL_MSG_TIMEOUT)) <= 0) { 265 wcn36xx_err("Timeout! No SMD response in %dms\n", 266 HAL_MSG_TIMEOUT); 267 ret = -ETIME; 268 goto out; 269 } 270 wcn36xx_dbg(WCN36XX_DBG_SMD, "SMD command completed in %dms", 271 jiffies_to_msecs(jiffies - start)); 272 out: 273 return ret; 274 } 275 276 #define INIT_HAL_MSG(msg_body, type) \ 277 do { \ 278 memset(&msg_body, 0, sizeof(msg_body)); \ 279 msg_body.header.msg_type = type; \ 280 msg_body.header.msg_version = WCN36XX_HAL_MSG_VERSION0; \ 281 msg_body.header.len = sizeof(msg_body); \ 282 } while (0) \ 283 284 #define PREPARE_HAL_BUF(send_buf, msg_body) \ 285 do { \ 286 memset(send_buf, 0, msg_body.header.len); \ 287 memcpy(send_buf, &msg_body, sizeof(msg_body)); \ 288 } while (0) \ 289 290 static int wcn36xx_smd_rsp_status_check(void *buf, size_t len) 291 { 292 struct wcn36xx_fw_msg_status_rsp *rsp; 293 294 if (len < sizeof(struct wcn36xx_hal_msg_header) + 295 sizeof(struct wcn36xx_fw_msg_status_rsp)) 296 return -EIO; 297 298 rsp = (struct wcn36xx_fw_msg_status_rsp *) 299 (buf + sizeof(struct wcn36xx_hal_msg_header)); 300 301 if (WCN36XX_FW_MSG_RESULT_SUCCESS != rsp->status) 302 return rsp->status; 303 304 return 0; 305 } 306 307 int wcn36xx_smd_load_nv(struct wcn36xx *wcn) 308 { 309 struct nv_data *nv_d; 310 struct wcn36xx_hal_nv_img_download_req_msg msg_body; 311 int fw_bytes_left; 312 int ret; 313 u16 fm_offset = 0; 314 315 if (!wcn->nv) { 316 ret = request_firmware(&wcn->nv, WLAN_NV_FILE, wcn->dev); 317 if (ret) { 318 wcn36xx_err("Failed to load nv file %s: %d\n", 319 WLAN_NV_FILE, ret); 320 goto out; 321 } 322 } 323 324 nv_d = (struct nv_data *)wcn->nv->data; 325 INIT_HAL_MSG(msg_body, WCN36XX_HAL_DOWNLOAD_NV_REQ); 326 327 msg_body.header.len += WCN36XX_NV_FRAGMENT_SIZE; 328 329 msg_body.frag_number = 0; 330 /* hal_buf must be protected with mutex */ 331 mutex_lock(&wcn->hal_mutex); 332 333 do { 334 fw_bytes_left = wcn->nv->size - fm_offset - 4; 335 if (fw_bytes_left > WCN36XX_NV_FRAGMENT_SIZE) { 336 msg_body.last_fragment = 0; 337 msg_body.nv_img_buffer_size = WCN36XX_NV_FRAGMENT_SIZE; 338 } else { 339 msg_body.last_fragment = 1; 340 msg_body.nv_img_buffer_size = fw_bytes_left; 341 342 /* Do not forget update general message len */ 343 msg_body.header.len = sizeof(msg_body) + fw_bytes_left; 344 345 } 346 347 /* Add load NV request message header */ 348 memcpy(wcn->hal_buf, &msg_body, sizeof(msg_body)); 349 350 /* Add NV body itself */ 351 memcpy(wcn->hal_buf + sizeof(msg_body), 352 &nv_d->table + fm_offset, 353 msg_body.nv_img_buffer_size); 354 355 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 356 if (ret) 357 goto out_unlock; 358 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, 359 wcn->hal_rsp_len); 360 if (ret) { 361 wcn36xx_err("hal_load_nv response failed err=%d\n", 362 ret); 363 goto out_unlock; 364 } 365 msg_body.frag_number++; 366 fm_offset += WCN36XX_NV_FRAGMENT_SIZE; 367 368 } while (msg_body.last_fragment != 1); 369 370 out_unlock: 371 mutex_unlock(&wcn->hal_mutex); 372 out: return ret; 373 } 374 375 static int wcn36xx_smd_start_rsp(struct wcn36xx *wcn, void *buf, size_t len) 376 { 377 struct wcn36xx_hal_mac_start_rsp_msg *rsp; 378 379 if (len < sizeof(*rsp)) 380 return -EIO; 381 382 rsp = (struct wcn36xx_hal_mac_start_rsp_msg *)buf; 383 384 if (WCN36XX_FW_MSG_RESULT_SUCCESS != rsp->start_rsp_params.status) 385 return -EIO; 386 387 memcpy(wcn->crm_version, rsp->start_rsp_params.crm_version, 388 WCN36XX_HAL_VERSION_LENGTH); 389 memcpy(wcn->wlan_version, rsp->start_rsp_params.wlan_version, 390 WCN36XX_HAL_VERSION_LENGTH); 391 392 /* null terminate the strings, just in case */ 393 wcn->crm_version[WCN36XX_HAL_VERSION_LENGTH] = '\0'; 394 wcn->wlan_version[WCN36XX_HAL_VERSION_LENGTH] = '\0'; 395 396 wcn->fw_revision = rsp->start_rsp_params.version.revision; 397 wcn->fw_version = rsp->start_rsp_params.version.version; 398 wcn->fw_minor = rsp->start_rsp_params.version.minor; 399 wcn->fw_major = rsp->start_rsp_params.version.major; 400 401 wcn36xx_info("firmware WLAN version '%s' and CRM version '%s'\n", 402 wcn->wlan_version, wcn->crm_version); 403 404 wcn36xx_info("firmware API %u.%u.%u.%u, %u stations, %u bssids\n", 405 wcn->fw_major, wcn->fw_minor, 406 wcn->fw_version, wcn->fw_revision, 407 rsp->start_rsp_params.stations, 408 rsp->start_rsp_params.bssids); 409 410 return 0; 411 } 412 413 int wcn36xx_smd_start(struct wcn36xx *wcn) 414 { 415 struct wcn36xx_hal_mac_start_req_msg msg_body, *body; 416 int ret = 0; 417 int i; 418 size_t len; 419 420 mutex_lock(&wcn->hal_mutex); 421 INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_REQ); 422 423 msg_body.params.type = DRIVER_TYPE_PRODUCTION; 424 msg_body.params.len = 0; 425 426 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 427 428 body = (struct wcn36xx_hal_mac_start_req_msg *)wcn->hal_buf; 429 len = body->header.len; 430 431 for (i = 0; i < ARRAY_SIZE(wcn36xx_cfg_vals); i++) { 432 ret = put_cfg_tlv_u32(wcn, &len, wcn36xx_cfg_vals[i].cfg_id, 433 wcn36xx_cfg_vals[i].value); 434 if (ret) 435 goto out; 436 } 437 body->header.len = len; 438 body->params.len = len - sizeof(*body); 439 440 wcn36xx_dbg(WCN36XX_DBG_HAL, "hal start type %d\n", 441 msg_body.params.type); 442 443 ret = wcn36xx_smd_send_and_wait(wcn, body->header.len); 444 if (ret) { 445 wcn36xx_err("Sending hal_start failed\n"); 446 goto out; 447 } 448 449 ret = wcn36xx_smd_start_rsp(wcn, wcn->hal_buf, wcn->hal_rsp_len); 450 if (ret) { 451 wcn36xx_err("hal_start response failed err=%d\n", ret); 452 goto out; 453 } 454 455 out: 456 mutex_unlock(&wcn->hal_mutex); 457 return ret; 458 } 459 460 int wcn36xx_smd_stop(struct wcn36xx *wcn) 461 { 462 struct wcn36xx_hal_mac_stop_req_msg msg_body; 463 int ret = 0; 464 465 mutex_lock(&wcn->hal_mutex); 466 INIT_HAL_MSG(msg_body, WCN36XX_HAL_STOP_REQ); 467 468 msg_body.stop_req_params.reason = HAL_STOP_TYPE_RF_KILL; 469 470 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 471 472 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 473 if (ret) { 474 wcn36xx_err("Sending hal_stop failed\n"); 475 goto out; 476 } 477 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 478 if (ret) { 479 wcn36xx_err("hal_stop response failed err=%d\n", ret); 480 goto out; 481 } 482 out: 483 mutex_unlock(&wcn->hal_mutex); 484 return ret; 485 } 486 487 int wcn36xx_smd_init_scan(struct wcn36xx *wcn, enum wcn36xx_hal_sys_mode mode) 488 { 489 struct wcn36xx_hal_init_scan_req_msg msg_body; 490 int ret = 0; 491 492 mutex_lock(&wcn->hal_mutex); 493 INIT_HAL_MSG(msg_body, WCN36XX_HAL_INIT_SCAN_REQ); 494 495 msg_body.mode = mode; 496 497 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 498 499 wcn36xx_dbg(WCN36XX_DBG_HAL, "hal init scan mode %d\n", msg_body.mode); 500 501 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 502 if (ret) { 503 wcn36xx_err("Sending hal_init_scan failed\n"); 504 goto out; 505 } 506 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 507 if (ret) { 508 wcn36xx_err("hal_init_scan response failed err=%d\n", ret); 509 goto out; 510 } 511 out: 512 mutex_unlock(&wcn->hal_mutex); 513 return ret; 514 } 515 516 int wcn36xx_smd_start_scan(struct wcn36xx *wcn) 517 { 518 struct wcn36xx_hal_start_scan_req_msg msg_body; 519 int ret = 0; 520 521 mutex_lock(&wcn->hal_mutex); 522 INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_SCAN_REQ); 523 524 msg_body.scan_channel = WCN36XX_HW_CHANNEL(wcn); 525 526 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 527 528 wcn36xx_dbg(WCN36XX_DBG_HAL, "hal start scan channel %d\n", 529 msg_body.scan_channel); 530 531 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 532 if (ret) { 533 wcn36xx_err("Sending hal_start_scan failed\n"); 534 goto out; 535 } 536 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 537 if (ret) { 538 wcn36xx_err("hal_start_scan response failed err=%d\n", ret); 539 goto out; 540 } 541 out: 542 mutex_unlock(&wcn->hal_mutex); 543 return ret; 544 } 545 546 int wcn36xx_smd_end_scan(struct wcn36xx *wcn) 547 { 548 struct wcn36xx_hal_end_scan_req_msg msg_body; 549 int ret = 0; 550 551 mutex_lock(&wcn->hal_mutex); 552 INIT_HAL_MSG(msg_body, WCN36XX_HAL_END_SCAN_REQ); 553 554 msg_body.scan_channel = WCN36XX_HW_CHANNEL(wcn); 555 556 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 557 558 wcn36xx_dbg(WCN36XX_DBG_HAL, "hal end scan channel %d\n", 559 msg_body.scan_channel); 560 561 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 562 if (ret) { 563 wcn36xx_err("Sending hal_end_scan failed\n"); 564 goto out; 565 } 566 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 567 if (ret) { 568 wcn36xx_err("hal_end_scan response failed err=%d\n", ret); 569 goto out; 570 } 571 out: 572 mutex_unlock(&wcn->hal_mutex); 573 return ret; 574 } 575 576 int wcn36xx_smd_finish_scan(struct wcn36xx *wcn, 577 enum wcn36xx_hal_sys_mode mode) 578 { 579 struct wcn36xx_hal_finish_scan_req_msg msg_body; 580 int ret = 0; 581 582 mutex_lock(&wcn->hal_mutex); 583 INIT_HAL_MSG(msg_body, WCN36XX_HAL_FINISH_SCAN_REQ); 584 585 msg_body.mode = mode; 586 587 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 588 589 wcn36xx_dbg(WCN36XX_DBG_HAL, "hal finish scan mode %d\n", 590 msg_body.mode); 591 592 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 593 if (ret) { 594 wcn36xx_err("Sending hal_finish_scan failed\n"); 595 goto out; 596 } 597 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 598 if (ret) { 599 wcn36xx_err("hal_finish_scan response failed err=%d\n", ret); 600 goto out; 601 } 602 out: 603 mutex_unlock(&wcn->hal_mutex); 604 return ret; 605 } 606 607 static int wcn36xx_smd_switch_channel_rsp(void *buf, size_t len) 608 { 609 struct wcn36xx_hal_switch_channel_rsp_msg *rsp; 610 int ret = 0; 611 612 ret = wcn36xx_smd_rsp_status_check(buf, len); 613 if (ret) 614 return ret; 615 rsp = (struct wcn36xx_hal_switch_channel_rsp_msg *)buf; 616 wcn36xx_dbg(WCN36XX_DBG_HAL, "channel switched to: %d, status: %d\n", 617 rsp->channel_number, rsp->status); 618 return ret; 619 } 620 621 int wcn36xx_smd_switch_channel(struct wcn36xx *wcn, 622 struct ieee80211_vif *vif, int ch) 623 { 624 struct wcn36xx_hal_switch_channel_req_msg msg_body; 625 int ret = 0; 626 627 mutex_lock(&wcn->hal_mutex); 628 INIT_HAL_MSG(msg_body, WCN36XX_HAL_CH_SWITCH_REQ); 629 630 msg_body.channel_number = (u8)ch; 631 msg_body.tx_mgmt_power = 0xbf; 632 msg_body.max_tx_power = 0xbf; 633 memcpy(msg_body.self_sta_mac_addr, vif->addr, ETH_ALEN); 634 635 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 636 637 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 638 if (ret) { 639 wcn36xx_err("Sending hal_switch_channel failed\n"); 640 goto out; 641 } 642 ret = wcn36xx_smd_switch_channel_rsp(wcn->hal_buf, wcn->hal_rsp_len); 643 if (ret) { 644 wcn36xx_err("hal_switch_channel response failed err=%d\n", ret); 645 goto out; 646 } 647 out: 648 mutex_unlock(&wcn->hal_mutex); 649 return ret; 650 } 651 652 static int wcn36xx_smd_update_scan_params_rsp(void *buf, size_t len) 653 { 654 struct wcn36xx_hal_update_scan_params_resp *rsp; 655 656 rsp = (struct wcn36xx_hal_update_scan_params_resp *)buf; 657 658 /* Remove the PNO version bit */ 659 rsp->status &= (~(WCN36XX_FW_MSG_PNO_VERSION_MASK)); 660 661 if (WCN36XX_FW_MSG_RESULT_SUCCESS != rsp->status) { 662 wcn36xx_warn("error response from update scan\n"); 663 return rsp->status; 664 } 665 666 return 0; 667 } 668 669 int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn) 670 { 671 struct wcn36xx_hal_update_scan_params_req msg_body; 672 int ret = 0; 673 674 mutex_lock(&wcn->hal_mutex); 675 INIT_HAL_MSG(msg_body, WCN36XX_HAL_UPDATE_SCAN_PARAM_REQ); 676 677 msg_body.dot11d_enabled = 0; 678 msg_body.dot11d_resolved = 0; 679 msg_body.channel_count = 26; 680 msg_body.active_min_ch_time = 60; 681 msg_body.active_max_ch_time = 120; 682 msg_body.passive_min_ch_time = 60; 683 msg_body.passive_max_ch_time = 110; 684 msg_body.state = 0; 685 686 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 687 688 wcn36xx_dbg(WCN36XX_DBG_HAL, 689 "hal update scan params channel_count %d\n", 690 msg_body.channel_count); 691 692 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 693 if (ret) { 694 wcn36xx_err("Sending hal_update_scan_params failed\n"); 695 goto out; 696 } 697 ret = wcn36xx_smd_update_scan_params_rsp(wcn->hal_buf, 698 wcn->hal_rsp_len); 699 if (ret) { 700 wcn36xx_err("hal_update_scan_params response failed err=%d\n", 701 ret); 702 goto out; 703 } 704 out: 705 mutex_unlock(&wcn->hal_mutex); 706 return ret; 707 } 708 709 static int wcn36xx_smd_add_sta_self_rsp(struct wcn36xx *wcn, 710 struct ieee80211_vif *vif, 711 void *buf, 712 size_t len) 713 { 714 struct wcn36xx_hal_add_sta_self_rsp_msg *rsp; 715 struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv; 716 717 if (len < sizeof(*rsp)) 718 return -EINVAL; 719 720 rsp = (struct wcn36xx_hal_add_sta_self_rsp_msg *)buf; 721 722 if (rsp->status != WCN36XX_FW_MSG_RESULT_SUCCESS) { 723 wcn36xx_warn("hal add sta self failure: %d\n", 724 rsp->status); 725 return rsp->status; 726 } 727 728 wcn36xx_dbg(WCN36XX_DBG_HAL, 729 "hal add sta self status %d self_sta_index %d dpu_index %d\n", 730 rsp->status, rsp->self_sta_index, rsp->dpu_index); 731 732 priv_vif->self_sta_index = rsp->self_sta_index; 733 priv_vif->self_dpu_desc_index = rsp->dpu_index; 734 735 return 0; 736 } 737 738 int wcn36xx_smd_add_sta_self(struct wcn36xx *wcn, struct ieee80211_vif *vif) 739 { 740 struct wcn36xx_hal_add_sta_self_req msg_body; 741 int ret = 0; 742 743 mutex_lock(&wcn->hal_mutex); 744 INIT_HAL_MSG(msg_body, WCN36XX_HAL_ADD_STA_SELF_REQ); 745 746 memcpy(&msg_body.self_addr, vif->addr, ETH_ALEN); 747 748 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 749 750 wcn36xx_dbg(WCN36XX_DBG_HAL, 751 "hal add sta self self_addr %pM status %d\n", 752 msg_body.self_addr, msg_body.status); 753 754 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 755 if (ret) { 756 wcn36xx_err("Sending hal_add_sta_self failed\n"); 757 goto out; 758 } 759 ret = wcn36xx_smd_add_sta_self_rsp(wcn, 760 vif, 761 wcn->hal_buf, 762 wcn->hal_rsp_len); 763 if (ret) { 764 wcn36xx_err("hal_add_sta_self response failed err=%d\n", ret); 765 goto out; 766 } 767 out: 768 mutex_unlock(&wcn->hal_mutex); 769 return ret; 770 } 771 772 int wcn36xx_smd_delete_sta_self(struct wcn36xx *wcn, u8 *addr) 773 { 774 struct wcn36xx_hal_del_sta_self_req_msg msg_body; 775 int ret = 0; 776 777 mutex_lock(&wcn->hal_mutex); 778 INIT_HAL_MSG(msg_body, WCN36XX_HAL_DEL_STA_SELF_REQ); 779 780 memcpy(&msg_body.self_addr, addr, ETH_ALEN); 781 782 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 783 784 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 785 if (ret) { 786 wcn36xx_err("Sending hal_delete_sta_self failed\n"); 787 goto out; 788 } 789 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 790 if (ret) { 791 wcn36xx_err("hal_delete_sta_self response failed err=%d\n", 792 ret); 793 goto out; 794 } 795 out: 796 mutex_unlock(&wcn->hal_mutex); 797 return ret; 798 } 799 800 int wcn36xx_smd_delete_sta(struct wcn36xx *wcn, u8 sta_index) 801 { 802 struct wcn36xx_hal_delete_sta_req_msg msg_body; 803 int ret = 0; 804 805 mutex_lock(&wcn->hal_mutex); 806 INIT_HAL_MSG(msg_body, WCN36XX_HAL_DELETE_STA_REQ); 807 808 msg_body.sta_index = sta_index; 809 810 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 811 812 wcn36xx_dbg(WCN36XX_DBG_HAL, 813 "hal delete sta sta_index %d\n", 814 msg_body.sta_index); 815 816 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 817 if (ret) { 818 wcn36xx_err("Sending hal_delete_sta failed\n"); 819 goto out; 820 } 821 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 822 if (ret) { 823 wcn36xx_err("hal_delete_sta response failed err=%d\n", ret); 824 goto out; 825 } 826 out: 827 mutex_unlock(&wcn->hal_mutex); 828 return ret; 829 } 830 831 static int wcn36xx_smd_join_rsp(void *buf, size_t len) 832 { 833 struct wcn36xx_hal_join_rsp_msg *rsp; 834 835 if (wcn36xx_smd_rsp_status_check(buf, len)) 836 return -EIO; 837 838 rsp = (struct wcn36xx_hal_join_rsp_msg *)buf; 839 840 wcn36xx_dbg(WCN36XX_DBG_HAL, 841 "hal rsp join status %d tx_mgmt_power %d\n", 842 rsp->status, rsp->tx_mgmt_power); 843 844 return 0; 845 } 846 847 int wcn36xx_smd_join(struct wcn36xx *wcn, const u8 *bssid, u8 *vif, u8 ch) 848 { 849 struct wcn36xx_hal_join_req_msg msg_body; 850 int ret = 0; 851 852 mutex_lock(&wcn->hal_mutex); 853 INIT_HAL_MSG(msg_body, WCN36XX_HAL_JOIN_REQ); 854 855 memcpy(&msg_body.bssid, bssid, ETH_ALEN); 856 memcpy(&msg_body.self_sta_mac_addr, vif, ETH_ALEN); 857 msg_body.channel = ch; 858 859 if (conf_is_ht40_minus(&wcn->hw->conf)) 860 msg_body.secondary_channel_offset = 861 PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; 862 else if (conf_is_ht40_plus(&wcn->hw->conf)) 863 msg_body.secondary_channel_offset = 864 PHY_DOUBLE_CHANNEL_LOW_PRIMARY; 865 else 866 msg_body.secondary_channel_offset = 867 PHY_SINGLE_CHANNEL_CENTERED; 868 869 msg_body.link_state = WCN36XX_HAL_LINK_PREASSOC_STATE; 870 871 msg_body.max_tx_power = 0xbf; 872 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 873 874 wcn36xx_dbg(WCN36XX_DBG_HAL, 875 "hal join req bssid %pM self_sta_mac_addr %pM channel %d link_state %d\n", 876 msg_body.bssid, msg_body.self_sta_mac_addr, 877 msg_body.channel, msg_body.link_state); 878 879 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 880 if (ret) { 881 wcn36xx_err("Sending hal_join failed\n"); 882 goto out; 883 } 884 ret = wcn36xx_smd_join_rsp(wcn->hal_buf, wcn->hal_rsp_len); 885 if (ret) { 886 wcn36xx_err("hal_join response failed err=%d\n", ret); 887 goto out; 888 } 889 out: 890 mutex_unlock(&wcn->hal_mutex); 891 return ret; 892 } 893 894 int wcn36xx_smd_set_link_st(struct wcn36xx *wcn, const u8 *bssid, 895 const u8 *sta_mac, 896 enum wcn36xx_hal_link_state state) 897 { 898 struct wcn36xx_hal_set_link_state_req_msg msg_body; 899 int ret = 0; 900 901 mutex_lock(&wcn->hal_mutex); 902 INIT_HAL_MSG(msg_body, WCN36XX_HAL_SET_LINK_ST_REQ); 903 904 memcpy(&msg_body.bssid, bssid, ETH_ALEN); 905 memcpy(&msg_body.self_mac_addr, sta_mac, ETH_ALEN); 906 msg_body.state = state; 907 908 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 909 910 wcn36xx_dbg(WCN36XX_DBG_HAL, 911 "hal set link state bssid %pM self_mac_addr %pM state %d\n", 912 msg_body.bssid, msg_body.self_mac_addr, msg_body.state); 913 914 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 915 if (ret) { 916 wcn36xx_err("Sending hal_set_link_st failed\n"); 917 goto out; 918 } 919 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 920 if (ret) { 921 wcn36xx_err("hal_set_link_st response failed err=%d\n", ret); 922 goto out; 923 } 924 out: 925 mutex_unlock(&wcn->hal_mutex); 926 return ret; 927 } 928 929 static void wcn36xx_smd_convert_sta_to_v1(struct wcn36xx *wcn, 930 const struct wcn36xx_hal_config_sta_params *orig, 931 struct wcn36xx_hal_config_sta_params_v1 *v1) 932 { 933 /* convert orig to v1 format */ 934 memcpy(&v1->bssid, orig->bssid, ETH_ALEN); 935 memcpy(&v1->mac, orig->mac, ETH_ALEN); 936 v1->aid = orig->aid; 937 v1->type = orig->type; 938 v1->listen_interval = orig->listen_interval; 939 v1->ht_capable = orig->ht_capable; 940 941 v1->max_ampdu_size = orig->max_ampdu_size; 942 v1->max_ampdu_density = orig->max_ampdu_density; 943 v1->sgi_40mhz = orig->sgi_40mhz; 944 v1->sgi_20Mhz = orig->sgi_20Mhz; 945 946 memcpy(&v1->supported_rates, &orig->supported_rates, 947 sizeof(orig->supported_rates)); 948 v1->sta_index = orig->sta_index; 949 } 950 951 static int wcn36xx_smd_config_sta_rsp(struct wcn36xx *wcn, 952 struct ieee80211_sta *sta, 953 void *buf, 954 size_t len) 955 { 956 struct wcn36xx_hal_config_sta_rsp_msg *rsp; 957 struct config_sta_rsp_params *params; 958 struct wcn36xx_sta *sta_priv = (struct wcn36xx_sta *)sta->drv_priv; 959 960 if (len < sizeof(*rsp)) 961 return -EINVAL; 962 963 rsp = (struct wcn36xx_hal_config_sta_rsp_msg *)buf; 964 params = &rsp->params; 965 966 if (params->status != WCN36XX_FW_MSG_RESULT_SUCCESS) { 967 wcn36xx_warn("hal config sta response failure: %d\n", 968 params->status); 969 return -EIO; 970 } 971 972 sta_priv->sta_index = params->sta_index; 973 sta_priv->dpu_desc_index = params->dpu_index; 974 sta_priv->ucast_dpu_sign = params->uc_ucast_sig; 975 976 wcn36xx_dbg(WCN36XX_DBG_HAL, 977 "hal config sta rsp status %d sta_index %d bssid_index %d uc_ucast_sig %d p2p %d\n", 978 params->status, params->sta_index, params->bssid_index, 979 params->uc_ucast_sig, params->p2p); 980 981 return 0; 982 } 983 984 static int wcn36xx_smd_config_sta_v1(struct wcn36xx *wcn, 985 const struct wcn36xx_hal_config_sta_req_msg *orig) 986 { 987 struct wcn36xx_hal_config_sta_req_msg_v1 msg_body; 988 struct wcn36xx_hal_config_sta_params_v1 *sta = &msg_body.sta_params; 989 990 INIT_HAL_MSG(msg_body, WCN36XX_HAL_CONFIG_STA_REQ); 991 992 wcn36xx_smd_convert_sta_to_v1(wcn, &orig->sta_params, 993 &msg_body.sta_params); 994 995 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 996 997 wcn36xx_dbg(WCN36XX_DBG_HAL, 998 "hal config sta v1 action %d sta_index %d bssid_index %d bssid %pM type %d mac %pM aid %d\n", 999 sta->action, sta->sta_index, sta->bssid_index, 1000 sta->bssid, sta->type, sta->mac, sta->aid); 1001 1002 return wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 1003 } 1004 1005 int wcn36xx_smd_config_sta(struct wcn36xx *wcn, struct ieee80211_vif *vif, 1006 struct ieee80211_sta *sta) 1007 { 1008 struct wcn36xx_hal_config_sta_req_msg msg; 1009 struct wcn36xx_hal_config_sta_params *sta_params; 1010 int ret = 0; 1011 1012 mutex_lock(&wcn->hal_mutex); 1013 INIT_HAL_MSG(msg, WCN36XX_HAL_CONFIG_STA_REQ); 1014 1015 sta_params = &msg.sta_params; 1016 1017 wcn36xx_smd_set_sta_params(wcn, vif, sta, sta_params); 1018 1019 if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) { 1020 ret = wcn36xx_smd_config_sta_v1(wcn, &msg); 1021 } else { 1022 PREPARE_HAL_BUF(wcn->hal_buf, msg); 1023 1024 wcn36xx_dbg(WCN36XX_DBG_HAL, 1025 "hal config sta action %d sta_index %d bssid_index %d bssid %pM type %d mac %pM aid %d\n", 1026 sta_params->action, sta_params->sta_index, 1027 sta_params->bssid_index, sta_params->bssid, 1028 sta_params->type, sta_params->mac, sta_params->aid); 1029 1030 ret = wcn36xx_smd_send_and_wait(wcn, msg.header.len); 1031 } 1032 if (ret) { 1033 wcn36xx_err("Sending hal_config_sta failed\n"); 1034 goto out; 1035 } 1036 ret = wcn36xx_smd_config_sta_rsp(wcn, 1037 sta, 1038 wcn->hal_buf, 1039 wcn->hal_rsp_len); 1040 if (ret) { 1041 wcn36xx_err("hal_config_sta response failed err=%d\n", ret); 1042 goto out; 1043 } 1044 out: 1045 mutex_unlock(&wcn->hal_mutex); 1046 return ret; 1047 } 1048 1049 static int wcn36xx_smd_config_bss_v1(struct wcn36xx *wcn, 1050 const struct wcn36xx_hal_config_bss_req_msg *orig) 1051 { 1052 struct wcn36xx_hal_config_bss_req_msg_v1 msg_body; 1053 struct wcn36xx_hal_config_bss_params_v1 *bss = &msg_body.bss_params; 1054 struct wcn36xx_hal_config_sta_params_v1 *sta = &bss->sta; 1055 1056 INIT_HAL_MSG(msg_body, WCN36XX_HAL_CONFIG_BSS_REQ); 1057 1058 /* convert orig to v1 */ 1059 memcpy(&msg_body.bss_params.bssid, 1060 &orig->bss_params.bssid, ETH_ALEN); 1061 memcpy(&msg_body.bss_params.self_mac_addr, 1062 &orig->bss_params.self_mac_addr, ETH_ALEN); 1063 1064 msg_body.bss_params.bss_type = orig->bss_params.bss_type; 1065 msg_body.bss_params.oper_mode = orig->bss_params.oper_mode; 1066 msg_body.bss_params.nw_type = orig->bss_params.nw_type; 1067 1068 msg_body.bss_params.short_slot_time_supported = 1069 orig->bss_params.short_slot_time_supported; 1070 msg_body.bss_params.lla_coexist = orig->bss_params.lla_coexist; 1071 msg_body.bss_params.llb_coexist = orig->bss_params.llb_coexist; 1072 msg_body.bss_params.llg_coexist = orig->bss_params.llg_coexist; 1073 msg_body.bss_params.ht20_coexist = orig->bss_params.ht20_coexist; 1074 msg_body.bss_params.lln_non_gf_coexist = 1075 orig->bss_params.lln_non_gf_coexist; 1076 1077 msg_body.bss_params.lsig_tx_op_protection_full_support = 1078 orig->bss_params.lsig_tx_op_protection_full_support; 1079 msg_body.bss_params.rifs_mode = orig->bss_params.rifs_mode; 1080 msg_body.bss_params.beacon_interval = orig->bss_params.beacon_interval; 1081 msg_body.bss_params.dtim_period = orig->bss_params.dtim_period; 1082 msg_body.bss_params.tx_channel_width_set = 1083 orig->bss_params.tx_channel_width_set; 1084 msg_body.bss_params.oper_channel = orig->bss_params.oper_channel; 1085 msg_body.bss_params.ext_channel = orig->bss_params.ext_channel; 1086 1087 msg_body.bss_params.reserved = orig->bss_params.reserved; 1088 1089 memcpy(&msg_body.bss_params.ssid, 1090 &orig->bss_params.ssid, 1091 sizeof(orig->bss_params.ssid)); 1092 1093 msg_body.bss_params.action = orig->bss_params.action; 1094 msg_body.bss_params.rateset = orig->bss_params.rateset; 1095 msg_body.bss_params.ht = orig->bss_params.ht; 1096 msg_body.bss_params.obss_prot_enabled = 1097 orig->bss_params.obss_prot_enabled; 1098 msg_body.bss_params.rmf = orig->bss_params.rmf; 1099 msg_body.bss_params.ht_oper_mode = orig->bss_params.ht_oper_mode; 1100 msg_body.bss_params.dual_cts_protection = 1101 orig->bss_params.dual_cts_protection; 1102 1103 msg_body.bss_params.max_probe_resp_retry_limit = 1104 orig->bss_params.max_probe_resp_retry_limit; 1105 msg_body.bss_params.hidden_ssid = orig->bss_params.hidden_ssid; 1106 msg_body.bss_params.proxy_probe_resp = 1107 orig->bss_params.proxy_probe_resp; 1108 msg_body.bss_params.edca_params_valid = 1109 orig->bss_params.edca_params_valid; 1110 1111 memcpy(&msg_body.bss_params.acbe, 1112 &orig->bss_params.acbe, 1113 sizeof(orig->bss_params.acbe)); 1114 memcpy(&msg_body.bss_params.acbk, 1115 &orig->bss_params.acbk, 1116 sizeof(orig->bss_params.acbk)); 1117 memcpy(&msg_body.bss_params.acvi, 1118 &orig->bss_params.acvi, 1119 sizeof(orig->bss_params.acvi)); 1120 memcpy(&msg_body.bss_params.acvo, 1121 &orig->bss_params.acvo, 1122 sizeof(orig->bss_params.acvo)); 1123 1124 msg_body.bss_params.ext_set_sta_key_param_valid = 1125 orig->bss_params.ext_set_sta_key_param_valid; 1126 1127 memcpy(&msg_body.bss_params.ext_set_sta_key_param, 1128 &orig->bss_params.ext_set_sta_key_param, 1129 sizeof(orig->bss_params.acvo)); 1130 1131 msg_body.bss_params.wcn36xx_hal_persona = 1132 orig->bss_params.wcn36xx_hal_persona; 1133 msg_body.bss_params.spectrum_mgt_enable = 1134 orig->bss_params.spectrum_mgt_enable; 1135 msg_body.bss_params.tx_mgmt_power = orig->bss_params.tx_mgmt_power; 1136 msg_body.bss_params.max_tx_power = orig->bss_params.max_tx_power; 1137 1138 wcn36xx_smd_convert_sta_to_v1(wcn, &orig->bss_params.sta, 1139 &msg_body.bss_params.sta); 1140 1141 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 1142 1143 wcn36xx_dbg(WCN36XX_DBG_HAL, 1144 "hal config bss v1 bssid %pM self_mac_addr %pM bss_type %d oper_mode %d nw_type %d\n", 1145 bss->bssid, bss->self_mac_addr, bss->bss_type, 1146 bss->oper_mode, bss->nw_type); 1147 1148 wcn36xx_dbg(WCN36XX_DBG_HAL, 1149 "- sta bssid %pM action %d sta_index %d bssid_index %d aid %d type %d mac %pM\n", 1150 sta->bssid, sta->action, sta->sta_index, 1151 sta->bssid_index, sta->aid, sta->type, sta->mac); 1152 1153 return wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 1154 } 1155 1156 1157 static int wcn36xx_smd_config_bss_rsp(struct wcn36xx *wcn, 1158 struct ieee80211_vif *vif, 1159 void *buf, 1160 size_t len) 1161 { 1162 struct wcn36xx_hal_config_bss_rsp_msg *rsp; 1163 struct wcn36xx_hal_config_bss_rsp_params *params; 1164 struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv; 1165 1166 if (len < sizeof(*rsp)) 1167 return -EINVAL; 1168 1169 rsp = (struct wcn36xx_hal_config_bss_rsp_msg *)buf; 1170 params = &rsp->bss_rsp_params; 1171 1172 if (params->status != WCN36XX_FW_MSG_RESULT_SUCCESS) { 1173 wcn36xx_warn("hal config bss response failure: %d\n", 1174 params->status); 1175 return -EIO; 1176 } 1177 1178 wcn36xx_dbg(WCN36XX_DBG_HAL, 1179 "hal config bss rsp status %d bss_idx %d dpu_desc_index %d" 1180 " sta_idx %d self_idx %d bcast_idx %d mac %pM" 1181 " power %d ucast_dpu_signature %d\n", 1182 params->status, params->bss_index, params->dpu_desc_index, 1183 params->bss_sta_index, params->bss_self_sta_index, 1184 params->bss_bcast_sta_idx, params->mac, 1185 params->tx_mgmt_power, params->ucast_dpu_signature); 1186 1187 priv_vif->bss_index = params->bss_index; 1188 1189 if (priv_vif->sta) { 1190 priv_vif->sta->bss_sta_index = params->bss_sta_index; 1191 priv_vif->sta->bss_dpu_desc_index = params->dpu_desc_index; 1192 } 1193 1194 priv_vif->self_ucast_dpu_sign = params->ucast_dpu_signature; 1195 1196 return 0; 1197 } 1198 1199 int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif, 1200 struct ieee80211_sta *sta, const u8 *bssid, 1201 bool update) 1202 { 1203 struct wcn36xx_hal_config_bss_req_msg msg; 1204 struct wcn36xx_hal_config_bss_params *bss; 1205 struct wcn36xx_hal_config_sta_params *sta_params; 1206 struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; 1207 int ret = 0; 1208 1209 mutex_lock(&wcn->hal_mutex); 1210 INIT_HAL_MSG(msg, WCN36XX_HAL_CONFIG_BSS_REQ); 1211 1212 bss = &msg.bss_params; 1213 sta_params = &bss->sta; 1214 1215 WARN_ON(is_zero_ether_addr(bssid)); 1216 1217 memcpy(&bss->bssid, bssid, ETH_ALEN); 1218 1219 memcpy(bss->self_mac_addr, vif->addr, ETH_ALEN); 1220 1221 if (vif->type == NL80211_IFTYPE_STATION) { 1222 bss->bss_type = WCN36XX_HAL_INFRASTRUCTURE_MODE; 1223 1224 /* STA */ 1225 bss->oper_mode = 1; 1226 bss->wcn36xx_hal_persona = WCN36XX_HAL_STA_MODE; 1227 } else if (vif->type == NL80211_IFTYPE_AP || 1228 vif->type == NL80211_IFTYPE_MESH_POINT) { 1229 bss->bss_type = WCN36XX_HAL_INFRA_AP_MODE; 1230 1231 /* AP */ 1232 bss->oper_mode = 0; 1233 bss->wcn36xx_hal_persona = WCN36XX_HAL_STA_SAP_MODE; 1234 } else if (vif->type == NL80211_IFTYPE_ADHOC) { 1235 bss->bss_type = WCN36XX_HAL_IBSS_MODE; 1236 1237 /* STA */ 1238 bss->oper_mode = 1; 1239 } else { 1240 wcn36xx_warn("Unknown type for bss config: %d\n", vif->type); 1241 } 1242 1243 if (vif->type == NL80211_IFTYPE_STATION) 1244 wcn36xx_smd_set_bss_nw_type(wcn, sta, bss); 1245 else 1246 bss->nw_type = WCN36XX_HAL_11N_NW_TYPE; 1247 1248 bss->short_slot_time_supported = vif->bss_conf.use_short_slot; 1249 bss->lla_coexist = 0; 1250 bss->llb_coexist = 0; 1251 bss->llg_coexist = 0; 1252 bss->rifs_mode = 0; 1253 bss->beacon_interval = vif->bss_conf.beacon_int; 1254 bss->dtim_period = vif_priv->dtim_period; 1255 1256 wcn36xx_smd_set_bss_ht_params(vif, sta, bss); 1257 1258 bss->oper_channel = WCN36XX_HW_CHANNEL(wcn); 1259 1260 if (conf_is_ht40_minus(&wcn->hw->conf)) 1261 bss->ext_channel = IEEE80211_HT_PARAM_CHA_SEC_BELOW; 1262 else if (conf_is_ht40_plus(&wcn->hw->conf)) 1263 bss->ext_channel = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; 1264 else 1265 bss->ext_channel = IEEE80211_HT_PARAM_CHA_SEC_NONE; 1266 1267 bss->reserved = 0; 1268 wcn36xx_smd_set_sta_params(wcn, vif, sta, sta_params); 1269 1270 /* wcn->ssid is only valid in AP and IBSS mode */ 1271 bss->ssid.length = vif_priv->ssid.length; 1272 memcpy(bss->ssid.ssid, vif_priv->ssid.ssid, vif_priv->ssid.length); 1273 1274 bss->obss_prot_enabled = 0; 1275 bss->rmf = 0; 1276 bss->max_probe_resp_retry_limit = 0; 1277 bss->hidden_ssid = vif->bss_conf.hidden_ssid; 1278 bss->proxy_probe_resp = 0; 1279 bss->edca_params_valid = 0; 1280 1281 /* FIXME: set acbe, acbk, acvi and acvo */ 1282 1283 bss->ext_set_sta_key_param_valid = 0; 1284 1285 /* FIXME: set ext_set_sta_key_param */ 1286 1287 bss->spectrum_mgt_enable = 0; 1288 bss->tx_mgmt_power = 0; 1289 bss->max_tx_power = WCN36XX_MAX_POWER(wcn); 1290 1291 bss->action = update; 1292 1293 wcn36xx_dbg(WCN36XX_DBG_HAL, 1294 "hal config bss bssid %pM self_mac_addr %pM bss_type %d oper_mode %d nw_type %d\n", 1295 bss->bssid, bss->self_mac_addr, bss->bss_type, 1296 bss->oper_mode, bss->nw_type); 1297 1298 wcn36xx_dbg(WCN36XX_DBG_HAL, 1299 "- sta bssid %pM action %d sta_index %d bssid_index %d aid %d type %d mac %pM\n", 1300 sta_params->bssid, sta_params->action, 1301 sta_params->sta_index, sta_params->bssid_index, 1302 sta_params->aid, sta_params->type, 1303 sta_params->mac); 1304 1305 if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) { 1306 ret = wcn36xx_smd_config_bss_v1(wcn, &msg); 1307 } else { 1308 PREPARE_HAL_BUF(wcn->hal_buf, msg); 1309 1310 ret = wcn36xx_smd_send_and_wait(wcn, msg.header.len); 1311 } 1312 if (ret) { 1313 wcn36xx_err("Sending hal_config_bss failed\n"); 1314 goto out; 1315 } 1316 ret = wcn36xx_smd_config_bss_rsp(wcn, 1317 vif, 1318 wcn->hal_buf, 1319 wcn->hal_rsp_len); 1320 if (ret) { 1321 wcn36xx_err("hal_config_bss response failed err=%d\n", ret); 1322 goto out; 1323 } 1324 out: 1325 mutex_unlock(&wcn->hal_mutex); 1326 return ret; 1327 } 1328 1329 int wcn36xx_smd_delete_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif) 1330 { 1331 struct wcn36xx_hal_delete_bss_req_msg msg_body; 1332 struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv; 1333 int ret = 0; 1334 1335 mutex_lock(&wcn->hal_mutex); 1336 INIT_HAL_MSG(msg_body, WCN36XX_HAL_DELETE_BSS_REQ); 1337 1338 msg_body.bss_index = priv_vif->bss_index; 1339 1340 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 1341 1342 wcn36xx_dbg(WCN36XX_DBG_HAL, "hal delete bss %d\n", msg_body.bss_index); 1343 1344 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 1345 if (ret) { 1346 wcn36xx_err("Sending hal_delete_bss failed\n"); 1347 goto out; 1348 } 1349 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 1350 if (ret) { 1351 wcn36xx_err("hal_delete_bss response failed err=%d\n", ret); 1352 goto out; 1353 } 1354 out: 1355 mutex_unlock(&wcn->hal_mutex); 1356 return ret; 1357 } 1358 1359 int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct ieee80211_vif *vif, 1360 struct sk_buff *skb_beacon, u16 tim_off, 1361 u16 p2p_off) 1362 { 1363 struct wcn36xx_hal_send_beacon_req_msg msg_body; 1364 int ret = 0; 1365 1366 mutex_lock(&wcn->hal_mutex); 1367 INIT_HAL_MSG(msg_body, WCN36XX_HAL_SEND_BEACON_REQ); 1368 1369 /* TODO need to find out why this is needed? */ 1370 msg_body.beacon_length = skb_beacon->len + 6; 1371 1372 if (BEACON_TEMPLATE_SIZE > msg_body.beacon_length) { 1373 memcpy(&msg_body.beacon, &skb_beacon->len, sizeof(u32)); 1374 memcpy(&(msg_body.beacon[4]), skb_beacon->data, 1375 skb_beacon->len); 1376 } else { 1377 wcn36xx_err("Beacon is to big: beacon size=%d\n", 1378 msg_body.beacon_length); 1379 ret = -ENOMEM; 1380 goto out; 1381 } 1382 memcpy(msg_body.bssid, vif->addr, ETH_ALEN); 1383 1384 /* TODO need to find out why this is needed? */ 1385 if (vif->type == NL80211_IFTYPE_MESH_POINT) 1386 /* mesh beacon don't need this, so push further down */ 1387 msg_body.tim_ie_offset = 256; 1388 else 1389 msg_body.tim_ie_offset = tim_off+4; 1390 msg_body.p2p_ie_offset = p2p_off; 1391 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 1392 1393 wcn36xx_dbg(WCN36XX_DBG_HAL, 1394 "hal send beacon beacon_length %d\n", 1395 msg_body.beacon_length); 1396 1397 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 1398 if (ret) { 1399 wcn36xx_err("Sending hal_send_beacon failed\n"); 1400 goto out; 1401 } 1402 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 1403 if (ret) { 1404 wcn36xx_err("hal_send_beacon response failed err=%d\n", ret); 1405 goto out; 1406 } 1407 out: 1408 mutex_unlock(&wcn->hal_mutex); 1409 return ret; 1410 } 1411 1412 int wcn36xx_smd_update_proberesp_tmpl(struct wcn36xx *wcn, 1413 struct ieee80211_vif *vif, 1414 struct sk_buff *skb) 1415 { 1416 struct wcn36xx_hal_send_probe_resp_req_msg msg; 1417 int ret = 0; 1418 1419 mutex_lock(&wcn->hal_mutex); 1420 INIT_HAL_MSG(msg, WCN36XX_HAL_UPDATE_PROBE_RSP_TEMPLATE_REQ); 1421 1422 if (skb->len > BEACON_TEMPLATE_SIZE) { 1423 wcn36xx_warn("probe response template is too big: %d\n", 1424 skb->len); 1425 ret = -E2BIG; 1426 goto out; 1427 } 1428 1429 msg.probe_resp_template_len = skb->len; 1430 memcpy(&msg.probe_resp_template, skb->data, skb->len); 1431 1432 memcpy(msg.bssid, vif->addr, ETH_ALEN); 1433 1434 PREPARE_HAL_BUF(wcn->hal_buf, msg); 1435 1436 wcn36xx_dbg(WCN36XX_DBG_HAL, 1437 "hal update probe rsp len %d bssid %pM\n", 1438 msg.probe_resp_template_len, msg.bssid); 1439 1440 ret = wcn36xx_smd_send_and_wait(wcn, msg.header.len); 1441 if (ret) { 1442 wcn36xx_err("Sending hal_update_proberesp_tmpl failed\n"); 1443 goto out; 1444 } 1445 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 1446 if (ret) { 1447 wcn36xx_err("hal_update_proberesp_tmpl response failed err=%d\n", 1448 ret); 1449 goto out; 1450 } 1451 out: 1452 mutex_unlock(&wcn->hal_mutex); 1453 return ret; 1454 } 1455 1456 int wcn36xx_smd_set_stakey(struct wcn36xx *wcn, 1457 enum ani_ed_type enc_type, 1458 u8 keyidx, 1459 u8 keylen, 1460 u8 *key, 1461 u8 sta_index) 1462 { 1463 struct wcn36xx_hal_set_sta_key_req_msg msg_body; 1464 int ret = 0; 1465 1466 mutex_lock(&wcn->hal_mutex); 1467 INIT_HAL_MSG(msg_body, WCN36XX_HAL_SET_STAKEY_REQ); 1468 1469 msg_body.set_sta_key_params.sta_index = sta_index; 1470 msg_body.set_sta_key_params.enc_type = enc_type; 1471 1472 msg_body.set_sta_key_params.key[0].id = keyidx; 1473 msg_body.set_sta_key_params.key[0].unicast = 1; 1474 msg_body.set_sta_key_params.key[0].direction = WCN36XX_HAL_TX_RX; 1475 msg_body.set_sta_key_params.key[0].pae_role = 0; 1476 msg_body.set_sta_key_params.key[0].length = keylen; 1477 memcpy(msg_body.set_sta_key_params.key[0].key, key, keylen); 1478 msg_body.set_sta_key_params.single_tid_rc = 1; 1479 1480 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 1481 1482 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 1483 if (ret) { 1484 wcn36xx_err("Sending hal_set_stakey failed\n"); 1485 goto out; 1486 } 1487 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 1488 if (ret) { 1489 wcn36xx_err("hal_set_stakey response failed err=%d\n", ret); 1490 goto out; 1491 } 1492 out: 1493 mutex_unlock(&wcn->hal_mutex); 1494 return ret; 1495 } 1496 1497 int wcn36xx_smd_set_bsskey(struct wcn36xx *wcn, 1498 enum ani_ed_type enc_type, 1499 u8 keyidx, 1500 u8 keylen, 1501 u8 *key) 1502 { 1503 struct wcn36xx_hal_set_bss_key_req_msg msg_body; 1504 int ret = 0; 1505 1506 mutex_lock(&wcn->hal_mutex); 1507 INIT_HAL_MSG(msg_body, WCN36XX_HAL_SET_BSSKEY_REQ); 1508 msg_body.bss_idx = 0; 1509 msg_body.enc_type = enc_type; 1510 msg_body.num_keys = 1; 1511 msg_body.keys[0].id = keyidx; 1512 msg_body.keys[0].unicast = 0; 1513 msg_body.keys[0].direction = WCN36XX_HAL_RX_ONLY; 1514 msg_body.keys[0].pae_role = 0; 1515 msg_body.keys[0].length = keylen; 1516 memcpy(msg_body.keys[0].key, key, keylen); 1517 1518 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 1519 1520 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 1521 if (ret) { 1522 wcn36xx_err("Sending hal_set_bsskey failed\n"); 1523 goto out; 1524 } 1525 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 1526 if (ret) { 1527 wcn36xx_err("hal_set_bsskey response failed err=%d\n", ret); 1528 goto out; 1529 } 1530 out: 1531 mutex_unlock(&wcn->hal_mutex); 1532 return ret; 1533 } 1534 1535 int wcn36xx_smd_remove_stakey(struct wcn36xx *wcn, 1536 enum ani_ed_type enc_type, 1537 u8 keyidx, 1538 u8 sta_index) 1539 { 1540 struct wcn36xx_hal_remove_sta_key_req_msg msg_body; 1541 int ret = 0; 1542 1543 mutex_lock(&wcn->hal_mutex); 1544 INIT_HAL_MSG(msg_body, WCN36XX_HAL_RMV_STAKEY_REQ); 1545 1546 msg_body.sta_idx = sta_index; 1547 msg_body.enc_type = enc_type; 1548 msg_body.key_id = keyidx; 1549 1550 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 1551 1552 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 1553 if (ret) { 1554 wcn36xx_err("Sending hal_remove_stakey failed\n"); 1555 goto out; 1556 } 1557 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 1558 if (ret) { 1559 wcn36xx_err("hal_remove_stakey response failed err=%d\n", ret); 1560 goto out; 1561 } 1562 out: 1563 mutex_unlock(&wcn->hal_mutex); 1564 return ret; 1565 } 1566 1567 int wcn36xx_smd_remove_bsskey(struct wcn36xx *wcn, 1568 enum ani_ed_type enc_type, 1569 u8 keyidx) 1570 { 1571 struct wcn36xx_hal_remove_bss_key_req_msg msg_body; 1572 int ret = 0; 1573 1574 mutex_lock(&wcn->hal_mutex); 1575 INIT_HAL_MSG(msg_body, WCN36XX_HAL_RMV_BSSKEY_REQ); 1576 msg_body.bss_idx = 0; 1577 msg_body.enc_type = enc_type; 1578 msg_body.key_id = keyidx; 1579 1580 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 1581 1582 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 1583 if (ret) { 1584 wcn36xx_err("Sending hal_remove_bsskey failed\n"); 1585 goto out; 1586 } 1587 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 1588 if (ret) { 1589 wcn36xx_err("hal_remove_bsskey response failed err=%d\n", ret); 1590 goto out; 1591 } 1592 out: 1593 mutex_unlock(&wcn->hal_mutex); 1594 return ret; 1595 } 1596 1597 int wcn36xx_smd_enter_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif) 1598 { 1599 struct wcn36xx_hal_enter_bmps_req_msg msg_body; 1600 struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; 1601 int ret = 0; 1602 1603 mutex_lock(&wcn->hal_mutex); 1604 INIT_HAL_MSG(msg_body, WCN36XX_HAL_ENTER_BMPS_REQ); 1605 1606 msg_body.bss_index = vif_priv->bss_index; 1607 msg_body.tbtt = vif->bss_conf.sync_tsf; 1608 msg_body.dtim_period = vif_priv->dtim_period; 1609 1610 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 1611 1612 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 1613 if (ret) { 1614 wcn36xx_err("Sending hal_enter_bmps failed\n"); 1615 goto out; 1616 } 1617 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 1618 if (ret) { 1619 wcn36xx_err("hal_enter_bmps response failed err=%d\n", ret); 1620 goto out; 1621 } 1622 out: 1623 mutex_unlock(&wcn->hal_mutex); 1624 return ret; 1625 } 1626 1627 int wcn36xx_smd_exit_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif) 1628 { 1629 struct wcn36xx_hal_enter_bmps_req_msg msg_body; 1630 struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; 1631 int ret = 0; 1632 1633 mutex_lock(&wcn->hal_mutex); 1634 INIT_HAL_MSG(msg_body, WCN36XX_HAL_EXIT_BMPS_REQ); 1635 1636 msg_body.bss_index = vif_priv->bss_index; 1637 1638 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 1639 1640 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 1641 if (ret) { 1642 wcn36xx_err("Sending hal_exit_bmps failed\n"); 1643 goto out; 1644 } 1645 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 1646 if (ret) { 1647 wcn36xx_err("hal_exit_bmps response failed err=%d\n", ret); 1648 goto out; 1649 } 1650 out: 1651 mutex_unlock(&wcn->hal_mutex); 1652 return ret; 1653 } 1654 int wcn36xx_smd_set_power_params(struct wcn36xx *wcn, bool ignore_dtim) 1655 { 1656 struct wcn36xx_hal_set_power_params_req_msg msg_body; 1657 int ret = 0; 1658 1659 mutex_lock(&wcn->hal_mutex); 1660 INIT_HAL_MSG(msg_body, WCN36XX_HAL_SET_POWER_PARAMS_REQ); 1661 1662 /* 1663 * When host is down ignore every second dtim 1664 */ 1665 if (ignore_dtim) { 1666 msg_body.ignore_dtim = 1; 1667 msg_body.dtim_period = 2; 1668 } 1669 msg_body.listen_interval = WCN36XX_LISTEN_INTERVAL(wcn); 1670 1671 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 1672 1673 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 1674 if (ret) { 1675 wcn36xx_err("Sending hal_set_power_params failed\n"); 1676 goto out; 1677 } 1678 1679 out: 1680 mutex_unlock(&wcn->hal_mutex); 1681 return ret; 1682 } 1683 /* Notice: This function should be called after associated, or else it 1684 * will be invalid 1685 */ 1686 int wcn36xx_smd_keep_alive_req(struct wcn36xx *wcn, 1687 struct ieee80211_vif *vif, 1688 int packet_type) 1689 { 1690 struct wcn36xx_hal_keep_alive_req_msg msg_body; 1691 struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; 1692 int ret = 0; 1693 1694 mutex_lock(&wcn->hal_mutex); 1695 INIT_HAL_MSG(msg_body, WCN36XX_HAL_KEEP_ALIVE_REQ); 1696 1697 if (packet_type == WCN36XX_HAL_KEEP_ALIVE_NULL_PKT) { 1698 msg_body.bss_index = vif_priv->bss_index; 1699 msg_body.packet_type = WCN36XX_HAL_KEEP_ALIVE_NULL_PKT; 1700 msg_body.time_period = WCN36XX_KEEP_ALIVE_TIME_PERIOD; 1701 } else if (packet_type == WCN36XX_HAL_KEEP_ALIVE_UNSOLICIT_ARP_RSP) { 1702 /* TODO: it also support ARP response type */ 1703 } else { 1704 wcn36xx_warn("unknown keep alive packet type %d\n", packet_type); 1705 ret = -EINVAL; 1706 goto out; 1707 } 1708 1709 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 1710 1711 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 1712 if (ret) { 1713 wcn36xx_err("Sending hal_keep_alive failed\n"); 1714 goto out; 1715 } 1716 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 1717 if (ret) { 1718 wcn36xx_err("hal_keep_alive response failed err=%d\n", ret); 1719 goto out; 1720 } 1721 out: 1722 mutex_unlock(&wcn->hal_mutex); 1723 return ret; 1724 } 1725 1726 int wcn36xx_smd_dump_cmd_req(struct wcn36xx *wcn, u32 arg1, u32 arg2, 1727 u32 arg3, u32 arg4, u32 arg5) 1728 { 1729 struct wcn36xx_hal_dump_cmd_req_msg msg_body; 1730 int ret = 0; 1731 1732 mutex_lock(&wcn->hal_mutex); 1733 INIT_HAL_MSG(msg_body, WCN36XX_HAL_DUMP_COMMAND_REQ); 1734 1735 msg_body.arg1 = arg1; 1736 msg_body.arg2 = arg2; 1737 msg_body.arg3 = arg3; 1738 msg_body.arg4 = arg4; 1739 msg_body.arg5 = arg5; 1740 1741 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 1742 1743 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 1744 if (ret) { 1745 wcn36xx_err("Sending hal_dump_cmd failed\n"); 1746 goto out; 1747 } 1748 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 1749 if (ret) { 1750 wcn36xx_err("hal_dump_cmd response failed err=%d\n", ret); 1751 goto out; 1752 } 1753 out: 1754 mutex_unlock(&wcn->hal_mutex); 1755 return ret; 1756 } 1757 1758 void set_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap) 1759 { 1760 int arr_idx, bit_idx; 1761 1762 if (cap < 0 || cap > 127) { 1763 wcn36xx_warn("error cap idx %d\n", cap); 1764 return; 1765 } 1766 1767 arr_idx = cap / 32; 1768 bit_idx = cap % 32; 1769 bitmap[arr_idx] |= (1 << bit_idx); 1770 } 1771 1772 int get_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap) 1773 { 1774 int arr_idx, bit_idx; 1775 int ret = 0; 1776 1777 if (cap < 0 || cap > 127) { 1778 wcn36xx_warn("error cap idx %d\n", cap); 1779 return -EINVAL; 1780 } 1781 1782 arr_idx = cap / 32; 1783 bit_idx = cap % 32; 1784 ret = (bitmap[arr_idx] & (1 << bit_idx)) ? 1 : 0; 1785 return ret; 1786 } 1787 1788 void clear_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap) 1789 { 1790 int arr_idx, bit_idx; 1791 1792 if (cap < 0 || cap > 127) { 1793 wcn36xx_warn("error cap idx %d\n", cap); 1794 return; 1795 } 1796 1797 arr_idx = cap / 32; 1798 bit_idx = cap % 32; 1799 bitmap[arr_idx] &= ~(1 << bit_idx); 1800 } 1801 1802 int wcn36xx_smd_feature_caps_exchange(struct wcn36xx *wcn) 1803 { 1804 struct wcn36xx_hal_feat_caps_msg msg_body, *rsp; 1805 int ret = 0, i; 1806 1807 mutex_lock(&wcn->hal_mutex); 1808 INIT_HAL_MSG(msg_body, WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_REQ); 1809 1810 set_feat_caps(msg_body.feat_caps, STA_POWERSAVE); 1811 1812 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 1813 1814 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 1815 if (ret) { 1816 wcn36xx_err("Sending hal_feature_caps_exchange failed\n"); 1817 goto out; 1818 } 1819 if (wcn->hal_rsp_len != sizeof(*rsp)) { 1820 wcn36xx_err("Invalid hal_feature_caps_exchange response"); 1821 goto out; 1822 } 1823 1824 rsp = (struct wcn36xx_hal_feat_caps_msg *) wcn->hal_buf; 1825 1826 for (i = 0; i < WCN36XX_HAL_CAPS_SIZE; i++) 1827 wcn->fw_feat_caps[i] = rsp->feat_caps[i]; 1828 out: 1829 mutex_unlock(&wcn->hal_mutex); 1830 return ret; 1831 } 1832 1833 int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn, 1834 struct ieee80211_sta *sta, 1835 u16 tid, 1836 u16 *ssn, 1837 u8 direction, 1838 u8 sta_index) 1839 { 1840 struct wcn36xx_hal_add_ba_session_req_msg msg_body; 1841 int ret = 0; 1842 1843 mutex_lock(&wcn->hal_mutex); 1844 INIT_HAL_MSG(msg_body, WCN36XX_HAL_ADD_BA_SESSION_REQ); 1845 1846 msg_body.sta_index = sta_index; 1847 memcpy(&msg_body.mac_addr, sta->addr, ETH_ALEN); 1848 msg_body.dialog_token = 0x10; 1849 msg_body.tid = tid; 1850 1851 /* Immediate BA because Delayed BA is not supported */ 1852 msg_body.policy = 1; 1853 msg_body.buffer_size = WCN36XX_AGGR_BUFFER_SIZE; 1854 msg_body.timeout = 0; 1855 if (ssn) 1856 msg_body.ssn = *ssn; 1857 msg_body.direction = direction; 1858 1859 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 1860 1861 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 1862 if (ret) { 1863 wcn36xx_err("Sending hal_add_ba_session failed\n"); 1864 goto out; 1865 } 1866 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 1867 if (ret) { 1868 wcn36xx_err("hal_add_ba_session response failed err=%d\n", ret); 1869 goto out; 1870 } 1871 out: 1872 mutex_unlock(&wcn->hal_mutex); 1873 return ret; 1874 } 1875 1876 int wcn36xx_smd_add_ba(struct wcn36xx *wcn) 1877 { 1878 struct wcn36xx_hal_add_ba_req_msg msg_body; 1879 int ret = 0; 1880 1881 mutex_lock(&wcn->hal_mutex); 1882 INIT_HAL_MSG(msg_body, WCN36XX_HAL_ADD_BA_REQ); 1883 1884 msg_body.session_id = 0; 1885 msg_body.win_size = WCN36XX_AGGR_BUFFER_SIZE; 1886 1887 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 1888 1889 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 1890 if (ret) { 1891 wcn36xx_err("Sending hal_add_ba failed\n"); 1892 goto out; 1893 } 1894 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 1895 if (ret) { 1896 wcn36xx_err("hal_add_ba response failed err=%d\n", ret); 1897 goto out; 1898 } 1899 out: 1900 mutex_unlock(&wcn->hal_mutex); 1901 return ret; 1902 } 1903 1904 int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 sta_index) 1905 { 1906 struct wcn36xx_hal_del_ba_req_msg msg_body; 1907 int ret = 0; 1908 1909 mutex_lock(&wcn->hal_mutex); 1910 INIT_HAL_MSG(msg_body, WCN36XX_HAL_DEL_BA_REQ); 1911 1912 msg_body.sta_index = sta_index; 1913 msg_body.tid = tid; 1914 msg_body.direction = 0; 1915 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 1916 1917 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 1918 if (ret) { 1919 wcn36xx_err("Sending hal_del_ba failed\n"); 1920 goto out; 1921 } 1922 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 1923 if (ret) { 1924 wcn36xx_err("hal_del_ba response failed err=%d\n", ret); 1925 goto out; 1926 } 1927 out: 1928 mutex_unlock(&wcn->hal_mutex); 1929 return ret; 1930 } 1931 1932 int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index) 1933 { 1934 struct wcn36xx_hal_trigger_ba_req_msg msg_body; 1935 struct wcn36xx_hal_trigger_ba_req_candidate *candidate; 1936 int ret = 0; 1937 1938 mutex_lock(&wcn->hal_mutex); 1939 INIT_HAL_MSG(msg_body, WCN36XX_HAL_TRIGGER_BA_REQ); 1940 1941 msg_body.session_id = 0; 1942 msg_body.candidate_cnt = 1; 1943 msg_body.header.len += sizeof(*candidate); 1944 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 1945 1946 candidate = (struct wcn36xx_hal_trigger_ba_req_candidate *) 1947 (wcn->hal_buf + sizeof(msg_body)); 1948 candidate->sta_index = sta_index; 1949 candidate->tid_bitmap = 1; 1950 1951 ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); 1952 if (ret) { 1953 wcn36xx_err("Sending hal_trigger_ba failed\n"); 1954 goto out; 1955 } 1956 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 1957 if (ret) { 1958 wcn36xx_err("hal_trigger_ba response failed err=%d\n", ret); 1959 goto out; 1960 } 1961 out: 1962 mutex_unlock(&wcn->hal_mutex); 1963 return ret; 1964 } 1965 1966 static int wcn36xx_smd_tx_compl_ind(struct wcn36xx *wcn, void *buf, size_t len) 1967 { 1968 struct wcn36xx_hal_tx_compl_ind_msg *rsp = buf; 1969 1970 if (len != sizeof(*rsp)) { 1971 wcn36xx_warn("Bad TX complete indication\n"); 1972 return -EIO; 1973 } 1974 1975 wcn36xx_dxe_tx_ack_ind(wcn, rsp->status); 1976 1977 return 0; 1978 } 1979 1980 static int wcn36xx_smd_missed_beacon_ind(struct wcn36xx *wcn, 1981 void *buf, 1982 size_t len) 1983 { 1984 struct wcn36xx_hal_missed_beacon_ind_msg *rsp = buf; 1985 struct ieee80211_vif *vif = NULL; 1986 struct wcn36xx_vif *tmp; 1987 1988 /* Old FW does not have bss index */ 1989 if (wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) { 1990 list_for_each_entry(tmp, &wcn->vif_list, list) { 1991 wcn36xx_dbg(WCN36XX_DBG_HAL, "beacon missed bss_index %d\n", 1992 tmp->bss_index); 1993 vif = container_of((void *)tmp, 1994 struct ieee80211_vif, 1995 drv_priv); 1996 ieee80211_connection_loss(vif); 1997 } 1998 return 0; 1999 } 2000 2001 if (len != sizeof(*rsp)) { 2002 wcn36xx_warn("Corrupted missed beacon indication\n"); 2003 return -EIO; 2004 } 2005 2006 list_for_each_entry(tmp, &wcn->vif_list, list) { 2007 if (tmp->bss_index == rsp->bss_index) { 2008 wcn36xx_dbg(WCN36XX_DBG_HAL, "beacon missed bss_index %d\n", 2009 rsp->bss_index); 2010 vif = container_of((void *)tmp, 2011 struct ieee80211_vif, 2012 drv_priv); 2013 ieee80211_connection_loss(vif); 2014 return 0; 2015 } 2016 } 2017 2018 wcn36xx_warn("BSS index %d not found\n", rsp->bss_index); 2019 return -ENOENT; 2020 } 2021 2022 static int wcn36xx_smd_delete_sta_context_ind(struct wcn36xx *wcn, 2023 void *buf, 2024 size_t len) 2025 { 2026 struct wcn36xx_hal_delete_sta_context_ind_msg *rsp = buf; 2027 struct wcn36xx_vif *tmp; 2028 struct ieee80211_sta *sta = NULL; 2029 2030 if (len != sizeof(*rsp)) { 2031 wcn36xx_warn("Corrupted delete sta indication\n"); 2032 return -EIO; 2033 } 2034 2035 list_for_each_entry(tmp, &wcn->vif_list, list) { 2036 if (sta && (tmp->sta->sta_index == rsp->sta_id)) { 2037 sta = container_of((void *)tmp->sta, 2038 struct ieee80211_sta, 2039 drv_priv); 2040 wcn36xx_dbg(WCN36XX_DBG_HAL, 2041 "delete station indication %pM index %d\n", 2042 rsp->addr2, 2043 rsp->sta_id); 2044 ieee80211_report_low_ack(sta, 0); 2045 return 0; 2046 } 2047 } 2048 2049 wcn36xx_warn("STA with addr %pM and index %d not found\n", 2050 rsp->addr2, 2051 rsp->sta_id); 2052 return -ENOENT; 2053 } 2054 2055 int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value) 2056 { 2057 struct wcn36xx_hal_update_cfg_req_msg msg_body, *body; 2058 size_t len; 2059 int ret = 0; 2060 2061 mutex_lock(&wcn->hal_mutex); 2062 INIT_HAL_MSG(msg_body, WCN36XX_HAL_UPDATE_CFG_REQ); 2063 2064 PREPARE_HAL_BUF(wcn->hal_buf, msg_body); 2065 2066 body = (struct wcn36xx_hal_update_cfg_req_msg *) wcn->hal_buf; 2067 len = msg_body.header.len; 2068 2069 put_cfg_tlv_u32(wcn, &len, cfg_id, value); 2070 body->header.len = len; 2071 body->len = len - sizeof(*body); 2072 2073 ret = wcn36xx_smd_send_and_wait(wcn, body->header.len); 2074 if (ret) { 2075 wcn36xx_err("Sending hal_update_cfg failed\n"); 2076 goto out; 2077 } 2078 ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); 2079 if (ret) { 2080 wcn36xx_err("hal_update_cfg response failed err=%d\n", ret); 2081 goto out; 2082 } 2083 out: 2084 mutex_unlock(&wcn->hal_mutex); 2085 return ret; 2086 } 2087 static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len) 2088 { 2089 struct wcn36xx_hal_msg_header *msg_header = buf; 2090 struct wcn36xx_hal_ind_msg *msg_ind; 2091 wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "SMD <<< ", buf, len); 2092 2093 switch (msg_header->msg_type) { 2094 case WCN36XX_HAL_START_RSP: 2095 case WCN36XX_HAL_CONFIG_STA_RSP: 2096 case WCN36XX_HAL_CONFIG_BSS_RSP: 2097 case WCN36XX_HAL_ADD_STA_SELF_RSP: 2098 case WCN36XX_HAL_STOP_RSP: 2099 case WCN36XX_HAL_DEL_STA_SELF_RSP: 2100 case WCN36XX_HAL_DELETE_STA_RSP: 2101 case WCN36XX_HAL_INIT_SCAN_RSP: 2102 case WCN36XX_HAL_START_SCAN_RSP: 2103 case WCN36XX_HAL_END_SCAN_RSP: 2104 case WCN36XX_HAL_FINISH_SCAN_RSP: 2105 case WCN36XX_HAL_DOWNLOAD_NV_RSP: 2106 case WCN36XX_HAL_DELETE_BSS_RSP: 2107 case WCN36XX_HAL_SEND_BEACON_RSP: 2108 case WCN36XX_HAL_SET_LINK_ST_RSP: 2109 case WCN36XX_HAL_UPDATE_PROBE_RSP_TEMPLATE_RSP: 2110 case WCN36XX_HAL_SET_BSSKEY_RSP: 2111 case WCN36XX_HAL_SET_STAKEY_RSP: 2112 case WCN36XX_HAL_RMV_STAKEY_RSP: 2113 case WCN36XX_HAL_RMV_BSSKEY_RSP: 2114 case WCN36XX_HAL_ENTER_BMPS_RSP: 2115 case WCN36XX_HAL_SET_POWER_PARAMS_RSP: 2116 case WCN36XX_HAL_EXIT_BMPS_RSP: 2117 case WCN36XX_HAL_KEEP_ALIVE_RSP: 2118 case WCN36XX_HAL_DUMP_COMMAND_RSP: 2119 case WCN36XX_HAL_ADD_BA_SESSION_RSP: 2120 case WCN36XX_HAL_ADD_BA_RSP: 2121 case WCN36XX_HAL_DEL_BA_RSP: 2122 case WCN36XX_HAL_TRIGGER_BA_RSP: 2123 case WCN36XX_HAL_UPDATE_CFG_RSP: 2124 case WCN36XX_HAL_JOIN_RSP: 2125 case WCN36XX_HAL_UPDATE_SCAN_PARAM_RSP: 2126 case WCN36XX_HAL_CH_SWITCH_RSP: 2127 case WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_RSP: 2128 memcpy(wcn->hal_buf, buf, len); 2129 wcn->hal_rsp_len = len; 2130 complete(&wcn->hal_rsp_compl); 2131 break; 2132 2133 case WCN36XX_HAL_OTA_TX_COMPL_IND: 2134 case WCN36XX_HAL_MISSED_BEACON_IND: 2135 case WCN36XX_HAL_DELETE_STA_CONTEXT_IND: 2136 msg_ind = kmalloc(sizeof(*msg_ind), GFP_KERNEL); 2137 if (!msg_ind) 2138 goto nomem; 2139 msg_ind->msg_len = len; 2140 msg_ind->msg = kmemdup(buf, len, GFP_KERNEL); 2141 if (!msg_ind->msg) { 2142 kfree(msg_ind); 2143 nomem: 2144 /* 2145 * FIXME: Do something smarter then just 2146 * printing an error. 2147 */ 2148 wcn36xx_err("Run out of memory while handling SMD_EVENT (%d)\n", 2149 msg_header->msg_type); 2150 break; 2151 } 2152 mutex_lock(&wcn->hal_ind_mutex); 2153 list_add_tail(&msg_ind->list, &wcn->hal_ind_queue); 2154 queue_work(wcn->hal_ind_wq, &wcn->hal_ind_work); 2155 mutex_unlock(&wcn->hal_ind_mutex); 2156 wcn36xx_dbg(WCN36XX_DBG_HAL, "indication arrived\n"); 2157 break; 2158 default: 2159 wcn36xx_err("SMD_EVENT (%d) not supported\n", 2160 msg_header->msg_type); 2161 } 2162 } 2163 static void wcn36xx_ind_smd_work(struct work_struct *work) 2164 { 2165 struct wcn36xx *wcn = 2166 container_of(work, struct wcn36xx, hal_ind_work); 2167 struct wcn36xx_hal_msg_header *msg_header; 2168 struct wcn36xx_hal_ind_msg *hal_ind_msg; 2169 2170 mutex_lock(&wcn->hal_ind_mutex); 2171 2172 hal_ind_msg = list_first_entry(&wcn->hal_ind_queue, 2173 struct wcn36xx_hal_ind_msg, 2174 list); 2175 2176 msg_header = (struct wcn36xx_hal_msg_header *)hal_ind_msg->msg; 2177 2178 switch (msg_header->msg_type) { 2179 case WCN36XX_HAL_OTA_TX_COMPL_IND: 2180 wcn36xx_smd_tx_compl_ind(wcn, 2181 hal_ind_msg->msg, 2182 hal_ind_msg->msg_len); 2183 break; 2184 case WCN36XX_HAL_MISSED_BEACON_IND: 2185 wcn36xx_smd_missed_beacon_ind(wcn, 2186 hal_ind_msg->msg, 2187 hal_ind_msg->msg_len); 2188 break; 2189 case WCN36XX_HAL_DELETE_STA_CONTEXT_IND: 2190 wcn36xx_smd_delete_sta_context_ind(wcn, 2191 hal_ind_msg->msg, 2192 hal_ind_msg->msg_len); 2193 break; 2194 default: 2195 wcn36xx_err("SMD_EVENT (%d) not supported\n", 2196 msg_header->msg_type); 2197 } 2198 list_del(wcn->hal_ind_queue.next); 2199 kfree(hal_ind_msg->msg); 2200 kfree(hal_ind_msg); 2201 mutex_unlock(&wcn->hal_ind_mutex); 2202 } 2203 int wcn36xx_smd_open(struct wcn36xx *wcn) 2204 { 2205 int ret = 0; 2206 wcn->hal_ind_wq = create_freezable_workqueue("wcn36xx_smd_ind"); 2207 if (!wcn->hal_ind_wq) { 2208 wcn36xx_err("failed to allocate wq\n"); 2209 ret = -ENOMEM; 2210 goto out; 2211 } 2212 INIT_WORK(&wcn->hal_ind_work, wcn36xx_ind_smd_work); 2213 INIT_LIST_HEAD(&wcn->hal_ind_queue); 2214 mutex_init(&wcn->hal_ind_mutex); 2215 2216 ret = wcn->ctrl_ops->open(wcn, wcn36xx_smd_rsp_process); 2217 if (ret) { 2218 wcn36xx_err("failed to open control channel\n"); 2219 goto free_wq; 2220 } 2221 2222 return ret; 2223 2224 free_wq: 2225 destroy_workqueue(wcn->hal_ind_wq); 2226 out: 2227 return ret; 2228 } 2229 2230 void wcn36xx_smd_close(struct wcn36xx *wcn) 2231 { 2232 wcn->ctrl_ops->close(); 2233 destroy_workqueue(wcn->hal_ind_wq); 2234 mutex_destroy(&wcn->hal_ind_mutex); 2235 } 2236