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