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